From 6de9cd9a886ea695aa892c3c7c07818a7b7e9e6f Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Thu, 13 May 2004 02:41:07 -0400 Subject: [PATCH] Merge tree-ssa-20020619-branch into mainline. From-SVN: r81764 --- ChangeLog | 25 + ChangeLog.tree-ssa | 110 + MAINTAINERS | 5 + Makefile.def | 5 + Makefile.in | 1007 +- Makefile.tpl | 18 +- configure | 334 +- configure.in | 132 +- contrib/ChangeLog | 11 + contrib/ChangeLog.tree-ssa | 46 + contrib/filter_gcc_for_doxygen | 12 + contrib/filter_knr2ansi.pl | 45 + contrib/filter_params.pl | 14 + contrib/gcc_update | 2 + contrib/tree-ssa.doxy | 932 + depcomp | 472 + gcc/ChangeLog | 1123 + gcc/ChangeLog.tree-ssa | 19338 ++++++++++++++++ gcc/Makefile.in | 256 +- gcc/ada/ChangeLog | 9 + gcc/ada/ChangeLog.tree-ssa | 29 + gcc/ada/config-lang.in | 5 +- gcc/ada/utils.c | 5 +- gcc/basic-block.h | 122 +- gcc/bb-reorder.c | 4 +- gcc/bitmap.c | 8 +- gcc/builtin-types.def | 2 + gcc/builtins.c | 1521 +- gcc/builtins.def | 12 + gcc/c-common.c | 619 +- gcc/c-common.def | 6 +- gcc/c-common.h | 99 +- gcc/c-convert.c | 3 + gcc/c-decl.c | 229 +- gcc/c-dump.c | 4 +- gcc/c-format.c | 2 +- gcc/c-lang.c | 30 +- gcc/c-mudflap.c | 100 + gcc/c-objc-common.c | 67 +- gcc/c-opts.c | 21 +- gcc/c-parse.in | 16 +- gcc/c-pragma.c | 5 +- gcc/c-pretty-print.c | 149 +- gcc/c-pretty-print.h | 5 +- gcc/c-semantics.c | 824 +- gcc/c-simplify.c | 1102 + gcc/c-tree.h | 17 +- gcc/c-typeck.c | 102 +- gcc/c.opt | 4 - gcc/calls.c | 475 +- gcc/cfg.c | 270 +- gcc/cfganal.c | 179 +- gcc/cfgbuild.c | 8 +- gcc/cfgcleanup.c | 30 +- gcc/cfghooks.c | 183 +- gcc/cfghooks.h | 49 +- gcc/cfglayout.c | 122 +- gcc/cfglayout.h | 18 - gcc/cfgloop.c | 2 + gcc/cfgloop.h | 1 + gcc/cfgloopmanip.c | 96 + gcc/cfgrtl.c | 308 +- gcc/cgraph.c | 10 - gcc/cgraph.h | 3 +- gcc/cgraphunit.c | 228 +- gcc/combine.c | 14 +- gcc/common.opt | 71 + gcc/config.in | 9 + gcc/config/alpha/alpha.c | 3 - gcc/config/arm/arm.c | 10 +- gcc/config/arm/arm.h | 1 - gcc/config/avr/avr.h | 3 - gcc/config/c4x/c4x.c | 3 - gcc/config/cris/cris.c | 3 - gcc/config/frv/frv.h | 3 +- gcc/config/h8300/h8300.c | 2 +- gcc/config/ia64/ia64.c | 16 +- gcc/config/ia64/ia64.h | 25 +- gcc/config/ip2k/ip2k.h | 3 - gcc/config/m32r/m32r.c | 2 - gcc/config/mips/mips.c | 3 - gcc/config/mmix/mmix.c | 1 - gcc/config/pa/pa.c | 3 - gcc/config/pa/pa.h | 4 +- gcc/config/rs6000/aix.h | 25 + gcc/config/rs6000/rs6000.c | 13 +- gcc/config/rs6000/t-rs6000 | 20 + gcc/config/s390/s390.c | 42 +- gcc/config/sh/sh.c | 4 +- gcc/config/sparc/sparc.c | 4 - gcc/config/v850/v850.c | 1 - gcc/config/xtensa/xtensa.c | 8 +- gcc/configure | 69 +- gcc/configure.ac | 33 + gcc/coverage.c | 61 +- gcc/coverage.h | 4 +- gcc/cp/ChangeLog | 13 + gcc/cp/ChangeLog.tree-ssa | 566 + gcc/cp/Make-lang.in | 14 +- gcc/cp/call.c | 20 +- gcc/cp/class.c | 31 +- gcc/cp/cp-lang.c | 121 +- gcc/cp/cp-mudflap.c | 108 + gcc/cp/cp-simplify.c | 236 + gcc/cp/cp-tree.def | 9 + gcc/cp/cp-tree.h | 19 +- gcc/cp/cvt.c | 5 +- gcc/cp/decl.c | 89 +- gcc/cp/decl2.c | 17 +- gcc/cp/error.c | 12 +- gcc/cp/except.c | 110 +- gcc/cp/expr.c | 18 +- gcc/cp/init.c | 137 +- gcc/cp/name-lookup.h | 1 - gcc/cp/optimize.c | 5 + gcc/cp/parser.c | 22 +- gcc/cp/pt.c | 37 +- gcc/cp/rtti.c | 23 +- gcc/cp/semantics.c | 220 +- gcc/cp/tree.c | 131 +- gcc/cp/typeck.c | 67 +- gcc/cp/typeck2.c | 9 +- gcc/cppexp.c | 28 +- gcc/cse.c | 36 +- gcc/dbxout.c | 3 +- gcc/defaults.h | 5 + gcc/diagnostic.h | 12 + gcc/doc/c-tree.texi | 42 +- gcc/doc/cfg.texi | 614 + gcc/doc/gccint.texi | 4 + gcc/doc/install.texi | 13 +- gcc/doc/invoke.texi | 298 +- gcc/doc/passes.texi | 1077 +- gcc/doc/rtl.texi | 3 - gcc/doc/sourcebuild.texi | 7 + gcc/doc/standards.texi | 5 +- gcc/doc/tm.texi | 10 - gcc/doc/tree-ssa.texi | 1189 + gcc/dominance.c | 28 +- gcc/domwalk.c | 265 + gcc/domwalk.h | 112 + gcc/dwarf2out.c | 40 +- gcc/emit-rtl.c | 13 +- gcc/et-forest.c | 12 +- gcc/except.c | 543 +- gcc/except.h | 30 +- gcc/explow.c | 34 +- gcc/expmed.c | 9 +- gcc/expr.c | 732 +- gcc/expr.h | 17 +- gcc/f/ChangeLog | 6 + gcc/f/ChangeLog.tree-ssa | 21 + gcc/f/config-lang.in | 2 + gcc/final.c | 10 +- gcc/flags.h | 47 + gcc/flow.c | 70 +- gcc/fold-const.c | 777 +- gcc/fortran/.cvsignore | 1 + gcc/fortran/CONTRIB | 33 + gcc/fortran/ChangeLog | 3068 +++ gcc/fortran/Make-lang.in | 300 + gcc/fortran/NEWS | 7 + gcc/fortran/README | 18 + gcc/fortran/TODO | 56 + gcc/fortran/arith.c | 2763 +++ gcc/fortran/arith.h | 91 + gcc/fortran/array.c | 1973 ++ gcc/fortran/bbt.c | 201 + gcc/fortran/check.c | 1866 ++ gcc/fortran/config-lang.in | 22 + gcc/fortran/convert.c | 124 + gcc/fortran/data.c | 457 + gcc/fortran/decl.c | 2649 +++ gcc/fortran/dependency.c | 679 + gcc/fortran/dependency.h | 30 + gcc/fortran/dump-parse-tree.c | 1459 ++ gcc/fortran/error.c | 750 + gcc/fortran/expr.c | 1954 ++ gcc/fortran/f95-lang.c | 838 + gcc/fortran/gfortran.h | 1652 ++ gcc/fortran/gfortran.texi | 829 + gcc/fortran/gfortranspec.c | 548 + gcc/fortran/interface.c | 1858 ++ gcc/fortran/intrinsic.c | 2560 ++ gcc/fortran/intrinsic.h | 314 + gcc/fortran/invoke.texi | 656 + gcc/fortran/io.c | 2409 ++ gcc/fortran/iresolve.c | 1377 ++ gcc/fortran/lang-specs.h | 35 + gcc/fortran/lang.opt | 152 + gcc/fortran/match.c | 3558 +++ gcc/fortran/match.h | 164 + gcc/fortran/matchexp.c | 776 + gcc/fortran/mathbuiltins.def | 14 + gcc/fortran/misc.c | 327 + gcc/fortran/module.c | 3459 +++ gcc/fortran/options.c | 320 + gcc/fortran/parse.c | 2503 ++ gcc/fortran/parse.h | 65 + gcc/fortran/primary.c | 2214 ++ gcc/fortran/resolve.c | 4435 ++++ gcc/fortran/scanner.c | 1073 + gcc/fortran/simplify.c | 4008 ++++ gcc/fortran/st.c | 186 + gcc/fortran/symbol.c | 2417 ++ gcc/fortran/trans-array.c | 4158 ++++ gcc/fortran/trans-array.h | 117 + gcc/fortran/trans-common.c | 756 + gcc/fortran/trans-const.c | 375 + gcc/fortran/trans-const.h | 59 + gcc/fortran/trans-decl.c | 2137 ++ gcc/fortran/trans-expr.c | 1835 ++ gcc/fortran/trans-intrinsic.c | 3003 +++ gcc/fortran/trans-io.c | 1157 + gcc/fortran/trans-stmt.c | 3159 +++ gcc/fortran/trans-stmt.h | 65 + gcc/fortran/trans-types.c | 1485 ++ gcc/fortran/trans-types.h | 143 + gcc/fortran/trans.c | 662 + gcc/fortran/trans.h | 534 + gcc/function.c | 538 +- gcc/function.h | 88 +- gcc/gcc.c | 28 +- gcc/gcse.c | 14 +- gcc/gdbinit.in | 18 + gcc/genattrtab.c | 4 +- gcc/gengtype-lex.l | 2 +- gcc/gengtype-yacc.y | 9 +- gcc/gengtype.c | 3 +- gcc/genrecog.c | 3 +- gcc/gimple-low.c | 472 + gcc/gimplify.c | 3754 +++ gcc/haifa-sched.c | 4 - gcc/ifcvt.c | 2 +- gcc/input.h | 3 - gcc/integrate.c | 1847 +- gcc/integrate.h | 15 - gcc/java/ChangeLog | 11 + gcc/java/ChangeLog.tree-ssa | 360 + gcc/java/Make-lang.in | 5 +- gcc/java/builtins.c | 2 +- gcc/java/check-init.c | 4 +- gcc/java/class.c | 42 +- gcc/java/constants.c | 42 +- gcc/java/decl.c | 448 +- gcc/java/except.c | 75 +- gcc/java/expr.c | 334 +- gcc/java/java-except.h | 3 + gcc/java/java-gimplify.c | 277 + gcc/java/java-tree.def | 9 +- gcc/java/java-tree.h | 36 +- gcc/java/jcf-parse.c | 15 +- gcc/java/jcf-write.c | 4 +- gcc/java/lang.c | 152 +- gcc/java/lang.opt | 3 - gcc/java/parse.y | 191 +- gcc/java/resource.c | 1 + gcc/jump.c | 361 +- gcc/langhooks-def.h | 30 +- gcc/langhooks.c | 35 +- gcc/langhooks.h | 35 +- gcc/objc/objc-act.c | 19 +- gcc/objc/objc-lang.c | 16 +- gcc/opts.c | 100 + gcc/output.h | 5 - gcc/params.def | 32 + gcc/params.h | 4 + gcc/passes.c | 256 +- gcc/predict.c | 509 +- gcc/predict.def | 4 + gcc/predict.h | 9 +- gcc/pretty-print.c | 2 +- gcc/pretty-print.h | 1 + gcc/print-rtl.c | 6 +- gcc/print-tree.c | 20 +- gcc/profile.c | 462 +- gcc/ra-rewrite.c | 2 + gcc/recog.c | 6 - gcc/regs.h | 4 + gcc/reload.c | 5 +- gcc/rtl-profile.c | 424 + gcc/rtl.def | 5 - gcc/rtl.h | 39 +- gcc/rtlanal.c | 12 +- gcc/sbitmap.c | 26 + gcc/sbitmap.h | 1 + gcc/sibcall.c | 753 - gcc/simplify-rtx.c | 5 - gcc/stmt.c | 815 +- gcc/stor-layout.c | 16 +- gcc/system.h | 1 + gcc/testsuite/ChangeLog | 5 + gcc/testsuite/ChangeLog.tree-ssa | 1204 + gcc/testsuite/g++.dg/README | 1 + gcc/testsuite/g++.dg/eh/goto1.C | 34 + gcc/testsuite/g++.dg/ext/asm3.C | 2 +- gcc/testsuite/g++.dg/ext/label3.C | 39 + gcc/testsuite/g++.dg/init/pmf1.C | 17 + gcc/testsuite/g++.dg/opt/bool1.C | 25 + gcc/testsuite/g++.dg/opt/cfg4.C | 45 + gcc/testsuite/g++.dg/opt/crash1.C | 14 + gcc/testsuite/g++.dg/opt/inline7.C | 7 + gcc/testsuite/g++.dg/opt/nothrow1.C | 24 + gcc/testsuite/g++.dg/opt/static4.C | 15 + gcc/testsuite/g++.dg/parse/crash10.C | 2 + gcc/testsuite/g++.dg/tree-ssa/20040317-1.C | 38 + gcc/testsuite/g++.dg/tree-ssa/nothrow-1.C | 19 + gcc/testsuite/g++.dg/tree-ssa/tree-ssa.exp | 36 + gcc/testsuite/g++.dg/warn/Wswitch-1.C | 14 +- gcc/testsuite/g++.dg/warn/Wswitch-2.C | 8 +- gcc/testsuite/g++.dg/warn/Wunused-5.C | 30 +- gcc/testsuite/g++.dg/warn/noeffect5.C | 8 + gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C | 10 +- gcc/testsuite/g++.old-deja/g++.martin/new1.C | 16 +- gcc/testsuite/g++.old-deja/g++.robertl/eb58.C | 2 +- gcc/testsuite/g++.old-deja/g++.robertl/eb63.C | 2 +- .../gcc.c-torture/compile/20010516-1.c | 5 - .../gcc.c-torture/compile/20030310-1.c | 13 + .../gcc.c-torture/compile/20030405-1.c | 78 +- .../gcc.c-torture/compile/20030405-1.x | 3 + .../gcc.c-torture/compile/20030416-1.c | 16 + .../gcc.c-torture/compile/20030530-1.c | 23 + .../gcc.c-torture/compile/20030530-3.c | 16 + .../gcc.c-torture/compile/20030716-1.c | 7 + .../gcc.c-torture/compile/20030823-1.c | 18 + .../gcc.c-torture/compile/20030902-1.c | 37 + .../gcc.c-torture/compile/20030910-1.c | 11 + .../gcc.c-torture/compile/20030917-1.c | 18 + .../gcc.c-torture/compile/20031124-1.c | 8 + .../gcc.c-torture/compile/20031125-1.c | 36 + .../gcc.c-torture/compile/20031125-2.c | 20 + .../gcc.c-torture/compile/20031203-1.c | 22 + .../gcc.c-torture/compile/20031203-2.c | 6 + .../gcc.c-torture/compile/20031203-3.c | 7 + .../gcc.c-torture/compile/20040219-1.c | 1 + .../gcc.c-torture/compile/20040220-1.c | 16 + .../gcc.c-torture/compile/20040303-1.c | 16 + .../gcc.c-torture/compile/20040303-2.c | 23 + .../gcc.c-torture/compile/20040304-1.c | 61 +- .../gcc.c-torture/compile/20040309-1.c | 20 + .../gcc.c-torture/compile/20040310-1.c | 10 + .../gcc.c-torture/compile/20040317-1.c | 4 + .../gcc.c-torture/compile/20040317-2.c | 25 + .../gcc.c-torture/compile/20040317-3.c | 11 + .../gcc.c-torture/compile/20040323-1.c | 11 + .../gcc.c-torture/compile/20040401-1.c | 6 + .../gcc.c-torture/compile/20040415-1.c | 5 + .../gcc.c-torture/compile/20040415-2.c | 7 + gcc/testsuite/gcc.c-torture/compile/pr14730.c | 16 + gcc/testsuite/gcc.c-torture/compile/pr15245.c | 21 + .../gcc.c-torture/execute/20000603-1.c | 11 +- .../gcc.c-torture/execute/20020819-1.c | 22 + .../gcc.c-torture/execute/20021113-1.c | 17 + .../gcc.c-torture/execute/20030403-1.c | 16 + .../gcc.c-torture/execute/20030404-1.c | 23 + .../gcc.c-torture/execute/20030501-1.c | 17 + .../gcc.c-torture/execute/20030828-1.c | 18 + .../gcc.c-torture/execute/20030828-2.c | 28 + .../gcc.c-torture/execute/20030903-1.c | 21 + .../gcc.c-torture/execute/20030909-1.c | 35 + .../gcc.c-torture/execute/20030910-1.c | 13 + .../gcc.c-torture/execute/20030913-1.c | 26 + .../gcc.c-torture/execute/20031010-1.c | 34 + .../gcc.c-torture/execute/20031211-1.c | 13 + .../gcc.c-torture/execute/20031211-2.c | 19 + .../gcc.c-torture/execute/20040319-1.c | 17 + .../gcc.c-torture/execute/20040423-1.c | 30 + .../gcc.c-torture/execute/930529-1.x | 23 +- .../gcc.c-torture/execute/builtin-constant.x | 11 - gcc/testsuite/gcc.dg/20010516-1.c | 5 + gcc/testsuite/gcc.dg/20030612-1.c | 32 +- gcc/testsuite/gcc.dg/20030805-1.c | 23 + gcc/testsuite/gcc.dg/20040202-1.c | 8 + gcc/testsuite/gcc.dg/20040206-1.c | 11 + gcc/testsuite/gcc.dg/Wswitch-2.c | 8 +- gcc/testsuite/gcc.dg/Wswitch-default.c | 16 +- gcc/testsuite/gcc.dg/Wswitch-enum.c | 22 +- gcc/testsuite/gcc.dg/Wswitch.c | 8 +- gcc/testsuite/gcc.dg/asm-7.c | 4 +- gcc/testsuite/gcc.dg/i386-ssetype-1.c | 3 +- gcc/testsuite/gcc.dg/i386-ssetype-3.c | 3 +- gcc/testsuite/gcc.dg/local1.c | 16 +- gcc/testsuite/gcc.dg/noncompile/920507-1.c | 3 +- gcc/testsuite/gcc.dg/noreturn-1.c | 11 +- gcc/testsuite/gcc.dg/noreturn-4.c | 4 +- gcc/testsuite/gcc.dg/noreturn-7.c | 10 +- gcc/testsuite/gcc.dg/pr14475.c | 8 + gcc/testsuite/gcc.dg/return-type-1.c | 4 +- gcc/testsuite/gcc.dg/return-type-3.c | 2 +- gcc/testsuite/gcc.dg/tls/asm-1.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/20030530-2.c | 26 + gcc/testsuite/gcc.dg/tree-ssa/20030611-1.c | 13 + gcc/testsuite/gcc.dg/tree-ssa/20030703-1.c | 21 + gcc/testsuite/gcc.dg/tree-ssa/20030703-2.c | 41 + gcc/testsuite/gcc.dg/tree-ssa/20030708-1.c | 41 + gcc/testsuite/gcc.dg/tree-ssa/20030709-1.c | 15 + gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c | 53 + gcc/testsuite/gcc.dg/tree-ssa/20030709-3.c | 45 + gcc/testsuite/gcc.dg/tree-ssa/20030710-1.c | 53 + gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c | 53 + gcc/testsuite/gcc.dg/tree-ssa/20030711-2.c | 67 + gcc/testsuite/gcc.dg/tree-ssa/20030711-3.c | 59 + gcc/testsuite/gcc.dg/tree-ssa/20030714-1.c | 44 + gcc/testsuite/gcc.dg/tree-ssa/20030714-2.c | 39 + gcc/testsuite/gcc.dg/tree-ssa/20030728-1.c | 47 + gcc/testsuite/gcc.dg/tree-ssa/20030729-1.c | 51 + gcc/testsuite/gcc.dg/tree-ssa/20030730-1.c | 23 + gcc/testsuite/gcc.dg/tree-ssa/20030730-2.c | 22 + gcc/testsuite/gcc.dg/tree-ssa/20030731-1.c | 65 + gcc/testsuite/gcc.dg/tree-ssa/20030731-2.c | 16 + gcc/testsuite/gcc.dg/tree-ssa/20030807-1.c | 46 + gcc/testsuite/gcc.dg/tree-ssa/20030807-10.c | 25 + gcc/testsuite/gcc.dg/tree-ssa/20030807-11.c | 19 + gcc/testsuite/gcc.dg/tree-ssa/20030807-2.c | 26 + gcc/testsuite/gcc.dg/tree-ssa/20030807-3.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c | 36 + gcc/testsuite/gcc.dg/tree-ssa/20030807-6.c | 44 + gcc/testsuite/gcc.dg/tree-ssa/20030807-7.c | 37 + gcc/testsuite/gcc.dg/tree-ssa/20030807-8.c | 52 + gcc/testsuite/gcc.dg/tree-ssa/20030807-9.c | 19 + gcc/testsuite/gcc.dg/tree-ssa/20030808-1.c | 39 + gcc/testsuite/gcc.dg/tree-ssa/20030814-1.c | 20 + gcc/testsuite/gcc.dg/tree-ssa/20030814-2.c | 21 + gcc/testsuite/gcc.dg/tree-ssa/20030814-3.c | 22 + gcc/testsuite/gcc.dg/tree-ssa/20030814-4.c | 40 + gcc/testsuite/gcc.dg/tree-ssa/20030814-5.c | 40 + gcc/testsuite/gcc.dg/tree-ssa/20030814-6.c | 43 + gcc/testsuite/gcc.dg/tree-ssa/20030814-7.c | 40 + gcc/testsuite/gcc.dg/tree-ssa/20030815-1.c | 42 + gcc/testsuite/gcc.dg/tree-ssa/20030820-1.c | 24 + gcc/testsuite/gcc.dg/tree-ssa/20030820-2.c | 24 + gcc/testsuite/gcc.dg/tree-ssa/20030821-1.c | 23 + gcc/testsuite/gcc.dg/tree-ssa/20030824-1.c | 22 + gcc/testsuite/gcc.dg/tree-ssa/20030824-2.c | 22 + gcc/testsuite/gcc.dg/tree-ssa/20030825-1.c | 28 + gcc/testsuite/gcc.dg/tree-ssa/20030907-1.c | 26 + gcc/testsuite/gcc.dg/tree-ssa/20030907-2.c | 30 + gcc/testsuite/gcc.dg/tree-ssa/20030917-1.c | 20 + gcc/testsuite/gcc.dg/tree-ssa/20030917-2.c | 40 + gcc/testsuite/gcc.dg/tree-ssa/20030917-3.c | 24 + gcc/testsuite/gcc.dg/tree-ssa/20030918-1.c | 15 + gcc/testsuite/gcc.dg/tree-ssa/20030920-1.c | 112 + gcc/testsuite/gcc.dg/tree-ssa/20030922-1.c | 32 + gcc/testsuite/gcc.dg/tree-ssa/20030922-2.c | 22 + gcc/testsuite/gcc.dg/tree-ssa/20031015-1.c | 16 + gcc/testsuite/gcc.dg/tree-ssa/20031021-1.c | 20 + gcc/testsuite/gcc.dg/tree-ssa/20031022-1.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/20031031-1.c | 17 + gcc/testsuite/gcc.dg/tree-ssa/20031106-1.c | 20 + gcc/testsuite/gcc.dg/tree-ssa/20031106-2.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/20031106-3.c | 21 + gcc/testsuite/gcc.dg/tree-ssa/20031106-4.c | 29 + gcc/testsuite/gcc.dg/tree-ssa/20031106-5.c | 28 + gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c | 28 + gcc/testsuite/gcc.dg/tree-ssa/20031113-1.c | 30 + gcc/testsuite/gcc.dg/tree-ssa/20031216-1.c | 19 + gcc/testsuite/gcc.dg/tree-ssa/20040121-1.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c | 36 + gcc/testsuite/gcc.dg/tree-ssa/20040209-1.c | 52 + gcc/testsuite/gcc.dg/tree-ssa/20040210-1.c | 32 + gcc/testsuite/gcc.dg/tree-ssa/20040211-1.c | 40 + gcc/testsuite/gcc.dg/tree-ssa/20040216-1.c | 18 + gcc/testsuite/gcc.dg/tree-ssa/20040302-1.c | 8 + gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c | 30 + gcc/testsuite/gcc.dg/tree-ssa/20040313-1.c | 16 + gcc/testsuite/gcc.dg/tree-ssa/20040319-1.c | 25 + gcc/testsuite/gcc.dg/tree-ssa/20040324-1.c | 31 + gcc/testsuite/gcc.dg/tree-ssa/20040326-1.c | 29 + gcc/testsuite/gcc.dg/tree-ssa/20040326-2.c | 63 + gcc/testsuite/gcc.dg/tree-ssa/20040408-1.c | 51 + gcc/testsuite/gcc.dg/tree-ssa/20040430-1.c | 25 + gcc/testsuite/gcc.dg/tree-ssa/asm-1.c | 16 + gcc/testsuite/gcc.dg/tree-ssa/cfgcleanup-1.c | 18 + gcc/testsuite/gcc.dg/tree-ssa/copy-headers.c | 15 + gcc/testsuite/gcc.dg/tree-ssa/sra-1.c | 72 + gcc/testsuite/gcc.dg/tree-ssa/sra-2.c | 25 + gcc/testsuite/gcc.dg/tree-ssa/sra-3.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-1.c | 74 + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c | 31 + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c | 41 + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c | 171 + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-3.c | 134 + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-7.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-9.c | 54 + gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-1.c | 12 + gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-2.c | 16 + gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-3.c | 29 + gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-ccp-1.c | 17 + gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c | 16 + .../gcc.dg/tree-ssa/ssa-dom-thread-1.c | 17 + gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c | 19 + gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c | 20 + gcc/testsuite/gcc.dg/tree-ssa/tailcall-1.c | 18 + gcc/testsuite/gcc.dg/tree-ssa/tailcall-2.c | 23 + .../gcc.dg/tree-ssa/tailrecursion-1.c | 11 + .../gcc.dg/tree-ssa/tailrecursion-2.c | 12 + .../gcc.dg/tree-ssa/tailrecursion-3.c | 15 + .../gcc.dg/tree-ssa/tailrecursion-4.c | 17 + .../gcc.dg/tree-ssa/tailrecursion-5.c | 72 + gcc/testsuite/gcc.dg/tree-ssa/tree-ssa.exp | 36 + gcc/testsuite/gcc.dg/tree-ssa/useless-1.c | 16 + gcc/testsuite/gcc.dg/uninit-1.c | 2 +- gcc/testsuite/gcc.dg/uninit-11.c | 42 + gcc/testsuite/gcc.dg/uninit-2.c | 2 +- gcc/testsuite/gcc.dg/uninit-3.c | 2 +- gcc/testsuite/gcc.dg/uninit-4.c | 2 +- gcc/testsuite/gcc.dg/uninit-5.c | 7 +- gcc/testsuite/gcc.dg/uninit-6.c | 4 +- gcc/testsuite/gcc.dg/uninit-8.c | 2 +- gcc/testsuite/gcc.dg/uninit-9.c | 2 +- gcc/testsuite/gcc.dg/uninit-H.c | 19 + gcc/testsuite/gcc.dg/warn-1.c | 4 +- .../gfortran.fortran-torture/ChangeLog.g95 | 99 + .../compile/actual.f90 | 38 + .../compile/allocate.f90 | 26 + .../compile/ambig.f90 | 26 + .../compile/arrayio.f90 | 12 + .../compile/bergervoet2.f90 | 5 + .../compile/compile.exp | 55 + .../compile/contained_1.f90 | 15 + .../compile/contained_2.f90 | 11 + .../compile/contained_3.f90 | 12 + .../compile/contained_4.f90 | 35 + .../compile/contained_5.f90 | 10 + .../compile/convert.f90 | 37 + .../compile/dummyfn.f90 | 13 + .../compile/emptyif.f90 | 42 + .../compile/fnresvar.f90 | 5 + .../compile/gen_interf.f90 | 19 + .../compile/implicit.f90 | 8 + .../compile/io_end.f90 | 9 + .../compile/module_common.f90 | 10 + .../compile/module_expr.f90 | 18 + .../compile/module_proc.f90 | 14 + .../compile/module_result.f90 | 9 + .../compile/named_args.f90 | 6 + .../compile/parameter_1.f90 | 7 + .../compile/parameter_2.f90 | 23 + .../compile/shape_reshape.f90 | 8 + .../compile/stoppause.f90 | 10 + .../compile/strparm_1.f90 | 6 + .../compile/write.f90 | 5 + .../execute/a_edit_1.f90 | 17 + .../execute/allocate.f90 | 38 + .../execute/alternate_return.f90 | 18 + .../gfortran.fortran-torture/execute/args.f90 | 22 + .../execute/arithmeticif.f90 | 25 + .../execute/arrayarg.f90 | 145 + .../execute/arrayarg2.f90 | 21 + .../execute/arraysave.f90 | 24 + .../execute/assumed_size.f90 | 39 + .../execute/bounds.f90 | 35 + .../execute/character_select_1.f90 | 12 + .../execute/cmplx.f90 | 45 + .../execute/common.f90 | 53 + .../execute/common_size.f90 | 10 + .../execute/constructor.f90 | 29 + .../execute/contained.f90 | 16 + .../execute/contained2.f90 | 28 + .../execute/csqrt_1.f90 | 78 + .../gfortran.fortran-torture/execute/data.f90 | 72 + .../execute/data_2.f90 | 17 + .../execute/dep_fails.f90 | 50 + .../execute/der_init.f90 | 32 + .../execute/der_io.f90 | 67 + .../execute/der_point.f90 | 45 + .../execute/der_type.f90 | 45 + .../execute/direct_io.f90 | 20 + .../execute/elemental.f90 | 32 + .../execute/empty_format.f90 | 14 + .../execute/emptyif.f90 | 20 + .../execute/execute.exp | 59 + .../execute/f2_edit_1.f90 | 10 + .../execute/forall.f90 | 17 + .../execute/forall_1.f90 | 61 + .../execute/forall_2.f90 | 20 + .../execute/forall_3.f90 | 36 + .../execute/forall_4.f90 | 27 + .../execute/forall_5.f90 | 28 + .../execute/forall_6.f90 | 25 + .../execute/function_module_1.f90 | 36 + .../execute/hollerith.f90 | 9 + .../execute/initializer.f90 | 26 + .../execute/inquire_1.f90 | 8 + .../execute/inquire_2.f90 | 6 + .../execute/inquire_3.f90 | 13 + .../execute/inquire_4.f90 | 20 + .../execute/integer_select.f90 | 71 + .../execute/integer_select_1.f90 | 31 + .../execute/internal_write.f90 | 11 + .../execute/intrinsic_abs.f90 | 33 + .../execute/intrinsic_achar.f90 | 9 + .../execute/intrinsic_aint_anint.f90 | 55 + .../execute/intrinsic_anyall.f90 | 26 + .../execute/intrinsic_associated.f90 | 137 + .../execute/intrinsic_associated_2.f90 | 36 + .../execute/intrinsic_bitops.f90 | 29 + .../execute/intrinsic_count.f90 | 21 + .../execute/intrinsic_cshift.f90 | 43 + .../execute/intrinsic_dim.f90 | 20 + .../execute/intrinsic_dotprod.f90 | 25 + .../execute/intrinsic_dprod.f90 | 13 + .../execute/intrinsic_dummy.f90 | 23 + .../execute/intrinsic_eoshift.f90 | 60 + .../execute/intrinsic_fraction_exponent.f90 | 84 + .../execute/intrinsic_index.f90 | 15 + .../execute/intrinsic_integer.f90 | 18 + .../execute/intrinsic_len.f90 | 22 + .../execute/intrinsic_matmul.f90 | 24 + .../execute/intrinsic_merge.f90 | 15 + .../execute/intrinsic_minmax.f90 | 37 + .../execute/intrinsic_mmloc.f90 | 52 + .../execute/intrinsic_mmloc_2.f90 | 22 + .../execute/intrinsic_mmloc_3.f90 | 12 + .../execute/intrinsic_mmloc_4.f90 | 13 + .../execute/intrinsic_mmval.f90 | 28 + .../execute/intrinsic_mod_ulo.f90 | 64 + .../execute/intrinsic_nearest.f90 | 71 + .../execute/intrinsic_pack.f90 | 12 + .../execute/intrinsic_present.f90 | 40 + .../execute/intrinsic_product.f90 | 25 + .../execute/intrinsic_rrspacing.f90 | 27 + .../execute/intrinsic_scale.f90 | 27 + .../execute/intrinsic_set_exponent.f90 | 91 + .../execute/intrinsic_shape.f90 | 22 + .../execute/intrinsic_si_kind.f90 | 35 + .../execute/intrinsic_sign.f90 | 31 + .../execute/intrinsic_size.f90 | 37 + .../execute/intrinsic_spacing.f90 | 33 + .../execute/intrinsic_spread.f90 | 10 + .../execute/intrinsic_sr_kind.f90 | 61 + .../execute/intrinsic_sum.f90 | 26 + .../execute/intrinsic_transpose.f90 | 24 + .../execute/intrinsic_trim.f90 | 23 + .../execute/intrinsic_unpack.f90 | 17 + .../execute/list_read_1.f90 | 53 + .../execute/logical_select_1.f90 | 55 + .../execute/mainsub.f90 | 17 + .../gfortran.fortran-torture/execute/math.f90 | 100 + .../execute/module_interface.f90 | 39 + .../execute/module_interface_2.f90 | 29 + .../execute/mystery_proc.f90 | 23 + .../execute/nestcons.f90 | 9 + .../execute/parameter_1.f90 | 12 + .../execute/partparm.f90 | 15 + .../execute/plusconst_1.f90 | 15 + .../execute/power.f90 | 43 + .../execute/procarg.f90 | 29 + .../gfortran.fortran-torture/execute/ptr.f90 | 20 + .../execute/read_eof.f90 | 5 + .../execute/retarray.f90 | 45 + .../execute/retarray_2.f90 | 20 + .../execute/scalarize.f90 | 23 + .../execute/scalarize2.f90 | 24 + .../execute/scalarize3.f90 | 8 + .../execute/slash_edit.f90 | 14 + .../execute/spec_abs.f90 | 12 + .../execute/specifics.f90 | 133 + .../execute/st_function.f90 | 87 + .../execute/stack_varsize.f90 | 30 + .../execute/straret.f90 | 18 + .../execute/strarray_1.f90 | 13 + .../execute/strarray_2.f90 | 14 + .../execute/strarray_3.f90 | 50 + .../execute/strarray_4.f90 | 39 + .../execute/strcmp.f90 | 16 + .../execute/strcommon_1.f90 | 28 + .../execute/string.f90 | 15 + .../execute/strlen.f90 | 34 + .../execute/strret.f90 | 25 + .../execute/test_slice.f90 | 17 + .../execute/unopened_unit_1.f90 | 13 + .../execute/userop.f90 | 67 + .../execute/where_1.f90 | 41 + .../execute/where_2.f90 | 22 + .../execute/where_3.f90 | 21 + .../execute/where_4.f90 | 13 + .../execute/where_5.f90 | 13 + .../execute/where_6.f90 | 23 + .../execute/write_logical.f90 | 23 + gcc/testsuite/lib/fortran-torture.exp | 344 + gcc/testsuite/lib/gcc-dg.exp | 1 + gcc/testsuite/lib/gfortran.exp | 233 + gcc/testsuite/lib/scantree.exp | 243 + gcc/testsuite/treelang/compile/compile.exp | 31 - gcc/testsuite/treelang/compile/tabs.tree | 11 - gcc/timevar.def | 33 +- gcc/toplev.c | 92 +- gcc/toplev.h | 2 + gcc/tracer.c | 4 +- gcc/tree-alias-ander.c | 933 + gcc/tree-alias-ander.h | 7 + gcc/tree-alias-common.c | 1264 + gcc/tree-alias-common.h | 99 + gcc/tree-alias-type.c | 37 + gcc/tree-alias-type.h | 41 + gcc/tree-browser.c | 1045 + gcc/tree-browser.def | 98 + gcc/tree-cfg.c | 4594 ++++ gcc/tree-complex.c | 572 + gcc/tree-dfa.c | 1153 + gcc/tree-dump.c | 227 +- gcc/tree-dump.h | 6 + gcc/tree-eh.c | 1756 ++ gcc/tree-flow-inline.h | 604 + gcc/tree-flow.h | 596 + gcc/tree-inline.c | 1828 +- gcc/tree-inline.h | 3 +- gcc/tree-into-ssa.c | 1179 + gcc/tree-iterator.c | 369 + gcc/tree-iterator.h | 120 + gcc/tree-mudflap.c | 1093 + gcc/tree-mudflap.h | 41 + gcc/tree-nested.c | 1383 ++ gcc/tree-nomudflap.c | 127 + gcc/tree-nrv.c | 217 + gcc/tree-optimize.c | 558 +- gcc/tree-outof-ssa.c | 2170 ++ gcc/tree-pass.h | 130 + gcc/tree-phinodes.c | 524 + gcc/tree-pretty-print.c | 2267 ++ gcc/tree-profile.c | 188 + gcc/tree-simple.c | 642 + gcc/tree-simple.h | 127 + gcc/tree-sra.c | 1193 + gcc/tree-ssa-alias.c | 2118 ++ gcc/tree-ssa-ccp.c | 2393 ++ gcc/tree-ssa-copy.c | 355 + gcc/tree-ssa-copyrename.c | 388 + gcc/tree-ssa-dce.c | 911 + gcc/tree-ssa-dom.c | 3121 +++ gcc/tree-ssa-dse.c | 445 + gcc/tree-ssa-forwprop.c | 445 + gcc/tree-ssa-live.c | 1912 ++ gcc/tree-ssa-live.h | 747 + gcc/tree-ssa-loop.c | 365 + gcc/tree-ssa-operands.c | 1318 ++ gcc/tree-ssa-operands.h | 97 + gcc/tree-ssa-phiopt.c | 306 + gcc/tree-ssa-pre.c | 3388 +++ gcc/tree-ssa.c | 1099 + gcc/tree-ssanames.c | 184 + gcc/tree-tailcall.c | 932 + gcc/tree.c | 469 +- gcc/tree.def | 129 +- gcc/tree.h | 672 +- gcc/unroll.c | 4 - gcc/unwind-sjlj.c | 17 +- gcc/value-prof.c | 94 +- gcc/value-prof.h | 52 +- gcc/varasm.c | 49 +- gcc/varray.c | 25 +- gcc/varray.h | 28 + include/ChangeLog | 6 +- libbanshee/AUTHORS | 0 libbanshee/COPYING | 0 libbanshee/COPYRIGHT | 26 + libbanshee/ChangeLog | 120 + libbanshee/INSTALL | 0 libbanshee/Makefile.am | 41 + libbanshee/Makefile.in | 554 + libbanshee/NEWS | 0 libbanshee/README | 11 + libbanshee/acinclude.m4 | 27 + libbanshee/aclocal.m4 | 928 + libbanshee/config.h.in | 110 + libbanshee/configure | 5967 +++++ libbanshee/configure.in | 44 + libbanshee/engine/ChangeLog | 14 + libbanshee/engine/Makefile.am | 6 + libbanshee/engine/Makefile.in | 405 + libbanshee/engine/array.c | 96 + libbanshee/engine/array.h | 76 + libbanshee/engine/banshee.c | 67 + libbanshee/engine/banshee.h | 105 + libbanshee/engine/bool.h | 63 + libbanshee/engine/bounds.c | 89 + libbanshee/engine/bounds.h | 56 + libbanshee/engine/buffer.c | 129 + libbanshee/engine/buffer.h | 58 + libbanshee/engine/compiler.h | 48 + libbanshee/engine/dot.c | 362 + libbanshee/engine/dot.h | 126 + libbanshee/engine/flow-var.c | 181 + libbanshee/engine/flow-var.h | 76 + libbanshee/engine/flowrow-sort.c | 1107 + libbanshee/engine/flowrow-sort.h | 133 + libbanshee/engine/hash.c | 427 + libbanshee/engine/hash.h | 140 + libbanshee/engine/hashset.c | 217 + libbanshee/engine/hashset.h | 50 + libbanshee/engine/jcollection.c | 326 + libbanshee/engine/jcollection.h | 63 + libbanshee/engine/linkage.h | 44 + libbanshee/engine/list.c | 438 + libbanshee/engine/list.h | 216 + libbanshee/engine/malloc.c | 5400 +++++ libbanshee/engine/nonspec.c | 852 + libbanshee/engine/nonspec.h | 189 + libbanshee/engine/setif-sort.c | 1141 + libbanshee/engine/setif-sort.h | 134 + libbanshee/engine/setif-var.c | 226 + libbanshee/engine/setif-var.h | 72 + libbanshee/engine/setst-sort.c | 907 + libbanshee/engine/setst-sort.h | 121 + libbanshee/engine/setst-var.c | 249 + libbanshee/engine/setst-var.h | 77 + libbanshee/engine/stamp.c | 120 + libbanshee/engine/stamp.h | 57 + libbanshee/engine/term-sort.c | 291 + libbanshee/engine/term-sort.h | 101 + libbanshee/engine/term-var.c | 133 + libbanshee/engine/term-var.h | 60 + libbanshee/engine/termhash.c | 262 + libbanshee/engine/termhash.h | 48 + libbanshee/engine/ufind.c | 177 + libbanshee/engine/ufind.h | 178 + libbanshee/engine/util.c | 201 + libbanshee/engine/util.h | 108 + libbanshee/libcompat/Makefile.am | 4 + libbanshee/libcompat/Makefile.in | 365 + libbanshee/libcompat/alloc.c | 133 + libbanshee/libcompat/pages.c | 459 + libbanshee/libcompat/profile.c | 521 + libbanshee/libcompat/profile.h | 59 + libbanshee/libcompat/radix-tree.c | 364 + libbanshee/libcompat/radix-tree.h | 51 + libbanshee/libcompat/regions.c | 387 + libbanshee/libcompat/regions.h | 86 + libbanshee/points-to/Makefile.am | 4 + libbanshee/points-to/Makefile.in | 364 + libbanshee/points-to/andersen_terms.c | 1363 ++ libbanshee/points-to/andersen_terms.h | 100 + libbanshee/points-to/andersen_terms.spec | 34 + libbanshee/points-to/andersen_terms_st.spec | 34 + libbanshee/stamp-h.in | 1 + libgfortran/AUTHORS | 2 + libgfortran/COPYING | 504 + libgfortran/ChangeLog | 753 + libgfortran/INSTALL | 1 + libgfortran/Makefile.am | 464 + libgfortran/Makefile.in | 5479 +++++ libgfortran/NEWS | 1 + libgfortran/README | 14 + libgfortran/acinclude.m4 | 85 + libgfortran/aclocal.m4 | 958 + libgfortran/config.h.in | 106 + libgfortran/configure | 8133 +++++++ libgfortran/configure.in | 88 + libgfortran/fmain.c | 22 + libgfortran/generated/_abs_c4.f90 | 29 + libgfortran/generated/_abs_c8.f90 | 29 + libgfortran/generated/_abs_i4.f90 | 29 + libgfortran/generated/_abs_i8.f90 | 29 + libgfortran/generated/_abs_r4.f90 | 29 + libgfortran/generated/_abs_r8.f90 | 29 + libgfortran/generated/_acos_r4.f90 | 29 + libgfortran/generated/_acos_r8.f90 | 29 + libgfortran/generated/_aint_r4.f90 | 29 + libgfortran/generated/_aint_r8.f90 | 29 + libgfortran/generated/_anint_r4.f90 | 29 + libgfortran/generated/_anint_r8.f90 | 29 + libgfortran/generated/_asin_r4.f90 | 29 + libgfortran/generated/_asin_r8.f90 | 29 + libgfortran/generated/_atan2_r4.f90 | 29 + libgfortran/generated/_atan2_r8.f90 | 29 + libgfortran/generated/_atan_r4.f90 | 29 + libgfortran/generated/_atan_r8.f90 | 29 + libgfortran/generated/_conjg_c4.f90 | 29 + libgfortran/generated/_conjg_c8.f90 | 29 + libgfortran/generated/_cos_c4.f90 | 29 + libgfortran/generated/_cos_c8.f90 | 29 + libgfortran/generated/_cos_r4.f90 | 29 + libgfortran/generated/_cos_r8.f90 | 29 + libgfortran/generated/_cosh_r4.f90 | 29 + libgfortran/generated/_cosh_r8.f90 | 29 + libgfortran/generated/_dim_i4.f90 | 29 + libgfortran/generated/_dim_i8.f90 | 29 + libgfortran/generated/_dim_r4.f90 | 29 + libgfortran/generated/_dim_r8.f90 | 29 + libgfortran/generated/_exp_c4.f90 | 29 + libgfortran/generated/_exp_c8.f90 | 29 + libgfortran/generated/_exp_r4.f90 | 29 + libgfortran/generated/_exp_r8.f90 | 29 + libgfortran/generated/_log10_r4.f90 | 29 + libgfortran/generated/_log10_r8.f90 | 29 + libgfortran/generated/_log_c4.f90 | 29 + libgfortran/generated/_log_c8.f90 | 29 + libgfortran/generated/_log_r4.f90 | 29 + libgfortran/generated/_log_r8.f90 | 29 + libgfortran/generated/_mod_i4.f90 | 29 + libgfortran/generated/_mod_i8.f90 | 29 + libgfortran/generated/_mod_r4.f90 | 29 + libgfortran/generated/_mod_r8.f90 | 29 + libgfortran/generated/_sign_i4.f90 | 29 + libgfortran/generated/_sign_i8.f90 | 29 + libgfortran/generated/_sign_r4.f90 | 29 + libgfortran/generated/_sign_r8.f90 | 29 + libgfortran/generated/_sin_c4.f90 | 29 + libgfortran/generated/_sin_c8.f90 | 29 + libgfortran/generated/_sin_r4.f90 | 29 + libgfortran/generated/_sin_r8.f90 | 29 + libgfortran/generated/_sinh_r4.f90 | 29 + libgfortran/generated/_sinh_r8.f90 | 29 + libgfortran/generated/_sqrt_c4.f90 | 29 + libgfortran/generated/_sqrt_c8.f90 | 29 + libgfortran/generated/_sqrt_r4.f90 | 29 + libgfortran/generated/_sqrt_r8.f90 | 29 + libgfortran/generated/_tan_r4.f90 | 29 + libgfortran/generated/_tan_r8.f90 | 29 + libgfortran/generated/_tanh_r4.f90 | 29 + libgfortran/generated/_tanh_r8.f90 | 29 + libgfortran/generated/all_l4.c | 133 + libgfortran/generated/all_l8.c | 133 + libgfortran/generated/any_l4.c | 133 + libgfortran/generated/any_l8.c | 133 + libgfortran/generated/count_4_l4.c | 129 + libgfortran/generated/count_4_l8.c | 129 + libgfortran/generated/count_8_l4.c | 129 + libgfortran/generated/count_8_l8.c | 129 + libgfortran/generated/cshift1_4.c | 170 + libgfortran/generated/cshift1_8.c | 170 + libgfortran/generated/dotprod_c4.c | 67 + libgfortran/generated/dotprod_c8.c | 67 + libgfortran/generated/dotprod_i4.c | 64 + libgfortran/generated/dotprod_i8.c | 64 + libgfortran/generated/dotprod_l4.c | 74 + libgfortran/generated/dotprod_l8.c | 74 + libgfortran/generated/dotprod_r4.c | 64 + libgfortran/generated/dotprod_r8.c | 64 + libgfortran/generated/eoshift1_4.c | 178 + libgfortran/generated/eoshift1_8.c | 178 + libgfortran/generated/eoshift3_4.c | 193 + libgfortran/generated/eoshift3_8.c | 193 + libgfortran/generated/exp_c4.c | 139 + libgfortran/generated/exp_c8.c | 139 + libgfortran/generated/exponent_r4.c | 31 + libgfortran/generated/exponent_r8.c | 31 + libgfortran/generated/fraction_r4.c | 30 + libgfortran/generated/fraction_r8.c | 30 + libgfortran/generated/hyp_c4.c | 71 + libgfortran/generated/hyp_c8.c | 71 + libgfortran/generated/in_pack_i4.c | 115 + libgfortran/generated/in_pack_i8.c | 115 + libgfortran/generated/in_unpack_i4.c | 102 + libgfortran/generated/in_unpack_i8.c | 102 + libgfortran/generated/matmul_c4.c | 138 + libgfortran/generated/matmul_c8.c | 138 + libgfortran/generated/matmul_i4.c | 138 + libgfortran/generated/matmul_i8.c | 138 + libgfortran/generated/matmul_l4.c | 151 + libgfortran/generated/matmul_l8.c | 151 + libgfortran/generated/matmul_r4.c | 138 + libgfortran/generated/matmul_r8.c | 138 + libgfortran/generated/maxloc0_4_i4.c | 230 + libgfortran/generated/maxloc0_4_i8.c | 230 + libgfortran/generated/maxloc0_4_r4.c | 230 + libgfortran/generated/maxloc0_4_r8.c | 230 + libgfortran/generated/maxloc0_8_i4.c | 230 + libgfortran/generated/maxloc0_8_i8.c | 230 + libgfortran/generated/maxloc0_8_r4.c | 230 + libgfortran/generated/maxloc0_8_r8.c | 230 + libgfortran/generated/maxloc1_4_i4.c | 266 + libgfortran/generated/maxloc1_4_i8.c | 266 + libgfortran/generated/maxloc1_4_r4.c | 266 + libgfortran/generated/maxloc1_4_r8.c | 266 + libgfortran/generated/maxloc1_8_i4.c | 266 + libgfortran/generated/maxloc1_8_i8.c | 266 + libgfortran/generated/maxloc1_8_r4.c | 266 + libgfortran/generated/maxloc1_8_r8.c | 266 + libgfortran/generated/maxval_i4.c | 255 + libgfortran/generated/maxval_i8.c | 255 + libgfortran/generated/maxval_r4.c | 255 + libgfortran/generated/maxval_r8.c | 255 + libgfortran/generated/minloc0_4_i4.c | 230 + libgfortran/generated/minloc0_4_i8.c | 230 + libgfortran/generated/minloc0_4_r4.c | 230 + libgfortran/generated/minloc0_4_r8.c | 230 + libgfortran/generated/minloc0_8_i4.c | 230 + libgfortran/generated/minloc0_8_i8.c | 230 + libgfortran/generated/minloc0_8_r4.c | 230 + libgfortran/generated/minloc0_8_r8.c | 230 + libgfortran/generated/minloc1_4_i4.c | 266 + libgfortran/generated/minloc1_4_i8.c | 266 + libgfortran/generated/minloc1_4_r4.c | 266 + libgfortran/generated/minloc1_4_r8.c | 266 + libgfortran/generated/minloc1_8_i4.c | 266 + libgfortran/generated/minloc1_8_i8.c | 266 + libgfortran/generated/minloc1_8_r4.c | 266 + libgfortran/generated/minloc1_8_r8.c | 266 + libgfortran/generated/minval_i4.c | 255 + libgfortran/generated/minval_i8.c | 255 + libgfortran/generated/minval_r4.c | 255 + libgfortran/generated/minval_r8.c | 255 + libgfortran/generated/nearest_r4.c | 38 + libgfortran/generated/nearest_r8.c | 38 + libgfortran/generated/product_c4.c | 253 + libgfortran/generated/product_c8.c | 253 + libgfortran/generated/product_i4.c | 253 + libgfortran/generated/product_i8.c | 253 + libgfortran/generated/product_r4.c | 253 + libgfortran/generated/product_r8.c | 253 + libgfortran/generated/reshape_i4.c | 225 + libgfortran/generated/reshape_i8.c | 225 + libgfortran/generated/set_exponent_r4.c | 30 + libgfortran/generated/set_exponent_r8.c | 30 + libgfortran/generated/shape_i4.c | 43 + libgfortran/generated/shape_i8.c | 43 + libgfortran/generated/sum_c4.c | 252 + libgfortran/generated/sum_c8.c | 252 + libgfortran/generated/sum_i4.c | 252 + libgfortran/generated/sum_i8.c | 252 + libgfortran/generated/sum_r4.c | 252 + libgfortran/generated/sum_r8.c | 252 + libgfortran/generated/transpose_i4.c | 69 + libgfortran/generated/transpose_i8.c | 69 + libgfortran/generated/trig_c4.c | 71 + libgfortran/generated/trig_c8.c | 71 + libgfortran/intrinsics/abort.c | 31 + libgfortran/intrinsics/associated.c | 50 + libgfortran/intrinsics/cpu_time.c | 116 + libgfortran/intrinsics/cshift0.c | 169 + libgfortran/intrinsics/dprod_r8.f90 | 27 + libgfortran/intrinsics/eoshift0.c | 188 + libgfortran/intrinsics/eoshift2.c | 204 + libgfortran/intrinsics/ishftc.c | 64 + libgfortran/intrinsics/pack_generic.c | 146 + libgfortran/intrinsics/random.c | 362 + libgfortran/intrinsics/reshape_generic.c | 231 + libgfortran/intrinsics/reshape_packed.c | 46 + libgfortran/intrinsics/selected_kind.f90 | 90 + libgfortran/intrinsics/size.c | 56 + libgfortran/intrinsics/spread_generic.c | 118 + libgfortran/intrinsics/string_intrinsics.c | 394 + libgfortran/intrinsics/transpose_generic.c | 74 + libgfortran/intrinsics/unpack_generic.c | 154 + libgfortran/io/backspace.c | 160 + libgfortran/io/close.c | 70 + libgfortran/io/endfile.c | 46 + libgfortran/io/format.c | 1285 + libgfortran/io/inquire.c | 371 + libgfortran/io/io.h | 653 + libgfortran/io/list_read.c | 1531 ++ libgfortran/io/lock.c | 84 + libgfortran/io/open.c | 528 + libgfortran/io/read.c | 793 + libgfortran/io/rewind.c | 56 + libgfortran/io/transfer.c | 1498 ++ libgfortran/io/unit.c | 380 + libgfortran/io/unix.c | 1432 ++ libgfortran/io/write.c | 1129 + libgfortran/libgfortran.h | 400 + libgfortran/m4/all.m4 | 37 + libgfortran/m4/any.m4 | 37 + libgfortran/m4/cexp.m4 | 140 + libgfortran/m4/chyp.m4 | 72 + libgfortran/m4/count.m4 | 33 + libgfortran/m4/cshift1.m4 | 175 + libgfortran/m4/ctrig.m4 | 72 + libgfortran/m4/dotprod.m4 | 71 + libgfortran/m4/dotprodc.m4 | 74 + libgfortran/m4/dotprodl.m4 | 79 + libgfortran/m4/eoshift1.m4 | 183 + libgfortran/m4/eoshift3.m4 | 198 + libgfortran/m4/exponent.m4 | 32 + libgfortran/m4/fraction.m4 | 31 + libgfortran/m4/head.m4 | 21 + libgfortran/m4/iforeach.m4 | 196 + libgfortran/m4/ifunction.m4 | 256 + libgfortran/m4/in_pack.m4 | 122 + libgfortran/m4/in_unpack.m4 | 109 + libgfortran/m4/iparm.m4 | 26 + libgfortran/m4/matmul.m4 | 145 + libgfortran/m4/matmull.m4 | 157 + libgfortran/m4/maxloc0.m4 | 54 + libgfortran/m4/maxloc1.m4 | 50 + libgfortran/m4/maxval.m4 | 39 + libgfortran/m4/minloc0.m4 | 54 + libgfortran/m4/minloc1.m4 | 50 + libgfortran/m4/minval.m4 | 39 + libgfortran/m4/mtype.m4 | 5 + libgfortran/m4/nearest.m4 | 39 + libgfortran/m4/product.m4 | 37 + libgfortran/m4/reshape.m4 | 232 + libgfortran/m4/set_exponent.m4 | 31 + libgfortran/m4/shape.m4 | 48 + libgfortran/m4/specific.m4 | 16 + libgfortran/m4/specific2.m4 | 16 + libgfortran/m4/sum.m4 | 36 + libgfortran/m4/transpose.m4 | 75 + libgfortran/m4/types.m4 | 4 + libgfortran/runtime/environ.c | 678 + libgfortran/runtime/error.c | 538 + libgfortran/runtime/in_pack_generic.c | 123 + libgfortran/runtime/in_unpack_generic.c | 120 + libgfortran/runtime/main.c | 113 + libgfortran/runtime/memory.c | 312 + libgfortran/runtime/pause.c | 71 + libgfortran/runtime/select.c | 125 + libgfortran/runtime/stop.c | 56 + libgfortran/runtime/string.c | 120 + libmudflap/ChangeLog | 957 + libmudflap/Makefile.am | 388 + libmudflap/Makefile.in | 918 + libmudflap/acinclude.m4 | 928 + libmudflap/aclocal.m4 | 1066 + libmudflap/config.h.in | 62 + libmudflap/configure | 3218 +++ libmudflap/configure.in | 137 + libmudflap/mf-heuristics.c | 174 + libmudflap/mf-hooks1.c | 478 + libmudflap/mf-hooks2.c | 1767 ++ libmudflap/mf-hooks3.c | 573 + libmudflap/mf-impl.h | 389 + libmudflap/mf-runtime.c | 2431 ++ libmudflap/mf-runtime.h.in | 191 + libmudflap/stamp-h.in | 0 libmudflap/testsuite/Makefile.am | 18 + libmudflap/testsuite/Makefile.in | 249 + libmudflap/testsuite/config/default.exp | 2 + libmudflap/testsuite/lib/libmudflap.exp | 237 + libmudflap/testsuite/lib/mfdg.exp | 377 + .../testsuite/libmudflap.c++/c++frags.exp | 16 + .../testsuite/libmudflap.c++/fail24-frag.cxx | 16 + .../testsuite/libmudflap.c++/pass27-frag.cxx | 12 + .../testsuite/libmudflap.c++/pass28-frag.cxx | 20 + .../testsuite/libmudflap.c++/pass31-frag.cxx | 12 + .../testsuite/libmudflap.c++/pass41-frag.cxx | 10 + libmudflap/testsuite/libmudflap.c/cfrags.exp | 15 + .../testsuite/libmudflap.c/fail1-frag.c | 13 + .../testsuite/libmudflap.c/fail10-frag.c | 16 + .../testsuite/libmudflap.c/fail11-frag.c | 19 + .../testsuite/libmudflap.c/fail12-frag.c | 19 + .../testsuite/libmudflap.c/fail13-frag.c | 26 + .../testsuite/libmudflap.c/fail14-frag.c | 29 + .../testsuite/libmudflap.c/fail15-frag.c | 27 + .../testsuite/libmudflap.c/fail16-frag.c | 26 + .../testsuite/libmudflap.c/fail17-frag.c | 18 + .../testsuite/libmudflap.c/fail18-frag.c | 16 + .../testsuite/libmudflap.c/fail19-frag.c | 18 + .../testsuite/libmudflap.c/fail2-frag.c | 13 + .../testsuite/libmudflap.c/fail20-frag.c | 13 + .../testsuite/libmudflap.c/fail21-frag.c | 18 + .../testsuite/libmudflap.c/fail22-frag.c | 17 + .../testsuite/libmudflap.c/fail23-frag.c | 16 + .../testsuite/libmudflap.c/fail25-frag.c | 18 + .../testsuite/libmudflap.c/fail26-frag.c | 24 + .../testsuite/libmudflap.c/fail27-frag.c | 24 + .../testsuite/libmudflap.c/fail28-frag.c | 18 + .../testsuite/libmudflap.c/fail29-frag.c | 17 + .../testsuite/libmudflap.c/fail3-frag.c | 13 + .../testsuite/libmudflap.c/fail30-frag.c | 18 + .../testsuite/libmudflap.c/fail31-frag.c | 22 + .../testsuite/libmudflap.c/fail4-frag.c | 13 + .../testsuite/libmudflap.c/fail5-frag.c | 14 + .../testsuite/libmudflap.c/fail6-frag.c | 17 + .../testsuite/libmudflap.c/fail7-frag.c | 17 + .../testsuite/libmudflap.c/fail8-frag.c | 19 + .../testsuite/libmudflap.c/fail9-frag.c | 21 + .../testsuite/libmudflap.c/hook-allocstuff.c | 16 + .../testsuite/libmudflap.c/pass-stratcliff.c | 319 + .../testsuite/libmudflap.c/pass1-frag.c | 9 + .../testsuite/libmudflap.c/pass10-frag.c | 12 + .../testsuite/libmudflap.c/pass11-frag.c | 15 + .../testsuite/libmudflap.c/pass12-frag.c | 15 + .../testsuite/libmudflap.c/pass13-frag.c | 17 + .../testsuite/libmudflap.c/pass14-frag.c | 20 + .../testsuite/libmudflap.c/pass15-frag.c | 23 + .../testsuite/libmudflap.c/pass16-frag.c | 22 + .../testsuite/libmudflap.c/pass17-frag.c | 9 + .../testsuite/libmudflap.c/pass18-frag.c | 27 + .../testsuite/libmudflap.c/pass19-frag.c | 11 + .../testsuite/libmudflap.c/pass2-frag.c | 9 + .../testsuite/libmudflap.c/pass20-frag.c | 13 + .../testsuite/libmudflap.c/pass21-frag.c | 15 + .../testsuite/libmudflap.c/pass22-frag.c | 23 + .../testsuite/libmudflap.c/pass23-frag.c | 29 + .../testsuite/libmudflap.c/pass24-frag.c | 18 + .../testsuite/libmudflap.c/pass25-frag.c | 15 + .../testsuite/libmudflap.c/pass26-frag.c | 52 + .../testsuite/libmudflap.c/pass29-frag.c | 15 + .../testsuite/libmudflap.c/pass3-frag.c | 9 + .../testsuite/libmudflap.c/pass30-frag.c | 12 + .../testsuite/libmudflap.c/pass32-frag.c | 18 + .../testsuite/libmudflap.c/pass33-frag.c | 17 + .../testsuite/libmudflap.c/pass34-frag.c | 18 + .../testsuite/libmudflap.c/pass35-frag.c | 14 + .../testsuite/libmudflap.c/pass36-frag.c | 15 + .../testsuite/libmudflap.c/pass38-frag.c | 9 + .../testsuite/libmudflap.c/pass4-frag.c | 9 + .../testsuite/libmudflap.c/pass42-frag.c | 17 + .../testsuite/libmudflap.c/pass43-frag.c | 11 + .../testsuite/libmudflap.c/pass44-frag.c | 14 + .../testsuite/libmudflap.c/pass45-frag.c | 31 + .../testsuite/libmudflap.c/pass46-frag.c | 18 + .../testsuite/libmudflap.c/pass5-frag.c | 11 + .../testsuite/libmudflap.c/pass6-frag.c | 14 + .../testsuite/libmudflap.c/pass7-frag.c | 13 + .../testsuite/libmudflap.c/pass8-frag.c | 16 + .../testsuite/libmudflap.c/pass9-frag.c | 16 + .../testsuite/libmudflap.cth/cthfrags.exp | 23 + .../testsuite/libmudflap.cth/pass37-frag.c | 58 + .../testsuite/libmudflap.cth/pass39-frag.c | 57 + .../testsuite/libmudflap.cth/pass40-frag.c | 59 + libobjc/configure | 55 +- maintainer-scripts/ChangeLog | 6 + maintainer-scripts/gcc_release | 7 +- maintainer-scripts/snapshot-README | 2 + maintainer-scripts/snapshot-index.html | 4 + 1209 files changed, 280216 insertions(+), 11375 deletions(-) create mode 100644 ChangeLog.tree-ssa create mode 100644 contrib/ChangeLog.tree-ssa create mode 100755 contrib/filter_gcc_for_doxygen create mode 100755 contrib/filter_knr2ansi.pl create mode 100755 contrib/filter_params.pl create mode 100644 contrib/tree-ssa.doxy create mode 100755 depcomp create mode 100644 gcc/ChangeLog.tree-ssa create mode 100644 gcc/ada/ChangeLog.tree-ssa create mode 100644 gcc/c-mudflap.c create mode 100644 gcc/c-simplify.c create mode 100644 gcc/cp/ChangeLog.tree-ssa create mode 100644 gcc/cp/cp-mudflap.c create mode 100644 gcc/cp/cp-simplify.c create mode 100644 gcc/doc/cfg.texi create mode 100644 gcc/doc/tree-ssa.texi create mode 100644 gcc/domwalk.c create mode 100644 gcc/domwalk.h create mode 100644 gcc/f/ChangeLog.tree-ssa create mode 100644 gcc/fortran/.cvsignore create mode 100644 gcc/fortran/CONTRIB create mode 100644 gcc/fortran/ChangeLog create mode 100644 gcc/fortran/Make-lang.in create mode 100644 gcc/fortran/NEWS create mode 100644 gcc/fortran/README create mode 100644 gcc/fortran/TODO create mode 100644 gcc/fortran/arith.c create mode 100644 gcc/fortran/arith.h create mode 100644 gcc/fortran/array.c create mode 100644 gcc/fortran/bbt.c create mode 100644 gcc/fortran/check.c create mode 100644 gcc/fortran/config-lang.in create mode 100644 gcc/fortran/convert.c create mode 100644 gcc/fortran/data.c create mode 100644 gcc/fortran/decl.c create mode 100644 gcc/fortran/dependency.c create mode 100644 gcc/fortran/dependency.h create mode 100644 gcc/fortran/dump-parse-tree.c create mode 100644 gcc/fortran/error.c create mode 100644 gcc/fortran/expr.c create mode 100644 gcc/fortran/f95-lang.c create mode 100644 gcc/fortran/gfortran.h create mode 100644 gcc/fortran/gfortran.texi create mode 100644 gcc/fortran/gfortranspec.c create mode 100644 gcc/fortran/interface.c create mode 100644 gcc/fortran/intrinsic.c create mode 100644 gcc/fortran/intrinsic.h create mode 100644 gcc/fortran/invoke.texi create mode 100644 gcc/fortran/io.c create mode 100644 gcc/fortran/iresolve.c create mode 100644 gcc/fortran/lang-specs.h create mode 100644 gcc/fortran/lang.opt create mode 100644 gcc/fortran/match.c create mode 100644 gcc/fortran/match.h create mode 100644 gcc/fortran/matchexp.c create mode 100644 gcc/fortran/mathbuiltins.def create mode 100644 gcc/fortran/misc.c create mode 100644 gcc/fortran/module.c create mode 100644 gcc/fortran/options.c create mode 100644 gcc/fortran/parse.c create mode 100644 gcc/fortran/parse.h create mode 100644 gcc/fortran/primary.c create mode 100644 gcc/fortran/resolve.c create mode 100644 gcc/fortran/scanner.c create mode 100644 gcc/fortran/simplify.c create mode 100644 gcc/fortran/st.c create mode 100644 gcc/fortran/symbol.c create mode 100644 gcc/fortran/trans-array.c create mode 100644 gcc/fortran/trans-array.h create mode 100644 gcc/fortran/trans-common.c create mode 100644 gcc/fortran/trans-const.c create mode 100644 gcc/fortran/trans-const.h create mode 100644 gcc/fortran/trans-decl.c create mode 100644 gcc/fortran/trans-expr.c create mode 100644 gcc/fortran/trans-intrinsic.c create mode 100644 gcc/fortran/trans-io.c create mode 100644 gcc/fortran/trans-stmt.c create mode 100644 gcc/fortran/trans-stmt.h create mode 100644 gcc/fortran/trans-types.c create mode 100644 gcc/fortran/trans-types.h create mode 100644 gcc/fortran/trans.c create mode 100644 gcc/fortran/trans.h create mode 100644 gcc/gimple-low.c create mode 100644 gcc/gimplify.c create mode 100644 gcc/java/ChangeLog.tree-ssa create mode 100644 gcc/java/java-gimplify.c create mode 100644 gcc/rtl-profile.c delete mode 100644 gcc/sibcall.c create mode 100644 gcc/testsuite/ChangeLog.tree-ssa create mode 100644 gcc/testsuite/g++.dg/eh/goto1.C create mode 100644 gcc/testsuite/g++.dg/ext/label3.C create mode 100644 gcc/testsuite/g++.dg/init/pmf1.C create mode 100644 gcc/testsuite/g++.dg/opt/bool1.C create mode 100644 gcc/testsuite/g++.dg/opt/cfg4.C create mode 100644 gcc/testsuite/g++.dg/opt/crash1.C create mode 100644 gcc/testsuite/g++.dg/opt/inline7.C create mode 100644 gcc/testsuite/g++.dg/opt/nothrow1.C create mode 100644 gcc/testsuite/g++.dg/opt/static4.C create mode 100644 gcc/testsuite/g++.dg/tree-ssa/20040317-1.C create mode 100644 gcc/testsuite/g++.dg/tree-ssa/nothrow-1.C create mode 100644 gcc/testsuite/g++.dg/tree-ssa/tree-ssa.exp create mode 100644 gcc/testsuite/g++.dg/warn/noeffect5.C delete mode 100644 gcc/testsuite/gcc.c-torture/compile/20010516-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030310-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030405-1.x create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030416-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030530-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030530-3.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030716-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030823-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030902-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030910-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20030917-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20031124-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20031125-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20031125-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20031203-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20031203-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20031203-3.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040219-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040220-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040303-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040303-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040309-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040310-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040317-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040317-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040317-3.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040323-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040401-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040415-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/20040415-2.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr14730.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr15245.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20020819-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20021113-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030403-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030404-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030501-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030828-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030828-2.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030903-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030909-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030910-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20030913-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20031010-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20031211-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20031211-2.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20040319-1.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/20040423-1.c delete mode 100644 gcc/testsuite/gcc.c-torture/execute/builtin-constant.x create mode 100644 gcc/testsuite/gcc.dg/20010516-1.c create mode 100644 gcc/testsuite/gcc.dg/20030805-1.c create mode 100644 gcc/testsuite/gcc.dg/20040202-1.c create mode 100644 gcc/testsuite/gcc.dg/20040206-1.c create mode 100644 gcc/testsuite/gcc.dg/pr14475.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030530-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030611-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030703-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030703-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030708-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030709-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030709-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030710-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030711-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030711-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030714-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030714-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030728-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030729-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030730-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030730-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030731-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030731-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-10.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-11.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-6.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-7.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-8.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030807-9.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030808-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030814-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030814-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030814-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030814-4.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030814-5.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030814-6.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030814-7.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030815-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030820-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030820-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030821-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030824-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030824-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030825-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030907-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030907-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030917-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030917-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030917-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030918-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030920-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030922-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20030922-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031015-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031021-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031022-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031031-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031106-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031106-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031106-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031106-4.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031106-5.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031113-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20031216-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040121-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040209-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040210-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040211-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040216-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040302-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040313-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040319-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040324-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040326-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040326-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040408-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/20040430-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/asm-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cfgcleanup-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/copy-headers.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/sra-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/sra-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/sra-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-7.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-9.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-ccp-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailcall-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailcall-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-4.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-5.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/tree-ssa.exp create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/useless-1.c create mode 100644 gcc/testsuite/gcc.dg/uninit-11.c create mode 100644 gcc/testsuite/gcc.dg/uninit-H.c create mode 100644 gcc/testsuite/gfortran.fortran-torture/ChangeLog.g95 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/actual.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/allocate.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/ambig.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/arrayio.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/bergervoet2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/compile.exp create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/contained_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/contained_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/contained_3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/contained_4.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/contained_5.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/convert.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/dummyfn.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/emptyif.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/fnresvar.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/gen_interf.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/implicit.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/io_end.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/module_common.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/module_expr.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/module_proc.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/module_result.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/named_args.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/parameter_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/parameter_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/shape_reshape.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/stoppause.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/strparm_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/write.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/a_edit_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/allocate.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/alternate_return.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/args.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/arithmeticif.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/arrayarg.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/arrayarg2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/arraysave.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/assumed_size.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/bounds.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/character_select_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/cmplx.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/common.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/common_size.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/constructor.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/contained.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/contained2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/csqrt_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/data.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/data_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/dep_fails.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/der_init.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/der_io.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/der_point.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/der_type.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/direct_io.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/elemental.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/empty_format.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/emptyif.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/execute.exp create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/f2_edit_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/forall.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/forall_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/forall_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/forall_3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/forall_4.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/forall_5.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/forall_6.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/function_module_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/hollerith.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/initializer.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/inquire_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/inquire_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/inquire_3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/inquire_4.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/integer_select.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/integer_select_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/internal_write.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_abs.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_achar.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_aint_anint.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_anyall.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_bitops.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_count.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_cshift.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dim.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dotprod.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dprod.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dummy.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_eoshift.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_fraction_exponent.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_index.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_integer.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_len.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_matmul.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_merge.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_minmax.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_4.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmval.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mod_ulo.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_nearest.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_pack.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_present.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_product.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_rrspacing.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_scale.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_set_exponent.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_shape.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_si_kind.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sign.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_size.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spacing.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spread.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sr_kind.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sum.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_transpose.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_trim.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_unpack.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/list_read_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/logical_select_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/mainsub.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/math.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/module_interface.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/module_interface_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/mystery_proc.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/nestcons.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/parameter_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/partparm.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/plusconst_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/power.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/procarg.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/ptr.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/read_eof.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/retarray.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/retarray_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/scalarize.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/scalarize2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/scalarize3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/slash_edit.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/spec_abs.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/specifics.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/st_function.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/stack_varsize.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/straret.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strarray_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strarray_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strarray_3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strarray_4.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strcmp.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strcommon_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/string.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strlen.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/strret.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/test_slice.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/unopened_unit_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/userop.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/where_1.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/where_2.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/where_3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/where_4.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/where_5.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/where_6.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/execute/write_logical.f90 create mode 100644 gcc/testsuite/lib/fortran-torture.exp create mode 100644 gcc/testsuite/lib/gfortran.exp create mode 100644 gcc/testsuite/lib/scantree.exp delete mode 100644 gcc/testsuite/treelang/compile/compile.exp delete mode 100644 gcc/testsuite/treelang/compile/tabs.tree create mode 100644 gcc/tree-alias-ander.c create mode 100644 gcc/tree-alias-ander.h create mode 100644 gcc/tree-alias-common.c create mode 100644 gcc/tree-alias-common.h create mode 100644 gcc/tree-alias-type.c create mode 100644 gcc/tree-alias-type.h create mode 100644 gcc/tree-browser.c create mode 100644 gcc/tree-browser.def create mode 100644 gcc/tree-cfg.c create mode 100644 gcc/tree-complex.c create mode 100644 gcc/tree-dfa.c create mode 100644 gcc/tree-eh.c create mode 100644 gcc/tree-flow-inline.h create mode 100644 gcc/tree-flow.h create mode 100644 gcc/tree-into-ssa.c create mode 100644 gcc/tree-iterator.c create mode 100644 gcc/tree-iterator.h create mode 100644 gcc/tree-mudflap.c create mode 100644 gcc/tree-mudflap.h create mode 100644 gcc/tree-nested.c create mode 100644 gcc/tree-nomudflap.c create mode 100644 gcc/tree-nrv.c create mode 100644 gcc/tree-outof-ssa.c create mode 100644 gcc/tree-pass.h create mode 100644 gcc/tree-phinodes.c create mode 100644 gcc/tree-pretty-print.c create mode 100644 gcc/tree-profile.c create mode 100644 gcc/tree-simple.c create mode 100644 gcc/tree-simple.h create mode 100644 gcc/tree-sra.c create mode 100644 gcc/tree-ssa-alias.c create mode 100644 gcc/tree-ssa-ccp.c create mode 100644 gcc/tree-ssa-copy.c create mode 100644 gcc/tree-ssa-copyrename.c create mode 100644 gcc/tree-ssa-dce.c create mode 100644 gcc/tree-ssa-dom.c create mode 100644 gcc/tree-ssa-dse.c create mode 100644 gcc/tree-ssa-forwprop.c create mode 100644 gcc/tree-ssa-live.c create mode 100644 gcc/tree-ssa-live.h create mode 100644 gcc/tree-ssa-loop.c create mode 100644 gcc/tree-ssa-operands.c create mode 100644 gcc/tree-ssa-operands.h create mode 100644 gcc/tree-ssa-phiopt.c create mode 100644 gcc/tree-ssa-pre.c create mode 100644 gcc/tree-ssa.c create mode 100644 gcc/tree-ssanames.c create mode 100644 gcc/tree-tailcall.c create mode 100644 libbanshee/AUTHORS create mode 100644 libbanshee/COPYING create mode 100644 libbanshee/COPYRIGHT create mode 100644 libbanshee/ChangeLog create mode 100644 libbanshee/INSTALL create mode 100644 libbanshee/Makefile.am create mode 100644 libbanshee/Makefile.in create mode 100644 libbanshee/NEWS create mode 100644 libbanshee/README create mode 100644 libbanshee/acinclude.m4 create mode 100644 libbanshee/aclocal.m4 create mode 100644 libbanshee/config.h.in create mode 100755 libbanshee/configure create mode 100644 libbanshee/configure.in create mode 100644 libbanshee/engine/ChangeLog create mode 100644 libbanshee/engine/Makefile.am create mode 100644 libbanshee/engine/Makefile.in create mode 100644 libbanshee/engine/array.c create mode 100644 libbanshee/engine/array.h create mode 100644 libbanshee/engine/banshee.c create mode 100644 libbanshee/engine/banshee.h create mode 100644 libbanshee/engine/bool.h create mode 100644 libbanshee/engine/bounds.c create mode 100644 libbanshee/engine/bounds.h create mode 100644 libbanshee/engine/buffer.c create mode 100644 libbanshee/engine/buffer.h create mode 100644 libbanshee/engine/compiler.h create mode 100644 libbanshee/engine/dot.c create mode 100644 libbanshee/engine/dot.h create mode 100644 libbanshee/engine/flow-var.c create mode 100644 libbanshee/engine/flow-var.h create mode 100644 libbanshee/engine/flowrow-sort.c create mode 100644 libbanshee/engine/flowrow-sort.h create mode 100644 libbanshee/engine/hash.c create mode 100644 libbanshee/engine/hash.h create mode 100644 libbanshee/engine/hashset.c create mode 100644 libbanshee/engine/hashset.h create mode 100644 libbanshee/engine/jcollection.c create mode 100644 libbanshee/engine/jcollection.h create mode 100644 libbanshee/engine/linkage.h create mode 100644 libbanshee/engine/list.c create mode 100644 libbanshee/engine/list.h create mode 100644 libbanshee/engine/malloc.c create mode 100644 libbanshee/engine/nonspec.c create mode 100644 libbanshee/engine/nonspec.h create mode 100644 libbanshee/engine/setif-sort.c create mode 100644 libbanshee/engine/setif-sort.h create mode 100644 libbanshee/engine/setif-var.c create mode 100644 libbanshee/engine/setif-var.h create mode 100644 libbanshee/engine/setst-sort.c create mode 100644 libbanshee/engine/setst-sort.h create mode 100644 libbanshee/engine/setst-var.c create mode 100644 libbanshee/engine/setst-var.h create mode 100644 libbanshee/engine/stamp.c create mode 100644 libbanshee/engine/stamp.h create mode 100644 libbanshee/engine/term-sort.c create mode 100644 libbanshee/engine/term-sort.h create mode 100644 libbanshee/engine/term-var.c create mode 100644 libbanshee/engine/term-var.h create mode 100644 libbanshee/engine/termhash.c create mode 100644 libbanshee/engine/termhash.h create mode 100644 libbanshee/engine/ufind.c create mode 100644 libbanshee/engine/ufind.h create mode 100644 libbanshee/engine/util.c create mode 100644 libbanshee/engine/util.h create mode 100644 libbanshee/libcompat/Makefile.am create mode 100644 libbanshee/libcompat/Makefile.in create mode 100644 libbanshee/libcompat/alloc.c create mode 100644 libbanshee/libcompat/pages.c create mode 100644 libbanshee/libcompat/profile.c create mode 100644 libbanshee/libcompat/profile.h create mode 100644 libbanshee/libcompat/radix-tree.c create mode 100644 libbanshee/libcompat/radix-tree.h create mode 100644 libbanshee/libcompat/regions.c create mode 100644 libbanshee/libcompat/regions.h create mode 100644 libbanshee/points-to/Makefile.am create mode 100644 libbanshee/points-to/Makefile.in create mode 100644 libbanshee/points-to/andersen_terms.c create mode 100644 libbanshee/points-to/andersen_terms.h create mode 100644 libbanshee/points-to/andersen_terms.spec create mode 100644 libbanshee/points-to/andersen_terms_st.spec create mode 100644 libbanshee/stamp-h.in create mode 100644 libgfortran/AUTHORS create mode 100644 libgfortran/COPYING create mode 100644 libgfortran/ChangeLog create mode 100644 libgfortran/INSTALL create mode 100644 libgfortran/Makefile.am create mode 100644 libgfortran/Makefile.in create mode 100644 libgfortran/NEWS create mode 100644 libgfortran/README create mode 100644 libgfortran/acinclude.m4 create mode 100644 libgfortran/aclocal.m4 create mode 100644 libgfortran/config.h.in create mode 100755 libgfortran/configure create mode 100644 libgfortran/configure.in create mode 100644 libgfortran/fmain.c create mode 100644 libgfortran/generated/_abs_c4.f90 create mode 100644 libgfortran/generated/_abs_c8.f90 create mode 100644 libgfortran/generated/_abs_i4.f90 create mode 100644 libgfortran/generated/_abs_i8.f90 create mode 100644 libgfortran/generated/_abs_r4.f90 create mode 100644 libgfortran/generated/_abs_r8.f90 create mode 100644 libgfortran/generated/_acos_r4.f90 create mode 100644 libgfortran/generated/_acos_r8.f90 create mode 100644 libgfortran/generated/_aint_r4.f90 create mode 100644 libgfortran/generated/_aint_r8.f90 create mode 100644 libgfortran/generated/_anint_r4.f90 create mode 100644 libgfortran/generated/_anint_r8.f90 create mode 100644 libgfortran/generated/_asin_r4.f90 create mode 100644 libgfortran/generated/_asin_r8.f90 create mode 100644 libgfortran/generated/_atan2_r4.f90 create mode 100644 libgfortran/generated/_atan2_r8.f90 create mode 100644 libgfortran/generated/_atan_r4.f90 create mode 100644 libgfortran/generated/_atan_r8.f90 create mode 100644 libgfortran/generated/_conjg_c4.f90 create mode 100644 libgfortran/generated/_conjg_c8.f90 create mode 100644 libgfortran/generated/_cos_c4.f90 create mode 100644 libgfortran/generated/_cos_c8.f90 create mode 100644 libgfortran/generated/_cos_r4.f90 create mode 100644 libgfortran/generated/_cos_r8.f90 create mode 100644 libgfortran/generated/_cosh_r4.f90 create mode 100644 libgfortran/generated/_cosh_r8.f90 create mode 100644 libgfortran/generated/_dim_i4.f90 create mode 100644 libgfortran/generated/_dim_i8.f90 create mode 100644 libgfortran/generated/_dim_r4.f90 create mode 100644 libgfortran/generated/_dim_r8.f90 create mode 100644 libgfortran/generated/_exp_c4.f90 create mode 100644 libgfortran/generated/_exp_c8.f90 create mode 100644 libgfortran/generated/_exp_r4.f90 create mode 100644 libgfortran/generated/_exp_r8.f90 create mode 100644 libgfortran/generated/_log10_r4.f90 create mode 100644 libgfortran/generated/_log10_r8.f90 create mode 100644 libgfortran/generated/_log_c4.f90 create mode 100644 libgfortran/generated/_log_c8.f90 create mode 100644 libgfortran/generated/_log_r4.f90 create mode 100644 libgfortran/generated/_log_r8.f90 create mode 100644 libgfortran/generated/_mod_i4.f90 create mode 100644 libgfortran/generated/_mod_i8.f90 create mode 100644 libgfortran/generated/_mod_r4.f90 create mode 100644 libgfortran/generated/_mod_r8.f90 create mode 100644 libgfortran/generated/_sign_i4.f90 create mode 100644 libgfortran/generated/_sign_i8.f90 create mode 100644 libgfortran/generated/_sign_r4.f90 create mode 100644 libgfortran/generated/_sign_r8.f90 create mode 100644 libgfortran/generated/_sin_c4.f90 create mode 100644 libgfortran/generated/_sin_c8.f90 create mode 100644 libgfortran/generated/_sin_r4.f90 create mode 100644 libgfortran/generated/_sin_r8.f90 create mode 100644 libgfortran/generated/_sinh_r4.f90 create mode 100644 libgfortran/generated/_sinh_r8.f90 create mode 100644 libgfortran/generated/_sqrt_c4.f90 create mode 100644 libgfortran/generated/_sqrt_c8.f90 create mode 100644 libgfortran/generated/_sqrt_r4.f90 create mode 100644 libgfortran/generated/_sqrt_r8.f90 create mode 100644 libgfortran/generated/_tan_r4.f90 create mode 100644 libgfortran/generated/_tan_r8.f90 create mode 100644 libgfortran/generated/_tanh_r4.f90 create mode 100644 libgfortran/generated/_tanh_r8.f90 create mode 100644 libgfortran/generated/all_l4.c create mode 100644 libgfortran/generated/all_l8.c create mode 100644 libgfortran/generated/any_l4.c create mode 100644 libgfortran/generated/any_l8.c create mode 100644 libgfortran/generated/count_4_l4.c create mode 100644 libgfortran/generated/count_4_l8.c create mode 100644 libgfortran/generated/count_8_l4.c create mode 100644 libgfortran/generated/count_8_l8.c create mode 100644 libgfortran/generated/cshift1_4.c create mode 100644 libgfortran/generated/cshift1_8.c create mode 100644 libgfortran/generated/dotprod_c4.c create mode 100644 libgfortran/generated/dotprod_c8.c create mode 100644 libgfortran/generated/dotprod_i4.c create mode 100644 libgfortran/generated/dotprod_i8.c create mode 100644 libgfortran/generated/dotprod_l4.c create mode 100644 libgfortran/generated/dotprod_l8.c create mode 100644 libgfortran/generated/dotprod_r4.c create mode 100644 libgfortran/generated/dotprod_r8.c create mode 100644 libgfortran/generated/eoshift1_4.c create mode 100644 libgfortran/generated/eoshift1_8.c create mode 100644 libgfortran/generated/eoshift3_4.c create mode 100644 libgfortran/generated/eoshift3_8.c create mode 100644 libgfortran/generated/exp_c4.c create mode 100644 libgfortran/generated/exp_c8.c create mode 100644 libgfortran/generated/exponent_r4.c create mode 100644 libgfortran/generated/exponent_r8.c create mode 100644 libgfortran/generated/fraction_r4.c create mode 100644 libgfortran/generated/fraction_r8.c create mode 100644 libgfortran/generated/hyp_c4.c create mode 100644 libgfortran/generated/hyp_c8.c create mode 100644 libgfortran/generated/in_pack_i4.c create mode 100644 libgfortran/generated/in_pack_i8.c create mode 100644 libgfortran/generated/in_unpack_i4.c create mode 100644 libgfortran/generated/in_unpack_i8.c create mode 100644 libgfortran/generated/matmul_c4.c create mode 100644 libgfortran/generated/matmul_c8.c create mode 100644 libgfortran/generated/matmul_i4.c create mode 100644 libgfortran/generated/matmul_i8.c create mode 100644 libgfortran/generated/matmul_l4.c create mode 100644 libgfortran/generated/matmul_l8.c create mode 100644 libgfortran/generated/matmul_r4.c create mode 100644 libgfortran/generated/matmul_r8.c create mode 100644 libgfortran/generated/maxloc0_4_i4.c create mode 100644 libgfortran/generated/maxloc0_4_i8.c create mode 100644 libgfortran/generated/maxloc0_4_r4.c create mode 100644 libgfortran/generated/maxloc0_4_r8.c create mode 100644 libgfortran/generated/maxloc0_8_i4.c create mode 100644 libgfortran/generated/maxloc0_8_i8.c create mode 100644 libgfortran/generated/maxloc0_8_r4.c create mode 100644 libgfortran/generated/maxloc0_8_r8.c create mode 100644 libgfortran/generated/maxloc1_4_i4.c create mode 100644 libgfortran/generated/maxloc1_4_i8.c create mode 100644 libgfortran/generated/maxloc1_4_r4.c create mode 100644 libgfortran/generated/maxloc1_4_r8.c create mode 100644 libgfortran/generated/maxloc1_8_i4.c create mode 100644 libgfortran/generated/maxloc1_8_i8.c create mode 100644 libgfortran/generated/maxloc1_8_r4.c create mode 100644 libgfortran/generated/maxloc1_8_r8.c create mode 100644 libgfortran/generated/maxval_i4.c create mode 100644 libgfortran/generated/maxval_i8.c create mode 100644 libgfortran/generated/maxval_r4.c create mode 100644 libgfortran/generated/maxval_r8.c create mode 100644 libgfortran/generated/minloc0_4_i4.c create mode 100644 libgfortran/generated/minloc0_4_i8.c create mode 100644 libgfortran/generated/minloc0_4_r4.c create mode 100644 libgfortran/generated/minloc0_4_r8.c create mode 100644 libgfortran/generated/minloc0_8_i4.c create mode 100644 libgfortran/generated/minloc0_8_i8.c create mode 100644 libgfortran/generated/minloc0_8_r4.c create mode 100644 libgfortran/generated/minloc0_8_r8.c create mode 100644 libgfortran/generated/minloc1_4_i4.c create mode 100644 libgfortran/generated/minloc1_4_i8.c create mode 100644 libgfortran/generated/minloc1_4_r4.c create mode 100644 libgfortran/generated/minloc1_4_r8.c create mode 100644 libgfortran/generated/minloc1_8_i4.c create mode 100644 libgfortran/generated/minloc1_8_i8.c create mode 100644 libgfortran/generated/minloc1_8_r4.c create mode 100644 libgfortran/generated/minloc1_8_r8.c create mode 100644 libgfortran/generated/minval_i4.c create mode 100644 libgfortran/generated/minval_i8.c create mode 100644 libgfortran/generated/minval_r4.c create mode 100644 libgfortran/generated/minval_r8.c create mode 100644 libgfortran/generated/nearest_r4.c create mode 100644 libgfortran/generated/nearest_r8.c create mode 100644 libgfortran/generated/product_c4.c create mode 100644 libgfortran/generated/product_c8.c create mode 100644 libgfortran/generated/product_i4.c create mode 100644 libgfortran/generated/product_i8.c create mode 100644 libgfortran/generated/product_r4.c create mode 100644 libgfortran/generated/product_r8.c create mode 100644 libgfortran/generated/reshape_i4.c create mode 100644 libgfortran/generated/reshape_i8.c create mode 100644 libgfortran/generated/set_exponent_r4.c create mode 100644 libgfortran/generated/set_exponent_r8.c create mode 100644 libgfortran/generated/shape_i4.c create mode 100644 libgfortran/generated/shape_i8.c create mode 100644 libgfortran/generated/sum_c4.c create mode 100644 libgfortran/generated/sum_c8.c create mode 100644 libgfortran/generated/sum_i4.c create mode 100644 libgfortran/generated/sum_i8.c create mode 100644 libgfortran/generated/sum_r4.c create mode 100644 libgfortran/generated/sum_r8.c create mode 100644 libgfortran/generated/transpose_i4.c create mode 100644 libgfortran/generated/transpose_i8.c create mode 100644 libgfortran/generated/trig_c4.c create mode 100644 libgfortran/generated/trig_c8.c create mode 100644 libgfortran/intrinsics/abort.c create mode 100644 libgfortran/intrinsics/associated.c create mode 100644 libgfortran/intrinsics/cpu_time.c create mode 100644 libgfortran/intrinsics/cshift0.c create mode 100644 libgfortran/intrinsics/dprod_r8.f90 create mode 100644 libgfortran/intrinsics/eoshift0.c create mode 100644 libgfortran/intrinsics/eoshift2.c create mode 100644 libgfortran/intrinsics/ishftc.c create mode 100644 libgfortran/intrinsics/pack_generic.c create mode 100644 libgfortran/intrinsics/random.c create mode 100644 libgfortran/intrinsics/reshape_generic.c create mode 100644 libgfortran/intrinsics/reshape_packed.c create mode 100644 libgfortran/intrinsics/selected_kind.f90 create mode 100644 libgfortran/intrinsics/size.c create mode 100644 libgfortran/intrinsics/spread_generic.c create mode 100644 libgfortran/intrinsics/string_intrinsics.c create mode 100644 libgfortran/intrinsics/transpose_generic.c create mode 100644 libgfortran/intrinsics/unpack_generic.c create mode 100644 libgfortran/io/backspace.c create mode 100644 libgfortran/io/close.c create mode 100644 libgfortran/io/endfile.c create mode 100644 libgfortran/io/format.c create mode 100644 libgfortran/io/inquire.c create mode 100644 libgfortran/io/io.h create mode 100644 libgfortran/io/list_read.c create mode 100644 libgfortran/io/lock.c create mode 100644 libgfortran/io/open.c create mode 100644 libgfortran/io/read.c create mode 100644 libgfortran/io/rewind.c create mode 100644 libgfortran/io/transfer.c create mode 100644 libgfortran/io/unit.c create mode 100644 libgfortran/io/unix.c create mode 100644 libgfortran/io/write.c create mode 100644 libgfortran/libgfortran.h create mode 100644 libgfortran/m4/all.m4 create mode 100644 libgfortran/m4/any.m4 create mode 100644 libgfortran/m4/cexp.m4 create mode 100644 libgfortran/m4/chyp.m4 create mode 100644 libgfortran/m4/count.m4 create mode 100644 libgfortran/m4/cshift1.m4 create mode 100644 libgfortran/m4/ctrig.m4 create mode 100644 libgfortran/m4/dotprod.m4 create mode 100644 libgfortran/m4/dotprodc.m4 create mode 100644 libgfortran/m4/dotprodl.m4 create mode 100644 libgfortran/m4/eoshift1.m4 create mode 100644 libgfortran/m4/eoshift3.m4 create mode 100644 libgfortran/m4/exponent.m4 create mode 100644 libgfortran/m4/fraction.m4 create mode 100644 libgfortran/m4/head.m4 create mode 100644 libgfortran/m4/iforeach.m4 create mode 100644 libgfortran/m4/ifunction.m4 create mode 100644 libgfortran/m4/in_pack.m4 create mode 100644 libgfortran/m4/in_unpack.m4 create mode 100644 libgfortran/m4/iparm.m4 create mode 100644 libgfortran/m4/matmul.m4 create mode 100644 libgfortran/m4/matmull.m4 create mode 100644 libgfortran/m4/maxloc0.m4 create mode 100644 libgfortran/m4/maxloc1.m4 create mode 100644 libgfortran/m4/maxval.m4 create mode 100644 libgfortran/m4/minloc0.m4 create mode 100644 libgfortran/m4/minloc1.m4 create mode 100644 libgfortran/m4/minval.m4 create mode 100644 libgfortran/m4/mtype.m4 create mode 100644 libgfortran/m4/nearest.m4 create mode 100644 libgfortran/m4/product.m4 create mode 100644 libgfortran/m4/reshape.m4 create mode 100644 libgfortran/m4/set_exponent.m4 create mode 100644 libgfortran/m4/shape.m4 create mode 100644 libgfortran/m4/specific.m4 create mode 100644 libgfortran/m4/specific2.m4 create mode 100644 libgfortran/m4/sum.m4 create mode 100644 libgfortran/m4/transpose.m4 create mode 100644 libgfortran/m4/types.m4 create mode 100644 libgfortran/runtime/environ.c create mode 100644 libgfortran/runtime/error.c create mode 100644 libgfortran/runtime/in_pack_generic.c create mode 100644 libgfortran/runtime/in_unpack_generic.c create mode 100644 libgfortran/runtime/main.c create mode 100644 libgfortran/runtime/memory.c create mode 100644 libgfortran/runtime/pause.c create mode 100644 libgfortran/runtime/select.c create mode 100644 libgfortran/runtime/stop.c create mode 100644 libgfortran/runtime/string.c create mode 100644 libmudflap/ChangeLog create mode 100644 libmudflap/Makefile.am create mode 100644 libmudflap/Makefile.in create mode 100644 libmudflap/acinclude.m4 create mode 100644 libmudflap/aclocal.m4 create mode 100644 libmudflap/config.h.in create mode 100755 libmudflap/configure create mode 100644 libmudflap/configure.in create mode 100644 libmudflap/mf-heuristics.c create mode 100644 libmudflap/mf-hooks1.c create mode 100644 libmudflap/mf-hooks2.c create mode 100644 libmudflap/mf-hooks3.c create mode 100644 libmudflap/mf-impl.h create mode 100644 libmudflap/mf-runtime.c create mode 100644 libmudflap/mf-runtime.h.in create mode 100644 libmudflap/stamp-h.in create mode 100644 libmudflap/testsuite/Makefile.am create mode 100644 libmudflap/testsuite/Makefile.in create mode 100644 libmudflap/testsuite/config/default.exp create mode 100644 libmudflap/testsuite/lib/libmudflap.exp create mode 100644 libmudflap/testsuite/lib/mfdg.exp create mode 100644 libmudflap/testsuite/libmudflap.c++/c++frags.exp create mode 100644 libmudflap/testsuite/libmudflap.c++/fail24-frag.cxx create mode 100644 libmudflap/testsuite/libmudflap.c++/pass27-frag.cxx create mode 100644 libmudflap/testsuite/libmudflap.c++/pass28-frag.cxx create mode 100644 libmudflap/testsuite/libmudflap.c++/pass31-frag.cxx create mode 100644 libmudflap/testsuite/libmudflap.c++/pass41-frag.cxx create mode 100644 libmudflap/testsuite/libmudflap.c/cfrags.exp create mode 100644 libmudflap/testsuite/libmudflap.c/fail1-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail10-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail11-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail12-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail13-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail14-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail15-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail16-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail17-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail18-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail19-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail2-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail20-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail21-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail22-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail23-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail25-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail26-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail27-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail28-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail29-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail3-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail30-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail31-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail4-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail5-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail6-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail7-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail8-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/fail9-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/hook-allocstuff.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass-stratcliff.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass1-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass10-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass11-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass12-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass13-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass14-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass15-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass16-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass17-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass18-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass19-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass2-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass20-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass21-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass22-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass23-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass24-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass25-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass26-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass29-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass3-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass30-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass32-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass33-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass34-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass35-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass36-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass38-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass4-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass42-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass43-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass44-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass45-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass46-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass5-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass6-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass7-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass8-frag.c create mode 100644 libmudflap/testsuite/libmudflap.c/pass9-frag.c create mode 100644 libmudflap/testsuite/libmudflap.cth/cthfrags.exp create mode 100644 libmudflap/testsuite/libmudflap.cth/pass37-frag.c create mode 100644 libmudflap/testsuite/libmudflap.cth/pass39-frag.c create mode 100644 libmudflap/testsuite/libmudflap.cth/pass40-frag.c diff --git a/ChangeLog b/ChangeLog index 1e078155926..34e409138da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. + + * Makefile.def: Add libbanshee, libmudflap and libgfortran. + * Makefile.tpl (BUILD_CONFIGDIRS): Add libbanshee. + (HOST_GMPLIBS): Define. + (HOST_GMPINC): Define. + (TARGET_LIB_PATH): Add libmudflap. + (GFORTRAN_FOR_TARGET): Define. + (configure-build*): Export GFORTRAN. + (configure-gcc): Export GMPLIBS and GMPINC. + (all-gcc): Add maybe-all-libbanshee. + (configure-target-libgfortran): Define. + * Makefile.in: Regenerate. + * configure.in (host_libs): Add libbanshee. + (target_libraries): Add target-libmudflap and target-libgfortran. + Add --with-libbanshee. + Handle --disable-libmudflap. + (*-*-freebsd*): Use with_gmp. + Add $(libgcj) to noconfigdirs. + * configure: Regenerate. + * depcomp: New file. + * MAINTAINERS: Add tree-ssa maintainers. + 2004-05-04 Vladimir Makarov * MAINTAINERS (Various Maintainers): Add myself. diff --git a/ChangeLog.tree-ssa b/ChangeLog.tree-ssa new file mode 100644 index 00000000000..9ada8f03e7f --- /dev/null +++ b/ChangeLog.tree-ssa @@ -0,0 +1,110 @@ +2004-05-03 Andrew Pinski + + * configure.in (GMP checking): s/save_CFLAGS/saved_CFLAGS. + * configure: Regenerate. + +2004-04-22 Loren J. Rittle + + * configure.in (*-*-freebsd*): Use with_gmp to "Avoid crusty gmp.h." + * configure: Rebuilt (with autoconf version 2.13). + +2004-04-17 Paul Brook + + * Makefile.tmp (EXTRA_HOST_FLAGS): Remove GMPLIBS and GMPINC. + (configure-gcc): Set GMPLIBS and GMPINC. + * Makefile.in: Regenerate. + +2004-04-14 Paul Brook + + * Makefile.tmp (HOST_GMPLIBS, HOST_GMPINC): New variables. + (EXTRA_HOST_FLAGS): Pass them. + * configure.in: Add check for GMP. Disable languages if not found. + * Makefile.in, configure: Regenrate. + +2004-03-29 Diego Novillo + + * configure.in: Set with_libbansshee to yes by default. + * configure: Regenerate. + +2004-03-28 Diego Novillo + + * configure.in: Fix handling of --without-libbanshee. + * configure: Regenerate. + +2004-03-26 Nathanael Nerode + + * configure.in: Add support for --without-libbanshee. + * configure: Regenerated. + +2004-02-17 Brian Booth + + * MAINTAINERS.tree-ssa: Add self to write after approval. + +2004-02-13 Loren J. Rittle + + * configure.in (*-*-freebsd*): Avoid crusty gmp.h. + (alpha*-*-*freebsd*, i[[3456789]]86-*-*freebsd*): Merge into above. + * configure: Rebuilt (with autoconf version 2.13). + +2003-10-22 Frank Ch. Eigler + + * configure.in: Add support for "--disable-libmudflap" option. + * configure: Regenerated. + +2003-09-22 Diego Novillo + + * MAINTAINERS.tree-ssa: Add Andrew MacLeod as global maintainer for + the branch. + +2003-08-23 Paul Brook + + * Makefile.in: Regenerate. + +2003-07-26 Paul Brook + + * Makefile.def: Add libgfortran and GFORTRAN_FOR_TARGET. + * Makefile.tmp: Ditto. + * configure.in: Ditto. + * depcomp: New file. + * maintainer-scripts/gcc_release: Add gcc-fortran. + * maintainer-scripts/snapshot-README: Ditto. + * maintainer-scripts/snapshot-index.html: Ditto. + * libgfortran: New target library. + +2003-06-05 Frank Ch. Eigler + + * Makefile.in: Regenerated to activate libmudflap builds. + +2003-04-25 Diego Novillo + + * MAINTAINERS.tree-ssa: New file. + +2003-01-29 Daniel Berlin + + * configure.in: Use ac_configure_args for libbanshee option + * configure: regen. + +2002-11-27 Diego Novillo + + * Makefile.tpl (all-gcc, all-bootstrap): Add dependency on + all-libbanshee. + * Makefile.in: Regenerate. + +2002-11-25 Daniel Berlin + + * Makefile.def: Diego already did the libmudflap moving in a merge, + so remove the extra i added. + * Makefile.in: Regenerate. + +2002-11-24 Daniel Berlin + + * configure.in: Add libbanshee related stuff. + * Makefile.in: Regenerate from Makefile.def. + * Makefile.def: Move libmudflap stuff to here, where it belongs. + Add libbanshee stuff. + * Makefile.tpl: Add libbanshee stuff. + +2002-08-12 Frank Ch. Eigler + + * Makefile.in (target-libmudflap): Add libmudflap-related targets. + * configure.in (target_libs): Ditto. diff --git a/MAINTAINERS b/MAINTAINERS index e2b979f4cc8..14dac9b630e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -170,6 +170,11 @@ gcov Nathan Sidwell nathan@codesourcery.com option handling Neil Booth neil@daikokuya.co.uk libffi testsuite Andreas Tobler andreast@gcc.gnu.org middle-end Roger Sayle roger@eyesopen.com +tree-ssa Diego Novillo dnovillo@redhat.com +tree-ssa Andrew MacLeod amacleod@redhat.com +PRE, points-to Daniel Berlin dberlin@dberlin.org +mudflap Frank Ch. Eigler fche@redhat.com +tree browser/unparser Sebastian Pop s.pop@laposte.net Note individuals who maintain parts of the compiler need approval to check in changes outside of the parts of the compiler they maintain. diff --git a/Makefile.def b/Makefile.def index e8e207aca58..5f293680ae2 100644 --- a/Makefile.def +++ b/Makefile.def @@ -25,6 +25,7 @@ AutoGen definitions Makefile.tpl; // that recursive target in its Makefile. build_modules= { module= libiberty; }; +build_modules= { module= libbanshee; }; host_modules= { module= ash; }; host_modules= { module= autoconf; }; @@ -59,6 +60,7 @@ host_modules= { module= tcl; host_modules= { module= itcl; }; host_modules= { module= ld; bootstrap=true; }; host_modules= { module= libgui; }; +host_modules= { module= libbanshee; bootstrap=true; no_install=true; }; host_modules= { module= libiberty; bootstrap=true; }; host_modules= { module= libtool; }; host_modules= { module= m4; }; @@ -97,8 +99,10 @@ host_modules= { module= libtermcap; no_check=true; host_modules= { module= utils; no_check=true; }; target_modules = { module= libstdc++-v3; raw_cxx=true; }; +target_modules = { module= libmudflap; }; target_modules = { module= newlib; }; target_modules = { module= libf2c; }; +target_modules = { module= libgfortran; }; target_modules = { module= libobjc; }; target_modules = { module= libtermcap; no_check=true; stage=true; missing=mostlyclean; @@ -202,6 +206,7 @@ flags_to_pass = { flag= CXX_FOR_TARGET ; }; flags_to_pass = { flag= CXXFLAGS_FOR_TARGET ; }; flags_to_pass = { flag= DLLTOOL_FOR_TARGET ; }; flags_to_pass = { flag= GCJ_FOR_TARGET ; }; +flags_to_pass = { flag= GFORTRAN_FOR_TARGET ; }; flags_to_pass = { flag= LD_FOR_TARGET ; }; flags_to_pass = { flag= LIBCFLAGS_FOR_TARGET ; }; flags_to_pass = { flag= LIBCXXFLAGS_FOR_TARGET ; }; diff --git a/Makefile.in b/Makefile.in index 8f609051914..ff065ac1ce6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -102,7 +102,7 @@ REALLY_SET_LIB_PATH = \ $(RPATH_ENVVAR)=`echo "$(HOST_LIB_PATH):$(TARGET_LIB_PATH):$$$(RPATH_ENVVAR)" | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; export $(RPATH_ENVVAR); # This is the list of directories to be built for the build system. -BUILD_CONFIGDIRS = libiberty +BUILD_CONFIGDIRS = libiberty libbanshee # Build programs are put under this directory. BUILD_SUBDIR = @build_subdir@ # This is set by the configure script to the arguments to use when configuring @@ -124,6 +124,10 @@ TARGET_SUBDIR = @target_subdir@ # directories built for the target. TARGET_CONFIGARGS = @target_configargs@ +# Where to find GMP +HOST_GMPLIBS = @gmplibs@ +HOST_GMPINC = @gmpinc@ + # ---------------------------------------------- # Programs producing files for the BUILD machine # ---------------------------------------------- @@ -241,7 +245,7 @@ PICFLAG = # This is the list of directories that may be needed in RPATH_ENVVAR # so that prorgams built for the target machine work. -TARGET_LIB_PATH = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs: +TARGET_LIB_PATH = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs:$$r/$(TARGET_SUBDIR)/libmudflap/.libs FLAGS_FOR_TARGET = @FLAGS_FOR_TARGET@ @@ -308,6 +312,7 @@ USUAL_DLLTOOL_FOR_TARGET = ` \ fi` GCJ_FOR_TARGET = @GCJ_FOR_TARGET@ +GFORTRAN_FOR_TARGET = @GFORTRAN_FOR_TARGET@ LD_FOR_TARGET=@LD_FOR_TARGET@ CONFIGURED_LD_FOR_TARGET=@CONFIGURED_LD_FOR_TARGET@ @@ -446,6 +451,7 @@ BASE_FLAGS_TO_PASS = \ "CXXFLAGS_FOR_TARGET=$(CXXFLAGS_FOR_TARGET)" \ "DLLTOOL_FOR_TARGET=$(DLLTOOL_FOR_TARGET)" \ "GCJ_FOR_TARGET=$(GCJ_FOR_TARGET)" \ + "GFORTRAN_FOR_TARGET=$(GFORTRAN_FOR_TARGET)" \ "LD_FOR_TARGET=$(LD_FOR_TARGET)" \ "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ "LIBCXXFLAGS_FOR_TARGET=$(LIBCXXFLAGS_FOR_TARGET)" \ @@ -568,6 +574,7 @@ configure-host: maybe-configure-gcc \ maybe-configure-itcl \ maybe-configure-ld \ maybe-configure-libgui \ + maybe-configure-libbanshee \ maybe-configure-libiberty \ maybe-configure-libtool \ maybe-configure-m4 \ @@ -603,8 +610,10 @@ configure-host: maybe-configure-gcc \ .PHONY: configure-target configure-target: \ maybe-configure-target-libstdc++-v3 \ + maybe-configure-target-libmudflap \ maybe-configure-target-newlib \ maybe-configure-target-libf2c \ + maybe-configure-target-libgfortran \ maybe-configure-target-libobjc \ maybe-configure-target-libtermcap \ maybe-configure-target-winsup \ @@ -658,6 +667,7 @@ all-host: maybe-all-gcc \ maybe-all-itcl \ maybe-all-ld \ maybe-all-libgui \ + maybe-all-libbanshee \ maybe-all-libiberty \ maybe-all-libtool \ maybe-all-m4 \ @@ -693,8 +703,10 @@ all-host: maybe-all-gcc \ .PHONY: all-target all-target: \ maybe-all-target-libstdc++-v3 \ + maybe-all-target-libmudflap \ maybe-all-target-newlib \ maybe-all-target-libf2c \ + maybe-all-target-libgfortran \ maybe-all-target-libobjc \ maybe-all-target-libtermcap \ maybe-all-target-winsup \ @@ -752,6 +764,7 @@ info-host: maybe-info-gcc \ maybe-info-itcl \ maybe-info-ld \ maybe-info-libgui \ + maybe-info-libbanshee \ maybe-info-libiberty \ maybe-info-libtool \ maybe-info-m4 \ @@ -788,8 +801,10 @@ info-host: maybe-info-gcc \ .PHONY: info-target info-target: \ maybe-info-target-libstdc++-v3 \ + maybe-info-target-libmudflap \ maybe-info-target-newlib \ maybe-info-target-libf2c \ + maybe-info-target-libgfortran \ maybe-info-target-libobjc \ maybe-info-target-libtermcap \ maybe-info-target-winsup \ @@ -842,6 +857,7 @@ dvi-host: maybe-dvi-gcc \ maybe-dvi-itcl \ maybe-dvi-ld \ maybe-dvi-libgui \ + maybe-dvi-libbanshee \ maybe-dvi-libiberty \ maybe-dvi-libtool \ maybe-dvi-m4 \ @@ -878,8 +894,10 @@ dvi-host: maybe-dvi-gcc \ .PHONY: dvi-target dvi-target: \ maybe-dvi-target-libstdc++-v3 \ + maybe-dvi-target-libmudflap \ maybe-dvi-target-newlib \ maybe-dvi-target-libf2c \ + maybe-dvi-target-libgfortran \ maybe-dvi-target-libobjc \ maybe-dvi-target-libtermcap \ maybe-dvi-target-winsup \ @@ -932,6 +950,7 @@ TAGS-host: maybe-TAGS-gcc \ maybe-TAGS-itcl \ maybe-TAGS-ld \ maybe-TAGS-libgui \ + maybe-TAGS-libbanshee \ maybe-TAGS-libiberty \ maybe-TAGS-libtool \ maybe-TAGS-m4 \ @@ -968,8 +987,10 @@ TAGS-host: maybe-TAGS-gcc \ .PHONY: TAGS-target TAGS-target: \ maybe-TAGS-target-libstdc++-v3 \ + maybe-TAGS-target-libmudflap \ maybe-TAGS-target-newlib \ maybe-TAGS-target-libf2c \ + maybe-TAGS-target-libgfortran \ maybe-TAGS-target-libobjc \ maybe-TAGS-target-libtermcap \ maybe-TAGS-target-winsup \ @@ -1022,6 +1043,7 @@ install-info-host: maybe-install-info-gcc \ maybe-install-info-itcl \ maybe-install-info-ld \ maybe-install-info-libgui \ + maybe-install-info-libbanshee \ maybe-install-info-libiberty \ maybe-install-info-libtool \ maybe-install-info-m4 \ @@ -1058,8 +1080,10 @@ install-info-host: maybe-install-info-gcc \ .PHONY: install-info-target install-info-target: \ maybe-install-info-target-libstdc++-v3 \ + maybe-install-info-target-libmudflap \ maybe-install-info-target-newlib \ maybe-install-info-target-libf2c \ + maybe-install-info-target-libgfortran \ maybe-install-info-target-libobjc \ maybe-install-info-target-libtermcap \ maybe-install-info-target-winsup \ @@ -1112,6 +1136,7 @@ installcheck-host: maybe-installcheck-gcc \ maybe-installcheck-itcl \ maybe-installcheck-ld \ maybe-installcheck-libgui \ + maybe-installcheck-libbanshee \ maybe-installcheck-libiberty \ maybe-installcheck-libtool \ maybe-installcheck-m4 \ @@ -1148,8 +1173,10 @@ installcheck-host: maybe-installcheck-gcc \ .PHONY: installcheck-target installcheck-target: \ maybe-installcheck-target-libstdc++-v3 \ + maybe-installcheck-target-libmudflap \ maybe-installcheck-target-newlib \ maybe-installcheck-target-libf2c \ + maybe-installcheck-target-libgfortran \ maybe-installcheck-target-libobjc \ maybe-installcheck-target-libtermcap \ maybe-installcheck-target-winsup \ @@ -1202,6 +1229,7 @@ mostlyclean-host: maybe-mostlyclean-gcc \ maybe-mostlyclean-itcl \ maybe-mostlyclean-ld \ maybe-mostlyclean-libgui \ + maybe-mostlyclean-libbanshee \ maybe-mostlyclean-libiberty \ maybe-mostlyclean-libtool \ maybe-mostlyclean-m4 \ @@ -1238,8 +1266,10 @@ mostlyclean-host: maybe-mostlyclean-gcc \ .PHONY: mostlyclean-target mostlyclean-target: \ maybe-mostlyclean-target-libstdc++-v3 \ + maybe-mostlyclean-target-libmudflap \ maybe-mostlyclean-target-newlib \ maybe-mostlyclean-target-libf2c \ + maybe-mostlyclean-target-libgfortran \ maybe-mostlyclean-target-libobjc \ maybe-mostlyclean-target-libtermcap \ maybe-mostlyclean-target-winsup \ @@ -1292,6 +1322,7 @@ clean-host: maybe-clean-gcc \ maybe-clean-itcl \ maybe-clean-ld \ maybe-clean-libgui \ + maybe-clean-libbanshee \ maybe-clean-libiberty \ maybe-clean-libtool \ maybe-clean-m4 \ @@ -1328,8 +1359,10 @@ clean-host: maybe-clean-gcc \ .PHONY: clean-target clean-target: \ maybe-clean-target-libstdc++-v3 \ + maybe-clean-target-libmudflap \ maybe-clean-target-newlib \ maybe-clean-target-libf2c \ + maybe-clean-target-libgfortran \ maybe-clean-target-libobjc \ maybe-clean-target-libtermcap \ maybe-clean-target-winsup \ @@ -1382,6 +1415,7 @@ distclean-host: maybe-distclean-gcc \ maybe-distclean-itcl \ maybe-distclean-ld \ maybe-distclean-libgui \ + maybe-distclean-libbanshee \ maybe-distclean-libiberty \ maybe-distclean-libtool \ maybe-distclean-m4 \ @@ -1418,8 +1452,10 @@ distclean-host: maybe-distclean-gcc \ .PHONY: distclean-target distclean-target: \ maybe-distclean-target-libstdc++-v3 \ + maybe-distclean-target-libmudflap \ maybe-distclean-target-newlib \ maybe-distclean-target-libf2c \ + maybe-distclean-target-libgfortran \ maybe-distclean-target-libobjc \ maybe-distclean-target-libtermcap \ maybe-distclean-target-winsup \ @@ -1472,6 +1508,7 @@ maintainer-clean-host: maybe-maintainer-clean-gcc \ maybe-maintainer-clean-itcl \ maybe-maintainer-clean-ld \ maybe-maintainer-clean-libgui \ + maybe-maintainer-clean-libbanshee \ maybe-maintainer-clean-libiberty \ maybe-maintainer-clean-libtool \ maybe-maintainer-clean-m4 \ @@ -1508,8 +1545,10 @@ maintainer-clean-host: maybe-maintainer-clean-gcc \ .PHONY: maintainer-clean-target maintainer-clean-target: \ maybe-maintainer-clean-target-libstdc++-v3 \ + maybe-maintainer-clean-target-libmudflap \ maybe-maintainer-clean-target-newlib \ maybe-maintainer-clean-target-libf2c \ + maybe-maintainer-clean-target-libgfortran \ maybe-maintainer-clean-target-libobjc \ maybe-maintainer-clean-target-libtermcap \ maybe-maintainer-clean-target-winsup \ @@ -1619,6 +1658,7 @@ do-check: maybe-check-gcc \ maybe-check-itcl \ maybe-check-ld \ maybe-check-libgui \ + maybe-check-libbanshee \ maybe-check-libiberty \ maybe-check-libtool \ maybe-check-m4 \ @@ -1652,8 +1692,10 @@ do-check: maybe-check-gcc \ maybe-check-libtermcap \ maybe-check-utils \ maybe-check-target-libstdc++-v3 \ + maybe-check-target-libmudflap \ maybe-check-target-newlib \ maybe-check-target-libf2c \ + maybe-check-target-libgfortran \ maybe-check-target-libobjc \ maybe-check-target-libtermcap \ maybe-check-target-winsup \ @@ -1729,6 +1771,7 @@ install-host-nogcc: \ maybe-install-itcl \ maybe-install-ld \ maybe-install-libgui \ + maybe-install-libbanshee \ maybe-install-libiberty \ maybe-install-libtool \ maybe-install-m4 \ @@ -1796,6 +1839,7 @@ install-host: maybe-install-gcc \ maybe-install-itcl \ maybe-install-ld \ maybe-install-libgui \ + maybe-install-libbanshee \ maybe-install-libiberty \ maybe-install-libtool \ maybe-install-m4 \ @@ -1832,8 +1876,10 @@ install-host: maybe-install-gcc \ .PHONY: install-target install-target: \ maybe-install-target-libstdc++-v3 \ + maybe-install-target-libmudflap \ maybe-install-target-newlib \ maybe-install-target-libf2c \ + maybe-install-target-libgfortran \ maybe-install-target-libobjc \ maybe-install-target-libtermcap \ maybe-install-target-winsup \ @@ -1918,6 +1964,7 @@ configure-build-libiberty: CXX="$(CXX_FOR_BUILD)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_BUILD)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_BUILD)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_BUILD)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \ LD="$(LD_FOR_BUILD)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \ @@ -1972,6 +2019,76 @@ all-build-libiberty: configure-build-libiberty s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ (cd $(BUILD_SUBDIR)/libiberty && $(MAKE) all) +.PHONY: configure-build-libbanshee maybe-configure-build-libbanshee +maybe-configure-build-libbanshee: +configure-build-libbanshee: + @test ! -f $(BUILD_SUBDIR)/libbanshee/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(BUILD_SUBDIR)/libbanshee ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + AR="$(AR_FOR_BUILD)"; export AR; \ + AS="$(AS_FOR_BUILD)"; export AS; \ + CC="$(CC_FOR_BUILD)"; export CC; \ + CFLAGS="$(CFLAGS_FOR_BUILD)"; export CFLAGS; \ + CONFIG_SHELL="$(SHELL)"; export CONFIG_SHELL; \ + CXX="$(CXX_FOR_BUILD)"; export CXX; \ + CXXFLAGS="$(CXXFLAGS_FOR_BUILD)"; export CXXFLAGS; \ + GCJ="$(GCJ_FOR_BUILD)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_BUILD)"; export GFORTRAN; \ + DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \ + LD="$(LD_FOR_BUILD)"; export LD; \ + LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \ + NM="$(NM_FOR_BUILD)"; export NM; \ + RANLIB="$(RANLIB_FOR_BUILD)"; export RANLIB; \ + WINDRES="$(WINDRES_FOR_BUILD)"; export WINDRES; \ + echo Configuring in $(BUILD_SUBDIR)/libbanshee; \ + cd "$(BUILD_SUBDIR)/libbanshee" || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) \ + topdir=$(srcdir) ;; \ + *) \ + case "$(BUILD_SUBDIR)" in \ + .) topdir="../$(srcdir)" ;; \ + *) topdir="../../$(srcdir)" ;; \ + esac ;; \ + esac; \ + if [ "$(srcdir)" = "." ] ; then \ + if [ "$(BUILD_SUBDIR)" != "." ] ; then \ + if $(SHELL) $$s/symlink-tree $${topdir}/libbanshee "no-such-file" ; then \ + if [ -f Makefile ]; then \ + if $(MAKE) distclean; then \ + true; \ + else \ + exit 1; \ + fi; \ + else \ + true; \ + fi; \ + else \ + exit 1; \ + fi; \ + else \ + true; \ + fi; \ + srcdiroption="--srcdir=."; \ + libsrcdir="."; \ + else \ + srcdiroption="--srcdir=$${topdir}/libbanshee"; \ + libsrcdir="$$s/libbanshee"; \ + fi; \ + rm -f no-such-file || : ; \ + CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \ + $(BUILD_CONFIGARGS) $${srcdiroption} \ + --with-build-subdir="$(BUILD_SUBDIR)" \ + || exit 1 + +.PHONY: all-build-libbanshee maybe-all-build-libbanshee +maybe-all-build-libbanshee: +all-build-libbanshee: configure-build-libbanshee + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + (cd $(BUILD_SUBDIR)/libbanshee && $(MAKE) all) + # -------------------------------------- # Modules which run on the host machine @@ -10483,6 +10600,268 @@ maintainer-clean-libgui: +.PHONY: configure-libbanshee maybe-configure-libbanshee +maybe-configure-libbanshee: +configure-libbanshee: + @test ! -f libbanshee/Makefile || exit 0; \ + [ -d libbanshee ] || mkdir libbanshee; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + CC="$(CC)"; export CC; \ + CFLAGS="$(CFLAGS)"; export CFLAGS; \ + CONFIG_SHELL="$(SHELL)"; export CONFIG_SHELL; \ + CXX="$(CXX)"; export CXX; \ + CXXFLAGS="$(CXXFLAGS)"; export CXXFLAGS; \ + AR="$(AR)"; export AR; \ + AS="$(AS)"; export AS; \ + CC_FOR_BUILD="$(CC_FOR_BUILD)"; export CC_FOR_BUILD; \ + DLLTOOL="$(DLLTOOL)"; export DLLTOOL; \ + LD="$(LD)"; export LD; \ + LDFLAGS="$(LDFLAGS)"; export LDFLAGS; \ + NM="$(NM)"; export NM; \ + RANLIB="$(RANLIB)"; export RANLIB; \ + WINDRES="$(WINDRES)"; export WINDRES; \ + OBJCOPY="$(OBJCOPY)"; export OBJCOPY; \ + OBJDUMP="$(OBJDUMP)"; export OBJDUMP; \ + echo Configuring in libbanshee; \ + cd libbanshee || exit 1; \ + case $(srcdir) in \ + \.) \ + srcdiroption="--srcdir=."; \ + libsrcdir=".";; \ + /* | [A-Za-z]:[\\/]*) \ + srcdiroption="--srcdir=$(srcdir)/libbanshee"; \ + libsrcdir="$$s/libbanshee";; \ + *) \ + srcdiroption="--srcdir=../$(srcdir)/libbanshee"; \ + libsrcdir="$$s/libbanshee";; \ + esac; \ + $(SHELL) $${libsrcdir}/configure \ + $(HOST_CONFIGARGS) $${srcdiroption} \ + || exit 1 + +.PHONY: all-libbanshee maybe-all-libbanshee +maybe-all-libbanshee: +all-libbanshee: configure-libbanshee + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd libbanshee && $(MAKE) $(FLAGS_TO_PASS) all) + +.PHONY: check-libbanshee maybe-check-libbanshee +maybe-check-libbanshee: + +check-libbanshee: + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd libbanshee && $(MAKE) $(FLAGS_TO_PASS) check) + + +.PHONY: install-libbanshee maybe-install-libbanshee +maybe-install-libbanshee: + +install-libbanshee: + + +# Other targets (info, dvi, etc.) + +.PHONY: maybe-info-libbanshee info-libbanshee +maybe-info-libbanshee: + +info-libbanshee: \ + configure-libbanshee + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing info in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + info) \ + || exit 1 + + +.PHONY: maybe-dvi-libbanshee dvi-libbanshee +maybe-dvi-libbanshee: + +dvi-libbanshee: \ + configure-libbanshee + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing dvi in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + dvi) \ + || exit 1 + + +.PHONY: maybe-TAGS-libbanshee TAGS-libbanshee +maybe-TAGS-libbanshee: + +TAGS-libbanshee: \ + configure-libbanshee + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing TAGS in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + TAGS) \ + || exit 1 + + +.PHONY: maybe-install-info-libbanshee install-info-libbanshee +maybe-install-info-libbanshee: + +install-info-libbanshee: \ + configure-libbanshee \ + info-libbanshee + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing install-info in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + install-info) \ + || exit 1 + + +.PHONY: maybe-installcheck-libbanshee installcheck-libbanshee +maybe-installcheck-libbanshee: + +installcheck-libbanshee: \ + configure-libbanshee + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing installcheck in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + installcheck) \ + || exit 1 + + +.PHONY: maybe-mostlyclean-libbanshee mostlyclean-libbanshee +maybe-mostlyclean-libbanshee: + +mostlyclean-libbanshee: + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing mostlyclean in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + mostlyclean) \ + || exit 1 + + +.PHONY: maybe-clean-libbanshee clean-libbanshee +maybe-clean-libbanshee: + +clean-libbanshee: + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing clean in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + clean) \ + || exit 1 + + +.PHONY: maybe-distclean-libbanshee distclean-libbanshee +maybe-distclean-libbanshee: + +distclean-libbanshee: + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing distclean in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + distclean) \ + || exit 1 + + +.PHONY: maybe-maintainer-clean-libbanshee maintainer-clean-libbanshee +maybe-maintainer-clean-libbanshee: + +maintainer-clean-libbanshee: + @[ -f ./libbanshee/Makefile ] || exit 0; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + for flag in $(EXTRA_HOST_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + echo "Doing maintainer-clean in libbanshee" ; \ + (cd libbanshee && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + maintainer-clean) \ + || exit 1 + + + .PHONY: configure-libiberty maybe-configure-libiberty maybe-configure-libiberty: configure-libiberty: @@ -18940,6 +19319,7 @@ configure-target-libstdc++-v3: $(TARGET_SUBDIR)/libstdc++-v3/multilib.out CXX="$(RAW_CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -19194,18 +19574,18 @@ maintainer-clean-target-libstdc++-v3: -.PHONY: configure-target-newlib maybe-configure-target-newlib -maybe-configure-target-newlib: +.PHONY: configure-target-libmudflap maybe-configure-target-libmudflap +maybe-configure-target-libmudflap: # There's only one multilib.out. Cleverer subdirs shouldn't need it copied. -$(TARGET_SUBDIR)/newlib/multilib.out: multilib.out - $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/newlib ; \ - rm -f $(TARGET_SUBDIR)/newlib/Makefile || : ; \ - cp multilib.out $(TARGET_SUBDIR)/newlib/multilib.out +$(TARGET_SUBDIR)/libmudflap/multilib.out: multilib.out + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libmudflap ; \ + rm -f $(TARGET_SUBDIR)/libmudflap/Makefile || : ; \ + cp multilib.out $(TARGET_SUBDIR)/libmudflap/multilib.out -configure-target-newlib: $(TARGET_SUBDIR)/newlib/multilib.out - @test ! -f $(TARGET_SUBDIR)/newlib/Makefile || exit 0; \ - $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/newlib ; \ +configure-target-libmudflap: $(TARGET_SUBDIR)/libmudflap/multilib.out + @test ! -f $(TARGET_SUBDIR)/libmudflap/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libmudflap ; \ r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ $(SET_LIB_PATH) \ @@ -19218,14 +19598,15 @@ configure-target-newlib: $(TARGET_SUBDIR)/newlib/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ NM="$(NM_FOR_TARGET)"; export NM; \ RANLIB="$(RANLIB_FOR_TARGET)"; export RANLIB; \ WINDRES="$(WINDRES_FOR_TARGET)"; export WINDRES; \ - echo Configuring in $(TARGET_SUBDIR)/newlib; \ - cd "$(TARGET_SUBDIR)/newlib" || exit 1; \ + echo Configuring in $(TARGET_SUBDIR)/libmudflap; \ + cd "$(TARGET_SUBDIR)/libmudflap" || exit 1; \ case $(srcdir) in \ /* | [A-Za-z]:[\\/]*) \ topdir=$(srcdir) ;; \ @@ -19235,27 +19616,306 @@ configure-target-newlib: $(TARGET_SUBDIR)/newlib/multilib.out *) topdir="../../$(srcdir)" ;; \ esac ;; \ esac; \ - srcdiroption="--srcdir=$${topdir}/newlib"; \ - libsrcdir="$$s/newlib"; \ + srcdiroption="--srcdir=$${topdir}/libmudflap"; \ + libsrcdir="$$s/libmudflap"; \ rm -f no-such-file || : ; \ CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \ $(TARGET_CONFIGARGS) $${srcdiroption} \ --with-target-subdir="$(TARGET_SUBDIR)" \ || exit 1 -.PHONY: all-target-newlib maybe-all-target-newlib -maybe-all-target-newlib: -all-target-newlib: configure-target-newlib +.PHONY: all-target-libmudflap maybe-all-target-libmudflap +maybe-all-target-libmudflap: +all-target-libmudflap: configure-target-libmudflap @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ $(SET_LIB_PATH) \ - (cd $(TARGET_SUBDIR)/newlib && \ + (cd $(TARGET_SUBDIR)/libmudflap && \ $(MAKE) $(TARGET_FLAGS_TO_PASS) all) -.PHONY: check-target-newlib maybe-check-target-newlib -maybe-check-target-newlib: +.PHONY: check-target-libmudflap maybe-check-target-libmudflap +maybe-check-target-libmudflap: -check-target-newlib: +check-target-libmudflap: + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) check) + + +.PHONY: install-target-libmudflap maybe-install-target-libmudflap +maybe-install-target-libmudflap: + +install-target-libmudflap: installdirs + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install) + + +# Other targets (info, dvi, etc.) + +.PHONY: maybe-info-target-libmudflap info-target-libmudflap +maybe-info-target-libmudflap: + +info-target-libmudflap: \ + configure-target-libmudflap + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing info in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + info) \ + || exit 1 + + +.PHONY: maybe-dvi-target-libmudflap dvi-target-libmudflap +maybe-dvi-target-libmudflap: + +dvi-target-libmudflap: \ + configure-target-libmudflap + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing dvi in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + dvi) \ + || exit 1 + + +.PHONY: maybe-TAGS-target-libmudflap TAGS-target-libmudflap +maybe-TAGS-target-libmudflap: + +TAGS-target-libmudflap: \ + configure-target-libmudflap + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing TAGS in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + TAGS) \ + || exit 1 + + +.PHONY: maybe-install-info-target-libmudflap install-info-target-libmudflap +maybe-install-info-target-libmudflap: + +install-info-target-libmudflap: \ + configure-target-libmudflap \ + info-target-libmudflap + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing install-info in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + install-info) \ + || exit 1 + + +.PHONY: maybe-installcheck-target-libmudflap installcheck-target-libmudflap +maybe-installcheck-target-libmudflap: + +installcheck-target-libmudflap: \ + configure-target-libmudflap + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing installcheck in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + installcheck) \ + || exit 1 + + +.PHONY: maybe-mostlyclean-target-libmudflap mostlyclean-target-libmudflap +maybe-mostlyclean-target-libmudflap: + +mostlyclean-target-libmudflap: + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing mostlyclean in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + mostlyclean) \ + || exit 1 + + +.PHONY: maybe-clean-target-libmudflap clean-target-libmudflap +maybe-clean-target-libmudflap: + +clean-target-libmudflap: + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing clean in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + clean) \ + || exit 1 + + +.PHONY: maybe-distclean-target-libmudflap distclean-target-libmudflap +maybe-distclean-target-libmudflap: + +distclean-target-libmudflap: + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing distclean in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + distclean) \ + || exit 1 + + +.PHONY: maybe-maintainer-clean-target-libmudflap maintainer-clean-target-libmudflap +maybe-maintainer-clean-target-libmudflap: + +maintainer-clean-target-libmudflap: + @[ -f $(TARGET_SUBDIR)/libmudflap/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing maintainer-clean in $(TARGET_SUBDIR)/libmudflap" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libmudflap && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + maintainer-clean) \ + || exit 1 + + + +.PHONY: configure-target-newlib maybe-configure-target-newlib +maybe-configure-target-newlib: + +# There's only one multilib.out. Cleverer subdirs shouldn't need it copied. +$(TARGET_SUBDIR)/newlib/multilib.out: multilib.out + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/newlib ; \ + rm -f $(TARGET_SUBDIR)/newlib/Makefile || : ; \ + cp multilib.out $(TARGET_SUBDIR)/newlib/multilib.out + +configure-target-newlib: $(TARGET_SUBDIR)/newlib/multilib.out + @test ! -f $(TARGET_SUBDIR)/newlib/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/newlib ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + AR="$(AR_FOR_TARGET)"; export AR; \ + AS="$(AS_FOR_TARGET)"; export AS; \ + CC="$(CC_FOR_TARGET)"; export CC; \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CONFIG_SHELL="$(SHELL)"; export CONFIG_SHELL; \ + CPPFLAGS="$(CFLAGS_FOR_TARGET)"; export CPPFLAGS; \ + CXX="$(CXX_FOR_TARGET)"; export CXX; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ + DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ + LD="$(LD_FOR_TARGET)"; export LD; \ + LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ + NM="$(NM_FOR_TARGET)"; export NM; \ + RANLIB="$(RANLIB_FOR_TARGET)"; export RANLIB; \ + WINDRES="$(WINDRES_FOR_TARGET)"; export WINDRES; \ + echo Configuring in $(TARGET_SUBDIR)/newlib; \ + cd "$(TARGET_SUBDIR)/newlib" || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) \ + topdir=$(srcdir) ;; \ + *) \ + case "$(TARGET_SUBDIR)" in \ + .) topdir="../$(srcdir)" ;; \ + *) topdir="../../$(srcdir)" ;; \ + esac ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/newlib"; \ + libsrcdir="$$s/newlib"; \ + rm -f no-such-file || : ; \ + CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) $${srcdiroption} \ + --with-target-subdir="$(TARGET_SUBDIR)" \ + || exit 1 + +.PHONY: all-target-newlib maybe-all-target-newlib +maybe-all-target-newlib: +all-target-newlib: configure-target-newlib + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/newlib && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) all) + +.PHONY: check-target-newlib maybe-check-target-newlib +maybe-check-target-newlib: + +check-target-newlib: @r=`${PWD_COMMAND}`; export r; \ s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ $(SET_LIB_PATH) \ @@ -19496,6 +20156,7 @@ configure-target-libf2c: $(TARGET_SUBDIR)/libf2c/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -19750,6 +20411,285 @@ maintainer-clean-target-libf2c: +.PHONY: configure-target-libgfortran maybe-configure-target-libgfortran +maybe-configure-target-libgfortran: + +# There's only one multilib.out. Cleverer subdirs shouldn't need it copied. +$(TARGET_SUBDIR)/libgfortran/multilib.out: multilib.out + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libgfortran ; \ + rm -f $(TARGET_SUBDIR)/libgfortran/Makefile || : ; \ + cp multilib.out $(TARGET_SUBDIR)/libgfortran/multilib.out + +configure-target-libgfortran: $(TARGET_SUBDIR)/libgfortran/multilib.out + @test ! -f $(TARGET_SUBDIR)/libgfortran/Makefile || exit 0; \ + $(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libgfortran ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + AR="$(AR_FOR_TARGET)"; export AR; \ + AS="$(AS_FOR_TARGET)"; export AS; \ + CC="$(CC_FOR_TARGET)"; export CC; \ + CFLAGS="$(CFLAGS_FOR_TARGET)"; export CFLAGS; \ + CONFIG_SHELL="$(SHELL)"; export CONFIG_SHELL; \ + CPPFLAGS="$(CFLAGS_FOR_TARGET)"; export CPPFLAGS; \ + CXX="$(CXX_FOR_TARGET)"; export CXX; \ + CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ + GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ + DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ + LD="$(LD_FOR_TARGET)"; export LD; \ + LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ + NM="$(NM_FOR_TARGET)"; export NM; \ + RANLIB="$(RANLIB_FOR_TARGET)"; export RANLIB; \ + WINDRES="$(WINDRES_FOR_TARGET)"; export WINDRES; \ + echo Configuring in $(TARGET_SUBDIR)/libgfortran; \ + cd "$(TARGET_SUBDIR)/libgfortran" || exit 1; \ + case $(srcdir) in \ + /* | [A-Za-z]:[\\/]*) \ + topdir=$(srcdir) ;; \ + *) \ + case "$(TARGET_SUBDIR)" in \ + .) topdir="../$(srcdir)" ;; \ + *) topdir="../../$(srcdir)" ;; \ + esac ;; \ + esac; \ + srcdiroption="--srcdir=$${topdir}/libgfortran"; \ + libsrcdir="$$s/libgfortran"; \ + rm -f no-such-file || : ; \ + CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \ + $(TARGET_CONFIGARGS) $${srcdiroption} \ + --with-target-subdir="$(TARGET_SUBDIR)" \ + || exit 1 + +.PHONY: all-target-libgfortran maybe-all-target-libgfortran +maybe-all-target-libgfortran: +all-target-libgfortran: configure-target-libgfortran + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) all) + +.PHONY: check-target-libgfortran maybe-check-target-libgfortran +maybe-check-target-libgfortran: + +check-target-libgfortran: + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) check) + + +.PHONY: install-target-libgfortran maybe-install-target-libgfortran +maybe-install-target-libgfortran: + +install-target-libgfortran: installdirs + @r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(TARGET_FLAGS_TO_PASS) install) + + +# Other targets (info, dvi, etc.) + +.PHONY: maybe-info-target-libgfortran info-target-libgfortran +maybe-info-target-libgfortran: + +info-target-libgfortran: \ + configure-target-libgfortran + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing info in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + info) \ + || exit 1 + + +.PHONY: maybe-dvi-target-libgfortran dvi-target-libgfortran +maybe-dvi-target-libgfortran: + +dvi-target-libgfortran: \ + configure-target-libgfortran + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing dvi in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + dvi) \ + || exit 1 + + +.PHONY: maybe-TAGS-target-libgfortran TAGS-target-libgfortran +maybe-TAGS-target-libgfortran: + +TAGS-target-libgfortran: \ + configure-target-libgfortran + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing TAGS in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + TAGS) \ + || exit 1 + + +.PHONY: maybe-install-info-target-libgfortran install-info-target-libgfortran +maybe-install-info-target-libgfortran: + +install-info-target-libgfortran: \ + configure-target-libgfortran \ + info-target-libgfortran + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing install-info in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + install-info) \ + || exit 1 + + +.PHONY: maybe-installcheck-target-libgfortran installcheck-target-libgfortran +maybe-installcheck-target-libgfortran: + +installcheck-target-libgfortran: \ + configure-target-libgfortran + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing installcheck in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + installcheck) \ + || exit 1 + + +.PHONY: maybe-mostlyclean-target-libgfortran mostlyclean-target-libgfortran +maybe-mostlyclean-target-libgfortran: + +mostlyclean-target-libgfortran: + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing mostlyclean in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + mostlyclean) \ + || exit 1 + + +.PHONY: maybe-clean-target-libgfortran clean-target-libgfortran +maybe-clean-target-libgfortran: + +clean-target-libgfortran: + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing clean in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + clean) \ + || exit 1 + + +.PHONY: maybe-distclean-target-libgfortran distclean-target-libgfortran +maybe-distclean-target-libgfortran: + +distclean-target-libgfortran: + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing distclean in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + distclean) \ + || exit 1 + + +.PHONY: maybe-maintainer-clean-target-libgfortran maintainer-clean-target-libgfortran +maybe-maintainer-clean-target-libgfortran: + +maintainer-clean-target-libgfortran: + @[ -f $(TARGET_SUBDIR)/libgfortran/Makefile ] || exit 0 ; \ + r=`${PWD_COMMAND}`; export r; \ + s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \ + $(SET_LIB_PATH) \ + echo "Doing maintainer-clean in $(TARGET_SUBDIR)/libgfortran" ; \ + for flag in $(EXTRA_TARGET_FLAGS); do \ + eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \ + done; \ + (cd $(TARGET_SUBDIR)/libgfortran && \ + $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \ + "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \ + "RANLIB=$${RANLIB}" \ + "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" \ + maintainer-clean) \ + || exit 1 + + + .PHONY: configure-target-libobjc maybe-configure-target-libobjc maybe-configure-target-libobjc: @@ -19774,6 +20714,7 @@ configure-target-libobjc: $(TARGET_SUBDIR)/libobjc/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -20052,6 +20993,7 @@ configure-target-libtermcap: $(TARGET_SUBDIR)/libtermcap/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -20292,6 +21234,7 @@ configure-target-winsup: $(TARGET_SUBDIR)/winsup/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -20570,6 +21513,7 @@ configure-target-libgloss: $(TARGET_SUBDIR)/libgloss/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -20844,6 +21788,7 @@ configure-target-libiberty: $(TARGET_SUBDIR)/libiberty/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -21122,6 +22067,7 @@ configure-target-gperf: $(TARGET_SUBDIR)/gperf/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -21400,6 +22346,7 @@ configure-target-examples: $(TARGET_SUBDIR)/examples/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -21670,6 +22617,7 @@ configure-target-libffi: $(TARGET_SUBDIR)/libffi/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -21949,6 +22897,7 @@ configure-target-libjava: $(TARGET_SUBDIR)/libjava/multilib.out CXX="$(RAW_CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -22227,6 +23176,7 @@ configure-target-zlib: $(TARGET_SUBDIR)/zlib/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -22527,6 +23477,7 @@ configure-target-boehm-gc: $(TARGET_SUBDIR)/boehm-gc/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -22805,6 +23756,7 @@ configure-target-qthreads: $(TARGET_SUBDIR)/qthreads/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -23083,6 +24035,7 @@ configure-target-rda: $(TARGET_SUBDIR)/rda/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -23361,6 +24314,7 @@ configure-target-libada: $(TARGET_SUBDIR)/libada/multilib.out CXX="$(CXX_FOR_TARGET)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -23655,6 +24609,8 @@ configure-gcc: WINDRES="$(WINDRES)"; export WINDRES; \ OBJCOPY="$(OBJCOPY)"; export OBJCOPY; \ OBJDUMP="$(OBJDUMP)"; export OBJDUMP; \ + GMPLIBS="$(HOST_GMPLIBS)"; export GMPLIBS; \ + GMPINC="$(HOST_GMPINC)"; export GMPINC; \ echo Configuring in gcc; \ cd gcc || exit 1; \ case $(srcdir) in \ @@ -24335,11 +25291,11 @@ new-restage3: all-stage2-gcc # GCC needs to identify certain tools. # GCC also needs the information exported by the intl configure script. configure-gcc: maybe-configure-intl maybe-configure-binutils maybe-configure-gas maybe-configure-ld maybe-configure-bison maybe-configure-flex -all-gcc: maybe-all-libiberty maybe-all-intl maybe-all-bison maybe-all-byacc maybe-all-binutils maybe-all-gas maybe-all-ld maybe-all-zlib +all-gcc: maybe-all-libiberty maybe-all-intl maybe-all-bison maybe-all-byacc maybe-all-binutils maybe-all-gas maybe-all-ld maybe-all-zlib maybe-all-libbanshee # This is a slightly kludgy method of getting dependencies on # all-build-libiberty correct; it would be better to build it every time. -all-gcc: maybe-all-build-libiberty -all-bootstrap: maybe-all-binutils maybe-all-bison maybe-all-byacc maybe-all-gas maybe-all-intl maybe-all-ld maybe-all-libiberty maybe-all-texinfo maybe-all-zlib +all-gcc: maybe-all-build-libiberty maybe-all-libbanshee +all-bootstrap: maybe-all-binutils maybe-all-bison maybe-all-byacc maybe-all-gas maybe-all-intl maybe-all-ld maybe-all-libbanshee maybe-all-libiberty maybe-all-texinfo maybe-all-zlib # Host modules specific to gdb. # GDB needs to know that the simulator is being built. @@ -24414,6 +25370,7 @@ all-target-fastjar: maybe-all-target-zlib maybe-all-target-libiberty configure-target-libada: $(ALL_GCC_C) configure-target-libf2c: $(ALL_GCC_C) all-target-libf2c: maybe-all-target-libiberty +configure-target-libgfortran: $(ALL_GCC_C) configure-target-libffi: $(ALL_GCC_C) configure-target-libjava: $(ALL_GCC_C) maybe-configure-target-zlib maybe-configure-target-boehm-gc maybe-configure-target-qthreads maybe-configure-target-libffi all-target-libjava: maybe-all-fastjar maybe-all-target-zlib maybe-all-target-boehm-gc maybe-all-target-qthreads maybe-all-target-libffi diff --git a/Makefile.tpl b/Makefile.tpl index 18d55f229f4..a8515bd6d56 100644 --- a/Makefile.tpl +++ b/Makefile.tpl @@ -105,7 +105,7 @@ REALLY_SET_LIB_PATH = \ $(RPATH_ENVVAR)=`echo "$(HOST_LIB_PATH):$(TARGET_LIB_PATH):$$$(RPATH_ENVVAR)" | sed 's,::*,:,g;s,^:*,,;s,:*$$,,'`; export $(RPATH_ENVVAR); # This is the list of directories to be built for the build system. -BUILD_CONFIGDIRS = libiberty +BUILD_CONFIGDIRS = libiberty libbanshee # Build programs are put under this directory. BUILD_SUBDIR = @build_subdir@ # This is set by the configure script to the arguments to use when configuring @@ -127,6 +127,10 @@ TARGET_SUBDIR = @target_subdir@ # directories built for the target. TARGET_CONFIGARGS = @target_configargs@ +# Where to find GMP +HOST_GMPLIBS = @gmplibs@ +HOST_GMPINC = @gmpinc@ + # ---------------------------------------------- # Programs producing files for the BUILD machine # ---------------------------------------------- @@ -244,7 +248,7 @@ PICFLAG = # This is the list of directories that may be needed in RPATH_ENVVAR # so that prorgams built for the target machine work. -TARGET_LIB_PATH = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs: +TARGET_LIB_PATH = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs:$$r/$(TARGET_SUBDIR)/libmudflap/.libs FLAGS_FOR_TARGET = @FLAGS_FOR_TARGET@ @@ -311,6 +315,7 @@ USUAL_DLLTOOL_FOR_TARGET = ` \ fi` GCJ_FOR_TARGET = @GCJ_FOR_TARGET@ +GFORTRAN_FOR_TARGET = @GFORTRAN_FOR_TARGET@ LD_FOR_TARGET=@LD_FOR_TARGET@ CONFIGURED_LD_FOR_TARGET=@CONFIGURED_LD_FOR_TARGET@ @@ -705,6 +710,7 @@ configure-build-[+module+]: CXX="$(CXX_FOR_BUILD)"; export CXX; \ CXXFLAGS="$(CXXFLAGS_FOR_BUILD)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_BUILD)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_BUILD)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_BUILD)"; export DLLTOOL; \ LD="$(LD_FOR_BUILD)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_BUILD)"; export LDFLAGS; \ @@ -921,6 +927,7 @@ ELSE normal_cxx +] ENDIF raw_cxx +] CXXFLAGS="$(CXXFLAGS_FOR_TARGET)"; export CXXFLAGS; \ GCJ="$(GCJ_FOR_TARGET)"; export GCJ; \ + GFORTRAN="$(GFORTRAN_FOR_TARGET)"; export GFORTRAN; \ DLLTOOL="$(DLLTOOL_FOR_TARGET)"; export DLLTOOL; \ LD="$(LD_FOR_TARGET)"; export LD; \ LDFLAGS="$(LDFLAGS_FOR_TARGET)"; export LDFLAGS; \ @@ -1083,6 +1090,8 @@ configure-gcc: WINDRES="$(WINDRES)"; export WINDRES; \ OBJCOPY="$(OBJCOPY)"; export OBJCOPY; \ OBJDUMP="$(OBJDUMP)"; export OBJDUMP; \ + GMPLIBS="$(HOST_GMPLIBS)"; export GMPLIBS; \ + GMPINC="$(HOST_GMPINC)"; export GMPINC; \ echo Configuring in gcc; \ cd gcc || exit 1; \ case $(srcdir) in \ @@ -1600,10 +1609,10 @@ new-restage3: all-stage2-gcc # GCC needs to identify certain tools. # GCC also needs the information exported by the intl configure script. configure-gcc: maybe-configure-intl maybe-configure-binutils maybe-configure-gas maybe-configure-ld maybe-configure-bison maybe-configure-flex -all-gcc: maybe-all-libiberty maybe-all-intl maybe-all-bison maybe-all-byacc maybe-all-binutils maybe-all-gas maybe-all-ld maybe-all-zlib +all-gcc: maybe-all-libiberty maybe-all-intl maybe-all-bison maybe-all-byacc maybe-all-binutils maybe-all-gas maybe-all-ld maybe-all-zlib maybe-all-libbanshee # This is a slightly kludgy method of getting dependencies on # all-build-libiberty correct; it would be better to build it every time. -all-gcc: maybe-all-build-libiberty +all-gcc: maybe-all-build-libiberty maybe-all-libbanshee all-bootstrap: [+ FOR host_modules +][+ IF bootstrap +]maybe-all-[+module+] [+ ENDIF bootstrap +][+ ENDFOR host_modules +] # Host modules specific to gdb. @@ -1679,6 +1688,7 @@ all-target-fastjar: maybe-all-target-zlib maybe-all-target-libiberty configure-target-libada: $(ALL_GCC_C) configure-target-libf2c: $(ALL_GCC_C) all-target-libf2c: maybe-all-target-libiberty +configure-target-libgfortran: $(ALL_GCC_C) configure-target-libffi: $(ALL_GCC_C) configure-target-libjava: $(ALL_GCC_C) maybe-configure-target-zlib maybe-configure-target-boehm-gc maybe-configure-target-qthreads maybe-configure-target-libffi all-target-libjava: maybe-all-fastjar maybe-all-target-zlib maybe-all-target-boehm-gc maybe-all-target-qthreads maybe-all-target-libffi diff --git a/configure b/configure index 65ecf0975e0..fd4f900547f 100755 --- a/configure +++ b/configure @@ -11,8 +11,14 @@ ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: +ac_help="$ac_help + --without-libbanshee Don't build with libbanshee" ac_help="$ac_help --enable-libada Builds libada directory" +ac_help="$ac_help + --with-gmp-dir=PATH Specify source directory for GMP library" +ac_help="$ac_help + --with-gmp=PATH Specify directory for installed GMP library" ac_help="$ac_help --enable-serial-[{host,target,build}-]configure Force sequential configuration of @@ -581,7 +587,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:585: checking host system type" >&5 +echo "configure:591: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -602,7 +608,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 echo $ac_n "checking target system type""... $ac_c" 1>&6 -echo "configure:606: checking target system type" >&5 +echo "configure:612: checking target system type" >&5 target_alias=$target case "$target_alias" in @@ -620,7 +626,7 @@ target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$target" 1>&6 echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:624: checking build system type" >&5 +echo "configure:630: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -675,7 +681,7 @@ test "$program_transform_name" = "" && program_transform_name="s,x,x," # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:679: checking for a BSD compatible install" >&5 +echo "configure:685: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -880,7 +886,7 @@ fi # these libraries are used by various programs built for the host environment # -host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl tix libgui zlib" +host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl tix libgui zlib libbanshee" # these tools are built for the host environment # Note, the powerpc-eabi build depends on sim occurring before gdb in order to @@ -903,7 +909,9 @@ target_libraries="target-libiberty \ target-libgloss \ target-newlib \ target-libstdc++-v3 \ + target-libmudflap \ target-libf2c \ + target-libgfortran \ ${libgcj} \ target-libobjc \ target-libada" @@ -1082,6 +1090,22 @@ case "${host}" in ;; esac +# Check whether --with-libbanshee or --without-libbanshee was given. +if test "${with_libbanshee+set}" = set; then + withval="$with_libbanshee" + : +fi + +case ${with_libbanshee} in + no) + noconfigdirs="$noconfigdirs libbanshee" ;; + yes|"") + with_libbanshee=yes + ;; + *) + { echo "configure: error: --with-libbanshee can only be empty, "yes" or "no" (empty defaults to "yes"." 1>&2; exit 1; } +esac + # Check whether --enable-libada or --disable-libada was given. if test "${enable_libada+set}" = set; then enableval="$enable_libada" @@ -1110,6 +1134,18 @@ no) ;; esac + +# Allow --disable-libmudflap to exclude target-libmudflap +case $enable_libmudflap in +yes | "") + # By default it's enabled + ;; +no) + noconfigdirs="$noconfigdirs target-libmudflap" + ;; +esac + + case "${target}" in *-*-chorusos) noconfigdirs="$noconfigdirs target-newlib target-libgloss ${libgcj}" @@ -1125,6 +1161,22 @@ case "${target}" in *-*-freebsd[12] | *-*-freebsd[12].* | *-*-freebsd*aout*) noconfigdirs="$noconfigdirs target-newlib target-libgloss ${libgcj}" ;; + *-*-freebsd* | *-*-kfreebsd*-gnu) + noconfigdirs="$noconfigdirs target-newlib target-libgloss" + if test "x$with_gmp" = x && test "x$with_gmp_dir" = x \ + && test -f /usr/local/include/gmp.h; then + with_gmp=/usr/local + fi + + # Skip some stuff that's unsupported on some FreeBSD configurations. + case "${target}" in + i*86-*-*) ;; + alpha*-*-*) ;; + *) + noconfigdirs="$noconfigdirs ${libgcj}" + ;; + esac + ;; *-*-kaos*) # Remove unsupported stuff on all kaOS configurations. skipdirs="target-libiberty ${libgcj} target-libstdc++-v3 target-libf2c target-librx" @@ -1176,9 +1228,6 @@ case "${target}" in # newlib is not 64 bit ready noconfigdirs="$noconfigdirs target-newlib target-libgloss" ;; - alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) - noconfigdirs="$noconfigdirs target-newlib target-libgloss" - ;; alpha*-*-*) # newlib is not 64 bit ready noconfigdirs="$noconfigdirs target-newlib target-libgloss ${libgcj}" @@ -1297,9 +1346,6 @@ case "${target}" in i[3456789]86-*-coff | i[3456789]86-*-elf) noconfigdirs="$noconfigdirs ${libgcj}" ;; - i[3456789]86-*-freebsd* | i[3456789]86-*-kfreebsd*-gnu) - noconfigdirs="$noconfigdirs target-newlib target-libgloss" - ;; i[3456789]86-*-linux*) # The GCC port for glibc1 has no MD_FALLBACK_FRAME_STATE_FOR, so let's # not build java stuff by default. @@ -1855,7 +1901,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1859: checking for $ac_word" >&5 +echo "configure:1905: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1885,7 +1931,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1889: checking for $ac_word" >&5 +echo "configure:1935: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1936,7 +1982,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1940: checking for $ac_word" >&5 +echo "configure:1986: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1968,7 +2014,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:1972: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 +echo "configure:2018: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -1979,12 +2025,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 1983 "configure" +#line 2029 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2034: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -2010,12 +2056,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:2014: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:2060: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:2019: checking whether we are using GNU C" >&5 +echo "configure:2065: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2024,7 +2070,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:2028: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:2074: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -2043,7 +2089,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:2047: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:2093: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2079,7 +2125,7 @@ fi # Extract the first word of "${ac_tool_prefix}gnatbind", so it can be a program name with args. set dummy ${ac_tool_prefix}gnatbind; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2083: checking for $ac_word" >&5 +echo "configure:2129: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_GNATBIND'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2111,7 +2157,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "gnatbind", so it can be a program name with args. set dummy gnatbind; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2115: checking for $ac_word" >&5 +echo "configure:2161: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_GNATBIND'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2144,7 +2190,7 @@ fi fi echo $ac_n "checking whether compiler driver understands Ada""... $ac_c" 1>&6 -echo "configure:2148: checking whether compiler driver understands Ada" >&5 +echo "configure:2194: checking whether compiler driver understands Ada" >&5 if eval "test \"`echo '$''{'acx_cv_cc_gcc_supports_ada'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2177,7 +2223,7 @@ else fi echo $ac_n "checking how to compare bootstrapped objects""... $ac_c" 1>&6 -echo "configure:2181: checking how to compare bootstrapped objects" >&5 +echo "configure:2227: checking how to compare bootstrapped objects" >&5 if eval "test \"`echo '$''{'gcc_cv_prog_cmp_skip'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2207,6 +2253,104 @@ do_compare="$gcc_cv_prog_cmp_skip" +# Check for GMP +gmplibs= +gmpinc= +have_gmp=yes +# Specify a location for gmp +# Check whether --with-gmp-dir or --without-gmp-dir was given. +if test "${with_gmp_dir+set}" = set; then + withval="$with_gmp_dir" + : +fi + + +if test "x$with_gmp_dir" != x && test -f "$with_gmp_dir/gmp.h"; then + gmpinc="-I$with_gmp_dir" + if test -f "$with_gmp_dir/.libs/libgmp.a"; then + gmplibs="$with_gmp_dir/.libs/libgmp.a" + elif test -f "$with_gmp_dir/_libs/libgmp.a"; then + gmplibs="$with_gmp_dir/_libs/libgmp.a" + fi + # One of the later tests will catch the error if neither library is present. +fi + +# Check whether --with-gmp or --without-gmp was given. +if test "${with_gmp+set}" = set; then + withval="$with_gmp" + : +fi + + +if test "x$with_gmp" != x && test -d "$with_gmp"; then + gmplibs="-L$with_gmp/lib -lgmp" + gmpinc="-I$with_gmp/include" +fi + +# Use system gmp if nothing else specified +if test "x$gmplibs" = x; then + gmplibs="-lgmp" +fi + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $gmpinc" +# Check GMP actually works +echo $ac_n "checking for correct version of gmp.h""... $ac_c" 1>&6 +echo "configure:2300: checking for correct version of gmp.h" >&5 +cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6; have_gmp=no +fi +rm -f conftest* + +if test x"$have_gmp" = xyes; then + echo $ac_n "checking for mpf_init in -lgmp""... $ac_c" 1>&6 +echo "configure:2326: checking for mpf_init in -lgmp" >&5 + + saved_LIBS="$LIBS" + LIBS="$LIBS $gmplibs" + cat > conftest.$ac_ext < +int main() { +mpf_t n; mpf_init(n); +; return 0; } +EOF +if { (eval echo configure:2338: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6; have_gmp=no +fi +rm -f conftest* + LIBS="$saved_LIBS" + CFLAGS="$saved_CFLAGS" +fi + + + + # By default, C is the only stage 1 language. stage1_languages=c @@ -2279,6 +2423,7 @@ if test -d ${srcdir}/gcc; then lang_dirs= boot_language= build_by_default= + need_gmp= . ${lang_frag} # This is quite sensitive to the ordering of the case statement arms. case ,${enable_languages},:${language}:${have_gnat}:${build_by_default} in @@ -2307,7 +2452,13 @@ if test -d ${srcdir}/gcc; then add_this_lang=no ;; esac - case $add_this_lang in + + # Disable language that need GMP if it isn't available. + if test x"$need_gmp" = xyes && test x"$have_gmp" = xno; then + add_this_lang=no + fi + + case $add_this_lang in no) # Remove language-dependent dirs. eval noconfigdirs='"$noconfigdirs "'\"$target_libs $lang_dirs\" @@ -2608,6 +2759,9 @@ if test x${with_newlib} != xno && echo " ${target_configdirs} " | grep " target- extra_host_args="$extra_host_args --with-newlib" fi +if test x${with_libbanshee} = xyes && echo " ${configdirs} " | grep " libbanshee " >/dev/null 2>&1; then + extra_host_args="$extra_host_args --with-libbanshee" +fi # Default to using --with-stabs for certain targets. if test x${with_stabs} = x ; then @@ -2642,7 +2796,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2646: checking for $ac_word" >&5 +echo "configure:2800: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_DEFAULT_YACC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2677,7 +2831,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2681: checking for $ac_word" >&5 +echo "configure:2835: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_DEFAULT_M4'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2712,7 +2866,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2716: checking for $ac_word" >&5 +echo "configure:2870: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_DEFAULT_LEX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3175,6 +3329,20 @@ else fi GCJ_FOR_TARGET=$GCJ_FOR_TARGET' $(FLAGS_FOR_TARGET)' +if test "x${GFORTRAN_FOR_TARGET+set}" = xset; then + : +elif test -d ${srcdir}/gcc; then + GFORTRAN_FOR_TARGET='$$r/gcc/gfortran -B$$r/gcc/' +elif test "$host" = "$target"; then + GFORTRAN_FOR_TARGET='gfortran' +else + GFORTRAN_FOR_TARGET=`echo gfortran | sed -e 's/x/x/' ${program_transform_name}` +fi +case $GFORTRAN_FOR_TARGET in +*' $(FLAGS_FOR_TARGET)') ;; +*) GFORTRAN_FOR_TARGET=$GFORTRAN_FOR_TARGET' $(FLAGS_FOR_TARGET)' ;; +esac + # Don't use libstdc++-v3's flags to configure/build itself. libstdcxx_flags='`test ! -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags || $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs' raw_libstdcxx_flags='-L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs' @@ -3216,6 +3384,7 @@ qqRAW_CXX_FOR_TARGET=`echo "$qRAW_CXX_FOR_TARGET" | sed -e 's,[$][$],$$$$,g'` # Wrap CC_FOR_TARGET and friends, for certain types of builds. CC_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${CC_FOR_TARGET}" GCJ_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${GCJ_FOR_TARGET}" +GFORTRAN_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${GFORTRAN_FOR_TARGET}" CXX_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${qCXX_FOR_TARGET}" RAW_CXX_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${qRAW_CXX_FOR_TARGET}" CXX_FOR_TARGET_FOR_RECURSIVE_MAKE="\$(STAGE_CC_WRAPPER) ${qqCXX_FOR_TARGET}" @@ -3275,7 +3444,7 @@ test -n "$target_alias" && ncn_target_tool_prefix=$target_alias- # Extract the first word of "${ncn_tool_prefix}ar", so it can be a program name with args. set dummy ${ncn_tool_prefix}ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3279: checking for $ac_word" >&5 +echo "configure:3448: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3308,7 +3477,7 @@ if test -z "$ac_cv_prog_AR" ; then # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3312: checking for $ac_word" >&5 +echo "configure:3481: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3347,7 +3516,7 @@ fi # Extract the first word of "${ncn_tool_prefix}as", so it can be a program name with args. set dummy ${ncn_tool_prefix}as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3351: checking for $ac_word" >&5 +echo "configure:3520: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3380,7 +3549,7 @@ if test -z "$ac_cv_prog_AS" ; then # Extract the first word of "as", so it can be a program name with args. set dummy as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3384: checking for $ac_word" >&5 +echo "configure:3553: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_AS'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3419,7 +3588,7 @@ fi # Extract the first word of "${ncn_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ncn_tool_prefix}dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3423: checking for $ac_word" >&5 +echo "configure:3592: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3452,7 +3621,7 @@ if test -z "$ac_cv_prog_DLLTOOL" ; then # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3456: checking for $ac_word" >&5 +echo "configure:3625: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_DLLTOOL'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3491,7 +3660,7 @@ fi # Extract the first word of "${ncn_tool_prefix}ld", so it can be a program name with args. set dummy ${ncn_tool_prefix}ld; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3495: checking for $ac_word" >&5 +echo "configure:3664: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3524,7 +3693,7 @@ if test -z "$ac_cv_prog_LD" ; then # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3528: checking for $ac_word" >&5 +echo "configure:3697: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_LD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3563,7 +3732,7 @@ fi # Extract the first word of "${ncn_tool_prefix}nm", so it can be a program name with args. set dummy ${ncn_tool_prefix}nm; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3567: checking for $ac_word" >&5 +echo "configure:3736: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3596,7 +3765,7 @@ if test -z "$ac_cv_prog_NM" ; then # Extract the first word of "nm", so it can be a program name with args. set dummy nm; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3600: checking for $ac_word" >&5 +echo "configure:3769: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_NM'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3635,7 +3804,7 @@ fi # Extract the first word of "${ncn_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ncn_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3639: checking for $ac_word" >&5 +echo "configure:3808: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3668,7 +3837,7 @@ if test -z "$ac_cv_prog_RANLIB" ; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3672: checking for $ac_word" >&5 +echo "configure:3841: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3707,7 +3876,7 @@ fi # Extract the first word of "${ncn_tool_prefix}windres", so it can be a program name with args. set dummy ${ncn_tool_prefix}windres; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3711: checking for $ac_word" >&5 +echo "configure:3880: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3740,7 +3909,7 @@ if test -z "$ac_cv_prog_WINDRES" ; then # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3744: checking for $ac_word" >&5 +echo "configure:3913: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_WINDRES'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3779,7 +3948,7 @@ fi # Extract the first word of "${ncn_tool_prefix}objcopy", so it can be a program name with args. set dummy ${ncn_tool_prefix}objcopy; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3783: checking for $ac_word" >&5 +echo "configure:3952: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_OBJCOPY'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3812,7 +3981,7 @@ if test -z "$ac_cv_prog_OBJCOPY" ; then # Extract the first word of "objcopy", so it can be a program name with args. set dummy objcopy; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3816: checking for $ac_word" >&5 +echo "configure:3985: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_OBJCOPY'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3851,7 +4020,7 @@ fi # Extract the first word of "${ncn_tool_prefix}objdump", so it can be a program name with args. set dummy ${ncn_tool_prefix}objdump; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3855: checking for $ac_word" >&5 +echo "configure:4024: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_OBJDUMP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3884,7 +4053,7 @@ if test -z "$ac_cv_prog_OBJDUMP" ; then # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3888: checking for $ac_word" >&5 +echo "configure:4057: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_OBJDUMP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3933,7 +4102,7 @@ fi # Extract the first word of "${ncn_target_tool_prefix}ar", so it can be a program name with args. set dummy ${ncn_target_tool_prefix}ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3937: checking for $ac_word" >&5 +echo "configure:4106: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CONFIGURED_AR_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -3966,7 +4135,7 @@ if test -z "$ac_cv_prog_CONFIGURED_AR_FOR_TARGET" ; then # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:3970: checking for $ac_word" >&5 +echo "configure:4139: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_CONFIGURED_AR_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4005,7 +4174,7 @@ fi # Extract the first word of "${ncn_target_tool_prefix}as", so it can be a program name with args. set dummy ${ncn_target_tool_prefix}as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4009: checking for $ac_word" >&5 +echo "configure:4178: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CONFIGURED_AS_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4038,7 +4207,7 @@ if test -z "$ac_cv_prog_CONFIGURED_AS_FOR_TARGET" ; then # Extract the first word of "as", so it can be a program name with args. set dummy as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4042: checking for $ac_word" >&5 +echo "configure:4211: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_CONFIGURED_AS_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4077,7 +4246,7 @@ fi # Extract the first word of "${ncn_target_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ncn_target_tool_prefix}dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4081: checking for $ac_word" >&5 +echo "configure:4250: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CONFIGURED_DLLTOOL_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4110,7 +4279,7 @@ if test -z "$ac_cv_prog_CONFIGURED_DLLTOOL_FOR_TARGET" ; then # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4114: checking for $ac_word" >&5 +echo "configure:4283: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_CONFIGURED_DLLTOOL_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4149,7 +4318,7 @@ fi # Extract the first word of "${ncn_target_tool_prefix}ld", so it can be a program name with args. set dummy ${ncn_target_tool_prefix}ld; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4153: checking for $ac_word" >&5 +echo "configure:4322: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CONFIGURED_LD_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4182,7 +4351,7 @@ if test -z "$ac_cv_prog_CONFIGURED_LD_FOR_TARGET" ; then # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4186: checking for $ac_word" >&5 +echo "configure:4355: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_CONFIGURED_LD_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4221,7 +4390,7 @@ fi # Extract the first word of "${ncn_target_tool_prefix}nm", so it can be a program name with args. set dummy ${ncn_target_tool_prefix}nm; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4225: checking for $ac_word" >&5 +echo "configure:4394: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CONFIGURED_NM_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4254,7 +4423,7 @@ if test -z "$ac_cv_prog_CONFIGURED_NM_FOR_TARGET" ; then # Extract the first word of "nm", so it can be a program name with args. set dummy nm; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4258: checking for $ac_word" >&5 +echo "configure:4427: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_CONFIGURED_NM_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4293,7 +4462,7 @@ fi # Extract the first word of "${ncn_target_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ncn_target_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4297: checking for $ac_word" >&5 +echo "configure:4466: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CONFIGURED_RANLIB_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4326,7 +4495,7 @@ if test -z "$ac_cv_prog_CONFIGURED_RANLIB_FOR_TARGET" ; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4330: checking for $ac_word" >&5 +echo "configure:4499: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_CONFIGURED_RANLIB_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4365,7 +4534,7 @@ fi # Extract the first word of "${ncn_target_tool_prefix}windres", so it can be a program name with args. set dummy ${ncn_target_tool_prefix}windres; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4369: checking for $ac_word" >&5 +echo "configure:4538: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CONFIGURED_WINDRES_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4398,7 +4567,7 @@ if test -z "$ac_cv_prog_CONFIGURED_WINDRES_FOR_TARGET" ; then # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:4402: checking for $ac_word" >&5 +echo "configure:4571: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_ncn_cv_CONFIGURED_WINDRES_FOR_TARGET'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -4443,6 +4612,7 @@ fi + # Fix up target tools. if test "x${build}" = "x${host}" ; then # In this case, the newly built tools can and should be used, @@ -4482,7 +4652,7 @@ RANLIB_FOR_TARGET=${RANLIB_FOR_TARGET}${extra_ranlibflags_for_target} NM_FOR_TARGET=${NM_FOR_TARGET}${extra_nmflags_for_target} echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 -echo "configure:4486: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "configure:4656: checking whether to enable maintainer-specific portions of Makefiles" >&5 # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then enableval="$enable_maintainer_mode" @@ -4607,15 +4777,34 @@ trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. -cat > conftest.defs <<\EOF -s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g -s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g -s%\[%\\&%g -s%\]%\\&%g -s%\$%$$%g -EOF -DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` -rm -f conftest.defs +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then we branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +cat >confdef2opt.sed <<\_ACEOF +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g +t quote +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g +t quote +d +: quote +s,[ `~#$^&*(){}\\|;'"<>?],\\&,g +s,\[,\\&,g +s,\],\\&,g +s,\$,$$,g +p +_ACEOF +# We use echo to avoid assuming a particular line-breaking character. +# The extra dot is to prevent the shell from consuming trailing +# line-breaks from the sub-command output. A line-break within +# single-quotes doesn't work because, if this script is created in a +# platform that uses two characters for line-breaks (e.g., DOS), tr +# would break. +ac_LF_and_DOT=`echo; echo .` +DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` +rm -f confdef2opt.sed # Without the "./", some shells look in PATH for config.status. @@ -4711,6 +4900,8 @@ s%@target_subdir@%$target_subdir%g s%@CC@%$CC%g s%@GNATBIND@%$GNATBIND%g s%@do_compare@%$do_compare%g +s%@gmplibs@%$gmplibs%g +s%@gmpinc@%$gmpinc%g s%@stage1_languages@%$stage1_languages%g s%@DEFAULT_YACC@%$DEFAULT_YACC%g s%@DEFAULT_M4@%$DEFAULT_M4%g @@ -4789,6 +4980,7 @@ s%@GCC_FOR_TARGET@%$GCC_FOR_TARGET%g s%@FLAGS_FOR_TARGET@%$FLAGS_FOR_TARGET%g s%@CC_FOR_TARGET@%$CC_FOR_TARGET%g s%@GCJ_FOR_TARGET@%$GCJ_FOR_TARGET%g +s%@GFORTRAN_FOR_TARGET@%$GFORTRAN_FOR_TARGET%g s%@CXX_FOR_TARGET@%$CXX_FOR_TARGET%g s%@RAW_CXX_FOR_TARGET@%$RAW_CXX_FOR_TARGET%g s%@CXX_FOR_TARGET_FOR_RECURSIVE_MAKE@%$CXX_FOR_TARGET_FOR_RECURSIVE_MAKE%g diff --git a/configure.in b/configure.in index 86bc1278460..a3e1f863445 100644 --- a/configure.in +++ b/configure.in @@ -126,7 +126,7 @@ fi # these libraries are used by various programs built for the host environment # -host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl tix libgui zlib" +host_libs="intl mmalloc libiberty opcodes bfd readline tcl tk itcl tix libgui zlib libbanshee" # these tools are built for the host environment # Note, the powerpc-eabi build depends on sim occurring before gdb in order to @@ -149,7 +149,9 @@ target_libraries="target-libiberty \ target-libgloss \ target-newlib \ target-libstdc++-v3 \ + target-libmudflap \ target-libf2c \ + target-libgfortran \ ${libgcj} \ target-libobjc \ target-libada" @@ -307,6 +309,18 @@ case "${host}" in ;; esac +AC_ARG_WITH(libbanshee, +[ --without-libbanshee Don't build with libbanshee]) +case ${with_libbanshee} in + no) + noconfigdirs="$noconfigdirs libbanshee" ;; + yes|"") + with_libbanshee=yes + ;; + *) + AC_MSG_ERROR([--with-libbanshee can only be empty, "yes" or "no" (empty defaults to "yes".]) +esac + AC_ARG_ENABLE(libada, [ --enable-libada Builds libada directory], ENABLE_LIBADA=$enableval, @@ -331,6 +345,18 @@ no) ;; esac + +# Allow --disable-libmudflap to exclude target-libmudflap +case $enable_libmudflap in +yes | "") + # By default it's enabled + ;; +no) + noconfigdirs="$noconfigdirs target-libmudflap" + ;; +esac + + case "${target}" in *-*-chorusos) noconfigdirs="$noconfigdirs target-newlib target-libgloss ${libgcj}" @@ -346,6 +372,22 @@ case "${target}" in *-*-freebsd[[12]] | *-*-freebsd[[12]].* | *-*-freebsd*aout*) noconfigdirs="$noconfigdirs target-newlib target-libgloss ${libgcj}" ;; + *-*-freebsd* | *-*-kfreebsd*-gnu) + noconfigdirs="$noconfigdirs target-newlib target-libgloss" + if test "x$with_gmp" = x && test "x$with_gmp_dir" = x \ + && test -f /usr/local/include/gmp.h; then + with_gmp=/usr/local + fi + + # Skip some stuff that's unsupported on some FreeBSD configurations. + case "${target}" in + i*86-*-*) ;; + alpha*-*-*) ;; + *) + noconfigdirs="$noconfigdirs ${libgcj}" + ;; + esac + ;; *-*-kaos*) # Remove unsupported stuff on all kaOS configurations. skipdirs="target-libiberty ${libgcj} target-libstdc++-v3 target-libf2c target-librx" @@ -397,9 +439,6 @@ case "${target}" in # newlib is not 64 bit ready noconfigdirs="$noconfigdirs target-newlib target-libgloss" ;; - alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu) - noconfigdirs="$noconfigdirs target-newlib target-libgloss" - ;; alpha*-*-*) # newlib is not 64 bit ready noconfigdirs="$noconfigdirs target-newlib target-libgloss ${libgcj}" @@ -518,9 +557,6 @@ case "${target}" in i[[3456789]]86-*-coff | i[[3456789]]86-*-elf) noconfigdirs="$noconfigdirs ${libgcj}" ;; - i[[3456789]]86-*-freebsd* | i[[3456789]]86-*-kfreebsd*-gnu) - noconfigdirs="$noconfigdirs target-newlib target-libgloss" - ;; i[[3456789]]86-*-linux*) # The GCC port for glibc1 has no MD_FALLBACK_FRAME_STATE_FOR, so let's # not build java stuff by default. @@ -1070,6 +1106,60 @@ fi ACX_PROG_GNAT ACX_PROG_CMP_IGNORE_INITIAL +# Check for GMP +gmplibs= +gmpinc= +have_gmp=yes +# Specify a location for gmp +AC_ARG_WITH(gmp-dir, [ --with-gmp-dir=PATH Specify source directory for GMP library]) + +if test "x$with_gmp_dir" != x && test -f "$with_gmp_dir/gmp.h"; then + gmpinc="-I$with_gmp_dir" + if test -f "$with_gmp_dir/.libs/libgmp.a"; then + gmplibs="$with_gmp_dir/.libs/libgmp.a" + elif test -f "$with_gmp_dir/_libs/libgmp.a"; then + gmplibs="$with_gmp_dir/_libs/libgmp.a" + fi + # One of the later tests will catch the error if neither library is present. +fi + +AC_ARG_WITH(gmp, [ --with-gmp=PATH Specify directory for installed GMP library]) + +if test "x$with_gmp" != x && test -d "$with_gmp"; then + gmplibs="-L$with_gmp/lib -lgmp" + gmpinc="-I$with_gmp/include" +fi + +# Use system gmp if nothing else specified +if test "x$gmplibs" = x; then + gmplibs="-lgmp" +fi + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $gmpinc" +# Check GMP actually works +AC_MSG_CHECKING([for correct version of gmp.h]) +AC_TRY_COMPILE([#include "gmp.h"],[ +#if __GNU_MP_VERSION < 3 +choke me +#endif +], [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]); have_gmp=no]) + +if test x"$have_gmp" = xyes; then + AC_MSG_CHECKING([for mpf_init in -lgmp]) + + saved_LIBS="$LIBS" + LIBS="$LIBS $gmplibs" + AC_TRY_LINK([#include ], [mpf_t n; mpf_init(n);], + [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]); have_gmp=no]) + LIBS="$saved_LIBS" + CFLAGS="$saved_CFLAGS" +fi + +AC_SUBST(gmplibs) +AC_SUBST(gmpinc) + # By default, C is the only stage 1 language. stage1_languages=c AC_SUBST(stage1_languages) @@ -1142,6 +1232,7 @@ if test -d ${srcdir}/gcc; then lang_dirs= boot_language= build_by_default= + need_gmp= . ${lang_frag} # This is quite sensitive to the ordering of the case statement arms. case ,${enable_languages},:${language}:${have_gnat}:${build_by_default} in @@ -1170,7 +1261,13 @@ if test -d ${srcdir}/gcc; then add_this_lang=no ;; esac - case $add_this_lang in + + # Disable language that need GMP if it isn't available. + if test x"$need_gmp" = xyes && test x"$have_gmp" = xno; then + add_this_lang=no + fi + + case $add_this_lang in no) # Remove language-dependent dirs. eval noconfigdirs='"$noconfigdirs "'\"$target_libs $lang_dirs\" @@ -1471,6 +1568,9 @@ if test x${with_newlib} != xno && echo " ${target_configdirs} " | grep " target- extra_host_args="$extra_host_args --with-newlib" fi +if test x${with_libbanshee} = xyes && echo " ${configdirs} " | grep " libbanshee " >/dev/null 2>&1; then + extra_host_args="$extra_host_args --with-libbanshee" +fi # Default to using --with-stabs for certain targets. if test x${with_stabs} = x ; then @@ -1935,6 +2035,20 @@ else fi GCJ_FOR_TARGET=$GCJ_FOR_TARGET' $(FLAGS_FOR_TARGET)' +if test "x${GFORTRAN_FOR_TARGET+set}" = xset; then + : +elif test -d ${srcdir}/gcc; then + GFORTRAN_FOR_TARGET='$$r/gcc/gfortran -B$$r/gcc/' +elif test "$host" = "$target"; then + GFORTRAN_FOR_TARGET='gfortran' +else + GFORTRAN_FOR_TARGET=`echo gfortran | sed -e 's/x/x/' ${program_transform_name}` +fi +case $GFORTRAN_FOR_TARGET in +*' $(FLAGS_FOR_TARGET)') ;; +*) GFORTRAN_FOR_TARGET=$GFORTRAN_FOR_TARGET' $(FLAGS_FOR_TARGET)' ;; +esac + # Don't use libstdc++-v3's flags to configure/build itself. libstdcxx_flags='`test ! -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags || $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs' raw_libstdcxx_flags='-L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs' @@ -1976,6 +2090,7 @@ qqRAW_CXX_FOR_TARGET=`echo "$qRAW_CXX_FOR_TARGET" | sed -e 's,[[$]][[$]],$$$$,g' # Wrap CC_FOR_TARGET and friends, for certain types of builds. CC_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${CC_FOR_TARGET}" GCJ_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${GCJ_FOR_TARGET}" +GFORTRAN_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${GFORTRAN_FOR_TARGET}" CXX_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${qCXX_FOR_TARGET}" RAW_CXX_FOR_TARGET="\$(STAGE_CC_WRAPPER) ${qRAW_CXX_FOR_TARGET}" CXX_FOR_TARGET_FOR_RECURSIVE_MAKE="\$(STAGE_CC_WRAPPER) ${qqCXX_FOR_TARGET}" @@ -2057,6 +2172,7 @@ AC_SUBST(GCC_FOR_TARGET) AC_SUBST(FLAGS_FOR_TARGET) AC_SUBST(CC_FOR_TARGET) AC_SUBST(GCJ_FOR_TARGET) +AC_SUBST(GFORTRAN_FOR_TARGET) AC_SUBST(CXX_FOR_TARGET) AC_SUBST(RAW_CXX_FOR_TARGET) AC_SUBST(CXX_FOR_TARGET_FOR_RECURSIVE_MAKE) diff --git a/contrib/ChangeLog b/contrib/ChangeLog index edc077af2e9..6451d6f0e90 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,14 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. + + * filter_gcc_for_doxygen: New file. + * filter_knr2ansi.pl: New file. + * filter_params.pl: New file. + * tree-ssa.doxy: New file. + * contrib/gcc_update (files_and_dependencies): Handle + libbanshee and libmudflap. + 2004-04-12 Kelley Cook Andreas Jaeger diff --git a/contrib/ChangeLog.tree-ssa b/contrib/ChangeLog.tree-ssa new file mode 100644 index 00000000000..2c1165f79b2 --- /dev/null +++ b/contrib/ChangeLog.tree-ssa @@ -0,0 +1,46 @@ +2004-03-25 Diego Novillo + + * gcc_update (files_and_dependencies): Add libbanshee and + libmudflap dependencies. + +2003-11-27 Diego Novillo + + * tree-ssa.doxy (FILE_PATTERNS): Update. + +2003-11-21 Diego Novillo + + * tree-ssa.doxy: Do not generate latex output. + +2003-07-21 Diego Novillo + + * tree-ssa.doxy: Include tree* files + +2003-07-15 Diego Novillo + + * tree-ssa.doxy: Add tree-must-alias.c. + +2003-01-28 Diego Novillo + + * filter_params.pl: Surround comments in @verbatim/@endverbatim. + +2003-01-19 Diego Novillo + + * tree-ssa.doxy (OUTPUT_DIRECTORY, INPUT_FILTER): Replace + hardwired values for with replaceable strings. + +2003-01-18 Diego Novillo + + * filter_params.pl: Change most comments to start with /**. + +2002-12-23 Steven Bosscher + + * filter_params.pl: Filter ATTRIBUTE_UNUSED. + +2002-12-12 Daniel Berlin + Steven Bosscher + Diego Novillo + + * filter_gcc_for_doxygen: New file. + * filter_knr2ansi.pl: New file. + * filter_params.pl: New file. + * tree-ssa.doxy: New file. diff --git a/contrib/filter_gcc_for_doxygen b/contrib/filter_gcc_for_doxygen new file mode 100755 index 00000000000..3787eebbf0e --- /dev/null +++ b/contrib/filter_gcc_for_doxygen @@ -0,0 +1,12 @@ +#!/bin/sh + +# This filters GCC source before Doxygen can get confused by it; +# this script is listed in the doxyfile. The output is not very +# pretty, but at least we get output that Doxygen can understand. +# +# $1 is a source file of some kind. The source we wish doxygen to +# process is put on stdout. + +dir=`dirname $0` +perl $dir/filter_params.pl < $1 | perl $dir/filter_knr2ansi.pl +exit 0 diff --git a/contrib/filter_knr2ansi.pl b/contrib/filter_knr2ansi.pl new file mode 100755 index 00000000000..c05e8d2ed20 --- /dev/null +++ b/contrib/filter_knr2ansi.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl +# +# Goes thourgh the input line by line to find K&R style function +# declarations, and replaces them with ANSI style declarations. +# +@blah = <>; + +for ($i = 0; $i < @blah; $i++) +{ + if ($blah[$i] =~ /^([a-zA-Z_0-9]+)\s*\([^)]+\)\s*$/) + { + $name = $1; + $funci = $i; + $blah[$funci]="$name ("; + $i++; + $lastline = $i; + while ($lastline < @blah && $blah[$lastline] !~ /^{/) + { + $lastline++; + } + $lastline--; + while ($i < @blah && $blah[$i] !~ /^{/) + { + $arg = $blah[$i]; + if ($i != $lastline) + { + $arg =~ s/;/,/g; + } + else + { + $arg =~ s/;//g; + } + $blah[$i] = ""; + $blah[$funci] = "$blah[$funci]" . "$arg"; + $i++; + } + $blah[$funci] = "$blah[$funci]" . ")\n"; + } +} + +for ($i = 0; $i < @blah; $i++) +{ + print $blah[$i]; +} + diff --git a/contrib/filter_params.pl b/contrib/filter_params.pl new file mode 100755 index 00000000000..05861e376fe --- /dev/null +++ b/contrib/filter_params.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl + +# Filters out some of the #defines used thourghout the GCC sources: +# - GTY(()) marks declarations for gengtype.c +# - PARAMS(()) is used for K&R compatibility. See ansidecl.h. + +while (<>) { + s/^\/\* /\/\*\* \@verbatim /; + s/\*\// \@endverbatim \*\//; + s/GTY[ \t]*\(\(.*\)\)//g; + s/[ \t]ATTRIBUTE_UNUSED//g; + s/PARAMS[ \t]*\(\((.*?)\)\)/\($1\)/sg; + print; +} diff --git a/contrib/gcc_update b/contrib/gcc_update index 9c4f40c44a7..dda18afd5a4 100755 --- a/contrib/gcc_update +++ b/contrib/gcc_update @@ -80,6 +80,8 @@ libf2c/libI77/stamp-h.in: libf2c/libI77/configure.in libf2c/libI77/config.h.in: libf2c/libI77/configure.in libf2c/libI77/stamp-h.in libf2c/libU77/configure: libf2c/libU77/configure.in libf2c/libU77/stamp-h.in: libf2c/libU77/configure.in libf2c/libU77/acconfig.h +libbanshee/configure: libbanshee/configure.in +libmudflap/configure: libmudflap/configure.in libobjc/configure: libobjc/configure.ac zlib/aclocal.m4: zlib/configure.ac zlib/acinclude.m4 zlib/Makefile.in: zlib/Makefile.am zlib/configure.ac zlib/aclocal.m4 diff --git a/contrib/tree-ssa.doxy b/contrib/tree-ssa.doxy new file mode 100644 index 00000000000..68d8f205ef1 --- /dev/null +++ b/contrib/tree-ssa.doxy @@ -0,0 +1,932 @@ +# Doxyfile 1.2.18 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + + +#----------------------------------------------------------------------------- +# NOTE: YOU MUST EDIT THE FOLLOWING HARDWIRED PATHS BEFORE USING THIS FILE. +#----------------------------------------------------------------------------- + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @OUTPUT_DIRECTORY@ + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = @INPUT_FILTER@ + +#----------------------------------------------------------------------------- + + + + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Tree SSA" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Chinese, Croatian, Czech, Danish, Dutch, Finnish, French, +# German, Greek, Hungarian, Italian, Japanese, Korean, Norwegian, Polish, +# Portuguese, Romanian, Russian, Slovak, Slovene, Spanish and Swedish. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consist of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl + +FILE_PATTERNS = tree* *mudflap* c-simplify.c gimpl* domwalk* + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse. + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the Html help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, +# or Internet explorer 4.0+). Note that for large projects the tree generation +# can take a very long time. In such cases it is better to disable this feature. +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = YES + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line and do not end with a semicolon. Such function macros are typically +# used for boiler-plate code, and will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yield more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are gif, jpg, and png +# If left blank gif will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermedate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/depcomp b/depcomp new file mode 100755 index 00000000000..aea3d00785d --- /dev/null +++ b/depcomp @@ -0,0 +1,472 @@ +#! /bin/sh + +# depcomp - compile a program generating dependencies as side-effects +# Copyright 1999, 2000 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi +# `libtool' can also be set to `yes' or `no'. + +if test -z "$depfile"; then + base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` + dir=`echo "$object" | sed 's,/.*$,/,'` + if test "$dir" = "$object"; then + dir= + fi + # FIXME: should be _deps on DOS. + depfile="$dir.deps/$base" +fi + +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. This file always lives in the current directory. + # Also, the AIX compiler puts `$object:' at the start of each line; + # $object doesn't have directory information. + stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + outname="$stripped.o" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + tmpdepfile1="$dir.libs/$base.lo.d" + tmpdepfile2="$dir.libs/$base.d" + "$@" -Wc,-MD + else + tmpdepfile1="$dir$base.o.d" + tmpdepfile2="$dir$base.d" + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + if test -f "$tmpdepfile1"; then + tmpdepfile="$tmpdepfile1" + else + tmpdepfile="$tmpdepfile2" + fi + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a space and a tab in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5891803f9a8..46d8d2e8f68 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,1126 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. + + * Makefile.in (reload1.o-warn): Add. + (tree-alias-ander.o-warn): Add. + (GMPLIBS): Define. + (GMPINC): Define. + (BANSHEELIB): Define. + (BANSHEEINC): Define. + (TREE_DUMP_H): Define. + (TREE_SIMPLE_H): Define. + (TREE_FLOW_H): Define. + (LIBDEPS): Add BANSHEELIB. + (INCLUDES): Add BANSHEEINC and GMPINC. + (C_AND_OBJC_OBJS): Add c-simplify.o, tree-mudflap.o, + c-mudflap.o and c-pretty-print.o. + (C_OBJS): Remove c-pretty-print.o. + (OBJS-common): Remove sibcall.o. + Add tree-cfg.o, tree-dfa.o, tree-eh.o, + tree-ssa.o, tree-optimize.o, tree-simple.o, + tree-alias-type.o, gimplify.o, tree-pretty-print.o, + tree-into-ssa.o, tree-outof-ssa.o, tree-alias-common.o, + tree-ssa-ccp.o, @ANDER@, tree-ssa-dce.o, tree-ssa-copy.o, + tree-nrv.o, tree-ssa-copyrename.o, tree-ssa-pre.o, + tree-ssa-live.o, tree-ssa-operands.o, tree-ssa-alias.o, + tree-ssa-phiopt.o, tree-ssa-forwprop.o, tree-nested.o, + tree-ssa-dse.o, tree-ssa-dom.o, domwalk.o, + tree-tailcall.o, gimple-low.o, tree-iterator.o, + tree-phinodes.o, tree-ssanames.o, tree-sra.o, + tree-complex.o, tree-ssa-loop.o, rtl-profile.o and + tree-profile.o. + (OBJC-archive): Add tree-nomudflap.o. + (cc1): Add dependency on @TREEBROWSER@. + (c-decl.o): Add dependency on TREE_DUMP_H. + (c-dump.o): Likewise. + (c-common.o): Add dependency on tree-iterator.h + (c-pretty-print.o): Add dependency on DIAGNOSTIC_H. + (gtype-desc.o): Add dependency on TREE_FLOW_H. + (tree.o): Add dependency on tree-iterator.h, + BASIC_BLOCK_H and TREE_FLOW_H. + (tree-dump.o): Depend on TREE_DUMP_H instead of tree-dump.h. + (langhooks.o): Add dependency on TREE_SIMPLE_H. + (tree-alias-type.o, tree-alias-ander.o, + tree-alias-common.o, tree-ssa.o, tree-into-ssa.o, + tree-outof-ssa.o, tree-ssa-dse.o, tree-ssa-forwprop.o, + tree-ssa-phiopt.o, tree-nrv.o, tree-ssa-copy.o, + tree-ssa-dom.o, tree-ssanames.o, tree-phinodes.o, + domwalk.o, tree-ssa-live.o, tree-ssa-copyrename.o, + tree-ssa-pre.o, tree-cfg.o, tree-tailcall.o, + tree-nested.o, tree-iterator.o, tree-dfa.o, + tree-ssa-operands.o, tree-eh.o, tree-ssa-loop.o, + tree-ssa-alias.o, tree-optimize.o, c-simplify.o, + gimplify.o, gimple-low.o, tree-browser.o, tree-simple.o, + tree-mudflap.o, c-mudflap.o, tree-nomudflap.o, + tree-pretty-print.o, tree-ssa-dce.o, tree-ssa-ccp.o, + tree-sra.o, tree-complex.o, tree-profile.o, + rtl-profile.o): New rules. + (function.o): Add dependency on basic-block.h + (expr.o): Add dependency on tree-iterator.h. + (sibcall.o): Remove. + (profile.o): Depend on TREE_FLOW_H instead of TREE_H. + (cfg.o): Add dependency on TIMEVAR_H. + (cfghooks.o): Add dependency on TREE_FLOW_H. + (reg-stack.o): Add dependency on basic-block.h. + (GTFILES): Add hwint.h, tree-mudflaph.c, tree-flow.h, + c-objc-common.c, c-common.c, c-parse.in, tree-ssanames.c, + tree-eh.c, tree-phinodes.c, tree-cfg.c, tree-dfa.c, + tree-ssa-ccp.c, tree-iterator.c, gimplify.c, + tree-alias-type.h, tree-alias-common.h, + tree-alias-type.c, tree-alias-common.c, + tree-ssa-operands.h, tree-ssa-operands.c, tree-profile.c, + rtl-profile.c and tree-nested.c. + (gt-tree-alias-common.h, gt-tree-mudflap.h, + gt-tree-ssa-ccp.h, gt-tree-eh.h, gt-tree-ssanames.h, + gt-tree-iterator.h, gt-gimplify.h, gt-tree-phinodes.h, + gt-tree-cfg.h, gt-tree-nested.h): New rules. + (TEXI_GCCINT_FILES): Add cfg.texi and tree-ssa.texi. + * basic-block.h: Include predict.h + (struct edge_def): Add GTY marker. + Change field 'insns' to be a union of tree and rtx. + (EDGE_TRUE_VALUE): Define. + (EDGE_FALSE_VALUE): Define. + (EDGE_EXECUTABLE): Define. + (struct bb_ann_d): Forward declare. + (struct basic_block_def): Add GTY marker. + Remove fields head_tree and end_tree. + Add fields stmt_list, rbi and tree_annotations. + (struct reorder_block_def): Define. + (basic_block_info): Add GTY marker. + (ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR): Change to global + variables instead of macros. + (flow_call_edges_add): Remove declaration. + (make_eh_edge): Remove declaration. + (brief_dump_cfg, find_edge, tree_predicted_by_p, + rtl_predicted_by_p, tree_predict_edge, rtl_predict_edge, + predict_edge_def, rtl_make_eh_edge, find_basic_blocks, + cleanup_cfg, delete_unreachable_blocks, merge_seq_blocks, + alloc_rbi_pool, initialize_bb_rbi, free_rbi_pool): Declare. + (try_redirect_by_replacing_jump): Modfiy return type to + edge instead of bool. + * bb-reorder.c (copy_bb): Call duplicate_block + instead of cfg_layout_duplicate_bb. + (copy_bb_p): Call can_duplicate_block_p instead of + cfg_layout_can_duplicate_bb_p. + * bitmap.c (bitmap_first_set_bit): Abort if word + wasn't found. + (bitmap_last_set_bit): Likewise. + * builtin-types.def (DEF_FUNCTION_TYPE_2): Add + (DEF_FUNCTION_TYPE_3): Add. + * builtins.c (c_strlen): Make extern. + (builtin_save_expr): New. + (expand_builtin_nonlocal_goto): New. + (expand_builtin_constant_p): Remove. + (expand_builtin_mathfn): Call builtin_save_expr instead + of save_expr. + (expand_builtin_mathfn_2): Likewise. + (expand_builtin_strcmp): Likewise. + (expand_builtin_strncmp): Likewise. + (expand_builtin_strcat): Likewise. + (fold_builtin_cabs): Likewise. + (expand_builtin_alloca): Don't trigger if -fmudflap is + given. + (build_string_literal): Set TREE_INVARIANT on new node. + (expand_builtin_profile_fun): New. + (round_trampoline_addr): New. + (expand_builtin_init_trampoline): New. + (expand_builtin_adjust_trampoline): New. + (expand_builtin) : Call simplify_builtin_next_arg. + : Return const0_rtx; + : + Handle. + (fold_builtin_expect): New. + (fold_builtin_isascii): Don't return non-constant results + in GIMPLE form. + (fold_builtin_isdigit): Likewise. + (fold_builtin_1): New. + (fold_builtin): Call it. + (build_function_call_expr): Update call to build a new + CALL_EXPR. + (purge_builtin_constant_p): Remove. + (simplify_builtin, simplify_builtin_memcmp, + simplify_builtin_strcmp, simplify_builtin_strncmp, + simplify_builtin_strpbrk, simplify_builtin_strstr, + simplify_builtin_strchr, simplify_builtin_strrchr, + simplify_builtin_strcat, simplify_builtin_strncat, + simplify_builtin_strspn, simplify_builtin_strcspn, + simplify_builtin_next_arg, simplify_builtin_va_start, + simplify_builtin_sprintf): New. + * builtins.def (BUILT_IN_STACK_ALLOC, + BUILT_IN_STACK_SAVE, BUILT_IN_STACK_RESTORE, + BUILT_IN_INIT_TRAMPOLINE, BUILT_IN_ADJUST_TRAMPOLINE, + BUILT_IN_NONLOCAL_GOTO, BUILT_IN_PROFILE_FUNC_ENTER, + BUILT_IN_PROFILE_FUNC_EXIT): Define. + * c-common.c: Include tree-iterator.h and hashtab.h. + (lang_statement_code_p): Declare. + (lang_gimplify_stmt): Declare. + (fix_string_type): Set TREE_INVARIANT for value. + (pointer_int_sum): Rely on build to set TREE_CONSTANT. + (c_type_hash): New. + (c_common_get_alias_set): Handle multiple type nodes + referring to "the same" type, currently for C90 only. + (c_add_case_label): Use create_artificial_label. + (finish_label_address_expr): Don't set TREE_CONSTANT on + result. + (c_expand_expr): Don't handle STMT_EXPR. + (handle_alias_attribute): Marke aliased variables to be + TREE_STATIC. + (handle_nonnull_attribute): Initialize arg_num. + (check_function_nonnull): Likewise. + (c_walk_subtrees): New. + (c_estimate_num_insns_1): Don't handle + EXPR_WITH_FILE_LOCATION nor FILE_STMT. + (c_decl_uninit_1): Remove. + (c_decl_uninit): Remove. + (c_warn_unused_result): New. + * c-common.def (ASM_STMT): Change number of operands + to 4. + (FILE_STMT): Remove. + * c-common.h (lang_expand_stmt, lang_expand_decl_stmt): + Remove. + (lang_gimplify_stmt): Add. + (expand_stmt): Remove. + (ASM_CV_QUAL, ASM_STRING, ASM_OUTPUTS, ASM_INPUTS, + ASM_CLOBBERS, STMT_EXPR_WARN_UNUSED_RESULT, + ASM_VOLATILE_P, FILE_STMT_FILENAME_NODE, + FILE_STMT_FILENAME, STMT_LINENO, STMT_LINENO_FOR_FN_P, + ASM_INPUT_P, DECL_C_HARD_REGISTER): Remove. + (genrtl_do_pushlevel, genrtl_goto_stmt, genrtl_expr_stmt, + genrtl_expr_stmt_value, genrtl_decl_stmt, genrtl_if_stmt, + genrtl_while_stmt, genrtl_do_stmt, genrtl_return_stmt, + genrtl_for_stmt, genrtl_break_stmt, genrtl_continue_stmt, + genrtl_scope_stmt, genrtl_switch_stmt, genrtl_case_label, + genrtl_compound_stmt, genrtl_asm_stmt, + genrtl_cleanup_stmt, c_decl_uninit): Remove. + (c_do_switch_warnings, c_gimplify_expr, c_walk_subtrees, + c_tree_chain_matters_p, c_warn_unused_result, + c_genericize, c_gimplify_stmt, stmt_expr_last_stmt): + Declare. + * c-convert.c (convert): Make convert work when + converting to compatible types across translation unit. + * c-decl.c: Include langhooks.h, tree-mudflap.h, + tree-simple.h, diagnostic.h and tree-dump.h + (merge_decls): Initialize oldtype to NULL. + (finish_decl): Use DECL_HARD_REGISTER instead of + DECL_C_HARD_REGISTER. + (check_bitfield_type_and_width): Check for null + lang_type_specific when check the precision of an enum. + (grokdeclarator): Immediately layout an ARRAY_TYPE used + in a pointer-to-array declarator. + (finish_struct): Clear allocated struct lang_type. + (finish_enum): Set enum_min and enum_max. Set + TYPE_MIN/MAX_VALUE to the limits of the compatible type, + not to the enumerators. + (set_decl_nonlocal): New. + (store_parm_decls): Use it via walk_tree. + (c_finalize): New. + (finish_function): When !targetm.have_ctors_dtors, + record static constructors and destructors here... + (c_expand_body_1): ... not here. + (c_expand_decl): Rename from c_expand_decl_stmt. + Handle all C-specific expansion semantics. + * c-dump.c (dump_stmt): Use EXPR_LOCUS instead of + STMT_LINENO. + * c-format.c (handle_format_arg_attribute): Initialize + format_num. + * c-lang.c: Include tree-inline.h + (LANG_HOOKS_EXPAND_DECL, + LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P, + LANG_HOOKS_TREE_INLINING_WALK_SUBTREES, + LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P, + LANG_HOOKS_GIMPLIFY_EXPR, LANG_HOOKS_TYPES_COMPATIBLE_P): Define. + (LANG_HOOKS_DECL_UNINIT, LANG_HOOKS_RTL_EXPAND_STMT, + LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): Remove. + (c_types_compatible_p): New. + * c-mudflap.c: New file. + * c-objc-common.c: Include tree-mudflap.h + (start_cdtor, finish_cdtor): Collapse + together into + (build_cdtor): ...here. Update to construct a complete tree + for the function. No need to call push_scope, pop_scope, or + clear_last_expr, or set current_function_cannot_inline. + (c_missing_noreturn_ok_p): Change prototype to return + bool. + (c_objc_common_init): Don't set lang_missing_noreturn_ok_p. + * c-opts.c (c_common_handle_option): Move handling of -fdump- to + opts.c. + (c_common_post_options): Don't ever use rtl inlining. + * c-parse.in: Use EXPR_LOCUS instead of STMT_LINENO. + * c-pragma.c (handle_pragma_redefine_extname): Define + always. + (init_pragma): Activate #pragma redefine_extname for mudflap. + * c-pretty-print.c (pp_c_statement): Remove FILE_STMT. + (pp_c_initializer): Accept any type CONSTRUCTOR. + (pp_c_initializer_list): Fix code expectations for VECTOR_TYPE and + COMPLEX_TYPE. + (decl_name_str): New local function. + (pp_c_direct_declarator): Call it. + (pp_c_primary_expression): Call it. + (pp_c_id_expression): Call it. + (pp_c_statement): Call it. + (print_c_tree): Create new pp object. + * c-pretty-print.h (pp_c_tree_decl_identifier, + print_c_tree): Declare. + * c-semantics.c: Include langhooks.h + (lang_expand_stmt, lang_expand_decl_stmt, + find_reachable_label_1, find_reachable_label, + expand_unreachable_if_stmt, expand_unreachable_stmt, + genrtl_do_stmt_1): Remove. + (begin_stmt_tree): Don't check for changed filename. + Call annotate_with_locus. + (finish_stmt_tree): Don't set line for end of function. + (build_stmt): Don't check type nodes for + side effects. + (build_stmt): Set TREE_SIDE_EFFECTS. + Set EXPR_LOCUS instead of STMT_LINENO. + (lang_expand_stmt, lang_expand_decl_stmt, + expand_cond, genrtl_do_pushlevel, genrtl_goto_stmt, genrtl_expr_stmt, + genrtl_expr_stmt_value, genrtl_decl_stmt, genrtl_if_stmt, + genrtl_while_stmt, genrtl_do_stmt_1, genrtl_do_stmt, + genrtl_return_stmt, genrtl_for_stmt, genrtl_break_stmt, + genrtl_continue_stmt, genrtl_scope_stmt, genrtl_switch_stmt, + genrtl_case_label, genrtl_compound_stmt, genrtl_asm_stmt, + genrtl_cleanup_stmt, expand_stmt, find_reachable_label, + find_reachable_label_1, expand_unreachable_if_stmt, + expand_unreachable_stmt): Remove. + (prep_stmt): Use EXPR_LOCUS instead of STMT_LINENO. + * c-simplify.c: New file. + * c-tree.h (C_LANG_TREE_NODE_CHAIN_NEXT): Define. + (struct lang_type): Add fields enum_min and enum_max. + (c_expand_decl_stmt, c_missing_noreturn_ok_p): Remove. + (c_expand_decl, c_missing_noreturn_ok_p, + c_types_compatible_p): Declare. + * c-typeck.c (tagged_types_tu_compatible_p): Allow for + compiler-generated TYPE_DECLs without a DECL_ORIGINAL_TYPE. + (default_function_array_conversion): Rely on build to + set TREE_CONSTANT. + (parser_build_binary_op, pointer_diff): Likewise. + (build_unary_op, build_binary_op): Likewise. + (build_array_ref): + (build_external_ref): Set TREE_INVARIANT. + (build_c_cast, pop_init_level): Likewise. + (process_init_element): Use ASM_VOLATILE_P. + (build_asm_expr): Adapt to GENERIC/GIMPLE syntax. + (c_finish_case): Call c_do_switch_warnings. + * c.opt (fdump-): Remove. + * calls.c (try_to_integrate): Remove. + (prepare_call_address): Replace fndecl arg with a + precomputed static chain value. + (emit_call_1): New argument for full call expr. + (flags_from_decl_or_type): Call special_function_p. + (initialize_argument_information): Add argument + may_tailcall. + (purge_reg_equiv_notes): New. + (expand_call): Do not try to expand calls inline. + (fixup_tail_calls): New. + * cfg.c: Include timevar.h and ggc.h. + (bb_pool, edge_pool): Remove. + (ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR): Declare. + (entry_exit_blocks): Remove. + (rbi_pool): Declare. + (init_flow): Do not create pools. + Allocate entry/exit block. + (free_edge, alloc_block, expunge_block, unchecked_make_edge): Use GGC. + (alloc_rbi_pool, free_rbi_pool, initialize_bb_rbi): New. + (unlink_block): Clear b->prev_bb and b->next_bb. + (compact_blocks): Clear all slots of BASIC_BLOCK array. + (dump_flow_info): Work on trees too. + (dump_cfg_bb_info): New. + (brief_dump_cfg): New. + * cfganal.c (need_fake_edge_p, flow_call_edges_add): Remove. + (find_edge): New. + * cfgbuild.c (rtl_make_eh_edge): Rename from + make_eh_edge. Update all users. + (find_basic_blocks): Don't call VARRAY_FREE on + basic_block_info. + * cfgcleanup.c (outgoing_edges_match): Initialize newpos1 + and newpos2. + (delete_unreachable_blocks): Return changed status. + (merge_seq_blocks): New. + * cfghooks.c: Include tree-flow.h + (tree_register_cfg_hooks, ir_type): New. + (redirect_edge_and_branch): Change return type to edge. + (predict_edge, predicted_by_p, can_duplicate_block_p, + duplicate_block, block_ends_with_call_p, + block_ends_with_condjump_p, flow_call_edges_add): New. + * cfghooks.h (redirect_edge_and_branch): Change return + type to edge. + (predict_edge, predicted_by_p, can_duplicate_block_p, + duplicate_block, block_ends_with_call_p, + block_ends_with_condjump_p, flow_call_edges_add): Declare. + (redirect_edge_and_branch): Change return type to edge. + (struct cfg_hooks): Add fields block_ends_with_call_p, + block_ends_with_condjump_p, flow_call_edges_add, + predict_edge, predicted_by_p, can_duplicate_block_p and + duplicate_block. + (tree_cfg_hooks, ir_type, tree_register_cfg_hooks): Declare. + * cfglayout.c (cfg_layout_pool, cfg_layout_initialize_rbi): Removed. + (fixup_reorder_chain): Use initialize_bb_rbi. + (cfg_layout_can_duplicate_bb_p, cfg_layout_duplicate_bb): Hookized. + (cfg_layout_initialize): Use cfg.c rbi pool manipulation functions. + (can_copy_bbs_p, copy_bbs): Use cfghooks for bb duplication. + (insn_locators_initialize): Use new info about blocks. + * cfglayout.h (typedef struct reorder_block_def): Moved to + basic_block.h. + (cfg_layout_can_duplicate_bb_p, cfg_layout_duplicate_bb): Declaration + removed. + * cfgloop.c: Include tree.h and tree-flow.h. + * cfgloop.h (create_loop_notes): Declare. + * cfgloopmanip.c (create_loop_notes): New. + * cfgrtl.c (cfg_layout_create_basic_block): Use initialize_bb_rbi. + (rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Fill in can_duplicate_block_p + and duplicate_block fields. + (create_basic_block_structure): Don't look at + RTX_INTEGRATED_P. + (rtl_block_ends_with_call_p): New. + (rtl_block_ends_with_condjump_p): New. + (need_fake_edge_p): Moved from cfganal.c. + (rtl_flow_call_edges_add): Moved from cfganal.c (flow_call_edges_add). + (rtl_cfg_hooks): Add rtl_block_ends_with_call_p, + rtl_block_ends_with_condjump_p, rtl_flow_call_edges_add. + (cfg_layout_rtl_cfg_hooks): Ditto. + * cgraph.c (cgraph_mark_reachable_node): Don't force nested + functions to be reachable. + * cgraphunit.c (decide_is_function_needed): + * cgraphunit.c (decide_is_function_needed): Nested functions of extern + inline functions don't need to be output. + (cgraph_assemble_pending_functions): Don't do anything + special for nested functions. + (cgraph_mark_functions_to_output): Likewise. + (cgraph_finalize_function): Don't zap DECL_STRUCT_FUNCTION. + (cgraph_analyze_function): Use estimate_num_insns. + (cgraph_mark_functions_to_output): Likewise. + (cgraph_estimate_growth, cgraph_clone_inlined_nodes): Likewise. + (cgraph_expand_function): Allow functions to not be + emitted. + (cgraph_remove_unreachable_nodes): + (cgraph_recursive_inlining_p): Simplify. + (lookup_recursive_calls, + cgraph_decide_recursive_inlining): New. + (cgraph_decide_inlining_*): Update calls of + cgraph_mark_inline. + * combine.c (get_pos_from_mask): Always set *plen. + * common.opt (fdump-, fmudflap, fmudflapth, fmudflapir, + ftree-based-profiling, ftree-ccp, ftree-ch, + ftree-combine-temps, ftree-copyrename, ftree-dce, + ftree-dominator-opts, ftree-dse, ftree-loop-optimize, + ftree-points-to, ftree-pre, ftree-sra, ftree-ter, + ftree-lrs): Add. + * config.in (HAVE_LD_PIE, HAVE_BANSHEE, PREFIX_INCLUDE_DIR): + Undefine. + * configure.ac: Add --enable-tree-browser option. + Add --with-libbanshee option. + Add GMPLIBS and GMPINC. + * configure: Regenerate. + * coverage.c (tree_ctr_tables): New. + (coverage_counter_alloc): Use it. + (build_ctr_info_value): Ditto. + (coverage_counter_ref): Ditto. Rename to rtl_coverage_counter_ref. + (tree_coverage_counter_ref): New. + * coverage.h (coverage_counter_ref): Remove declaration. + (rtl_coverage_counter_ref): Declare. + (tree_coverage_counter_ref): Declare. + * cppexp.c (append_digit): Rearrange unsignedp/overflow setting. + (eval_token, num_binary_op, num_part_mul, num_div_op): Likewise. + * cse.c (fold_rtx): Do not handle CONSTANT_P_RTX. + (struct cse_basic_block_data): Rename enum values to not + conflict with profile.h; update all uses. + * dbxout.c (dbxout_symbol_location): Don't mention integrate.c + in comments. + * defaults.h (TRAMPOLINE_ALIGNMENT): Move from function.c. + * diagnostic.h (debug_output_buffer, dump_generic_node, + print_generic_stmt, print_generic_stmt_indented, + print_generic_expr, print_generic_decl, + debug_generic_expr, debug_generic_stmt, debug_c_tree): + Declare. + * dominance.c: Cache immediate dominators. + * domwalk.c: New file. + * domwalk.h: New file. + * dwarf2out.c (is_fortran): Support DW_LANG_Fortran95. + (gen_subprogram_die): Generate a DIE for a named + return value. + (loc_descriptor_from_tree): Treat RESULT_DECL like VAR_DECL. + (add_location_or_const_value_attribute): Likewise. + (add_bound_info): Likewise. + (gen_decl_die): Likewise. + * emit-rtl.c (maybe_set_first_label_num): New. + (copy_most_rtx): Don't copy the integrated flag. + Copy the new return_val flag. + * et-forest.c (MAX_NODES): Define. + (record_path_before_1): Abort if len is greater than + MAX_NODES. + * except.c (gen_eh_region, gen_eh_region_cleanup, gen_eh_region_try, + gen_eh_region_catch, gen_eh_region_allowed, + gen_eh_region_must_not_throw, get_eh_region_number, + get_eh_region_may_contain_throw, get_eh_region_tree_label, + set_eh_region_tree_label, expand_resx_expr): New. + (expand_eh_region_start, expand_start_catch): Use them. + (expand_end_catch): Tidy. + (note_eh_region_may_contain_throw): Take region argument. + (note_current_region_may_contain_throw): New. + (get_exception_filter): Export. + (collect_eh_region_array): Export. + (remove_unreachable_regions): Check ERT_TRY based on reachability + of catches, not reachability of continue_label. Never remove + ERT_MUST_NOT_THROW regions. + (collect_rtl_labels_from_trees): New. + (convert_from_eh_region_ranges): Use it. + (connect_post_landing_pads): Handle dying cleanups. + (struct reachable_info): Add callback data. + (add_reachable_handler): Invoke the callback. + (foreach_reachable_handler): New. + (reachable_handlers): Use it. + (arh_to_landing_pad, arh_to_label): New. + (can_throw_internal_1): Split out from can_throw_internal. + (can_throw_external_1): Similarly. + * except.h: Update. + * explow.c (emit_stack_save): Remove savearea mode check. + (update_nonlocal_goto_save_area): New. + (allocate_dynamic_stack_space): Use it. + (probe_stack_range): Never emit loop notes. + * expmed.c (extract_fixed_bit_field): Always propagate the + target for the shift if it is a REG. + * expr.c: Include tree-iterator.h + (is_zeros_p): Remove. + (categorize_ctor_elements_1, categorize_ctor_elements): New. + (count_type_elements): New. + (mostly_zeros_p): Use them. + (expr_wfl_stack): Remove. + (convert_move): Do nothing if to and from are the same. + (emit_block_move_via_loop): Don't emit LOOP notes. + (emit_move_insn): Don't handle CONSTANT_P_RTX. + (emit_move_insn_1): Don't generate inline warnings. + (expand_vars, expand_var): Split from ... + (expand_expr_1): ... here. + (expand_expr_real, expand_expr_real_1): Use new macros + EXPR_LOCATION and EXPR_HAS_LOCATION. + * expr.h (simplify_builtin_fputs, + simplify_builtin_strcpy, simplify_builtin_strncpy, + expand_var, fixup_tail_calls, + update_nonlocal_goto_save_area): Declare. + (lookup_static_chain, expand_inline_function, + mark_seen_cases): Remove. + (prepare_call_address): Change type of 2nd argument to + rtx. + * final.c (profile_function): Update static chain test. + (final): Don't look at RTX_INTEGRATED_P. + * flags.h (flag_mudflap, flag_mudflap_threads, + flag_mudflap_ignore_reads, flag_tree_pre, flag_tree_ccp, + flag_tree_dce, flag_tree_combine_temps, + flag_tree_live_range_split, flag_tree_dom, flag_tree_ch, + flag_tree_dse, flag_tree_sra, flag_tree_copyrename, + flag_tree_points_to): Declare. + (enum pta_type): Declare. + * flow.c (lang_missing_noreturn_ok_p): Remove. + (check_function_return_warnings): Remove. + (update_life_info): Update comments. + (free_basic_block_vars): Don't call VARRAY_FREE for + basic_block_info. + (regno_uninitialized): Remove. + * fold-const.c (int_const_binop): Make extern. + (non_lvalue): Rely on build to set TREE_CONSTANT. + (operand_equal_p): Replace only_const argument with + flags. Allow pure functions if OEP_PURE_SAME. + (fold): Use OEP_ONLY_CONST. + (invert_truthvalue) Break if argument is of + boolean type. + (fold_relational_hi_lo, + nondestructive_fold_binary_to_constant, + nondestructive_fold_unary_to_constant, + fold_read_from_constant_string): New. + * function.c (struct function): Remove calls_constant_p. + (current_function_calls_constant_p): Remove. + (inline_function_decl): Remove. + (put_var_into_stack): Don't use it. + (fix_lexical_addr): Likewise. + (inline_function_decl): Remove extern declaration. + (TRAMPOLINE_ALIGNMENT): Move to defaults.h. + (trampolines_created): Move to varasm.c. + (free_after_compilation): Update for removed fields. + (allocate_struct_function): Likewise. + (delete_handlers, lookup_static_chain): Remove. + (fix_lexical_addr): Don't consider non-local variable refs. + (trampoline_address): Remove. + (round_trampoline_addr): Move to builtins.c. + (adjust_trampoline_addr): Remove. + (expand_function_start): Update for changes to static chain + and nonlocal goto handling. + (initial_trampoline): Move to varasm.c. + (expand_function_end): Don't build trampolines or kill + unreferenced nonlocal goto labels. + (free_after_compilation): Don't set it. + (expand_function_end): Likewise. + (setjmp_vars_warning): Rename from + uninitialized_vars_warning, remove uninitialized vars warning. + (uninitialized_vars_warning): Remove old comment + and check for DECL_INITIAL, replace with a check of TREE_NO_WARNING + and do not call the langhook. + (expand_function_start, expand_function_end): Don't do + function instrumentation here. + (clear_block_marks): Rename from reorder_blocks_0, export. + (blocks_nreverse): Export. + (uninitialized_vars_warning): Use DECL_RTL_SET_P to test for presence + of rtl. + (reset_block_changes, record_block_change, finalize_block_changes, + check_block_change, free_block_changes): New functions. + (assign_parms): Setting of current_function_stdarg + moved ... + (allocate_struct_function): ... here. + * function.h (struct function): Remove x_nonlocal_labels, + x_nonlocal_goto_handler_slots, x_nonlocal_goto_stack_level, + x_context_display, x_trampoline_list, needs_context. + Add static_chain_decl, nonlocal_goto_save_area. + (struct function): Remove x_clobber_return_insn. + Add tail_call_emit field, last_label_uid, + unexpanded_var_list, dont_emit_block_notes, + ib_boundaries_block, function_end_locus and saved_tree/saved_args. + (clear_block_marks): Declare. + * gcc.c (MFWRAP_SPEC, MFLIB_SPEC): Add -fmudflapth support. + (mfwrap_spec, mflib_spec): Declare. + (cpp_unique_options, cc1_options): Ditto. + (default_compilers): Add .F and .f90. + (static_specs): Add mfwrap and mflib. + * gcse.c (want_to_gcse_p, gcse_constant_p): Don't handle + CONSTANT_RTX_P. + (reg_used_on_edge, reg_killed_on_edge, bypass_block): + Update to match insns field in struct edge_def. + * gdbinit.in (pgs, pge): Define. + * genattrtab.c (ATTR_PERMANENT_P): Use the return_val flag + instead of the integrated flag. + * gengtype-lex.l (IWOrD): Add HOST_WIDEST_INT + * gengtype-yacc.y (bitfieldlen): Add empty action. + (struct_fields): Accept unnamed bitfields. + (bitfieldlen): Split from ... + (bitfieldopt): ... here. + * gengtype.c (ifiles): Add tree-alias-type.h and + tree-flow.h. + * genrecog.c (validate_pattern): Do not handle + CONSTANT_P_RTX. + * gimple-low.c: New file. + * gimplify.c: New file. + * haifa-sched.c (priority): Do not handle CONSTANT_P_RTX. + (restore_line_notes): Do not set RTX_INTEGRATED_P. + * ifcvt.c (dead_or_predicable): Initialize local variable + 'earliest'. + * input.h (expr_wfl_stack): Remove. + * integrate.c (INTEGRATE_THRESHOLD): Remove. + (setup_initial_hard_reg_value_integration): Likewise. + (initialize_for_inline): Likewise. + (note_modified_parmregs): Likewise. + (integrate_parm_decls): Likewise. + (process_reg_param): Likewise. + (save_parm_insns): Likewise. + (copy_insn_list): Likewise. + (copy_insn_notes): Likewise. + (compare_blocks): Likewise. + (find_block): Likewise. + (inlining): Likewise. + (function_cannot_inline_p): Likewise. + (parmdecl_map): Likewise. + (in_nonparam_insns): Likewise. + (save_for_inline): Likewise. + (FIXED_BASE_PLUS): Likewise. + (expand_inline_function): Likewise. + (copy_rtx_and_substitute): Don't look at map->integrating, + map->inline_target, and inlining, since we are never copying + for integrating. + Don't abort on RTX_INTEGRATED_P. + (old_fun): Remove. + (output_inline_function): Remove. + * integrate.h (struct inline_map): Remove fields integrating, + block_map, leaf_reg_map, inline_target, and local_return_label. + * jump.c (next_nonnote_insn_in_loop, duplicate_loop_exit_test, + copy_loop_headers, never_reached_warning): Removed. + (any_uncondjump_p): Reject nonlocal goto. + * langhooks-def.h (lhd_types_compatible_p, + lhd_expand_decl, lhd_gimplify_expr): Declare. + (LANG_HOOKS_EXPAND_DECL, LANG_HOOKS_TYPES_COMPATIBLE_P, + LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P, + LANG_HOOKS_FUNCTION_LEAVE_NESTED, + LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P, + LANG_HOOKS_GIMPLIFY_EXPR, + LANG_HOOKS_GIMPLE_BEFORE_INLINING, + LANG_HOOKS_EXPAND_DECL, LANG_HOOKS_TYPES_COMPATIBLE_P, + LANG_HOOKS_GIMPLIFY_EXPR, + LANG_HOOKS_GIMPLE_BEFORE_INLINING): Define. + (LANG_HOOKS_DECL_UNINIT, LANG_HOOKS_RTL_EXPAND_START, + LANG_HOOKS_RTL_EXPAND_STMT, LANG_HOOKS_RTL_EXPAND_END, + LANG_HOOKS_FUNCTION_LEAVE_NESTED, + LANG_HOOKS_RTL_EXPAND_INITIALIZER, + LANG_HOOKS_DECL_UNINIT, + LANG_HOOKS_RTL_EXPAND_INITIALIZER): Remove. + * langhooks.c: Include tree-simple.h. + (lhd_expand_decl): New. + (lhd_types_compatible_p): New. + (lhd_decl_uninit): Remove. + (lhd_gimplify_expr): New. + * langhooks.h (struct lang_hooks_for_rtl_expansion): + Remove. + (struct lang_hooks_for_functions): Add field + missing_noreturn_ok_p. + (struct lang_hooks): Add field expand_decl, + types_compatible_p, gimplify_expr and + gimple_before_inlining. + Remove fields decl_uninit and rtl_expand + * opts.c (decode_options): Set flag_tree_ccp, + flag_tree_dce, flag_tree_dom, flag_tree_dse, + flag_tree_pre, flag_tree_ter, + flag_tree_live_range_split, flag_tree_sra, + flag_tree_copyrename and flag_tree_ch at -O1 and higher. + (common_handle_option): Handle OPT_fdump_, OPT_fmudflap, + OPT_fmudflapth, OPT_fmudflapir, + OPT_ftree_based_profiling, OPT_ftree_ccp, OPT_ftree_dce, + OPT_ftree_combine_temps, OPT_ftree_ter, OPT_ftree_lrs, + OPT_ftree_dominator_opts, OPT_ftree_copyrename, + OPT_ftree_ch, OPT_ftree_dse, OPT_ftree_sra, + OPT_ftree_points_to_ and OPT_ftree_pre. + * output.h (regno_uninitialized, find_basic_blocks, + cleanup_cfg, delete_unreachable_blocks, + check_function_return_warnings): Remove. + * params.def (PARAM_MAX_INLINE_INSNS_RECURSIVE, + PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO, + PARAM_MAX_INLINE_RECURSIVE_DEPTH, + PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO, + PARAM_GLOBAL_VAR_THRESHOLD, PARAM_MAX_ALIASED_VOPS): + * params.h (GLOBAL_VAR_THRESHOLD, MAX_ALIASED_VOPS): + Define. + * passes.c (rest_of_decl_compilation): + (rest_of_handle_sibling_calls): Remove. + (rest_of_handle_inlining): Remove. + (rest_of_handle_gcse): Do not run + purge_builtin_constant_p. + (rest_of_compilation): Update. + Do not call copy_loop_headers. + Do rtl-based profiling only when + !flag_tree_based_profiling. Register rtl-based profiling + hooks. + * predict.c: Include tree-flow.h, ggc.h, tree-dump.h + (predicted_by_p): Rename to ... + (rtl_predicted_by_p): .. this one; make global + (tree_predicted_by_p): New. + (dump_prediction): Add FILE argument. + (predict_edge): Rename to ... + (rtl_predict_edge): .. this one. + (tree_predict_edge): New. + (combine_predictions_for_insn): Update calls of predict_edge. + (predict_loops): Break out from ... + (estimate_probability): ... here; update comments; move updating + of unknown probabilities from ... + (estimate_bb_frequencies): ... here. + (combine_predictions_for_bb): New. + (tree_predict_by_opcode): New. + (tree_estimate_probability): New. + * predict.def (PRED_TREE_POINTER, PRED_TREE_OPCODE_POSITIVE, + PRED_TREE_OPCODE_NONEQUAL, PRED_TREE_FPOPCODE): New predictors. + * predict.h: Add include guard. + (predict_edge, predict_edge_def): Move prototypes to basic_block.h + * pretty-print.c (pp_write_text_to_stream): Make extern. + * pretty-print.h (pp_write_text_to_stream): Declare. + * print-rtl.c (print_rtx): Don't print the integrated flag. + Print the return_val flag. + * print-tree.c: Use TREE_FILENAME and TREE_LINENO instead + of DECL_SOURCE_FILE and DECL_SOURCE_LINE respectively. + Remove support for EXPR_WITH_FILE_LOCATION nodes. + (print_node): Print TREE_INVARIANT and TREE_VISITED. + * profile.c: Include cfghooks.h, tree-flow.h. + (profile_hooks): New. + (profile_dump_file): New. + (instrument_edges): Use hooks instead of RTL-specific code. + (instrument_values): Ditto. + (get_exec_counts): Ditto. + (compute_branch_probabilities): Ditto. + (compute_value_histograms): Ditto. + (branch_prob): Ditto. + (find_spanning_tree): Ditto. + (end_branch_prob): Ditto. + (gen_edge_profiler): Move to rtl-profile.c (rtl_gen_edge_profiler). + (gen_interval_profiler): Ditto (rtl_gen_interval_profiler). + (gen_pow2_profiler): Ditto (rtl_gen_pow2_profiler). + (gen_one_value_profiler): Ditto (rtl_gen_one_value_profiler). + (tree_register_profile_hooks): New. + (rtl_register_profile_hooks): New. + * ra-rewrite.c (rewrite_program): Clear variable info. + * recog.c (immediate_operand): Do not handle CONSTANT_P_RTX. + * regs.h: Add include guards. + * reload.c (decompose): Clear val using memset. + * rtl.def (CONSTANT_P_RTX): Remove. + * rtl.h (CONSTANT_P): Do not handle CONSTANT_P_RTX. + (copy_loop_headers): Remove. + (struct rtx_def): Replace the integrated flag with the + return_val flag. + (maybe_set_first_label_num): Declare. + (init_branch_prob): Move declaration to value-prof.h. + (end_branch_prob): Ditto. + (branch_prob): Ditto. + (never_reached_warning): Don't declare it. + * rtlanal.c (get_related_value): Initialize get_jump_table_offset + (hoist_insn_to_edge): Update to match field insns in + struct edge_def. + * sbitmap.c (sbitmap_realloc): New. + * sbitmap.h (sbitmap_realloc): Declare. + * sibcall.c: Remove file. + * simplify-rtx.c (simplify_rtx): Do not handle + CONSTANT_P_RTX. + * stmt.c (parse_output_constraint): Don't warn for read-write + memory operand. + (tail_recursion_args): Use types_compatible_p langhook. + (force_label_rtx): Don't look at inline_function_decl. + (label_rtx): Set LABEL_PRESERVE_P appropriately. + (expand_label): Handle DECL_NONLOCAL and FORCED_LABEL. + (declare_nonlocal_label): Remove. + (expand_goto): Don't handle nonlocal gotos. + (expand_nl_handler_label): Remove. + (expand_nl_goto_receivers): Remove. + (expand_end_bindings): Don't expand_nl_goto_receivers. Use + update_nonlocal_goto_save_area. + (expand_expr_stmt_value): Check TREE_NO_WARNING. + (warn_if_unused_value): Likewise. + (expand_start_loop, expand_loop_continue_here, + expand_end_loop): Don't create loop notes. + (all_cases_count, BITARRAY_TEST, BITARRAY_SET, + mark_seen_cases, check_for_full_enumeration_handling): Remove. + (expand_end_case_type): Don't do warn_switch handling. + (pushcase, pushcase_range) Update add_case_node calls. + (add_case_node): Add dont_expand_label argument. + (same_case_target_p): Don't search rtl. + (expand_start_bindings_and_block, expand_end_bindings): + Don't emit block notes when dont_emit_block_notes. + (using_eh_for_cleanups_p): Export. + (expand_return): Allow any typed rhs. + (expand_stack_alloc): New. + (expand_stack_save, expand_stack_restore): New. + (containing_blocks_have_cleanups_or_stack_level): New + function. + (asm_op_is_mem_input): New fn. + (expand_asm_expr): New fn. + (warn_if_unused_value): Check operand 0 of SAVE_EXPR + nodes. + * stor-layout.c (layout_type): Just return if type is + error_mark_node. + (update_alignment_for_field): Export. + (variable_size): We don't care about global_bindings_p if + the frontend doesn't want a list of the expressions. + * system.h: Poison INTEGRATE_THRESHOLD. + * timevar.def (TV_TREE_GIMPLIFY, TV_TREE_EH, TV_TREE_CFG, + TV_TREE_CLEANUP_CFG, TV_TREE_PTA, TV_TREE_MAY_ALIAS, + TV_TREE_INSERT_PHI_NODES, TV_TREE_SSA_REWRITE_BLOCKS, + TV_TREE_SSA_OTHER, TV_TREE_OPS, + TV_TREE_SSA_DOMINATOR_OPTS, TV_TREE_SRA, TV_TREE_CCP, + TV_TREE_SPLIT_EDGES, TV_TREE_PRE, TV_TREE_PHIOPT, + TV_TREE_FORWPROP, TV_TREE_DCE, TV_TREE_CD_DCE, + TV_TREE_DSE, TV_TREE_LOOP, TV_TREE_CH, + TV_TREE_SSA_TO_NORMAL, TV_TREE_SSA_TO_NORMAL, + TV_TREE_NRV, TV_TREE_COPY_RENAME, TV_TREE_SSA_VERIFY, + TV_TREE_STMT_VERIFY, TV_DOM_FRONTIERS, + TV_CONTROL_DEPENDENCES): Define. + * toplev.c: Include tree-alias-common.h + (current_file_decl, flag_mudflap, flag_mudflap_threads, + flag_mudflap_ignore_reads, flag_tree_based_profiling, + flag_tree_gvn, flag_tree_points_to, flag_tree_ccp, + flag_tree_dce, flag_tree_ch, flag_tree_sra, + flag_tree_combine_temps, flag_tree_ter, + flag_tree_live_range_split, flag_tree_dom, + flag_tree_copyrename, flag_tree_dse): Declare. + (f_options): Add tree-based-profiling, tree-gvn, + tree-pre, tree-ccp, tree-dce, + tree-dominator-opts, tree-copyrename, tree-dse, + tree-combine-temps, tree-ter, tree-lrs and tree-ch. + (wrapup_global_declarations): Don't output nested inlined functions. + (general_init): Call init_tree_optimization_passes. + (process_options): Sorry for -ftree-based-profiling plus + -ftest-coverage or -fprofile-values. + * toplev.h (init_tree_optimization_passes, + flag_tree_based_profiling): Declare. + * tracer.c (tail_duplicate): Use cfghooks for bb duplication. + * tree-alias-ander.c: New file. + * tree-alias-ander.h: New file. + * tree-alias-common.c: New file. + * tree-alias-common.h: New file. + * tree-alias-type.c: New file. + * tree-alias-type.h: New file. + * tree-browser.c: New file. + * tree-browser.def: New file. + * tree-cfg.c: New file. + * tree-complex.c: New file. + * tree-dfa.c: New file. + * tree-dump.c (dump_enable_all): New. + (dequeue_and_dump): Do not handle EXPR_WITH_FILE_LOCATION. + (dump_node): Remove const from field suffix and swtch. + (dump_files): Add null entry, .generic, .nested, .vcg, + .xml and a match-all entry. + (extra_dump_files, extra_dump_files_in_use, + extra_dump_files_alloced): Declare + (dump_option_value_info): Add raw, details, stats, + blocks, vops, lineno, uid and all. + (dump_register): New. + (get_dump_file_info): New. + (dump_begin): Call it. + Do nothing for TDI_none. + (dump_begin): Include phase number in dump filename. + (dump_enable_all): New. + (dump_switch_p_1): Split out from dump_switch_p. + (dump_switch_p): Handle extra_dump_files. + Start our scan at TDI_none + 1. + If -fdump-tree-all was given, call dump_enable_all. + * tree-dump.h: Include splay-tree.h. + (dump_function, dump_function_to_file, dump_register): + Declare. + * tree-eh.c: New file. + * tree-flow-inline.h: New file. + * tree-flow.h: New file. + * tree-inline.c: Re-write to handle inlining on GIMPLE. + * tree-inline.h (walk_tree, + walk_tree_without_duplicates): Move to tree.h. + (estimate_num_insns): Declare. + * tree-into-ssa.c: New file. + * tree-iterator.c: New file. + * tree-iterator.h: New file. + * tree-mudflap.c: New file. + * tree-mudflap.h: New file. + * tree-nested.c: New file. + * tree-nomudflap.c: New file. + * tree-nrv.c: New file. + * tree-optimize.c (dump_flags, vars_to_rename, + in_gimple_form, all_passes, pass_gimple, + pass_rebuild_bind, pass_all_optimizations, pass_del_cfg): Declare. + (execute_gimple, execute_rebuild_bind, + gate_all_optimizations, execute_del_cfg, + register_one_dump_file, register_dump_files, dup_pass_1, + init_tree_optimization_passes, execute_todo, + execute_one_pass, execute_pass_list): New. + (clear_decl_rtl): Remove. + (tree_rest_of_compilation): Update to use tree + optimizers. + * tree-outof-ssa.c: New file. + * tree-pass.h: New file. + * tree-phinodes.c: New file. + * tree-pretty-print.c: New file. + * tree-profile.c: New file. + * tree-simple.c: New file. + * tree-simple.h: New file. + * tree-sra.c: New file. + * tree-ssa-alias.c: New file. + * tree-ssa-ccp.c: New file. + * tree-ssa-copy.c: New file. + * tree-ssa-copyrename.c: New file. + * tree-ssa-dce.c: New file. + * tree-ssa-dom.c: New file. + * tree-ssa-dse.c: New file. + * tree-ssa-forwprop.c: New file. + * tree-ssa-live.c: New file. + * tree-ssa-live.h: New file. + * tree-ssa-loop.c: New file. + * tree-ssa-operands.c: New file. + * tree-ssa-operands.h: New file. + * tree-ssa-phiopt.c: New file. + * tree-ssa-pre.c: New file. + * tree-ssa.c: New file. + * tree-ssanames.c: New file. + * tree-tailcall.c: New file. + * tree.c: Include tree-iterator.h, basic-block.h and + tree-flow.h. + (tree_node_kind): Add phi_nodes and ssa names. + (tree_size): Handle PHI_NODE, EPHI_NODE, SSA_NAME, + EUSE_NODE, EKILL_NODE, EEXIT_NODE and STATEMENT_LIST. + (make_node_stat): Handle PHI_NODE and SSA_NAME. + <'c'> Set TREE_INVARIANT. + (copy_node_stat): Abort if trying to copy a + STATEMENT_LIST. + Clear TREE_VISITED. + Clear annotation field. + (build_constructor): Copy TREE_INVARIANT from vals. + Don't clear TREE_CONSTANT. + (expr_first, expr_last, expr_length): Remove. + (staticp): Pass unknown component references to the language. + (save_expr): Check TREE_INVARIANT instead of TREE_CONSTANT. + (skip_simple_arithmetic): Likewise. + (stabilize_reference_1): Likewise. + (tree_node_structure): Handle PHI_NODE, EPHI_NODE, + EUSE_NODE, EKILL_NODE, EEXIT_NODE, SSA_NAME and + STATEMENT_LIST. + (lhd_unsave_expr_now): Remove. + (unsafe_for_reeval): Handle LABEL_EXPR and BIND_EXPR. + (recompute_tree_invarant_for_addr_expr): New. + (build1_stat): Clear EXPR_LOCUS and TREE_BLOCK. + Call recompute_tree_invarant_for_addr_expr. + Set TREE_INVARIANT accordingly. + (build2_stat): Don't handle CALL_EXPR. + (build3_stat): Don't call build2_stat for CALL_EXPRs. + (build_expr_wfl): Remove. + (annotate_with_file_line, annotate_with_locus): New. + (simple_cst_equal): Call simple_cst_list_equal to compare + CONSTRUCTOR_ELTS pointers. + (iterative_hash_expr): Don't hash types associated + with conversions. Instead hash on the signedness of the + toplevel object and the operand of the conversion. + (dump_tree_statistics): Call ssanames_print_statistics + and phinodes_print_statistics. + (ephi_node_elt_check_failed, phi_node_elt_check_failed, + add_var_to_bind_expr, build_empty_stmt, is_essa_node, + needs_to_live_in_memory): New. + (initializer_zerop): Handle VECTOR_CST. Don't check + AGGREGATE_TYPE_P for CONSTRUCTOR. + * tree.def (FILTER_EXPR, CASE_LABEL_EXPR, RESX_EXPR, + SSA_NAME, EUSE_NODE, EKILL_NODE, EPHI_NODE, EEXIT_NODE, + PHI_NODE, CATCH_EXPR, EH_FILTER_EXPR, STATEMENT_LIST): Define. + (GOTO_SUBROUTINE_EXPR): Change type to 's'. + (CALL_EXPR): Add another operand. + (EXPR_WITH_FILE_LOCATION): Remove. + (SWITCH_EXPR): Add another operand. + * tree.h: Update various comments. + (union tree_ann_d): Forward declare. + (struct tree_common): Add fields nowarning_flag, + invariant_flag and visited. + (EREF_NODE_CHECK, EPHI_NODE_ELT_CHECK, + PHI_NODE_ELT_CHECK, EREF_NODE_CHECK, PHI_NODE_ELT_CHECK, + EPHI_NODE_ELT_CHECK, TREE_BLOCK, + STRIP_USELESS_TYPE_CONVERSION, CALL_EXPR_TAILCALL, + TREE_NO_WARNING, FORCED_LABEL, TREE_INVARIANT, + IS_EMPTY_STMT, EXPR_LOCUS, SET_EXPR_LOCUS, EXPR_FILENAME, + EXPR_LINENO, EXPR_LOCATION, EXPR_HAS_LOCATION, + EXIT_EXPR_COND, SWITCH_COND, SWITCH_BODY, SWITCH_LABELS, + CASE_LOW, CASE_HIGH, CASE_LABEL, BIND_EXPR_VARS, + BIND_EXPR_BODY, BIND_EXPR_BLOCK, GOTO_DESTINATION, + ASM_STRING, ASM_OUTPUTS, ASM_INPUTS, ASM_CLOBBERS, + ASM_INPUT_P, ASM_VOLATILE_P, COND_EXPR_COND, + COND_EXPR_THEN, COND_EXPR_ELSE, LABEL_EXPR_LABEL, + CATCH_TYPES, CATCH_BODY, EH_FILTER_TYPES, + EH_FILTER_FAILURE, EH_FILTER_MUST_NOT_THROW, + SSA_NAME_VAR, SSA_NAME_DEF_STMT, SSA_NAME_VERSION, + SSA_NAME_OCCURS_IN_ABNORMAL_PHI, SSA_NAME_IN_FREE_LIST, + PHI_RESULT, PHI_REWRITTEN, PHI_NUM_ARGS, + PHI_ARG_CAPACITY, PHI_ARG_ELT, PHI_ARG_EDGE, PHI_ARG_DEF, + EREF_PROCESSED, EREF_ID, EREF_NAME, EREF_STMT, + EREF_RELOAD, EREF_SAVE, EREF_CLASS, EREF_INJURED, + EREF_TEMP, EUSE_DEF, EUSE_PHIOP, EUSE_INSERTED, + EUSE_LVAL, EPHI_NUM_ARGS, EPHI_ARG_CAPACITY, + EPHI_ARG_ELT, EPHI_ARG_EDGE, EPHI_ARG_PRED, EPHI_ARG_DEF, + EPHI_ARG_INJURED, EPHI_ARG_DELAYED_RENAME, + EPHI_ARG_HAS_REAL_USE, EPHI_ARG_STOPS, + EPHI_ARG_PROCESSED2, EPHI_IDENTITY, EPHI_IDENT_INJURED, + EPHI_REP_OCCUR_KNOWN, EPHI_IDENTICAL_TO, EPHI_DOWNSAFE, + EPHI_CANT_BE_AVAIL, EPHI_DEAD, EPHI_USES, EPHI_STOPS, + TREE_VISITED, SSA_VAR_P, DECL_NUM_STMTS, + DECL_HARD_REGISTER, DECL_PTA_ALIASVAR, LABEL_DECL_UID, + DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL, + STATEMENT_LIST_HEAD, STATEMENT_LIST_TAIL, TDF_RAW, + TDF_DETAILS, TDF_STATS, TDF_BLOCKS, TDF_VOPS, TDF_LINENO, + TDF_UID,): Define. + (TREE_NO_UNUSED_WARNING, EXPR_WFL_EMIT_LINE_NOTE, + EXPR_WFL_NODE, EXPR_WFL_FILENAME_NODE, EXPR_WFL_FILENAME, + EXPR_WFL_LINECOL, EXPR_WFL_LINENO, EXPR_WFL_COLNO, + EXPR_WFL_SET_LINECOL): Remove. + (phi_node_elt_check_failed, ephi_node_elt_check_failed, + make_phi_node, init_phinodes, fini_phinodes, + release_phi_node, phinodes_print_statistics, + init_ssanames, fini_ssanames, make_ssa_name, + release_ssa_name, ssanames_print_statistics, + annotate_with_file_line, build_empty_stmt, + annotate_with_locus, expr_only, categorize_ctor_elements, + count_type_elements, add_var_to_bind_expr, is_essa_node, + expand_stack_alloc, expand_stack_save, + expand_stack_restore, add_case_node, operand_equal_p, + nondestructive_fold_unary_to_constant, + nondestructive_fold_binary_to_constant, + fold_read_from_constant_string, int_const_binop, + strip_float_extensions, simplify_builtin, c_strlen, + recompute_tree_invarant_for_addr_expr, + needs_to_live_in_memory, make_vector, + setjmp_vars_warning, update_alignment_for_field, + expand_asm_expr, asm_op_is_mem_input, + containing_blocks_have_cleanups_or_stack_level, + create_artificial_label, gimplify_function_tree, + get_name, unshare_expr, walk_tree, + walk_tree_without_duplicates, in_gimple_form): Declare. + (struct tree_exp): Add fields locus and block. + (struct tree_ssa_name, struct edge_def, struct + tree_phi_node, struct tree_eref_common, struct + tree_euse_node, struct ephi_arg_d, struct tree_ephi_node, + union alias_var_def, struct tree_statement_list_node, + struct tree_statement_list, enum operand_equal_flag): Declare. + (enum tree_node_structure_enum): Add TS_SSA_NAME, + TS_PHI_NODE, TS_EPHI_NODE, TS_EUSE_NODE, TS_EREF_NODE, + TS_STATEMENT_LIST. + (union tree_node): Add fields ssa_name, phi, eref, ephi, + euse and stmt_list. + (function_cannot_inline_p, uninitialized_vars_warning, + save_for_inline, output_inline_function, all_cases_count, + check_for_full_enumeration_handling, + declare_nonlocal_label): Remove. + (enum tree_dump_index): Add TDI_none, TDI_tu, + TDI_generic, TDI_nested, TDI_vcg, TDI_xml. + * unroll.c (unroll_loop): Don't clear map->inline_target. + * unwind-sjlj.c (uw_install_context): Make a proper static inline + function. + * value-prof.c (value_prof_hooks): New. + (find_values_to_profile): Rename to rtl_find_values_to_profile. + Move rtl-specific bits in from branch_prob. + (value_profile_transformations): Rename to + rtl_value_profile_transformations. + (struct value_prof_hooks): New. + (rtl_value_prof_hooks): New. + (rtl_register_value_prof_hooks): New. + (tree_find_values_to_profile): New stub. + (tree_value_profile_transformations): New stub. + (tree_value_prof_hooks): New stub. + (tree_register_value_prof_hooks): New stub. + (find_values_to_profile): New. + (value_profile_transformations): New. + * value-prof.h: Add multiple inclusion guard. + (struct histogram_value): Change rtx fields to void *. + (rtl_register_value_prof_hooks): New declaration. + (tree_register_value_prof_hooks): New declaration. + (find_values_to_profile): New declaration. + (free_profiled_values): New declaration. + (value_profile_transformations): New declaration. + (struct profile_hooks): New declaration. + (init_branch_prob): Declaration moved from rtl.h. + (branch_prob): Declaration moved from rtl.h. + (end_branch_prob): Declaration mooved from rtl.h. + (tree_register_profile_hooks): New declaration. + (rtl_register_profile_hooks): New declaration. + (tree_profile_hooks): New declaration. + (rtl_profile_hooks): New declaration. + * varasm.c: Include tree-mudflap.h. + (TRAMPOLINE_ALIGNMENT): Remove. + (make_decl_rtl): Call mudflap_enqueue_decl. + (assemble_static_space): + (assemble_trampoline_template): Set and return + TRAMPOLINE_ALIGNMENT. + * varray.c (element): Add GENERIC_PTR_NOGC entry. + Add entry for 'tree *'. + Add entry for struct edge_def *. + (varray_copy): New. + * varray.h (enum varray_data_enum): Add + VARRAY_DATA_GENERIC_NOGC, VARRAY_DATA_EDGE and + VARRAY_DATA_TREE_PTR. + (union varray_data_tag): Corresponding changes. + (VARRAY_GENERIC_PTR_NOGC_INIT, VARRAY_EDGE_INIT, + VARRAY_TREE_PTR_INIT, VARRAY_GENERIC_PTR_NOGC, + VARRAY_EDGE, VARRAY_TREE_PTR, + VARRAY_PUSH_GENERIC_PTR_NOGC, VARRAY_PUSH_EDGE, + VARRAY_PUSH_TREE_PTR, VARRAY_TOP_GENERIC_PTR_NOGC, + VARRAY_TOP_EDGE, VARRAY_TOP_TREE_PTR): Define. + + * config/*/*: Various updates for changed macros, tree + codes, etc. Check ChangeLog.tree-ssa. + + * doc/cfg.texi: New file. + * doc/tree-ssa.texi: New file. + * doc/c-tree.texi: Document new codes. + * doc/gccint.texi: Include new files. + * doc/install.texi: Document new features. + * doc/invoke.texi: Document new switches. + * doc/passes.texi: Document new passes. + * doc/rtl.texi: Update changed RTL codes. + * doc/sourcebuild.texi: Update build instructions. + * doc/standards.texi: Document Fortran changes. + * doc/tm.texi: Update. + 2004-05-12 Paolo Bonzini Replace several arrays with a struct of arrays. diff --git a/gcc/ChangeLog.tree-ssa b/gcc/ChangeLog.tree-ssa new file mode 100644 index 00000000000..cf077aa1e36 --- /dev/null +++ b/gcc/ChangeLog.tree-ssa @@ -0,0 +1,19338 @@ +2004-05-11 Diego Novillo + + * tree-cfg.c (delete_tree_cfg): Update call to + free_basic_block_vars. + +2004-05-10 Diego Novillo + + * tree-ssa-live.h: Fix typo in #include guard. + +2004-05-08 Jeff Sturm + + * tree-eh.c (lower_catch): Lower catch body in context of + catch_region. + +2004-05-07 Richard Henderson + + * tree-eh.c (tree_could_trap_p): Use get_base_address on references. + +2004-05-07 Diego Novillo + + * doc/invoke.texi: Remove documentation for -ftree-copyprop. + Update documentation for -ftree-pre. + +2004-05-06 Richard Henderson + + * stmt.c (parse_output_constraint): Don't warn for read-write + memory operand. + * gimplify.c (gimplify_asm_expr): Force in-out memory operands + to minimal lvalues, then expand to non-matching constraints. + +2004-05-06 Zack Weinberg + + * c-decl.c (finish_function): When !targetm.have_ctors_dtors, + record static constructors and destructors here... + (c_expand_body_1): ... not here. + * c-objc-common.c (start_cdtor, finish_cdtor): Collapse + together into + (build_cdtor): ...here. Update to construct a complete tree + for the function. No need to call push_scope, pop_scope, or + clear_last_expr, or set current_function_cannot_inline. + (c_objc_common_finish_file): Just call build_cdtor for static + ctors/dtors, then clear the variables. Do this before calling + cgraph_finalize_compilation_unit and cgraph_optimize. + +2004-05-06 Richard Henderson + + * fold-const.c (fold): Don't build COND_EXPR from comparisons for + boolean and integer result types. Handle X ^ X for TRUTH_XOR_EXPR. + +2004-05-05 Richard Henderson + + * tree-nested.c (create_tmp_var_for): Disallow variable sized types. + (convert_nonlocal_reference): Set val_only false for the base of a + component or array reference. + (convert_local_reference): Likewise. + +2004-05-05 Richard Henderson + + * gimplify.c (create_tmp_var): Disallow variable sized objects. + (gimplify_modify_expr): Don't memcpy for VA_ARG_EXPR. + +2004-05-05 Richard Henderson + + * fold-const.c (operand_equal_p): Replace only_const argument with + flags. Allow pure functions if OEP_PURE_SAME. + (fold, nondestructive_fold_binary_to_constant): Use OEP_ONLY_CONST. + * tree-cfg.c (phi_alternatives_equal): Fix operand_equal_p flag type. + * tree-ssa-dom.c (avail_expr_eq): Use OEP_PURE_SAME. + * tree.h (enum operand_equal_flag): New. + (operand_equal_p): Update argument list. + +2004-05-05 Richard Henderson + + * tree-ssa-operands.c (get_call_flags): Remove. + (get_expr_operands): Use call_expr_flags. + * tree-alias-common.c (call_may_clobber): Likewise. + (call_may_return): Likewise. + +2004-04-05 Andrew Pinski + + PR c/15062 + * c-typeck.c (build_asm_expr): Mark the output operands + to an asm addressable, if necessary. + +2004-05-05 Steven Bosscher + + * Makefile.in (GTFILES): Remove duplicate basic-block.h. + +2004-05-04 Richard Henderson + + * gimplify.c (build_addr_expr_with_type): Set TREE_ADDRESSABLE. + (gimplify_modify_expr): Turn variable-width assignment into memcpy. + * tree-nested.c (convert_local_reference): Set val_only after default. + +2004-05-04 Diego Novillo + + * tree-cfg.c (tree_cfg2vcg): Rename from tree_cfg2dot. Update all + users. + Emit flowgraph using VCG syntax. + * tree-dump.c (dump_files): Rename -fdump-tree-dot to + -fdump-tree-vcg. + * tree.h (enum tree_dump_index): Rename TDI_dot to TDI_vcg. + * doc/invoke.texi: Update documentation to describe + -fdump-tree-vcg. + +2004-05-03 Andrew Pinski + + * objc/objc-act.c (build_objc_string_object): + Add the fields to the purpose of the list for + the constructor. + +2004-05-03 Richard Henderson + + * c-simplify.c (gimplify_if_stmt): Loop for else-if. + +2004-05-03 Andrew Pinski + + PR optimization/15245 + * tree-ssa-phiopt.c (conditional_replacement): Use fold_convert + instead of convert. + +2004-05-03 Diego Novillo + + * gimplify.c (gimplify_compound_lval): Gimplify non-constant + array indices into a temporary variable. + +2004-04-30 Richard Henderson + + * builtins.c (validate_arglist): Don't reject side effects. + (simplify_builtin_strcpy): Do reject side effects in length. + +2004-04-30 Jeff Law + + * tree-outof-ssa.c (eliminate_build): Move code which verifies + that all of a PHI's arguments do not have a partition if the + result does not have a partition from here to... + (rewrite_trees): Here. + +2004-04-24 Zdenek Dvorak + + * tree-cfg.c (factored_computed_goto_label, + factored_computed_goto): Removed. + (disband_implicit_edges): Unfactor computed gotos without + using them. + +2004-04-23 Per Bothner + + * expr.c (expr_wfl_stack): Remove unused global. + + Pre-patches for future source_location / location_t merge. + * tree.h (EXPR_LOCATION, EXPR_HAS_LOCATION): New macros. + * expr.c (expand_expr_real, expand_expr_real_1): Use new macros. + * gimple-low.c (lower_stmt): Likewise. + * gimplify.c (annotate_all_with_locus): Likewise. + * print-tree.c (print_node): Likewise. + * tree-inline.c (expand_call_inline): Likewise. + * tree-pretty-print.c (tree-pretty-print.c): Likewise. + * tree-sra.c (scalarize_structure_assignment, emit_scalar_copies, + scalarize_call_expr): Likewise. + * tree-ssa-pre.c (code_motion): Likewise. + +2004-04-23 Andrew Pinski + + * c-simplify.c (gimplify_decl_stmt) [TYPE_DECL]: + Do not check the type. + +2004-04-22 Jeff Law + + * tree-into-ssa.c (rewrite_initialize_block_local_data): Mark all + arguments as potentially unused. Do not bother to VARRAY_CLEAR + the block_defs. Instead abort if we are presented with a block + which has a nonempty block_defs. Wrap entire thing inside + #ifdef ENABLE_CHECKING. + * tree-ssa-dom.c (dom_opt_initialize_block_local_data): Similarly + + * tree-ssa-dom.c (redirect_edges_and_update_ssa_graph): Do not mark + arguments to bypassed PHIs as needing to be rewritten. + +2004-04-21 Richard Henderson + + PR middle-end/14978 + * tree-nested.c (convert_nonlocal_reference): Set val_only when + processing any otherwise unhandled expression. + +2004-04-21 Jeff Law + + * tree-ssa-copy.c (cprop_operand): Break out of cprop_into_stmt. + (cprop_into_stmt): Use cprop_operand. Rearrange slightly to avoid + switch statement inside a loop. + + * tree-flow.h (var_ann_d): Add "current_def" field. + (register_new_def): Lose last argument (currdefs table). + * tree-into-ssa.c (currdefs): Remove. + (rewrite_into_ssa): Initialize current_def field on each variable's + annotation. Remove initialization/clearing of currdefs. + (set_value_for, get_value_for): Kill. + (rewrite_initialize_block): Update call to register_new_def. + (rewrite_stmt): Similarly. + (rewrite_finalize_block): Get/set a _DECL node's current + definition from its annotation. + (get_reaching_def): Similarly. + (register_new_def): Similarly. Lose last argument. + * tree-ssa-dom.c (currdefs): Remove. + (get_value_for, set_value_for): Simplify. + (tree_ssa_dominator_optimize): Initialize current_def on each + variable's annotation. Remove initialization/clearing of currdefs. + (thread_across_edge): Lose unnecessary argument to register_new_def. + (record_equivalences_from_phis): Likewise. + (register_definitions_for_stmt): Likewise. + (restore_currdefs_to_original_value): Get/set a _DECL node's current + definition from its annotation. Lose unnecessary "table" argument. + (dom_opt_finalize_block): Corresponding changes. + + * tree-dfa.c (free_df_for_stmt): Release memory back to the GC + system immediately. + +2004-04-21 Ben Elliston + + PR middle-end/14730 + * expr.c (expand_expr_real_1) : Discard out of bounds + case label values and ranges. Saturate case range values that + exceed the minimum or maximum permitted value for the controlling + expression type to TYPE_MIN_VALUE or TYPE_MAX_VALUE. + +2004-04-20 Jeff Law + + * tree-into-ssa.c (register_new_def): Avoid pushing useless + information onto the block local definition stack. + + * tree-into-ssa.c (register_new_def): If there is no current + reaching definition for SSA_NAME_VAR (DEF), then just push + SSA_NAME_VAR (DEF) onto the stack. + (rewrite_finalize_block): If we pop a _DECL node from the stack, + then the _DECL node has no current reaching definition. + * tree-ssa-dom.c (restore_currdefs_to_original_value): Similarly. + +2004-04-19 Jeff Law + + * tree-ssa-dom.c: Reinstate all changes from 2004-04-12. + (lookup_avail_expr): Do not access a hash table object after + it has been freed. + +2004-04-19 Daniel Berlin + + * doc/passes.texi: Add blurb about PRE. + +2004-04-19 Andrew Pinski + + * tree-ssa-phiopt.c (conditional_replacement): + Catch some more non-gimple. + +2004-04-19 Jan Hubicka + + * predict.c (combine_predictions_for_bb): Fix pasto. + +2004-04-18 Jan Hubicka + + * tree-inline.c (estimate_num_insn_1): Deal properly with + builtin_constant_p and builtin_expect. + +2004-04-17 Andrew MacLeod + + * doc/invoke.texi (tree-ter, tree-lrs): Document options. + +2004-04-17 Paul Brook + + * Makefile.in: Set GMPLIBS and GMPINC. + * configure.ac: Add GMPLIBS and GMPINC. + * configure: Regenerate. + +2004-04-16 Andrew MacLeod + + * common.opt (ftree-lrs): New common option. + * flags.h (flag_tree_live_range_split): New flag. + * opts.c (decode_options): Turn on LRS by default. + (common_handle_option): Set LRS flag to specified value. + * toplev.c (flag_tree_live_range_split): Initialize. + (lang_independent_options f_): Add tree-lrs. + * tree-outof-ssa.c (rewrite_out_of_ssa): Use LRS flag. + * tree-ssa-copyrename.c (copy_rename_partition_coalesce): Don't coalesce + variables if one is a hardware register. Coalesce inlined user vars. + (rename_ssa_copies): Scan blocks first, then PHI nodes. + +2004-04-15 Andrew Pinski + + * builtins.c (fold_builtin_isascii): Do not return non-gimple + code when we are in gimple form. + (fold_builtin_isdigit): Do not return non-gimple + code when we are in gimple form. + + * c-simplify.c (gimplify_decl_stmt): Handle TYPE_DECL. + +2004-04-14 Paul Brook + + * Makefile.in (GMPLIBS, GMPINC): Don't set. + * configure.ac: Remove checks for GMP. + * configure: Regenerate. + +2004-04-13 Diego Novillo + + * fold-const.c, tree-ssa-ccp.c, tree-ssa-dom.c, + tree-ssa.c, tree.c: Replace all uses of TREE_UNSIGNED with + TYPE_UNSIGNED or DECL_UNSIGNED. + + * c-semantics.c (build_stmt): Don't check type nodes for + side effects. + +2004-04-13 Jeff Law + + * tree-ssa-dom.c: Revert all changes from 2004-04-12. + +2004-04-12 Jeff Law + + * tree-ssa-dom.c (struct expr_hash_elt): Add new field for hash value. + (initialize_hash_element): New LHS argument. Callers changed. + Initialize the hash value field. + (remove_local_expressions_from_table): Use htab_remove_elt_with_hash. + (update_rhs_and_lookup_avail_expr): Similary. + (lookup_avail_expr): Use htab_find_slot_with_hash. Simplify slightly + and pass LHS to initialize_hash_element. + (record_cond): Also use htab_find_slot_with_hash. Initialize the + hash table entry with initialize_hash_element. + (avail_expr_eq): Use the saved hash value rather than calling into + the hash functions again. + + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Slightly rearrange + code to clear tables before each iteration to be clearer. + + * tree-ssa-dom.c (redirect_edges_and_update_ssa_graph): Use + DEF_OPS and VDEF_OPS instead of STMT_DEF_OPS and STMT_VDEF_OPS. + +2004-04-12 Diego Novillo + + * flags.h (flag_tree_loop): Remove. Update all users. + * opts.c (common_handle_option) : Remove. + * toplev.c (f_options): Remove -ftree-loop-optimize. + * tree-optimize.c (init_tree_optimization_passes): Don't + schedule pass_loop. + * tree-ssa-loop.c (tree_ssa_loop_opt): Remove. + (gate_loop): Remove. + * doc/invoke.texi: Remove documentation for -ftree-loop-optimize. + +2004-04-12 Diego Novillo + + * c-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): Remove. + * c-semantics.c (expand_stmt_toplev): Remove. + * langhooks-def.h (LANG_HOOKS_RTL_EXPAND_INITIALIZER): Remove. + (LANG_HOOKS_RTL_EXPAND_START): Remove. + (LANG_HOOKS_RTL_EXPAND_STMT): Remove. + (LANG_HOOKS_RTL_EXPAND_END): Remove. + * langhooks.h (struct lang_hooks_for_rtl_expansion): Remove. + (struct lang_hooks): Update. + * tree-optimize.c (tree_rest_of_compilation): Don't call + lang_hooks.rtl_expand.start nor lang_hooks.rtl_expand.end. + Call expand_expr_stmt_value instead of + lang_hooks.rtl_expand.stmt. + * objc/objc-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): Remove. + + +2004-04-12 Richard Henderson + + * c-common.c (c_do_switch_warnings): Use EXPR_LOCUS instead + of STMT_LINENO. + (c_walk_subtrees): Likewise. + (c_estimate_num_insns_1): Remove FILE_STMT. + * c-common.def (FILE_STMT): Remove. + * c-common.h (FILE_STMT_FILENAME_NODE): Remove. + (FILE_STMT_FILENAME, STMT_LINENO, STMT_LINENO_FOR_FN_P): Remove. + (c_common_stmt_codes): Remove FILE_STMT. + * c-dump.c (dump_stmt): Use EXPR_LOCUS instead of STMT_LINENO. + * c-parse.in (lineno_stmt, lineno_label): Likewise. + * c-pretty-print.c (pp_c_statement): Remove FILE_STMT. + * c-semantics.c (add_stmt): Don't emit FILE_STMT. Do set + EXPR_LOCUS if not yet set. + (finish_stmt_tree): Don't set line for end of function. + (build_stmt): Set EXPR_LOCUS instead of STMT_LINENO. + (prep_stmt): Use EXPR_LOCUS instead of STMT_LINENO. + * c-simplify.c (c_gimplify_stmt): Remove FILE_STMT. + (gimplify_block): Save and restore entire locus. + (stmt_expr_last_stmt): Use EXPR_LOCUS instead of STMT_LINENO. + * doc/c-tree.texi (FILE_STMT, FILE_STMT_FILENAME, STMT_LINENO): Remove. + +2004-04-12 Jeff Law + + * tree-ssa-dom.c (true_exprs, false_exprs): Kill. + (struct expr_hash_elt): New structure for the expression hash table. + (struct dom_walk_block_data): Kill block local true_exprs and + false_exprs. + (get_eq_expr_value): One less local varray argument. Fix prototype. + Use record_cond rather than record_cond_is_{true,false}. + (true_false_expr_hash, true_false_expr_eq): Kill. + (record_cond_is_true, record_cond_is_false): Collapse into ... + (record_cond): New function. + (tree_ssa_dominator_optimize): Kill references to true_exprs and + false_exprs. Use "free" as the free function for the avail_exprs + hash table. + (dom_opt_initialize_block_local_data): No longer initialize + block local true/false expressions. + (initialize_hash_element): New function. + (remove_local_expressions_from_table): Use initialize_hash_element. + (update_rhs_and_lookup_avail_expr): Similarly. + (dom_opt_finalize_block): Record true/false expressions into the + main avail_expr hash table. Unwind main hash table appropriately. + Use record_cond rather than record_cond_is_{true,false}. + (record_equivalences_from_incoming_edge): Pass block local avail_exprs + varray instead of block local true/false varrays to get_eq_expr_value. + (dump_dominator_optimization_stats): Update to reflect that the + true/false expression hash tables are gone. + (lookup_avail_expr): Simplify slightly now that we only have one + expression hash table. + (avail_expr_hash, avail_expr_eq): Generalize slightly to handle new + hash table entry structure and having true/false expression information + in the available expression hash table. + +2004-04-09 Jeff Law + + * tree-ssa_dom.c (register_definitions_for_stmt): Accept a statement + annotation rather than the statement itself. Callers changed. + Use [V]DEF_OPS rather than STMT_[V]DEF_OPS. + * tree-ssa-operands.c (get_stmt_operands): Slightly reorganize to + avoid unnecessary calls to stmt_ann. + * tree-ssa-pre.c (expr_phi_insertion): Get the statement's annotation + and use [V]USE_OPS rather than STMT_[V]USE_OPS. + (same_e_version_phi_result): Similarly + (process_left_occs_and_kills): Similarly for [V]DEF_OPS and + STMT_[V]DEF_OPS. + * tree-ssa.c (replace_immediate_uses): Similarly. + (verify_ssa): Similarly. Also verify that VDEF_OPs uses are dominated + by their sets. + + * tree-into-ssa.c (insert_phi_nodes_for): Use passed in worklist + varray instead of allocated one for every variable we rewrite into + SSA form. + (insert_phi_nodes_1): Pass worklist varray from caller to + insert_phi_nodes_for. + (insert_phi_nodes): Allocate a worklist for insert_phi_nodes_for + and pass it to insert_phi_nodes_1. + +2004-04-08 Jeff Law + + * tree-ssa-dom.c (nonzero_vars): Turn it into a bitmap. + (tree_ssa_dominator_optimize): Update initialization, clearing and + freeing of nonzero_vars. + (restore_nonzero_vars_to_original_value): New function. + (dom_opt_finalize_block): Use it. + (record_var_is_nonzero): Only record the variable into the block + local nonzero vars array if it did not already have a nonzero property. + (lookup_avail_expr): Lookup the nonzero property of an SSA_NAME with + a bitmap test. + + * fold-const.c (fold): Remove attempt to share code which + simplifies tests against the highest/lowest value of a + range between the main folder and the nondestructive folder. + +2004-04-08 Brian Booth + Diego Novillo + + * tree-into-ssa.c (invalidate_name_tags): New function. + Mark aliases of invalidated name tags for renaming. + (rewrite_into_ssa): Call invalidate_name_tags. + +2004-04-07 Diego Novillo + + * gimplify.c (gimplify_call_expr): Remove argument POST_P. + Update all callers. + Don't use POST_P when gimplifying the call expression. + +2004-04-07 Diego Novillo + + * doc/tree-ssa.texi: Add documentation for the dominator + walker. + +2004-04-07 Andrew MacLeod + + * tree-outof-ssa.c: Update comments and reformat for legibility. + * tree-ssa-copyrename.c: Update comments and reformat for legibility. + * tree-ssa-live.c: Update comments and reformat for legibility. + * tree-ssa-live.h: Update comments and reformat for legibility. + +2004-04-07 Diego Novillo + + * gimplify.c (gimplify_call_expr): Don't use POST_P when + gimplifying CALL_EXPR arguments. + +2004-04-06 Diego Novillo + + * tree-dfa.c: Update comments and reformat for legibility. + (find_vars_r): Remove special casing of MODIFY_EXPR and + simplify logic. + (compute_reached_uses, compute_reaching_defs, remove_decl, + find_decl_location): Remove. + (discover_nonconstat_array_refs_r, + discover_nonconstant_array_refs): Move ... + * tree-outof-ssa.c: ... here. + +2004-04-05 Richard Henderson + + * tree-simple.c (is_gimple_min_invariant): Disallow &a+i. + * tree-ssa-ccp.c (maybe_fold_stmt_addition): Rename from + maybe_fold_stmt_plus. Handle MINUS_EXPR. + (fold_stmt_r): Pass MINUS_EXPR to it. + +2004-04-05 Ben Elliston + + * Makefile.in (OBJS-common): Remove tree-browser.o. + (cc1): Depend on @TREEBROWSER@ and include in list of objects. + * configure.ac: Add --enable-tree-browser option. + * configure: Rebuild. + +2004-04-05 Andrew Pinski + + * tree-ssa-ccp.c (fold_stmt_r): Fix whitespace formatting. + (set_rhs): Likewise. + +2004-04-03 Paolo Bonzini + Diego Novillo + + * tree-alias-common.c (find_func_aliases): Support + assigning to BIT_FIELD_REFs. + * tree-cfg.c (verify_expr): Don't allow assign to + a register with BIT_FIELD_REF. + * tree-dfa.c (get_virtual_var): Add consistency check on + the shape of expected VARs. + (discover_nonconstant_array_refs_r): Go through BIT_FIELD_REFs. + * tree-simple.c: Document that BIT_FIELD_REFs are valid lvalues. + * tree-ssa.c (set_is_used): Go through BIT_FIELD_REFs. + * tree-ssa-operands.c (get_expr_operands): Mark VA_ARG_EXPR + nodes as making volatile references. + +2004-04-02 Fariborz Jahanian + + * c-convert.c (convert): Make convert work when converting + to compatible types across translation unit. + +2004-04-02 Andrew Pinski + + * Makefile.in (stage2_build): Remove support for + rebuilding libbanshee. + * configure.ac: Remove support for rebuilding + libbanshee. + * config.gcc (powerpc-*-darwin*): Do not rebuild + libbanshee. + +2004-04-01 Kazu Hirata + + * tree-ssa-forwprop.c: Add a comment about forward propagation + of TRUTH_NOT_EXPR. + +2004-04-01 Diego Novillo + + * tree-optimize.c (tree_rest_of_compilation): Fix typo in + setting of in_gimple_form. + +2004-04-01 Jeff Law + + * fold-const.c (fold_relational_hi_lo): Do not return non-gimple + code when we are in gimple form. + * tree-optimize.c (tree_rest_of_compilation): Note when we are in + gimple form. + * tree-ssa-ccp.c (ccp_fold): Tighten tests on return value from + nondestructive_fold_{unary,binary}_to_constant. + * tree.h (in_gimple_form): Declare. + + * tree-ssa.c (ssa_remove_edge): Correct looping structure. + (ssa_redirect_edge): Similarly + +2004-03-30 Brian Booth + + * tree-pretty-print.c (dump_vops): Add flags argument and + propagate it to dump_generic_node calls. + (dump_generic_node): Update dump_vops call. + +2004-03-29 Diego Novillo + + * configure.ac: Emit confirmation messages for libbanshee. + * configure: Regenerate. + +2004-03-29 Jan Hubicka + + PR 14756 + * cgraphunit.c (cgraph_decide_inlining): Rewrite handling of + always_inline functions. + +2004-03-28 Jan Hubicka + + * tree-inline.c (expand_call_inline): Remove fixme introduced by + nested function patch. + +2004-03-26 Diego Novillo + + * tree-ssa-operands.c (get_stmt_operands): Remove always-true + predicate. + + * tree-ssa-alias.c (maybe_create_global_var): Create + .GLOBAL_VAR if there are no call-clobbered variables. + * tree-ssa-operands.c (get_stmt_operands): Add call-clobbering + VDEFs for asm ("":::"memory") if there are call-clobbered + variables or if .GLOBAL_VAR has been created. + + +2004-03-26 Diego Novillo + + * passes.c (rest_of_compilation): Re-enable .01.rtl + dumps. + +2004-03-25 Diego Novillo + + * tree-pretty-print.c (dump_generic_node) : Remove. + * tree-inline.c (estimate_num_insns_1) : Remove. + * fold-const.c (fold_relational_hi_lo): Change type of argument + 'type_p' to const tree and rename it to 'type'. Update + all callers. + +2004-03-25 Diego Novillo + + * Makefile.in (C_AND_OBJC_OBJS): Remove c-call-graph.o + (c-call-graph.o): Remove. + * c-call-graph.c: Remove. + * c-tree.h (print_call_graph): Remove. + (debug_call_graph): Remove. + * tree-cfg.c: Update/add comments everywhere. + (pre_insert_on_edge): Rename from bsi_insert_on_edge_immediate. + * tree-flow.h (build_tree_cfg): Make static. + (tree_cfg2dot): Likewise. + (verify_stmt): Likewise. + * tree-ssa-pre.c (insert_one_operand): Call pre_insert_on_edge. + +2004-03-25 Diego Novillo + + * tree-ssa-alias.c (struct alias_info): Change type of field + 'num_references' to varray_type. Update all users. + +2004-03-24 Jeff Law + + * c-mudflap (mflang_flush_calls): Use push_scope/pop_scope instead + of pushlevel and poplevel. + +2004-03-23 Richard Henderson + + PR middle-end/14694 + * c-common.c (handle_alias_attribute): Mark aliased variables + to be TREE_STATIC. + +2004-03-23 Jeff Law + + * tree-into-ssa.c (register_new_def): Lose unnecessary VAR argument, + instead derive VAR from DEF argument. + (rewrite_initialize_block, rewrite_stmt, rewrite_operand): Corresponding + changes. + * tree-ssa-dom.c (register_definitions_for_stmt): Corresponding changes. + (record_equivalences_from_phis): Likewise. + (restore_currdefs_to_original_value): New, extracted from ... + (dom_opt_finalize_block): Use restore_currdefs_to_original_value. + Restore currdefs after threading across a true edge. + (thread_across_edge): Register new defintions when we walk through + a PHI node or real statement. + * tree-flow.h (register_new_def): Updated. + +2004-03-23 Zdenek Dvorak + + * tree-ssa-dce.c (find_obviously_necessary_stmts, + perform_tree_ssa_dce): Do not remove loops. + +2004-03-19 Diego Novillo + + PR optimization/14643 + * tree-ssa-alias.c (group_aliases_into): Don't add a variable + to its own may-alias set. + (create_alias_map_for): New. + (setup_pointers_and_addressables): Call it. + Fix allocation of AI->ADDRESSABLE_VARS and AI->POINTERS. + If there are no addressable variables and more than one + dereferenced pointers, add type tags to the ADDRESSABLE_VARS + array. + (get_tmt_for): Add comment about using alias set equality when + checking for existing tags. + +2004-03-19 Kazu Hirata + + * fold-const.c (fold_relational_const): Remove dead code. + +2004-03-19 Dale Johannesen + + * tree-ssa-dse.c (dse_optimize_stmt): Redirect uses feeding into + a deleted store correctly. + +2004-03-19 Jeff Law + + * tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): Fix typo. + Eliminate unnecessary test of VAL. + + * tree-dfa.c (find_hidden_use_vars): Also look inside the + PENDING_SIZES list for hidden uses. + * tree-optimize.c (tree_rest_of_compilation): Expand used variables + before setting up parameters. + * tree-ssa-copyrename.c (rename_ssa_copies): Do nothing for copies + where the LHS has a hidden use. + +2004-03-18 Diego Novillo + + * Makefile.in (TREE_FLOW_H): Reformat. + (OBJS-common): Add tree-into-ssa.o and tree-outof-ssa.o. + (tree-ssa.o): Remove dependency on domwalk.h and tree-ssa-live.h + (tree-into-ssa.o): New. + (tree-outof-ssa.o): New. + (GTFILES): Remove tree-ssa.c. + (gt-tree-ssa.h): Remove. + * tree-into-ssa.c: New file. + Move all the functions used to rename into SSA from tree-ssa.c. + Update/add comments. + Remove unused variables and structures. + Don't use GGC for memory allocation. + * tree-outof-ssa.c: New file. + Move all the functions used to rename out of SSA from + tree-ssa.c. + Update/add comments. + * tree-ssa-alias.c (compute_points_to_and_addr_escape): Add + bibliographic reference. + +2004-03-18 Jeff Law + + * Makefile.in (tree-tailcall.o): Depend on langhooks.h. + * tree-tailcall.c: Include langhooks.h. + (find_tail_calls): Use types_compatible_p langhook instead of + equality test of TYPE_MAIN_VARIANT. + + * tree-nested.c (get_chain_decl): Mark the chain decl with + TREE_NO_WARNING. + +2004-03-18 Devang Patel + + * tree-ssa-live.c (new_tree_live_info): Set num_blocks to + last_basic_block instead of n_basic_blocks. + (calculate_live_on_entry): Use last_basic_block instead of + n_basic_blocks. + (calculate_live_on_exit): Same. + +2004-03-17 Jeff Law + + * tree-tailcall.c (find_tail_calls): Tighten test for tail recursion. + +2004-03-17 Diego Novillo + + PR optimization/14511 + * tree-ssa-alias.c (compute_flow_insensitive_aliasing): Do not + ignore read-only variables. + (may_alias_p): Fix pointer-to-var calculation when 'var' is an + array. + +2004-03-17 Jan Hubicka + + * tree-ssa.c (rewrite_into_ssa, compute_global_livein): Fix. + +2004-03-17 Paolo Bonzini + + * builtins.c (expand_builtin_constant_p, + purge_builtin_constant_p): Remove. + (expand_builtin): Expand __builtin_constant_p to zero. + * function.c (struct function): Remove calls_constant_p. + (current_function_calls_constant_p): Remove. + * passes.c (rest_of_handle_gcse): Do not run + purge_builtin_constant_p. + * rtl.def (CONSTANT_P_RTX): Die die die. + + * cse.c (fold_rtx): Do not handle CONSTANT_P_RTX. + * expr.c (emit_move_insn): Likewise. + * gcse.c (want_to_gcse_p, gcse_constant_p): Likewise. + * genrecog.c (validate_pattern): Likewise. + * recog.c (immediate_operand): Likewise. + * rtl.h (CONSTANT_P): Likewise. + * simplify-rtx.c (simplify_rtx): Likewise. + * config/alpha/alpha.c (input_operand): Likewise. + * config/arm/arm.c (THUMB_LEGITIMATE_CONSTANT_P): Likewise. + * config/c4x/c4x.c (const_operand): Likewise. + * config/cris/cris.c (cris_gotless_symbol, + cris_got_symbol): Likewise. + * config/frv/frv.h (LEGITIMATE_PIC_OPERAND_P): Likewise. + * config/ia64/ia64.c (gr_reg_or_5bit_operand, + gr_reg_or_6bit_operand, gr_reg_or_8bit_operand, + gr_reg_or_8bit_adjusted_operand, + gr_reg_or_8bit_and_adjusted_operand, + gr_reg_or_14bit_operand, gr_reg_or_22bit_operand, + shift_count_operand, shift_32bit_count_operand): Likewise. + * config/m32r/m32r.c (move_src_operand): Likewise. + * config/mips/mips.c (mips_const_insns): Likewise. + * config/mmix/mmix.c (mmix_constant_address_p): Likewise. + * config/pa/pa.c (move_src_operand): Likewise. + * config/rs6000/rs6000.c (input_operand): Likewise. + * config/sparc/sparc.c (input_operand): Likewise. + * config/v850/v850.c (movsi_source_operand): Likewise. + * config/xtensa/xtensa.c (move_operand, + xtensa_emit_move_sequence): Likewise. + * config/ia64/ia64.h (PREDICATE_CODES): Do not mention CONSTANT_P_RTX. + * config/pa/pa.h (PREDICATE_CODES): Likewise. + +2004-03-16 Diego Novillo + + * tree-dump.c (struct dump_option_value_info): Add TDF_UID. + * tree.h (TDF_UID): Define. + * doc/invoke.texi: Document -ftree-dump-...-uid. + * tree-pretty-print.c (debug_generic_expr): Add TDF_UID. + (debug_generic_stmt): Likewise. + (dump_decl_name): New function. + (dump_generic_node): Call it. + (print_declaration): Add new argument 'flags'. Update all users. + (print_struct_decl): Likewise. + * tree-alias-ander.c, tree-cfg.c, tree-dfa.c, tree-mudflap.c, + tree-nrv.c, tree-sra.c, tree-ssa-alias.c, tree-ssa-ccp.c, + tree-ssa-copy.c, tree-ssa-dom.c, tree-ssa-dse.c, + tree-ssa-forwprop.c, tree-ssa-operands.c, tree-ssa-pre.c, + tree-ssa.c, tree-tail-call.c: Call print_generic_* with + 'dump_flags'. + +2004-03-16 Dale Johannesen + + * Makefile.in (tree-ssa-phiopt.o): add langhooks.h dependency. + (tree-nrv.o): Ditto. + (tree-ssa-copy.o): Ditto. + (tree-ssa-dom.o): Ditto. + (tree-ssa-ccp.o): Ditto. + * c-common.c: Add #include hashtab.h. + (c_type_hash): New. + (c_common_get_alias_set): Handle multiple type nodes referring + to "the same" type, currently for C90 only. + * c-decl.c (current_file_decl): Move to toplev.c. + * c-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Define to + c_types_compatible_p. + (c_types_compatible_p): New. + * c-tree.h (c_types_compatible_p): New declaration. + * c-typeck.c (tagged_types_tu_compatible_p): Allow for + compiler-generated TYPE_DECLs without a DECL_ORIGINAL_TYPE. + * gimplify.c (canonicalize_addr_expr): Use types_compatible_p langhook. + (cpt_same_type): Ditto. + * langhooks-def.h (lhd_types_compatible_p): New declaration. + LANG_HOOKS_TYPES_COMPATIBLE_P: New. + * langhooks.c (lhd_types_compatible_p): New. + * langhooks.h (struct lang_hooks): Add types_compatible_p. + * stmt.c (tail_recursion_args): Use types_compatible_p langhook. + * toplev.c (current_file_decl): New, moved from c-decl.c. + * tree-nrv.c: Include langhooks.h. + (tree_nrv): Use types_compatible_p langhook. + * tree-ssa-ccp.c: Include langhooks.h. + (maybe_fold_offset_to_array_ref): Use types_compatible_p langhook. + (maybe_fold_offset_to_component_ref): Ditto (2 places). + (fold_stmt_r): Make sure rhs of COMPONENT_REF is in lhs type. + * tree-ssa-copy.c: Include langhooks.h. + (cprop_into_stmt): Use types_compatible_p langhook. + * tree-ssa-dom.c: Include langhooks.h. + (avail_expr_p): Use types_compatible_p langhook. + * tree-ssa-phiopt.c: Include langhooks.h. + (conditional_replacement): Use types_compatible_p langhook. + * tree-ssa.c (tree_ssa_useless_type_conversion_1): Use + types_compatible_p langhook. + * tree.h (current_file_decl): New declaration. + +2004-03-16 Dale Johannesen + + PR optimization/14498 + * gimplify.c (copy_if_shared_r): Mark VA_ARGS_EXPRs as volatile. + (mark_decls_volatile_r): Moved higher in file (unchanged). + +2004-03-16 Daniel Berlin + + PR optimization/14562 + * tree-ssa-pre.c (generate_expr_as_of_bb): Don't use names_match_p. + (generate_vops_as_of_bb): Ditto. + +2004-03-12 Diego Novillo + + PR optimization/14553 + * tree-ssa.c (replace_immediate_uses): Call propagate_value to + update operands. + +2004-03-12 Diego Novillo + + * tree-alias-common.c (create_alias_vars): Add #if + HAVE_BANSHEE around test for PTA_ANDERSEN. + +2004-03-11 Diego Novillo + + * tree-dfa.c (struct walk_state): Remove fields 'is_store' and + 'is_indirect_ref'. Update all users. + * tree-flow.h (struct var_ann_d): Remove fields 'is_stored', + 'is_dereferenced_store' and 'is_dereferenced_load'. Update + all users. + * tree-simple.c (get_base_address): Handle BIT_FIELD_REF. + * tree-ssa-alias.c (struct alias_info): Add fields + 'written_vars', 'dereferenced_ptrs_store' and + 'dereferenced_ptrs_load'. + (init_alias_info): Initialize them. + (delete_alias_info): Free them. + (find_ptr_dereference): New. + (ptr_is_dereferenced_by): Call it. + Add new argument 'is_store'. Set to true if the + expression is an indirect store operation. + (compute_points_to_and_addr_escape): If the statement + makes a store, load or write operation, update the + corresponding bitmap. + (compute_flow_insensitive_aliasing): Test the + 'written_vars' bitmap to determine if alias sets should + be computed. + (setup_pointers_and_addressables): Always assume that + volatile pointers and hidden pointers have been used in a + memory store operation. + * tree-ssa-operands.c (add_stmt_operand): Do add an + operand for may-aliased variables before computing + aliases. + +2004-03-11 Zdenek Dvorak + + * tree-optimize.c (init_tree_optimization_passes): Move + pass_tail_recursion and pass_ch after pass_may_alias. + * tree-ssa-loop.c (mark_defs_for_rewrite): Mark type tags + for rewriting. + * tree-ssa.c (mark_def_sites): Process the operand of a + VDEF before the result. + +2004-03-11 Richard Henderson + + PR 14204 + * tree-ssa.c (warn_uninit): Don't warn for hard register variables. + +2004-03-10 Richard Henderson + + * tree-simple.c (get_base_var, get_base_decl): Remove. + * tree-simple.h: Likewise. + * tree-dfa.c (discover_nonconstant_array_refs_r): Use get_base_address. + * tree-ssa-alias.c (ptr_is_dereferenced_by): Likewise. + (add_pointed_to_var, is_escape_site): Likewise. + * tree-ssa-ccp.c (get_default_value): Expect only SSA_NAME and DECLs. + * tree-ssa-operands.c (add_stmt_operand): Likewise. + (note_addressable): Use get_base_address. + * tree-ssa-dce.c (need_to_preserve_store): Expect only SSA_NAME. + * tree-ssa.c (set_is_used): Inline get_base_decl. + +2004-03-10 Richard Henderson + + * tree-nested.c (convert_nonlocal_reference): Clear TREE_INVARIANT + on modified ADDR_EXPRs. + +2004-03-10 Andrew Pinski + + * Makefile.in (tree-ssa-forwprop.o): Fix the dependences. + +2004-03-09 Jeff Law + + * tree-flow-inline.h (may_propagate_copy): Do not allow propagation of + a constant for a virtual operand. + +2004-03-08 Richard Henderson + + * calls.c (initialize_argument_information): Add + parameter may_tail_call. Set to false for invisible + pass-by-reference arguments that require stack + allocation. + Update all users. + +2004-03-07 Jeff Law + + * tree-ssa-dom.c: (get_eq_expr_value): Fix typo when comparing a + boolean against a constant. + * tree-ssa-forwprop.c (record_single_argument_cond_exprs): Do not + record the same SSA_NAME more than once. Only record the SSA_NAME + tested, not the COND_EXPR. + (substitute_single_use_vars): Substitute booleans which are + set from a TRUTH_NOT_EXPR even if they have more than one use site. + +2004-03-05 Jeff Law + + * tree-ssa-dce.c (remove_dead_stmt): Clear PENDING_STMT after + redirect_edge_and_branch call. + + * tree-ssa-forwprop.c (record_single_argument_cond_exprs): Also + record COND_EXPRs with single use vars defined by SSA_NAME + CONST + expressions. + (substitute_single_use_vars): Corresponding changes to rewrite + COND_EXPRs using single use vars defined by SSA_NAME + CONST + expressions. + +2004-03-05 Ulrich Weigand + + * config/s390/s390.c (s390_expand_movstr): Do not use + expand_exit_loop_top_cond, manually copy loop header. + (s390_expand_clrstr): Likewise. + (s390_expand_cmpmem): Likewise. + +2004-03-04 Diego Novillo + + * tree-ssa-alias.c (compute_flow_sensitive_aliasing): If + a name tag has been marked call-clobbered, also mark the + corresponding type tag. + +2004-03-04 Zdenek Dvorak + + * tree-ssa-loop-live.c (coalesce_tpa_members): Update the root + variable of the partition. + +2004-03-04 Jeff Law + + * tree-ssa-dce.c (remove_dead_stmt): Redirect an existing edge + rather than deleting the old ones and creating a new one when + removing a dead conditional. + + * fold-const.c (fold): When rebuilding the expression after a + call to fold_relational_hi_lo, make sure to convert the type of + the second argument to the type of the first. + +2004-03-04 Diego Novillo + + * cgraphunit.c (cgraph_optimize): Do not do memory release + check if there have been errors. + +2004-03-03 Jeff Law + + * tree-ssa-phiopt.c (conditional_replacement): Clear EDGE_TRUE_VALUE + and EDGE_FALSE_VALUE on the remaining edge after eliminating a PHI. + +2004-03-03 Andrew MacLeod + + * tree-ssa-copyrename.c (gate_copyrename): Really check it in. + * tree-ssa.c (create_temp): Use DECL_ARTIFICIAL from original decl. + +2004-03-02 Zdenek Dvorak + + * tree-tailcall.c (struct tailcall): Remove return_block and return_bsi + fields, add m and a fields. + (m_acc, a_acc): New. + (find_tail_calls): Find tail calls on whose results simple operations + are performed. + (independent_on_stmt_p, process_assignment, + propagate_through_phis, adjust_accumulator_values, + adjust_return_value): New. + (eliminate_tail_call): Update the accumulators if needed. + (optimize_tail_call): Do not create phis. + (tree_optimize_tail_calls): Create phis and accumulators as needed. + Adjust return values. + +2004-03-02 Diego Novillo + + * tree-ssa-operands.c (get_expr_operands): Mark CALL_EXPRs + with has_volatile_ops if aliases haven't been computed yet. + (add_stmt_operand): Use 'true' instead of '1'. + +2004-03-02 Diego Novillo + + PR optimization/14266 + * tree-ssa-alias.c (create_global_var): Mark GLOBAL_VAR for + renaming. + +2004-03-01 Richard Henderson + + * tree.c (associative_tree_code): Remove MINUS_EXPR, LSHIFT_EXPR, + RSHIFT_EXPR. + * tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): Use + is_gimple_min_invariant and is_gimple_var. Handle minus_expr + specially. + +2004-03-01 Richard Henderson + + * cfgbuild.c (rtl_make_eh_edge): Rename from make_eh_edge. + * basic-block.h, except.c: Update decl and uses. + +2004-03-01 Frank Ch. Eigler + + * doc/passes.texi: Add information about mudflap. + +2004-03-01 Andrew Pinski + + PR middle-end/13066 + * fold-const (fold): Call fold_convert when building + a TRUTH_*_EXPR tree. + +2004-03-01 Andrew MacLeod + + * common.opt : Add tree-copyrename option. Remove duplicate tree-sra. + * flags.h (flag_tree_copyrename): Declare. + * opts.c (decode_options): Turn copyrename on by default at -O. + (common_handle_option): Handle -ftree-copyrename. + * toplev.c (flag_tree_copyrename): Declare. + * tree-ssa-copyrename.c (gate_copyrename): New. Check flag. + (pass_rename_ssa_copies): Initialize with gated routine. + (lang_independent_options f_): Add tree-copyrename. + * doc/invoke.texi: Add -fdump-tree-copyrename and -ftree-copyrename. + * doc/passes.texi: Add blurb for copy renaming. + +2004-03-01 Jeff Law + + * tree-ssa-dom.c (true_false_expr_hash): Update comments slightly. + (true_false_expr_eq): Update comments slightly. Avoid using + operand_equal_p, instead check the code and operands directly. + +2004-03-01 Andrew MacLeod + + * Makefile.in (tree-ssa-copyrename.o): New object. + * timevar.def (TV_TREE_COPY_RENAME): New time variable. + * tree-optimize.c (init_tree_optimization_passes): Add copy rename + pass. + * tree-pass.h (pass_rename_ssa_copies): New pass structure. + * tree-sra.c (lookup_scalar): Copy DECL_ARITIFICIAL flag from base. + * tree-ssa-copyrename.c : New file. + (copy_rename_partition_coalesce): Coalesce partitions for renaming. + (rename_ssa_copies): Find renamable copies. + (pass_rename_ssa_copies): Initialize. + * tree-ssa-live.c (register_ssa_partition): Move to tree-ssa-live.h. + * tree-ssa-live.h (register_ssa_partition): Moved from tree-ssa-live.c. + +2004-02-29 David Edelsohn + + * doloop.c (doloop_optimize): Increment n_iterations if loop->top + present. + +2004-02-29 Diego Novillo + + * gimple-low.c (pass_remove_useless_vars): Add TODO_dump_func. + +2004-02-27 Richard Henderson + + PR middle-end/14310 + * explow.c (emit_stack_save): Remove savearea mode check. + +2004-02-27 Richard Henderson + + * builtins.c (simplify_builtin_strcmp): Don't export. Remove + length parameters. Remove conversion to memcmp. + (simplify_builtin_strncmp): Likewise. + * expr.h: Don't declare them. + * tree-ssa-ccp.c (ccp_fold_builtin): Don't call them. + +2004-02-27 Dale Johannesen + + * tree-cfg.c (cleanup_control_expr_graph): Prevent edge + probability from overflowing due to roundoff errors. + +2004-02-27 Jeff Law + + * tree-cfg.c (verify_expr): Do not walk down into types. + Expand checking to verify that unary/binary operators have + gimple operands. + * tree-ssa-ccp.c (ccp_fold_builtin, case BUILT_IN_STRLEN): Do not + create non-gimple code. Similarly for BUILTIN_IN_STRCPY and + BUILT_IN_STRNCPY. + * tree-ssa-phiopt.c (conditional_replacement): Do not create + non-gimple code. + * tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): Likewise. + + * tree-simple.c (is_gimple_min_invariant): Subtraction of a + constant from a constant pointer is a gimple invariant as well. + * tree-ssa-operands.c (get_expr_operands): Handle subtraction + of a constant from a constant pointer too. + + * fold-const.c (fold): Tighten test for optimizing an equality + comparison of the address of two variables. + + * tree-inline.c (setup_one_parameter): Improve test for when we + need to gimplify the initialization statements. + +2004-02-27 Diego Novillo + + PR optimization/14312 + * tree-pretty-print.c (dump_generic_node): Mark tail calls. + * tree-ssa-alias.c (compute_may_aliases): Restore call to + dump_referenced_vars. + (compute_points_to_and_addr_escape): If the address of a + variable V is stored into a non-pointer variable, mark V as + call-clobbered. + * tree-tailcall.c (suitable_for_tail_opt_p): Check for + call-clobbered instead of TREE_ADDRESSABLE. + Ignore memory tags. + (optimize_tail_call): Add newline to dump output. + +2004-02-27 Diego Novillo + + PR optimization/13347 + * tree-sra.c (scalarize_structure_assignment): Use STRIP_NOPS + instead of STRIP_USELESS_TYPE_CONVERSION to remove type casts + from RHS of the assignment. + + * tree-ssa.c (tree_ssa_useless_type_conversion_1): Reformat + and rephrase comments. + * tree.h (STRIP_USELESS_TYPE_CONVERSION): Reformat comment. + +2004-02-26 Zdenek Dvorak + + * tree-cfg.c (tree_redirect_edge_and_branch_1): Allow to redirect + RETURN_EXPR branches. + +2004-02-26 Jeff Law + + * tree-nrv.c (tree_nrv): Only perform NRV optimization when the + return value lives in memory. + + * tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): If an + operand is unsigned, then we can eliminate more ABS expressions + and turned div/mod expression into shift/and expressions. + + * fold-const.c (fold): An equality comparison of the address of + two non-weak variables has known compile-time result. + +2004-02-26 Andrew Pinski + + * tree-ssa-phiopt.c (conditional_replacement): + s/tree_dump_flags/dump_flags/. + + * tree-ssa-phiopt.c (tree_ssa_phiopt): Split into ... + (conditional_replacement): Here. + +2004-02-26 Andrew MacLeod + + * tree-ssa.c (find_replaceable_in_bb): Don't repalce expressions in + volatile statements. + +2004-02-25 Richard Henderson + + PR opt/14288 + * gimplify.c (gimple_push_cleanup): Add VAR argument. Set + TREE_NO_WARNING if in a conditional context. + (gimplify_target_expr): Pass new argument. + * tree-sra.c (lookup_scalar): Copy TREE_NO_WARNING to replacement. + +2004-02-24 Kazu Hirata + + * doc/invoke.texi: Replace -fdump-tree-all-ssa with + -fdump-tree-all. + +2004-02-24 Kazu Hirata + + PR target/14285 + * config/arm/arm.c (arm_compute_func_type): Replace + "current_function_needs_context" with "cfun->static_chain_decl + != NULL". + (arm_compute_initial_elimination_offset): Likewise. + * config/h8300/h8300.c (h8300_emit_stack_adjustment): + Likewise. + * config/sh/sh.c (output_stack_adjust): Likewise. + (sh5_schedule_saves): Likewise. + * config/xtensa/xtensa.c (compute_frame_size): Likewise. + +2004-02-24 Richard Henderson + + * c-simplify.c (c_genericize): s/dump_flags/local_dump_flags/. + * predict.c, tree-alias-ander.c, tree-cfg.c, tree-nrv.c, + tree-optimize.c, tree-pass.h, tree-sra.c, tree-ssa-alias.c, + tree-ssa-ccp.c, tree-ssa-copy.c, tree-ssa-dce.c, tree-ssa-dom.c, + tree-ssa-dse.c, tree-ssa-forwprop.c, tree-ssa-loop.c, + tree-ssa-phiopt.c, tree-ssa-pre.c, tree-ssa.c, tree-tailcall.c: + s/tree_dump_flags/dump_flags/. + +2004-02-24 Richard Henderson + + * predict.c, tree-alias-ander.c, tree-cfg.c, tree-mudflap.c, + tree-nrv.c, tree-optimize.c, tree-pass.h, tree-profile.c, tree-sra.c, + tree-ssa-alias.c, tree-ssa-ccp.c, tree-ssa-copy.c, tree-ssa-dce.c, + tree-ssa-dom.c, tree-ssa-dse.c, tree-ssa-forwprop.c, tree-ssa-loop.c, + tree-ssa-operands.c, tree-ssa-phiopt.c, tree-ssa-pre.c, tree-ssa.c, + tree-tailcall.c: s/tree_dump_file/dump_file/g. + +2004-02-24 Diego Novillo + + * doc/tree-ssa.texi: Fix formatting mark ups. + +2004-02-24 Jeff Law + + * gimple-low.c (remove_useless_vars): Now static. + (pass_remove_useless_vars): New. + * tree-flow.h (remove_useless_vars): Remove prototype. + * tree-nrv.c (struct nrv_data): Remove visited hashtable. + (finalize_nrv_r): Do not descend into types. No need to update + the visited hashtable. + (tree_nrv): No need to allocate/free the visited hashtable. + Clear the used flag on the variable's annotation. + * tree-optimize.c (init_tree_optimizatio_passes): Link in + pass_remove_useless_vars. + * tree-pass.h (pass_remove_useless_vars): Declare. + * tree-ssa.c (rewrite_out_of_ssa): Do not remove useless vars here. + + * Makefile.in (OBJS-common): Add tree-nrv.o. + (tree-nrv.o): Add dependencies. + * timevar.def (TV_TREE_NRV): New timevar. + * tree-nrv.c: New file implementing NRV on generic trees. + * tree-optimize.c (init_tree_optimization_passes): Link in + tree_nrv optimization pass. + * tree-pass.h (tree_nrv): Declare. + * doc/invoke.texi: Add -fdump-tree-nrv documentation. + +2004-02-24 Sebastian Pop + + * tree-flow.h (walk_use_def_chains_fn): Return a boolean. + True for stopping the use-def walk, false otherwise. + * tree-ssa-alias.c (collect_points_to_info_r): Same. + Always return false, and never stopping the def-use walk as before. + * tree-ssa.c (walk_use_def_chains_1): Stop when the result of the + callback function is true. + * doc/tree-ssa.texi: Document the behavior of the callback + function for walk_use_def_chains. + +2004-02-24 Richard Henderson + + * doc/passes.texi: Rewrite. + +2004-02-23 Diego Novillo + + * Makefile.in (TEXI_GCCINT_FILES): Add cfg.texi and tree-ssa.texi + * tree-ssa-alias.c (compute_may_aliases): Update documentation. + * doc/gccint.texi: Add node for Tree SSA documentation. + Include tree-ssa.texi. + * doc/tree-ssa.texi: New file. + +2004-02-23 Dale Johannesen + + * config/rs6000/rs6000.md: Roll in changes from mainline: + (movdf_softfloat64): Add POWER form of nop. + (movsf_hardfloat): Ditto, and accept CTR-to-CTR copy. + (movdf_hardfloat64): Ditto. + +2004-02-23 Jeff Law + + * ggc-page.c (struct page_entry): New field PREV. + (ggc_alloc): Update PREV field appropriately. + (sweep_pages): Likewise. + (ggc_free): Likewise. Use PREV field rather than loop to + improve ggc_free performance. + + * Makefile.in (OBJC-common): Add tree-ssa-copy.o. + (tree-ssa-copy.o): Add dependencies. + * tree-flow.h (propagate_value, replace_exp): Prototype. + (cprop_into_stmt, cprop_into_successor_phis): Likewise. + * tree-ssa-copy.c: New file, most functions copied from tree-ssa-dom.c + (cprop_into_stmt): Handle pointer & reference types better. + * tree-ssa-dom.c (opt_stats_d): Kill uninteresting stats. + (dump_dominator_optimization_stats): Corresponding changes. + (cprop_into_stmt): Moved into tree-ssa-copy.c. + (propagate_value): Likewise. + (cprop_into_phis): Simplify using code fromi tree-ssa-copy.c. + (optimize_stmt): Pass additional argument to cprop_into_stmt. + * tree-ssa-pre.c (generate_expr_as_of_bb): Use replace_exp. + (generate_vops_as_of_bb): Similarly. + +2004-02-21 Jan Hubicka + + * cgraphunit.c (decide_is_function_needed): Nested functions of extern + inline functions don't need to be output. + (expand_function): Re-enable sanity check. + +2004-02-21 Zdenek Dvorak + + * tree-ssa-loop.c (do_while_loop_p): New function. + (copy_loop_headers): Do not peel do-while loops. + +2004-02-21 Jan Hubicka + + * tree-cfg.c (cleanup_control_expr_graph): Update profile. + + * tree-cfg.c (disband_implicit_edges): Set fallthru edges correctly. + + * cfg.c (dump_flow_info): Work on trees too. + + * tree-pretty-print.c (dump_generic_bb_stuff): Do not touch bb + annotations when not allocated. + +2004-02-21 Jeff Law + + * tree-ssa-dom.c (cprop_into_stmt): Look at the type's main variant + to determine if the two operands of a copy have equivalent types. + +2004-02-20 Jeff Law + + * tree-flow-inline.h (may_propagate_copy): Do not perform ABNORMAL_PHI + and DECL_HARD_REGISTER tests on virtual operands. + * tree-flow.h (propagate_copy): Kill prototype. + (propagate_value): New prototype. + * tree-ssa-dom.c (propagate_copy): Now static. + (propagate_value): No longer static. + +2004-02-20 Richard Henderson + + PR middle-end/14218 + * c-simplify.c (mark_labels_r): Move to ... + * gimplify.c (force_labels_r): ... here, and rename. + (gimplify_init_constructor): Invoke it. + * tree-simple.h (force_labels_r): Declare. + +2004-02-20 Richard Henderson + + PR opt/14194 + * tree-ssa-ccp.c (substitute_and_fold): Also mark new vars + if fold_stmt was successful. + +2004-02-20 Diego Novillo + + * doc/invoke.texi: Add documentation for parameters + global-var-threshold and max-aliased-vops. + * params.def (PARAM_GLOBAL_VAR_THRESHOLD): Reformat help message. + (PARAM_MAX_ALIASED_VOPS): Rename from PARAM_MAX_ALIAS_SET_SIZE. + * params.h (MAX_ALIASED_VOPS): Rename from MAX_ALIAS_SET_SIZE. + Update all users. + * tree-ssa-alias.c (struct alias_map_d): Document fields. + Add fields total_alias_vops, grouped_p and may_aliases. + (struct alias_info): Change fields addressable_vars and + pointers to malloc'd arrays. Update all users. + Add fields num_references and total_alias_vops. + (compute_may_aliases): Add more comments. + (init_alias_info): Initialize new fields in struct alias_info. + (delete_alias_info): Corresponding changes. + (compute_points_to_and_addr_escape): Count references to + potentially aliased variables and pointer dereferences. + (compute_flow_insensitive_aliasing): Remove old grouping + heuristic. + Count the number of virtual operands induced by all the alias + sets created and call group_aliases if the number exceeds the + threshold set by --param max-aliased-vops. + (total_alias_vops_cmp): New. + (group_aliases_into): New. + (group_aliases): New. + * tree-ssa-operands.c (get_expr_operands): Change dump file + message when no flow-sensitive alias information is available. + (add_stmt_operand): Reformat comment. + * tree-ssa.c (init_tree_ssa): Don't call bitmap_clear. + + * tree-simple.c (get_base_decl): Fix typo in comment. + + * tree-pretty-print.c (print_call_name): Handle matrices of + function pointers. + +2004-02-20 Zdenek Dvorak + + * Makefile.in (tree-ssa-loop.o): Add tree-inline.h dependency. + * basic-block.h (struct reorder_block_def): Moved from cfglayout.h. + (alloc_rbi_pool, initialize_bb_rbi, free_rbi_pool): New. + * bb-reorder.c (copy_bb): Use cfghooks for bb duplication. + * cfg.c (rbi_pool): New variable. + (alloc_rbi_pool, free_rbi_pool, initialize_bb_rbi): New functions. + * cfghooks.c (can_duplicate_block_p, duplicate_block): New functions. + * cfghooks.h (struct cfg_hooks): Add can_duplicate_block_p and + duplicate_block hooks. + (can_duplicate_block_p, duplicate_block): Declare. + * cfglayout.c (cfg_layout_pool, cfg_layout_initialize_rbi): Removed. + (fixup_reorder_chain): Use initialize_bb_rbi. + (cfg_layout_can_duplicate_bb_p, cfg_layout_duplicate_bb): Hookized. + (cfg_layout_initialize): Use cfg.c rbi pool manipulation functions. + (can_copy_bbs_p, copy_bbs): Use cfghooks for bb duplication. + * cfglayout.h (typedef struct reorder_block_def): Moved to + basic_block.h. + (cfg_layout_can_duplicate_bb_p, cfg_layout_duplicate_bb): Declaration + removed. + * cfgrtl.c (cfg_layout_create_basic_block): Use initialize_bb_rbi. + (rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Fill in can_duplicate_block_p + and duplicate_block fields. + * common.opt (ftree-ch): Add. + * flags.h (flag_tree_ch): Declare. + * jump.c (next_nonnote_insn_in_loop, duplicate_loop_exit_test, + copy_loop_headers): Removed. + * loop-unswitch.c (unswitch_loop): Use cfghooks for bb duplication. + * opts.c (decode_options): Enable flag_tree_ch at -O1. + (common_handle_option): Handle -ftree_ch. + * rtl.h (copy_loop_headers): Declaration removed. + * timevar.def (TV_TREE_CH): New. + * toplev.c (flag_tree_ch): New. + (rest_of_compilation): Do not call copy_loop_headers. + * tracer.c (tail_duplicate): Use cfghooks for bb duplication. + * tree-cfg.c (build_tree_cfg): Call alloc_rbi_pool. + (create_bb): Call initialize_bb_rbi. + (delete_tree_cfg): Call free_rbi_pool. + (tree_duplicate_bb): Hookize. + (tree_can_duplicate_bb_p): New. + (tree_cfg_hooks): Fill in can_duplicate_block_p and duplicate_block + fields. + * tree-flow.h (tree_duplicate_bb): Declaration removed. + * tree-optimize.c (init_tree_optimization_passes): Add pass_ch. + * tree-pass.h (pass_ch): Declare. + * tree-ssa-loop.c: Include tree-inline.h. + (call_expr_p, should_duplicate_loop_header_p, mark_defs_for_rewrite, + duplicate_blocks, copy_loop_headers, gate_ch): New functions. + (pass_ch): New. + * doc/invoke.texi (-fdump-tree-ch, -ftree-ch): Document. + +2004-02-19 David Edelsohn + + * config/rs6000/aix.h (MFWRAP_SPEC): Define. + (MFLIB_SPEC): Define. + +2004-02-19 Jeff Law + + * tree-ssa-phiopt.c (tree_ssa_phiopt): TRUTH_NOT_EXPR is valid + gimple code. + +2004-02-19 Steven Bosscher + + * tree-cfg.c (cleanup_dead_labels): New function to remove + redundant labels. + + Remove the RTL inliner. + * calls.c (try_to_integrate): Remove. + (expand_call): Do not try to expand calls inline. + * dbxout.c (dbxout_symbol_location): Don't mention integrate.c + in comments. + * expmed.c (extract_fixed_bit_field): Always propagate the + target for the shift if it is a REG. + * expr.c (emit_move_insn_1): Don't generate inline warnings. + (expand_expr_real_1): Don't look at inline_function_decl. + Don't output inlined functions here. + * expr.h (expand_inline_function): Remove prototype. + * emit-rtl.c (copy_most_rtx): Don't copy the integrated flag. + Copy the new return_val flag. + * final.c (final): Don't look at RTX_INTEGRATED_P. + * cfgrtl.c (create_basic_block_structure): Likewise. + * haifa-sched.c (priority): Likewise. + (restore_line_notes): Likewise. + * function.c (inline_function_decl): Remove. + (put_var_into_stack): Don't use it. + (fix_lexical_addr): Likewise. + * function.c (inline_function_decl): Remove extern declaration. + * genattrtab.c (ATTR_PERMANENT_P): Use the return_val flag + instead of the integrated flag. + * integrate.c (INTEGRATE_THRESHOLD): Remove. + (setup_initial_hard_reg_value_integration): Likewise. + (initialize_for_inline): Likewise. + (note_modified_parmregs): Likewise. + (integrate_parm_decls): Likewise. + (process_reg_param): Likewise. + (save_parm_insns): Likewise. + (copy_insn_list): Likewise. + (copy_insn_notes): Likewise. + (compare_blocks): Likewise. + (find_block): Likewise. + (inlining): Likewise. + (function_cannot_inline_p): Likewise. + (parmdecl_map): Likewise. + (in_nonparam_insns): Likewise. + (save_for_inline): Likewise. + (FIXED_BASE_PLUS): Likewise. + (expand_inline_function): Likewise. + (copy_rtx_and_substitute): Don't look at map->integrating, + map->inline_target, and inlining, since we are never copying + for integrating. + Don't abort on RTX_INTEGRATED_P. + (old_fun): Remove. + (output_inline_function): Remove. + * integrate.h (struct inline_map): Remove fields integrating, + block_map, leaf_reg_map, inline_target, and local_return_label. + * print-rtl.c (print_rtx): Don't print the integrated flag. + Print the return_val flag. + * rtl.h (struct rtx_def): Replace the integrated flag with the + return_val flag. + (RTX_INTEGRATED_P): Remove. + (notice_rtl_inlining_of_deferred_constant): Remove prototype. + * stmt.c (force_label_rtx): Don't look at inline_function_decl. + * toplev.c (rest_of_handle_inlining): Remove. + (rest_of_compilation): Don't call it, and never jump to exit. + Call convert_from_eh_region_ranges. + (wrapup_global_declarations): Don't output nested inlined functions. + * tree.h (function_cannot_inline_p): Remove prototype. + (save_for_inline): Ditto. + (output_inline_function): Ditto. + * unroll.c (unroll_loop): Don't clear map->inline_target. + * varasm.c (notice_rtl_inlining_of_deferred_constant): Remove. + + * system.h: Poison INTEGRATE_THRESHOLD. + * config/avr/avr.h: Remove define. + * config/ip2k/ip2k.h: Likewise. + + * unwind-sjlj.c (uw_install_context): Make a proper static inline + function. + + * doc/rtl.texi: Remove references to the integrated flag. + * doc/tm.texi: Remove documentation of INTEGRATE_THRESHOLD. + +2004-02-17 Andrew Macleod + + * tree-ssa-live.c (coalesce_tpa_members): Don't coalesce partitions + which are not in the same TPA group. + * tree-ssa.c (rewrite_out_of_ssa): Coalesce via list first. + +2004-02-17 Brian Booth + + * tree-ssa-ccp.c (substitute_and_fold): Update stmt after + calling fold_stmt. + +2004-02-16 Andrew Pinski + + * config/rs6000/rs6000.c (output_function_profiler): Check + cfun->static_chain_decl instead of current_function_needs_context. + +2004-02-16 Jeff Law + + * tree-ssa.dse.c (dse_optimize_stmt): Dump info when we delete + stores. + + * tree-ssa-dse.c: Update comments. + + * Makefile.in (OBJS-common): Add tree-ssa-dse.o + (tree-ssa-dse.o): Add dependencies. + * common.opt (ftree-dse): New option. + * flags.h (flag_tree_dse): New. + (flag_tree_dom): Fix comments. + * opts.c (decode_options): Turn on flag_tree_dse. + (common_handle_option): Handle OPT_ftree_dse. + * timevar.def (TV_TREE_PHIOPT): Update text. + (TV_TREE_DSE): New timevar. + * toplev.c (flag_tree_dse): New. + (flag_tree_dom): Fix comments. + (lang_independent_options): Add -ftree-dse. + * tree-dfa.c (redirect_immediate_use): New function. + (redirect_immediate_uses): New function. + * tree-flow.h (stmt_ann_d): Add UID field. + (redirect_immediate_uses): Declare. + * tree-optimize.c (init_tree_optimization_passes): Link in DSE pass. + * tree-pass.h (pass_dse): Declare. + * tree-ssa-dse.c: New file implementing DSE. + * doc/invoke.texi: Document new option. + +2004-02-16 Richard Henderson + + * tree-nested.c: New file. + * Makefile.in (OBJS-common, GTFILES, tree-nested.o): Add it. + * builtin-types.def (BT_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR_PTR): New. + * builtins.c (expand_builtin_nonlocal_goto): New. + (expand_builtin_apply): Fix prepare_call_address args. + (round_trampoline_addr): Move from function.c. + (expand_builtin_init_trampoline): New. + (expand_builtin_adjust_trampoline): New. + (expand_builtin): Invoke them. + (build_function_call_expr): Add CALL_EXPR chain operand. + * builtins.def (BUILT_IN_INIT_TRAMPOLINE, + BUILT_IN_ADJUST_TRAMPOLINE, BUILT_IN_NONLOCAL_GOTO): New. + * c-decl.c (finish_function): Call lower_nested_functions. + (c_expand_decl): Don't declare_nonlocal_label. + * calls.c (prepare_call_address): Replace fndecl arg with a + precomputed static chain value. + (expand_call): Precompute the static chain value. Use + update_nonlocal_goto_save_area. + * cgraph.c (cgraph_mark_reachable_node): Don't force nested + functions to be reachable. + (cgraph_clone_node): Don't abort cloning functions containing + nested functions. + * cgraphunit.c (cgraph_assemble_pending_functions): Don't do + anything special for nested functions. + (cgraph_mark_functions_to_output): Likewise. + (cgraph_estimate_growth, cgraph_clone_inlined_nodes): Likewise. + (cgraph_optimize): Likewise. + (cgraph_finalize_function): Don't zap DECL_SAVED_INSNS. + (cgraph_expand_function): Allow functions to not be emitted. + * defaults.h (TRAMPOLINE_ALIGNMENT): Move from function.c. + * dwarf2out.c (gen_subprogram_die): Generate DW_AT_static_link. + * emit-rtl.c (maybe_set_first_label_num): New. + * explow.c (update_nonlocal_goto_save_area): New. + (allocate_dynamic_stack_space): Use it. + * expr.c (expand_expr_real_1) : Don't force_label_rtx. + : Ignore the possibility of non-local labels. + : Don't do trampoline_address. + * expr.h (lookup_static_chain): Remove. + (prepare_call_address): Update 2nd arg. + (update_nonlocal_goto_save_area): Declare. + * final.c (profile_function): Update static chain test. + * function.c (TRAMPOLINE_ALIGNMENT): Move to defaults.h. + (trampolines_created): Move to varasm.c. + (free_after_compilation): Update for removed fields. + (allocate_struct_function): Likewise. + (delete_handlers, lookup_static_chain): Remove. + (fix_lexical_addr): Don't consider non-local variable refs. + (trampoline_address): Remove. + (round_trampoline_addr): Move to builtins.c. + (adjust_trampoline_addr): Remove. + (expand_function_start): Update for changes to static chain + and nonlocal goto handling. + (initial_trampoline): Move to varasm.c. + (expand_function_end): Don't build trampolines or kill + unreferenced nonlocal goto labels. + * function.h (struct function): Remove x_nonlocal_labels, + x_nonlocal_goto_handler_slots, x_nonlocal_goto_stack_level, + x_context_display, x_trampoline_list, needs_context. + Add static_chain_decl, nonlocal_goto_save_area. + * gimple-low.c (record_vars): Don't record functions. + * gimplify.c (declare_tmp_vars): Export. + (create_artificial_label): Set type. + (gimplify_expr): Don't consider nonlocal gotos. + * integrate.c (expand_inline_function): Kill lookup_static_chain ref. + * jump.c (any_uncondjump_p): Reject nonlocal goto. + * rtl.h (maybe_set_first_label_num): Declare. + * stmt.c (label_rtx): Set LABEL_PRESERVE_P appropriately. + (expand_label): Handle DECL_NONLOCAL and FORCED_LABEL. + (declare_nonlocal_label): Remove. + (expand_goto): Don't handle nonlocal gotos. + (expand_nl_handler_label): Remove. + (expand_nl_goto_receivers): Remove. + (expand_end_bindings): Don't expand_nl_goto_receivers. Use + update_nonlocal_goto_save_area. + * tree-cfg.c (make_edges): Handle abnormal edges out of block + falling through to EXIT. + (make_ctrl_stmt_edges): Don't check GOTO_EXPR for nonlocal goto. + Handle computed goto with no destinations. + (tree_can_merge_blocks_p): Don't merge blocks with nonlocal labels. + (remove_useless_stmts_label, stmt_starts_bb_p): Likewise. + (tree_forwarder_block_p): Likewise. + (nonlocal_goto_p): Remove. + (tree_verify_flow_info): Update to match. + * tree-dump.c (dump_files): Add tree-nested. + * tree-flow.h (nonlocal_goto_p): Remove. + * tree-inline.c (setup_one_parameter): Split out from ... + (initialize_inlined_parameters): ... here. Handle static chain. + (inline_forbidden_p_1): Update nonlocal goto check. + (expand_call_inline): Disable mysterious cgraph abort. + * tree-optimize.c (tree_rest_of_compilation): Save DECL_SAVED_INSNS. + * tree-pretty-print.c (dump_generic_node): Print static chain + and nonlocal label. + * tree-simple.h (declare_tmp_vars): Declare. + (lower_nested_functions): Declare. + * tree-ssa-dom.c (propagate_value): Avoid sharing problems. + * tree-ssa-operands.c (get_expr_operands): Walk static chain + field of call_expr. + * tree.def (CALL_EXPR): Add static chain operand. + * tree.h (NONLOCAL_LABEL): Remove. + (TDI_nested): New. + * varasm.c (TRAMPOLINE_ALIGNMENT): Remove. + (initial_trampoline): Move from function.c. + (assemble_trampoline_template): Set and return it. + (trampolines_created): Move from function.c. + +2004-02-16 Steven Bosscher + + * tree-flow.h (cleanup_control_expr_graph): Don't declare here. + * tree-cfg.c (cleanup_control_expr_graph): Make static. + (find_edge_taken_cond_expr): Return an edge if the true and false + edges of a branch lead to the same basic block. + +2004-02-13 Diego Novillo + + * tree-phinodes.c (resize_phi_node): Do not use ggc_realloc to + allocate a new PHI node. + +2004-02-12 Diego Novillo + + * tree-flow.h (kill_redundant_phi_nodes): Remove declaration. + * tree-optimize.c (init_tree_optimization_passes): Add + pass_redundant_phi after DOM and CCP. + (execute_todo): Do not call kill_redundant_phi_nodes. + * tree-pass.h (TODO_redundant_phi): Remove. + Update all users. + Adjust values for all the other TODO_* entries. + (pass_redundant_phi): Declare. + * tree-ssa.c (replace_immediate_uses): Call mark_new_vars_to_rename + if a pointer was replaced. + (kill_redundant_phi_nodes): Make static. + (pass_redundant_phi): Define. + +2004-02-12 Dale Johannesen + + * Makefile.in (OBJS-common): Add rtl-profile.o, tree-profile.o. + (profile.o): Add tree-flow.h dependency. + (rtl-profile.o): New rule. + (tree-profile.o): New rule. + (GTFILES): Add tree-profile.c, rtl-profile.c. + * basic-block.h (flow_call_edges_add): Remove. + * cfganal.c (need_fake_edge_p): Move to cfgrtl.c. + (flow_call_edges_add): Move to cfgrtl.c. + * cfghooks.c: (block_ends_with_call_p): New. + (block_ends_with_condjump_p): New. + (flow_call_edges_add): New. + * cfghooks.h: (struct cfg_hooks): add block_ends_with_call_p, + block_ends_with_condjump_p, flow_call_edges_add. + (block_ends_with_call_p): New declaration. + (block_ends_with_condjump_p): New declaration. + (flow_call_edges_add): New declaration. + * cfgrtl.c (rtl_block_ends_with_call_p): New. + (rtl_block_ends_with_condjump_p): New. + (need_fake_edge_p): Moved from cfganal.c. + (rtl_flow_call_edges_add): Moved from cfganal.c (flow_call_edges_add). + (rtl_cfg_hooks): Add rtl_block_ends_with_call_p, + rtl_block_ends_with_condjump_p, rtl_flow_call_edges_add. + (cfg_layout_rtl_cfg_hooks): Ditto. + * common.opt (ftree-based-profiling): New. + * coverage.c (tree_ctr_tables): New. + (coverage_counter_alloc): Use it. + (build_ctr_info_value): Ditto. + (coverage_counter_ref): Ditto. Rename to rtl_coverage_counter_ref. + (tree_coverage_counter_ref): New. + * coverage.h (coverage_counter_ref): Remove declaration. + (rtl_coverage_counter_ref): New declaration. + (tree_coverage_counter_ref): New declaration. + * opts.c (OPT_ftree_based_profiling): New. + * profile.c: Include cfghooks.h, tree-flow.h. + (profile_hooks): New. + (profile_dump_file): New. + (instrument_edges): Use hooks instead of RTL-specific code. + (instrument_values): Ditto. + (get_exec_counts): Ditto. + (compute_branch_probabilities): Ditto. + (compute_value_histograms): Ditto. + (branch_prob): Ditto. + (find_spanning_tree): Ditto. + (end_branch_prob): Ditto. + (gen_edge_profiler): Move to rtl-profile.c (rtl_gen_edge_profiler). + (gen_interval_profiler): Ditto (rtl_gen_interval_profiler). + (gen_pow2_profiler): Ditto (rtl_gen_pow2_profiler). + (gen_one_value_profiler): Ditto (rtl_gen_one_value_profiler). + (tree_register_profile_hooks): New. + (rtl_register_profile_hooks): New. + * rtl-profile.c: New file. + * rtl.h (init_branch_prob): Move declaration to value-prof.h. + (end_branch_prob): Ditto. + (branch_prob): Ditto. + * toplev.c (flag_tree_based_profiling): New. + (f_options): Add -ftree-based-profiling. + (compile_file): Register rtl-based CFG and profiling hooks. + (rest_of_compilation): Do rtl-based profiling only when + !flag_tree_based_profiling. Register rtl-based profiling hooks. + (process_options): Sorry for -ftree-based-profiling plus + -ftest-coverage or -fprofile-values. + * toplev.h (flag_tree_based_profiling): New. + * tree-cfg.c (tree_block_ends_with_call_p): New. + (tree_block_ends_with_condjump_p): New. + (need_fake_edge_p): New. + (tree_flow_call_edges_add): New (largely from flow_call_edges_add + in cfganal.c). + (tree_cfg_hooks): Add tree_block_ends_with_call_p, + tree_block_ends_with_condjump_p, tree_flow_call_edges_add. + * tree-optimize.c (init_tree_optimization_passes): + Add pass_tree_profile. + * tree-pass.h: Ditto. + * tree-profile.c: New file. + * value-prof.c (value_prof_hooks): New. + (find_values_to_profile): Rename to rtl_find_values_to_profile. + Move rtl-specific bits in from branch_prob. + (value_profile_transformations): Rename to + rtl_value_profile_transformations. + (struct value_prof_hooks): New. + (rtl_value_prof_hooks): New. + (rtl_register_value_prof_hooks): New. + (tree_find_values_to_profile): New stub. + (tree_value_profile_transformations): New stub. + (tree_value_prof_hooks): New stub. + (tree_register_value_prof_hooks): New stub. + (find_values_to_profile): New. + (value_profile_transformations): New. + * value-prof.h: Add multiple inclusion guard. + (struct histogram_value): Change rtx fields to void *. + (rtl_register_value_prof_hooks): New declaration. + (tree_register_value_prof_hooks): New declaration. + (find_values_to_profile): New declaration. + (free_profiled_values): New declaration. + (value_profile_transformations): New declaration. + (struct profile_hooks): New declaration. + (init_branch_prob): Declaration moved from rtl.h. + (branch_prob): Declaration moved from rtl.h. + (end_branch_prob): Declaration mooved from rtl.h. + (tree_register_profile_hooks): New declaration. + (rtl_register_profile_hooks): New declaration. + (tree_profile_hooks): New declaration. + (rtl_profile_hooks): New declaration. + * doc/invoke.texi: Document -ftree-based-profiling. + +2004-02-12 Jeff Law + + * domwalk.c (walk_dominator_tree): Move statement walking from + clients into here. Walk statements in forward or backward order + as requested by the client. Walk either the dominator tree or + the post-dominator tree as requested by the client. + * domwalk.h (dom_walk_data): Add two fields to control direction of + statement walk and dominator vs post-dominator tree walk. Add + BSI argument to the per-statement callbacks. + * tree-ssa-dom.c (optimize_stmt): Update prototype so that it can + be directly used as a callback for the dominator tree walker. + Update stmts_to_rescan here. + (tree_ssa_dominator_optimize): Initialize new fields in the dominator + walker structure. Use optimize_stmt instead of dom_opt_walk_stmts + for statement callback. + (dom_opt_walk_stmts): Kill. No longer used. + * tree-ssa.c (mark_def_sites): Update prototype so that it can be + called as the per-statement callback. No longer walk statements here. + (mark_def_sites_initialize_block): New. + (rewrite_stmt): Update prototype so that it can be called as the + per-statement callback. + (rewrite_walk_stmts): Kill. No longer used. + (rewrite_into_ssa): Initialize new fields in the dominator walker + structure. Use rewrite_stmt instead of rewrite_walk_stmts. Add + mark_def_sites_initialize_block callback. + +2004-02-12 Steven Bosscher + + * doc/cfg.texi: New file. + * doc/ggcint.texi: Include it. Add a new chapter. + +2004-02-11 Jeff Law + + * Makefile.in (OBJS-common): Add tree-ssa-forwprop.o + (tree-ssa-forwprop.o): Add dependencies. + * timevar.def (TV_TREE_FORWPROP): New timevar. + * tree-optimize.c (init_tree_optimization_passes): Link in + the forward propagation pass. + * tree-pass.h (pass_forwprop): Declare. + * tree-ssa-forwprop.c: New file with forward propagation pass. + * doc/invoke.texi: Document dump for forward propagation pass. + +2004-02-11 Andrew MacLeod + + * tree-ssa.c (rewrite_out_of_ssa): Don't use coalesce list until new + bug resolved. + +2004-02-11 Andrew MacLeod + + * tree-ssa-live.c (compare_pairs): New. Coalesce list cost function. + (sort_coalesce_list): Use qsort() to sort list by cost. + (coalesce_tpa_members): Use correct partition representatives. Add more + debug information. Allow coalesce by list, root_var, or both. + (tpa_dump): Show partition index. + * tree-ssa-live.h (SSANORM_COALESCE_PARTITIONS): New flag. + (SSANORM_USE_COALESCE_LIST): New flag. + * tree-ssa.c (create_temp): Don't mark as used when created. + (coalesce_ssa_name): Create coalesce list if requested. Add more + debug output. + (assign_vars): Add additional debug info. + (remove_ssa_form): Perform TER after assign_vars(). + (rewrite_vars_out_of_ssa): Pass coalesce partitions flag to + remove_ssa_form. + (rewrite_out_of_ssa): Add coalesce list flag to remove_ssa_form call. + +2004-02-10 Jeff Law + + * Makefile.in (OBJS-common): Add tree-ssa-phiopt.o + (tree-ssa-phiopt.o): Add dependencies. + * timevar.def (TV_TREE_PHIOPT): New timevar. + * tree-cfg.c (extract_true_false_edges_from_block): Moved here from + tree-ssa-dom.c. + (tree_verify_flow_info): Use extract_true_false_edges_from_block. + * tree-flow.h (extract_true_false_edges_from_block): Declare. + * tree-ssa-dom.c (extract_true_false_edges_from_block): Moved into + tree-cfg.c. + (get_eq_expr_value): Improve type check. + * tree-optimize.c (init_tree_optimization_passes): Link in + phiopt pass. + * tree-pass.h (pass_phiopt): Declare. + * tree-ssa-phiopt.c: New file with PHI node optimization pass. + * doc/invoke.texi: Document dump for PHI node optimization. + +2004-02-10 Richard Henderson + + * tree-sra.c (lookup_scalar): Handle unnamed fields. + +2004-02-10 Diego Novillo + + * Makefile.in (OBJS-common): Add tree-ssa-alias.o. + (tree-ssa-alias.o): New rule. + (tree-ssa-operands.o): Add dependency on $(TIMEVAR_H) and tree-pass.h + (gt-tree-dfa.h): Remove. + * timevar.def (TV_TREE_OPS): Rename from unused entry TV_TREE_DFA. + * tree-ssa-alias.c: New file. + * tree-dfa.c (struct alias_stats_d, alias_stats, dump_alias_stats, + may_alias_p, add_may_alias, global_var, aliases_computed_p, + compute_may_aliases): Move to tree-ssa-alias.c. + (struct walk_state): Remove fields 'is_asm_expr' and 'num_calls'. + Update all users. + (compute_alias_sets, create_memory_tags, may_access_global_mem_p, + get_memory_tag_for, promote_call_clobbered_vars, + find_addressable_vars): Remove. + (call_clobbered_vars): Move to tree-ssa-alias.c and convert to + bitmap. + (find_referenced_vars): Move logic to create .GLOBAL_VAR to + tree-ssa-alias.c. + (create_ssa_name_ann): New. + (dump_variable): Rearrange. + (dump_dfa_stats): Do not show the number of call clobbered + variables. + (find_vars_r): Do not try to determine if an assignment my access + global memory. + (add_referenced_var): Remove hacks to establish global memory + dependencies. + If the variable needs to live in memory mark it call-clobbered. + * tree-flow-inline.h (ssa_name_ann): New. + (get_ssa_name_ann): New. + (set_may_alias_global_mem): Remove. + (may_alias_global_mem_p): Remove. + (set_may_point_to_global_mem): Remove. + (may_point_to_global_mem_p): Remove. + (is_call_clobbered): New + (mark_call_clobbered): New + (mark_non_addressable): New + * tree-flow.h (enum tree_ann_type): Add SSA_NAME_ANN. + (enum mem_tag_kind): Declare. + (struct var_ann_d): Remove fields 'is_call_clobbered', + 'may_alias_global_mem' and 'may_point_to_global_mem'. + Replace bitfield 'mem_tag' with enum bitfield 'mem_tag_kind'. + Rename field 'mem_tag' to 'type_mem_tag'. + (struct stmt_ann_d): Change type of field 'addresses_taken' to a + bitmap. Update all users. + (struct ssa_name_ann_d): Declare. + (union tree_ann_d): Add field 'ssa_name'. + (ssa_name_ann_t): New type. + (struct bb_ann_d): Add field 'has_escape_site'. + (num_call_clobbered_vars): Remove. + (call_clobbered_var): Remove. + (call_clobbered_vars): Change to bitmap. + (dump_points_to_info): Declare. + (debug_points_to_info): Declare. + (walk_use_def_chains_fn): New type. + (walk_use_def_chains): Declare. + (is_call_clobbered): Declare. + (mark_call_clobbered): Declare. + * tree-simple.c (needs_to_live_in_memory): Move to tree.c. + (is_gimple_non_addressable): Update comment. + (is_gimple_call_clobbered): Remove. + (get_call_expr_in): New. + (get_base_var): Rename from get_base_symbol. Update all callers. + Don't strip SSA_NAME wrappers. + (get_base_decl): New. + (get_base_address): New. + * tree-simple.h (is_gimple_call_clobbered): Remove. + (needs_to_live_in_memory): Remove. + (get_base_decl): Declare. + (get_base_var): Declare. + (get_base_address): Declare. + * tree-ssa-dce.c (need_to_preserve_store): Reduce to calling + needs_to_live_in_memory. + * tree-ssa-operands.c: Include tree-pass.h and timevar.h + (get_stmt_operands): Push/pop TV_TREE_OPS time var. + Call mark_call_clobbered for asms that store to memory. + (get_expr_operands): When adding operands for INDIRECT_REF + expressions, use flow-sensitive aliasing, if available. + Assume that malloc-like function calls won't clobber. + (add_call_clobber_ops): + (add_call_read_ops): + * tree-ssa.c (rewrite_into_ssa): If any variable in vars_to_rename + is a pointer, invalidate all name memory tags. + (create_temp): Call is_call_clobbered and mark_call_clobbered. + (walk_use_def_chains_1): New. + (walk_use_def_chains): New. + + * tree.c (needs_to_live_in_memory): New. + * tree.h (DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL): Define. + (struct tree_decl): Add bitfield 'needs_to_live_in_memory'. + Update unused bits comment. + (needs_to_live_in_memory): Declare. + + * tree-simple.h (get_call_expr_in): Declare. + * tree-sra.c (scalarize_stmt): Call get_call_expr_in when handling + function calls. + * tree-ssa-ccp.c (likely_value): Likewise. + + * params.def (PARAM_MAX_CLOBBERED_VARS_GLOBAL_VAR): Remove. + (PARAM_MAX_CALLS_GLOBAL_VAR): Remove. + (PARAM_GLOBAL_VAR_THRESHOLD): Define. + (PARAM_MAX_ALIAS_SET_SIZE): Define. + Update all users. + * params.h (MAX_CALLS_FOR_GLOBAL_VAR): Remove. + (MAX_CLOBBERED_VARS_FOR_GLOBAL_VAR): Remove. + (GLOBAL_VAR_THRESHOLD): Define. + (MAX_ALIAS_SET_SIZE): Define. + +2004-02-09 Richard Henderson + + * langhooks.h (lang_hooks_for_functions): Add missing_noreturn_ok_p. + * langhooks-def.h, c-lang.c, objc/objc-lang.c + (LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P): New. + * c-objc-common.c (c_missing_noreturn_ok_p): Return bool. + (c_objc_common_init): Don't set lang_missing_noreturn_ok_p. + * c-tree.h (c_missing_noreturn_ok_p): Update decl. + * flow.c (lang_missing_noreturn_ok_p): Remove. + + * flow.c (check_function_return_warnings): Move to tree-cfg.c. + * toplev.c (rest_of_compilation): Don't call it. + * tree-cfg.c (execute_warn_function_return): Move from flow.c, + rename, update for tree vs rtl. + (pass_warn_function_return): New. + * tree-pass.h (pass_warn_function_return): Declare it. + * tree-optimize.c (init_tree_optimization_passes): Run it. + + * function.h (struct function): Remove x_clobber_return_insn. + * function.c (free_after_compilation): Don't set it. + (expand_function_end): Likewise. + +2004-02-09 Richard Henderson + + Revert: + 2004-02-06 Richard Henderson + * tree-ssa-dom.c (record_equivalences_from_phis): Use + record_const_or_copy. + (record_equivalences_from_stmt): Likewise. Replace + block_avail_exprs_p and block_nonzero_vars_p args with bd. + +2004-02-09 Jeff Law + + * tree-ssa-dom.c (get_eq_expr_value): Improve handling of boolean + conditions. + + * domwalk.c (walk_dominator_tree): Completely lose PARENT argument. + Callers updated. No longer pass PARENT to callbacks. + * domwalk.h (struct dom_walk_data): Corresponding changes. + * tree-ssa-dom.c: Likewise. + * tree-ssa.c: Likewise. + + * domwalk.c (walk_dominator_tree): Change last argument to be the + parent block in the dominator tree rather than the last statement + in the parent block in the dominator tree. Similarly in all the + callbacks. + * domwalk.h (struct dom_walk_data): Update callback prototypes. + * tree-ssa-dom.c: Corresponding changes. + * tree-ssa.c: Likewise. + + * tree-ssa-dom.c (redirect_edges_and_update_ssa_graph): Break out + of tree_ssa_dominator_optimize. If the out-of-ssa pass creates + new variables, then invalidate some requested jump threads. + +2004-02-08 Richard Henderson + + * flow.c (regno_uninitialized): Remove. + * output.h (regno_uninitialized): Remove. + * function.c (setjmp_vars_warning): Rename from + uninitialized_vars_warning, remove uninitialized vars warning. + * toplev.c (rest_of_handle_life): Update to match. + * tree.h (setjmp_vars_warning): Likewise. + + * tree-sra.c (lookup_scalar): Set DECL_NAME to something descriptive. + + * tree-ssa.c (warn_uninit): New. + (warn_uninitialized_var, warn_uninitialized_phi): New. + (execute_early_warn_uninitialized): New. + (execute_late_warn_uninitialized): New. + (gate_warn_uninitialized): New. + (pass_early_warn_uninitialized): New. + (pass_late_warn_uninitialized): New. + * tree-pass.h (pass_early_warn_uninitialized): New. + (pass_late_warn_uninitialized): New. + * tree-optimize.c (init_tree_optimization_passes): Add them. + +2004-02-08 Richard Henderson + + * cppexp.c (append_digit): Rearrange unsignedp/overflow setting. + (eval_token, num_binary_op, num_part_mul, num_div_op): Likewise. + * ra-rewrite.c (rewrite_program2): Zero info. + * reload.c (decompose): Zero val. + * tree-ssa-ccp.c (visit_phi_node): Zero phi_val.const_val. + +2004-02-07 Jan Hubicka + + * tree-inline.c (save_body): Clone the parm decl correctly. + + * cgraph.c: Add introductionary comment. + (cgraph_remove_node): Release DECL_SAVED_INSNS too. + * cgraphunit.c: Likewise. + (cgraph_finalize_function): Release DECL_SAVED_INSNS of external function. + (decl_expand_function): Release DECL_SAVED_INSNS/body/tree. + (cgraph_remove_unreachable_nodes): Likewise; guard cgraph verification. + +2004-02-06 Richard Henderson + + * common.opt (fdisable-tree-ssa): Remove. + * flags.h (flag_disable_tree_ssa): Remove. + * toplev.c (flag_disable_tree_ssa): Remove. + (f_options): Don't set it. + * opts.c (common_handle_option): Likewise. + * doc/invoke.texi (fdisable-tree-ssa): Remove. + +2004-02-06 Richard Henderson + + * tree-ssa-dom.c (record_equivalences_from_phis): Use + record_const_or_copy. + (record_equivalences_from_stmt): Likewise. Replace + block_avail_exprs_p and block_nonzero_vars_p args with bd. + +2004-02-06 Andrew Pinski + + PR middle-end/13127 + * tree-inline.c (declare_return_variable): Set the no warning bit + on the variable created for the return value. + +2004-02-06 Richard Henderson + + * tree-pretty-print.c (dump_generic_node): Render NON_LVALUE_EXPR. + + * tree-ssa-dom.c (local_fold): New. + (thread_across_edge, simplify_rhs_and_lookup_avail_expr, + find_equivalent_equality_comparison): Use it. + +2004-02-06 Andrew Pinski + + PR c/13863 + * c-common.c (c_decl_uninit_1): Remove. + (c_decl_uninit): Remove. + * c-common.h (c_decl_uninit): Remove prototype. + * c-lang.c (LANG_HOOKS_DECL_UNINIT): Delete. + * objc/objc-lang.c (LANG_HOOKS_DECL_UNINIT): Delete. + * c-simplify.c (gimplify_decl_stmt): Set TREE_NO_WARNING + on the decl where the initial is itself. + * function.c (uninitialized_vars_warning): Remove old comment + and check for DECL_INITIAL, replace with a check of TREE_NO_WARNING + and do not call the langhook. + * langhooks-def.h (LANG_HOOKS_DECL_UNINIT): Remove. + (LANG_HOOKS_INITIALIZER): Remove usage of LANG_HOOKS_DECL_UNINIT. + * langhooks.c (lhd_decl_uninit): Remove. + * langhooks.h (lhd_decl_uninit): Remove prototype. + +2004-02-05 Richard Henderson + + * tree-ssa-dom.c (record_const_or_copy_1): New. + (record_const_or_copy): New. + (thread_across_edge): Use it. + (dom_opt_finalize_block): Likewise. Tidy. + (record_equality): Split out from ... + (record_equivalences_from_incoming_edge): ... here. + +2004-02-05 Richard Henderson + + * tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): Allow + mixing PLUS and MINUS when folding operations. + +2004-02-05 Andrew Macleod + + * tree-pretty-print.c (dump_bb_header): Allow TDF_SLIM printing. + (dump_bb_end): Allow TDF_SLIM printing. + (dump_generic_bb_buff): Add flags parameter to dump_bb_end. + +2004-02-05 Jan Hubicka + + * alias.c (find_base_term, get_addr): Do not dereference NULL + pointer when all VALUE's locations has been invalidated. + (rtx_equal_for_memref_p): Simplify checking of VALUEs. + +2004-02-04 Daniel Berlin + + * tree-alias-ander.c (andersen_init): Reorder/Redo code so that we + actually free the memory in intraprocedural mode. + (andersen_cleanup): Ditto. + +2004-02-04 Richard Henderson + + * tree-ssa-ccp.c (get_value, visit_phi_node, + visit_assignment, dump_lattice_value): Tidy. + (evaluate_stmt): Don't do debug dump here. + (def_to_undefined): Merge into set_lattice_value. + (def_to_varying): Likewise, but retain as a wrapper. + (set_lattice_value): Tidy. Emit correct debug info. + (replace_uses_in): Remove strlen hacks. + (execute_fold_all_builtins): Fix DECL_BUILT_IN comparison. + Force folding of BUILT_IN_CONSTANT_P. + +2004-02-04 Richard Henderson + + * builtins.c (fold_builtin_expect): New. + (fold_builtin_1): Call it. + +2004-02-04 Jeff Law + + * jump.c (duplicate_loop_exit_test): Allow copying of the loop + exit test even if we do not find the LOOP_END note. + + * domwalk.c: Update comments. + +2004-02-04 Brian Booth + + PR opt/13755 + * tree-dfa.c (compute_alias_sets): set rename flag for variables + aliased by GLOBAL_VAR. + +2004-02-04 Richard Henderson + + * tree-ssa-dom.c (simplify_switch_and_lookup_avail_expr): New. + (eliminate_redundant_computations): Call it. + +2004-02-03 Richard Henderson + + PR opt/13869 + * tree-cfg.c (cfg_remove_useless_stmts_bb): Correct handling of + boolean variables in COND_EXPR_COND. + +2004-02-03 Richard Henderson + + PR middle-end/13325 + * builtins.c (fold_builtin_1): Rename from fold_builtin. + (fold_builtin): New. + * c-simplify.c (gimplify_expr_stmt): Check TREE_NO_WARNING. + * stmt.c (expand_expr_stmt_value): Likewise. + * tree.h (struct tree_common): Add nowarning_flag. + (TREE_NO_WARNING): New. + (TREE_NO_UNUSED_WARNING): Remove. + * c-typeck.c (build_unary_op): Use TREE_NO_WARNING instead. + * stmt.c (warn_if_unused_value): Likewise. + +2004-02-03 Steven Bosscher + + * tree-ssa-dce.c: Partial rewrite. The old DCE is now called + `conservative'. The more aggressive algorithm uses control + dependence and is called `aggressive' or cd-dce. + * timevar.def (TV_TREE_DCE): Rename. + (TV_TREE_CD_DCE, TV_CONTROL_DEPENDENCES): New timevars. + * tree-pass.h: Declare extern pass_cd_dce. + * tree-optimize.c (init_tree_optimization_passes): Replace + the final DCE pass with a CD-DCE pass. + +2004-02-01 Jan Hubicka + + * cgraphunit.c (cgraph_mark_inline_edge): Fix insertion to + cgraph_inline_hash. + +2004-01-30 Frank Ch. Eigler + + * common.opt: Add support for -fmudflapth, -fmudflapir. + * invoke.texi: Document them. + * opts.c: Ditto. + * flags.h: Add new flags flag_mudflap_threads, _ignore_reads. + * toplev.c: Initialize new flags. Remove redundant code from + lang_independent_options[]. + * tree-mudflap.c (*): Support new flag_mudflap_threads encoding. + (mf_xform_derefs_1): Support flag_mudflap_ignore_reads option. + * c-mudflap.c (mflang_flush_calls): Mark static ctor TREE_USED. + +2004-01-30 Ian Lance Taylor + + * gengtype-yacc.y (bitfieldlen): Add empty action. + +2004-01-30 Diego Novillo + + * configure.ac: Move configuration for libbanshee and + libgmp from configure.in. + +2004-01-30 Richard Henderson + + PR opt/13524 + * gengtype-yacc.y (struct_fields): Accept unnamed bitfields. + (bitfieldlen): Split from ... + (bitfieldopt): ... here. + * gimplify.c (mark_not_gimple): Remove. + (gimplify_call_expr): Don't ignore BUILT_IN_MD. + * tree-dfa.c (struct walk_state): Remove is_not_gimple. + (find_referenced_vars): Don't look for TREE_NOT_GIMPLE. + (find_vars_r, add_referenced_var): Likewise. + * tree-ssa-operands.c (get_stmt_operands, get_expr_operands): Likewise. + * tree-simple.h (mark_not_gimple): Remove. + * tree.h (struct tree_common): Remove not_gimple_flag. + (TREE_NOT_GIMPLE): Remove. + +2004-01-29 Jason Merrill + + PR c++/13865 + * c-simplify.c (gimplify_for_stmt): Reorganize to fix cleanups. + +2004-01-29 Richard Henderson + + PR c++/13543 + * tree-inline.c (initialize_inlined_parameters): Register the + substitute reference also. + +2004-01-29 Richard Henderson + + * tree-inline.c (gimple_expand_calls_inline): Look inside + RETURN_EXPR. + + * tree-pretty-print.c (dump_generic_node): If TDF_DETAILS, dump + both name and uid. + +2004-01-29 Zdenek Dvorak + + * cfg.c (unlink_block): Reset prev_bb and next_bb. + +2004-01-29 Jeff Law + Andrew MacLeod + + * tree-ssa-live.h (tpa_next_partition): Correctly handle compressed + elements. + * tree-ssa.c (coalesce_ssa_name): New argument, flags. Callers + updated. Test SSANORM_COMBINE_TEMPS in flags rather than + flag_tree_combine_temps. + (coalesce_vars): Either operand of a copy might not have a + partition when rewriting a subset of the variables out of SSA form. + (rewrite_vars_out_of_ssa): Honor -ftree-combine-temps by passing + in SSANORM_COMBINE_TEMPS in flags argument to remove_sas_form.. + +2004-01-29 Dale Johannesen + + * Makefile.in (OBJS-common): Move tree-nomudflap.o... + (OBJS-archive): ...to here, and remove duplicate tree-optimize.o. + +2004-01-28 Richard Henderson + + PR middle-end/13898 + * gimplify.c (gimplify_init_constructor): Invoke + lhd_set_decl_assembler_name on the now-static variable. + +2004-01-28 Richard Henderson + + PR opt/13798 + * expr.c (is_zeros_p): Remove. Change all callers to use + initializer_zerop. + (categorize_ctor_elements_1, categorize_ctor_elements): New. + (count_type_elements): New. + (mostly_zeros_p): Use them. + * gimplify.c (tmp_var_id_num): Split out from create_tmp_var_raw. + (create_tmp_var_name): Likewise. + (gimplify_init_constructor): Drop constructors to readonly memory + as indicated by categorize_ctor_elements and can_move_by_pieces. + * tree.c (initializer_zerop): Handle VECTOR_CST. Don't check + AGGREGATE_TYPE_P for CONSTRUCTOR. + * tree.h (categorize_ctor_elements): Declare. + (count_type_elements): Declare. + * Makefile.in (gimplify.o): Update dependencies. + (GTFILES): Add gimplify.c. + +2004-01-27 Frank Ch. Eigler + + * tree-mudflap.c (mx_register_decls): Support VLAs. + (mf_xform_derefs_1): Disable checking shortcut for VLAs. + * c-simplify.c (gimplify_decl_stmt): Add mudflap xref comment. + * gimplify.c (gimplify_bind_expr): Ditto. + +2004-01-27 Daniel Berlin + + * tree-ssa-pre.c: Add more comments describing SSAPRE and + the various functions. + (generate_expr_as_of_bb): Use PRED, a basic block argument, instead of + j, the index of that bb. + (generate_vops_as_of_bb): Ditto. + (insert_occ_in_preorder_dt_order): Rename to + create_and_insert_occ_in_preorder_dt_order. + +2004-01-27 Daniel Berlin + + * tree-ssa-pre.c (rename_1): Add some more comments. + +2004-01-25 Andrew Pinski + + PR c/13748 + * c-decl.c (finish_function): Do not pass + the function on to optimizers if there was an error. + +2004-01-23 Richard Henderson + + PR opt/12941 + * combine.c (SHIFT_COUNT_TRUNCATED): Provide default value. + (simplify_comparison): Don't simplify (eq (zero_extract c 1 r) 0) + if SHIFT_COUNT_TRUNCATED is set. + +2004-01-21 Richard Henderson + + PR c/11267 + * c-decl.c (c_finalize): New. + (finish_function): Use it. Genericize and finalize only non-nested + functions. Register nested functions with cgraph. + * c-simplify.c: Include cgraph.h. + (c_genericize): Genericize nested functions. + * gimplify.c (gimplify_expr): Use DECL_SAVED_INSNS to access + the struct function for the context. + * Makefile.in (c-simplify.o): Update dependencies. + +2004-01-21 Steven Bosscher + + PR opt/13767 + * tree-cfg.c (simple_goto_p): Remove NONLOCAL_LABEL check. + +2004-01-21 Dale Johannesen + + * tree-dfa.c: Fix comment. + +2004-01-21 Richard Henderson + + PR opt/13681 + * tree-ssa-operands.c (get_expr_operands): Handle (&x + c). + + * tree-ssa-ccp.c (maybe_fold_offset_to_component_ref): Handle + flexible array members and lookalikes. + +2004-01-21 Dale Johannesen + + * tree-ssa-dom.c (cprop_into_stmt): Add convert call + to prevent type mismatches. + +2004-01-21 Daniel Berlin + + * tree-ssa-pre.c (load_modified_phi_result): PARM_DECL is okay + to not have a defbb. + (rename_1): Add a comment. + +2004-01-21 Jeff Law + + * tree-ssa-dom.c (find_equivalent_equality_comparison): Treat + CONVERT_EXPRs just like NOP_EXPRs. + (record_equivalences_from_stmt): Similarly. + (thread_across_edge): Fix formatting goof. + + * tree-ssa-dom.c (thread_across_edge): Remove bogus restriction + which prevents threading around to the top of a loop. + + * tree-ssa-dom.c (thread_across_edge): Handle SWITCH_EXPRs in the + target block in addition to COND_EXPRs. + + * tree-ssa-dom.c (thread_across_edge): Create equivalences for + PHIs before looking at the statements in the destination + block. + +2004-01-20 Roger Sayle + + * fold-const.c (fold_convert): Rename to fold_convert_const. + (fold_convert_const): Change arguments to take a tree_code, + a type and the operand/expression to be converted. Return + NULL_TREE if no simplification is possible. Add support for + FIX_CEIL_EXPR and FIX_FLOOR_EXPR in addition to FIX_TRUNC_EXPR. + (fold): Handle FIX_CEIL_EXPR and FIX_FLOOR_EXPR. + Adjust call to fold_convert to match new fold_convert_const. + Avoid modifying the tree passed to fold in-place. + (nondestructive_fold_unary_to_constant): Likewise, simplify + call to fold_convert to match new fold_convert_const. + +2004-01-20 Daniel Berlin + + * tree-alias-ander.c (andersen_op_assign): Update + prototype. Make this handle &x in the operands using + the addrargs parameter. + (andersen_init): Turn off ip_partial until variables + aliasing variables in other functions is resolved. + (andersen_add_var): Use newly renamed alias_var_new_with_aterm. + Fix comment. + (andersen_add_var_same): Ditto. + (andersen_function_call): Use ip_partial, not flag_unit_at_a_time. + * tree-alias-common.c (get_values_from_constructor): Add bitmap + and int * arguments. Used to mark operands that we are taking + address of. + (get_alias_var_decl): We should never see FIELD_DECL's right now. + (intra_function_call): Reverse ordering for slightly faster + projection merging. + (find_op_of_decl): New function. + (find_func_aliases): Use it. + Comment x = foo.y case. + Move get_alias_var_decl of arguments so we only call it if + necessary. + Handle address of arguments in operations. + (create_fun_alias_var): tvar->var. + Set context of fakeargs. + Set context of fakedecls. + Set DECL_PTA_ALIASVAR of RETURN_DECL's. + (create_fun_alias_var_ptf): tvar->var. + Set context of fakedecls. + (create_alias_vars): Only create alias vars for globals + with DECL_INITIAL's. + * tree-alias-common.h (struct tree_alias_ops): + Update op_assign arguments. + (may_alias): Fix comment. + (same_points_to_set): Ditto. + (empty_points_to_set): Ditto. + * tree-alias-type.h: Rename alias_tvar_new_with_aterm + -> alias_var_new_with_aterm. + * tree-alias-type.c: Ditto. + +2004-01-20 Richard Henderson + + * tree-sra.c (get_scalar_for_field): Validate field. + (create_scalar_copies): Iterate over rhs fields too. + +2004-01-19 Dale Johannesen + + * params.def: Add PARAM_MAX_CALLS_GLOBAL_VAR and + PARAM_MAX_CLOBBERED_VARS_GLOBAL_VAR. + params.h: Ditto. + tree-dfa.c: Use them. + doc/invoke.texi: Document them. + +2004-01-19 Jeff Law + + * tree-ssa.c (insert_phi_nodes_for): Always use fully pruned + SSA form. + + * tree-flow.h: Update copyright dates. + (register_new_def): Declare. + * tree-ssa-dom.c: Update copyright dates. + Add tracking of current definition of each program variable just + like we do when rewriting into SSA form. + (get_value_for, set_value_for): Handle either an SSA_NAME or + regular variable. + (tree_ssa_dominator_optimize): Initialize and update CURRDEFS. + If we thread through a block with real statements, the destination + of those statements must be rewritten too. + (thread_across_edge): Skip nop statements at the start of a + block. + (dom_opt_initialize_block_local_data): Clear block_defs + appropriately. + (record_equivalences_from_phis): Accept walk_data structure. + Call register_new_def appropriately. + (optimize_stmt): Call register_new_defs_for_stmt. + (dom_opt_finalize_block): Restore CURRDEFS appropriately. + (register_new_definitions_for_stmt): New. + * tree-ssa.c: Update copyright dates. + (register_new_def): No longer static. Accept additional argument + for the table to hold the new definition. Callers updated. + + * gimplify.c: Update copyright dates. + * tree-cfg.c: Likewise. + * tree.h: Likewise. + + * tree-iterator.c, tree-iterator.c: Use GCC rather than GNU CC. + * tree-ssa-pre.c, tree-ssa-live.h: Likewise. + +2004-01-19 Daniel Berlin + + * timevar.def (TV_TREE_SPLIT_EDGES): New timevar. + * tree-ssa-pre.c (split_critical_edges): Move from here + (pass_pre): Add PROP_no_crit_edges as required. + * tree-cfg.c (split_critical_edges): to here. + (pass_split_crit_edges): New pass. + * tree-optimize.c (tree_optimization_passes): Add NEXT_PASS + (split_crit_edges). + * tree-pass.h: Add PROP_no_crit_edges. + (pass_split_crit_edges): Declared. + +2004-01-19 Frank Ch. Eigler + + * tree-mudflap.c (mf_build_check_statement_for): Tolerate + incoming locus NULL pointer. + +2004-01-18 Richard Henderson + + * builtins.c (simplify_builtin_strcpy): Export. Take strlen argument. + (simplify_builtin_strncpy, simplify_builtin_strcmp): Similarly. + (simplify_builtin_strncmp): Similarly. + (simplify_builtin): Update to match. + * expr.h (simplify_builtin_strcmp, simplify_builtin_strncmp, + simplify_builtin_strcpy, simplify_builtin_strncpy): Declare. + * tree-pass.h (pass_fold_builtins): New. + * tree-optimize.c (init_tree_optimization_passes): Add it. + * tree-ssa-ccp.c (ccp_fold_builtin): Handle BUILT_IN_STRCPY, + BUILT_IN_STRNCPY, BUILT_IN_STRCMP, BUILT_IN_STRNCMP. + (get_strlen): Don't cast to size_t. + (execute_fold_all_builtins, pass_fold_builtins): New. + +2004-01-19 Jan Hubicka + + PR opt/13729 + * cgraphunit.c (cgraph_finalize_compilation_unit): Fix memory leak. + (cgraph_remove_unreachable_nodes): Do not mix analyzed and + DECL_SAVED_TREE flags. + +2004-01-18 Richard Henderson + + * tree-sra.c (REALPART_INDEX, IMAGPART_INDEX): Remove. + (sra_candidates, needs_copy_in): Use a bitmap. Update all users. + (struct sra_elt, sra_elt_hash, sra_elt_eq): New. + (sra_map_size): Remove. + (sra_map): Use a htab_t. + (lookup_scalar): Update to match. + (get_scalar_for_field, get_scalar_for_complex_part): Likewise. + (scalarize_structure_assignment): Use annotate_all_with_locus. + (csc_build_component_ref): Remove index argument. + (csc_build_complex_part): Take tree_code, not index. + (create_scalar_copies): Don't collect indicies. + (emit_scalar_copies): New. + (scalarize_modify_expr, scalarize_tree_list): Use it. + (scalarize_return_expr): Likewise. + (scalarize_structures): Simplify needs_copy_in iteration. + (scalarize_call_expr): Use annotate_all_with_locus. + (dump_sra_map_trav): Split from ... + (dump_sra_map): ... here. Update for hash table. + (tree_sra): Update for new datastructures. + +2004-01-18 Richard Henderson + + * tree-cfg.c (dump_function_to_file): Move ";; Function" header ... + * tree-optimize.c (execute_one_pass): ... here. + +2004-01-17 Daniel Berlin + + * tree-alias-common.c: s@_typevar@_var@g, s@_TVAR@_VAR@g, + s@_TYPEVAR@_VAR@g + * tree-alias-common.h: Ditto + * tree.h: Ditto + * tree-alias-ander.c: Ditto + * tree-alias-type.c: Ditto + * tree-alias-type.h: Ditto + +2004-01-17 Richard Henderson + + * tree-complex.c (gimplify_val): Copy TREE_BLOCK. + + * tree-complex.c (gimplify_val): New. + (extract_component, do_binop, do_unop): Use it. + +2004-01-17 Richard Henderson + + * tree-complex.c (expand_complex_operations_1): Fix RETURN_EXPR + thinko in last change. + +2004-01-18 Zdenek Dvorak + + * cfghooks.c (split_block): Don't redirect edges. + * cfgrtl.c (rtl_split_block): Do it here. + * tree-cfg.c (tree_split_block): Ditto. + +2004-01-17 Richard Henderson + + * tree-cfg.c (verify_expr): Tidy. Check COND_EXPR for boolean + condition. + +2004-01-17 Jan Hubicka + + PR optimization/11761 + * Makefile.in: Remove tree-simple.c from GTYized files. + * tree-dfa.c (find_addressable_vars): Parse nontrivial ADDR_EXPRs. + (discover_nonconstant_array_refs_r): New static function. + (discover_nonconstant_array_refs): New global function. + * tree-flow.h (discover_nonconstant_array_refs): Declare. + * tree-simple.c (types_checked, types_in_memory): Kill. + (struct_needs_to_live_in_memory): Kill. + (needs_to_live_in_memory): aggregates are safe. + * tree-ssa.c (rewrite_out_of_ssa): Call the new function. + +2004-01-17 Richard Henderson + + PR opt/13718 + * tree-complex.c (expand_complex_comparison): Handle COND_EXPR. + (expand_complex_operations_1): Likewise. + +2004-01-17 Richard Henderson + + * tree-sra.c (scalarize_tree_list): Take bitmap argument to + avoid emitting duplicates. Update all callers. + +2004-01-17 Richard Henderson + + PR opt/13718 + * tree-complex.c (expand_complex_comparison): New. + (expand_complex_operations_1): Handle EQ_EXPR and NE_EXPR. + +2004-01-16 Daniel Berlin + + * tree-alias-common.c (get_alias_var): Handle BIT_FIELD_REF. + (find_func_aliases): Ditto. + Update for fact that basic component_refs are no longer + is_gimple_variable. + (create_fun_alias_var): Set DECL_CONTEXT on our faked declarations. + (pass_del_pta): PTA dumps info on delete, so it needs a name. + +2004-01-16 Steven Bosscher + + * tree-optimize.c (init_tree_optimization_passes): Run DCE + before the first dominator optimization pass. + +2004-01-15 Brian Booth + Richard Henderson + + * tree-sra.c (REALPART_INDEX, IMAGPART_INDEX): New. + (sra_map_size): New. + (make_temp): New. + (mark_all_vdefs): New. + (is_sra_candidate_decl): New. + (is_sra_candidate_ref): New. + (lookup_scalar): Use sra_map_size, make_temp. + (get_scalar_for_field): Rename from get_scalar_for. + (get_scalar_for_complex_part): New. + (can_be_scalarized_p): Handle COMPLEX_TYPE. + (scalarize_component_ref): Handle REAL/IMAGPART_EXPR. + (scalarize_structure_assignment): Tidy. + (find_candidates_for_sra): Handle COMPLEX_TYPE, return bool. + (csc_assign, csc_build_component_ref): Split out from ... + (create_scalar_copies): ... here. Handle COMPLEX_TYPE. + (csc_build_complex_part): New. + (scalarize_modify_expr): Use is_sra_candidate_foo. + (scalarize_tree_list): Likewise. + (scalarize_return_expr): Likewise. + (dump_sra_map): Split out from ... + (tree_sra): ... here. Tidy. + +2004-01-15 Frank Ch. Eigler + + * tree-mudflap.c (mf_xform_derefs): Accept void return statements. + +2004-01-15 Andrew MacLeod + Jeff Law + + * tree-ssa-dom.c (remove_local_expressions_from_table): New function + extracted from dom_opt_finalize_block. + (restore_vars_to_originalvalue): Likewise. + (extract_true_false_edges_from_block): Likewise. + (thread_across_edge): Handle if (cond) too. + (dom_opt_finalize_block): Use new functions. Handle if (cond). + + * tree-ssa-dom.c (thread_across_edge): Accept dom_walk argument. + Record temporary equivalences created by PHIs and temporarily + const/copy propagate into conditionals. + (dom_opt_finalize_block): Thread across an edge to a dominated block + if the dominated block has PHIs. Remove temporary equivalenecs + created by PHIs in thread_across_edge. Update code to restore the + various hash tables to use the actual varray rather than a local + copy of the varray. + (simplify_rhs_and_lookup_avail_expr): Set the condition's code + before settings its operands. + + * tree-ssa.c (create_temp): Use add_referenced_var rather than + an incomplete inline of its behavior. Also make sure to + set is_dereferenced_{load,store}, is_call_clobbered and is_stored. + + * tree-ssa-live.c (build_tree_conflict_graph): Correctly handle + case where the result of a PHI is unused. + +2004-01-15 Diego Novillo + + * cfghooks.c (predicted_by_p): Add missing return. + +2004-01-15 Richard Henderson + + * tree-ssa-dom.c (optimize_stmt): Dump new statement if + folding succeeded. + +2004-01-15 Kazu Hirata + + * tree-cfg.c: Fix comment typos. + * tree-eh.c: Likewise. + * tree-inline.c: Likewise. + * tree-optimize.c: Likewise. + * tree-ssa.c: Likewise. + * tree-ssa-dom.c: Likewise. + * tree-ssa-operands.c: Likewise. + * tree-ssa-pre.c: Likewise. + * tree-tailcall.c: Likewise. + +2004-01-14 Jan Hubicka + + * basic-block.h: Include predict.h + (tree_predicted_by_p, rtl_predicted_by_p, rtl_predict_edge, + predict_edge_def): Declare. + * cfghooks.h (cfg_hooks): add predict_edge and predicted_by_p + (predict_edge, predicted_by_p): Declare. + * cfghooks.c (predict_edge, predicted_by_p): Declare. + * cfgrtl (rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Add new hooks. + * cse.c (struct cse_basic_block_data): Rename enum values to not + conflict with profile.h; update all uses. + * predict.c: Include tree-flow.h, ggc.h, tree-dump.h + (predicted_by_p): Rename to ... + (rtl_predicted_by_p): .. this one; make global + (tree_predicted_by_p): New. + (dump_prediction): Add FILE argument. + (predict_edge): Rename to ... + (rtl_predict_edge): .. this one. + (tree_predict_edge): New. + (combine_predictions_for_insn): Update calls of predict_edge. + (predict_loops): Break out from ... + (estimate_probability): ... here; update comments; move updating + of unknown probabilities from ... + (estimate_bb_frequencies): ... here. + (combine_predictions_for_bb): New. + (tree_predict_by_opcode): New. + (tree_estimate_probability): New. + * predict.def (PRED_TREE_POINTER, PRED_TREE_OPCODE_POSITIVE, + PRED_TREE_OPCODE_NONEQUAL, PRED_TREE_FPOPCODE): New predictors. + * predict.h: Add include guard. + (predict_edge, predict_edge_def): Move prototypes to basic_block.h + * tree-cfg.c (tree_cfg_hooks): Add prediction hooks. + * tree-dump.c (dump_files): Add profile. + * tree-flow.h (struct edge_prediction): New structure. + (struct bb_ann_d): Add field predictions. + (tree_estimate_probability): Declare. + * tree-optimize.c (optimize_function_tree): Call tree_estimate_probability. + * tree.h (tree_dump_index): Add TDI_profile. + * tree-pass.h (pass_profile): Declare. + +2004-01-14 Zdenek Dvorak + + * basic-block.h (find_basic_blocks, cleanup_cfg, + delete_unreachable_blocks, merge_seq_blocks): Declare. + * cfgcleanup.c (merge_seq_blocks): New. + * output.h (find_basic_blocks, cleanup_cfg, delete_unreachable_blocks): + Declarations moved to basic-block.h. + * tree-cfg.c (tree_merge_blocks, tree_can_merge_blocks_p): New. + (cleanup_tree_cfg): Call merge_seq_blocks. + (tree_cfg_hooks): Add tree_can_merge_blocks_p and tree_merge_blocks. + +2004-01-14 Zdenek Dvorak + + * tree-cfg.c (tree_make_forwarder_block): Fix. + +2004-01-14 Richard Henderson + + * tree-complex.c: New file. + * Makefile.in (OBJS-common): Add it. + * tree-pass.h (pass_lower_complex): New. + * tree-optimize.c (init_tree_optimization_passes): Add it. + +2004-01-14 Zdenek Dvorak + + * Makefile.in (tree-ssa-loop.o): Add cfgloop.h dependency. + (cfghooks.o): Add TIMEVAR_H and toplev.h dependency. + * basic-block.h (struct edge_def): Use ir_type instead testing of + cfg_hooks directly. + (tidy_fallthru_edge, tidy_fallthru_edges, dump_bb, verify_flow_info): + Declaration removed. + * cfg.c (verify_flow_info, dump_bb): Moved to cfghooks.c. + * cfgcleanup.c (try_simplify_condjump): Changed due to change of + tidy_fallthru_edge. + * cfghooks.c: Include timevar.h and toplev.h. + (cfg_hooks): Made static. + (tree_register_cfg_hooks, ir_type): New. + (verify_flow_info, dump_bb): Moved from cfg.c. + (redirect_edge_and_branch, redirect_edge_and_branch_force, + split_block, split_block_after_labels, move_block_after, + delete_basic_block, split_edge, create_basic_block, + create_empty_bb, can_merge_blocks_p, merge_blocks, + make_forwarder_block, tidy_fallthru_edge, tidy_fallthru_edges): New. + * cfghooks.h (struct cfg_hooks): Modified. + (redirect_edge_and_branch, redirect_edge_and_branch_force, split_block, + delete_basic_block, split_edge, create_basic_block, can_merge_blocks_p, + merge_blocks, make_forwarder_block): Changed into functions. + (loop_optimizer_init, loop_optimizer_finalize): Removed. + (HEADER_BLOCK, LATCH_EDGE): Moved into cfgloop.c. + (tidy_fallthru_edge, tidy_fallthru_edges, create_empty_bb, + verify_flow_info, dump_bb, ir_type): Declare. + (cfg_layout_rtl_cfg_hooks): Declare. + * cfglayout.c (copy_bbs): Don't call add_to_dominance_info. + * cfgloop.c (HEADER_BLOCK, LATCH_EDGE): Moved from cfghooks.h. + (update_latch_info, mfb_keep_just, mfb_keep_nonlatch): New functions. + (canonicalize_loop_headers): Use new semantics of make_forwarder_block. + * cfgloop.h (rtl_loop_optimizer_init, rtl_loop_optimizer_finalize): + Removed. + (loop_optimizer_init, loop_optimizer_finalize): Declare. + * cfgloopmanip.c (split_loop_bb): Don't update dominators. + (remove_bbs): Don't call remove_bbs. + (create_preheader): Use make_forwarder_block. + (mfb_keep_just, mfb_update_loops): New static functions. + * cfgrtl.c (cfg_layout_split_block, rtl_split_block, + rtl_make_forwarder_block, rtl_create_basic_block, + rtl_delete_block, rtl_split_block, rtl_merge_blocks, + tidy_fallthru_edge, rtl_split_edge, cfg_layout_merge_blocks, + cfg_layout_split_edge): Parts not specific to rtl moved to cfghooks.c + (tidy_fallthru_edges): Moved to cfghooks.c. + (rtl_move_block_after): New. + (redirect_edge_with_latch_update, update_cfg_after_block_merging): + Removed. + (rtl_cfg_hooks, cfg_layout_rtl_cfg_hooks): Modified. + * ifcvt.c (merge_if_block, find_cond_trap, find_if_case_1, + find_if_case_2): Don't update dominators. + * loop-init.c (rtl_loop_optimizer_init, rtl_loop_optimizer_finalize): + Replaced by rtl_loop_optimizer_init and rtl_loop_optimizer_finalize. + * loop-unswitch.c (unswitch_loop): Don't call add_to_dominance_info. + * toplev.c (rest_of_handle_loop2): Enter cfglayout mode here. + * tree-cfg.c (create_bb): Modified to suit create_basic_block hook. + (tree_redirect_edge_and_branch_1): Merged into + tree_redirect_edge_and_branch. + (create_blocks_annotations): Removed. + (tree_loop_optimizer_init, tree_loop_optimizer_finalize): Removed. + (tree_make_forwarder_block, remove_bb, tree_split_edge, + tree_redirect_edge_and_branch, tree_split_block, + tree_move_block_after): Partially moved to cfghooks.c. + (tree_duplicate_bb): New. + (PENDING_STMT): Moved to tree-flow.h. + (tree_register_cfg_hooks): Moved to cfghooks.c. + (build_tree_cfg): Don't call create_blocks_annotations. + (factor_computed_gotos, make_blocks): Use create_empty_bb. + (cleanup_tree_cfg): Use delete_unreachable_blocks. + (remove_unreachable_blocks, insert_bb_before): Removed. + (remove_phi_nodes_and_edges_for_unreachable_block): Modified. + (tree_find_edge_insert_loc, thread_jumps): Use cfg hooks. + (bsi_commit_edge_inserts): Update_annotations argument removed. + (tree_cfg_hooks): Modified. + * tree-flow.h (PENDING_STMT): Moved from tree-cfg.c. + (insert_bb_before, remove_unreachable_blocks, + remove_phi_nodes_and_edges_for_unreachable_block, tree_split_edge): + Declaration removed. + (bsi_commit_edge_inserts): Declaration changed. + (tree_duplicate_bb): Declare. + * tree-sra.c (scalarize_structures): Changed due to + bsi_commit_edge_inserts change. + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Use + delete_unreachable_blocks. + * tree-ssa-loop.c: Include cfgloop.h. + * tree-ssa-pre.c (split_critical_edges, tree_perform_ssapre): Use cfg + hooks. + * tree-ssa.c (rewrite_trees, rewrite_vars_out_of_ssa): Changed due to + bsi_commit_edge_inserts change. + (ssa_redirect_edge): Record the phi arguments on the redirected edge. + * tree-tailcall.c (eliminate_tail_call): Clean stored phi arguments. + +2004-01-13 Richard Henderson + + * gimplify.c (gimplify_lhs_complex_part_expr): Remove. + (gimplify_modify_expr): Don't call it. + + * tree-alias-common.c (HAVE_BANSHEE): Make sure it's defined. + (pass_build_pta): Set name. + +2004-01-13 Zdenek Dvorak + + * tree-tailcall.c (eliminate_tail_call): Add phi nodes for the call + vdefs. + (find_tail_calls): Ignore returns with virtual operands. + +2004-01-12 Richard Henderson + + * tree-pass.h: New file. + * gimple-low.c: Include tree-pass.h. + (lower_function_body): Make static, take no arguments. Set + dont_emit_block_notes and call reset_block_changes here. + (pass_lower_cf): New. + * toplev.c (general_init): Call init_tree_optimization_passes. + * toplev.h (init_tree_optimization_passes): Declare. + * tree-alias-ander.c: Include tree-pass.h. + (tree_dump_file, tree_dump_flags): Remove. + (andersen_init): Don't dump_begin. + (andersen_cleanup): Don't dump_end. + * tree-alias-common.c: Include tree-pass.h, timevar.h. + (currptadecl): Remove. + (create_alias_vars): Make static, take no args. Tidy ifdefs. + (delete_alias_vars): Likewise. Protect vs PTA_ANDERSEN. + (pass_build_pta, pass_del_pta): New. + * tree-alias-common.h (create_alias_vars): Delete decl. + (delete_alias_vars): Likewise. + * tree-cfg.c: Include tree-pass.h. + (tree_dump_file, tree_dump_flags): Remove. + (build_tree_cfg): Don't timevar, do init_flow. Ensure one bb. + Don't dump the function here. + (execute_build_cfg, pass_build_cfg): New. + (remove_useless_stmts): Make static, take no arguments. + (pass_remove_useless_stmts): New. + (remove_bb): Don't open the dump file. + * tree-dfa.c: Include tree-pass.h. + (tree_dump_file, tree_dump_flags): Remove. + (find_referenced_vars): Make static, take no args. Do init_tree_ssa. + (compute_may_aliases): Similarly. Don't timevar or open dump file. + Don't delete_alias_vars here. + (pass_referenced_vars, pass_may_alias): New. + * tree-dump.c (dump_files): Remove optimization dumps. + (extra_dump_files, extra_dump_files_in_use): New. + (extra_dump_files_alloced): New. + (dump_register): New. + (get_dump_file_info): New. + (dump_begin, dump_enabled_p, dump_flag_name): Use it. + (dump_enable_all): Handle extra_dump_files. + (dump_switch_p_1): Split out from dump_switch_p. + (dump_switch_p): Handle extra_dump_files. + * tree-dump.h (dump_register): Declare. + * tree-eh.c: Include tree-pass.h + (lower_eh_constructs): Make static, take no args. Don't timevar, + don't dump function. + (pass_lower_eh): New. + * tree-flow.h (remove_useless_stmts, find_referenced_vars, + compute_may_aliases, lower_function_body, rewrite_out_of_ssa, + tree_ssa_ccp, tree_ssa_dominator_optimize, tree_ssa_dce, + tree_ssa_loop_opt, lower_eh_constructs, tree_sra): Remove. + (rewrite_into_ssa): Update decl. + * tree-mudflap.c: Include tree-pass.h. + (mudflap_function_decls): Make static, take no args, don't process + functions with mf_marked_p. + (mudflap_function_ops): Likewise. + (gate_mudflap, pass_mudflap_1, pass_mudflap_2): New. + (mudflap_enqueue_decl): Don't open dump file. + (mudflap_enqueue_constant): Likewise. + * tree-nomudflap.c: Include tree-pass.h. + (mudflap_c_function_decls, mudflap_c_function_ops): Remove. + (pass_mudflap_1, pass_mudflap_2): New. + * tree-optimize.c: Include tree-pass.h. + (optimize_function_tree): Remove. + (tree_dump_file, tree_dump_flags, vars_to_rename): New. + (all_passes): New. + (execute_gimple, pass_gimple): New. + (execute_rebuild_bind, pass_rebuild_bind): New. + (gate_all_optimizations, pass_all_optimizations): New. + (execute_del_cfg, pass_del_cfg): New. + (register_one_dump_file, register_dump_files): New. + (dup_pass_1, init_tree_optimization_passes): New. + (current_properties, last_verified): New. + (execute_todo, execute_one_pass, execute_pass_list): New. + (tree_rest_of_compilation): Remove -O0 passes. + * tree-sra.c: Include tree-pass.h, flags.h. + (tree_dump_file, tree_dump_flags, vars_to_rename): Remove. + (tree_sra): Make static, take no args. Don't timevar or dump file. + (gate_sra, pass_sra): New. + * tree-ssa-ccp.c: Include tree-pass.h, flags.h. + (tree_dump_file, tree_dump_flags): New. + (tree_ssa_ccp): Make static, take no args. Don't timevar or dump file. + (gate_ccp, pass_ccp): New. + (substitute_and_fold): Take no args. + * tree-ssa-dce.c: Include tree-pass.h, flags.h. + (tree_dump_file, tree_dump_flags): New. + (tree_ssa_dce): Make static, take no args. Don't open dump file. + (gate_dce, pass_dce): New. + * tree-ssa-dom.c: Include tree-pass.h, flags.h. + (tree_dump_file, tree_dump_flags, vars_to_rename): Remove. + (tree_ssa_dominator_optimize): Make static, take no args, don't + timevar, don't dump file. + (gate_dominator, pass_dominator): New. + * tree-ssa-loop.c: Include tree-pass.h, flags.h. + (tree_dump_file, tree_dump_flags): Remove. + (tree_ssa_loop_opt): Make static, take no args, don't open dump file. + (gate_loop, pass_loop): New. + * tree-ssa-pre.c: Include tree-pass.h, flags.h. + (tree_dump_file, tree_dump_flags): Remove. + (execute_pre): Rename from tree_perform_ssapre, make static, + take no args, don't timevar, don't open dump file, don't allocate + vars_to_rename. + (gate_pre, pass_pre): New. + * tree-ssa.c: Include tree-pass.h. + (tree_dump_file, tree_dump_flags, vars_to_rename): Remove. + (rewrite_into_ssa): Take no arguments, don't open dump file. + (rewrite_out_of_ssa): Make static, take no args, don't timevar, + don't open dump file. Disable TER if mudflap. + (pass_build_ssa, pass_del_ssa): New. + * tree-tailcall.c: Include tree-pass.h, flags.h. + (tree_dump_file, tree_dump_flags): Remove. + (tree_optimize_tail_calls_1): Rename from tree_optimize_tail_calls. + Make static, take only opt_tailcalls, don't dump file. + (execute_tail_recursion, gate_tail_calls, execute_tail_calls): New. + (pass_tail_recursion, pass_tail_calls): New. + * tree.h (enum tree_dump_index): Remove optimization dumps. + * Makefile.in (tree-alias-ander.o, tree-alias-common.o, tree-ssa.o, + tree-ssa-dom.o, tree-ssa-pre.o, tree-cfg.o, tree-tailcall.o, + tree-dfa.o, tree-eh.o, tree-ssa-loop.o, tree-optimize.o, gimple-low.o, + tree-mudflap.o, tree-ssa-dce.o, tree-ssa-ccp.o, tree-sra.o: Update + dependencies. + +2004-01-12 Frank Ch. Eigler + + * tree-mudflap.c (mf_xform_derefs): Restore instrumentation of + RETURN_EXPRs. + +2004-01-11 Jan Hubicka + + * tree-cfg.c (remove_usless_stmts_cond): Fold statement. + (remove_useless_stmts_1): Fold trees we know how to fold. + +2004-01-09 Richard Henderson + + * gimplify.c (gimplify_constructor): Merge into ... + (gimplify_init_constructor): ... here. Handle COMPLEX_TYPE and + VECTOR_TYPE. + (gimplify_lhs_complex_part_expr): New. + (gimplify_modify_expr): Call it. + * tree-simple.c (is_gimple_rhs): Accept COMPLEX_EXPR. + * c-pretty-print.c (pp_c_initializer): Accept any type CONSTRUCTOR. + (pp_c_initializer_list): Fix code expectations for VECTOR_TYPE and + COMPLEX_TYPE. + +2004-01-09 Steven Bosscher + + PR optimization/13599 + * tree-cfg.c (remove_useless_stmts_cond): Clear last-goto + before returning. + +2004-01-09 Richard Henderson + + * gimplify.c (gimplify_asm_expr): Fix ordering of ASM_INPUTS. + +2004-01-09 Jan Hubicka + + * cgraph.h (cgraph_clone_inlined_nodes): Declare. + * cgraphunit.c (cgrpah_clone_inlined_nodes): Make global. + (cgraph_mark_inline_edge): Sanity check that size is positive. + (cgraph_decide_inlining): Fix typo. + * tree-optimize.c (tree_rest_of_compilation): Fix node duplication + code. + +2004-01-09 Jan Hubicka + + * tree-inline.c (estimate_num_insns_1): Fix. + +2004-01-09 Richard Henderson + + * tree-alias-ander.c, tree-cfg.c, tree-dfa.c, tree-mudflap.c, + tree-sra.c, tree-ssa-ccp.c, tree-ssa-dce.c, tree-ssa-dom.c, + tree-ssa-loop.c, tree-ssa-pre.c, tree-ssa.c, tree-tailcall.c: Rename + dump_file and dump_flags to tree_dump_file/flags. + +2004-01-08 Frank Ch. Eigler + + * tree-mudflap.c (mf_build_string): Properly mf_mark string. + (mf_varname_tree): Remove redundant marking. + * tree-optimize.c (tree_rest_of_compilation): Skip mudflap processing + of mf_marked functions. + * c-mudflap.c (mflang_flush_calls): mf_mark synthetic function. + +2004-01-07 Diego Novillo + + * Makefile.in (OBJS-common): Remove tree-must-alias.o + (tree-must-alias.o): Remove. + * common.opt (ftree-must-alias): Remove. + * flags.h (flag_tree_must_alias): Remove. Update all users. + * timevar.def (TV_TREE_MUST_ALIAS): Remove. + * toplev.c (f_options): Remove entry for -ftree-must-alias. + * tree-alias-common.c (local_alias_vars): Add GTY marker. + (local_alias_varnums): Likewise. + * tree-dfa.c (aliases_computed_p): Declare. + (dump_variable): Show variable UID and dereferenced bits. + (compute_may_aliases): Add arguments 'vars_to_rename' and 'phase'. + Do not call create_alias_vars. + Call promote_call_clobbered_vars + Do debugging dumps. + Set 'aliases_computed_p' to true before returning. + (create_memory_tags): Call may_be_aliased. + Mark new memory tags for renaming. + (compute_alias_sets): Don't do debugging dumps. + (find_variable_in): Move from tree-must-alias.c + (remove_element_from): Likewise. + (find_addressable_vars): Likewise + (promote_call_clobbered_vars): New. + (get_memory_tag_for): Mark the tag volatile if the pointed-to type + is volatile. + * tree-dump.c (dump_files): Remove entry for tree-mustalias. + Add entries for tree-ssa7, tree-dom3 and tree-dce3. + * tree-flow-inline.h (may_be_aliased): New. + * tree-flow.h (may_be_aliased): Declare. + (aliases_computed_p): Declare. + (tree_compute_must_alias): Remove. + * tree-must-alias.c: Remove. + * tree-optimize.c: Include tree-alias-common.h. + (optimize_function_tree): Call create_alias_vars before going into + SSA form. + Do not compute aliases until after the first DOM and DCE passes. + Run DOM and DCE once more after computing may-aliases. + * tree-ssa-dom.c (propagate_copy): Merge the dereferenced bit flags + when copy propagating pointers. + * tree-ssa-operands.c (get_stmt_operands): Assume that the + statement has no volatile operands. + (get_expr_operands): When processing an INDIRECT_REF expressions, + mark the statement as having volatile operands if aliases have not + been computed. + (add_stmt_operand): If the variable may be aliased and aliasing has + not been computed yet, mark the statement as having volatile + operands. + * tree-ssa.c (init_tree_ssa): Set aliases_computed_p to false. + (delete_tree_ssa): Likewise. + * tree.h (tree_dump_index): Remove TDI_mustalias. + Add TDI_dom_3, TDI_ssa_7 and TDI_dce_3. + * doc/invoke.texi: Remove must-alias documentation. + +2004-01-07 Jeff Law + + * tree-ssa-dce.c (find_useful_stmts): Do not consider PHIs for + virtual operands inherently necessary. + +2004-01-07 Zdenek Dvorak + + * tree-dfa.c (free_df_for_stmt, free_df): New functions. + (compute_immediate_uses_for_stmt): Record uses in VDEFs. + * tree-flow.h (free_df, kill_redundant_phi_nodes): Declare. + * tree-optimize.c (optimize_function_tree): Call + kill_redundant_phi_nodes. + * tree-ssa-ccp.c (finalize): Call free_df. + * tree-ssa.c (replace_immediate_uses, raise_value, + kill_redundant_phi_nodes): New functions. + +2004-01-06 Jeff Law + + * tree.h (FUNCTION_RECEIVES_NONLOCAL_GOTO): Kill. + * tree-cfg.c (make_exit_edges, is_ctrl_altering_stmt): Use + current_function_has_nonlocal_label instead of + FUNCTION_RECEIVES_NONLOCAL_GOTO. + * gimplify.c (gimplify_expr): Set has_nonlocal_label in the + appropriate function's struct function rather than setting + a bit in the FUNCTION_DECL. + +2004-01-06 Jan Hubicka + + * expr.c (string_constant): Recognize array_ref. + +2004-01-06 Richard Henderson + + * builtins.c (builtin_save_expr): New. + (expand_builtin_mathfn, expand_builtin_mathfn_2, + expand_builtin_strcmp, expand_builtin_strncmp, + expand_builtin_strcat, fold_builtin_cabs): Use it. + +2004-01-06 Jan Hubicka + + * fold-const.c (fold): Do not rebuild comparison when nothing + changed. + +2004-01-05 Jan Hubicka + + * tree-ssa-ccp.c (ccp_fold_builtin): Return early for builtins + taking no arugment. + +2004-01-05 Steven Bosscher + + * tree-ssa-dce.c: Clean up whitespace. + + * tree-cfg.c (tree_verify_flow_info): Fix complaint about + missing or wrong labels in the targets of a conditional branch. + +2004-01-05 Richard Henderson + + * tree-ssa-dom.c (record_equivalences_from_incoming_edge): Check + for signed zeros before recording value. + * Makefile.in (tree-ssa-dom.o): Depend on real.h. + +2004-01-05 Jeff Law + + * tree-ssa-dom.c (cprop_into_stmt): Remove hack which prevented + copy propagation into statements with virtual operands, but no + real operands. + + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Correctly handle + the case where an edge we wish to redirect is split by the out of SSA + code. + +2004-01-05 Richard Henderson + + * c-tree.h (struct lang_type): Add enum_min, enum_max. + * c-decl.c (finish_enum): Set them. Set TYPE_MIN/MAX_VALUE to + the limits of the compatible type, not to the enumerators. + (check_bitfield_type_and_width): Use them. + (finish_struct): Clear allocated struct lang_type. + * gimplify.c (gimplify_switch_expr): Remove special handling of + outer cast in a switch. + * tree-ssa-dom.c (record_equivalences_from_incoming_edge): Likewise. + +2004-01-05 Daniel Berlin + + * tree-ssa-pre.c (added_phis): Removed. + Remove gt-tree-ssa-pre.h. + (process_left_occs_and_kills): ASM_EXPR's block load pre. + + * Makefile.in (GTFILES): Don't process tree-ssa-pre.c. + gt-tree-ssa-pre.h isn't a gtfile anymore. + +2004-01-05 Andrew Pinski + + * config.gcc (powerpc-*-darwin*): Make libbanshee rebuild + on PPC darwin. + +2004-01-05 Richard Henderson + + * gimplify.c (gimplify_expr): Move check for error_mark inside + the main loop. + +2004-01-04 Jan Hubicka + + * Makefile.in (cgraph.o, cgraphunit.o): Add intl.h dependency. + * cgraph.c (create_edge, dump_cgraph): Update to use inline_failed + * cgraph.h (cgraph_edge): Replace inline_call by inline_failed + (cgraph_inline_p): Add extra argument reason. + * cgraphunit.c: Minor formating fixes. + cgraph_first_inlined_callee): New functions. + (record_call_1): Record builtins too. + (cgraph_analyze_function): Update inline_failed messages. + (cgraph_mark_functions_to_output, cgraph_expand_function, cgraph_inlined_into, + cgraph_inlined_callees, cgraph_estimate_growth): Update to use inline_failed. + (cgraph_check_inline_limits): Likewise; Add argument reason. + (cgraph_set_inline_failed): New static function. + (cgraph_decide_inlining_of_small_function, cgraph_decide_inlining): Set + reasons. + (cgraph_inline_p): Add new argument reason. + * tree-inline.c (expand_call_inline): Update warning. + +2004-01-04 Andreas Jaeger + + * common.opt: Re-order some options in ASCII collating orders. + +2004-01-03 Richard Henderson + + * toplev.c (rest_of_compilation): Fixup merge error wrt + check_function_return_warnings. + + * tree.h (FUNCTION_RECEIVES_NONLOCAL_GOTO): Use unsigned_flag. + +2004-01-02 Jan Hubicka + + * c-decl.c (duplicate_decls): Output DIE of extern inline function + only when it can be inlined. + * c-objc-common.c (c_disregard_inline_limits): When not inlining + extern inline functions do not disregard. + * cgraphunit.c (cgraph_analyze_function): When not inlining do not set + inline. + (cgraph_decide_inlining): Limit work done when not inlining. + (cgrpah_decide_inlining_incrementally): Likewise. + * tree-optimize.c (tree_rest_of_compilation): Do not call + optimize_inline_calls + when there is nothing to inline. + +2004-01-01 Richard Henderson + + * c-common.c (c_expand_expr): Don't handle STMT_EXPR. + * c-objc-common.c (c_objc_common_finish_file): Use expand_expr. + * c-semantics.c (lang_expand_stmt, lang_expand_decl_stmt, + expand_cond, genrtl_do_pushlevel, genrtl_goto_stmt, genrtl_expr_stmt, + genrtl_expr_stmt_value, genrtl_decl_stmt, genrtl_if_stmt, + genrtl_while_stmt, genrtl_do_stmt_1, genrtl_do_stmt, + genrtl_return_stmt, genrtl_for_stmt, genrtl_break_stmt, + genrtl_continue_stmt, genrtl_scope_stmt, genrtl_switch_stmt, + genrtl_case_label, genrtl_compound_stmt, genrtl_asm_stmt, + genrtl_cleanup_stmt, expand_stmt, find_reachable_label, + find_reachable_label_1, expand_unreachable_if_stmt, + expand_unreachable_stmt): Remove. + * c-common.h: Update. + +2003-12-31 Richard Henderson + + * c-mudflap.c (mflang_register_call): Remove. + (mflang_flush_calls): Use start_function/finish_function. + * tree-mudflap.c (mf_init_extern_trees): Tidy. + (mf_decl_cache_locals): Fix chaining for empty body. + (deferred_static_decl_labels): Remove. + (deferred_static_decls_init): Remove. + (mudflap_register_call): New. + (mudflap_enqueue_decl): Use it. Remove label argument. + (mudflap_enqueue_constant): Likewise. + (mudflap_finish_file): Update to match. + * tree-mudflap.h (mudflap_enqueue_decl): Remove label argument. + (mudflap_enqueue_constant): Likewise. + (mflang_register_call): Remove. + * tree-nomudflap.c (mudflap_enqueue_decl): Remove label argument. + (mudflap_enqueue_constant): Likewise. + * tree-optimize.c (tree_ssa_finish): Don't create NULL bodies. + * varasm.c (make_decl_rtl): Update mudflap_enqueue_decl call. + (output_constant_def_contents): Similarly for mudflap_enqueue_constant. + +2003-12-26 Sebastian Pop + + * tree-cfg.c (print_loop, print_pred_bbs, print_succ_bbs, + debug_loop_ir, print_loop_ir): New. + * tree-flow.h (debug_loop_ir, print_loop_ir): Declare. + +2003-12-23 Jeff Law + + * tree-cfg.c (tree_find_edge_insert_loc): Do not use the target + block as an insertion location if the target block has PHI nodes. + +2003-12-23 Jan Hubicka + + * cgraphunit.c (cgraph_mark_inline): Accept argument edge; return + next edge not redirected. + (cgraph_recursive_inlining_p): Simplify. + (cgraph_decide_inlining*): Update calls of cgraph_mark_inline. + +2003-12-22 Toon Moene + + * tree-alias-common.c (find_func_aliases): Do not call + intra_function_call for languages assuring no aliasing between + arguments (by themselves) and and global memory. + +2003-12-21 Jan Hubicka + + * tree-ssa-ccp.c (fold_stmt): Return when there is no RHS + (get_rhs): Return for RETURN_EXPR with no operand. + +2003-12-21 Zdenek Dvorak + + * tree-cfg.c (tree_make_forwarder_block): Use split_block. + (tree_split_block): New. + (tree_cfg_hooks): Add tree_split_block. + (tree_loop_optimizer_init): Enable force_single_succ_latches. + * cfgloopmanip.c (loop_split_edge_with): Don't update dominators. + * cfgrtl.c (rtl_split_edge, cfg_layout_split_edge): Update dominators. + +2003-12-19 Daniel Berlin + + * tree-dfa.c (alias_stats_d): New structure. + (alias_stats): New variable. + (create_memory_tags): Zero out alias_stats. + (dump_alias_stats): New function. + (compute_alias_sets): Call it if TDF_STATS is set. + (may_alias_p): Collect the various statistics. + +2003-12-19 Diego Novillo + + * gimple-low.c (expand_var_p): Always expand volatiles. + * tree-dfa.c (find_referenced_vars): Move up in the file. + (create_memory_tags): New local function. + (compute_may_aliases): Call it. + (add_referenced_var): Move code to create memory tags and create + aliasing arrays to create_memory_tags. + (get_memory_tag_for): Don't mark memory tags volatile. Mark them + addressable. + * tree-flow.h (var_ann_d): Add bitfields is_dereferenced_store and + is_dereferenced_load. + (add_call_clobbered_var): Remove. + * tree-ssa-operands.c (check_optype_freelist): Mark arguments + unused. + (add_optype_freelist): Likewise. + (add_stmt_operand): Don't add operands for volatile variables. + +2003-12-19 Kazu Hirata + + * dominance.c: Fix comment typos. + * et-forest.c: Likewise. + * et-forest.h: Likewise. + * tree-cfg.c: Likewise. + * tree-eh.c: Likewise. + * tree-mudflap.c: Likewise. + * tree-optimize.c: Likewise. + * tree-pretty-print.c: Likewise. + * tree-ssa-ccp.c: Likewise. + * tree-ssa-dom.c: Likewise. + * tree-ssa.c: Likewise. + * tree-tailcall.c: Likewise. + * tree.def: Likewise. + * tree.h: Likewise. + +2003-12-18 Jason Merrill + + PR c++/12453 + * c-simplify.c (stmt_expr_last_stmt): Split out from... + (gimplify_stmt_expr): Here. + * c-common.h: Declare it. + +2003-12-18 Zdenek Dvorak + + * et-forest.h (et_forest_create, et_forest_delete, + et_forest_add_node, et_forest_add_edge, et_forest_remove_node, + et_forest_remove_edge, et_forest_parent, + et_forest_common_ancestor, et_forest_node_value, + et_forest_enumerate_sons): Declarations removed. + (struct et_node): New. + (et_new_tree, et_free_tree, et_set_father, et_split, et_nca, + et_below): Declare. + * et-forest.c (struct et_forest_occurrence, struct et_forest, + struct et_forest_node): Removed. + (et_forest_create, et_forest_delete, + et_forest_add_node, et_forest_add_edge, et_forest_remove_node, + et_forest_remove_edge, et_forest_parent, + et_forest_common_ancestor, et_forest_node_value, + et_forest_enumerate_sons, splay, remove_all_occurrences, + find_leftmost_node, find_rightmost_node, calculate_value): Removed. + (struct et_occ): New. + (et_nodes, et_occurences): New. + (set_depth, set_depth_add, set_prev, set_next, et_recomp_min, + et_check_occ_sanity, et_check_sanity, et_check_tree_sanity, + record_path_before_1, record_path_before, check_path_after_1, + check_path_after, et_splay, et_new_occ, et_new_tree, + et_free_tree, et_set_father, et_split, et_nca, et_below): New. + * basic-block.h (struct basic_block_def): New field dom. + (struct dominance_info): Type removed. + (calculate_dominance_info, free_dominance_info, + nearest_common_dominator, set_immediate_dominator, + get_immediate_dominator, dominated_by_p, get_dominated_by, + add_to_dominance_info, delete_from_dominance_info, + recount_dominator, redirect_immediate_dominators, + iterate_fix_dominators, verify_dominators): Declarations + changed. + (enum dom_state): New. + (dom_computed): New variable. + (first_dom_son, next_dom_son): Declare. + * dominance.c (struct dominance_info): Removed. + (BB_NODE, SET_BB_NODE): Removed. + (calculate_dominance_info, free_dominance_info, + nearest_common_dominator, set_immediate_dominator, + get_immediate_dominator, dominated_by_p, get_dominated_by, + add_to_dominance_info, delete_from_dominance_info, + recount_dominator, redirect_immediate_dominators, + iterate_fix_dominators, verify_dominators, + debug_dominance_info): Work over new datastructure. Access + dominance datastructures through CFG. + (assign_dfs_numbers, compute_dom_fast_query, first_dom_son, + next_dom_son): New. + * tree-cfg.c (pdom_info): Variable removed. + (create_bb): Add the block to the dominance information. + (cleanup_tree_cfg): Let updating of the dominance on the + individual passes. + (remove_bb): Don't handle pdom. + (cleanup_control_expr_graph, tree_make_forwarder_block, + thread_jumps): Invalidate the dominators. + (tree_split_edge): Update the dominators. + (compute_dominance_frontiers_1, compute_dominance_frontiers, + tree_verify_flow_info, tree_loop_optimizer_init): Use the new + interface to dominators. + * domwalk.c (walk_dominator_tree): Do not use dom_children. + * tree-flow-inline.h (add_dom_child, remove_dom_child, + clear_dom_children, dom_children): Removed. + * tree-flow.h (struct bb_ann_d): Dom_children field removed. + (add_dom_child, dom_children, build_dominator_tree): Declaration + removed. + (compute_dominance_frontiers): Declaration changed. + * tree-optimize.c (optimize_function_tree): Free dominance + information in the end. + * tree-ssa-dom.c (tree_ssa_dominator_optimize, + dom_opt_finalize_block): Do not use dom_children. + * tree-ssa-pre.c (fast_a_dominates_b, build_dfs_id_array_1, + build_dfs_id_array): Removed. + (pre_idom, dfs_id, dfs_id_last): Variables removed. + (build_dfn_array): Do not use dom_children. + (eref_compare, load_modified_phi_result, rename_1, reaching_def, + finalize_1, collect_expressions, tree_perform_ssapre): Use the + new interface to the dominance information. + * tree-ssa.c (struct mark_def_sites_global_data): Idom field + removed. + (set_livein_block, verify_use, verify_phi_args, + rewrite_into_ssa, mark_def_sites, verify_ssa): Use the new + interface to the dominance information. + (build_dominator_tree): Removed. + * tree-tailcall.c (tree_optimize_tail_calls): Invalidate + dominance information. + * bt-load.c (dom): Variable removed. + (augment_live_range, combine_btr_defs, migrate_btr_def, + migrate_btr_defs, branch_target_load_optimize): Updated for the + new interface for dominance information. + * cfglayout.c (copy_bbs): Removed loops argument. Updated for + the new interface for dominance information. + * cfglayout.h (copy_bbs): Declaration changed. + * cfgloop.c (flow_loop_pre_header_find, flow_loops_cfg_dump, + flow_loop_scan, canonicalize_loop_headers, flow_loops_find): Updated + for the new interface for dominance information. + (flow_loop_scan): Loops argument removed. + (flow_loops_free): Don't release dominators. + * cfgloop.h (struct cfg): Dom field removed. + (flow_loop_scan, loop_split_edge_with, simple_loop_p, + just_once_each_iteration_p, split_loop_bb): Declaration changed. + * cfgloopanal.c (simple_loop_exit_p, simple_increment, + just_once_each_iteration_p, simple_loop_p): Remove loops argument. + Updated for the new interface for dominance information. + * cfgloopmanip.c (remove_bbs, find_path, create_preheader, + split_loop_bb, loopify, duplicate_loop_to_header_edge, + force_single_succ_latches, loop_split_edge_with): Ditto. + (create_loop_notes): Free the dominators. + * gcse.c (dominators): Variable removed. + (free_code_hoist_mem, compute_code_hoist_data, hoist_code): + Updated for the new interface for dominance information. + * ifcvt.c (post_dominators): Variable removed. + (mark_loop_exit_edges, merge_if_block, find_if_header, + find_cond_trap, find_if_case_1, find_if_case_2, if_convert): + Updated for the new interface for dominance information. + * loop-init.c (rtl_loop_optimizer_init, + rtl_loop_optimizer_finalize): Ditto. + * loop-unroll.c (decide_peel_simple, decide_peel_once_rolling, + decide_peel_completely, decide_unroll_stupid, + decide_unroll_constant_iterations, + decide_unroll_runtime_iterations): Loops argument removed. + Updated for the new interface for dominance information. + (unroll_and_peel_loops, peel_loops_completely, + unroll_loop_runtime_iterations): Updated for the new interface for + dominance information. + * loop-unswitch.c (may_unswitch_on_p, unswitch_loops, + unswitch_single_loop, unswitch_loop): Updated for the new + interface for dominance information. + * predict.c (process_note_predictions, process_note_prediction, + estimate_probability, note_prediction_to_br_prob): Ditto. + * sched-rgn.c (find_rgns, init_regions): Ditto. + * toplev.c (rest_of_handle_branch_prob): Free the dominators. + +2003-12-18 Jeff Law + + * tree-ssa-dom.c (edges_to_redirect, redirection_targets): Merged + into a single varray "redirection_edges". + (tree_ssa_dominator_optimize): Twiddle initialization, finalization + and accessors to redirection information based on combining varrays. + Get the threading destination from the saved edge rather than from a + saved block. Mark variables appearing in PHIs at the jump thread + destination to be taken out of SSA form. + (thread_across_edge): Save the edge into the destination block + rather than the destination block itself. Twiddle based on + combining varrays of jump threading information. + * tree-flow.h (tree_block_forwards_to): Returns an edge rather than + a block. + * tree-cfg.c (tree_block_forwards_to): Return the edge leading to + the target block rather than the target block itself. + +2003-12-18 Daniel Berlin + + * tree-dfa.c (get_memory_tag_for): Don't put things with different + points-to sets in the same memory tag. + +2003-12-18 Jan Hubicka + + * c-common.c (handle_nonnull_attribute, check_function_nonnull): + Initialize arg_num. + * c-format.c (handle_format_attribute): Initialize format_num. + * rtlanal.c (get_related_value): Initialize get_jump_table_offset + +2003-12-18 Zdenek Dvorak + + * stmt.c (expand_start_loop, expand_loop_continue_here, + expand_end_loop): Don't create loop notes. + +2003-12-18 Zdenek Dvorak + Jeff Law + + * tree-cfg.c (tree_node_shared_p): Explicitly allow sharing of + CST nodes. + * tree-simple.c (is_gimple_rhs): Allow CST nodes. + (is_gimple_min_invariant): Reject constants with TREE_OVERFLOW set. + * tree-ssa-ccp (visit_assignment): Test is_gimple_min_invariant + after munging bitfields. + * tree-ssa-dom.c (record_equivalences_from_stmt): Similarly. + +2003-12-17 Jan Hubicka + + Based on patch by Dale Johannesen + * expr.c (MOVE_RATIO, CLEAR_RATIO): Move to ... + * expr.h (MOVE_RATIO, CLEAR_RATIO): ... here + +2003-12-17 Jan Hubicka + + * Makefile.in (sibcall.o): Kill. + (tree-tailcall.o): Add except.h dependency + * sibcall.c: Kill. + (purge_reg_equiv_notes, purge_mem_unchanging_flag): Move to ... + * calls.c (purge_reg_equiv_notes, purge_mem_unchanging_flag) ... here. + (expand_call): Do not produce placeholders; do not deal with tail + recursion; set tail_call_emit. + (fixup_tail_calls): New. + * expr.h (fixup_tail_calls): Declare. + * toplev.c (rest_of_handle_sibling_calls): Kill. + (rest_of_compialtion): Do not use rest_of_handle_sibling_calls; + call fixup_tail_calls. + * tree-dump.c (dump_files): Add tail2 + * tree-flow.h (tree_optimize_tail_calls): Update prototype. + * tree-optimize.c (optimize_function_tree): Do tail optimization twice. + * tree-tailcall.c: Inlucde except.h + (suitable_for_tail_call_opt_p): New. + (optimize_tail_call): Add opt_tailcalls argument; optimize tailcalls. + (tree_optimize_tail_calls): Add opt_tailcalls/pass arguments. + * tree.h (CALL_EXPR_TAILCALL): New. + (tree_dump_index): Add tail2 + * function.h (struct function): Add tail_call_emit field. + +2003-12-17 Jan Hubicka + + * tree-inline.c (estimate_num_insns_1): Check that all nodes are + known; add missing nodes; fix MODIFY_EXPR + +2003-12-16 Jason Merrill + + PR middle-end/12920 + * stor-layout.c (layout_type): Just return if type is + error_mark_node. + * c-decl.c (grokdeclarator): Immediately layout an + ARRAY_TYPE used in a pointer-to-array declarator. + +2003-12-16 Diego Novillo + + * tree-dfa.c (may_alias_p): If VAR and PTR are pointers with the + same alias set, return false. + (get_memory_tag_for): Group based on alias set classes, not on + conflicting alias sets. + * tree-must-alias.c (promote_var): Don't bring aliases over when + all the may-aliases of a non-promotable variable are promoted. + +2003-12-16 Andrew MacLeod + + * tree-flow-inline.h (free_vuse, free_vdefs): Moved to + tree-ssa-operands.c + (get_def_ops, get_use_ops, get_vdef_ops, get_vuse_ops): Use the new + more direct structure pointer. + (get_use_op_ptr, get_def_op_ptr): Cast is no longer necessary. + * tree-flow.h (struct stmt_ann_d): Replace operands and voperands + pointers with pointers directly to the operand types. + * tree-ssa-dom.c (cprop_into_stmt): Use new stmt based interface to + free virtual operands. Check virtual bases of both VUSE and VDEF. + * tree-ssa-operands.c (struct voperands_d): Declare here, used only + for previous_vops during stmt operand construction. + (struct vecmanage_d, vecmanage_add_segmen, vecmanage_add_special, + vecmanage_init, vecmanage_tree_ptr_init, vecmanage_fini, check_free, + vecmanage_new_vector, vecmanage_new_tree_ptr_vector, + vecmanage_free_vector): Remove. + (allocate_ssa_op_vec, free_ssa_op_vec, allocate_ssa_virtual_op_vec, + allocate_operands_t, allocate_voperands_t): Remove. + (finalize_new_ssa_operands, inalize_new_ssa_virtual_operand): Remove. + (struct freelist_d): New. List of free operand structures. + (check_optype_freelist): New. Choose memory from freelist, if available. + (add_optype_freelist): New. Add structure to freelist, if appropriate. + (allocate_def_optype): New. Allocate a def operand list from GC. + (allocate_use_optype): New. Allocate a useoperand list from GC. + (allocate_vdef_optype): New. Allocate a vdef operand list from GC. + (allocate_vuse_optype): New. Allocate a vuse operand list from GC. + (free_uses, free_defs, free_vuses, free_vdefs): Use GC and the freelist. + (remove_vuses, remove_vdefs): New. External interface to remove virtual + operands. + (init_ssa_operands, fini_ssa_operands): Ensure the free list is empty. + (finalize_ssa_defs, finalize_ssa_use, finalize_ssa_vdefs, + finalize_ssa_vuses): Use new direct pointers from the stmt annotation. + (append_vdef, append_vuse): No need to hack prev_vops pointer now. + (get_stmt_operands): use new freeing interface, keep previous vops in + their own local structure for now, passing its address around. + * tree-ssa-operands.h (struct def_optype_d, struct use_optype_d, + struct vdef_optype_d, struct vuse_optype_d): Implement as a single + dynamically allocated structure. + (struct operands_d, struct operands_d): Remove. + * tree-ssa-pre.c (subst_phis): Remove virtual operands using new funcs. + +2003-12-16 Jan Hubicka + + * tree-cfg.c (verify_addr_expr): Rename to .... + (verify_expr): ... this one; check that no SSA names are on + freelist. + (verify_stmt, verify_stmts): Update calls of verify_addr_expr. + + Revert until initializers are made language independent: + * cgraphunit.c (record_call_1): Do not call analyze_expr hook + * langhooks-def.h (LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR): Kill. + (LANG_HOOKS_CALLGRAPH_INITIALIZER): Update. + * longhooks.h (lang_hooks_for_callgraph): Kill analyze_expr. + +2003-12-16 Zdenek Dvorak + + * tree-pretty-print.c (dump_bb_header): Show block number when + there is no label. + (pp_cfg_jump): Show labels in addition to block numbers. + (dump_generic_bb_buff): Always call dump_bb_header. + +2003-12-16 Jan Hubicka + + * cgraphunit.c (cgraph_remove_unreachable_nodes): Fix typo; + improve comments; cleanup linked list mantenance. + +2003-12-15 Diego Novillo + + * tree-sra.c (can_be_scalarized_p): Reject volatile variables. + + * sibcall.c (skip_copy_to_return_value): Initialize 'hardret' and + 'softret'. + +2003-12-16 Jan Hubicka + + * cgraph.c (cgraph_remove_node): Ignore DECL_EXTERNAL clones. + * cgraphunit.c (verify_cgraph_node): Do not insist on unemmited extern + inline functions to be valid. + (cgraph_finalize_compilation_unit): Fix ordering. + (cgraph_mark_functions_to_output): Do not insist on DECL_EXTERNAL + nodes to be reclaimed. + (cgraph_remove_unreachable_nodes): New function. + (cgraph_decide_inlining): use it. + +2003-12-15 Andrew MacLeod + + * Makefile.in (TREE_FLOW_H): Add dependence on tree-ssa-operands.h + (OBJS-common): Add tree-ssa-operands.o + (tree-ssa-operands.o): Add dependencies. + (GTFILES): Add tree-ssa-operands.[ch]. + * tree-dfa.c (get_stmt_operands, get_expr_operands, add_stmt_operand, + note_addressable, add_def, add_use, add_vde, add_vuse, + add_call_clobber_ops, add_call_read_ops): Moved to tree-ssa-operands.c. + (compute_immediate_uses_for_stmt): Use new optypes interface. + (cleanup_operand_arrays): Delete. + (collect_dfa_stats_r): Use new optypes interface. + (get_call_flags): Moved to tree-ssa-operands.c. + (vdefs_disappeared_p, mark_new_vars_to_rename): Use optypes interface. + * tree-flow-inline.h (def_ops, use_ops, vdef_ops, vuse_ops): Use new + optypes. + (free_vuses): New. Clear and release vuses. + (free_vdefs): New. Clear and release vdefs. + (get_use_ops_ptr): New. Get address of a use op. + (get_def_ops_ptr): New. Get address of a use op. + (get_vdef_result_ptr): New. Get address of a use op. + (get_vdef_op_ptr): New. Get address of a use op. + (get_vuse_op_ptr): New. Get address of a use op. + (start_ssa_stmt_operands): New. Entry point to start processing stmt + operands. + * tree-flow.h (struct operands_d, struct voperands_d): Move to + tree-ssa-operands.h + (struct stmt_ann_d): Add GTY markers to operands. + * tree-pretty-print.c (dump_vops): Use optypes interface. + * tree-sra.c (create_scalar_copies): Use optypes interface. + (scalarize_structures, scalarize_modify_exp): Use optypes interface. + * tree-ssa-ccp.c (visit_stmt, ccp_fold, initialize, replace_uses_in, + likely_value, set_rhs): Use optypes interface. + * tree-ssa-dce.c (find_useful_stmts, stmt_useful_p, process_worklist): + Use optypes interface. + * tree-ssa-dom.c (thread_across_edge, thread_jumps_walk_stmts): Use + optypes interface. + (cprop_into_stmt): Rewrite using new interface. + (eliminate_redundant_computations, record_equivalences_from_stmt, + optimize_stmt, avail_expr_hash, avail_expr_eq): Use optypes interface. + * tree-ssa-live.c (create_ssa_var_map, calculate_live_on_entry, + build_tree_conflict_graph,register_ssa_partitions_for_vars): Use + optypes interface. + * tree-ssa-pre.c (names_match_p, maybe_find_rhs_use_for_var, + expr_phi_insertion, same_e_version_real_occ_real_occ, opnum_of_phi, + generate_expr_as_of_bb, generate_vops_as_of_bb, subst_phis, + load_modified_real_occ_real_occ, same_e_version_phi_result, can_insert, + get_default_def, reaching_def, process_left_occs_and_kills, + collect_expressions): Use optypes interface. + * tree-ssa.c (mark_def_sites, check_replaceable, find_replaceable_in_bb, + dump_replaceable_exprs, rewrite_trees, verify_ssa, rewrite_stmt): Use + optypes interface. + (init_tree_ssa): Initialize new operand data structures. + (delete_tree_ssa): Free new operand structures. + * tree.h (VDEF_RESULT, VDEF_OP, NUM_VDEFS): Move to tree-ssa-operands.h. + + * tree-ssa-operands.h: New file. + (struct def_optype_d): New. Structure for stmt defs. + (struct use_optype_d): New. Structure for stmt uses. + (struct vdef_optype_d): New. Structure for stmt vdefs. + (struct vuse_optype_d): New. Structure for stmt vuses. + (USE_OPS, STMT_USE_OPS, NUM_USES, USE_OP_PTR, USE_OP): Macros to + access stmt uses. + (DEF_OPS, STMT_DEF_OPS, NUM_DEFS, DEF_OP_PTR, DEF_OP): Macros to + access stmt defs. + (VDEF_OPS, STMT_VDEF_OPS, NUM_VDEFS, VDEF_RESULT_PTR, VDEF_RESULT, + VDEF_OP_PTR, VDEF_OP): Macros to access stmt vdefs. + (VUSE_OPS, STMT_VUSE_OPS, NUM_VUSES, VUSE_OP_PTR, VUSE_OP): Macros to + access stmt vuses. + (struct operands_d, struct voperands_d): moved from tree-dfa.c. + * tree-ssa-operands.c: New file. + (build_defs, build_uses, build_vdefs, build_vuses): New static varrays. + (struct vecmanage_d): New. Struct to manage non-GC vectors. + (vecmanage_add_segment): New. Add a new segment to a vector manager. + (vecmanage_add_special): New. Add a large vector to the special list. + (vecmanage_init): Initialize a vector manager. + (vecmanage_tree_ptr_init): New. Initialize a vector manager for tree *. + (vecmanage_fini): New. Release vector manager memory. + (check_free): New. Look for free memory in the vector maanger. + (vecmanage_new_vector): New. Allocate a vector. + (vecmanage_new_tree_ptr_vector): New. Allocate a vector of 'tree *'. + (vecmanage_free_vector): New. Free a vector. + (free_ssa_op_vec): New. Free an ssa operand's memory. + (allocate_ssa_op_vec): New. Allocate a vector for use/defs. + (allocate_ssa_virtual_op_vec): New. Allocate a vector for vuse/vdefs. + (allocate_operands_t): New. Allocate an operand structure. + (allocate_voperands_t): New. Allocate a virtual operand structure. + (free_uses): New. Clear and release uses. + (free_defs): New. Clear and release defs. + (init_ssa_operands): New. Initialize ssa operand management. + (fini_ssa_operands): New. Cleanup ssa operand management. + (finalize_new_ssa_operands): New. Commit current operands. + (finalize_new_ssa_virtual_operands): New. Commit current virtual ops. + (finalize_ssa_defs): New. Commit and verify stmt definitions. + (finalize_ssa_uses): New. Commit and verify stmt uses. + (finalize_ssa_vdefs): New. Commit and verify stmt virtual definitions. + (finalize_ssa_vuses): New. Commit and verify stmt virtual uses. + (finalize_ssa_stmt_operands): New. Commit all stmt operands. + (verify_start_operands): New. Verify build mechanism is ready for a new + stmt. + (append_def): Renamed from add_def, and moved from tree-dfa.c. + (append_use): Renamed from add_def, and moved from tree-dfa.c. + (append_vdef): Renamed from add_def, and moved from tree-dfa.c. + (append_vuse): Renamed from add_def, and moved from tree-dfa.c. + (add_vuse): New. Entry point to add a vuse to a stmt. + (get_call_flags): Moved from tree-dfa.c + (get_stmt_operands, get_expr_operands, add_stmt_operand): Moved from + tree-dfa.c, and use new optype interface. + (note_addressabe, add_call_clobber_ops, add_call_read_ops): Moved from + tree-dfa.c + +2003-12-15 Diego Novillo + + * tree-optimize.c (optimize_function_tree): Call BITMAP_XFREE. + +2003-12-15 Diego Novillo + + PR optimization/12747 + + * tree-cfg.c (verify_addr_expr): Simplify predicates. + * tree-must-alias.c (addresses_needed): Declare as file local. + (can_be_promoted): New. + (tree_compute_must_alias): Call it. + Remove promoted variables from call_clobbered_vars. + (find_addressable_vars): Update comment. + Remove argument. Update callers. + (promote_var): Always clear TREE_ADDRESSABLE. + Don't remove promoted variables from call_clobbered_vars. + If the promoted variable is in the may-alias set of a + non-promotable variable, copy its alias set into the alias set of + the non-promotable variable. + (find_variable_in): Update comment. + * tree-sra.c (can_be_scalarized_p): Reject structures with + __complex__ fields in them. + +2003-12-15 Diego Novillo + Jason Merrill + + PR optimization/12747 + + * Makefile.in (tree-simple.o): Add dependency on bitmap.h and + $(GGC_H). + (GTFILES): Add tree-simple.c. + * tree-simple.c: Include ggc.h and bitmap.h. + (is_gimple_non_addressable_1): Remove. Update all callers. + (types_checked): New local variable. + (types_in_memory): New local variable. + (struct_needs_to_live_in_memory): New. + (needs_to_live_in_memory): New. + (is_gimple_reg): Call it. + (is_gimple_non_addressable): Call it. + (is_gimple_call_clobbered): Call it. + * tree-simple.h (needs_to_live_in_memory): Declare. + +2003-12-14 Andreas Jaeger + + * config/rs6000/rs6000.c (rs6000_output_function_epilogue): Handle + GNU F95. + +2003-12-14 Jan Hubicka + + * cgraphunit.c (cgraph_expand_function): Release function body when no + longer needed. + (lookup_recursive_calls): New function. + (cgraph_decide_recursive_inlining): Likewise. + (cgraph_decide_inlining_of_small_functions): Do recursive inlining. + * tree-inline.c: Include function.h + (copy_body): Choose saved body for recursive inlining. + (initialize_inlined_parameters): Likewise. + (expand_call_inline): Do not verify nodes when recursivly inlining, + insert ret_label into decl map. + * params.def (PARAM_MAX_INLINE_INSNS_RECURSIVE, + PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO, + PARAM_MAX_INLINE_RECURSIVE_DEPTH, + PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO): New argument. + * invoke.texi (max-inline-insns-recursive, max-inline-recursive-depth): + Document. + * Makefile.in (tree-inline.o): Include function.h. + +2003-12-14 Jan Hubicka + + * cgraphunit.c (record_call_1): Do not call analyze_expr hook + * langhooks-def.h (LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR): Kill. + (LANG_HOOKS_CALLGRAPH_INITIALIZER): Update. + * longhooks.h (lang_hooks_for_callgraph): Kill analyze_expr. + +2003-12-13 Jan Hubicka + + * timevar.def (TV_TREE_STMT_VERIFY, TV_CFG_VERIFY, TV_CGRAPH_VERIFY): + New timers. + * tree-cfg.c (verify_stmts): Push/pop timevar. + * cfg.c: Include timevar.h + (verify_flow_info): Push/pop timevar. + * Makefile.in (cfg.o): Add dependnecy on TIMEVARS + + * cgraph.c (cgraph_create_edge): Sanity check for duplicates; + initialize aux. + (cgraph_remove_node): Decrease cgraph_n_nodes; do not clear + DECL_SAVED_TREE when dumping. + (cgraph_dump_node): Break out from ...; print more information. + (cgraph_dump): ... here. + * cgraph.h (cgraph_node): Add aux field. + (dump_cgraph_node, verify_cgraph, verify_cgraph_node): Declare. + (cgraph_mark_inline_edge): Declare + * cgraphunit.c (error_found): New static variable. + (verify_cgraph_node_1): New static function. + (verify_cgraph_node, verify_cgraph): New global function. + (cgraph_expand_function): More sanity checks. + (cgraph_clone_inline_nodes): Destructivly clone DECL_EXTERNAL nodes. + (cgraph_mark_inline_edge): Make global. + (cgraph_decide_inlining): Remove extern inline functions never inlined. + (cgraph_decide_inlining_incrementally): Verify that function body is + still present. + (expand_all_functions): Verify that all nodes are reachable. + (cgraph_optimize): Verify cgraph and memory management. + * tree-inline.c (copy_body_r): All edges must be present. + (expand_call_inline): Sanity check newly created edges and nodes + being inlined. + (optimize_inline_calls): Sanity check that we've inlined everything. + * tree-optimize.c (tree_rest_of_compilation): Clone functions inlined + into cloned node. + +2003-12-13 Jan Hubicka + + * tree-flow.h (tree_ssa_useless_type_conversion_1): Declare. + * tree-flow.c (tree_ssa_useless_type_conversion_1): Break out from + from...; allow complex types whose subtypes match. + (tree_ssa_useless_type_conversion): ... here. + +2003-12-12 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Don't call cleanup_control_expr + here. Instead just note that we need to cleanup the cfg (which + will DTRT). + + * timevar.def (TV_TREE_SSA_THREAD_JUMPS): Kill. + * tree-dump.c (dump_files): Kill .thread dump. + * tree.h (TDI_thread_jumps): Kill. + * tree-flow.h (tree_ssa_dominator_thread_jumps): Kill prototype. + * tree-optimize.c (optimize_function_tree): Kill call to + tree_ssa_dominator_thread_jumps. + * tree-ssa-dom.c (thread_through_phis): Kill. We no longer need + to restrict threading through PHIs. + (tree_ssa_dominator_thread_jumps): Kill. + (tree_ssa_domiantor_optimize_1): Fold back into + tree_ssa_dominator_optimize. + (tree_ssa_dominator_optimize): Mark back edges in the flow graph. + Kill code which conditionalized the walk_tree callbacks based + on thread_through_phis. When threading jumps, reorganize code + so that we can take the affected variables out of SSA form. + Mark new variables created by out-of-ssa code as needing to be + rewritten. + (thread_across_edge): Always allow threading through phis. + (thread_jumps_walk_stmts): Kill. + + * tree-ssa.c (create_temp): When we create a new temporary, make + sure to put it into referenced_vars, give it an ID number and + a suitable mem_tag. + (eliminate_build): If we encounter a PHI argument which is an + SSA_VAR we are not rewriting out of SSA form, then just treat + it like a constant. + (rewrite_vars_out_of_ssa): New function. + * tree-flow.h (rewrite_vars_out_of_ssa): Prototype. + * tree-ssa-live.c (register_ssa_partitions_for_vars): New function. + * tree-ssa-live.h (register_ssa_partitions_for_vars): Prototype. + +2003-12-12 Jan Hubicka + + * tree-inline.c (remap_decl): Avoid invalid sharing. + * cp-tree.h (optimize_function): Kill. + * optimize.c (optimize_function): Kill. + * semantics.c (expand_body): Do not call optimize_function. + +2003-12-12 Jan Hubicka + + * cgraphunit.c (cgraph_optimize): Do not decide inlining when not + inlining + +2003-12-11 Jan Hubicka + + * tree-inline.c (initialize_inlined_parameters): Disable + constant propagation for non-gimple-min-invariant when + preserving gimple form. + +2003-12-11 Jeff Law + + * tree-ssa-ccp.c (widen_bitfield): Clear out unwanted high bits + even if the field's type is unsigned. + * tree-ssa-dom.c (record_equivalences_from_stmt): When creating + equivalences from stores, be more careful about non-constant + stores to bitfields. + +2003-12-11 Diego Novillo + + * opts.c (decode_options): Do not enable the tree loop optimizer by + default. + * tree-ssa-loop.c (tree_ssa_loop_opt): Remove ENABLE_CHECKING + guards. + +2003-12-10 Richard Henderson + + * builtins.c (expand_builtin_profile_func): New. + (expand_builtin): Use it. + * builtins.def (BUILT_IN_PROFILE_FUNC_ENTER): New. + (BUILT_IN_PROFILE_FUNC_EXIT): New. + * function.c (expand_function_start, expand_function_end): Don't + do function instrumentation here. + * gimplify.c (gimplify_function_tree): Do it here. + + * c-opts.c (c_common_post_options): Don't ever use rtl inlining. + +2003-12-10 Diego Novillo + + * ifcvt.c (dead_or_predicable): Initialize local variable + 'earliest'. + * tree-cfg.c (verify_stmt): Fix typo. + * tree-ssa-dom.c (propagate_value): New local function. + (cprop_into_stmt): Call it. + (cprop_into_phis): Call it. + (eliminate_redundant_computations): Call it. + +2003-12-10 Dale Johannesen + + * tree-dfa.c (compute_alias_sets): Don't try to make + GLOBAL_VAR alias itself. + +2003-12-08 Steven Bosscher + + * tree-must-alias.c (tree_compute_must_alias): Use + num_call_clobbered_vars and call_clobbered_var() instead of + poking in the call_clobbered_vars varray directly. + +2003-12-11 Jan Hubicka + + * cgraph.c (cgraph_function_possibly_inlined_p): Fix syntax error on + gcc-2.95. + +2003-12-10 Diego Novillo + + Revert + + 2003-12-07 Richard Henderson + + * c-common.c (c_address_looks_like_offsetof): New. + * c-common.h (c_address_looks_like_offsetof): Declare. + * c-typeck.c (build_unary_op) : Use it. Don't lower + address references not destined for offsetof. + (c_expand_return): Only look inside ARRAY_REF and COMPONENT_REF + when looking for returning address of local variable. + * expr.c (expand_expr_1): Don't dereference size + of unbounded arrays. + * gimplify.c (gimplify_addr_expr): Only fold + address of variable size array elements. + * tree-simple.c (is_gimple_min_invariant): Also check + is_gimple_variable before disallowing offset address for type. + * tree-ssa-ccp.c (maybe_fold_offset_to_aggregate_ref): New. + (maybe_fold_offset_to_component_ref): Use it. + (maybe_fold_stmt_indirect, maybe_fold_stmt_plus): Likewise. + (maybe_fold_offset_to_array_ref): Likewise. + Don't fail for division remainder non-zero. + * varasm.c (initializer_constant_valid_p) : Use + handled_component_p and look inside references. + : Always look past widening casts. + +2003-12-09 Jan Hubicka + + * cgraph.c (cgraph_inline_hash): New global variable. + (cgraph_create_node): Break out of .... + (cgraph_node): ... this one. + (cgraph_redirect_edge_callee): New function. + (cgraph_remove_node): Aggressively elliminate dead nodes; + remove node out of clone list. + (dump_cgraph): Dump inlined_to field; dump uid numbers. + (cgraph_clone_edge): Return edge created. + (cgraph_clone_node): New. + (cgraph_function_possibly_inlined_p): Re-implement using hashtable. + * cgraph.h: Include hashtab.h + (struct cgraph_global_info): Kill inline_once, will be output and + cloned_times fields. Add inlined_to field. + (cgraph_node): Add next_clone. + (cgraph_inline_hash): Declare. + (cgraph_clone_edge): Update prototype. + (cgraph_clone_node, cgraph_redirect_callee): Declare. + * cgraphunit.c (cgraph_optimize_function): Kill. + (cgraph_assemble_function): Kill next_needed to avoid GGC corruption. + (cgraph_analyze_function): Do not intialize cloned_times and + will_be_output. + (cgraph_finalize_compilation_unit): Clear next_needed. + (cgraph_optimize_function): Kill. + (cgraph_expand_function): Do not use cgraph_optimize_function. + (cgraph_estimate_growth, cgraph_mark_inline, + cgraph_check_inline_limits, cgraph_recursive_inlining_p, + cgraph_preserve_function_body_p): Update for explicit clones. + (INLINED_TIMES, SET_INLINED_TIMES, cgraph_inlined_into, + cgraph_inlined_callees, struct cgraph_inline_context, + cgraph_create_inline_context, cgraph_free_inline_context, + cgraph_inline_context_set_caller, cgraph_inline_context_clear_caller, + cgraph_inline_context_set_callee, cgraph_inline_context_clear_callee, + update_callee_keys): Kill. + (cgraph_clone_inlined_nodes, cgraph_mark_inline_edge): New. + (cgraph_decide_inlining_of_small_functions, (cgraph_decide_inlining, + cgraph_decide_inlining_incrementally): Simplify. + * tree-inline.c (typedef struct_inline_data): New field saving_p. + (copy_body_r): Update all clones. + (expand_call_inline): Remove inlined cgraph node. + (save_body): Inicialize id.node and id.saving_p. + * tree-optimize.c (tree_rest_of_compilation): Maintain clone up-to-date + in no-unit-at-a-time mode. + +2003-12-08 Steven Bosscher + + * tree-optimize.c (optimize_function_tree): Move verify_ssa calls + into conditionals. + +2003-12-08 Daniel Berlin + + * tree-alias-ander.c (andersen_same_points_to_set): Fix memory leak. + +2003-12-08 Jeff Law + + * tree-ssa-live.c (register_ssa_partition): Kill legacy code which + recursively called register_ssa_partition on PHI arguments when + SSA_VAR was defined by a PHI_NODE. + +2003-12-08 Jan Hubicka + + * tree-dump.c (dump_files): Fix ordering of tail call pass. + * tree.h (tree_dump_index): Likewise. + +2003-12-08 Zdenek Dvorak + + * Makefile.in (tree-cfg.o): Add gt-tree-cfg.h dependency. + (GTFILES): Add tree-cfg.c. + * tree-cfg.c: Include gt-tree-cfg.h. + (factored_computed_goto_label, factored_computed_goto): + Mark gc roots. + +2003-12-08 Steven Bosscher + Jan Hubicka + + * gengtype-lex.l (IWOrD): Add HOST_WIDEST_INT + * Makefile.in (function.o, reg-stack.o): Add missing dependency on + basic-block.h. + (GTFILES): Add basic-block.h and hwint.h. + * basic-block.h (struct edge_def): Add GTY markers, make garbage + collectable. Make `insns' field GC safe depending on the setting + of cfg_hooks. + (struct basic_block_def): Add GTY markers, make garbage collectable. + (tree_bb_root, tree_phi_root): Kill extern decls. + (ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR): Change from macro to variable + (entry_exit_blocks): Kill. + * cfg.c: Include ggc.h + (bb_pool, edge_pool, entry_exit_blocks): Kill. + (ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR): Define. + (init_flow): Do not create ppols; allocate entry/exit block. + (free_edge, alloc_block, expunge_block, unchecked_make_edge): Use GGC. + (compact_blocks): Don't update tree_bb_root and tree_phi_root. + * cfgrtl.c (rtl_merge_blocks): Clear head pointer. + * regs.h: Protect against multiple inclusion. + * tree-cfg.c (obstack_tree_ann_obstack, first_block_tree_and_obj, + tree_bb_root): Kill. + (build_tree_cfg, create_bb, remove_bb, delete_tree_cfg): Don't + touch tree_bb_root and tree_phi_root. + (create_block_annotations): Do not initialize obstack. + (free_block_annotations): Do not free obstack. + (create_block_annotation): Use GGC. + * tree-dfa.c (tree_phi_root): Kill. + * tree-flow.h (bb_ann, bb_ann_d): Declare. Add `phi_nodes' field. + * tree-phinodes.c (create_phi_node, add_phi_arg, remove_phi_node, + remove_all_phi_nodes_for): Use `phi_nodes' field in the bb + annotation instead of tree_phi_root. + * tree-flow-inline.h (phi_nodes, set_phi_nodes): Likewise. + (add_dom_child, clear_dom_children): Use GGC. + * tree-ssa-pre.c (code_motion): Use `phi_nodes' field in the bb + annotation instead of tree_phi_root. + * varray.h (union varray_data): Make basic_block_def and edge_def + varrays garbage collectable. + +2003-12-07 Richard Henderson + + * c-common.c (c_address_looks_like_offsetof): New. + * c-common.h (c_address_looks_like_offsetof): Declare. + * c-typeck.c (build_unary_op) : Use it. Don't lower + address references not destined for offsetof. + (c_expand_return): Only look inside ARRAY_REF and COMPONENT_REF + when looking for returning address of local variable. + * expr.c (expand_expr_1): Don't dereference size of unbounded arrays. + * gimplify.c (gimplify_addr_expr): Only fold address of variable size + array elements. + * tree-simple.c (is_gimple_min_invariant): Also check + is_gimple_variable before disallowing offset address for type. + * tree-ssa-ccp.c (maybe_fold_offset_to_aggregate_ref): New. + (maybe_fold_offset_to_component_ref): Use it. + (maybe_fold_stmt_indirect, maybe_fold_stmt_plus): Likewise. + (maybe_fold_offset_to_array_ref): Likewise. Don't fail for division + remainder non-zero. + * varasm.c (initializer_constant_valid_p) : Use + handled_component_p and look inside references. + : Always look past widening casts. + +2003-12-07 Zdenek Dvorak + + * tree-cfg.c (compute_dominance_frontiers): Don't assume that + the first block has index 0. + +2003-12-07 Jan Hubicka + + * cgraph.c (create_edge): Rename to ... + (cgraph_create_edge): ... this one; accept call_expr as operand. + (cgraph_edge): New function + (cgraph_remove_edge): Use edge as argument + (cgraph_record_call, cgraph_remove_call): Kill. + (clone_cgraphedge): New function. + * cgraph.h (cgraph_edge): Add call_expr argument; add chain_next. + (cgraph_record_call, cgraph_remove_call): Kill prototype. + (cgraph_remove_call, cgraph_inline_p): Update prototype. + (cgraph_clone_edge): Declare. + * cgraphunit.c (cgraph_finalize_function): Update use of + cgraph_remove_edge + (record_call_1): Use cgraph_create_edge; record builtins too. + (cgraph_create_edges): Accept node instead of decl. + (cgraph_analyze_function): Update use cgraph_create_edges. + (cgraph_inline_p): Accept edge. + * tree-inline.c (inline_data): Replace decl and current_decl + by node and current_node. + (copy_body_r): Clone edges. + (expand_call_inline): Do not create inlined edges. + (optimize_inline_call): Set id->current_node, id->node. + * tree-optimize.c (tree_rest_of_compilation): Update cgraph edges after + compiling. + +2003-12-07 Diego Novillo + + * tree-ssa-loop.c (dump_file, dump_flags): Only declare with + checking enabled. + (tree_ssa_loop_opt): Mark arguments with ATTRIBUTE_UNUSED. + +2003-12-07 Richard Henderson + + * function.h (struct function): Add last_label_uid. + * tree-cfg.c (set_bb_for_stmt): Use it. + (delete_tree_cfg): Clear label_to_block_map. + + * gimple-low.c (lower_stmt_body): Export. + (lower_stmt): Allow data to be null. + * gimplify.c (declare_tmp_vars): Make static. + (push_gimplify_context): Export. + (pop_gimplify_context): Export. Put the temps somewhere. + (gimplify_body): Don't declare_tmp_vars here. + * tree-flow.h, tree-simple.h: Update for new decls. + + * tree-mudflap.c (mf_build_string): New. + (mudflap_c_function_decls): Push and pop gimplify context, don't + gimplify here. Dump pass 1. + (mudflap_c_function_ops): Similarly. + (mf_decl_cache_locals): Gimplify eveything as we go along. + (mf_build_check_statement_for): Likewise. + (mf_mostly_copy_tree_r): Remove. + (mf_varname_tree): Use mf_build_string. + (mf_file_function_line_tree): Rewrite. + (mf_offset_expr_of_array_ref): Remove. + (mx_xfn_indirect_ref): Remove. + (mf_xform_derefs_1): New. + (mf_xform_derefs): Rewrite to expect gimple. + (mx_register_decls): Use build_function_call_expr. + (mudflap_enqueue_constant): Use mf_build_string. + * tree-optimize.c (tree_rest_of_compilation): Reorder mudflap bits. + * tree-dump.c (dump_files): Split mudflap to parts 1 and 2. + * tree.h (enum tree_dump_index): Likewise. + +2003-12-06 Zdenek Dvorak + + * tree-ssa-loop.c: New. + * Makefile.in (tree-ssa-loop.o): New. + * common.opt (ftree-loop-optimize): Add. + * flags.h (flag_tree_loop): Declare. + * opts.c (decode_options): Enable flag_tree_loop at -O1. + (common_handle_option): Handle OPT_ftree_loop_optimize. + * timevar.def (TV_TREE_LOOP): New. + * toplev.c (flag_tree_loop): New. + (f_options): Add -ftree-loop-optimize. + * tree-cfg.c (build_tree_cfg): Remove disabled loop optimizer + initialization. + (tree_make_forwarder_block): Update phi nodes. + (tree_loop_optimizer_init): Don't call force_single_succ_latches. + (tree_try_redirect_by_replacing_jump): Comment fix. + * tree-dump.c (dump_files): Add .loop dump. + * tree-flow.h (tree_ssa_loop_opt, set_phi_nodes): Declare. + * tree-optimize.c (optimize_function_tree): Call tree_ssa_loop_opt. + * tree.h (enum tree_dump_index): Add TDI_loop. + * tree-flow-inline.h (set_phi_nodes): New. + * doc/invoke.texi (-fdump-tree-loop, -ftree-loop-optimize): Document. + +2003-12-05 Jeff Law + + * tree-dfa.c (mark_new_vars_to_rename): Change VARS_TO_RENAME to be + a "bitmap" instead of an "sbitmap". Callers updated. + * tree-must-alias.c (promote_var): Likewise. + (tree_compute_must_alias): Likewise. + * tree-phinodes.c (remove_all_phi_nodes_for): Likewise. + * tree-ssa-dom.c (tree_ssa_dominator_thread_jumps): Likewise. + (tree_ssa_dominator_optimize): Likewise. + (tree_ssa_dominator_optimize_1): Likewise. + * tree-ssa-pre.c (pre_expression): Likewise. + (tree_perform_ssapre): Likewise. + * tree-ssa.c (rewrite_into_ssa): Likewise. + (insert_phi_nodes): If VARS_TO_RENAME is zero, then examine + each node to determine if we need to insert a PHI. + (prepare_operand_for_rename): If VARS_TO_RENAME is zero, then + assume the operand needs renaming. + * tree-ssa-ccp.c (substitute_and_fold): Change VARS_TO_RENAME to + be a "bitmap" instead of an "sbitmap". Callers updated. + (tree_ssa_ccp): Likewise. Also make sure timevar_pop encloses + entire function. + (scalarize_modify_expr): Likewise. + * tree-sra.c (create_scalar_copies): Change VARS_TO_RENAME to + be a "bitmap" instead of an "sbitmap". Callers updated. + (tree_sra): Likewise. + * tree-optimize.c (optimize_function_tree): Make VARS_TO_RENAME + be a "bitmap" instead of an "sbitmap". + * tree-flow.h: Update various prototypes. + +2003-12-05 Zdenek Dvorak + + * tree-cfg.c (remove_useless_stmts_goto, remove_useless_stmts): Move + handling of factored_computed_goto ... + (disband_implicit_edges): ... here. + +2003-12-05 Jan Hubicka + + * tree-eh.c (tree_could_trap_p): Fix warning. + * expr.c (expand_expr): Fix warning on uninitialized last. + +2003-12-04 Jeff Law + + * tree-ssa.c (rewrite_trees): Do not unconditionally overwrite + variables set by statements. Let replace_variable do any + required rewriting. + +2003-12-04 Richard Henderson + + * c-parse.in (primary): Use annotate_with_locus instead of + STMT_LINENO for STMT_EXPR. + * c-simplify.c (gimplify_stmt_expr): Likewise. + +2003-12-04 Jan Hubicka + + * tree-dump.c (dump_files): Reorder tailcall and mustalias + * tree.h (tree_dump_index): Likewise. + * tree-optimize.c (optimize_function_tree): Do tail call after mustalias. + +2003-12-04 Diego Novillo + + * tree-dfa.c (opf_none, opf_is_def, opf_no_vops): Change to #define. + +2003-12-04 Canqun Yang + + * stor-layout.c (update_alignment_for_field): Export. + * tree.h (update_alignment_for_field): Declare. + +2003-12-03 Andrew Haley + + * tree-eh.c (tree_could_trap_p): Add division instructions. + * expr.c (expand_expr): Check the EH region of an expression and + mark all the insns that result from its expansion with the + appropriate REG_EH_REGION. + +2003-12-03 Jan Hubicka + + * tree-cfg.c (verify_addr_expr, verify_stmt, tree_node_shared_p, + verify_stmts): New functions. + (verify_flow_info): Remove PHI checking code. + * tree-flow.h (verify_stmt, verify_stmts): Declare. + * tree-inline.h (walk_tree, walk_tree_without_duplicates): Move + prototypes ... + * tree.h (walk_tree, walk_tree_without_duplicates): ... here. + +2003-12-03 Jan Hubicka + Diego Novillo + + * tree-ssa.c (verify_def, verify_use, verify_phi_args): New static + functions. + (verify_ssa): New global function. + * tree-flow.h (verify_ssa): Declare. + * tree-optimize.c (optimize_function_tree): Call it. + +2003-12-03 Diego Novillo + + * timevar.def (TV_TREE_SSA_VERIFY): New timer. + * tree-sra.c (create_scalar_copies): Always mark the previous + variables on the LHS for renaming. + Do not emit unnecessary assignments from VA_ARG_EXPRs. + (scalarize_modify_expr): Similarly, when scalarizing the LHS of a + COMPONENT_REF assignment. + * tree-must-alias.c (tree_compute_must_alias): Do not promote + variables with hidden uses. + * tree-ssa-ccp.c (set_rhs): When replacing the whole statement, reset + SSA_NAME_DEF_STMT for all the SSA_NAMEs in vdef and def + operands. + +2003-12-03 Zdenek Dvorak + Diego Novillo + + * tree-dfa.c (opf_no_vops): New. + (add_stmt_operand): Don't create virtual operands when opf_no_vops + is passed in flags. + (get_expr_operands): Set opf_no_vops flag before diving into the + operand of an ADDR_EXPR node. + +2003-12-03 Richard Henderson + + * tree-simple.c (is_gimple_min_invariant): Disallow offset of + address of a scalar. + + * c-parse.in (primary): Set STMT_LINENO on STMT_EXPR. + * c-simplify.c (gimplify_stmt_expr): Be prepared for last_stmt + to be null. + +2003-12-03 Daniel Berlin + + Fix PR 13177 + * tree-ssa-pre.c (code_motion): Do phi nodes last, and rearrange + how we decide what temporary to choose so that we get it right. + +2003-12-03 Zdenek Dvorak + + * tree-dfa.c (get_expr_operands): Don't record VUSEs for invariant + adresses. + +2003-12-03 Brian Booth + + * tree-pretty-print.c (dump_phi_nodes): Removed superfluous ampersand. + +2003-12-03 Jeff Law + + * ggc-page.c: Resync with mainline sources. Remove tree-ssa + specific hack which disabled special GC pagesizes for 2 operand + tree expressions. + + * tree-ssa.c (mark_def_sites): Call prepare_operand_for_rename + on the VDEF_RESULT as well, providing a dummy uid argument. + + * tree-phinodes.c: Include rtl.h for ceil_log2. + (ideal_phi_node_len): New function. + (resize_phi_node): Make static. + (make_phi_node): Use ideal_phi_node_len. + (add_phi_arg): Likewise. + * tree.h (resize_phi_node): Remove prototype. + * Makefile.in (tree-phinodes.o): Depend on $(RTL_H). + +2003-12-03 Zdenek Dvorak + + * tree-cfg.c: (make_edges): Eliminate fallthru to exit. + (make_ctrl_stmt_edges): Nonlocal goto handling moved to + make_goto_expr_edges. + (make_goto_expr_edges): Remove simple gotos. + (cfg_remove_useless_stmts_bb): Goto removal cancelled. + (cleanup_cond_expr_graph, cleanup_switch_expr_graph): + Replaced by ... + (cleanup_control_expr_graph): New. + (cleanup_control_flow): Use it. + (disband_implicit_edges): New. + (tree_find_edge_insert_loc): Never insert before a control statement. + (tree_split_edge, thread_jumps, tree_try_redirect_by_replacing_jump, + tree_redirect_edge_and_branch): Work over no-gotos form. + (tree_verify_flow_info): Check no-gotos form invariants. + * tree-pretty-print.c (pp_cfg_jump, dump_implicit_edges): New. + (dump_generic_bb_buff): Call dump_implicit_edges. + * tree-flow.h (cleanup_cond_expr_graph, cleanup_switch_expr_graph): + Declaration removed. + (cleanup_control_expr_graph, delete_tree_ssa, disband_implicit_edges): + Declare. + * tree-optimize.c (tree_ssa_finish): New. + (optimize_function_tree): Call it. + * tree-ssa-dom.c (thread_jumps_walk_stmts, optimize_stmt): Use + cleanup_control_expr_graph. + * tree-ssa.c (delete_tree_ssa): Export, work even if there are no + referenced_vars. + (rewrite_out_of_ssa): Don't call it. + +2003-12-03 Jan Hubicka + + * tree-ssa.dom.c (tree_ssa_domionator_thread_jumps): Mark back edges. + (thread_across_edge): Do not thread across loop headers. + + * Makefile.in (tree-optimize.o): Depend on cgraph.h + * cgraph.h (cgraph_preserve_function_body_p): Declare. + * cgraphunit.c (cgraph_preserve_function_body_p): New function. + * tree-optimize.c: Include cgraph.h + (clear_decl_rtl): Kill. + (tree_rest_of_compilation): Use cgraph_preserve_function_body_p; + do not clear DECL_RTL; do final ggc in the pushed context for nested + functions; + +2003-12-02 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Accept and pass down dominator + walker structure instead of individual varrays. Callers updated. + (eliminate_redundant_computations): Likewise. + (simplify_rhs_and_lookup_avail_expr): Likewise. Cache and update + a dummy COND_EXPR when querying the hash tables when transforming + DIV/MOD into RSHIFT/BIT_AND or ABS_EXPR into NEG_EXPR. + (dom_opt_walk_stmts): Don't reload the block data pointer each + iteration of the loop. Load it once outside the loop. + + * tree-dfa.c (cleanup_operand_arrays): Avoid creating a new + varray for the vuse operands. + + * tree-ssa-dom.c (extract_range_from_cond): Use int_const_binop to + avoid creating useless tree nodes. + + * tree-phinodes.c (add_phi_arg): If we receive a new node from + resize_phi_node, then release the old node and update the PHI + chain. + +2003-12-02 Brian Booth + + * tree-pretty-print.c (dump_phi_nodes): Added code to always show phi + nodes of regular gimple scalars. + (dump_generic_bb_buff): Removed condition upon which to show phi nodes. + +2003-12-02 Jan Hubicka + + * tree-optimize.c (optimize_function_tree): Invoke ggc_collect in + between optimization passes. + +2003-12-02 Daniel Berlin + + * tree-sra.c (can_be_scalarized_p): Print details about why something + could not be scalarized to the dump file. + +2003-12-01 Jeff Law + + * Makefile.in (OBJS-common): Add tree-phinodes.o. + (tree-phinodes.o): Add dependencies. + (GTFILES): Add tree-phinodes.c. + * tree-phinodes.c: New file. + * tree-dfa.c (create_phi_node): Moved to tree-phinodes.o. + (add_phi_arg, remove_phi_arg, remove_phi_arg_num): Similarly. + (remove_phi_node, remove_all_phi_nodes_for): Similarly. + * tree-ssa.c (init_tree_ssa): Initialize PHI node management. + (delete_tree_ssa): Finalize PHI node management. + * tree.c (dump_tree_statistics): Dump PHI node stats. + (make_phi_node, resize_phi_node): Moved to tree-phinodes.o. + * tree.h (init_phinodes): Prototype. + (fini_phinodes, release_phi_node): Likewise. + (phinodes_print_statistics): Likewise. + +2003-12-01 Richard Henderson + + * tree-dfa.c (get_expr_operands): Don't handle PLUS_EXPR inside + INDIRECT_REF. + * tree-ssa-ccp.c (maybe_fold_offset_to_array_ref): Use int_const_binop. + (maybe_fold_offset_to_component_ref): Likewise. + (maybe_fold_stmt_indirect): Likewise. + (maybe_fold_stmt_plus): Expand ARRAY_REF when seen with addend. + * fold-const.c (int_const_binop): Export. + * tree.h (int_const_binop): Declare. + +2003-12-01 Jan Hubicka + + * basic-block.h (tree_phi_root): New variable. + * cfg.c: Include tree-flow.h. + (compact_blocks): Compact tree_phi_root + * tree-cfg.c (build_tree_cfg): Initialize tree_phi_root. + (create_bb, remove_bb, delete_tree_cfg): Update tree_phi_root. + * tree-dfa.c (tree_phi_root): Declare. + (create_phi_node, add_phi_arg, remove_phi_node, + remove_all_phi_nodes_for): Always use accessor functions for + getting, varray for setting phis. + * tree-ssa-pre.c (code_motion): Likewsie. + * tree-flow-inline.h (phi_nodes): Use varray. + * tree-flow.h (bb_ann_d): Remove phi_nodes. + + * tree-ssanames.c (free_ssanames): Do not use deleteable GTY flag. + +2003-11-30 Jan Hubicka + + * tree-optimize.c (tree_rest_of_compilation): Move ggc_collect call to + the end of function; keep clearing of DECL_SAVED_TREE to the cgraph + code. + +2003-11-30 Jan Hubicka + + * cgraphunit.c (cgraph_inline_context): New structure. + (cgrpah_mark_inline, cgraph_check_inline_limits): Use context + instead of passing all arguments by hand. + (cgraph_create_inline_context, cgraph_free_inline_context, + cgraph_inline_context_set_caller, cgraph_inline_context_clear_caller, + cgraph_inline_context_set_callee, cgrpah_inline_context_clear_callee, + cgraph_recursive_inlining_p): New static function. + (cgraph_decide_inline*): Reorganize to use context. + +2003-11-30 Paul Brook + + * Makefile.in (GTFILES): Remove stray '\'. + +2003-11-30 Daniel Berlin + + * c-config-lang.in: Move tree-alias-* from here + * Makefile.in (GTFILES): To here. + * tree-alias-ander.c: Include bitmap.h + (andersen_function_call): Updated to take address of variables + in an ADDR_EXPR in a CALL_EXPR. + * tree-alias-common.h (struct tree_alias_ops): Update arguments to + function_call. + * tree-alias-type.h (struct alias_typevar_common): Add varnum. + * tree-alias-common.c: Include bitmap.h, and function.h. + s/global_var/pta_global_var/g. + (addrargs): New static variable. + (pta_global_var): Ditto. + (find_func_decls): Remove. + (find_func_aliases): Take one argument, update all callers. + Handle (cast) [addr-expr] [var]. + Handle COMPONENT_REF of an INDIRECT_REF. + Pass info about ADDR_EXPR arguments to function_call function. + (deal_with_call_aliasing): New function. + (call_may_return): New function. + (get_alias_var_decl): Call find_func_aliases on the DECL_INITIAL + of a global var. + Use ALIAS_TVAR_VARNUM, instead of VARRAY_ACTIVE_SIZE (alias_vars) - 1. + (get_alias_var): Handle REALPART_EXPR and IMAGPART_EXPR. + Return NULL in default case. + (intra_function_call): Remove wrong code. + (create_fun_alias_var): Use simple_assign, not addr_assign. + Set up ALIAS_TVAR_VARNUM when creating an alias var. + (create_fun_alis_var_ptf): Ditto on ALIAS_TVAR_VARNUM. + (create_alias_var): Ditto. + (create_alias_vars): Build pta_global_var here. + Walk unexpanded_var_list. + Walk the statements in basic blocks. + (delete_alias_vars): Correct ip_partial case. + Free addrargs. + (init_alias_vars): Create addrargs. + +2003-11-29 Jan Hubicka + + * Makefile.in (tree-ssanames.o): Depend on gt-tree-ssanames.h. + (tree-eh.o): Depend on gt-tree-eh.h. + (gr-tree-ssanames.h, gt-tree-eh.h): New targets. + (GTFILES): Add tree-ssanames.c, tree-eh.c + * tree-eh.c: Include ggc.h and gt-tree-eh.h + (lower_eh_constructs): Allecate throw_stmt_table in ggc. + * tree-ssanames.c: Include ggc.h and gt-tree-ssanames.h + + * function.h (struct function): Add saved_tree/saved_args. + * toplev.c (rest_of_compilation): Move code to clear cfun and + DECL_SAVED_INSNS and call to ggc_collect to ... + * tree-optimize.c (tree_rest_of_compilation): ... this function. Use + cfun to save/restore function body. + +2003-11-28 Richard Henderson + + * gimplify.c (create_tmp_var_raw): Split out from create_tmp_var. + (create_tmp_var): Use it. + (create_tmp_alias_var): Remove. + * tree-alias-common.c, tree-dfa.c: Use create_tmp_var_raw instead. + * tree-simple.h: Update decls. + +2003-11-28 Richard Henderson + + * gimple-low.c (lower_function_body): Call lower_bind_expr + to handle the outermost BIND_EXPR. + +2003-11-28 Jan Hubicka + + * tree-ssa.c (remove_annotations_r): Kill. + (delete_tree_ssa): Remove annotations using statement walk; + kill argument fndecl. + (rewrite_out_of_ssa): Update call. + +2003-11-27 Andrew MacLeod + + * tree-ssa-live.c (register_ssa_partition): Abort if a virtual SSA + version is registered. + (create_ssa_var_map): Always process PHI nodes. + * tree-ssa.c (Eliminate_virtual_phis): Rename from + eliminate_extraneous_phis, and look specifically for virtuals. + (rewrite_out_of_ssa): Eliminate virtual PHI nodes before building + partitions. + +2003-11-27 Zdenek Dvorak + + * tree-ssa-ccp.c (get_strlen): Mark the visited variables. + (ccp_fold_builtin): Changed due to changed calling convention of + get_strlen. + +2003-11-26 Diego Novillo + + Revert + + 2003-11-25 Jeff law + + * Makefile.in (OBJS-common): Add tree-phinodes.o. + (tree-phinodes.o): Add dependencies. + * tree-phinodes.c: New file. + * tree-dfa.c (create_phi_node): Moved to tree-phinodes.o. + (add_phi_arg, remove_phi_arg, remove_phi_arg_num): Similarly. + (remove_phi_node, remove_all_phi_nodes_for): Similarly. + * tree-ssa.c (init_tree_ssa): Initialize PHI node management. + (delete_tree_ssa): Finalize PHI node management. + * tree.c (dump_tree_statistics): Dump PHI node stats. + (make_phi_node, resize_phi_node): Moved to tree-phinodes.o. + * tree.h (init_phinodes): Prototype. + (fini_phinodes, release_phi_node): Likewise. + (phinodes_print_statistics): Likewise. + +2003-11-25 Jan Hubicka + + * tree-mustalias.c (promote_var): Do not clear + may_point_to_global_mem. + +2003-11-25 Jeff law + + * domwalk.c (walk_dominator_tree): Indicate to the block local + data initializer if the block local data is new or recycled. + * domwalk.h (struct dom_walk_data): Corresponding changes. + * tree-ssa-dom.c (dom_opt_initialize_block_local_data): Accept and use + "recycled" argument. For recycled structures, only clear varrays + that have been initialized. For new blocks, do not initialize + varrays here. + (dom_opt_finalize_block): When threading across edges, if the + true/false varrays have not been initialized, then the limit is zero. + Only clear block local varrays that have been initialized. + (record_equivalences_from_incoming_edge): If necessary, initialize + block local const_and_copies. + (dom_opt_walk_stmts): If necessary, initialize block local + stmts_to_rescan. + (record_var_is_nonzero): If necessary, initialize block local + nonzero_vars. + (record_cond_is_true): If necessary, initialize block local + true_exprs. + (record_cond_is_false): If necessary, initialize block local + false_exprs. + (lookup_avail_expr): If necessary, initialize block local + avail_exprs. + (record_range): If necessary, initialize block local vrp_varaibles. + * tree-ssa.c + * tree-ssa.c (rewrite_initialize_block_local_data): Accept and use + "recycled" argument. For recycled structures, only clear varrays + that have been initialized. For new blocks, do not initialize + varrays here. + (rewrite_finalize_block): Only clear block local varrays that have + been initialized. + (register_new_def): If necessary, initialize block local defs. + + * tree-ssa-dom.c (get_eq_expr_value): Return a struct rather than + a tree node. + (record_equivalences_from_incoming_edge): Corresponding changes. + (find_equivalent_equality_comparison): Use tree_int_cst_XXX rather + then building and folding nodes. + (simplify_cond_and_lookup_avail_expr): Likewise. + + * Makefile.in (OBJS-common): Add tree-phinodes.o. + (tree-phinodes.o): Add dependencies. + * tree-phinodes.c: New file. + * tree-dfa.c (create_phi_node): Moved to tree-phinodes.o. + (add_phi_arg, remove_phi_arg, remove_phi_arg_num): Similarly. + (remove_phi_node, remove_all_phi_nodes_for): Similarly. + * tree-ssa.c (init_tree_ssa): Initialize PHI node management. + (delete_tree_ssa): Finalize PHI node management. + * tree.c (dump_tree_statistics): Dump PHI node stats. + (make_phi_node, resize_phi_node): Moved to tree-phinodes.o. + * tree.h (init_phinodes): Prototype. + (fini_phinodes, release_phi_node): Likewise. + (phinodes_print_statistics): Likewise. + +2003-11-25 Jan Hubicka + + * tree-inline.c (save_body): New body + * tree-inline.h (save_body): Declare. + * tree-optimize.c (tree_rest_of_compilation): Save function tree + properly. + +2003-11-24 Richard Henderson + + * gimplify.c (canonicalize_addr_expr): New. + (gimplify_conversion): Use it. Canonicalize after nop cast removal. + * tree-simple.c (is_gimple_min_invariant): Remove STRING_CST cast + special case. + +2003-11-24 Jeff Law + + * flow.c (count_or_remove_death_notes_bb): New. Extracted from + count_or_remove_death_notes. + (count_or_remove_death_notes): Use EXECUTE_IF_SET_IN_SBITMAP. + +2003-11-24 Richard Henderson + + PR 13174, PR 13143 + * gimplify.c (cpt_same_type): Allow different ARRAY_TYPEs with + the same base type. + +2003-11-24 Daniel Berlin + + Fix PR/13163 + * tree-ssa-pre.c (append_eref_to_block): Delete. + (insert_euse_in_preorder_dt_order_1): Ditto. + (insert_one_operand): Take an extra argument, because + avdefs may need to be changed. + (clear_all_eref_arrays): Use FOR_ALL_BB. + (insert_occ_in_preorder_dt_order): Stop appending to bb eref arrays. + Use FOR_ALL_BB. + (insert_euse_in_preorder_dt_order): Rewrite to just build a new varray + with only the EPHI's and EUSE's, and then sort it. + (pre_expression): Don't use bb based erefs array when printing + expressions. + (split_critical_edges): Just use FOR_ALL_BB. + (tree_perform_ssapre): Pre-split entry block successor edge if the + successor block has multiple preds. + + * tree-flow.h (struct bb_ann_d): Remove erefs varray. + +2003-11-24 Daniel Berlin + + * tree-cfg.c (cleanup_tree_cfg): FOR_EACH_BB -> FOR_ALL_BB when + clearing dom children, because the entry block has dom_children + too. + * tree-ssa.c (build_dominator_tree): Ditto. + +2003-11-24 Diego Novillo + + * tree-cfg.c (compute_dominance_frontiers_1, + compute_dominance_frontiers): Move from ssa.c. + * tree-flow.h (compute_dominance_frontiers): Declare. + * Makefile.in (tree-ssa.o, tree-ssa-live.o, tree-ssa-pre.o, + tree-optimize.o): Don't depend on ssa.h. + * tree-ssa.c: Don't include ssa.h. + * tree-ssa-live.c: Likewise. + * tree-ssa-pre.c: Likewise. + * tree-optimize.c: Likewise. + +2003-11-24 Jan Hubicka + + * fold-const.c (fold): Do not return early when + optimizing COMPONENT_REF and constant. + +2003-11-24 Richard Henderson + + * objc/objc-act.c (build_protocol_expr): Use convert instead of + smashing TREE_TYPE. + +2003-11-23 Andrew MacLeod + + * tree-ssa-live.h (SSANORM_PERFORM_TER, SSANORM_COMBINE_TEMPS, + SSANORM_REMOVE_ALL_PHIS): New flag macros. + * tree-ssa.c (replace_variable): Return true if var was rewritten. + (eliminate_extraneous_phis): Dump var map to file if checking triggers + an abort. + (rewrite_trees): Set modified_stmt if stmt was changed. + (remove_ssa_form): Move more of rewrite_out_of_ssa to make it serve + all the same functions based on new flags in tree-ssa-live.h. + (rewrite_out_of_ssa): Call remove_ssa_form. + +2003-11-23 Jan Hubicka + + * tree-cfg.c (tree_verify_flow_info): Check that ENTRY/EXIT block + has no instructions associated with it. + +2003-11-22 Jeff Law + + * tree-ssa-names.c (release_ssa_name): Use SSA_NAME_IN_FREE_LIST + instead of checking SSA_NAME_DEF_STMT being null. + * tree.h (SSA_NAME_DEF_STMT): Use chain field rather than the + def_stmt field. + (SSA_NAME_OCCURS_IN_ABNORMAL_PHI): Use existing flag from tree_common. + (SSA_NAME_IN_FREE_LIST): Define. + (struct tree_ssa_name): Kill DEF_STMT and OCCURS_IN_ABNORMAL_PHI fields. + +2003-11-22 Zdenek Dvorak + + * tree-pretty-print.c (dump_generic_node): Remove superfluous ';'. + +2003-11-22 Diego Novillo + + * Makefile.in (simple-break-elim.o): Remove. + (simple-goto-elim.o): Remove. + (tree-dchain.o): Remove. + * simple-break-elim.c: Remove. + * simple-goto-elim.c: Remove. + * tree-dchain.c: Remove. + * tree-dchain.h: Remove. + +2003-11-22 Daniel Berlin + + * tree-ssa-pre.c (build_dfs_id_array_1): > should be >= + (build_dfn_array): Ditto. + +2003-11-21 Diego Novillo + + * Makefile.in (tree-dfa.o): Add dependency on $(TREE_DUMP_H) + * tree-dfa.c: Include tree-dump.h + (compute_alias_sets): Call dump_function_to_file. + (may_access_global_mem_p): Check if the base address of _REF nodes + may point to global memory. + + * cfgcleanup.c (try_crossjump_to_edge): Initialize newpos1 and + newpos2. + +2003-11-21 Jeff Law + + Revert: + + 2003-11-21 Jan Hubicka + + * tree-dfa.c (get_expr_operands): Fix handling of CALL_EXPR. + * tree-must-alias.c (tree_compute_must_alias): promote pointers. + (find_addressable_vars): Deal with complex constant + expressions; do not clear may_point_to_global_mem. + +2003-11-21 Jeff Law + + * Makefile.in (domwalk.o): Depend on $(GGC_H). + * domwalk.c: Include ggc.h. + (walk_dominator_tree): Manage allocation/deallocation and + pushing/popping of the toplevel block data pointer here. + Use callback to initialize the block local data. + (init_walk_dominator_tree): New function. + (fini_walk_dominator_tree): Likewise. + * domwalk.h (struct dom_walk_data): Add callback to initialize + block local data. Add field for sizeof block local data. + Add "private" field free_block_data. + (init_dominator_tree, fini_dominator_tree): Prototype. + * tree-ssa-dom.c (dom_opt_initialize_local_data): New function. + (tree_ssa_dominator_optimize_1): Initialize new fields in the + dominator walker structure. Initialize and finalize the dominator + walker. Slightly reorder code to make it more readable.. + (dom_opt_initialize_block): No longer deal with allocation and + initialization of block local data. + (dom_opt_finalize_block): Similarly for deallocation of block + local data. + * tree-ssa.c (rewrite_block_data): New structure. + (rewrite_initialize_block_local_data): New function. + (rewrite_initialize_block): No longer deal with allocation and + initialization of block local data. + (rewrite_into_ssa): Initialize new fields in the dominator walker + structure. Initialize and finalize the dominator walker. + (rewrite_initialize_block): No longer deal with allocation and + initialization of block local data. + (rewrite_optimize_stmts): Deal with changes in the dominator + walker structure. + (rewrite_finalize_block): No longer with deallocation of block + local data. + + * tree-dfa.c (add_vdef, cleanup_voperand_arrays): Use NUM_VDEFS. + (mark_new_vars_to_rename, collect_dfa_status_r): Likewise. + * tree-pretty-print.c (dump_vops): Likewise. + * tree-sra.c (create_scalar_copies): Likewise. + * tree-ssa-dce.c (stmt_useful_p, process_worklist): Likewise. + * tree-ssa-live.c (create_ssa_var_map): Likewise. + (calculate_live_on_entry): Likewise. + * tree-ssa-pre.c (process_left_occs_and_kills): Likewise. + * tree-ssa.c (mark_def_sites, rewrite_stmt): Likewise. + * tree.h (NUM_VDEFS): Define. + * tree-ssa-ccp.c (visit_stmt): Use NUM_VDEFS. Fix thinko in last + change. + (initialize): Use NUM_VDEFS. + + * tree-dfa.c (add_vdef): Revamp to handle new method for + recording vdefs. + (cleanup_operand_arrays): Similarly. + * tree-sra.c (create_scalar_copies): Similarly. + * tree-ssa-ccp.c (visit_stmt, initialize): Similarly. + * tree-ssa-dce.c (stmt_useful_p, process_worklist): Similarly. + * tree-ssa-dom.c (cprop_into_stmt): Similarly. + (record_equivalences_from_stmt): Similarly. + * tree-ssa-live.c (create_ssa_var_map): Similarly. + (calculate_live_on_entry): Similarly. + * tree-ssa.c (mark_def_sites, rewrite_stmt): Similarly. + * tree-ssa-pre.c (process_left_occr_and_kills): Similarly. + * tree-inline.c (estimate_num_insns_1): Kill VDEF_EXPR. + * tree-pretty-print.c (dump_generic_node) Kill VDEF_EXPR. + (dump_vops): Dump VDEFs here. + * tree.c (build_vdef_expr): Kill. + * tree.h (build_vdef_expr): Kill prototype. + (VDEF_RESULT, VDEF_OP): Revamp to handle new method for recording + vdefs. + * tree.def (VDEF_EXPR): Kill. + + * tree-cfg.c (cfg_remove_useless_stmts): Set both VAR and VAL to + NULL anytime one of them is determined to be invalid. + +2003-11-21 Andrew MacLeod + + * tree-ssa-live.c (compact_var_map): Fix typo. Clear correct field. + (calculate_live_on_entry): Remove unneeded stmt. + * tree-ssa-live.h (version_to_var): New. Return variable associated + with a specific SSA version. + * tree-ssa.c (eliminate_build): Add check that ignored results don't + have important arguments. Allow ignored results. + (coalesce_abnormal_edges): Allow non-relevant results to be ignored. + (eliminate_extraneous_phis): Allow non-relevant results. Check that + no important arguments are being missed. + (coalesce_vars): Non-partition variables are allowed now, just ignored. + (rewrite_trees): New. Split out from rewrite_out_of_ssa. Perform tree + rewriting step. + (remove_ssa_form): New. Allow rewriting of just specified variables. + (rewrite_out_of_ssa): Use rewrite_trees and reorganize slightly to + accommodate typechecking in eliminate_extraneous_phis. + +2003-11-21 Jan Hubicka + + * tree-dfa.c (get_expr_operands): Fix handling of CALL_EXPR. + * tree-must-alias.c (tree_compute_must_alias): promote pointers. + (find_addressable_vars): Deal with complex constant expressions; + do not clear may_point_to_global_mem. + +2003-11-21 Jan Hubicka + + * parser.c (cp_parser_postfix_expression): Initialize 's' to + NULL_TREE. + +2003-11-20 Richard Henderson + + * Makefile.in (bitmap.o-warn, caller-save.o-warn, combine.o-warn, + cgraphunit.o-warn, c-semantics.o-warn, emit-rtl.o-warn, expr.o-warn, + fold-const.o-warn, genattrtab.o-warn, regmove.o-warn, tree.o-warn, + varasm.o-warn, f/expr.o-warn, profile.o-warn): Remove. + * bitmap.c (bitmap_first_set_bit): Abort if no non-zero word found. + (bitmap_last_set_bit): Likewise. + * combine.c (get_pos_from_mask): Always set *plen. + +2003-11-20 Richard Henderson + + * tree-dfa.c (get_expr_operands): Remove handling of PLUS_EXPR + inside INDIRECT_REF. + +2003-11-20 Diego Novillo + + * tree-nomudflap.c (nogo): Fix prototype. + +2003-11-20 Richard Henderson + + * except.c (output_function_exception_table): Strip nops. + * gimplify.c (gimplify_addr_expr): Kill missing cast workaround. + (cpt_same_type, check_pointer_types_r): New. + (gimplify_body): Call it. + * tree-inline.c (insert_decl_map): New. + (remap_decl, remap_type, remap_block, copy_body_r, + initialize_inlined_parameters, declare_return_variable, + remap_save_expr, mark_local_for_remap_r): Use it. + +2003-11-20 Frank Ch. Eigler + + libstdc++/11696 + * c-pragma.c (handle_pragma_redefine_extname): Define always. + (init_pragma): Activate #pragma redefine_extname for mudflap. + + * tree-inline.c (copy_tree_r): Propagate mf_marked-ness. + * tree-mudflap.c (mudflap_c_function): Break into new + _decls and _ops functions. + (mudflap_c_function_decls): Avoid unnecessary tree copying. + (mudflap_c_function_ops): Ditto. Gimplify explicitly only for + tree dumping. + * tree-nomudflap.c: Add new stub functions. Simplify error + message emission throughout. + * tree-mudflap.h: Corresponding changes. + * tree-optimize.c (tree_rest_of_compilation): Call the _decl + instrumentation before gimplification and ssa optimizations; + call the _ops instrumentation after ssa optimizations. + +2003-11-20 Diego Novillo + + Initial fix for PR optimization/12747 + + * Makefile.in (OBJS): Add tree-sra.o + * common.opt (ftree-sra): Add. + * flags.h (flag_tree_sra): Declare. + * gimplify.c (gimplify_addr_expr): Set TREE_INVARIANT + when producing and address expression for a DECL node. + * opts.c (decode_options): Enable SRA at -O1. + (common_handle_option): Handle -ftree-sra. + * timevar.def (TV_TREE_SRA): New timer. + * toplev.c (flag_tree_sra): Define. + * tree-cfg.c (stmt_ends_bb_p): Declare extern. + (bsi_replace): Add boolean argument to specify whether to + preserve EH region information. Update all callers. + (bsi_commit_edge_inserts): Also check the edge from ENTRY_BLOCK_PTR + to basic block 0. + Move loop body ... + (bsi_commit_edge_inserts_1): ... here. + * tree-dump.c: Add dump for SRA pass. + * tree.h (enum tree_dump_index): Modify accordingly. + (STRIP_USELESS_TYPE_CONVERSION): Define. Update all callers to + tree_ssa_useless_type_conversion. + * tree-eh.c (add_stmt_to_eh_region): New function. + * tree-flow.h (stmt_ends_bb_p): Declare. + (add_stmt_to_eh_region): Declare. + (tree_sra): Declare. + (enum bsi_iterator_update): Mirror entries in + enum tsi_iterator_update. + * tree-optimize.c (optimize_function_tree): Call SRA pass + after must-alias. + * tree-sra.c: New file. + * doc/invoke.texi: Document -ftree-sra and -fdump-tree-sra. + +2003-11-20 Andrew Macleod + + * tree-ssa.c (check_replaceable): Return false if the LHS is a + DECL_HARD_REGISTER. + +2003-11-20 Diego Novillo + + * tree-ssa-ccp.c (set_rhs): Replace with an empty statement when + the replacement has no side effects. + +2003-11-20 Jeff Law + + * Makefile.in (OBJS-common): Kill tree-ssa-copyprop.o. + (tree-ssa-copyprop.o): Kill dependencies clause. + * common.opt (tree-copyprop): Kill option. + * flags.h (flag_tree_copyprop): Kill. + * opts.c (decode_options): Don't set flag_tree_copyprop. + (common_handle_option): Kill handling of -ftree-copyprop. + * timevar.def (TV_TREE_COPYPROP): Kill. + * toplev.c (flag_tree_copyprop): Kill. + (lang_independent_options): Kill -ftree-copyprop. + * tree-dump.c (dump_files): Kill .copyprop dump. + * tree-flow.h (tree_ssa_copyprop): Kill prototype. + (propagate_copy): Move prototype. + * tree-optimize.c (optimize_function_tree): Kill -ftree-copyprop stuff. + * tree.h (tree_dump_index): Kill TDI_copyprop. + * tree-ssa-copyprop.c: Kill. + * tree-ssa-dom.c (propagate_copy): Moved here from tree-ssa-copyprop.c. + + * tree-ssanames.c (free_ssanames): No longer a varray. + (init_ssanames, make_ssa_name, release_ssa_name): Corresponding changes. + +2003-11-20 Steven Bosscher + + * tree-ssanames.c (ssanames_print_statistics): Use ISO function + declaration. Print unsigned ints, not usinged longs. + +2003-11-18 Daniel Berlin + + * tree-ssa-pre.c (rename_1): This should be static. + (append_eref_to_block): Don't gc allocate. + (clear_all_eref_arrays): Free the array rather than + clear them. + (rename_1): Ditto on both counts. + (free_expr_info): Free the arrays. + (collect_expressions): Don't gc allocate the arrays. + +2003-11-18 Daniel Berlin + + * tree-ssa-pre.c (insert_one_operand): Handle self-referential + ephi's properly. + +2003-11-19 Jeff Law + + * tree-ssa-dom.c (true_exprs, false_exprs): New hash tables. + (nonzero_vars): New varray. + (dom_walk_block_data): Add true_exprs, false_exprs and nonzero_vars. + (get_value_for, set_value_for): Accept additional argument indicating + which table to use. Callers updated. + (tree_ssa_dominator_optimize_1): Initialize and wipe our new hash + tables and varray appropriately. + (dom_opt_initialize_block): Initialize new block local varrays for + true expressions, false expressions and nonzero vars. Update call + to record_equivalences_from_incoming_edge. + (dom_opt_finalize_block): Put equivalences from taken edges + into the true_exprs and false_exprs hash tables. Restore global + state for true_exprs, false_exprs and nonzero_vars too. + (record_equivalences_from_incoming_edge): Accept dom_walk structure + instead of a gazillion varrays. Pass down block local + true_exprs, false_exprs and nonzero_vars varrays to various children. + (optimize_stmt): Accept block local nonzero_vars argument. Pass + new varrays down to record_equivalences_from_stmt. + (thread_jumps_walk_stmt): Pass new varrays down to + record_equivalences_from_stmt. + (dom_opt_walk_stmt): Pass new varrays down to optimize_stmt. + (dump_dominator_optimizer_statistics): Dump new hash tables. + (record_cond_is_true, record_cond_is_false): Record info into + the true/false hash tables/varrays instead of the main expression + varrays. Don't create useless tree nodes. + (record_var_is_nonzero): New function. + (record_equivalences_from_stmt): Don't generate useless tree nodes. + (lookup_avail_expr): Consult nonzero_vars and the true/false + expression tables as well. + (get_eq_expr_value): Record local true/false expressions in the + local true/false varrays rather than the main local expression + varray. + (true_false_expr_hash, true_false_expr_eq): New functions. + + * Makefile.in (OBJS-sommon): Add tree-ssanames.o. + (tree-ssanames.o): Add dependencies. + * tree-dfa.c (remove_phi_node): Release SSA_NAME expression when + we remove the PHI node. + (remove_all_phi_nodes_for): Similarly. + * tree-ssa.c (prepare_operand_for_rename): Similarly when we + strip away an SSA_NAME expression from an operand. + (init_tree_ssa): Call the SSA_NAME initializer. + (delete_tree_ssa): Call the SSA_NAME finalizer. + * tree-ssa-dom.c (tree_ssa_dominator_optimize_1): Clear the + const_and_copies and vrp_data virtual arrays. + * tree-ssanames.c: New file for management of SSA_NAME expressions. + * tree.h: Prototypes for functions exported by tree-ssanames.c. + * tree-flow.h, tree-ssa-ccp.c, tree-ssa-dce.c: Use highest_ssa_version + rather than next_ssa_version. + * tree-ssa-dom.c, tree-ssa-live.c, tree-ssa.c: Similarly. + * tree.c (dump_tree_statistics): Call into tree-ssaname statistics + dumper too. + (make_ssa_name): Kill. Now in tree-ssanames.c + +2003-11-18 Richard Henderson + + * tree.c (recompute_tree_invarant_for_addr_expr): Split out from ... + (build1): ... here. + * tree.h: Declare it. + * gimplify.c (gimplify_addr_expr): Use it. + * tree-ssa-ccp.c (maybe_fold_offset_to_array_ref): Split out + from fold_indirect_refs_r. + (maybe_fold_stmt_indirect): Likewise. + (maybe_fold_offset_to_component_ref): New. + (maybe_fold_stmt_plus): New. + (fold_stmt_r): Rename from fold_indirect_refs_r. + (fold_stmt): Strip more useless type conversions. + +2003-11-18 Richard Henderson + + * tree-cfg.c (dump_function_to_file): Mind when cfun is null. + +2003-11-18 Diego Novillo + + Revert + + 2003-11-18 Jan Hubicka + + * tree-cfg.c (cfg_remove_useless_stmts_bb): Avoid crash. + * tree-dfa.c (get_expr_operands): Fix handling of CALL_EXPR. + + 2003-11-18 Jan Hubicka + + * Makefile.in (sibcall.o): Kill. + (tree-tailcall.o): Add except.h dependency + * sibcall.c: Kill. + (purge_reg_equiv_notes, purge_mem_unchanging_flag): Move to ... + * calls.c (purge_reg_equiv_notes, + purge_mem_unchanging_flag) ... here. + (expand_call): Do not produce placeholders; do + not deal with tail recursion; update + equivalencies after sibcall production. + * toplev.c (rest_of_handle_sibling_calls): Kill. + (rest_of_compialtion): Do not use rest_of_handle_sibling_calls. + * tree-dump.c (dump_files): Add tail2 + * tree-flow.h (tree_optimize_tail_calls): Update prototype. + * tree-optimize.c (optimize_function_tree): Do + tail optimization twice. + * tree-tailcall.c: Inlucde except.h + (suitable_for_tail_call_opt_p): New. + (optimize_tail_call): Add opt_tailcalls argument; + optimize tailcalls. + (tree_optimize_tail_calls): Add opt_tailcalls/pass arguments. + * tree.h (CALL_EXPR_TAILCALL): New. + (tree_dump_index): Add tail2 + +2003-11-18 Jan Hubicka + + * tree-cfg.c (cfg_remove_useless_stmts_bb): Avoid crash. + * tree-dfa.c (get_expr_operands): Fix handling of CALL_EXPR. + +2003-11-18 Diego Novillo + + * tree-optimize.c (optimize_function_tree): Disable tail + call optimizations. + +2003-11-18 Jan Hubicka + + * Makefile.in (sibcall.o): Kill. + (tree-tailcall.o): Add except.h dependency + * sibcall.c: Kill. + (purge_reg_equiv_notes, purge_mem_unchanging_flag): Move to ... + * calls.c (purge_reg_equiv_notes, purge_mem_unchanging_flag) ... here. + (expand_call): Do not produce placeholders; do not deal with tail + recursion; update equivalencies after sibcall production. + * toplev.c (rest_of_handle_sibling_calls): Kill. + (rest_of_compialtion): Do not use rest_of_handle_sibling_calls. + * tree-dump.c (dump_files): Add tail2 + * tree-flow.h (tree_optimize_tail_calls): Update prototype. + * tree-optimize.c (optimize_function_tree): Do tail optimization twice. + * tree-tailcall.c: Inlucde except.h + (suitable_for_tail_call_opt_p): New. + (optimize_tail_call): Add opt_tailcalls argument; optimize tailcalls. + (tree_optimize_tail_calls): Add opt_tailcalls/pass arguments. + * tree.h (CALL_EXPR_TAILCALL): New. + (tree_dump_index): Add tail2 + +2003-11-18 Jeff Law + + * tree-ssa-dom.c (thread_across_edge): Lose block_avail_exprs argument. + Callers updated. Pass NULL for block_avail_exprs in call to + lookup_avail_expr. Record both the condition and the inverted + condition when threading across an edge. + +2003-11-18 Richard Henderson + + * tree-ssa.c (tree_ssa_useless_type_conversion): Use TYPE_MAIN_VARIANT + when compariing pointer types too. + +2003-11-18 Jan Hubicka + + * tree-dump.c (dump_files): Reorder tail calls. + * tree-optimize.c (optimize_function_tree): Likewise + * tree-tailcall.c (optimize_tail_call, eliminate_tail_call): Remove + variable tmpvars; update SSA. + (suitable_for_tail_opt_p): Do not give up because of static variables. + (find_tail_calls): Track return values in SSA graph. + * tree.c (make-phi_node): Do not create new SSA name when operand + already is. + * tree.h (enum tree_dump_index): Reorder tail call. + +2003-11-17 Diego Novillo + + * gimplify.c (gimplify_call_expr): Change gimple_test_f argument to + return bool type. + (mark_decls_volatile_r): New local function. + (gimplify_expr): Make gimple_test_f return bool type. + Call mark_decls_volatile_r when gimplifying VA_ARG_EXPR. + * tree-dfa.c (struct walk_state): Remove field is_va_arg_expr. + Update all callers. + (opf_force_vop): Remove. Update all users. + (add_stmt_operand): Re-structure to add real operands only for + GIMPLE register variables. + (find_vars_r): Don't handle VA_ARG_EXPR nodes. + (add_referenced_var): Also assign a UID to variables with hidden + uses. + Call is_gimple_call_clobbered to determine if a variable is call + clobbered. + (get_memory_tag_for): Mark memory tags volatile and static. + * tree-flow.h (struct var_ann_d): Remove field is_in_va_arg_expr. + Update all users. + * tree-simple.c (is_gimple_*): Change return type to bool. Update + all users. + (is_gimple_reg_type): Return true only for non aggregate types. + (is_gimple_non_addressable_1): New local function. + (is_gimple_reg): Call it. + (is_gimple_non_addressable): New function. + (is_gimple_call_clobbered): New function. + * tree-simple.h (is_gimple_*): Change return type to bool. + +2003-11-17 Jason Merrill + + PR c++/11266 + * gimplify.c (gimple_add_tmp_var): Also make sure + seen_in_bind_expr isn't set. + (mostly_copy_tree_r): Don't copy a TARGET_EXPR. + (gimplify_target_expr): Only expand a TARGET_EXPR the first time + we see it. + +2003-11-17 Richard Henderson + + * tree-pretty-print.c (dump_generic_node): Use %u not %x for + printing DECL_UID. + +2003-11-16 Richard Henderson + + * c-common.c (c_add_case_label): Use create_artificial_label. + * tree-simple.h (create_artificial_label): Move decl ... + * tree.h: ... here. + +2003-11-16 Richard Henderson + + PR c++/12770 + * gimple-low.c (lower_stmt_body): Take a tree, not a tree*. + (lower_stmt): Handle EH nodes. + (lower_bind_expr): Remove fixme. + (block_may_fallthru): Move from tree-eh.c. Handle COND_EXPR, + BIND_EXPR, and TRY_FINALLY_EXPR. + (lower_cond_expr): Use it. + * tree-eh.c (collect_finally_tree): Ignore COND_EXPR and BIND_EXPR. + (replace_goto_queue_cond_clause): New. + (replace_goto_queue_1): Use it. Split out statement_list handling. + (replace_goto_queue_stmt_list): New. + (-block_may_fallthru): Move to gimple-low.c. + (lower_eh_constructs_1): Ignore BIND_EXPR. + * tree-flow.h (block_may_fallthru): Declare. + + * tree-dump.c (dump_files): Exchange .eh and .lower passes. + * tree-optimize.c (tree_rest_of_compilation): Likewise. + * tree.h (enum tree_dump_index): Likewise. + +2003-11-16 Jason Merrill + + * gimplify.c (mostly_copy_tree_r): Don't walk into a BLOCK. + + * tree-inline.c (walk_tree): Don't walk into the BIND_EXPR_VARS + of a BIND_EXPR. + * c-common.c (c_walk_subtrees): Don't walk into the decl of a + DECL_STMT. + + PR optimization/11269 + * dwarf2out.c (gen_subprogram_die): Generate a DIE for a named + return value. + (loc_descriptor_from_tree): Treat RESULT_DECL like VAR_DECL. + (add_location_or_const_value_attribute): Likewise. + (add_bound_info): Likewise. + (gen_decl_die): Likewise. + +2003-11-16 Jason Merrill + + * c-pretty-print.c (debug_c_tree): Restore removed fn. + * diagnostic.h: Declare it. + + * tree-pretty-print.c (dump_generic_node): Use DECL_UID when + dumping anonymous decls. + +2003-11-16 Richard Henderson + + * tree-cfg.c (last_and_only_stmt): New. + * tree-flow.h (last_and_only_stmt): Declare. + * tree-ssa-dom.c (thread_across_edge): Use it. + + * tree-cfg.c (tree_block_forwards_to): Don't check for empty stmts. + (tree_forwarder_block_p): Likewise. + * tree-dfa.c (get_stmt_operands): Likewise. + * tree-ssa-ccp.c (set_rhs): Likewise. + * tree-ssa-dom.c (optimize_stmt): Likewise. + * tree-ssa.c (rewrite_stmt): Likewise. + +2003-11-16 Richard Henderson + + * tree.h (LABEL_DECL_UID): Rename from LABEL_DECL_INDEX. + * tree-flow.h (bsi_remove): Declare. + * tree-flow-inline.h (bsi_remove): Move ... + * tree-cfg.c (set_bb_for_stmt): Don't re-set LABEL_DECL_UID. + Verify that a label isn't already in a block before adding it. + (bsi_remove): Move from tree-flow-inline.h, clear bb. + * tree-pretty-print.c (dump_generic_node): Use LABEL_DECL_UID if set. + +2003-11-15 Richard Henderson + + * function.c (clear_block_marks): Rename from reorder_blocks_0, export. + * function.h (clear_block_marks): Declare. + * gimple-low.c (lower_function_body): Use it. + (lower_bind_expr): Ensure we don't link blocks into the tree twice. + * gimplify.c (gimplify_body): Keep old bind_expr at top level if + possible. + +2003-11-14 Richard Henderson + + * tree-ssa-pre.c (split_critical_edges): Reimplement. Call + tree_split_edge directly. + +2003-11-14 Jason Merrill + + * tree-eh.c (do_return_redirection): Assign directly to the + RESULT_DECL of a function which returns in memory. + +2003-11-14 Daniel Berlin + + * tree-ssa-pre.c (pre_stats): Add ephis_current member. + (create_ephi_node): Use xmalloc, not ggc_alloc_tree. + (clear_all_eref_arrays): Free the ephis here. + (expr_phi_insertion): Don't append the ephis to the erefs array. + (insert_occ_in_preorder_dt_order): Move building/freeing of dfn + array so that it only occurs once per function.. + (rename_1): Ditto on the dfs_id array. + (ephi_use_pool): New alloc pool. + (add_ephi_use): Pool allocate these things, rather than + ggc_alloc'ing them. + (insert_euse_in_preorder_dt_order_1): Use ephi_at_block to put the + ephi in the list. + (pre_expression): Don't PRE when we only have 1 occurrence. + (expr_lexically_eq): Make inline. + (names_match_p): Move closer to first use. + (tree_perform_ssapre): Alloc and free the ephi_use_pool. + Make stat printing per-expression. + Add checking that we freed all ephis. + +2003-11-14 Andrew MacLeod + + * common.opt (ftree-ter): Document new option. + * flags.h (flag_tree_ter): Add new flag. + * fold-const.c (invert_truthvalue): Don't ignore cast to BOOLEAN_TYPE. + * opts.c (decode_options): Option -ftree-ter defaults to on. + (common_handle_option): Add processing for flag_tree_ter. + * toplev.c (flag_tree_ter): Initialize to 0. + (lang_independent_options f_): Add -ftree-ter flag. + * tree-ssa-live.c (init_var_map): Initialize ref_count to 0. + (delete_var_map): Free ref count if allocated. + (register_ssa_partition): Add "is_use" parameter for reference counting. + (create_ssa_var_map): Add flag and code for calculating ref counts. + * tree-ssa-live.h (struct _var_map): Add ref_count field. + (SSA_VAR_MAP_REF_COUNT): Define flag. + (version_ref_count): Function to retreive ref_count. + * tree-ssa.c (replace_variable): If an expression vector is passed in, + use replacement expression instead of mapped variable when available. + (struct value_expr_d): New structure for value lists. + (struct temp_expr_table_d): Structure used to build an expression + replacement table. + (new_temp_expr_table): New. Create a new TER (Temporary Expression + Replacement) table. + (free_temp_expr_table): New. Free a TER table. + (new_value_expr): New. Allocate a value list element. + (free_value_expr): New. Free a value list element. + (find_value_in_list): New. Find a value in a list. + (add_value_to_list): New. Add a value to a list if not already present. + (remove_value_from_list): New. Remove a value from a list. + (add_dependance): New. Add a dependency to an expression. + (check_replaceable): New. Check if a stmt is a candidate for TER. Add + to active list and create dependancies if so. + (finish_expr): New. Remove an expression from TER consideration. + (mark_replaceable): New. Finish a TER expression as a valid replacement. + (kill_expr): New. Finish dependent TER expressions as not replaceable. + (kill_virtual_exprs): New. Finish any TER expressions dependent on a + virtual operand as not replaceable. + (find_replaceable_in_bb): New. Process a basic block for TER expression. + (find_replaceable_exprs): New. Entry point for TER expression finder. + (dump_replaceable_exprs): New. output list of replaceable expressions. + (rewrite_out_of_ssa): Build TER table if requested, and use it. + +2003-11-14 Andreas Jaeger + + * c-semantics.c (find_reachable_label): Use C90 function + declaration. + +2003-11-14 Jason Merrill + + PR middle-end/12526 + * tree-cfg.c (call_expr_flags): Move to calls.c. + * tree-flow.h: Move prototype to tree.h. + + PR c++/13033 + * c-simplify.c (gimplify_c_loop): Wrap the increment in a + CLEANUP_POINT_EXPR. + + * tree-dfa.c (get_stmt_operands) : A memory clobber + clobbers all call-clobbered variables. Clobber clobber. + + * gimplify.c (canonicalize_component_ref): Remove redundant call + to recalculate_side_effects. + +2003-11-14 Richard Henderson + + PR c++/12751 + * tree-eh.c (struct leh_tf_state): Add outer. + (lower_try_finally, lower_cleanup): Set it. + (lower_try_finally_fallthru_label): New. + (honor_protect_cleanup_actions): Use it. + (lower_try_finally_copy, lower_try_finally_switch): Likewise. + + * tree-eh.c (collect_finally_tree): Complete manual tailrecurse + transformation. + +2003-11-14 Richard Henderson + + * gimplify.c (voidify_wrapper_expr): Don't clobber TREE_TYPE of + statements in a STATEMENT_LIST. Be prepared for an empty list. + +2003-11-14 Steven Bosscher + + * jump.c (never_reached_warning): Remove function. + * rtl.h (never_reached_warning): Don't declare it. + * cfgrtl.c (never_reached_warning): Don't call it. + * cse.c (never_reached_warning): Ditto. + +2003-11-13 Jeff Law + + * tree-cfg.c (bsi_replace): Restore accidentally removed code. + + * tree-cfg.c (cfg_remove_useless_stmts_bb): Also detect useless + var->var copies created by the out-of-ssa translation. + +2003-11-13 Steven Bosscher + + PR middle-end/11514 + * tree-inline.c (walk_tree): Handle PLACEHOLDER_EXPR. + +2003-11-13 Richard Henderson + + * tree-cfg.c (cfg_remove_useless_stmts_bb): Initialize stmt. + +2003-11-13 Jan Hubicka + + * calls.c (special_function_p): Do not check for ECF_MALLOC. + (flags_from_decl_or_type): Use special_function_p. + (expand_call): Remove call to special_function_p. + * tree-cfg.c (notice_special_calls, clear_special_calls): New functions. + (remove_useless_stmts): Use clear_special_calls. + (remove_useless_stmts_1): Use notice_special_calls. + * tree-flow.h (notice_special_calls, clear_special_calls): New functions. + * tree-ssa-dce.c (remove_dead_stmts): Use clear_special_calls and + notice_special_calls.. + + * gimplify.c (gimplify_expr): Check labels. + + * tree-cfg.c (tree_verify_flow_info): Check labels. + + * tree-cfg.c (make_exit_edges): Do not create edges for const + functions. + (update_call_expr_flags): Fix. + +2003-11-12 Diego Novillo + + (declare_inlined_vars): New local function. + (initialize_inlined_parameters): Call it. + (expand_call_inline): Call it. + +2003-11-13 Steven Bosscher + + PR optimization/12640 + * tree-ssa-ccp.c (get_strlen): Don't follow the UD chain + of a PHI argument if the DEF stmt for the argument is + the PHI itself. + +2003-11-12 Zdenek Dvorak + Jeff Law + + * tree-cfg.c (cfg_remove_useless_stmts): New function. + (cfg_remove_useless_stmts_bb): Likewise. + * tree-flow.h (cfg_remove_useless_stmts): Prototype. + * tree-ssa.c (rewrite_out_of_ssa): Use cfg_remove_useless_stmts + instead of remove_useless_stmts. + +2003-11-12 Richard Henderson + + * Makefile.in (OBJS-common): Add tree-iterator.o. + (expr.o): Depend on tree-iterator.h. + (GTFILES): Add tree-iterator.c. + * basic-block.h (struct basic_block_def): Replace head_tree_p + and end_tree_p with stmt_list. + (tree_bb_root): New. + (create_bb): Don't declare. + * c-common.c (c_warn_unused_result): Handle STATEMENT_LIST. + * c-simplify.c (c_gimplify_stmt): Don't rationalize_compound_expr. + * cfg.c (entry_exit_blocks): Adjust for member changes. + (compact_blocks): Manage tree_bb_root. + * expr.c (expand_expr_1): Handle STATEMENT_LIST. + * gimple-low.c: Update for tree_stmt_iterator changes. + (lower_cond_expr): Use expr_only. Notice empty conditionals. + * gimplify.c (append_to_statement_list_1): Create and + manage statement_list nodes. + (foreach_stmt): Remove. + (wfl_locus): Remove. + (annotate_all_with_locus_1): Merge into... + (annotate_all_with_locus): ... here. Iterate over the + statement list directly. + (voidify_wrapper_expr): Handle STATEMENT_LIST. + (gimplify_return_expr): Likewise. + (gimplify_loop_expr): Likewise. + (shortcut_cond_r, shortcut_cond_expr): Likewise. + (gimplify_cleanup_point_expr): Likewise. + (gimple_build_eh_filter): Create statement list bodies. + (gimplify_bind_expr): Likewise. + (gimplify_switch_expr): Likewise. + (gimplify_cond_expr): Likewise. + (gimplify_compound_expr): Handle void expressions as well. + (gimplify_statement_list): New. + (gimple_push_cleanup): Gimplify the WITH_CLEANUP_EXPR operand. + (gimplify_stmt): Ensure non-null result. + (gimplify_to_stmt_list): New. + (gimplify_expr): Use gimplify_compound_expr, gimplify_statement_list, + gimplify_to_stmt_list as appropriate. + (gimplify_body): Fix creation of outer BIND_EXPR. + * tree-cfg.c (tree_bb_root): New. + (build_tree_cfg): Initialize it. Update for make_blocks changes. + (factor_computed_gotos): Use create_bb directly. + (make_blocks): Rewrite to use statement lists. + (append_stmt_to_bb, prepend_stmt_to_bb): Remove. + (create_bb): Make static. Add stmt_list argument. Don't allow + null after argument. Set tree_bb_root. + (make_edges): ENTRY block successor is FALLTHRU. + (remove_useless_stmts_warn_notreached): Handle STATEMENT_LIST. + (struct rus_data): Add last_goto. + (remove_useless_stmts_cond): Clear it. Zap empty conditionals. + Use expr_only for simple statment elimination. + (remove_useless_stmts_tf): Clear last_goto. Use TREE_SIDE_EFFECTS + instead of IS_EMPTY_STMT. Use append_to_statement_list instead of + munging to COMPOUND_EXPR. + (remove_useless_stmts_tc): Clear last_goto. Use TREE_SIDE_EFFECTS. + (remove_useless_stmts_goto): Set last_goto. + (remove_useless_stmts_label): New. Kill goto-next-label. + (remove_useless_stmts_1): Reorg to handle STATEMENT_LIST. + (remove_bb): Simplify block removal. + (remove_bsi_from_block): Kill. + (tree_block_forwards_to): Tidy bsi loops. Do not create + block label here. + (tree_cfg2dot): Update for bb->stmt_list. + (delete_tree_cfg): Clear tree_bb_root. + (set_bb_for_stmt): Handle STATEMENT_LISTs. + (bsi_insert_before, bsi_insert_after): Re-implement on TSIs. + (bsi_move_after, bsi_move_before, bsi_move_to_bb_end): Likewise. + (bsi_replace): Likewise. + (tree_find_edge_insert_loc): New, split from ... + (bsi_insert_on_edge_immediate): ... here. + (bsi_commit_edge_inserts): Use it. Add all stmts at once. + (bsi_insert_on_edge): Use statement lists. + (tree_split_edge): Position new block correctly. Deal with + fallthrough to EXIT. + (tree_verify_flow_info): Do not check block order vs statement chain. + (tree_make_forwarder_block): Update create_bb call, fix edge flags. + (thread_jumps): Call tree_redirect_edge_and_branch directly. + (tree_block_label): Don't return a NONLOCAL_LABEL. + (tree_redirect_edge_and_branch_1): Rename from s/_1//. Take an + argument to use ssa_redirect_edge or redirect_edge_succ. Use + tree_split_edge instead of bsi_insert_on_edge_immediate. + (tree_redirect_edge_and_branch): New. + (remove_stmt, first_exec_stmt, bsi_init, bsi_next_in_bb): Kill. + (bsi_start, bsi_last, bsi_prev, bsi_from_tsi): Kill. + (bsi_update_from_tsi, bsi_link_after): Kill. + * tree-eh.c (collect_finally_tree): Handle STATEMENT_LIST. + (replace_goto_queue_1): Likewise. + (replace_goto_queue): Don't use walk_tree. + (do_return_redirection): Create statement lists. + (do_goto_redirection): Likewise. + (block_may_fallthru_last): Fold into... + (block_may_fallthru): ... here. + (frob_into_branch_around): Use append_to_statement_list. + (honor_protect_cleanup_actions): Likewise. + (lower_try_finally_nofallthru): Likewise. + (lower_try_finally_onedest): Likewise. + (lower_try_finally_copy): Likewise. + (lower_try_finally_switch): Likewise. + (lower_try_finally): Likewise. + (lower_catch): Likewise. + (lower_eh_filter): Likewise. + (lower_eh_constructs_1): Handle STATEMENT_LIST. + * tree-flow-inline.h (BSI_NUM_ELEMENTS, bsi_list_p): Remove. + (new_bsi_list, empty_bsi_stack, FOR_EACH_BSI_IN_REVERSE): Remove. + (FOR_EACH_STMT_IN_REVERSE): Remove. + (bsi_start, bsi_last, bsi_end_p): Re-implement based on TSIs. + (bsi_next, bsi_prev, bsi_stmt, bsi_stmt_ptr, bsi_remove): Likewise. + * tree-flow.h (block_stmt_iterator): Likewise. + * tree-inline.c (copy_statement_list): New. + (copy_body_r): Use it, and append_to_statement_list. + (initialize_inlined_parameters): Use append_to_statement_list. + (expand_call_inline): Likewise. + (gimple_expand_calls_inline): New. + (expand_calls_inline): Use it. + (walk_tree, unsave_r): Handle STATEMENT_LIST. + (add_stmt_to_compound): Remove. + * tree-iterator.c: New file. + * tree-iterator.h: Re-implement based on STATEMENT_LIST. + * tree-mudflap.c (mf_decl_cache_locals): Don't + rationalize_compound_expr. + * tree-optimize.c (optimize_function_tree): Make static. + Rechain statements from blocks before deleting the cfg. + * tree-pretty-print.c (dump_generic_node): Handle STATEMENT_LIST, + update for change in tree_stmt_iterator wrt COMPOUND_EXPR. + (dump_generic_node): Dump lowered COND_EXPR on a single line. + * tree-simple.c (is_gimple_stmt): Handle STATEMENT_LIST. + * tree-simple.h (foreach_stmt_fn, foreach_stmt): Remove. + (gimplify_to_stmt_list): Declare. + (alloc_stmt_list, free_stmt_list): Declare. + * tree-ssa-dce.c (should_remove_dead_stmt): Rename from + remove_dead_stmt; return bool if statement should be removed. + (remove_dead_stmts): Update to match. + * tree-ssa-live.c (build_tree_conflict_graph): Don't use + FOR_EACH_STMT_IN_REVERSE. + * tree-ssa-pre.c (reaching_def): Tidy BSI usage. + (insert_one_operand, collect_expressions): Likewise. + * tree.c (tree_size): Handle STATEMENT_LIST. + (copy_node): Abort on STATEMENT_LIST. + (expr_first, expr_last): Move to tree-iterator.c. + (expr_length): Remove. + (tree_node_structure): Handle STATEMENT_LIST. + (tsi_link_before, tsi_link_after, tsi_delink): Move to tree-iterator.c. + (tsi_link_chain_before, tsi_link_chain_after): Merge into non-chain. + (tsi_new_stmt_list, tsi_stmt_list_head, body_is_empty): Kill. + * tree.def (STATEMENT_LIST): New. + * tree.h (STATEMENT_LIST_HEAD, STATEMENT_LIST_TAIL): New. + (struct tree_statement_list_node): New. + (struct tree_statement_list): New. + (enum tree_node_structure_enum): Add TS_STATEMENT_LIST. + (union tree_node): Add stmt_list. + (expr_length): Remove. + (expr_only): New. + (add_to_compound_expr, body_is_empty): Remove. + (optimize_function_tree): Remove. + +2003-11-12 Zdenek Dvorak + + * tree-flow.h (remove_useless_vars): Declare. + (expand_var_p): Declaration removed. + * tree-ssa.c (rewrite_out_of_ssa): Call remove_useless_vars. + * tree-cfg.c (dump_function_to_file): Update dumping of variables. + * gimple-low.c (expand_var_p): Made static. + (remove_useless_vars): New. + (expand_used_vars): Expand all variables in the + cfun->unexpanded_var_list. + +2003-11-11 Richard Henderson + + * c-common.c (c_gimplify_stmt): Fix botched removal of + rationalize_compound_expr calls. + + * c-semantics.c (build_stmt): Set TREE_SIDE_EFFECTS. + * c-simplify.c (c_gimplify_stmt): Return a gimplify_status; + mind the status from subroutines to avoid re-gimplification. + (c_build_bind_expr): Do not call gimplify_stmt. + (gimplify_c_loop): Don't create a loop_expr; fully gimplify. + (gimplify_block, gimplify_cleanup, gimplify_expr_stmt, + gimplify_for_stmt, gimplify_while_stmt, gimplify_do_stmt, + gimplify_if_stmt, gimplify_switch_stmt, gimplify_return_stmt, + gimplify_decl_stmt, gimplify_compound_literal_expr, + gimplify_stmt_expr): Return a gimplify_status. In most cases, + don't do local gimplification of sub-structures. + (gimplify_decl_stmt): Use append_to_compound_expr when we care + about the result value. + (gimplify_stmt_expr): Use append_to_statement_list_force and + re-gimplify so that voidify_wrapper_expr can work. + (finish_bc_block): Don't append to a non-list. + (c_gimplify_expr): Pass back the gimplify_status of subroutines. + * c-common.h (c_gimplify_stmt): Update decl. + * gimplify.c (append_to_statement_list_1): Make sure list_p is + never null after call. + (append_to_compound_expr): New. + * tree-simple.h (append_to_compound_expr): Declare. + +2003-11-11 Richard Henderson + + * gimplify.c (gimplify_addr_expr): Clear, not copy, TREE_SIDE_EFFECTS. + +2003-11-11 Richard Henderson + + PR c/13014 + * c-simplify.c (gimplify_if_stmt): Remove short circuit. + * tree-cfg.c (struct rus_data): Add has_label. + (remove_useless_stmts_warn_notreached): New. + (remove_useless_stmts_cond): Warn for deleted conditionals. + (remove_useless_stmts_tc): Warn for deleted catches. + (remove_useless_stmts_1): Set has_label. + +2003-11-11 Jan Hubicka + + * gimplify.c (gimplify_call_expr): Unset side effects for + pure functions too. + * tree-cfg.c (update-call_expr_flags): New function. + (remove_useless_stmts_and_vars_1): Use it. + (is_ctrl_altering_stmt): Pure/const calls never alter the CFG. + * tree-ssa-dce.c (stmt_useful_p): Check side effects flag + on call exprs. + +2003-11-11 Jan Hubicka + + * tree-cfg.c (has_label_p): New function. + (tree_verify_flow_info): New checks. + * tree-optimize.c (optimize_function_tree): Call verify_flow_info + before de-SSA. + +2003-11-11 Richard Henderson + + * tree-cfg.c (struct rus_data): Rename from rusv_data. + Remove remove_unused_vars. + (remove_useless_stmts*): Rename from remove_useless_stmts_and_vars*. + (remove_useless_stmts_bind): Do not remove dead variables. + (remove_useless_stmts): Kill remove_unused_vars argument. + * tree-flow.h (remove_useless_stmts): Update. + * tree-optimize.c (tree_rest_of_compilation): Update call. + * tree-ssa.c (rewrite_out_of_ssa): Likewise. + +2003-11-11 Zdenek Dvorak + Diego Novillo + + * basic-block.h (brief_dump_cfg): Declare. + * cfg.c (dump_cfg_bb_info, brief_dump_cfg): New. + * diagnostic.h (dump_generic_node): Declaration changed. + (print_generic_stmt_indented): Declare. + * gimple-low.c (expand_var_p): New. + (expand_used_vars): Use it. + * tree-cfg.c (struct cfg_stats_d): Remove num_failed_bind_expr_merges + field. + (remove_bb): Only dump whole block with TDF_DETAILS. + (tree_dump_bb): Use dump_generic_bb. + (dump_tree_cfg): Use brief_dump_cfg and dump_function_to_file. + (dump_cfg_function_to_file): Merged into dump_function_to_file, + removed. + (dump_cfg_stats): Do not dump cfg_stats.num_failed_bind_expr_merges. + (dump_function_to_file): Moved from tree-dump.c, merged with + dump_cfg_function_to_file. + * tree-dump.c (dump_function_to_file): Removed. + * tree-flow.h (dump_cfg_function_to_file): Declaration removed. + (dump_generic_bb, expand_var_p): Declare. + * tree-must-alias.c (tree_compute_must_alias): Replace + dump_cfg_function_to_file by dump_function_to_file. + * tree-ssa-ccp.c (tree_ssa_ccp): Ditto. + * tree-ssa-copyprop.c (tree_ssa_copyprop): Ditto. + * tree-ssa-dce.c (tree_ssa_dce): Ditto. + * tree-ssa-dom.c (tree_ssa_dominator_optimize_1): Ditto. + * tree-ssa-pre.c (tree_perform_ssapre): Ditto. + * tree-ssa.c (rewrite_into_ssa, rewrite_out_of_ssa): Ditto. + * tree-tailcall.c (tree_optimize_tail_calls): Ditto. + * tree-pretty-print.c (print_declaration, print_generic_decl): Don't + use flags argument, change spacing. + (dump_block_info): Removed. + (dump_generic_bb_buff, dump_generic_bb, print_generic_stmt_indented, + dump_bb_header, dump_bb_end, dump_phi_nodes): New functions. + (dump_vops): Change spacing, don't dump phi nodes. + (do_niy, print_generic_stmt, print_generic_expr, print_declaration, + print_struct_decl, print_call_name): Add argument to + the dump_generic_node calls. + (last_bb): Removed. + (dump_generic_node): Print semicolons at end of statements correctly. + Don't print bb related stuff. + (maybe_init_pretty_print): Don't initialize last_bb. + * tree-ssa.c (rewrite_out_of_ssa): Do not allow virtual operands to + be shown in the .optimized dump. + +2003-11-11 Daniel Berlin + + PR optimization/12936 + * tree-ssa-pre.c (expr_phi_insertion): Remove unused code that was + causing ICE's for VA_ARG_EXPR. + +2003-11-10 Richard Henderson + + * gimple-low.c (lower_function_body): Lower bind_expr in place. + (lower_stmt): Only incr for stmts we're skipping. + (lower_cond_expr): Detect empty if. + +2003-11-10 Steven Bosscher + + * toplev.c (rest_of_decl_compilation): Use the location of the + declaration for error messages. + +2003-11-10 Richard Henderson + + * gimplify.c (add_stmt_to_compound, add_tree): Remove. + (append_to_statement_list_1, append_to_statement_list): New. + (append_to_statement_list_force): New. + (gimplify_loop_expr): Take pre_p. + (gimplify_expr): Provide it. + * tree-simple.h: Update. + + * c-simplify.c: Replace add_tree with append_to_statement_list. + * gimplify.c, tree-mudflap.c: Likewise. + +2003-11-10 Richard Henderson + + * c-common.c (c_warn_unused_result): Restructure to use iterator + on COMPOUND_EXPR only. + +2003-11-09 Zdenek Dvorak + + * tree-cfg.c (tree_verify_flow_info): Fix checking of order of basic + blocks over code. + +2003-11-09 Richard Henderson + + * basic-block.h (struct edge_def): Turn insns into a union. + * cfgrtl.c (insert_insn_on_edge): Update to match. + (commit_one_edge_insertion, commit_edge_insertions): Likewise. + (commit_edge_insertions_watch_calls): Likewise. + * gcse.c (reg_killed_on_edge, bypass_block): Likewise. + * profile.c (instrument_edges): Likewise. + * rtlanal.c (hoist_insn_to_edge): Likewise. + * tree-cfg.c (PENDING_STMT): Likewise. + (SET_PENDING_STMT): Remove. + (bsi_commit_edge_inserts): Update to match. + +2003-11-08 Jan Hubicka + + * fold.c (nondestructive_fold_binary_to_constant): Fix typo. + * fold-const.c (fold_relational_const): Check for side effects. + +2003-11-07 Zdenek Dvorak + + * basic-block.h (create_bb): Declaration changed. + * tree-cfg.c (create_bb): Enable creating a block on specified place. + (make_blocks, tree_split_edge, tree_make_forwarder_block): Use it. + (tree_verify_flow_info): Check bbs are in the correct order. + + * tree-cfg.c (find_unreachable_blocks): Remove now incorrect comments. + + * tree-ssa.c (rewrite_out_of_ssa): Don't remove annotations from + statements before the final dump. + +2003-11-07 Zdenek Dvorak + + * tree-tailcall.c (struct tailcall): New. + (bb_optimize_tail_calls, find_tail_call_p): Removed. + (eliminate_tail_call): Get the tailcall from the struct tailcall. + (optimize_tail_call, find_tail_calls): New. + (tree_optimize_tail_calls): Use them. + +2003-11-07 Jan Hubicka + + * gimple-low.c (simple_goto_p): Move to... + * tree-cfg.c: (simple_goto_p): ... here; + (nonlocal_goto_p): New. + (is_computed_goto): Rename to ... + (computed_goto_p): ... this; make global. + (factor_computed_gotos, make_blocks): Update calls. + (make_ctrl_stmt_edges): Add edge for nonlocal labels; use new functions. + * tree-flow.h (is_coputed_goto): Kill. + (nonlocal_goto_p, simple_goto_p, computed_goto_p): Declare. + * tree-ssa-ccp (visit_stmt): Update. + +2003-11-07 Jan Hubicka + + * fold-const.c (tree_expr_nonzero_p): Fix typo. + + * fold-const.c (tree_expr_nonzero_p): New function. + (fold_relational_const): Use it. + (nondestructive_fold_binary_to_constant): Allow casts in address + expressions. + +2003-11-06 Jan Hubicka + + * tree-cfg.c (tree_block_label): Cleanup. + +2003-11-06 Daniel Berlin + + * tree-ssa-pre.c (fast_a_dominates_b): New function. + (build_dfs_id_array_1): Ditto. + (build_dfs_id_array): Ditto. + (load_modified_phi_result): Use fast_a_dominates_b. + (rename_1): Ditto. + Also use build_dfs_id_array, and remove some duplicate ephi_at_block + calls. + (insert_occ_in_preorder_dt_order): Remove some duplicate ephi_at_block + calls. + (pre_expression): Ditto. + Also free dfs_id arrays here. + (collect_expressions): Remove duplicate bsi_stmt calls. + +2003-11-06 Daniel Berlin + + * tree-ssa-pre.c (count_stmts_in_bb): Removed. + (set_var_phis): Only call bb_for_stmt once. + (insert_one_operand): Remove endtree, endtreep, a lot of special handling + no longer needed. Remove insert_done. + (collect_expressions): Enable INDIRECT_REF and SSA_NAME handling. + +2003-11-06 Steven Bosscher + + * tree-cfg.c (STRIP_CONTAINERS): Remove. + +2003-11-06 Jan Hubicka + + * tree-cfg.c (cleanup_cond_expr_graph): Clean edge flags. + +2003-11-06 Zdenek Dvorak + + * tree-dump.c (dump_options): Remove TDF_LINENO from all setting. + +2003-11-06 Jan Hubicka + + * builtins.c (expand_builtin_strstr, expand_builtin_strchr, + expand_builtin_strrchr, expand_builtin_strpbrk, + simplify_builtin_strstr, simplify_builtin_strrchr, + simplify_builtin_strpbrk): Add missing casts. + +2003-11-05 Zdenek Dvorak + + * diagnostic.h (print_generic_decl): Declare. + * tree-cfg.c (dump_cfg_function_to_file): Dump variables in + unexpanded_var_list. + * tree-pretty-print.c (print_generic_decl): New function. + +2003-11-05 Zdenek Dvorak + + * Makefile.in (gimplify.o): Add function.h dependency. + * c-call-graph.c (construct_call_graph): Modify build_tree_cfg call. + * gimple-low.c (record_vars): Export. + (lower_function_body): Remove the topmost BIND_EXPR. + * gimplify.c: Include function.h. + (gimple_add_tmp_var): Record temporaries in the + cfun->unexpanded_vars_list if available. + * tree-cfg.c (build_tree_cfg): Work without the topmost BIND_EXPR. + (dump_cfg_function_to_file): New. + (dump_tree_cfg): Use dump_cfg_function_to_file. + * tree-dump.c (dump_function_to_file): Work without the topmost + BIND_EXPR. + * tree-flow.h (build_tree_cfg): Declaration changed. + (dump_cfg_function_to_file, record_vars): Declare. + * tree-optimize.c (optimize_function_tree, tree_rest_of_compilation): + Work without the topmost BIND_EXPR. + * tree-must-alias.c (tree_compute_must_alias): Use + dump_cfg_function_to_file. + * tree-ssa-ccp.c (tree_ssa_ccp): Ditto. + * tree-ssa-copyprop.c (tree_ssa_copyprop): Ditto. + * tree-ssa-dce.c (tree_ssa_dce): Ditto. + * tree-ssa-dom.c (tree_ssa_dominator_optimize_1): Ditto. + * tree-ssa-pre.c (tree_perform_ssapre): Ditto. + * tree-ssa.c (rewrite_into_ssa, rewrite_out_of_ssa): Ditto. + * tree-tailcall.c (tree_optimize_tail_calls): Ditto. + * tree.h (optimize_function_tree): Declaration changed. + +2003-11-03 Daniel Berlin + + * tree-ssa-pre.c (handle_bb_creation): Removed. + (redo_dominators): Removed. + (insert_one_operand): Remove code to handle bb creation, since all + critical edges are now pre-split. + (finalize_2): Remove redo_dominators related code. + (pre_expression): Return 1 if we exited early because nothing happened. + (split_critical_edges): Do fake variable assignments instead, because + it works. return true if we actually split an edge. + (tree_perform_ssapre): Remove redo_dominators code. + +2003-11-03 Zdenek Dvorak + + * function.h (struct function): New field unexpanded_var_list. + * gimple-low.c (unexpanded_var_list): Removed. + (record_vars, expand_used_vars): Use cfun->unexpanded_var_list. + * tree-flow.h (unexpanded_var_list): Declaration removed. + + * gimplify.c (should_carry_locus_p): New. + (annotate_all_with_locus_1): Use it. Do not annotate empty + statements. + +2003-11-03 Jan Hubicka + + * tree-cfg.c (tree_try_redirect_by_replacing_jump): Do not use + succesor_block. + +2003-11-03 Zdenek Dvorak + + * tree-pretty-print.c (dump_block_info): Add flags parameter. + Only show line number when asked to. + (dump_generic_node): Pass flags to dump_block_info. + +2003-11-03 Jan Hubicka + + * cfghooks.h (redirect_edge_and_branch hook): Make it return edge. + * cfgrtl.c (cfg_layout_redirect_edge_and_branch, + rtl_redirect_edge_and_branch, try_redirect_by_replacing_jump): + Update to new interface. + * tree-cfg.c (tree_cfg_hooks): Move to end of file; set + redirect_edge_and_branch and redirect_edge_and_branch_force. + (thread_jumps): Use redirect_edge_and_branch. + (tree_block_label): new; break out of thread_edge. + (tree_try_redirect_by_replacing_jump): New. + (thread_edge): Rename to tree_redirect_edge_and_branch; deal sanely + with unusual edges; preserve profile. + (tree_redirect_edge_and_branch_force): New. + * tree-flow.h (ssa_redirect_edge): Declare. + * tree-ssa.dom.c (tree_ssa_dominator_optimize): Use redirect_edge_and_branch. + * tree-ssa.c (ssa_redirect_edge): New. + +2003-11-03 Jeff Law + + * domwalk.h (struct dom_walk_data): New field "global_data". + * tree-ssa-dom.c (tree_ssa_dominator_optimize_1): Initialize new + "global_data" field. + * tree-flow.h (enum need_phi_state): New enumeration. + (var_ann_d): Add bitfield for need_phi_state. + * tree-ssa.c (mark_def_sites_global_data): New structure to hold + global data for mark_def_sites dominator walk. + (mark_def_sites): Revamp to be called via the dominator walker. + (set_def_block): Update need_phi_state for the variable as needed. + (set_livein_block): Similarly. + (rewrite_into_ssa): Use dominator walker to call mark_def_sites. + Delay freeing dominance info. Kill "globals" bitmap. + (insert_phi_nodes): No longer need "globals" bitmap. Use + need_phi_state in variable's annotation to determine if a PHI + may be needed. + + * tree-ssa-dom.c (dom_opt_finalize_block): Try to thread across the + edges leaving COND_EXPR nodes which are leafs in the dominator + tree. + (record_equivalences_from_incoming_edge): Do not set EQ_EXPR_VALUE + unless the block's single predecessor contains parent_block_last_stmt. + +2003-11-03 Zdenek Dvorak + + * tree-dump.c (dump_options): Add TDF_LINENO. + * tree-pretty-print.c (dump_generic_node): Print line number for + statements if asked to. + * tree.h (TDF_LINENO): New. + * doc/invoke.texi (lineno): Document. + +2003-11-03 Zdenek Dvorak + + * expr.c (expand_vars, expand_var): Split of ... + (expand_expr_1): ... here. + * expr.h (expand_var): Declare. + * gimple-low.c (lower_function_body, lower_stmt, lower_bind_expr): + Eliminate BIND_EXPRs. + (expand_used_vars): New. + * tree-alias-common.c (create_alias_vars): Walk variables in blocks. + * tree-cfg.c (make_bind_expr_blocks): Removed. + (make_blocks, build_tree_cfg, factor_computed_gotos): Don't handle + BIND_EXPRs. + (assign_vars_to_scope, successor_block, NEXT_BLOCK_LINK): Removed. + (make_edges, make_exit_edges): Don't use successor_block. + (remove_useless_stmts_and_vars_goto): Don't expect NEXT_BLOCK_LINK + to be set. + (bsi_init, bsi_next_in_bb, bsi_from_tsi): Don't handle BIND_EXPRs. + (replace_stmt): Don't create BIND_EXPRs. + * tree-flow.h (struct var_ann_d): Removed field scope. + (struct stmt_ann_d): Removed fields scope and scope_level. + (propagate_copy): Declaration changed. + (fixup_var_scope): Removed. + * tree-must-alias.c (tree_compute_must_alias): Consider DECL_NONLOCAL + vars call clobbered. + * tree-optimize.c (tree_rest_of_compilation): Call expand_used_vars. + * tree-ssa-copyprop.c (move_var_to_scope, fixup_var_scope): Removed. + (copyprop_stmt): Call to propagate_copy changed. + (propagate_copy): Don't update scope. + * tree-ssa-dom.c (cprop_into_stmt): Call to propagate_copy changed. + (eliminate_redundant_computations): Don't call fixup_var_scope. + * tree-ssa.c (insert_copy_on_edge): Don't update scope. + +2003-11-02 Zdenek Dvorak + + * tree-inline.c (walk_tree): Tail recursion optimized for + COMPOUND_EXPRs. + * tree-eh.c (collect_finally_tree): Ditto. + +2003-11-02 Zdenek Dvorak + + * tree-optimize.c (optimize_function_tree): Removed duplicate call of + lower_function_body. Moved call of reset_block_changes ... + (tree_rest_of_compilation) ... here. Reset the scope to top before + expanding function end. + +2003-11-01 Zdenek Dvorak + + * basic-block.h (BB_CONTROL_STRUCTURE): Removed. + * tree-cfg.c (struct cfg_stats_d): Field num_merged_cases removed. + (make_blocks, make_bind_expr_blocks, append_stmt_to_bb, bsi_link_after, + build_tree_cfg, factor_computed_gotos, prepend_stmt_to_bb, + remove_stmt, replace_stmt): Don't set parent. + (set_parent_stmt, add_stmt_to_bb, find_contained_blocks, + blocks_unreachable_p, remove_blocks, remove_unreachable_block, + move_outgoing_edges, merge_tree_blocks, remap_stmts): Removed. + (REMOVE_ALL_STMTS, REMOVE_NO_STMTS, REMOVE_NON_CONTROL_STRUCTS, + REMOVE_CONTROL_STRUCTS): Removed. + (remove_bb): Code to handle control structures removed. + (tree_block_forwards_to): Don't stop due to CASE_LABEL_EXPRs. + (tree_dump_bb): Don't print parent. Print only BIND_EXPRs in slim + form. + (dump_tree_cfg): Don't count merged case labels. + (is_ctrl_structure): Removed. + (stmt_starts_bb_p): Don't handle CASE_LABEL_EXPRs. + (tree_verify_flow_info): Don't check BB_CONTROL_STRUCTURE. + * tree-flow-inline.h (parent_block, parent_stmt): Removed. + * tree-flow.h (struct stmt_ann_d): Remove parent_stmt field. + (parent_stmt, parent_block, is_ctrl_structure): Declarations removed. + * tree-pretty-print.c (dump_generic_node): Don't handle lowered + COND_EXPRs specially. + * tree-ssa-ccp.c (visit_stmt): Don't check is_ctrl_structure. + +2003-10-31 Jeff Law + + * tree-ssa-dom.c (record_equivalences_from_stmt): Restore lost code + to create equivalences from BIT_IOR_EXPR. + + * tree-ssa-dom.c (thread_jumps_walk_stmts): Go ahead and optimize + a COND_EXPR with a compile-time constant condition. + +2003-10-31 Diego Novillo + + * tree-optimize.c (optimize_function_tree): Fix comment + describing SSA pass after DOM2. + +2003-10-31 Diego Novillo + + Fix PR optimization/12825 + * tree-optimize.c (optimize_function_tree): Run SSA renamer after + second DOM pass. + +2003-10-30 Richard Henderson + + * c-common.c (match_case_to_enum_1, match_case_to_enum): New. + (c_do_switch_warnings): New. + * c-common.h (c_do_switch_warnings): Declare. + * c-typeck.c (c_finish_case): Call it. + * stmt.c (all_cases_count, BITARRAY_TEST, BITARRAY_SET, + mark_seen_cases, check_for_full_enumeration_handling): Remove. + (expand_end_case_type): Don't do warn_switch handling. + * expr.h, tree.h: Remove dead decls. + + * c-simplify.c (gimplify_switch_stmt): Force switch body non-null. + +2003-10-30 Richard Henderson + + * tree-cfg.c (thread_jumps): Allow SWITCH_EXPR. + (thread_edge): Handle it. Tidy surrounding code. + +2003-10-30 Richard Henderson + + * domwalk.c (walk_dominator_tree): Pass any final is_ctrl_stmt + down the recursive walk. + +2003-10-30 Jeff Law + + * tree-ssa-dom.c (thread_across_edge): Renamed from + thread_through_successor. Revamp to thread the destination of an edge + rather than the successors of a block. + (dom_opt_finalize_block): Corresponding changes. Do not bother calling + thread_across_edge unless we are at a leaf in the dominator tree. + + * tree-cfg.c (thread_jumps): Now returns a bool. Move some tests into + tree_forwarder_block_p. Improve comments. + (cleanup_control_flow): Now returns a bool indicating if anything was + changed. + (thread_unconditional_jumps): Kill. + (cleanup_tree_cfg): Repeat cascading cleanups until nothing changes. + (tree_forwarder_block_p): Check forwardable bit in the block's + annotation to avoid useless work. Mark blocks as not forwardable as + appropriate. Verify destination is not the exit block here. Do not + consider successors of the entry block as forwarders. Ignore empty + statements when walking through the block's statements. Verify target + block is not the start of a case label and that we can safely insert + a label at the target block. + +2003-10-29 Richard Henderson + + * c-common.c (c_warn_unused_result): Remove lowered containers. + * c-semantics.c (genrtl_case_label): Update add_case_node call. + * c-simplify.c (gimplify_switch_stmt): Build SWITCH_EXPR and + gimplify it simultaneously with the body. + * expr.c (expand_expr_1): Handle SWITCH_BODY clear and + SWITCH_LABELS set. Update add_case_node calls. + * gimple-low.c (lower_stmt): Don't do anything for SWITCH_EXPR. + (lower_switch_expr, lower_case_label_expr): Remove. + * gimplify.c (gimplify_switch_expr): Zap SWITCH_BODY after + gimplification. Force default entry for SWITCH_LABELS. + (gimplify_case_label_expr): Rename from gimple_add_case_label. + Assert switch in scope; lower to LABEL_EXPR. + * stmt.c (pushcase, pushcase_range) Update add_case_node calls. + (add_case_node): Add dont_expand_label argument. + (same_case_target_p): Don't search rtl. + * tree-cfg.c (enum find_location_action): Remove. + (make_switch_expr_blocks): Remove. + (make_blocks): Update. + (make_case_label_edges): Remove. + (make_edges): Update. + (find_contained_blocks): Remove lowered containers. + (make_switch_expr_edges): New. + (make_ctrl_stmt_edges): Call it. + (make_cond_expr_edges): Use label_to_block. + (remove_useless_stmts_and_vars_1): Don't go into SWITCH_BODY. + (remove_unreachable_block): Remove SWITCH_EXPR special case. + (cleanup_cond_expr_graph): Tidy. + (cleanup_switch_expr_graph): Rewrite. + (disconnect_unreachable_case_labels): Remove. + (find_taken_edge_cond_expr): Use integer_zerop/integer_nonzerop. + (find_taken_edge_switch_expr): Rewrite. + (value_matches_some_label): Remove. + (find_case_label_for_value): New. + (is_ctrl_structure): Remove lowered containers. + (is_ctrl_stmt): Add SWITCH_EXPR. + (switch_parent): Remove. + (handle_switch_fallthru): Remove. + (handle_switch_split): Remove. + (find_insert_location): Merge into ... + (bsi_insert_on_edge_immediate): ... here. Simplify. + (tree_split_edge): Don't set EDGE_FALLTHRU. + * tree-eh.c (collect_finally_tree): Remove lowered containers. + (replace_goto_queue_1, block_may_fallthru_last): Likewise. + (lower_eh_constructs_1): Likewise. + (verify_norecord_switch_expr): New. + (lower_try_finally_switch): Generate lowered switches. + * tree-inline.c (expand_calls_inline): Don't search null SWITCH_BODY. + * tree-pretty-print.c (dump_generic_node): Do something sensible + with lowered switch_expr. + * tree-ssa-dom.c (record_equivalences_from_incoming_edge): Update + for lowered switch_expr. + * tree.def (SWITCH_EXPR): Update docs. + * tree.h (add_case_node): Update decl. + +2003-10-29 Daniel Berlin + + * tree-ssa-pre.c (n_phi_preds): New variable. + (generate_vops_as_of_bb): New function + (generate_expr_as_of_bb): Remove unused first argument. Update all + callers. + (subst_phis): Add boundary check for the phi_pred_cache array. + (same_e_version_phi_result): Once modified, no point in continuing + the loop. + (finalize_2): ESSA Minimization can crash if we ended up with new + BB's + +2003-10-29 Richard Henderson + + * tree-eh.c (do_return_redirection): Don't move copy to RESULT_DECL + outside the RETURN_EXPR. Introduce a new temporary as needed. + +2003-10-26 Richard Henderson + + * gimplify.c (keep_function_tree_in_gimple_form): Remove. + (gimplify_function_tree): Return void. Remove hack for + language not supporting gimple. + * tree.h: Update decls. + * langhooks-def.h (LANG_HOOKS_GIMPLE_BEFORE_INLINING): New. + * langhooks.h (struct lang_hooks): Add gimple_before_inlining. + * tree-inline.c (copy_body_r): Check that instead of + keep_function_tree_in_gimple_form. + (initialize_inlined_parameters): Likewise. + (expand_call_inline, expand_calls_inline): Likewise. + + * explow.c (probe_stack_range): Never emit loop notes. + * expr.c (emit_block_move_via_loop): Likewise. + * toplev.c (rest_of_compilation): Always synthesize loop notes. + +2003-10-26 Zdenek Dvorak + + * Makefile.in (gimple-low.o): Add function.h dependency. + * gimple-low.c (struct lower_data): New field block. + (lower_function_body, lower_stmt, lower_bind_expr): Record + the block at statements. + * cfglayout.c (insn_locators_initialize): Use new info about + blocks. + * expr.c (expand_expr): Record block changes. + * function.c (blocks_nreverse): Export. + (uninitialized_vars_warning): Use DECL_RTL_SET_P to test for presence + of rtl. + (reset_block_changes, record_block_change, finalize_block_changes, + check_block_change, free_block_changes): New functions. + * function.h (struct function): New bitfield dont_emit_block_notes. + New field ib_boundaries_block. + (blocks_nreverse, reset_block_changes, record_block_change, + finalize_block_changes, check_block_change, free_block_changes): + Declare. + * sibcall.c (optimize_sibling_and_tail_recursive_call): Don't call + reorder_blocks when dont_emit_block_notes. + * stmt.c (expand_start_bindings_and_block, expand_end_bindings): + Don't emit block notes when dont_emit_block_notes. + * toplev.c (rest_of_compilation): Don't call reorder_blocks when + dont_emit_block_notes. + * tree.c (build1): Initialize TREE_BLOCK field. + * tree-flow.h (lower_function_body): Declare. + * tree-optimize.c: Include function.h. + (optimize_function_tree): Call lower_function_body. + * tree.h (struct tree_exp): Add block field. + (TREE_BLOCK): New macro. + +2003-10-26 Richard Henderson + + * tree.h (tree_dump_index): Add TDI_lower. + * tree-dump.c (dump_files): Add .lower entry. + * tree-optimize.c (optimize_function_tree): Move lower_function_body, + (tree_rest_of_compilation): here. Tidy .useless dump. + +2003-10-25 Jan Hubicka + + * c-common.c (c_estimate_num_insns_1): Kill. + (c_estimate_num_insns): Kill. + * c-common.h (c_estimate_num_insns): Kill. + * c-lang.c (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): Kill. + * cp-lang.c (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): Kill. + * objc-lang.c (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): Kill. + * java/lang.c (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): Kill. + (java_estimate_num_insns_1, java_estimate_num_insns): Kill. + * cgraphunit (cgraph_analyze_function): Use estimate_num_insns. + * tree-eh.c (decide_copy_try_finally): Likewise. + * tree-inline.c (limits_allow_inilining, optimize_inline_calls): Likewise. + (estimate_num_insns_1, estimate_num_insns): New functions. + * langhooks-def.h (LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS): Kill. + * langhooks.h (estimate_num_inssn): Kill. + * tree-inline.h (estimate_num_insns): Declare. + +2003-10-25 Zdenek Dvorak + + * gimple-low.c: New. + * Makefile.in (gimple-low.o): Add. + * domwalk.c (walk_dominator_tree): Consider COND_EXPR a control + structure. + * tree-cfg.c (make_cond_expr_blocks, linearize_control_structures, + linearize_cond_expr): Removed. + (thread_jumps, tree_forwarder_block_p): New. + (merge_tree_blocks): Unused now. + (phi_alternatives_equal): Modified for use in jump threading. + (enum find_location_action): Remove EDGE_INSERT_LOCATION_NEW_ELSE. + (make_blocks): Don't call make_cond_expr_blocks. + (set_parent_stmt): Ensure we don't set COND_EXPR as a parent + statement. + (find_contained_blocks): Remove COND_EXPR alternative. + (make_cond_expr_edges): Handle lowered gotos. + (cleanup_tree_cfg): Don't call linearize_control_structures, + call thread_jumps and verify_flow_info and rerun cleanup_control_flow. + (remove_unreachable_block): Remove handling of structured COND_EXPRs. + (remove_bb): Fix warning for removed goto exprs. + (cleanup_control_flow, cleanup_cond_expr_graph, + cleanup_switch_expr_graph, find_taken_edge_cond_expr, + bsi_insert_before, find_insert_location, bsi_insert_on_edge_immediate): + Handle lowered COND_EXPRs. + (is_ctrl_structure): Remove COND_EXPR. + (is_ctrl_stmt): Add COND_EXPR. + (tree_verify_flow_info): Check validity of COND_EXPRs. + (thread_edge): Moved from tree-ssa-dom.c. + * tree-flow.h (cleanup_cond_expr_graph, cleanup_switch_expr_graph): + Declaration changed. + (thread_edge, lower_function_body): Declare. + * tree-optimize.c (optimize_function_tree): Call lower_function_body. + * tree-pretty-print.c (dump_generic_node): Dump lowered cond_exprs in + full. + * tree-ssa-copyprop.c (fixup_var_scope): Handle non-SSA_NAMEs. + * tree-ssa-dce.c (stmt_useful_p, process_worklist): Cleaned up when + COND_EXPRs are lowered. + * tree-ssa-dom.c (thread_edge): Moved to tree-cfg.c. + (tree_ssa_dominator_optimize_1): Dumps and setting of vars_to_rename + moved from thread_edge. + (optimize_stmt): Pass block iterator to cleanup_cond_expr_graph and + cleanup_switch_expr_graph. + * tree-ssa.c (insert_copy_on_edge): Fixup scope for emitted variables. + + * dominance.c (BB_NODE): Use VARRAY_GENERIC_PTR_NOGC. + (calculate_dominance_info): Use VARRAY_GENERIC_PTR_NOGC_INIT. + * varray.c (element): Add GENERIC_PTR_NOGC entry. + * varray.h (enum varray_data_enum): Add VARRAY_DATA_GENERIC_NOGC. + (union varray_data_tag): Add generic_nogc. + (VARRAY_GENERIC_PTR_NOGC_INIT, VARRAY_GENERIC_PTR_NOGC, + VARRAY_PUSH_GENERIC_PTR_NOGC, VARRAY_TOP_GENERIC_PTR_NOGC): New. + +2003-10-25 Jan Hubicka + + * cppcharset.c (one_utf8_to_utf32): Initialize 's' to silence warning. + +2003-10-25 Jan Hubicka + + * fold-const.c (nondestructive_fold_binary_to_constant): Realize that + (plus (address) (const_int)) is a constant. + +2003-10-25 Jan Hubicka + + * opts.c (decode_options): Uncomment unit-at-a-time setting + * params.def: Syncrhonize with manline. + * tree-inline.c (initialize_inlined_parameters): Set variable as + gimplified. + +2003-10-24 Steven Bosscher + + * gimplify.c (create_artificial_label): New function. + (build_and_jump): Use it. + * c-simplify.c (c_gimplify_stmt): Likewise. + (gimplify_condition): Likewise. + * tree-cfg.c (factor_computed_gotos, tree_block_forwards_to, + handle_switch_fallthru, handle_switch_split): Likewise. + * tree-ssa-dom.c (thread_edge): Likewise. + * tree-ssa-pre.c (split_critical_edges): Likewise. + * tree-tailcall.c (eliminate_tail_call): Likewise. + * tree-eh.c (frob_into_branch_around, + honor_protect_cleanup_actions, lower_try_finally_nofallthru, + lower_try_finally_onedest, lower_try_finally_copy, + lower_try_finally_switch, lower_catch, lower_eh_filter, + lower_cleanup): Likewise. + (make_label): Remove. + * tree-simple.h (create_artificial_label): Add prototype. + * tree-inline.c (expand_call_inline): Make return label for + inlined function artificial. + +2003-10-23 Jeff Law + + * timevar.def (TV_TREE_SSA_THREAD_JUMPS): New timevar. + * tree-dump.c (dump_files): Add dump file for jump threading. + * tree.h (TDI_thread_jumps): New enum member. + * tree-cfg.c (tree_block_forwards_to): No longer static. + * tree-flow.h (tree_block_forwards_to): Prototype. + (tree_ssa_dominator_thread_jumps): Likewise. + * tree-optimize.c (optimize_function_tree): Call jump threader. + * tree-ssa-dom.c (tree_ssa_dominator_optimize_1): New function. + Common code for redundancy elimination and jump threading on + the dominator tree. Slightly different callback initialization + for redundancy elimination and jump threading. Initialize + block forwardable attribute. + (tree_ssa_dominator_optimize): Call tree_ssa_dominator_optimize_1. + (tree_ssa_dominator_thread_jumps): New function. + (thread_edge): Mark results of PHI nodes as needing rewriting if + we have threaded through a block with PHI nodes. + (thread_through_successor): If thread_through_phis is nonzero, + then allow jump threading through blocks with PHI nodes. If the + target block is a forwarder block, then forward the jump. + (thread_jumps_walk_stmts): Statement walker for dominator thread + jumping. + + * tree-ssa-dom.c (record_equivalence_from_incoming_edge): Fix + comment typo. + +2003-10-23 Richard Henderson + + * gimplify.c (gimplify_*): Return gimplify_status. + (gimple_add_tmp_var): Set seen_in_bind_expr. + (gimplify_bind_expr): Likewise. Kill if 0 code. + (gimplify_return_expr): Cope with error marks. + (gimple_push_cleanup): Do nothing if errors seen. + (gimplify_expr): Cope with error marks. Use gimplify_status to + decide when to exit the main loop. Zap statements with errors. + (gimplify_body): Return void. + (keep_function_tree_in_gimple_form): Don't exit on errors. + (gimplify_function_tree): Return bool. Don't exit on errors. + * langhooks.c (lhd_gimplify_expr): Return GS_UNHANDLED. + * langhooks.h (struct lang_hooks): Update docs for gimplify_expr. + * tree-optimize.c (optimize_function_tree): Don't exit on errors. + Move delete_tree_cfg call outside optimization clause. + (tree_rest_of_compilation): Don't exit on errors. + * tree-simple.h (enum gimplify_status): New. + (gimplify_expr, gimplify_stmt, gimplify_body): Update. + * tree-ssa.c (rewrite_out_of_ssa): Move delete_tree_cfg call to + optimize_function_tree. + * tree.h (struct tree_decl): Add seen_in_bind_expr. + (gimplify_function_tree): Update. + * c-common.c (c_add_case_label): Unify three error exit paths. + Create a normal label, not a case label to suppress unreachable + code warning. + * c-simplify.c (c_build_bind_expr): Don't create an empty bind + body. Pass entire bind_expr to gimplify_stmt. + (gimplify_block): Don't abort on mismatches if errors seen. + (gimplify_expr_stmt): Cope with error marks. + (gimplify_decl_stmt): Likewise. + (c_gimplify_expr): Return gimplify_status. + +2003-10-22 Daniel Berlin + + * tree-pretty-print.c (dump_generic_node): Kill off ELEFT_NODE. + Print out status of new EUSE_LVAL flag. + + * tree-ssa-pre.c: #include alloc-pool.h + (append_eref_to_block): Inline. + (names_match_p): Ditto. + (pre_expression): Take sbitmap of variables to rename so we can + mark our new variable if necessary. + (insert_occ_in_preorder): Completely redo to be an O(n log n) + algorithm worst case, instead O(n^2) all the time. + (build_dfn_array): New function. + (eref_compare): Ditto. + (preorder_count): Remove no-longer used variable. + (pre_stats): Add new stats about memory use. + (struct expr_info): add loadpre_cand member. + (euse_node_pool): New alloc-pool + (eref_node_pool): Ditto + (create_expr_ref): Use them. + (expr_phi_insertion): Insert on PHI's of VUSES for loadpre cands. + Not all expressions have uses (left occurrences don't). + (load_modified_real_occ_real_occ): Return false, not abort. + (process_delayed_rename): Remove useless fibheap, do proper LVAL + handling. + (insert_euse_in_preorder_dt_order_1): No more ELEFT_NODE's. + (finalize_1): Ditto. + (set_save): Ditto. + (really_available_def): New function. + (finalize_2): Use really_available_def, not EUSE_SAVE, during EPHI + minimization. + (names_match_p): Handle INDIRECT_REF properly. + (call_modifies_slot): Removed. + (add_call_to_ei): Removed. + (process_left_occs_and_kills): Fix. + (pre_expression): Zero out counts. + (collect_expressions): Split out from tree_perform_ssapre. Do this + in domtree order. + (tree_perform_ssapre): Create and free alloc-pools. + Rename new variables that need to be renamed. + + * tree.c (tree_size): Remove ELEFT_NODE. + (tree_node_size): Ditto. + (is_essa_node): Ditto. + + * tree.def (ELEFT_NODE): Gone. + + * tree.h (EREF_NODE_CHECK): No more ELEFT_NODE. + (struct tree_eref_common): Add ID flag. + (struct tree_euse_node): Add lval flag. + (EREF_ID): New macro. + (EUSE_LVAL): New macro. + +2003-10-22 Daniel Berlin + + * tree-flow-inline.h (add_dom_child): XMALLOC, not GGC_ALLOC, + the bitmap. + (clear_dom_children): XFREE the bitmap. + +2003-10-22 Andrew MacLeod + + * tree-ssa-live.c (new_tree_live_info, (delete_tree_live_info, + live_worklist, set_if_valid, add_livein_if_notdef, + calculate_live_on_entry, calculate_live_on_exit, + add_conflicts_if_valid, dump_live_info): Use bitmap instead of sbitmap. + (build_tree_conflict_graph): Use bitmap, Change mechanism for + adding conflicts between live-on-entry partitions. + * tree-ssa-live.h (struct tree_live_info_d): Switch to bitmaps. + (partition_is_global, live_entry_blocks, live_on_exit, + live_merge_and_clear, make_live_on_entry): Switch to bitmaps. + * tree-ssa.c (struct _elim_graph): Remove bitmaps, use varrays. + (new_elim_graph, clear_elim_graph, delete_elim_graph): Switch from + old bitmap implementation. + (elim_graph_size): New. Number of elements in elimination graph. + (elim_graph_add_node): New. Add an element to the elim-graph. + (elim_graph_add_edge): New. Add an edge to the elim-graph. + (elim_graph_remove_succ_edge): New. Remove an edge for which a node + has a successor. + (FOR_EACH_ELIM_GRAPH_SUCC): Find all successor nodes. + (FOR_EACH_ELIM_GRAPH_PRED): Find all predeccesor nodes. + (eliminate_name, eliminate_build, elim_forward, + elim_unvisited_predecessor, elim_backward, elim_create, eliminate_phi): + Use new elim-graph routines. + (rewrite_out_of_ssa): Enable single-definition compaction when not + combining temporaries. + +2003-10-21 Richard Henderson + + * gimplify.c: Sort functions into use order, and all gimplification + functions to the end. + +2003-10-22 Jeff Law + + * tree-cfg.c (thread_unconditional_jumps): New function. + (tree_block_forwards_to): Likewise. + (cleanup_tree_cfg): Call thread_unconditional_jumps. + * tree-flow.h (bb_ann_t): Add forwardable status bit. + + * tree-dump.c (dump_files): Add entry for TDI_none. + (dump_begin): Do nothing for TDI_none. + (dump_enable_all, dump_switch_p): Start our scan at TDI_none + 1. + * tree.h (tree_dump_index): Add. + * tree-ssa-dom.c (tree_ssa_dominator_optimize): If we have altered the + CFG and we have variables to [re]rename, go ahead and rename them before + starting the next iteration of the dominator optimizer. + +2003-10-21 Jason Merrill + + * gimplify.c (gimplify_modify_expr): Require a regvar on either + the lhs or rhs if we're dealing with a renameable type. + (canonicalize_component_ref): New fn. + (gimplify_compound_lval): Use it. + (gimplify_conversion): Use it. + (gimplify_expr): Lose redundant STRIP_MAIN_TYPE_NOPS. + Discard conversions in void context. + +2003-10-21 Daniel Berlin + + * tree-ssa-pre.c (pre_expression): Free and allocate the + ephi_pindex_htab and phi_pred_cache in this function only. + (phi_pred_cache): New array to store cached phi preds, to avoid + recomputation and unnecessary copying. + (subst_phis): Use it. + (added_phis): array of added phis that is marked for GC. + + * Makefile.in: Add tree-ssa-pre.c to the gtype files, and + gt-tree-ssa-pre.h to the list of generated files. + +2003-10-21 Jason Merrill + + PR optimization/12661 + * tree-dfa.c (get_expr_operands): Handle TRUTH_NOT_EXPR. + * tree-simple.c (is_gimple_rhs): Allow TRUTH_NOT_EXPR. + * gimplify.c (gimplify_expr) : Don't rewrite to an + EQ_EXPR. + +2003-10-21 Jan Hubicka + + * haifa-sched.c (choose_ready): Initialize index. + * tree-tailcall.c (bb_optimize_tail_calls): Initialize has_return. + * f/lex.c (ffelex_cfelex_): Initialize d. + +2003-10-20 Diego Novillo + + Fix PR optimization/12688 + * tree-dfa.c (get_stmt_operands): Don't return early when dealing + with an empty statement. + * tree-ssa-ccp.c (set_rhs): If the expression has no side effects, + replace the statement with an empty statement. + +2003-10-20 Andrew MacLeod + + * tree-ssa-dce.c (processed): Change to an sbitmap. + (mark_necessary): Test bits in 'processed'. + (tree_ssa_dce): Initialize/free processed as an sbitmap. + +2003-10-20 Diego Novillo + + * tree-cfg.c (bsi_prev): Also copy the context from the previous + iterator. + +2003-10-18 Richard Henderson + + * builtins.c (simplify_builtin): Handle BUILT_IN_CONSTANT_P. + +2003-10-18 Zdenek Dvorak + + * tree-tailcall.c: New. + * Makefile.in (tree-tailcall.o): Add. + * function.c (assign_parms): Setting of current_function_stdarg + moved ... + (allocate_struct_function): ... here. + * tree-dump.c (dump_files): Add .tail dump. + * tree-flow.h (tree_optimize_tail_calls): Declare. + * tree-optimize.c (optimize_function_tree): Call + tree_optimize_tail_calls. + * tree.h (enum tree_dump_index): Add TDI_tail. + +2003-10-18 Jan Hubicka + + * tree-ssa-copyprop.c (move_var_to_scope): Do not clear abstract + origin for static variables. + +2003-10-18 Jan Hubicka + + * integrate.c (copy_decl_for_inlinig): Fix copying of copies. + +2003-10-18 Jan Hubicka + + * cgraphunit.c (cgraph_analyze_function): Fix call of estimate_num_insns. + +2003-10-17 Kazu Hirata + + * ChangeLog.tree-ssa: Fix typos. + * tree-alias-common.c: Fix comment typos. + * tree-cfg.c: Likewise. + * tree-dfa.c: Likewise. + * tree-eh.c: Likewise. + * tree-flow.h: Likewise. + * tree-iterator.h: Likewise. + * tree-mudflap.c: Likewise. + * tree-ssa-ccp.c: Likewise. + * tree-ssa-dce.c: Likewise. + * tree-ssa-dom.c: Likewise. + * tree-ssa-live.c: Likewise. + * tree-ssa-live.h: Likewise. + * tree-ssa-pre.c: Likewise. + * tree-ssa.c: Likewise. + +2003-10-17 Andrew MacLeod + + * tree-ssa-dce.c (processed): New Global vector. + (mark_necessary): Check if SSA_NAME has already been processed first. + (find_useful_stmts, process_worklist): Change call to mark_necessary(). + (tree_ssa_dce): Initialize and free processed vector. + * tree-cfg.c (handle_switch_fallthru): A new basic block can result + from splitting edges of nested switch stmts. + (handle_switch_split): If a new block is created, restart the loop for + inserting GOTO's to handle the new block. + +2003-10-17 Jan Hubicka + + * tree-cfg.c (remove_useless_stmts_and_vars_bind): Fix handling of + static variables. + +2003-10-16 Richard Henderson + + * common.opt (fdisable-gimple): Remove. + * flags.h (flag_disable_gimple): Remove. + * toplev.c (flag_disable_gimple): Remove. + (process_options): Don't check it. + (lang_independent_options): Don't set it. + * opts.c (common_handle_option): Likewise. + * gimplify.c (keep_function_tree_in_gimple_form): Don't check it. + * c-semantics.c (expand_stmt_toplev): Likewise. + * tree-optimize.c (tree_rest_of_compilation): Likewise. + * doc/invoke.texi: Don't document it. + +2003-10-16 Roger Sayle + + * fold-const.c: Merge from mainline. + * tree.c (associate_tree_code, commutative_tree_code): Use a + switch statement instead of a sequence of comparisons. + +2003-10-16 Richard Henderson + + * gimplify.c (maybe_protect_cleanup): Remove. + * tree-simple.h (maybe_protect_cleanup): Remove. + * c-simplify.c (gimplify_cleanup): Don't call it. + +2003-10-16 Jeff Law + + * tree-cfg.c (found_computed_goto): New global for computed goto + factoring/unfactoring. + (factored_computed_goto_label, factored_computed_goto): Likewise. + (factor_computed_gotos): New function. + (build_tree_cfg): Use it. + (make_blocks): Record whether or not we find a computed goto. + (remove_useless_stmts_and_vars): Un-factor computed gotos. + (remove_useless_stmts_and_vars): Reset factored_computed_goto_label + and factored_computed_goto. + + * tree-ssa-dom.c (get_value_for, set_value_for): Move to the start + of the file. Delete pointless sanity checking. + + * tree-ssa.c (currdefs): Now a varray instead of a hash table. + (get_value_for, set_value_for): Corresponding changes. Move to + the start of the file and delete pointless sanity checking. + (rewrite_into_ssa, dump_tree_ssa_stats): Corresponding changes. + (var_value_hash, var_value_eq): Kill. + + * tree-ssa.c (rewrite_add_phi_arguments): Once we encounter a + rewritten PHI break the inner loop. + + * tree-ssa.c (insert_phi_nodes_for): Use EXECUTE_IF_AND_COMPL_IN_BITMAP. + + * tree-dfa.c (create_phi_node): Clear PHI_REWRITTEN on all new PHIs + (remove_all_phi_nodes_for): Set PHI_REWRITTEN on any PHIs which are + not removed. + * tree-ssa.c (rewrite_add_phi_arguments): Check the PHI node itself + to see if it has already been rewritten. + * tree.h (PHI_REWRITTEN): New accessor macro. + (struct phi_node): New field rewritten. + + * tree-flow.h (struct bb_ann_d): New field num_preds. + * tree-dfa.c (create_phi_node): Get the number of predecessors from + the block's annotation. + * tree-ssa.c (rewrite_into_ssa): Compute number of preds for each + block and store it into the block's annotation. + (insert_phi_nodes_for): Get the number of preds for each block + from the block's annotation. + + * tree-ssa.c: Remove parallel lifetime analysis code from April 2003. + (def_blocks_d): Remove PHI_INSERTION_POINTS field. + (compute_global_livein): Accept livein/def bitmaps to use for + life analyis rather than a varray of variables. Callers updated. + Rewritten to compute life information for one variable at a + time instead of several variables at once. + (insert_phis_for_deferred_variables): Remove. + (insert_phi_nodes_for): Lose varray argument. Callers updated. + No longer mess with deferring PHI insertions for variables. + (insert_phi_nodes): No longer need to deal with deferred variables. + Kill everything related to them. + +2003-10-15 Jeff Law + + * domwalk.c, domwalk.h: New files. + * Makefile.in (OBJS-common): Add domwalk.c. + (tree-ssa-dom.o): Add dependency on $(BASIC_BLOCK_H) and domwalk.h. + (tree-ssa.o): Add dependency on domwalk.h. + (domwalk.o): Add dependencies. + * tree-ssa-dom.c: Include domwalk.h. + (cfg_altered, vars_to_rename): Now globals. + (dom_walk_block_data): New structure for block data used by dominator + walker. + (optimize_block, record_equivalences_from_block_entry): Kill. + (optimize_stmt): Lose "cfg_altered" argument. Update callers. + Initialize may_have_exposed_new_symbols. + (get_value_for, set_value_for): Lose "table" argument. Update + callers. Use const_and_copies table directly. + (lookup_avail_expr): Lose "const_and_copies" argument. Callers + updated. + (get_eq_expr_value): Similarly. Also accept a pointer to the + vrp_variables. Callers updated. + (update_rhs_and_lookup_avail_expr): Similarly. + (record_cond_is_true, record_cond_is_false): Similarly. + (simplify_rhs_and_lookup_avail_expr): Similarly. + (simplify_cond_and_lookup_avail_expr): Similarly. + (record_equivalences_from_phis): Similarly. + (record_equivalences_from_incoming_edge): Similarly. Also accept + a pointer to the block const_and_copies table and vrp_variables. + Callers updated. + (eliminate_redundant_computations): Similarly + (record_equivalences_from_stmt, thread_through_successor): Similarly. + (dom_opt_initialize_block): New function. Perform block local + initialization for the dominator optimizer. + (dom_opt_finalize_block): Renamed from finalize_block. Get + block local varrays from walk_data. Pop entry off block local + data stack when complete. + (dom_opt_walk_stmts): New function. + (cprop_into_phis): Get block local varrays from walk_data. + (record_range): Get vrp varray by reference than by value. + (tree_ssa_dominator_optimize): Store incoming "vars" variable into + global "vars_to_rename". Initialize walk_data. Use + walk_dominator_tree. + (cprop_into_stmt): Initialize may_have_exposed_new_symbols. + * tree-ssa.c: Include domwalk.h + (rewrite_finalize_block, rewrite_initialize_block): New functions + extracted from rewrite_block. + (rewrite_walk_stmts, rewrite_add_phi_arguments): Similarly. + (rewrite_block): Kill. + (rewrite_into_ssa): Initialize walk_data. Use walk_dominator_tree. + +2003-10-14 Richard Henderson + + * gimplify.c (gimplify_expr): Return bool. Bail gracefully if + fb_mayfail is set. + (gimplify_asm_expr): Take pointer-to-expr. Allow gimplify_expr + to fail for lvalues, and issue appropriate error messages. Zap + the entire asm statement on failure. + * tree-simple.h (enum fallback_t): Add fb_mayfail. + +2003-10-14 Richard Henderson + + * c-tree.h (C_LANG_TREE_NODE_CHAIN_NEXT): New. + (union lang_tree_node): Use it for chain_next annotation. + +2003-10-14 Richard Henderson + + * c-common.c: Include tree-iterator.h. + (c_expand_expr): Kill warn_unused_result checks. + (c_warn_unused_result): New. + * c-common.h (STMT_EXPR_WARN_UNUSED_RESULT): Remove. + (c_warn_unused_result): Declare. + * c-decl.c (finish_function): Always gimplify. Call + c_warn_unused_result. + * calls.c (expand_call): Kill warn_unused_result checks. + * Makefile.in (c-common.o): Update. + +2003-10-15 Steven Bosscher + + * cfghooks.c (dump_bb): Take extra `int indent' argument. + * cfg.c (dump_bb): Take extra argument to match cfg hook. + Write out all information about bb that is shared between the tree + and rtl representations. + * basic-block.c (dump_bb): Adjust prototype. + * cfgrtl.c (rtl_dump_bb): Update prototype to match cfg hook. + Use indent. + * flow.c (verify_wide_reg, verify_local_live_at_start): + Fixup dump_bb calls. + * tree-cfg.c (dump_tree_bb): Rename to tree_dump_bb. Remove unused + `prefix' argument. Put in tree_cfg_hooks as cfg hook for dump_bb. + (remove_bb, debug_tree_bb, dump_tree_cfg): Call dump_bb. + * tree-ssa (dump_tree_ssa): Likewise. + * tree-flow.h (dump_tree_bb): Replace with new tree_dump_bb + prototype. + * tree-pretty-print (dump_block_info): Match case of BLOCK, SUCC, + PRED with dump_bb. + +2003-10-14 Daniel Berlin + + * tree-alias-ander.c (throwaway_global): Delete. + (andersen_same_ponts_to_set): We handle all globals individually + now. + * tree-alias-common.c: Remove doxygen markers. + (get_alias_var_decl): Always create an alias var for globals now. + Assign the global alias vars to GLOBAL_VAR, too. + (intra_function_call): Fix logic, do a bit of pre-filtering to + avoid useless global aliasing. + (get_values_from_constructor): It's the same for field based and + not field based. + (create_alias_vars): Remove special global var handling. + (same_points_to_set): Ditto. + (ptr_may_alias_var): Ditto. + +2003-10-14 Jeff Law + + * tree-ssa-dom.c (cprop_into_phis): Avoid doing useless work if the + edge we care about is abnormal. + * tree-ssa-copyprop (cprop_phi): Avoid doing useless work if the + destination of the PHI node occurs in an abnormal PHI. + + * tree-ssa-dom.c (record_equivalences_from_stmt): Renamed from + record_equivalances. Caller updated. + (record_equivalences_from_phis): New function extracted from + optimize_block. + (record_equivalences_from_incoming_edge): Likewise. + (record_equivalances_from_block_entry): Likewise. + (cprop_into_phis): Likewise. + (optimize_stmt): Lots of code moved into new functions. Call + record_equivlances_from_block_entry. + + * tree-ssa-dom.c (optimize_block): Simplify interface slightly. + Use finalize_block. Extract edge_flags from our block's + incoming edge as necessary. Simplify recursive call. + (thread_through_successor): Extracted from optimize_block. + (finalize_block): Similarly. + + * tree-ssa-dom.c (eliminate_redundant_computations): New function + extracted from optimize_stmt. + (record_equivalences): Similarly. + (optimize_stmt): Use eliminate_redundant_computations and + record_equivalences. If fold_stmt changes stmt, then make sure + to get a new annotation as well. + + * tree-cfg.c (cleanup_control_flow): Pass last statement down to + cleanup_cond_expr_graph and cleanup_switch_expr_graph. + (cleanup_cond_expr_graph): Accept statement from caller and + use it. Return nonzero if the predicate was constant. No longer + static. + (cleanup_switch_expr_graph): Similarly. + (disconnect_unreachable_case_labels): Similarly, except that it + is still static. + * tree-flow.h (cleanup_cond_expr_graph): Prototype. + (cleanup_switch_expr_graph): Similarly. + * tree-ssa-dom.c (optimize_stmt): Also optimize the condition + in a SWITCH_EXPR. Use COND_EXPR_COND and SWITCH_COND to get + conditions instead of relying upon known operand positions. + Use cleanup_cond_expr_graph and cleanup_switch_expr_graph rather + than open coding equivalents. + (lookup_avail_expr): Handle SWITCH_EXPRs. Use COND_EXPR_COND and + SWITCH_COND to get conditions instead of relying upon known + operand positions. + (avail_expr_hash, avail_expr_eq): Similarly. + +2003-10-14 Richard Henderson + + * gimplify.c (gimplify_body): Save and restore input_location; + initialize input_location to DECL_SOURCE_LOCATION. + (gimplify_expr): Always save and restore input_location. + +2003-10-14 Richard Henderson + + * expr.c (expand_expr): Break out EXPR_LOCUS code from ... + (expand_expr_1): ... here, renamed from expand_expr. + +2003-10-13 Richard Henderson + + * c-simplify.c (c_gimplify_stmt): Upreate on location_t and not + fine and line individually. + (gimplify_c_loop, gimplify_switch_stmt): Likewise. + * gimplify.c (wfl_locus): Merge wfl_filename+wfl_lineno. + (annotate_all_with_locus_1): Rename from annotate_stmt_with_file_line. + (annotate_all_with_locus): Replace annotate_all_with_file_line; + update all callers. + * tree-simple.h: Update. + * tree.c, tree.h (annotate_with_locus): New. + +2003-10-13 Steven Bosscher + + * tree-flow-inline.h (def_ops): Take a stmt_ann_t as argument + instead of a tree. + (use_ops): Likewise. + (vdef_ops): Likewise. + (vuse_ops): Likewise. + * tree-flow.h: Update prototypes. + * tree-cfg.c (remove_stmt): Load the statement annotation. + Adjust *_ops calls. + * tree-dfa.c (compute_immediate_uses_for_stmt, + mark_new_vars_to_rename): Likewise. + * tree-pretty-print.c (dump_vops): Likewise. + * tree-ssa-ccp.c (tree_ssa_ccp): Likewise. Also remove now + superfluous stmt_ann() calls. + (visit_stmt, cpp_fold, add_var_to_ssa_edges_worklist, + initialize, replace_uses_in, likely_value): Likewise. + * tree-ssa-copyprop.c (copyprop_stmt): Likewise. + * tree-ssa-dce.c (stmt_useful_p, process_worklist): Likewise. + * tree-ssa-dom.c (cprop_into_stmt, optimize_stmt, + avail_expr_hash, avail_expr_eq): + Likewise. + * tree-ssa-live.c (create_ssa_var_map, calculate_live_on_entry, + build_tree_conflict_graph): Likewise. + * tree-ssa-pre.c (maybe_find_rhs_use_for_var, + expr_phi_insertion, same_e_version_real_occ_real_occ, + generate_expr_as_of_bb, bool load_modified_real_occ_real_occ, + bool same_e_version_phi_result, get_default_def,reaching_def, + tree_perform_ssapre): Likewise. + * tree-ssa.c (mark_def_sites, rewrite_out_of_ssa, rewrite_stmt): + Likewise. + +2003-10-12 Richard Henderson + + * gimplify.c (gimplify_array_ref_to_plus): Be prepared for + null TYPE_DOMAIN or TYPE_MIN_VALUE for the array. + * tree-ssa-ccp.c (fold_indirect_refs_r): Likewise. + +2003-10-12 Richard Henderson + + * tree.h (struct tree_common): Rename unused_1 to invariant_flag. + (TREE_INVARIANT): New. + * builtins.c (build_string_literal): Set TREE_INVARIANT. + * c-common.c (fix_string_type): Likewise. + * c-typeck.c (build_external_ref): Likewise. + (build_c_cast, pop_init_level): Likewise. + * fold-const.c (fold_convert, fold): Likewise. + * tree.c (make_node, build_constructor): Likewise. + (build, build1): Likewise. + (staticp): Pass unknown component references to the language. + (save_expr): Check TREE_INVARIANT instead of TREE_CONSTANT. + (skip_simple_arithmetic): Likewise. + (stabilize_reference_1): Likewise. + * print-tree.c (print_node): Print TREE_INVARIANT. + + * c-common.c (pointer_int_sum): Rely on build to set TREE_CONSTANT. + (finish_label_address_expr): Likewise. + * c-typeck.c (default_function_array_conversion): Likewise. + (parser_build_binary_op, pointer_diff): Likewise. + (build_unary_op, build_binary_op): Likewise. + * fold-const.c (non_lvalue): Likewise. + + * tree-pretty-print.c (dump_generic_node): Handle VIEW_CONVERT_EXPR. + +2003-10-12 Richard Henderson + Diego Novillo + + * gimplify.c (gimplify_array_ref_to_plus): Subtract the array + domain minimum index. + (gimplify_addr_expr): Expand ARRAY_REFs. Cope with Fortran + missing cast wierdnesses. + * tree-dfa.c (get_expr_operands): Handle (&v + c); abort on + other address invariants that should have been folded. + (vdefs_disappeared_p): New. + (mark_new_vars_to_rename): Use it. Move from ... + * tree-ssa-dom.c: ... here. + * tree-flow-inline.h (is_unchanging_value): Remove; use + is_gimple_min_invariant everywhere instead. + (phi_ssa_name_p): New. + * tree-must-alias.c (find_addressable_vars): Process PHIs. + * tree-simple.c (is_gimple_min_invariant): Rename from + is_gimple_const; allow non-static variable addresses; update callers. + (is_gimple_val): Remove ADDR_EXPR checks. + * tree-simple.h: Update. + * tree-ssa-ccp.c (replace_uses_in): Add replaced_address argument. + (substitute_and_fold): Use that to mark_new_vars_to_rename. + (fold_indirect_refs_r): New. + (fold_stmt): Use it. + * tree-ssa-copyprop.c (copyprop_stmt): Call fold_stmt. + * tree-ssa-dce.c (NECESSARY): Use asm_written_flag. + (mark_necessary): Reject DECLs. + * tree-ssa-live.c (register_ssa_partition): Use phi_ssa_name_p. + * tree-ssa-pre.c (generate_expr_as_of_bb): Call fold_stmt if we + replaced with constants. + * tree-ssa.c (insert_copy_on_edge): Unwrap ADDR_EXPRs to set_is_used. + (eliminate_build, coalesce_abnormal_edges, coalesce_vars): Use + phi_ssa_name_p. + +2003-10-09 Frank Ch. Eigler + + java/12211 + * gimplify.c (gimplify_save_expr): Tolerate void-typed saved + expressions. + +2003-10-09 Diego Novillo + + * tree-dfa.c (add_call_clobber_ops): If a variable is read-only, + add a VUSE operand instead of VDEF. + +2003-10-08 Jason Merrill + + PR optimization/12525 + * tree-dfa.c (note_addressable): New fn, split out from... + (add_stmt_operands): Here. + (get_stmt_operands) : Call it for mem ops. + * gimplify.c (gimplify_asm_expr): Call parse_input_constraint + directly. It's only a mem op if allows_mem is set. + +2003-10-08 Diego Novillo + + PR/12187 + * tree-dfa.c (add_stmt_operand): Test against current_function_decl + when checking for global variables. + (may_access_global_mem_p): Likewise. + (add_referenced_var): Likewise. + Consider DECL_NONLOCAL variables call clobbered and used. + (find_hidden_use_vars): Do not test for DECL_NONLOCAL variables. + * tree-optimize.c (tree_rest_of_compilation): Test against + current_function_decl when checking for global variables. + * tree-ssa-ccp.c (get_default_value): Likewise. + * tree-ssa-dce.c (need_to_preserve_store): Likewise. + +2003-10-07 Jason Merrill + + PR optimization/12525 + * gimplify.c (gimplify_asm_expr): If the constraint doesn't allow + a register, call mark_addressable. Split an in/out operand that + does allow a register into separate input and output operands. + +2003-10-06 Richard Henderson + + * fold-const.c (fold): Fold (T1)((T2)X op Y) into (T1)X op Y, + for suitable values of T1 & T2. + +2003-10-06 Andrew Macleod + + * tree-dfa.c (compute_immediate_uses): Add optional callback. + (compute_immediate_uses_for_phi): Remove unused parameter. Add optional + callback to determine if usage info should be calculated for variable. + (compute_immediate_uses_for_stmt): Add optional callback to determine + if usage info should be calculated for variable. + * tree-flow.h (compute_immediate_uses): Update prototype. + * tree-ssa-ccp.c (need_imm_uses_for): New. Callback function passed to + compute_immediate_uses. + (initialize): Calculate defaults initially, then build reduced + immediate use information. + (get_default_value): Non empty stmt's which are not a PHI_NODE or + a MODIFY_EXPR default to VARYING. + +2003-10-06 Andrew Macleod + + * tree-cfg.c (tree_split_edge): Mark edge as FALLTHRU when splitting. + +2003-10-03 Zdenek Dvorak + + * tree-ssa.c (rewrite_block): Test vars_to_rename instead of + PHI_ARG_CAPACITY. + * tree-dfa.c (remove_phi_arg_num): Don't update + PHI_ARG_CAPACITY. + +2003-10-01 Richard Henderson + + * c-decl.c (set_decl_nonlocal): New. + (store_parm_decls): Use it via walk_tree. + +2003-10-01 Jeff Law + + * tree-ssa-dom.c (cprop_into_stmt): New function extracted from + optimize_stmt. + (optimize_stmt): Use cprop_into_stmt. + +2003-09-30 Richard Henderson + + * function.h (struct function): Add function_end_locus. + * c-decl.c (finish_function): Set it. + * tree-optimize.c (tree_rest_of_compilation): Set input_location + to function_end_locus before expand_function_end. + + * tree-optimize.c (optimize_function_tree): Move calls to + remove_useless_stmts_and_vars and lower_eh_constructs ... + (tree_rest_of_compilation): ... here. + + * c-simplify.c (gimplify_expr_stmt): Don't warn for any statement + with void result type. + +2003-09-30 Jeff Law + + * tree-ssa-dom.c (simplify_cond_and_lookup_avail_expr): Fix thinko + in test for swapping ranges. + + * tree-ssa-dom.c (record_range): New function. + (extract_range_from_cond): Likewise. + (tree_ssa_dominator_optimize): Initialize the vrp_data varray. + (optimize_block): Initialize the vrp_variables varray. Wipe + appropriate entries from the VRP varrays when done processing a block. + (get_eq_expr_value): Accept new argument "bb". Call record_range + appropriately. Refactor code to avoid useless work. + (simplify_cond_and_lookup_avail_expr): Use value range records to + simplify conditions. + (simplify_rhs_and_lookup_avail_expr): When simplifying ABS_EXPR, + DIV_EXPR and MOD_EXPR, use simplify_cond_and_lookup_avail_expr + to determine the range of the given variable. + + * tree-ssa-dom.c (find_equivalent_equality_comparison): Do not + look through a typecast which narrows a value. + +2003-09-30 Paul Brook + + * Makefile.in: Add rules for check-gfortran. + +2003-09-29 Richard Henderson + + * gimplify.c (gimplify_cond_expr): Fix both arms dead return value. + +2003-09-29 Jeff Law + + * tree-ssa-dom.c (simplify_cond_and_lookup_avail_expr): New function. + (find_equivalent_equality_comparison): Likewise. + (optimize_block): Remove code to build a == c equivalence after + seeing a == b and b == c. Remove code to walk backwards + though typecasts to record equivalences and move relevant parts + into find_equivalent_equality_comparison. + (optimize_stmt): Call simplify_cond_and_lookup_avail_expr. + +2003-09-28 Richard Henderson + + * gimplify.c (gimplify_call_expr): Annotate all call_exprs. + * tree-inline.c (expand_call_inline): Set input_location based + on EXPR_LOCUS; save and restore input_location around that. + (walk_tree): Do not set input_location. + +2003-09-27 Graham Stott + + * expr.c (expand_expr)[CATCH_EXPR]: Fix bogus return value. + +2003-09-26 Andrew MacLeod + + * tree-ssa-dom.c (struct var_value_d): Remove. + (const_and_copies): Change to a varray_type. + (tree_ssa_dominator_optimize): Initialize const_and_copies as a varray. + (optimize_block): Simply set the value in const_and_copies. + (dump_dominator_optimization_stats): No hash stats for const_and_copies. + (record_cond_is_true, record_cond_is_false, + simplify_rhs_and_lookup_avail_expr, update_rhs_and_lookup_avail_expr): + Parameter const_and_copies is now a varray_type. + (var_value_hash, var_value_eq): Remove. + (get_value_for, set_value_for): Access varray elements. + (get_eq_expr_value): Parameter const_and_copies is now a varray_type. + + * tree-cfg.c (handle_switch_split): Update container of previous stmt. + +2003-09-25 Daniel Berlin + + * tree-ssa-pre.c (split_critical_edges): New function, temporarily + disabled until some edge splitting/insertion problems are fixed. + (opnum_of_ephi): Take an edge argument, constify. Use hash table lookup. + Update all callers. + (ephi_pindex_eq): New function. + (ephi_pindex_hash): New function. + (ephi_pindex_htab): New variable. + (add_ephi_pred): Update hash table. + (expr_phi_insertion): Don't free the bitmap returned by compute_idfs + anymore. + (idfs_cache): New variable. + (compute_idfs): Rewrite to use cache as much as possible, and not + recompute when we can avoid it. + +2003-09-25 Daniel Berlin + + * tree-alias-ander.c: Fixup comment spacing. + (andersen_op_assign): Handle >2 operands case. + +2003-09-24 Steven Bosscher + + * tree-dfa.c (compute_immediate_uses_for): Split up in two + separate functions, one for PHIs and one for normal statements. + (compute_immediate_uses_for_phi): New. + (compute_immediate_uses_for_stmt): New. + +2003-09-25 Jeff Law + + * tree-ssa-dom.c (optimize_block): When EQ_EXPR_VALUE has the + form DEST = SRC where both DEST and SRC are SSA_NAMEs also + record SRC = DEST into the const and copies table. + + * tree-ssa-dom.c (optimize_block): Change tests which checked + for SSA_VAR_P to only allow SSA_NAMEs. + (get_value_for, set_value_for): Likewise. + (lookup_avail_expr, get_eq_expr_value): Likewise. + +2003-09-25 Andrew MacLeod + + * tree-ssa-dce.c (pdom_info, needed_stmts): Remove. + (NECESSARY): Define. + (necessary_p): Check bit instead of hash table lookup. + (clear_necessary): New. Clear necessary bit. + (mark_necessary): Use bit instead of hash table. No control lookup. + (mark_tree_necessary): Remove. + (find_useful_stmts): Clear necessary bit before checking it. + (stmt_useful_p): Remove GOTO_EXPR case. Check arms of COND_EXPR for + GOTO. All other control flow stmts are necessary. + (process_worklist): Dont look for control parents. + (remove_dead_stmts): No dominattor info is necessary. + (remove_dead_stmt): Don't need BB any more. Remove COND_EXPR by changing + the condition to 'if (0)'. Abort on other control flow. + (tree_ssa_dce): No longer need the hash table. + (remove_conditional): Remove. + +2003-09-25 Andreas Schwab + + * tree-flow.h: Declare next_ssa_version. + * tree-ssa-ccp.c: Remove conflicting declaration. + * tree-ssa-live.c: Likewise. + * tree.c (make_ssa_name): Likewise. + +2003-09-24 Jason Merrill + + * tree.h (DECL_SOURCE_LOCATION): Resurrect. + (DECL_SOURCE_FILE, DECL_SOURCE_LINE): Likewise. + (EXPR_LOCUS): Renamed from TREE_LOCUS. Null for non-exprs. + (SET_EXPR_LOCUS): New macro. + (EXPR_FILENAME): Renamed from TREE_FILENAME. + (EXPR_LINENO): Renamed from TREE_LINENO. + (struct tree_common): Remove locus field. + (struct tree_decl): Re-add locus field. + (struct tree_expr): Add locus field. + * c-aux-info.c, c-decl.c, coverage.c, c-parse.in, dbxout.c, + diagnostic.c, dwarf2out.c, expr.c, function.c, gimplify.c, + integrate.c, print-tree.c, stmt.c, tree.c, tree-cfg.c, + tree-dump.c, tree-flow-inline.h, config/alpha/alpha.c, + config/mips/mips.c: Adjust. + +2003-09-24 Andrew MacLeod + + * tree-ssa-ccp.c (enum latticevalue): Add UNINITIALIZED. + (const_values, struct value_map_d): Remove hash table structures. + (value_vector): New array of values. + (get_value): Use value_vector instead of hash table. Mark inline. + (visit_phi_node): Ignore arguments if the PHI result is already VARYING. + (initialize): Initialize value vector instead of hash table. + (finalize): Free value vector instead of hash table. + (add_var_to_ssa_edges_worklist): Don't add to worklist if + DONT_SIMULATE_AGAIN flag is set. + (value_map_hash, value_map_eq): Delete. + +2003-09-24 Jeff Law + + * tree-ssa-dom.c (optimize_block): Create infrastructure for + tracking const_and_copies equivalences which disappear when + we leave the current block. Use it for equivalences created + by EQ_EXPR_VALUE. Follow use-def chains for EQ_EXPR_VALUE + equivalences and see if certain NOP_EXPRs can be ignored + to create a block-local equivalence for const_and_copies. + (optimize_stmt): Do not get confused by a cast of the return + value from alloca or the address of a non-weak decl. + + * fold-const.c (fold_read_from_constant_string): New function. + * tree.h (fold_read_from_constant_string): Prototype. + * expr.c (expand_expr, case INDIRECT_REF): Use it. + (expand_expr, case ARRAY_REF): Likewise. Put checking code + inside an ENABLE_CHECKING. + * tree-ssa-ccp.c (fold_stmt): Use fold_read_from_constant_string. + * tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): Likewise. + +2003-09-23 Jeff Law + + * tree-ssa-dom.c (optimize_block): Ignore "useless" type + conversions in SWITCH_COND when creating equivalenecs at + case labels. + +2003-09-22 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Addresses of non-weak symbols + as well as dynamically allocated stack space are always nonzero. + + * tree-cfg.c (handle_switch_split): Properly mark the fallthru + edge from SRC to DEST with EDGE_FALLTHRU. + +2003-09-22 Daniel Berlin + + * tree-flow.h (struct bb_ann_d): Add erefs array. + * tree-ssa-pre.c (handle_bb_creation): Remove ei parameter. + Update caller. + (struct expr_info): Remove erefs array. + (append_eref_to_block): New function. + (clear_all_eref_arrays): Ditto. + (expr_phi_insertion): Use append_eref_to_block. + (insert_occ_in_preorder_dt_order_1): Ditto. + (subst_phis): Only copy expression, not the containing EUSE/EPHI. + Update all callers to reflect this. + (compute_will_be_avail): Update for per-block eref array. + (handle_bb_creation): Ditto. + (pre_expression): Ditto. + (tree_perform_ssapre): Clear eref arrays when done with expression. + +2003-09-22 Diego Novillo + + * tree-cfg.c (dump_tree_bb): Remove superlfuous newlines. + +2003-09-21 Diego Novillo + + * tree-dfa.c (compute_alias_sets): Use TDI_alias instead of + TDI_ssa. + * tree-dump.c (dump_files): Add enties for TDI_alias, TDI_ssa1, + TDI_dom1, TDI_ssa2, TDI_dce1, TDI_ssa3, TDI_dom2, TDI_ssa4, + TDI_ssa5 and TDI_dce2. + Remove entries for TDI_ssa, TDI_dom and TDI_dce. + * tree.h (enum tree_dump_index): Similarly. + (TDF_ALIAS): Remove. + (TDF_VOPS): Change value. + * doc/invoke.texi (-fdump-tree-alias): Document. + * tree-flow.h (tree_warn_uninitialized): Remove unused variable. + (rewrite_into_ssa): Add enum tree_dump_index argument. Update all + callers. + (rewrite_out_of_ssa): Likewise. + (tree_perform_ssa_pre): Likewise. + (tree_ssa_dominator_optimize): Likewise. + (tree_ssa_dce): Likewise. + (tree_ssa_copyprop): Likewise. + (tree_ssa_ccp): Likewise. + Add sbitmap argument. + (tree_compute_must_alias): Likewise. + (mark_new_vars_to_rename): Declare. + * tree-must-alias.c (tree_compute_must_alias): Do not call + rewrite_into_ssa. + Remove local vars_to_rename. Use new argument instead. + * tree-optimize.c (optimize_function_tree): Re-write optimization + ordering to support passes that need the SSA form updated. + Call tree_ssa_dominator_optimize. + Re-arrange optimization ordering. + * tree-ssa-ccp.c (substitute_and_fold): Take new argument + vars_to_rename. + Call mark_new_vars_to_rename. + (visit_phi_node): Move variable 'val' into the right scope. + (initialize): Move call dump_begin ... + (tree_ssa_ccp): ... here. + * tree-ssa-dom.c (mark_new_vars_to_rename): Declare extern. + Make sure that variables in virtual operands aren't marked + unnecessarily. + * tree-ssa.c (rewrite_into_ssa): Do not call + tree_ssa_dominator_optimize. + +2003-09-21 Diego Novillo + + * tree-ssa-dce.c (dom_info): Remove unused variable. + * tree-ssa-dom.c (tree_ssa_dominator_optimize): If the CFG has been + altered, call cleanup_tree_cfg. + Call cleanup_tree_cfg before returning. + * tree-ssa-pre.c (tree_perform_ssapre): Call get_stmt_operands + before processing the statement. + * tree-ssa-dom.c (thread_edge): Remove attribute EDGE_FALLTHRU from + edge. + +2003-09-21 Jeff Law + + * tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): Break out of + optimize_stmt. Follow the def-use chains back for certain expressions + to see if we can simplify the RHS of the current expression based + on earlier expressions. + + * tree-ssa-dom.c (optimize_block): Rework code to propagate values + into PHI nodes to be more efficient. + +2003-09-20 Andrew MacLeod + + * tree-flow.h (struct dataflow_d): Remove reaching fields, add 2 element + vector of trees. + * tree-flow-inline.h (immediate_uses): Rename to get_immediate_uses, + return a dataflow object. + (reaching_defs): Remove until needed. + (num_immediate_uses): New. Return number of immediate uses. + (immediate_use): New. Return a specified immediate use. + * tree-dfa.c (add_immediate_use): Use new fields. + (dump_immediate_uses_for): Use new interface. + (create_phi_node): Chain to start of list. + * tree-ssa-ccp.c (add_var_to_ssa_edges_worklist): Use new interface. + * tree-ssa.c (compute_global_livein): Loop interchange. + +2003-09-18 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Allow optimizing the RHS of a + MODIFY_EXPR even if we can't record any equivalences created by + the MODIFY_EXPR. Move code to simplify ABS_EXPR, TRUNC_DIV_EXPR + and TRUNC_MOD_EXPR to an earlier position. + +2003-09-19 Andrew MacLeod + + * tree-ssa-ccp.c (cfg_edges): Rename to cfg_blocks. + (cfg_blocks_num, cfg_blocks_head, cfg_blocks_tail): New. Queue markers. + (bb_in_list): New. Vector indicating if a BB is in the cfg_blocks list. + (tree_ssa_ccp): Use new routines. + (add_control_edge): Add to cfg_blocks list. + (initialize): Initialize new variables. + (finalize): Free allocations. + (cfg_blocks_empty): New. Is cfg_blocks queue list. + (cfg_blocks_add): New. Add a basic block to cfg_blocks list. + (cfg_blocks_pop): New. Get a a basic_block form the list. + +2003-09-18 Richard Henderson + + * tree-cfg.c (struct rusv_data): Add may_throw, may_branch. + (remove_useless_stmts_and_vars_1): Set them. + (remove_useless_stmts_and_vars_goto): Likewise. + (remove_useless_stmts_and_vars_tf): Transform to compound_expr + if only fallthrough. + (remove_useless_stmts_and_vars_tc): Kill region if nothrow. + Detect catch regions that don't propagate exceptions. + (remove_useless_stmts_and_vars): Zero entire data struct. + +2003-09-18 Richard Henderson + + * tree-eh.c (lower_try_finally_dup_block): New. + (honor_protect_cleanup_actions, lower_try_finally_copy): Use it. + +2003-09-18 Richard Henderson + + * tree-cfg (remove_useless_stmts_and_vars_cond, + remove_useless_stmts_and_vars_tf, + remove_useless_stmts_and_vars_tc, + remove_useless_stmts_and_vars_bind, + remove_useless_stmts_and_vars_goto): Break out of ... + (remove_useless_stmts_and_vars_1): ... here. Rename to _1; + take and use struct rusv_data. + (remove_useless_stmts_and_vars): New. Loop until no change. + * tree-flow.h (remove_useless_stmts_and_vars): Update decl. + * tree-ssa.c (rewrite_out_of_ssa): Don't loop here. + +2003-09-18 Richard Henderson + + * tree-pretty-print.c (dump_generic_node): Don't double indent asms. + +2003-09-18 Richard Henderson + + * tree-eh.c: Include langhooks.h, remove errors.h. + (decide_copy_try_finally): Use estimate_num_insns to choose + between copy and switch implementations. + + * c-common.c (c_estimate_num_insns): Take an expr, not a decl. + * tree-inline.c (limits_allow_inlining): Pass it the body of the decl. + +2003-09-18 Jeff Law + + * tree-ssa-dom.c (lookup_avail_expr): New argument which indicates + if the expression should be entered into the hash table. All + callers updated. + (update_rhs_and_lookup_avail_expr): New function factored out + of optimize_stmt. + + * tree.h (commutative_tree_code, associative_tree_code): Declare + * tree.c (commutative_tree_code, associative_tree_code): New + functions. + (iterative_hash_expr): Use commutative_tree_code. + * fold-const.c (operand_equal_p): Use commutative_tree_code + rather than inlining the communitivy check. + (fold, nondestructive_fold_binary_to_constant): Similarly. + +2003-09-18 Diego Novillo + + * Makefile.in (tree-eh.o): Add dependency on errors.h + * tree-eh.c: Include errors.h + +2003-09-17 Richard Henderson + + * tree-cfg.c (remove_useless_stmts_and_vars): Revert last change. + * tree-flow.h, tree-ssa.c: Likewise. + +2003-09-17 Richard Henderson + + * tree-eh.c (decide_copy_try_finally): Remove forgotten debug code. + +2003-09-17 Daniel Berlin + + * tree-ssa-pre.c (pick_ssa_name): New function. + (code_motion): Use it. + +2003-09-17 Richard Henderson + + * tree-eh.c: New file. + * Makefile.in (OBJS-common): Add it. + (tree-eh.o): New. + * calls.c (emit_call_1): New argument for full call expr. + Check with lookup_stmt_eh_region to set REG_EH_REGION. + (expand_call): Likewise for tail-calls. + * except.c (struct eh_region): Add tree_label. + (gen_eh_region, gen_eh_region_cleanup, gen_eh_region_try, + gen_eh_region_catch, gen_eh_region_allowed, + gen_eh_region_must_not_throw, get_eh_region_number, + get_eh_region_may_contain_throw, get_eh_region_tree_label, + set_eh_region_tree_label, expand_resx_expr): New. + (expand_eh_region_start, expand_start_catch): Use them. + (expand_end_catch): Tidy. + (note_eh_region_may_contain_throw): Take region argument. + (note_current_region_may_contain_throw): New. + (get_exception_filter): Export. + (collect_eh_region_array): Export. + (remove_unreachable_regions): Check ERT_TRY based on reachability + of catches, not reachability of continue_label. Never remove + ERT_MUST_NOT_THROW regions. + (collect_rtl_labels_from_trees): New. + (convert_from_eh_region_ranges): Use it. + (connect_post_landing_pads): Handle dying cleanups. + (struct reachable_info): Add callback data. + (add_reachable_handler): Invoke the callback. + (foreach_reachable_handler): New. + (reachable_handlers): Use it. + (arh_to_landing_pad, arh_to_label): New. + (can_throw_internal_1): Split out from can_throw_internal. + (can_throw_external_1): Similarly. + * except.h: Update. + * expr.c (expand_expr): Handle RESX_EXPR, FILTER_EXPR. + * gimplify.c (gimplify_modify_expr): Use tree_could_trap_p. + * stmt.c (using_eh_for_cleanups_p): Export. + (expand_return): Allow any typed rhs. + * timevar.def (TV_TREE_EH): New. + * tree-cfg.c (eh_stack): Kill. + (build_tree_cfg): Don't set it. Kill code to handle EH. + (could_trap_p): Move to tree-eh.c as tree_could_trap_p. + (get_eh_region_type, make_try_expr_blocks, make_catch_expr_blocks, + make_eh_filter_expr_blocks, try_finallys): Kill. + (make_edges): Kill code to handle EH. + (make_ctrl_stmt_edges): Kill TRY_FINALLY_EXPR, CATCH_EXPR, + EH_FILTER_EXPR. Handle RESX_EXPR. + (make_call_expr_edges): Kill. + (make_exit_edges): Use make_eh_edges. + (label_to_block): New. + (make_goto_expr_edges): Use it. + (is_ctrl_stmt): Add RESX_EXPR. + (is_ctrl_altering_stmt): Restructure. Use tree_can_throw_internal. + (last_exec_block, compute_reachable_eh): Kill. + * tree-dfa.c (get_stmt_operands): Add RESX_EXPR. + (get_expr_operands): Add FILTER_EXPR. + * tree-dump.c (dump_files): Add tree-eh. + * tree-flow.h (struct stmt_ann_d): Kill reachable_exception_handlers. + (label_to_block, lower_eh_constructs, make_eh_edges, + tree_could_trap_p, tree_could_throw_p, tree_can_throw_internal, + tree_can_throw_external): Declare. + * tree-optimize.c (optimize_function_tree): Call lower_eh_constructs. + (tree_rest_of_compilation): Save tree for inlining. + * tree-pretty-print.c (dump_generic_node): Handle FILTER_EXPR, + RESX_EXPR. + * tree-simple.c (is_gimple_stmt): Add RESX_EXPR. + (is_gimple_val): Add FILTER_EXPR. + * tree-ssa-dce.c (stmt_useful_p): Restructure. Add lhs of + EXC_PTR_EXPR or FILTER_EXPR. + * tree.def (FILTER_EXPR, RESX_EXPR): New. + * tree.h (enum tree_dump_index): Add TDI_eh. + +2003-09-17 Richard Henderson + + * tree.c (tsi_link_before): Remove unnecessary parens. + (tsi_link_chain_before, tsi_delink): Likewise. + (tsi_link_after): Accept the case if the iterator points + to a NULL node; treat it as an empty list. + (tsi_link_chain_after): Likewise. Update iterator properly + for TSI_CHAIN_END. + +2003-09-17 Richard Henderson + + * tree-inline.c (debug_find_tree_1, debug_find_tree): New. + +2003-09-17 Richard Henderson + + * tree-cfg.c (struct rusv_data): New. + (remove_useless_stmts_and_vars_1): Rename from + remove_useless_stmts_and_vars. Use rusv_data. Handle goto-next + via remembering the last goto seen, and zapping it when appropriate. + (remove_useless_stmts_and_vars): New. Loop until done. + * tree-flow.h (remove_useless_stmts_and_vars): Update decl. + * tree-optimize.c (optimize_function_tree): Don't cache fnbody. + Dump data after remove_useless_stmts_and_vars. + * tree-ssa.c (rewrite_out_of_ssa): Kill loop around + remove_useless_stmts_and_vars. + * tree-dump.c (dump_files): Add .useless. + * tree.h (enum tree_dump_index): Add TDI_useless. + +2003-09-17 Diego Novillo + + * pretty-print.c (pp_write_text_to_stream): Export. + * pretty-print.h (pp_write_text_to_stream): Declare. + * tree-pretty-print.c (print_generic_stmt): Flush to file. + (dump_generic_node): Call pp_write_text_to_stream. + (maybe_init_pretty_print): Take file argument; associate the + stream with the buffer. + +2003-09-17 Jeff Law + + * tree-ssa-ccp.c (ccp_fold): If the return value has the wrong + type, try to convert it to the proper type rather than failing. + + * tree-ssa-dom.c (optimize_stmt): Note that the statement is + modified, even if we just change the virtual operands. If + the statement was modified by const/copy propagation, then + set may_have_exposed_new_symbols. + +2003-09-17 Diego Novillo + + * tree-dfa.c (find_vars_r): Do not consider 'void *' pointers as + dereferenced when scanning function call arguments. + * tree-flow-inline.h (may_propagate_copy): Block propagation of + pointers when they have different memory tags. + * tree-ssa-copyprop.c (propagate_copy): When copy propagating + pointers, abort if the two pointers don't have identical memory + tags. + +2003-09-16 Jeff Law + + * tree-ssa-ccp.c (visit_stmt): Do not set DONT_SIMULATE_AGAIN + just because a statement as virtual definitions. + (likely_value): A CALL_EXPR is assumed to return a VARYING + result, regardless of its operands. + +2003-09-15 Jason Merrill + + * tree-simple.c (is_gimple_val): Allow addresses of all decls. + (is_gimple_const): Allow addresses of all non-weak statics. + * tree-ssa-ccp.c (fold_stmt): Return bool. + * tree-flow.h: Adjust prototype. + * tree-ssa-dom.c (optimize_stmt): If folding changed stuff, we + need to recalculate the vops. + +2003-09-13 Diego Novillo + + Fix PR optimization/12268 + * tree-dfa.c (add_referenced_var): Call-clobbered pointers may + point to global memory. + +2003-09-13 Jason Merrill + + * c-common.c (c_apply_type_quals_to_decl): Unset TREE_READONLY for + types with constructors. + Remove superfluous references to TREE_TYPE (decl). + +2003-09-13 Diego Novillo + + * opts.c (decode_options): Enable must-alias optimization by default. + * tree-dfa.c (get_expr_operands): Always call add_stmt_operand when + dealing with ADDR_EXPR nodes. + (add_stmt_operand): If the variable has an alias set + of size zero, abort. + Call get_base_symbol() to retrieve the variable from an ADDR_EXPR + node. + (compute_alias_sets): Deep copy the aliases array when triggering + the alias grouping heuristic. + Don't group aliases if -ftree-must-alias is given. + * tree-must-alias.c (tree_compute_must_alias): Call + dump_referenced_vars when doing detailed dumps. + Rename promoted_vars to vars_to_rename. Update all users. + (find_addressable_vars): Always mark statements modified. + (promote_var): Also mark aliases of promoted variable to be + renamed. + Call find_variable_in and remove_element_from to update varrays for + call-clobbered variables and alias sets. + (find_variable_in): New local function. + (remove_element_from): New local function. + * varray.c (varray_copy): New function. + * varray.h (varray_copy): Declare. + +2003-09-13 Diego Novillo + + * tree-flow-inline.h (is_optimizable_addr_expr): Remove. Update + all users. + * tree-ssa-dom.c (optimize_stmt): Do not propagate SSA names from + redundant expressions across abnormal edges. + +2003-09-13 Zdenek Dvorak + + * tree-cfg.c (remove_unreachable_blocks): Clean up. + (debug_tree_bb_n): New. + (is_ctrl_structure): Remove LOOP_EXPR. + * tree-flow.h (debug_tree_bb_n): Declare. + +2003-09-12 Andrew Macleod + + * tree-ssa-live.c (calculate_live_on_entry): Use default_def to add + addition checks to live on entry calculations. + * tree-ssa.c (print_exprs_edge): New debug output function. + (coalesce_abnormal_edges): Add basic block information to output. + (coalesce_ssa_name): Use default_def instead of trying to compute live + on entry variables. + +2003-09-12 Diego Novillo + + * tree-optimize.c (tree_rest_of_compilation): Set TREE_ASM_WRITTEN + for functions that have errors. + +2003-09-12 Diego Novillo + + * tree-ssa-pre.c (graph_dump_file, graph_dump_flags): Remove + unused variables. + +2003-09-11 Daniel Berlin + + * tree-ssa-pre.c (reset_down_safe): Make test less conservative. + (cba_search_start_from): Start from abnormal edge arguments, too. + (cba_search_continue_from_to): Ditto here. + +2003-09-11 Daniel Berlin + + * tree-ssa-pre.c: s/#if ENABLE_CHECKING/#ifdef ENABLE_CHECKING/g. + Add more comments to DFS searching functions. + (cba_search_reach_from_to): Remove empty function. + (code_motion): Remove #if 0'd code. + (pre_expression): Ditto. + * tree.h (tree_dump_index): Remove TDI_predot. + * tree-dump.c (dump_files): Ditto. + +2003-09-11 Jason Merrill + + Make EDGE_FALLTHRU meaningful for tree-cfg. + * tree-cfg.c (make_edges): Set EDGE_FALLTHRU on fallthrough edge. + (make_exit_edges): Likewise. + (make_ctrl_stmt_edges): Don't set EDGE_FALLTHRU on edges into a + control structure. + (handle_switch_fallthru): Clear EDGE_FALLTHRU after inserting a goto. + (find_insert_location): Only insert after a CALL_EXPR or MODIFY_EXPR. + (bsi_insert_on_edge_immediate): Count outgoing abnormal edges. + Insert before all control stmts. + (bsi_link_after): Handle a block with nops after the last stmt. + + Rename some things to clarify difference between "control structures" + (i.e. COND_EXPR) and "control statements" (also GOTO_EXPR). + * basic-block.h (BB_CONTROL_STRUCTURE): Rename from BB_CONTROL_EXPR. + * tree-cfg.c (REMOVE_NON_CONTROL_STRUCTS): Rename from + REMOVE_NON_CONTROL_STMTS. + (REMOVE_CONTROL_STRUCTS): Rename from REMOVE_CONTROL_STMTS. + (make_ctrl_stmt_edges): Move GOTO_EXPR/RETURN_EXPR handling here... + (make_exit_edges): ...from here. + (is_ctrl_altering_stmt): Don't accept GOTO_EXPR/RETURN_EXPR. + (is_ctrl_structure): Renamed from old is_ctrl_stmt. + (is_ctrl_stmt): New fn. + (bsi_move_to_bb_end): Use it. + (stmt_starts_bb_p): Use is_ctrl_stmt and is_ctrl_altering_stmt. + * tree-flow.h: Add prototype. + * tree-ssa-ccp.c, tree-ssa-dom.c: Update for name changes. + +2003-09-10 Daniel Berlin + + * tree-ssa-pre.c (ephi_has_bottom): Remove dead function. + (ephi_has_unsafe_arg): New function. + (compute_down_safety): Use it. + (reset_down_safe): Continue search on abnormal edges, too. + +2003-09-10 Jason Merrill + + * gimplify.c (gimplify_asm_expr): Add post_p parm. + (get_initialized_tmp_var): Add post_p parm. + (internal_get_tmp_var): Likewise. + (gimplify_expr, get_formal_tmp_var): Pass it. + * c-simplify.c (gimplify_decl_stmt): Pass it. + * tree-simple.h: Adjust prototype. + + * tree-cfg.c (make_call_expr_edges): Break out from... + (make_exit_edges): ...here. Check TREE_NOTHROW. + (is_ctrl_altering_stmt): Check TREE_NOTHROW. + +2003-09-10 Paul Brook + + * gimplify.c (gimplify_compound_lval): Treat REALPART_EXPR and + IMAGPART_EXPR the same as COMPONENT_REF. + * tree-simple.c (is_gimple_addr_expr_arg): Ditto. + (is_gimple_lvalue): Remove REALPART_EXPR and IMAGPART_EXPR. + +2003-09-10 Diego Novillo + + * c-pretty-print.c (decl_name_str): New local function. + (pp_c_direct_declarator): Call it. + (pp_c_primary_expression): Call it. + (pp_c_id_expression): Call it. + (pp_c_statement): Call it. + +2003-09-10 Diego Novillo + + * tree-pretty-print.c (dump_generic_node): Change string used to + display _DECL nodes with no DECL_NAME. + +2003-09-10 Diego Novillo + + * tree-dfa.c (add_referenced_var): Handle cases when argument + walk_state is NULL. + (add_referenced_tmp_var): New function. + * tree-flow.h (add_referenced_tmp_var): Declare it. + * tree-ssa-pre.c (pre_expression): Call it. + * tree-ssa-live.c (create_ssa_var_map): Add checking for variables + being in real and virtual operands. + +2003-09-01 Zdenek Dvorak + Jeff Law + + * tree-flow.h (remove_unreachable_blocks): Declare. + * tree-cfg.c (remove_unreachable_blocks): Export. Return true + if blocks were removed. + * tree-ssa-dom.c (optimize_block, optimize_stmt): Record whether + the cfg has changed. Schedule jump threading. If a block + has more than one pred, then do not record equivalences created + by a controlling COND_EXPR. + (edges_to_redirect, redirection_targets): New variables. + (thread_edge): Split out of optimize_block. + (tree_ssa_dominator_optimize); Remove unreachable blocks and + recompute dominator tree when the cfg changes. + +2003-09-07 Steven Bosscher + + * c-tree.h: Don't declare c_genericize, it's already + declared in c-common.h. + +2003-09-07 Steven Bosscher + + Fix PR optimization/12198 + * tree-cfg.c (value_matches_some_label): Handle integer + case ranges. + +2003-09-06 Zdenek Dvorak + + * tree-iterator.h (tsi_iterator_update): Added TSI_CHAIN_START, + TSI_CHAIN_END, TSI_CONTINUE_LINKING and comments. + (tsi_link_chain_before, tsi_link_chain_after): Declare. + * tree.c (tsi_link_chain_before, tsi_link_chain_after): New. + (tsi_link_before, tsi_link_after): Handle new TSI_... + positions. + +2003-09-06 Diego Novillo + + * varray.c (element): Add entry for 'tree *'. + * varray.h (enum varray_data_enum): Add VARRAY_DATA_TREE_PTR. + (union varray_data_tag): Add entry for 'tree *'. + (VARRAY_TREE_PTR_INIT): Define. + (VARRAY_TREE_PTR): Define. + (VARRAY_PUSH_TREE_PTR): Define. + (VARRAY_TOP_TREE_PTR): Define. + * tree-cfg.c: Replace uses of VARRAY_GENERIC_PTR with + VARRAY_TREE_PTR when accessing operand arrays. + * tree-ssa-ccp.c: Likewise. + * tree-ssa-copyprop.c: Likewise. + * tree-ssa-dce.c: Likewise. + * tree-ssa-dom.c: Likewise. + * tree-ssa-live.c: Likewise. + * tree-ssa-pre.c: Likewise. + * tree-dfa.c: Likewise. + * tree-ssa.c: Likewise. + * tree-flow.h (struct operands_d): Remove 'skip' GC markers from + all fields. + (struct dataflow_d): Likewise. + +2003-09-05 Diego Novillo + + * tree-dfa.c (find_referenced_vars): Re-enable .GLOBAL_VAR + optimization. + +2003-09-05 Daniel Berlin + + * tree.h (tree_eref_common): Make stmt a tree, not a tree *. + * tree-ssa-pre.c: Transform all tree *'s to tree. + +2003-09-05 Paul Brook + + * tree.h (enum tree_index): Delete TI_SIGNED_SIZE_TYPE here. + (signed_size_type_node): No longer a member of global_trees. + * c-common.h (enum c_tree_index): New member CTI_SIGNED_SIZE_TYPE. + (signed_size_type_node): Moved, now a member of c_global_trees. + +2003-09-05 Diego Novillo + + * tree-dfa.c (find_referenced_vars): Temporarily disable + .GLOBAL_VAR optimization. + +2003-09-04 Daniel Berlin + + * tree-alias-common.c: Add overview. + * tree-alias-ander.c: Add overview and more specific comments on what + each function does. + +2003-09-04 Diego Novillo + + * tree-optimize.c (tree_rest_of_compilation): Return if errorcount + or sorrycount are non-zero. + +2003-09-04 Diego Novillo + + * tree-cfg.c (cleanup_tree_cfg): Traverse basic blocks + with FOR_EACH_BB. + (remove_useless_stmts_and_vars): Likewise. + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Likewise. + * tree-ssa.c (rewrite_into_ssa): Likewise. + * tree-dfa.c (remove_all_phi_nodes_for): Make sure that the new + list of PHI nodes is NULL-terminated. + Add sanity checks to make sure all the PHI nodes for variables to + rename are gone. + +2003-09-04 Diego Novillo + + * tree-dfa.c (struct walk_state): Add field 'num_calls'. + (add_call_clobber_ops): New local function. + (add_call_read_ops): New local function. + (get_expr_operands): Call them. + (add_stmt_operand): Call-clobbered variables are always added to + virtual operands. + (find_referenced_vars): If the number of call-clobbered variables + and number of call sites is larger than a certain threshold, group + all call-clobbered variables under .GLOBAL_VAR. + (find_vars_r): Count the number of call sites. + Don't add .GLOBAL_VAR to the list of referenced variables. + (add_referenced_var): If the addressable variable is an array, + register alias set of the type of the elements, not the type of the + array. + * tree-ssa-dom.c (mark_new_vars_to_rename): Rename from + find_new_vars_to_rename. Update all users. + Before scanning the statement for new operands, mark the existing + virtual operands to be renamed again. + (optimize_stmt): Also check for newly exposed variables when doing + redundancy elimination. + * tree-ssa.c (rewrite_into_ssa): Don't abort when rename_count is + greater than 2. Simply stop trying at 3. + (prepare_operand_for_rename): New function. + (mark_def_sites): Call it. + (rewrite_stmt): Don't check if the operand is an SSA_NAME before + calling rewrite_operand. + (rewrite_operand): Don't abort if the operand was already an + SSA_NAME. Ignore it. + +2003-09-03 Richard Henderson + + * tree-optimize.c (set_save_expr_context, clear_decl_rtl, + tree_rest_of_compilation): Merge from mainline new file. + * Makefile.in (tree-optimize.o): Update. + * c-semantics.c (expand_stmt_toplev): New. + * c-common.h (expand_stmt_toplev): Declare. + * c-lang.c, objc/objc-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): Use it. + +2003-09-03 Richard Henderson + + * gimplify.c (gimplify_switch_expr): Leave the outermost cast + as part of the switch condition. + +2003-09-02 Diego Novillo + + * Makefile.in (tree.o): Add dependency on $(BASIC_BLOCK_H) and + $(TREE_FLOW_H) + * tree.c: Include basic-block.h and tree-flow.h + (tsi_link_after): Adjust basic block tree pointers when inserting a + new COMPOUND_EXPR. + +2003-09-02 Richard Henderson + + * c-decl.c (finish_function): Fix misapplied patch. Don't + free_after_parsing or free_after_compilation. For real this time. + +2003-09-01 Daniel Berlin + + * tree-ssa-pre.c (finalize_1): Remove unnecessary call to + insert_euse_in_preorder_dt_order. + (code_motion): Ditto. + (pre_expression): Ditto. + +2003-09-01 Zdenek Dvorak + Jeff Law + + * basic-block.h (BB_LOOP_CONTROL_EXPR): Remove. + * c-simplify.c (gimplify_c_loop): Create loops in a better shape. + * cfgloop.h (create_loop_notes): Declare. + * cfgloopmanip.c (create_loop_notes): New. + * explow.c (probe_stack_range): Don't produce loop notes when we + recreate them. + * expr.c (emit_block_move_via_loop): Ditto. + * gimplify.c (build_and_jump): Export. + (gimplify_loop_expr): Don't produce LOOP_EXPRs. + * toplev.c (rest_of_compilation): Recreate loop notes if needed. + * tree-cfg.c (make_loop_expr_edges, make_loop_expr_blocks): Removed. + (find_contained_blocks, make_ctrl_stmt_edges, + remove_useless_stmts_and_vars, stmt_ends_bb_p, bsi_insert_before, + find_insert_location, bsi_insert_on_edge_immediate, + merge_tree_blocks): Remove handling of LOOP_EXPRs. + (remove_stmt): Remove handling of BB_LOOP_CONTROL_EXPR. + (find_taken_edge): Remove comment on LOOP_EXPRs. + (dump_tree_bb): Don't dump loop-related information. + (is_loop_stmt, is_latch_block_for): Removed. + (find_insert_location): Handle TRY_CATCH and TRY_FINALLY. + * tree-flow.h (is_loop_stmt, loop_body, set_loop_body, + is_latch_block_for): Removed. + * tree-dfa.c (get_stmt_operands): Don't handle LOOP_EXPRs. + * tree-simple.c (is_gimple_stmt): Remove handling of LOOP_EXPRs. + * tree-simple.h: Remove LOOP_EXPRs from gimple grammar comment. + (build_and_jump): Declare. + * tree-ssa.c (remove_annotations_r): Don't handle LOOP_EXPRs. + +2003-08-29 Daniel Berlin + + * opts.c (decode_options): Turn on SSAPRE by default. + +2003-08-29 Jason Merrill + + * builtins.c (simplify_builtin): Make sure that the replacement + has the same type as the original expression. + (simplify_builtin_strpbrk): Fix type of COMPOUND_EXPR. + (simplify_builtin_strncpy, simplify_builtin_memcmp): Likewise. + (simplify_builtin_strncmp, simplify_builtin_strncat): Likewise. + (simplify_builtin_strspn, simplify_builtin_strcspn): Likewise. + (simplify_builtin_fputs, simplify_builtin_sprintf): Likewise. + +2003-08-28 Zdenek Dvorak + + * builtins.c (expand_builtin): Expand BUILT_IN_STACK_SAVE and + BUILT_IN_STACK_RESTORE. + * builtins.def (BUILT_IN_STACK_SAVE, BUILT_IN_STACK_RESTORE): New. + * gimplify.c (build_stack_save_restore): New functions. + (struct gimplify_ctx): New field save_stack. + (gimplify_bind_expr, gimplify_call_expr): Arrange save of stack on + BIND_EXPR entry and restore on exits. + * stmt.c (expand_stack_alloc): Saving of stack removed. + (expand_stack_save, expand_stack_restore): New. + * tree.h (expand_stack_save, expand_stack_restore): Declare. + +2003-08-28 Diego Novillo + + * tree-dfa.c (add_vdef): Check for duplicate voperands first. + Handle SSA_NAME in voperands. + (add_vuse): Likewise. + +2003-08-27 Diego Novillo + + * tree-flow.h (var_ann_d): Convert is_in_va_arg_expr into a + bitfield. + +2003-08-27 Daniel Berlin + + * tree-ssa-pre.c: Update comments to reflect reality. + (insert_one_operand): Remove #if'0d code. + +2003-08-27 Zdenek Dvorak + + * gcov.c (typedef struct arc_info): New field cs_count. + (accumulate_line_counts): Find cycles correctly. + +2003-08-27 Daniel Berlin + + * tree-ssa-pre.c (compute_du_info): Move #if ENABLE_CHECKING up one + line. + +2003-08-27 Daniel Berlin + + * tree.h (struct ephi_arg_d): New structure. + (struct eref_common): Remove non-used members, move some members + elsewhere. + (struct ephi_node): Ditto. + + * tree-optimize.c (optimize_function_tree): Move PRE before DCE. + + * tree.c (tree_size): use sizeof (struct ephi_arg_d) for ephi's. + + * tree-pretty-print.c (dump_generic_node): Re-teach to pretty + print euses/ephis/etc given new structures, members, and + relationships. + + * tree-ssa-pre.c (fixup_domchildren): Removed. + (a_dom_b): Ditto. + (calculate_preorder): Ditto. + (defs_match_p): Ditto. + (defs_y_dom_x): Ditto. + (compute_can_be_avail): Ditto. + (reset_can_be_avail): Ditto. + (reset_later): Ditto. + (compute_later): Ditto. + (repair_*): Ditto. + (set_replacement): Ditto. + (remove_ephi): Ditto. + (set_expruse_def): Ditto. + (occ_compare): Ditto. + (defs_hash_expr): Ditto. + (compute_dt_preorder): Ditto + (search_dt_preorder): Ditto. + (ephi_operand_for_pred): Ditto. + (injured_ephi_operand): Ditto. + (compute_stops): New function. + (occ_identical_to): Ditto. + (require_phi): Ditto. + (do_ephi_df_search_1): Ditto. + (do_ephi_df_search): Ditto. + (any_operand_injured): Ditto. + (compute_du_info): Ditto. + (add_ephi_use): Ditto. + (insert_one_operand): Ditto. + (add_ephi_pred): Ditto. + (created_phi_preds): New bitmap. + (dfn) Removed static variable. + (idom_of_ephi): Ditto. + (avdefs): Move into expr_info). + (struct ephi_use_entry): New structure for EPHI uses. + (struct ephi_df_search): New structure for depth first searchs. + (cant_be_avail_search): Implementation of structure for + cant_be_avail search. + (stops_search): Ditto for stops. + (replacing_search): Ditto for replacing_search. + (do_proper_save): Arguments changed, callers updated. + (create_ephi_node): Use sizeof (struct ephi_arg_d). + (ephi_has_bottom): Rewrite for updated ephi-pred handling. + (ephi_will_be_avail): Rewrite in terms of CANT_BE_AVAIL and STOPS. + (expr_phi_insertion): Remove dead code. + Update for new flags. + (insert_occ_in_preorder_dt_order_1): Only insert one ephi-pred per + block. + Fix exit occurence handling. + (rename_1): Remove occs stuff. + Update for new ephi-pred handling. + (reset_down_safe): Update for new ephi-pred handling. + (compute_down_safe): Ditto. + (can_insert): Ditto. + (insert_one_operand): Split out from finalize_1. + (finalize_1): Update for new ephi-pred handling. + Only insert non-pointless, will-be-avail phis, rather than *all* + ephis. + (get_temp): New function. Hand us the right temporary for a given + EPHI/EUSE. + (code_motion): Use EREF_TEMP again, now that we can do it + properly. + +2003-08-26 Zdenek Dvorak + + * builtins.c (expand_builtin): Handle STACK_ALLOC. + * builtins.def (BUILT_IN_STACK_ALLOC): New. + * c-simplify.c (gimplify_decl_stmt, c_gimplify_stmt, + gimplify_compound_literal_expr): Arrange explicit stack allocation. + * expr.c (expand_expr): Handle deferred variables. + * stmt.c (expand_stack_alloc): New. + * tree-simple.c (is_gimple_val): Prevent ADDR_EXPRs of vla's from + being reduced. + * tree.h (expand_stack_alloc): Declare. + +2003-08-26 Zdenek Dvorak + + * tree-ssa.c (build_dominator_tree): Use FOR_EACH_BB. + +2003-08-26 Jason Merrill + + * tree-simple.c (is_gimple_val): Also disallow memory vars. + +2003-08-25 Zdenek Dvorak + + * integrate.c (copy_decl_for_inlining): Reset DECL_TOO_LATE. + +2003-08-25 Zdenek Dvorak + + * tree-ssa-dom.c (optimize_block): Handle empty source block. + + * tree-ssa-dom.c (optimize_block): Handle case when dominance + tree children have also other sucessors. Add dump to jump + threading. + +2003-08-25 Jason Merrill + + * c-simplify.c (mark_labels_r): New fn. + (gimplify_decl_stmt): Use it to mark labels in static initializers. + * tree-simple.c (is_gimple_initializer): Remove. + (is_gimple_reg_type): New fn. + (is_gimple_reg): Use it. Handle SSA_NAMEs properly. + * tree-simple.h: Adjust. + * gimplify.c (gimplify_expr) : Do nothing here. + + * gimplify.c (create_tmp_var): Set DECL_IGNORED_P. + + * tree-inline.c (initialize_inlined_parameters): Improve error + recovery. + + * gimplify.c (gimplify_boolean_expr): Just replace with a COND_EXPR. + +2003-08-25 Diego Novillo + + * tree-dfa.c (get_expr_operands): Don't create shared operands when + folding *&VAR expressions. + +2003-08-24 Diego Novillo + + * tree-flow.h (struct var_ann_d): Add field default_def. + (widen_bitfield): Declare. + (set_default_def): Declare. + (default_def): Declare. + * tree-flow-inline.h (set_default_def): New inline function. + (default_def): New inline function. + * tree-dfa.c (dump_variable): Display default_def, if set. + * tree-simple.c (is_gimple_reg): Check for DECL_P before checking + for DECL_EXTERNAL. + * tree-ssa-dom.c (add_expr_propagated_p): Remove. Update all + users. + (find_new_vars_to_rename): New local function. + (tree_ssa_dominator_optimize): Add new argument vars_to_rename. + Change return type to void. Update all users. + (optimize_block): Add new argument vars_to_rename. Update all + users. + If the call to optimize_stmt returns true, add the statement to the + list of statements to re-scan for operands. + After optimizing the block and its dominator children, call + find_new_vars_to_rename for every statement that may have had new + symbols exposed. + (optimize_stmt): Change return type to bool. Return true if the + statement may have had new symbols exposed by optimization. + Add a sanity check for the value returned by lookup_avail_expr. + Create equivalences for more memory stores, not just the ones done + via INDIRECT_REF expressions. + Call widen_bitfield when optimizing stores to bitfields. + (lookup_avail_expr): Reformat comment. + * tree-ssa.c (rewrite_into_ssa): Remove local variable + addr_expr_propagated_p. + Clear out vars_to_rename before running dominator optimizations. + (check_for_new_variables): Remove. + (rewrite_stmt): Always register new definitions and virtual + definitions. + (register_new_def): Update comment. + (get_reaching_def): Update the default_def field for the variable + if it didn't have a reaching definition. + * tree-ssa-ccp.c (widen_bitfield): Declare it extern. + +2003-08-23 Zdenek Dvorak + + * tree-cfg.c (bsi_next_in_bb): Work correctly when the block ends + with start of BIND_EXPR. + +2003-08-23 Daniel Berlin + + * tree-alias-ander.c (andersen_op_assign): Fix to join the operands, + the assign to the lhs. + +2003-08-23 Daniel Berlin + + * tree-alias-common.c (get_alias_var): Remove REFERENCE_EXPR. + (find_func_aliases): Fix some not quite right predicates, add ARRAY_REF + handling. + +2003-08-22 Jeff Law + + * tree-dfa.c (compute_alias_sets): A memory tag used for stores can + not conflict with objects marked TREE_READONLY. + + * tree-ssa-ccp.c (fold_stmt): Optimize reads from constant strings. + +2003-08-22 Jason Merrill + + * tree-simple.c: Total overhaul to only check forms and remove + unnecessary predicates. + (is_gimple_const): Accept function addresses here. + Don't accept LABEL_DECL or RESULT_DECL. + (is_gimple_val): Accept EXC_PTR_EXPR here. + (is_gimple_lvalue): Rename from is_gimple_modify_expr_lhs. + Accept BIT_FIELD_REF, REALPART_EXPR and IMAGPART_EXPR here. + (is_gimple_addr_expr_arg): Replace with former is_gimple_varname. + (is_gimple_constructor_elt): Just check for CONSTRUCTOR. + (is_gimple_initializer): Just hand off to is_gimple_rhs. + (is_gimple_rhs): Recognize most expressions here. + (is_gimple_variable): New fn. + (is_gimple_id): Use it. Now static. + (is_gimple_reg): New fn. + (is_gimple_cast): Replace with former is_gimple_cast_op. + (is_gimple_constructor, is_gimple_expr): Remove. + (is_gimple_modify_expr, is_gimple_relop): Remove. + (is_gimple_binary_expr, is_gimple_unary_expr): Remove. + (is_gimple_call_expr, is_gimple_arglist): Remove. + (is_gimple_compound_lval, is_gimple_arrayref): Remove. + (is_gimple_compref, is_gimple_exprseq): Remove. + (is_gimplifiable_builtin): Remove. + * tree-simple.h: Adjust. + * gimplify.c (gimplify_conversion): Break out from gimplify_expr. + (gimplify_expr): Use is_gimple_reg predicate to force a temp. + : Use gimplify_compound_lval. + : Likewise. + : Use is_gimple_reg predicate. + : Use new gimplify_minimax_expr. + : Reject. + (gimplify_tree_list, gimplify_component_ref): Remove. + (gimplify_compound_lval): Include REALPART_EXPR and IMAGPART_EXPR. + (gimplify_component_ref): Remove. + (gimplify_call_expr): Handle non-gimplifiable builtins and walking + the argument list here. + (gimplify_tree_list): Remove. + (gimplify_addr_expr): Use fb_either. + * tree-simple.h: Adjust. + * tree-alias-common.c (find_func_aliases): Update use of predicates. + +2003-08-21 Andrew Pinski + + * tree-ssa.c (tree_ssa_useless_type_conversion): Check also the + precision of the type to make sure they are really useless type + conversions. + +2003-08-21 Diego Novillo + + * tree-dump.c (dequeue_and_dump): Handle 'r' and 's' code classes. + +2003-08-21 Zdenek Dvorak + + * c-pretty-print.c (print_c_tree): Create new pp object. + +2003-08-21 Zdenek Dvorak + + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Don't free hash tables + before statistics are made from them. + * tree-ssa.c (rewrite_into_ssa): Ditto. + +2003-08-21 Jason Merrill + + * tree-inline.c (copy_body_r): Don't convert when stripping &*. + Fix thinko in stripping *&. + +2003-08-21 Diego Novillo + Zdenek Dvorak + + * tree-cfg.c (stmt_starts_bb_p): Nonlocal and computed GOTO targets + always start a new block. + +2003-08-20 Jason Merrill + + * tree-pretty-print.c (dump_generic_node): Just print "" + for the RESULT_DECL. + + * c-simplify.c (make_type_writable, mostly_copy_tree_r): Remove. + (deep_copy_list, deep_copy_node): Remove. + + * expr.c (expand_expr): Don't check for 'r' or 's' if we're + checking IS_EXPR_CODE_CLASS. + * tree-dfa.c (may_access_global_mem_p): Likewise. + * tree-browser.c (browse_tree): Likewise. + * tree-ssa-pre.c (defs_hash_expr): Likewise. + * gimplify.c (gimplify_expr): Likewise. + (internal_get_tmp_var): Only copy TREE_LOCUS from an expr. + (mostly_copy_tree_r): Ignore decls here. + +2003-08-20 Diego Novillo + + * c-pretty-print.c: Discard. Replace with same file from + mainline. Update all users. + (print_c_tree): New function. + * c-pretty-print.h (print_c_tree): Declare. + * tree-pretty-print.c: Update to use new pp_* primitives. + * c-simplify.c: Include c-pretty-print.h. + * Makefile.in (c-simplify.o): Add dependency on $(C_PRETTY_PRINT_H). + +2003-08-20 Roger Sayle + + * c-common.h (enum c_tree_index): Delete CTI_SIGNED_SIZE_TYPE. + (signed_size_type_node): No longer a member of c_global_trees. + * tree.h (enum tree_index): New member TI_SIGNED_SIZE_TYPE here. + (signed_size_type_node): Moved, now a member of global_trees. + +2003-08-20 Zdenek Dvorak + + * tree-ssa-dom.c (optimize_block): Thread jump into empty + block correctly. + + * tree-cfg.c (linearize_cond_expr): Don't merge blocks if the + later has other predecessors. + +2003-08-19 Jason Merrill + + * c-typeck.c (build_array_ref): Also build ARRAY_REFs from + INDIRECT_REFs of ARRAY_TYPE. + + * tree-ssa.c (tree_ssa_useless_type_conversion): Also strip + conversions between pointer and reference types. + + * tree-dfa.c (get_stmt_operands): Just mark non-GIMPLE statements + as unmodified. + (find_referenced_vars): So we don't need to mark them here. + + * tree-inline.c (inline_data): Add retvar field. + (declare_return_variable): Set it. + (remap_decls): Use it. + (expand_call_inline): Tweak. + +2003-08-19 Zdenek Dvorak + + * cfg.c (dump_edge_info): Add name for EDGE_LOOP_EXIT flag. + +2003-08-19 Zdenek Dvorak + + * tree-flow.h (struct var_ann_d): New field scope. + (struct stmt_ann_d): New field scope. + (propagate_copy): Declaration changed. + (fixup_var_scope): Declare. + * tree-cfg.c (make_blocks, make_cond_expr_blocks, + make_catch_expr_blocks, make_eh_filter_expr_blocks, + make_try_expr_blocks, make_loop_expr_blocks, make_switch_expr_blocks, + make_bind_expr_blocks, build_tree_cfg): Assign variables and statements + to scopes. + (assign_vars_to_scope): New. + * tree-ssa-copyprop.c (move_var_to_scope): New. + (copyprop_stmt): Pass scope of statement to propagate_copy. + (propagate_copy): Assign variable to the right bind_expr. + (fixup_var_scope): New. + * tree-ssa-dom.c (optimize_stmt): Pass scope of statement to + propagate_copy. + +2003-08-19 Daniel Berlin + + * tree-cfg (bsi_move_after): New function. + (bsi_move_before): New function. + (bsi_move_to_bb_end): New function. + * tree-flow.h: Prototype new functions. + +2003-08-18 Daniel Berlin + + * tree-alias-ander.c: Remove doxygen markers. + (eq_to_var): remove. + (simple_cmp): Add. + (throwaway_global): Add. + (andersen_same_points_to_set): Handle ignoring global var aliasing the + right way here. + (andersen_may_alias): Use list_member to avoid stupid hack. + * tree-alias-common.c: Remove hacks for disabling global var aliasing. + +2003-08-17 Zdenek Dvorak + + * tree.c (resize_phi_node): Initialize new entries. + +2003-08-17 Jeff Law + + * tree-pretty-print.c (last_bb): Actually record the basic block, + not just its index. + (maybe_init_pretty_print): Corresponding changes. + (dump_generic_node, dump_vops): Test the actual block pointers, not + their indices. + + * tree-ssa-dom.c (optimize_block): Use equivalences from the + dominator tree walk to thread through conditional jumps at leafs in + the dominator tree. + + * tree-cfg.c (blocks_unreachable_p, remove_blocks): Use a bitmap + rather than a varray. + (REMOVE_ALL_STMTS, REMOVE_NO_STMTS): New defines for remove_bb. + (REMOVE_NON_CONTROL_STMTS, REMOVE_CONTROL_STMTS): Likewise. + (remove_unreachable_block): Use find_contained_blocks rather + than find_subblocks. If we have a COND_EXPR or SWITCH_EXPR which + is unreachable, but which has reachable children clear out the + condition and request all non-control statements be removed + from the block. + (remove_bb): Allow better control over what (if any) statements + are removed. All callers updated. + (find_subblocks): Remove. + (find_contained_blocks): Handle statements with no associated + basic block. + +2003-08-15 Andrew Pinski + + * objc/objc-lang.c (LANG_HOOKS_GIMPLIFY_EXPR): Define + as the c gimplifier. + +2003-08-15 Jeff Law + + * tree-cfg.c (cleanup_tree_cfg): Wipe out the dominator tree + if the number of basic blocks changes as a result of cfg cleanups. + * tree-flow.h (build_dominator_tree): Prototype. + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Build the dominator + tree if it is not already available. + * tree-ssa.c (build_dominator_tree): New function. + (rewrite_into_ssa): Use it. + + * gimplify.c (gimplify_expr, cases NOP_EXPR, CONVERT_EXPR): If a + COMPONENT_REF is wrapped with a NOP_EXPR, then force the type of + the COMPONENT_REF to match the accessed field. Strip away + unnecessary type conversions and handle the case where all type + conversions were removed. + (case ARRAY_REF, COMPONENT_REF): Indicate to gimplify_array_ref + and gimplify_component_ref if we want an lvalue or not. + (gimplify_array_ref, gimplify_component_ref): Pass new argument + WANT_LVALUE through to gimplify_compound_lval. + (gimplify_compound_lval): If we do not want an lvalue and the + toplevel COMPONENT_REF's type does not match its field's type, + then wrap the COMPONENT_REF in a NOP_EXPR and force the + COMPONENT_REF's type to match its field's type. + (gimplify_modify_expr): If the RHS is a CALL_EXPR and the LHS + is not a gimple temporary, then force the RHS through a gimple + temporary, even if the call can not throw. + (create_tmp_var): Make sure not to lose the type's attributes + for the new variable. + * tree-ssa.c (tree_ssa_useless_type_conversion): New function. + * tree-flow.h (tree_ssa_useless_type_conversion): Prototype. + * tree-ssa-dom.c (optimize_stmt): Use tree_ssa_useless_type_conversion. + + * tree-cfg.c (remove_useless_stmts_and_vars): Catch more + useless statements created during the out-of-ssa pass. + +2003-08-14 Jeff Law + + * tree-ssa-dom.c (optimize_block): Record equivalences created by + SWITCH_EXPRs. + + * tree-ssa-dom.c (optimize_stmt): Allow optimizing the RHS of + a RETURN_EXPR which contains an optimizable MODIFY_EXPR. + (lookup_avail_expr): Corresponding changes. + (avail_expr_hash, avail_expr_eq): Likewise. + + * tree-ssa-dom.c (optimize_stmt): Fix typo which prevented + stores with more than one VDEF from creating useful equivalences. + + * tree-dfa.c (get_expr_operands): Do not special case *0; + + * fold-const.c (fold, case INDIRECT_REF): Revert last change. + +2003-08-14 Diego Novillo + + * tree-cfg.c (bsi_insert_on_edge_immediate): Only update the + container for the head tree of the next block if the new statement + needs to be linked to it. + +2003-08-13 Jeff Law + + * fold-const.c (fold, case INDIRECT_REF): Optimize reads from + constant strings. + + * tree-cfg.c (remove_useless_stmts_and_vars): For a COND_EXPR + where the condition is a variable and the ELSE clause merely + sets that variable to zero, remove the ELSE clause. + + * tree-ssa-dom.c (optimize_stmt): Do not check the type of the + value returned by lookup_avail_expr. + +2003-08-13 Daniel Berlin + + * tree-cfg.c (remove_stmt): Add new argument saying whether to remove + annotations and invalidate defs. Update all callers + (remove_bsi_from_block): Moved from bsi_remove, argument added. + (bsi_remove): Made into wrapper for remove_bsi_from_block. + +2003-08-13 Zdenek Dvorak + + * tree-ssa-dom.c (optimize_stmt): Call get_stmt_operands. + +2003-08-12 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Record equivalences created + by memory stores. + +2003-08-12 Diego Novillo + + * tree-cfg.c (find_insert_location): Handle other control + statements that may be at the end of the block. + +2003-08-12 Zdenek Dvorak + + * Makefile.in (tree-pretty-print.o): Add tree-iterator.h dependency. + * tree-pretty-print.c: Include tree-iterator.h. + (dump_generic_node): Avoid recursing into COMPOUND_EXPRs. + +2003-08-12 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Optimize ABS_EXPR when we know + the sign of the source operand. + + * tree-ssa-dom.c (optimize_stmt): Rewrite TRUNC_DIV_EXPR and + TRUNC_MOD_EXPR even if the LHS is not an SSA variable. Do not + enter the new expression in the hash tables if !may_optimize_p. + Also try GE_EXPR to see if this transformation is safe. + + * tree-ssa-dom.c (optimize_stmt): Fix typo in last change which + prevented recording equivalences created by IOR_EXPR. + + * tree-ssa-dom.c (optimize_stmt): Record that the destination of + a MODIFY_EXPR nonzero if the RHS contains an IOR with a nonzero + constant. Turn DIV/MOD by a power of 2 into SHIFT/AND if we know + dividend is positive. + +2003-08-11 Jeff Law + + * fold-const.c (fold, cases NE_EXPR and EQ_EXPR): Fold equality + comparisons of non-weak symbol addresses against zero. + + * tree-ssa-ccp.c (fold_stmt): Strip unnecessary NOP_EXPRs from + the folded result. + + * gimplify.c (gimplify_expr, case INDIRECT_REF): Copy the base + object into a temporary if it's in static memory or is addressable. + +2003-08-11 Steven Bosscher + + * tree-alias-common.h (struct tree_alias_ops): Add a semicolon, fix + bootstrap. + +2003-08-10 Daniel Berlin + + * tree-dfa.c (compute_may_aliases): Move points-to initialization from + here. + (find_referenced_vars): To here. + (get_memory_tag_for): Use new same_points_to_set function. + + * tree-alias-common.h (struct tree_alias_ops): Remove doxygen markers. + Add same_points_to_set function to struct. + (same_points_to_set): New function. + + * tree-alias-common.c (we_created_global_var): A bit of magic to ignore + global var aliasing when we didn't create global var. This will go + away soon + (same_points_to_set): New function. + + * tree-alias-andersen.c (struct andersen_alias_ops): Add + andersen_same_points_to_set. + (andersen_same_points_to_set): New function. Return true if the two + variables have the same points-to set. + + * opts.c (common_handle_option): Add "none" as a points-to option. + +2003-08-10 Paul Brook + + * doc/install.texi: Mention --enable-languages=f95. + +2003-08-09 Daniel Berlin + + * tree-pretty-print.c (dump_vops): check bb->tree_annotations, not + bb->aux. + +2003-08-08 Daniel Berlin + + * tree-cfg.c (bsi_insert_on_edge_immediate): If there's only + one statement in the block, and it's an empty statement, replace it. + +2003-08-08 Jason Merrill + + * c-decl.c (c_expand_body_1): Restore support for + !keep_function_tree_in_gimple_form. + (finish_function, c_expand_deferred_function): Do TDI_inlined dump. + + * gimplify.c (voidify_wrapper_expr): Set TREE_SIDE_EFFECTS on the + wrapper if we insert a MODIFY_EXPR. + +2003-08-07 Diego Novillo + + * Makefile.in (GTFILES): Add tree-ssa.c, tree-dfa.c and + tree-ssa-ccp.c. + (gt-tree-ssa.h, gt-tree-dfa.h, gt-tree-ssa-ccp.h): Depend on + s-gtype. + * tree-dfa.c (struct clobber_data_d): Remove. Update all users. + (struct alias_map_d): Mark for garbage collection. + (struct walk_state): Add fields 'is_not_gimple' and + 'is_va_arg_expr'. + (clobber_vars_r): Remove. Update all users. + (get_stmt_operands): Abort if attempting to get operands from a + non-GIMPLE statement. + (get_expr_operands): Likewise. + Do not force a virtual operand when scanning VA_ARG_EXPR. + (add_stmt_operand): If the variable has hidden uses, mark the + statement as having volatile operands and return. + If the variable occurs inside a VA_ARG_EXPR, add it as a virtual + operand. + (add_immediate_use): Call VARRAY_TREE_INIT instead of + VARRAY_GENERIC_PTR_INIT. + (dump_variable): Check is_in_va_arg_expr flag. + (compute_may_aliases): Move code to find variables ... + (find_referenced_vars): ... here. + (find_vars_r): Abort if we find a non-GIMPLE expression + unexpectedly. + Mark variables found inside a VA_ARG_EXPR. + Do not scan arguments for non-GIMPLE CALL_EXPRs. + Remove local variable saved_is_store. + Reformat some code for readability. + (add_referenced_var): If the variable is already marked as having + hidden uses, ignore it. + If the variable is found inside a non-GIMPLE expression, mark it. + If the variable is found inside a VA_ARG_EXPR, mark it. + + * tree-flow.h (struct var_ann_d): Add field is_in_va_arg_expr. + (find_referenced_vars): Declare. + * tree-optimize.c (optimize_function_tree): Call + find_referenced_vars before computing may aliases. + + * tree-ssa-dce.c (need_to_preserve_store): Do not check if the + variable has hidden uses. + * tree-ssa-live.c (type_var_init): Likewise. + + * tree-ssa-ccp.c (ssa_edges): Mark for garbage collection. + (tree_ssa_ccp): Use VARRAY_.*_EDGE calls to manipulate the varray + of CFG edges. + (add_control_edge): Likewise. + (initialize): Likewise. + * tree-ssa.c (struct def_blocks_d): Mark for garbage collection. + (struct var_value_d): Likewise. + (def_blocks_free): Remove. Update all users. + (rewrite_into_ssa): Do not specify free function when creating + def_blocks and currdefs. + Call sbitmap_free instead of free. + (mark_def_sites): Call sbitmap_free instead of free. + (set_def_block): Use GC allocation. + (set_livein_block): Likewise. + (insert_phi_nodes): Adjust name of varray def_maps when creating it. + (insert_phis_for_deferred_variables): Remove call to BITMAP_XFREE. + (insert_phi_nodes_for): Use GC allocation for phi_insertion_points. + (init_tree_ssa): Remove typecast in call to memset. + (set_value_for): Use GC allocation. + (get_def_blocks_for): Remove typecast in call to htab_find. + * varray.c (element): Add entry for struct edge_def *. + * varray.h (enum varray_data_enum): Add VARRAY_DATA_EDGE. + (union varray_data_tag): Add field of type struct edge_def *. + (VARRAY_EDGE_INIT): Define. + (VARRAY_EDGE): Define. + (VARRAY_PUSH_EDGE): Define. + (VARRAY_TOP_EDGE): Define. + +2003-08-06 Diego Novillo + + * tree-cfg.c (handle_switch_fallthru): Do not abort when the last + statement of the case block needs to be the last statement of the + block. + (find_insert_location): Fix typo. + +2003-08-06 Steven Bosscher + + * tree-dfa.c (remove_phi_arg): When the PHI no longer has + arguments, don't remove it here, but do so... + (remove_phi_arg_num): ...from here. + +2003-08-05 Jason Merrill + + * gimplify.c (gimplify_cond_expr): Gimplify shortcut expansion in + a conditional context. + + * tree-cfg.c (make_catch_expr_blocks): Don't change next_block_link. + (make_eh_filter_expr_blocks): Likewise. + + * tree-dfa.c (add_referenced_var): Static locals are call + clobbered. + +2003-08-05 Steven Bosscher + + * tree-dfa.c (add_phi_arg): Allow PHI capacity to grow. + * tree-flow.h (add_phi_arg): Adjust prototype. + * tree-ssa-pre.c (code_motion): Adjust call. + * tree-ssa.c (rewrite_block): Likewise. + * tree.c (resize_phi_node): New function. + * tree.h (resize_phi_node): Add prototype. + +2003-08-05 Jeff Law + + * tree-ssa-dom.c (optimize_block): Be more aggressive about + creating equivalences from PHI nodes. + + * tree-ssa-dom.c (optimize_stmt): Strip away certain NOP_EXPRs + before determining if we have an equivalence to enter into + the const_and_copies table. + + * tree-ssa-dce.c (remove_dead_stmts): Iterate backwards through the + basic blocks removing dead statements. Within each block iterate + backwards through the statements removing those which are dead. + + * tree-ssa-optimize.c (optimize_function_tree): Call + remove_useless_stmts_and_vars before building the flow graph. + * tree-cfg.c (remove_useless_stmts_and_vars): Rename argument from + first_iteration to remove_unused_vars. + + * tree-cfg.c (remove_unreachable_blocks): Remove blocks in reverse + order. + (remove_bb): Remove unwanted call to bsi_next. + (bsi_remove): Refine code which removes useless COMPOUND_EXPRs to allow + removal if one of the arms is not associated with a basic block. + (remove_stmt): Improve check for testing when a basic block head/end + pointer needs to be updated when removing a COMPOUND_EXPR. + + * tree-cfg.c (phi_alternatives_equal): New function. + (linearize_cond_expr): Allow linearization if the PHI nodes at the + target have equivalent arguments for the incoming edges from the THEN + and ELSE clauses. + + * tree-ssa-dce.c (mark_tree_necessary): Empty statements may be + necessary. + (process_worklist): Handle any incoming abnormal edges the first + time a statement in each block becomes executable. + + * tree-ssa-ccp.c (substitute_and_fold): Substitute known + constants into PHI nodes. + +2003-08-04 Sebastian Pop + + * basic-block.h: Declare bb_ann_d. + (basic_block_def): Add a field tree_annotations. + * cfg.c (entry_exit_blocks): Initialize tree_annotations to NULL. + * cfghooks.c: Remove the definition of cfg_level. + (rtl_register_cfg_hooks): Remove the initiallization of cfg_level. + * cfghooks.h (cfg_hooks): Add cfgh_loop_optimizer_init, and + cfgh_loop_optimizer_finalize. + (loop_optimizer_init, loop_optimizer_finalize): New macros. + (cfg_level): Remove. + * cfgloop.h (loop_optimizer_init, loop_optimizer_finalize): Rename + to rtl_loop_optimizer_init and rtl_loop_optimizer_finalize. + * cfgrtl.c (rtl_loop_optimizer_init, rtl_loop_optimizer_finalize): + Declare, and register them in rtl_cfg_hooks and cfg_layout_rtl_cfg_hook. + * loop-init.c (loop_optimizer_init, loop_optimizer_finalize): Rename + to rtl_loop_optimizer_init and rtl_loop_optimizer_finalize. Remove + the checks to cfg_level. + * tree-cfg.c (block_tree_ann_obstack, first_block_tree_ann_obj): New. + (create_blocks_annotations, create_block_annotation, + free_blocks_annotations, clear_blocks_annotations): New functions. + (tree_loop_optimizer_init, tree_loop_optimizer_finalize): New + functions. Register them in tree_cfg_hooks. + (build_tree_cfg, dump_tree_bb, delete_tree_cfg, tree_split_edge): Use + create_blocks_annotations instead of alloc_aux_for_blocks, + create_block_annotation instead of alloc_aux_for_block, + .tree_annotations instead of .aux, + free_blocks_annotations instead of free_aux_for_blocks. + (tree_register_cfg_hooks): Remove initialization of cfg_level. + * tree-flow-inline.h (bb_ann): Use .tree_annotations. + * tree-flow.h: Update comment. + +2003-08-04 Zdenek Dvorak + + * Makefile.in (c-pretty-print.o): Add TREE_H and C_TREE_H dependencies. + +2003-08-01 Paul Brook + + * Makefile.in (GMPINC): Set and use. + (GMPLIBS): Set it. + * configure.in: Add test and switches for the GMP library. + (all_need_gmp): Set from config-lang.in. + * sourcebuild.texi: Document need_gmp. + * configure: regen + +2003-08-01 Steven Bosscher + + * tree-inline.c (expand_calls_inline): Fix comments. + +2003-07-31 Diego Novillo + + * Makefile.in (tree-ssa-ccp.o): Depend on $(EXPR_H). + * builtins.c (c_strlen): Remove static declaration. + (simplify_builtin_fputs): Remove static declaration. + (simplify_builtin_sprintf): New local function. + (expand_builtin_sprintf): Remove by surrounding with #if 0. + (expand_builtin): Add BUILT_IN_SPRINTF to the list of built-ins + handed over to simplify_builtin. + (validate_arglist): Do not allow arguments with TREE_SIDE_EFFECTS. + (simplify_builtin_fputs): Add new argument KNOWN_LEN. If it's set, + use it instead of trying to compute the length of the string. + Update all callers. + * expr.h (simplify_builtin_fputs): Declare. + * tree-flow.h (fold_stmt): Change argument type to tree *. Update + all users. + * tree-ssa-ccp.c: Include expr.h. + (replace_uses_in): If the statement makes a call to some selected + built-ins, mark it for folding. + (get_strlen): New local function. + (ccp_fold_builtin): New local function. + (fold_stmt): Call it. + (set_rhs): Fix if-else-if chaining. Handle cases where the whole + statement needs to be replaced. + * tree.h (c_strlen): Declare. + +2003-07-31 Diego Novillo + + Fix PR optimization/11373 + * tree-ssa-dce.c (stmt_useful_p): Get statement operands before + checking for volatile operands. + * tree-dfa.c (get_expr_operands): If a constant is dereferenced as a + pointer, mark the statement as having volatile operands. + (may_access_global_mem_p): If a non-NULL constant is used as a + pointer, consider it as pointing to global memory. + * tree-ssa-dom.c (optimize_stmt): Set addr_expr_propagated_p when + propagating pointers that are integer constants. + +2003-07-31 Andrew MacLeod + + * tree-dfa.c (add_stmt_operand): Don't treat complex types as scalars. + * tree-ssa-live.c (var_union): Change comment. + (coalesce_tpa_members): Don't proceed if var_union fails. + * tree-ssa.c (insert_copy_on_edge): Change comment. + (coalesce_abnormal_edges): Handle var_union failing. + (coalesce_vars): Skip constant PHI arguments. + +2003-07-30 Jeff Law + + * tree-cfg.c (bsi_remove): Don't remove a COMPOUND_EXPR with empty + arms if the arms are in different basic blocks. + + * tree-ssa-dom.c (record_cond_is_false): New function. + (record_cond_is_true): Similarly. + (get_eq_expr_value): Use record_cond_expr_is_{true,false}. + (optimize_stmt): Fix minor formatting issue. If we encounter an + INDIRECT_REF, record that the dereferenced pointer can not be + null. + +2003-07-30 Daniel Berlin + + * tree-dump.c (dump_option_value_in): "all" is now everything but + TDF_RAW and TDF_SLIM. + +2003-07-30 Diego Novillo + + * tree-simple.c (is_gimple_const): Accept CONST + CONST expressions + as GIMPLE constants. + +2003-07-30 Daniel Berlin + + * tree-ssa-pre.c: #include real.h + (defs_match_p): Change arguments to something normal now that we use + the new renaming algorithm. Update all callers. + Use defs_hash_expr. + (defs_y_dom_x): Ditto. + (defs_hash_expr): New. Based on iterative_hash_expr. + (generate_exr_as_of_bb): If there aren't any uses, return. + (subst_phis): Call modify_stmt on the actually modified statement. :) + (get_default_def): Only walk SSA_NAME arguments in PHI's. + +2003-07-30 Jason Merrill + + Don't modify code that is already GIMPLE. + * gimplify.c (gimplify_expr): Don't return early if the predicate + matches. + Use a variable temp if the caller wants an lvalue. + Don't call gimplify_constructor if we're on the rhs of a MODIFY_EXPR. + (add_tree, add_stmt_to_compound): Do add an empty stmt if we + previously had nothing at all. + (gimplify_return_expr): Don't mess with iterators if it was already + gimple. + (gimplify_cond_expr): Remove a COND_EXPR with two empty arms. + (gimplify_call_expr): Try to simplify a builtin again after + gimplifying the args. + (internal_get_tmp_var): Gimplify the new MODIFY_EXPR. + (gimplify_expr, gimple_push_cleanup): Use boolean_false_node. + (gimplify_init_constructor): New fn, broken out from... + (gimplify_modify_expr): ...here. Be smarter about zero-initialization. + * tree-simple.c (is_gimple_rhs): Accept any CONSTRUCTOR. + * tree-simple.h: Adjust add_tree prototype. + +2003-07-29 Daniel Berlin + + * tree-alias-common.c (create_alias_vars): If we created global_var, + delete it when we are done. + (ptr_may_alias_var): Handle case that global_var is now NULL_TREE. + +2003-07-29 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Propagate copies into VUSEs and + the RHS of VDEFs. + +2003-07-29 Andrew MacLeod + + * tree-ssa.c (insert_copy_on_edge): Only set used bit on DECL nodes. + +2003-07-29 Andrew MacLeod + + * common.opt (ftree-combine-temps): Add new option. + * flags.h (flag_tree_combine_temps): New flag. + * opts.c (decode_options): Initialize flag_tree_combine_temps. + (common_handle_option): Handle new flag. + * toplev.c (flag_tree_combine_temps): Declare. + (lang_independent_options f): Add tree-combine-temp. + * tree-ssa-live.c (var_union): When combining 2 root variables, choose + the user variable over a temporary as the new variable. + (compact_var_map): Use renamed root_var routines. + (calculate_live_on_exit): Reformatting. + (tpa_init): Initialize a tpa object. + (tpa_remove_partition): Remove a partition from a tpa list. + (tpa_delete): Delete a tpa object. + (tpa_compact): Hide single elemenet lists. + (root_var_init): Split common part into tpa_init and rename. + (remove_root_var_partition, delete_root_va, dump_root_var): Delete. + (type_var_init): New. Initialize a type_var object. + (create_coalesce_list): New. Create a coalesce_list object. + (delete_coalesce_list): New. Free a coalesce list's memory. + (find_partition_pair): New. Find a coalesce pair in a coalesce list. + (add_coalesce): New. Add a coalesce between 2 partitions. + (sort_coalesce_list): New. Sort coalesce pairs by importance. + (pop_best_coalesce): New. Get best remaining pair to coalesce. + (add_conflicts_if_valid): Move from tree-ssa.c. + (build_tree_conflict_graph): Move from coalesce_ssa_name in tree-ssa.c. + Genericize to use tpa_p instead of root_var object. Don't add + interferences between copies. Update coalesce list. + (coalesce_tpa_members): Move from coalesce_ssa_name in tree-ssa.c. Use + tpa_p instead of root_var. Use coalesce list if provided. + (dump_coalesce_list): New. Show debug info for a coalesce list. + (tpa_dump): Rename from dump_root_var and genericize to use tpa_p. + * tree-ssa-live.h (root_var_p): Rename structure type to tpa_p + (tpa_num_trees, tpa_tree, tpa_first_partition, tpa_next_partition, + tpa_find_tree): New. Generic versions of existing root_var routines. + (tpa_decompact): New. Include single version lists. + (root_var_p): Declare as type tpa_p. + (root_var_num, root_var, root_var_first_partition, + root_var_next_partition, root_var_dump, root_var_delete, + root_var_remove_partition, root_var_find , root_var_compac, + root_var_decompac): Rename and call generic versions. + (type_var_p): New. Use tpa_p structure for a type based association. + (type_var_num, type_var, type_var_first_partition, + type_var_next_partition, type_var_dump, type_var_delete, + type_var_remove_partition, type_var_find, type_var_compact, + type_var_decompact): New. Call generic versions of the routine. + (struct partition_pair_d): New. Represent a desired coalesce. + (struct coalesce_list_d): New. Organize lists of desired coalesces. + (NO_BEST_COALESCE): Define value. + * tree-ssa.c (set_if_valid): Remove. + (insert_copy_on_edge): Set variable as used when inserting a copy. + (add_conflicts_if_valid): Remove. Move to tree-ssa-live.c. + (print_exprs): New. Routine for commonly used output format. + (coalesce_abnormal_edges): New. Split from coalece_ssa_name. Force + partition coalesces across abnormal edges. + (coalesce_ssa_name): Split out build_tree_conflict_graph, + coalesce_abnormal_edges, and coalesce_tpa_members. Return live + range info if required. Use renamed root_var routines. + (assign_vars): Use renamed root_var routines. + (replace_variable): Mark as inline. + (coalesce_vars): Coalesce variable memory storage. + (rewrite_out_of_ssa): Don't compact varmap anymore. Free live range + info if required. Call coalesce_vars if combining temps. + +2003-07-29 Andrew MacLeod + + * tree-cfg.c (handle_switch_fallthru): Use bsi_link_after if stmt is + in a basic block. + +2003-07-28 Diego Novillo + + * opts.c (decode_options): Disable must-alias optimization. + +2003-07-28 Andrew MacLeod + + * tree-ssa.c (struct _elim_graph): Add varray for constant copies. + (new_elim_graph): Initialize constant copy array.. + (eliminate_build): Push constant copies onto stack instead of emitting. + (eliminate_phi): Emit any pending constant copies. + +2003-07-28 Jeff Law + + * tree-ssa-dom.c (optimize_block): If a PHI has a single argument + that is a constant, then that creates a useful equivalence. + Propagate constant values into PHI nodes. + + * tree-flow-inline.h (may_propagate_copy): Allow RHS to be a + constant. + + * tree-dfa.c (compute_immediate_uses_for): Do not assume that + PHI arguments are SSA_NAMEs. + * tree-ssa-dce.c (process_worklist): Likewise. + * tree-ssa-copyprop.c (copyprop_phi): Likewise. Use may_propagate_copy. + * tree-ssa-ccp.c (visit_phi_node): Do not assume that PHI arguments + are SSA_NAMEs. Create a suitable value if a PHI argument is a + constant. + + * tree-cfg.c (move_outgoing_edges): Correctly handle case where + an edge already exists from BB1 to BB2's successor. + +2003-07-27 Daniel Berlin + + * tree.h (EREF_TEMP): Rename to EPHI_TEMP. + (tree_eref_common): Move temp to tree_ephi_node. + * tree-ssa-pre.c: Remove #if 0'd code. + Use EPHI_TEMP rather than EREF_TEMP, remove EREF_TEMP on EUSE nodes. + (finalize_1): Handle empty blocks properly. + +2003-07-27 Andreas Jaeger + + * tree.c: Convert remaining K&R prototypes to ISO C90. + * tree-dump.c: Likewise. + * tree-inline.c: Likewise. + * stmt.c (expand_asm_expr): Likewise. + + * diagnostic.h: Remove PARAMS. + +2003-07-26 Paul Brook + + * Makefile.in: Rename check-g95 to check-gfortran. + * gcc.c (default_compilers): Add entries for .f90 and .f95. + * doc/frontends.texi: Document new F95 front end. + * doc/install.texi: Ditto. + * doc/invoke.texi: Ditto. + * doc/sourcebuild.texi: Ditto. + * fortran: New front end. + +2003-07-25 Jeff law + + * tree-ssa-dom.c (optimize_block): Use may_propagate_copy. + +2003-07-25 Diego Novillo + + * opts.c (decode_options): Re-enable must-alias optimizations. + +2003-07-25 Daniel Berlin + + * configure.in: Update BANSHEEREBUILD for PWD change. + * configure: regen + +2003-07-25 Andreas Jaeger + + * c-call-graph.c: Convert to ISO C90. + * c-common.c: Likewise. + * c-mudflap.c: Likewise. + * c-pretty-print.c: Likewise. + * cfganal.c (find_edge): Likewise. + * dependence.c: Likewise. + * diagnostic.c (debug_output_buffer): Likewise. + * except.c (expand_eh_handler): Likewise. + * fold-const.c: Likewise. + * langhooks.c: Likewise. + * tree-cfg.c (last_exec_block): Likewise. + * tree-ssa-pre.c: Likewise. + * builtins.c: Likewise. + + * tree.h: Remove remaining PARAMS. + * c-common.h: Likewise. + * c-pretty-print.h: Likewise + * c-tree.h: Likewise. + * except.h: Likewise. + * langhooks-def.h: Likewise. + * langhooks.h: Likewise. + +2003-07-24 Diego Novillo + + * tree-dfa.c (cleanup_operand_arrays): New local function. Remove + superfluous VUSE operands. + (get_stmt_operands): Call it. + +2003-07-24 Jason Merrill + + * gimplify.c (gimple_boolify): New fn. + (gimplify_expr) : Boolify arg. + (gimplify_cond_expr): Boolify condition. + (gimplify_boolean_expr): Boolify args. + (gimple_push_cleanup): Make flag boolean. + + * tree-simple.c (is_gimple_relop): TRUTH_{AND,OR,XOR}_EXPR + are not comparisons. + (is_gimple_binary_expr): They are binary ops. + + * tree-mudflap.c (mf_build_check_statement_for): Use TRUTH_OR_EXPR + rather than BIT_IOR_EXPR. + +2003-07-23 Jason Merrill + Diego Novillo + + * c-common.h (DECL_C_HARD_REGISTER): Replace ... + * tree.h (DECL_HARD_REGISTER): ... with this. Update all users. + +2003-07-23 Diego Novillo + + * tree-flow-inline.h (may_propagate_copy): New function. + * tree-flow.h (may_propagate_copy): Declare. + * tree-ssa-copyprop.c (copyprop_stmt): Call it. + (get_original): Likewise. + * tree-ssa-dom.c (optimize_stmt): Likewise. + +2003-07-23 Frank Ch. Eigler + + * gcc.c (MFWRAP_SPEC): Also wrap pthread_join and pthread_exit. + +2003-07-23 Steven Bosscher + + * tree-flow-inline.h (remove_dom_child): New function. + (clear_dom_children): New function. + * tree-cfg.c (bsi_insert_on_edge_immediate): Do not clear + the annotation for the new bb, it is already memset to zero + in alloc_aux_for_block(). + (move_outgoing_edges): Use dom_children() instead of looking + at the dom_children field in the basic block annotation. + * tree-ssa.c (rewrite_into_ssa): Use clear_dom_children(). + + * tree-cfg.c (dump_tree_cfg): Dump to `file', not `dump_file'. + +2003-07-23 Diego Novillo + + * tree.h (DECL_ESTIMATED_INSNS): Move from c-common.h. + +2003-07-23 Steven Bosscher + + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Make + found_unreachable a bool. Create/delete hash tables for + copies and available exprs outside the main loop. Use + htab_clean to wipe them after each iteration. + +2003-07-22 Diego Novillo + + * opts.c (decode_options): Add temporary test for environment + variable TREE_SSA_DO_PRE. + Do not disable dominator optimizations when PRE is enabled. + +2003-07-22 Daniel Berlin + + * tree-ssa-pre.c (finalize_1): Change to not use bsi_last. + +2003-07-22 Daniel Berlin + + * tree-cfg.c (remove_stmt): Revert 07-15 change. Turns out the bug is in + the reverse iterator. + +2003-07-22 Diego Novillo + + * tree-ssa-ccp.c (visit_phi_node): Assume default value of CONSTANT + if the PHI value was already constant. + +2003-07-22 Andrew MacLeod + + * c-pretty-print.c (print_call_name): Handle COND_EXPR correctly. + * tree-pretty-print.c (print_call_name): Handle COND_EXPR correctly and + handle SSA_NAME. + * tree-dfa.c (add_phi_arg, remove_phi_arg_num): Remove references to + SSA_NAME_HAS_REAL_REFS. + * tree-ssa-ccp.c (visit_phi_node): Remove SSA_NAME_HAS_REAL_REFS. + * tree-ssa-copyprop.c (copyprop_phi): Remove SSA_NAME_HAS_REAL_REFS. + * tree-ssa-live.c (register_ssa_partition): Register the PHI and it's + arguments if this variable is defined by a PHI. + (create_ssa_var_map): Only register real uses and defs, and virtual + operands of ASM_EXPR's. Remove SSA_NAME_HAS_REAL_REFS. Don't set + used flag on variables here. + (calculate_live_on_entry): Ignore constants in PHI arguments. + (calculate_live_on_exit): Ignore constants in PHI arguments. + (dump_live_info): New. Dump live range information. + * tree-ssa-live.h (dump_live_info): New prototype and flags. + * tree-ssa-pre.c (create_expr_ref, finalize_1, repair_use_injury, + code_motion): Remove SSA_NAME_HAS_REAL_REFS. + * tree-ssa.c (rewrite_operand, register_new_def): Remove real_ref + parameter and SSA_NAME_HAS_REAL_REFS. + (rewrite_block): Remove real_ref parameter from register_new_def call. + (eliminate_build): Remove SSA_NAME_HAS_REAL_REFS. Insert copy if PHI + argument is a constant. Handle irregular PHI argument ordering. + (elim_create): Remove dead code to count PHI nodes. + (assign_vars): Set used flag on variables when assigned. + (replace_variable): Eliminate dead code. + (coalesce_ssa_name): Remove SSA_NAME_HAS_REAL_REFS. Print error for + constant argument across an abnormal edge. + (eliminate_extraneous_phis): New. Remove PHI nodes which are not in + the partition. + (rewrite_out_of_ssa): Call eliminate_extraneous_phis. + (rewrite_stmt): Remove real_ref parameter from rewrite_operand and + register_new_def. + * tree.h (SSA_NAME_HAS_REAL_REFS): Remove. + (struct tree_ssa_name): Remove 'has_real_refs' field. + +2003-07-22 Daniel Berlin + + * tree-ssa-pre.c (factor_through_injuries): Take new argument specifying + whether use was injured or not (needed for SR). Update all callers. + (maybe_find_rhs_use_for_var): Take new argument specifying which + operand to start search with. Update all callers. + (phi_opnd_from_res): #if 0 out. + (rename_2): Ditto. + (rename_1): Ditto. + (defs_match_p): Take new arguments specifying which defs were injured. + Update all callers. + (defs_y_dom_x): Ditto. + (generate_expr_as_of_bb): Fix small memory overwrite. + (process_delayed_rename): Propagate injured flag around. + (new_rename_1): Ditto. + (finalize_1): Get correct variable names for newly created statement if + necessary due to PHI. + (repair_use_injury): Note the repair in the stats. Insert repair + in right place. + (repair_euse_injury): Fix handling of PHI_NODE. + (code_motion): Fix algorithm so it can handle using reaching_def all the + time (needed for SR). + Use reaching_def rather than EREF_TEMP. + +2003-07-21 Diego Novillo + + * tree-dfa.c (get_stmt_operands): Remove FIXME note + regarding virtual operands for ASM_EXPRs. + +2003-07-21 Diego Novillo + + * tree-dfa.c (add_def): Renamed from set_def. Update all users. + (get_stmt_operands): Don't force ASM_EXPR operands to be virtual. + (add_stmt_operand): Allow non-assignments to create new defs. + * tree-dump.c (dump_function): Move header dump... + (dump_function_to_file): ... here. + * tree-flow-inline.h (def_ops): Renamed from def_op. Return a + varray with all the definitions made by the statement. + Update all users. + * tree-flow.h (struct operands_d): Rename field 'def_op' to + 'def_ops'. Convert it into a varray. + * tree-must-alias.c (tree_compute_must_alias): Call + dump_function_to_file instead of dump_function. + * tree-ssa-ccp.c (tree_ssa_ccp): Likewise. + (visit_stmt): Only visit statements that make new definitions using + MODIFY_EXPR. + Definitions coming from other statements are considered VARYING. + * tree-ssa-copyprop.c (tree_ssa_copyprop): Call + dump_function_to_file instead of dump_function. + * tree-ssa-dce.c (tree_ssa_dce): Likewise. + * tree-ssa-dom.c (tree_ssa_dominator_optimize): Likewise. + (optimize_stmt): Don't abort if a statement makes more than one + definition. + Check for MODIFY_EXPR statements directly, instead of relying on + the the presence of a single definition. + * tree-ssa-pre.c (tree_perform_ssapre): Call dump_function_to_file + instead of dump_function. + * tree-ssa.c (rewrite_into_ssa): Likewise. + Dump the function before dominator optimizations if TDF_DETAILS is + set. + (rewrite_stmt): Don't abort if the statement makes more than one + definition. + +2003-07-21 Jeff Law + + * tree-ssa-dom.c (tree_ssa_dominator_optimize): If we made any + blocks unreachable, repeat the dominator optimizations. + (optimize_block): Enter PHIs with a single source argument into + the const_and_copies table. When propagating into a PHI node, + break the loop over the PHI arguments when a propagation is performed. + If the PHI agument is not an SSA_VAR, then no propagation is possible. + (optimize_stmt): If an operand is not an SSA_VAR, then no propagation + is possible/needed. + +2003-07-21 Diego Novillo + + * Makefile.in (tree-ssa-dom.o): Add dependency on $(TREE_DUMP_H). + * fold-const.c (fold): Remove unusued local variable 'invert'. + * tree-dump.c (dump_files): Add entry for -fdump-tree-dom. + * tree-flow.h (tree_ssa_dominator_optimize): Change declaration to + accept a function decl. + * tree-ssa-dom.c: Include timevar.h and tree-dump.h. + (tree_ssa_dominator_optimize): Change to receive the function decl + for the function to optimize. Update callers. + Use own dump file instead of dumping on the .ssa dump file. + Dump function at the end. + Push and pop TV_TREE_SSA_DOMINATOR_OPTS. + * tree-ssa.c (rewrite_into_ssa): Restore check for number of times + that the rename loop has been executed. Abort if the loop executes + more than twice. + * tree.h (enum tree_dump_index): Add TDI_dom. + * doc/invoke.texi: Document -fdump-tree-dom. + +2003-07-21 Steven Bosscher + Diego Novillo + + * Makefile.in (install-po): Check if $CATALOGS is empty to avoid + buggy shells. + * basic-block.h (rtl_verify_flow_info): Remove. + (tree_verify_flow_info): Remove. + (verify_flow_info): Declare. + * builtins.c: Rearrange to simplify merges. Add #if 0 around + expand_ functions that are not used in the branch and move new code + to the end of the file. + * c-opts.c (c_common_handle_option): Move handling of -fdump- to + opts.c. + * cfgloopmanip.c (loop_split_edge_with_NULL): Remove. Update all + users. + * common.opt: Add all the tree-ssa switches. + * opts.c: Handle them. + * flags.h (flag_tree_cp): Remove unused variable. + (enum pta_type): Move from tree-must-alias.h + (flag_tree_points_to): Likewise. + * toplev.c (flag_tree_cp): Remove unused variable. + * tree-cfg.c: Move cfg_hooks structures and functions for + trees from cfghooks.c. + * tree-mudflap.c (mudflap_enqueue_decl): Don't use %D to + avoid warning about format specifiers. + +2003-07-21 Diego Novillo + + * gimplify.c (gimplify_function_tree): Move gimplification of the + function body ... + (gimplify_body): ... here. + * tree-simple.h (gimplify_body): Declare. + * tree-inline.c (initialize_inlined_parameters): If the + emitted assignment is not in GIMPLE form, gimplify the + body of assignments emitted. + +2003-07-17 Jeff Law + + * tree-dfa.c (remove_phi_arg): Update PHI_ARG_CAPACITY. + + * tree-ssa.c (mark_def_sites): Do not build the dominator tree here. + (rewrite_into_ssa): Do not depend on mark_def_sites to build the + dominator tree. Move computation of dominance frontiers out + of main loop (even though it was only done once). Free immediate + dominator information as soon as we're done with it. + + * tree-flow.h (remove_phi_nodes_and_edges_for_unreachable_block): + Prototype. + * tree-cfg.c (remove_phi_nodes_and_edges_for_unreachable_block): New + function extracted from remove_bb. + (remove_bb): Call remove_phi_nodes_and_edges_for_unreachable_block. + + * tree-ssa-dom.c (optimize_block): Propagate values into PHI nodes. + Do not optimize a block which has become unreachable. + If a COND_EXPR has a compile-time constant condition, then remove + outgoing from the COND_EXPR which can not execute. + +2003-07-16 Frank Ch. Eigler + + * tree-mudflap.c (mx_xfn_indirect_ref): Correct source locations + for tracked expressions by ignoring incidental decl source loci. + +2003-07-16 Jeff Law + + * tree-cfg.c (remove_bb): Remove statements in reverse order. + Simplify code to issue warnings for unreachable code. + + * tree-ssa-dom.c (get_eq_expr_value): Also enter expressions + into the available expression hash table. Callers changed to + pass in the block_avail_exprs varray and const_and_copies hash + table. + (optimize_stmt): Allow optimization of the condition in + a COND_EXPR statement. + (lookup_avail_expr): For COND_EXPRs, just see if their condition + has been recorded into the hash table, do not enter them into + the hash table. Only do a lookup of the result in the + const_and_copies table if it is an SSA_VAR. + (avail_expr_hash): Handle COND_EXPRs, specifically we only care + about their condition and virtual operands. + (avail_expr_eq): Likewise. If one statement has virtual operands + and the other does not, then the expressions are not equal. + + * tree-ssa.c (rewrite_into_ssa): If we have done dominator + optimizations, then call cleanup_tree_cfg after rewriting is + complete. + * tree-ssa-dom.c (optimize_block): Get eq_expr_value for the + current block rather than having it passed in by the caller. + Propagate eq_expr_value into the false arm of a COND_EXPR. + (get_eq_expr_value): Return equivalences for the false + arm of a COND_EXPR if requested. + +2003-07-16 Daniel Berlin + + * c-decl.c (store_parm_decls): Also strip NON_LVALUE_EXPRs and + CONVERT_EXPRs when setting DECL_NONLOCAL. + +2003-07-15 Daniel Berlin + + * tree-cfg.c (remove_stmt): Update bb->end_tree_p properly when + stmt_p is the end of the bb. + +2003-07-15 Jeff Law + + * tree-ssa-dom.c (optimize_stmt): Consider two types equivalent if + their TYPE_MAIN_VARIANT is equivalent. + (avail_expr_eq): Likewise. + + * Makefile.in (OBJS): Add tree-ssa-dom.o + (tree-ssa-dom.o): Add dependencies. + (ssa.o, cfghooks.o): Use $(TREE_FLOW_H), not tree-flow.h. + * timevar.def: Add new timevar for dominator optimizer. Reorder + slightly. + * tree-dfa.c (add_stmt_operand): Do not consider references to + static storage as volatile operands. + (add_referenced_var): Static storage items reference global memory. + * tree-ssa.c: Simplify by moving everything specific to the + dominator optimizer into tree-ssa-dom.c. Call into the dominator + optimizer after rewriting all the basic blocks. + * tree-ssa-dom.c: New file. Mostly extracted from tree-ssa.c + * tree-flow.h (tree_ssa_dominator_optimize): Prototype. + (dump_dominator_optimization_stats): Likewise. + (debug_dominator_optimization_stats): Likewise. + +2003-07-15 Diego Novillo + + * tree-dfa.c (add_stmt_operand): Move volatile handling... + (find_vars_r): ... here. + Mark when the walker is inside an ASM_EXPR. + (struct walk_state): Add field 'is_asm_expr'. + Change flag fields to bitfields. + (add_referenced_var): If the variable is a pointer being stored by + an ASM_EXPR, mark it as a global memory pointer. + * tree-flow-inline.h (is_optimizable_addr_expr): New function. + * tree-flow.h (is_optimizable_addr_expr): Declare it. + * tree-ssa.c (rewrite_and_optimize_stmt): Use it. + (lookup_avail_expr): Likewise. + (get_eq_expr_value): Likewise. + (avail_expr_eq): Return 'true' when comparing a statement against + itself. + * tree-ssa-dce.c (need_to_preserve_store): Move volatile checking... + (stmt_useful_p): ...here. + +2003-07-15 Andreas Jaeger + + * c-simplify.c: Convert prototypes to ISO C90. + * gimplify.c: Likewise. + * simple-break-elim.c: Likewise. + * simple-goto-elim.c: Likewise. + + * tree-alias-ander.c: Convert prototypes to ISO C90. + * tree-alias-common.c: Likewise. + * tree-alias-type.c: Likewise. + * tree-browser.c: Likewise. + * tree-dchain.c: Likewise. + * tree-mudflap.c: Likewise. + * tree-nomudflap.c: Likewise. + * tree-optimize.c: Likewise. + * tree-pretty-print.c: Likewise. + * tree-simple.c: Likewise. + + * tree-alias-common.h: Convert prototypes to ISO C90, remove extra + whitespace. + * tree-alias-type.h: Convert prototypes to ISO C90. + * tree-dchain.h: Likewise. + * tree-flow-inline.h: Likewise. + * tree-flow.h: Likewise. + * tree-iterator.h: Likewise. + * tree-mudflap.h: Likewise. + * tree-simple.h: Likewise. + +2003-07-14 Daniel Berlin + + * tree-ssa-pre.c (tree_perform_ssapre): Fix dom_children after DCE + breaks them. + +2003-07-14 Diego Novillo + + * tree-dfa.c (add_vdef): Initialize variable 'vdef'. + (add_vuse): Initialize variable 'vuse'. + +2003-07-14 Diego Novillo + + Must alias analysis. Allow the SSA rename pass to be done on a set + of variables. + + * Makefile.in (OBJS): Add tree-must-alias.o. + * flags.h (flag_tree_must_alias): Declare. + * timevar.def (TV_TREE_MUST_ALIAS): Define. + * toplev.c (flag_tree_must_alias): Declare. + (f_options): Add entry for -ftree-must-alias. + (parse_options_and_default_flags): Enable must-alias analysis at -O1. + + * tree-cfg.c (remove_useless_stmts_and_vars): Do not remove + addressable variables. + + * tree-dfa.c (dump_file, dump_flags): New local variables to + replace tree_ssa_dump_file and tree_ssa_dump_flags. Update every + user. + (get_stmt_operands): Clear the array of virtual operands before + scanning the statement. + (get_expr_operands): Do not add an operand for ADDR_EXPR if the + expression takes the address of a VAR_DECL or a PARM_DECL. Instead + add the variable to the list of variables whose address has been + taken by the statement. + Allow INDIRECT_REF expressions of the form *&VAR. Convert them + into an operand for VAR. + When processing function calls, add a VUSE for .GLOBAL_VAR if the + function is pure but not const. + (add_stmt_operand): If the operand is an ADDR_EXPR, add the + variable to the list of variables whose address has been taken by + the statement. + (add_vdef): If the statement had virtual definitions, try to find + an existing VDEF for the variable, to preserve SSA information. If + none is found, create a new one. + (add_vuse): Likewise. + (remove_all_phi_nodes_for): New function. + (get_call_flags): New function to replace call_may_clobber. Update + all callers. + + * tree-dump.c (dump_files): Add entry for -fdump-tree-mustalias. + * tree-flow-inline.h (addresses_taken): New function. + (is_unchanging_value): New function. + + * tree-flow.h (addresses_taken): Declare. + (remove_all_phi_nodes): Declare. + (init_tree_ssa): Declare. + (propagate_copy): Declare. + (is_unchanging_value): Declare. + (tree_compute_must_alias): Declare. + + * tree-inline.c (copy_body_r): Fold instances of *&VAR. + + * tree-must-alias.c: New file. + + * tree-optimize.c (optimize_function_tree): Call init_tree_ssa and + compute_may_aliases before calling rewrite_into_ssa. + After the SSA pass, run dead code elimination and compute + must-aliases. + + * tree-simple.c (is_gimple_call_expr): Add comment that + is_gimple_* predicates should not have side effects. + + * tree-ssa-ccp.c: Replace calls to really_constant_p with + is_unchanging_value everywhere. + (fold_stmt): Don't fold if the RHS is already a constant. + + * tree-ssa-copyprop.c (copyprop_stmt): Remove unnecessary + variable 'vuse'. + Call propagate_copy to replace the operand with its new value. + (copyprop_phi): Remove unnecessary variable 'vuse'. + (get_original): Remove unused parameter 'vuse_p'. + (propagate_copy): New function. + + * tree-ssa-dce.c (need_to_preserve_store): Update comments. + + * tree-ssa.c (dump_file, dump_flags): New local variables to + replace globals tree_ssa_dump_file and tree_ssa_dump_flags. Update + all users. + (addr_expr_propagated_p): New local variable. + (vars_to_rename): New local variable. + (check_for_new_variables): New local function. + (rewrite_into_ssa): Add new argument VARS which is a bitmap + representing all the variables that should be renamed into SSA. If + VARS is NULL, all the variables in the program are renamed. + Don't call init_tree_ssa nor compute_may_aliases. + Initialize all the local hash tables and bitmaps. + Add support for repeating the SSA rename process more than once. + If the dominator optimizations produced new symbols, repeat the + process. + (mark_def_sites): Ignore operands that are in SSA form already. + (insert_phi_nodes): Only add PHI nodes for variables in the + VARS_TO_RENAME bitmap. + (rewrite_block): Ignore PHI nodes that have been renamed already. + (rewrite_and_optimize_stmt): Ignore operands that are already in + SSA form. + When propagating ADDR_EXPR set addr_expr_propagated_p to 'true'. + Call propagate_copy when doing copy propagation. + Call is_unchanging_value to decide if the RHS of an assignment is a + constant. + (rewrite_stmt): Ignore operands that are already in SSA form. + (init_tree_ssa): Make external. + Move initialization of local hash tables and bitmaps to + rewrite_into_ssa. + (remove_annotations_r): Don't special case MODIFY_EXPR nodes. + (lookup_avail_expr): Call is_unchanging_value. + (get_eq_expr_value): Likewise. + + * tree.h (enum tree_dump_index): Add TDI_must_alias. + + * cp/optimize.c (optimize_function): Don't call the tree optimizers + if -fdisable-tree-ssa is given. + + * doc/invoke.texi: Add documentation for -ftree-must-alias. + +2003-07-07 Jeff Law + + * fold-const.c (nondestructive_fold_unary_to_constant: For BIT_NOT_EXPR + make sure OP0 is a suitable constant before trying to fold it. + + * tree-cfg.c (handle_switch_fallthru): Set DECL_CONTEXT for + newly created labels. + + * tree-cfg.c (move_outgoing_edges): New function. + (merge_tree_blocks): Use it. + (remove_bb): Remove the block from the pdom_info structures + as well if they exist. + (linearize_cond_expr): Move important edges from the then and + else arms to BB as appropriately + + * tree-cfg.c (remove_stmt): When removing a COMPOUND_EXPR, make + sure that any basic block pointers to the arms of the COMPOUND_EXPR + are updated. + + * tree-cfg.c (make_goto_expr_edges): Computed gotos create + abnormal edges. + +2003-07-05 Daniel Berlin + + * tree-ssa-pre.c (defs_match_p): Check for copies of the same version. + +2003-07-03 Frank Ch. Eigler + + * tree-nomudflap.c (mf_marked_p, mf_mark): New dummy functions. + +2003-07-03 Jeff Law + + * tree-ssa.c (lookup_avail_expr): Accept new argument containing the + const_and_copies table. All callers changed. If we find the + given expression in the availe expression hash table, then lookup + the LHS of the hash table's entry in the const_and_copies_table. + Do record type casts into the available expression table. + + * tree-nomudflap.c (mf_marked_p): Mark arguments as being unused. + (mf_mark): Likewise. + + * c-decl.c (store_parm_decls): Strip away NOP_EXPRs when looking + for hidden use variables. + +2003-07-02 Frank Ch. Eigler + + * varasm.c (build_constant_desc): Propagate mudflap marked-ness + across constant copying. + +2003-07-02 Daniel Berlin + + * tree-ssa-pre.c (tree_perform_ssapre): Don't optimize things with + volatile ops or making aliased loads right now. + (create_expr_ref): Mark the phi result of the new phi as having + real refs. + (finalize_1): Mark the new temp as having real refs. + (repair_use_injury): Ditto. + (code_motion): Ditto. + +2003-07-01 Daniel Berlin + + * tree.h (struct tree_eref_common): Add injured flag. + Add EREF_INJURED macro. + +2003-07-01 Daniel Berlin + + * tree-flow-inline.h (stmt_ann): We have stmt_ann on E*_NODE's as well, + so use is_essa_node as well. + * tree-dfa.c (create_stmt_ann): Ditto. + * tree.h (is_essa_node): Declare. + * tree.c (is_essa_node): Define. + +2003-07-01 Jason Merrill + + * tree-cfg.c (prepend_stmt_to_bb): New fn. + (bsi_insert_after): Add to the beginning of an empty block. + +2003-07-01 Jeff Law + + * expr.c (expand_expr, case COND_EXPR): Correctly (?) handle + cases where a containing block has a stack level. Handle + cases where one arm is a GOTO_EXPR and the other arm has + side effects. + + * stmt.c (containing_blocks_have_cleanups_or_stack_level): New + function. + (any_pending_cleanups): Further simplification. + * tree.h (containing_blocks_have_cleanups_or_stack_level): Prototype. + +2003-06-30 Diego Novillo + + * tree-flow.h (struct tree_ann_common_d): Remove 'stmt' field. + Update all users. + (struct var_ann_d): Remove field 'has_real_refs'. Update all callers + with calls to SSA_NAME_HAS_REAL_REFS. + Remove field 'occurs_in_abnormal_phi'. Update all callers with + calls to SSA_NAME_OCCURS_IN_ABNORMAL_PHI. + * tree-flow-inline.h (var_ann): Only accept _DECL nodes. + (stmt_ann): Only accept GIMPLE statements. + (tree_stmt): Remove. Update all users. + + * tree-cfg.c (linearize_cond_expr): Handle cases where BB doesn't + have a postdominator. + (find_contained_blocks): Do not look inside COND_EXPR_COND nor + SWITCH_COND expressions. + + * tree-dfa.c (get_stmt_operands): Force virtual operands on + ASM_EXPRs. + (get_expr_operands): Handle SSA names when adding operands for + memory tags. + (add_stmt_operand): Handle SSA names. + Move checks for volatile operands earlier in the code. + (add_vdef): Re-format for readability. + (create_var_ann): Only allow _DECL nodes. + (create_stmt_ann): Only allow GIMPLE statements. + (dump_variable): Handle SSA names. + (dump_may_aliases_for): Likewise. + (may_access_global_mem_p): Handle SSA names. + (remove_phi_arg): If the argument removed was the last one with + real references, update the LHS of the PHI node. + (add_phi_arg): If the argument added has real references, propagate + the attribute into the LHS of the PHI node. + + * tree-pretty-print.c (dump_generic_node): Only retrieve basic + block information from GIMPLE statements. + Always output the THEN and ELSE clauses of COND_EXPR nodes. + + * tree-simple.c (is_gimple_stmt): Accept PHI_NODEs. + (is_gimple_id): Accept SSA_NAMEs. + + * tree-ssa-copyprop.c (copyprop_phi): If an argument is used as a + real operand, propagate the attribute into the LHS of the PHI. + + * tree-ssa-live.c (create_ssa_var_map): Don't set 'used' flag on + both the operand and the result of VDEFs. + Only register PHI results and arguments that have been used as real + operands. + (calculate_live_on_entry): Fix formatting in debugging message. + + * tree-ssa.c (register_new_def): Add new argument + 'is_real_operand'. If it's set, set SSA_NAME_HAS_REAL_REFS for the + new name. Update all callers. + (rewrite_operand): Add new argument 'is_real_operand'. If it's + set, set SSA_NAME_HAS_REAL_REFS to the operand. + (eliminate_build): Ignore PHI arguments and PHI results that have + not been used in real operands. + (rewrite_vdefs): Remove. Update all users. + (set_is_used): Don't handle SSA names. + (coalesce_ssa_name): Ignore PHI arguments that have not had real + references in the program. + + * tree.c (make_ssa_name): Update documentation. + * tree.h (IS_EMPTY_STMT): Call integer_zerop instead of comparing + against size_zero_node. + (SSA_NAME_HAS_REAL_REFS): Define. + (SSA_NAME_OCCURS_IN_ABNORMAL_PHI): Define. + (struct tree_ssa_name): Add bitfields 'has_real_refs' and + 'occurs_in_abnormal_phi'. + +2003-06-30 Jeff Law + + * c-simplify.c (gimplify_c_loop): Don't return a LOOP_EXPR for + a do ... while (0) loop. + + * expr.c (expand_expr, case COND_EXPR): Be smarter about expanding + a COND_EXPR with only one useful arm, which happens to be a GOTO_EXPR. + + * tree-cfg.c (remove_useless_stmts_and_vars): Don't remove user + variables unless we're at -O2 or higher. + +2003-06-30 Daniel Berlin + + * tree-ssa-pre.c (expr_phi_insertion): Stop optimizing the expression + if we have > some very large number of ephi operands, as it will + take an ungodly amount of memory and time. + (pre_expression): Push/pop gc context so we can do gc collection + in between expressions. + Throw away expression info right after done optimizing it. + +2003-06-30 Jason Merrill + + * gimplify.c (gimplify_call_expr): Check PUSH_ARGS_REVERSED. + + * gimplify.c (gimplify_modify_expr): Also force a call with a + possible nonlocal goto into a temporary. + (gimplify_return_expr): Don't duplicate the MODIFY_EXPR. + * tree-iterator.h (tsi_one_before_end_p): New fn. + +2003-06-29 Jeff Sturm + + * fold-const.c (fold): Don't save_expr unless TREE_SIDE_EFFECTS. + +2003-06-26 Diego Novillo + + * c-simplify.c (gimplify_stmt_expr): Handle statement-expressions + that don't end in a non-void expression. Emit a warning in that + case. + +2003-06-26 Daniel Berlin + + * tree-ssa-pre.c (fixup_domchildren): Rename from + compute_domchildren, change to not use our own array. + (domchildren): Remove variable. + (insert_occ_in_preorder_dt_order_1): Use dom_children now. + (insert_euse_in_preorder_dt_order_1): Ditto. + (search_dt_preorder): Ditto. + (handle_bb_creation): Fix to work properly. + (tree_perform_ssapre): Remove remnants of domchildren. + Redo dominator info if we have to due to a new block. + +2003-06-26 Andrew MacLeod + + * tree-cfg.c (handle_switch_split): Use a tree iterator to find the + real split point rather than a block iterator. + +2003-06-26 Jason Merrill + + * tree-simple.c (is_gimple_stmt): Complete. + +2003-06-24 Jeff Law + + * tree-cfg.c (remove_useless_stmts_and_vars): On the first + iteration, remove unused variables from BIND_EXPRs. + * tree-flow.h (var_ann_d): Add new field USED. + (set_is_used): Prototype. + (remove_useless_stmts_and_vars): Update prototype. + * tree-ssa-live.c (create_ssa_var_map): Note which variables + are used so that we can delete those which are not used. + * tree-ssa.c (create_temp): Mark the new temporary as being used. + (rewrite_out_of_ssa): Note if the call to remove_useless_stmts_and_vars + is the first iteration or not. + (set_is_used): New function. + + * c-decl.c (store_parm_decls): Variables and parameters on the + pending_sizes chain have nonlocal uses. + +2003-06-25 Daniel Berlin + + * tree-ssa-pre.c: Convert to ISO C. + (handle_bb_creation): New function. + (ephi_will_be_avail): Remove dead code. + (finalize_1): Use handle_bb_creation, start to fix edge insertion + related fun. + (maybe_find_rhs_use_for_var): Stop using tree_stmt. + (code_motion): Always get the temporary from the right place. + +2003-06-24 Jason Merrill + + * gimplify.c (gimplify_self_mod_expr): Add want_value parm. + For postfix ops, make sure it returns an rvalue. + (gimplify_expr): Copy a volatile reference into a temp. + (create_tmp_var): Require a complete type. + (create_tmp_alias_var): Use TYPE_VOLATILE on types. + * tree-simple.c (is_gimple_stmt): Flesh out a bit. + (is_gimple_val): Don't allow volatiles. + + * c-simplify.c (gimplify_expr_stmt): Don't insert a null pointer. + + * gimplify.c (gimplify_return_expr): Search through the gimple + form for the interesting MODIFY_EXPR. + (gimplify_modify_expr): Don't suppress posteffects if want_value. + +2003-06-24 Diego Novillo + + * tree-dfa.c (struct dfa_stats_d): Remove obsolete fields + num_tree_refs and size_tree_refs. Update all users. + (dump_dfa_stats): Also dump information about VUSE and VDEF + operands. + * tree-ssa.c (rewrite_vdefs): Dump information about VDEF operators + promoted to real copies if -fdump-tree-optimized-details is given. + +2003-06-23 Jeff Law + + * tree-ssa.c (avail_expr_eq): Verify types are the same before + handing expressions to operand_equal_p. + + * tree-cfg.c (make_edges): Remove fake edges before building + extra edges for TRY_FINALLY_EXPRs. Delete unnecessary edges + leaving the TRY block in a TRY_FINALLY_EXPR. + (find_contained_blocks): Don't consider statements in the CATCH + clause of a TRY_CATCH_EXPR when noting the last statement in + the block. + * tree-dfa.c (remove_phi_arg): If we removed the last PHI argument, + then remove the entire PHI node. + * tree-ssa-dce.c (stmt_useful_p): Consider the other EH related + nodes useful as well (TRY_FINALLY_EXPR, TRY_CATCH_EXPR, and + EH_FILTER_EXPR). + + * tree-cfg.c (remove_useless_stmts_and_vars): If the body of a + TRY_CATCH_EXPR is empty, then the entire TRY_CATCH_EXPR can + be safely removed. + + * tree-cfg.c (find_contained_blocks): Renamed from + find_contained_blocks_and_edge_targets. Remove targets + bitmap argument and no longer record targets of edges. + All callers changed. + (make_edges): No longer need TRY_TARGETS bitmap. Kill it. + Simplify code which creates additional edges out of the TRY + block and the FINALLY block in a TRY_FINALLY_EXPR. + +2003-06-23 Diego Novillo + + * tree-alias-common.c (ptr_may_alias_var): Don't handle memory + tags. + * tree-dfa.c (struct alias_set_d): Remove. Update all users. + (alias_sets): Remove. Update all users. + (struct walk_state): Remove field aliased_objects_found. + (struct alias_map_d): New. + (addressable_vars): New local variable. + (pointers): New local variable. + (add_stmt_operand): Do not force aliased variables to be in virtual + operands. + (register_alias_set): Remove. Update all users. + (find_alias_for): Remove. Update all users. + (get_memory_tag_for): New local function. + (num_referenced_vars): Remove. + (num_aliased_objects): Remove. Update all users. + (aliased_objects): Remove. Update all users. + (aliased_objects_alias_set): Remove. Update all users. + (num_call_clobbered_vars): Remove. Update all users. + (dump_variable): Move code to dump aliases ... + (dump_may_aliases_for): ... here. + (debug_may_aliases_for): New function. + (compute_may_aliases): Initialize 'addressable_vars' and 'pointers' + arrays. + (compute_alias_sets): Re-implement matching pointers with + addressable variables. Limit the size of may-alias sets. + (may_alias_p): Re-implement to compare pointers against variables, + instead of memory tags. + (dump_alias_info): Re-implement to display pointers and addresable + variables arrays. + (add_referenced_var): Collect addressable variables and pointers. + Share memory tags among pointers that may alias each other. + * tree-flow.h (num_referenced_vars): Change to macro. + (referenced_var): Likewise. + (num_call_clobbered_vars): Likewise. + (call_clobbered_var): Likewise. + (dump_may_aliases_for): Declare. + (debug_may_aliases_for): Declare. + * tree-ssa.c (rewrite_vdefs): New local function. + (rewrite_out_of_ssa): Call it. + +2003-06-23 Jeff Law + + * tree-cfg.c (make_edges): Walk TRY_FINALLYs inner to outer and + simplify creation of special edges related to the TRY_FINALLY_EXPR. + + * tree-cfg.c (remove_useless_stmts_and_vars): More aggressively + remove TRY_CATCH_EXPRs and TRY_FINALLY_EXPRs. + + * tree-cfg.c (make_edges): Remove fake edges. + (make_exit_edges): Mark edges from nonreturning functions to the + exit block as being fake edges. + + * gimplify.c (gimplify_modify_expr): Don't create a new MODIFY_EXPR, + reuse the existing one. + +2003-06-23 Andrew MacLeod + + * tree-cfg.c (find_insert_location): Default case should insert after + the last stmt in the block. + +2003-06-22 Jeff Sturm + + * Makefile.in (old-tree-inline.o): Remove rule. + * old-tree-inline.c: Remove. + +2003-06-19 Jeff Law + + * tree-cfg.c (make_ctrl_stmt_edges): Do not create bogus edges + to the successor block of TRY_CATCH_EXPR, TRY_FINALLY_EXPR, + CATCH_EXPR or EH_FILTER_EXPR nodes. + + * gimplify.c (gimplify_modify_expr): If the RHS of an MODIFY_EXPR + might throw, then make sure its result goes into a temporary. + + * tree-cfg.c (handle_switch_split): Handle case where target + block has only one statement (the case label itself). + +2003-06-19 Diego Novillo + + * doc/invoke.texi: Add documentation for -ftree-dominator-opts + that was missing from an earlier patch. + +2003-06-19 Jeff Sturm + + * gimplify.c (gimplify_expr): Handle LABELED_BLOCK_EXPR + and EXIT_BLOCK_EXPR. + (gimplify_labeled_block_expr): New function. + (gimplify_exit_block_expr): New function. + +2003-06-18 Andrew MacLeod + + * tree-cfg.c (EDGE_INSERT_LOCATION_BSI_AFTER): New location code. + (cleanup_switch_expr_graph): Find default case correctly. + (bsi_insert_after): Get BB from stmt when its avialble. + (bsi_insert_before): Get BB from stmt when its avialble. + (handle_switch_fallthru): New. Handle edge from switch to the fallthru. + (handle_switch_split): Re-implement using new scheme. + (find_insert_location): Use handle_switch_fallthru (). + (bsi_insert_on_edge_immediate): Handle EDGE_INSERT_LOCATION_BSI_AFTER. + * tree-iterator.h (tsi_last): New. Find last stmt in a chain. + +2003-06-17 Daniel Berlin + + * tree-alias-common.c (find_func_aliases): Guard cast op + properly. + (ptr_may_alias_var): Small optimization to avoid calling + decl_function_context so often. + * tree-alias-ander.c (ander_simple_assign): Ignore if lhs == rhs. + +2003-06-17 Steven Bosscher + + * timevar.def (TV_TREE_BUILD_FUD_CHAINS): Remove. + +2003-06-16 Diego Novillo + + * tree-ssa-ccp.c (DONT_SIMULATE_AGAIN): Define. + (visit_phi_node): Don't do anything if the PHI node doesn't need to + be simulated. + If the PHI variable does not have real references, consider it + VARYING. + If the PHI node has a lattice value of VARYING, set + DONT_SIMULATE_AGAIN. + (visit_stmt): Don't do anything if the statement doesn't need to be + simulated. + Only visit conditional branches COND_EXPR and SWITCH_EXPR. + If the statement doesn't produce a result mark it with + DONT_SIMULATE_AGAIN. + (visit_assignment): Remove unnecessary def_op() check. + If the value is VARYING, mark the statement with + DONT_SIMULATE_AGAIN. + (visit_cond_stmt): Remove unnecessary is_ctrl_stmt() check. + If the predicate is VARYING, mark the statement with + DONT_SIMULATE_AGAIN. + (initialize): Clear DONT_SIMULATE_AGAIN flag for every statement + and PHI node. + (likely_value): Get statement operands after checking if it makes + aliased loads or has volatile operands. + +2003-06-16 Jeff Law + Jason Merrill + + * except.c (enum eh_region_type): Don't declare the enumeration + members here. Instead do it in except.h. + (expand_eh_hander): Use expr_first instead of open-coding it. + * except.h (enum eh_region_type): Define the enumeration memebers + here. + * tree-cfg.c (last_exec_block): Break out from make_edges. + (could_trap_p): No longer static. + (get_eh_region_type): New function. + (make_try_expr_blocks): Keep the whole TRY_CATCH_EXPR or + TRY_FINALLY_EXPR instead of just the handler part in the + EH_STACK varray. For a cleanup, record which cleanup higher + in the EH_STACK it can reach. + (make_edges): Use last_exec_block. + (make_ctrl_stmt_edges): Thread cleanups as needed. + (compute_reachable_eh): Use get_eh_region_type. Properly + track when we can skip cleanups. Skip cleanups when possible. + * tree-flow.h (could_trap_p): Prototype. + +2003-06-16 Andrew Macleod + + * tree-cfg.c (find_insert_location): Check for control_altering stmts, + and abort if its an unrecognized BB ending stmt. + (bsi_commit_first_edge_insert): Rename to bsi_insert_on_edge_immediate, + externalize, and change the interface to an on-demand inserter. + (bsi_commit_edge_inserts): Call bsi_insert_on_edge_immediate(). + * tree-flow.h (bsi_insert_on_edge_immediate): Prototype. + * tree-pretty-print.c (dump_block_info): Add 'ab' for abnormal edges. + * tree-ssa-dce.c (process_worklist): Use sparse bitmaps. + * tree-ssa-live.c (calculate_live_on_entry): Abort if ssa_name has a + definition, but is also live on entry. + * tree-ssa.c (coalesce_ssa_name): Call abort() instead of error(), and + provide more detailed info. + (rewrite_out_of_ssa): Provide CFG dumps before and after rewritting. + +2003-06-16 Frank Ch. Eigler + + * tree-mudflap.c (mf_mark): Use GC-compatible htab_create_ggc. + +2003-06-15 Jeff Law + + * tree-ssa-ccp.c (visit_phi_node): If the PHI is already known + to be varying, don't recompute its value. + +2003-06-14 Jeff Law + Jason Merrill + + * tree-cfg.c (make_blocks): Do not return early if presented + with an empty statement. + (make_ctrl_stmt_edges): Do not try to optimize an empty TRY + block in a TRY_FINALLY_EXPR. Simplify TRY_FINALLY_EXPR, + TRY_CATCH_EXPR, CATCH_EXPR, and EH_FILTER_EXPR now that empty + statements are no longer shared. + +2003-06-14 Kazu Hirata + + * tree-ssa-pre.c: Fix a comment typo. + +2003-06-13 Diego Novillo + + * tree-dfa.c (get_stmt_operands): Abort if the statement is a + variable. + (create_var_ann): Abort if the variable is not a _DECL node. + +2003-06-13 Frank Ch. Eigler + + * tree-mudflap.c (mudflap_c_function): Change calling conventions so + as to return the instrumented function body rather than changing the + given fndecl in place. Gimplify at the very end, for cosmetic + reasons. + * tree-mudflap.h, tree-nomudflap.c: Corresponding changes. + * c-decl.c (c_expand_body_1): Call mudflap_c_function just before + rtl expansion of function body; don't interfere with inlining. + +2003-06-13 Diego Novillo + + * c-simplify.c: Fix typo in previous change. + +2003-06-13 Diego Novillo + + * c-common.c, c-common.h, c-decl.c, c-lang.c, c-simplify.c, + flags.h, gimplify.c, langhooks-def.h, langhooks.c, langhooks.h, + simple-break-elim.c, simple-goto-elim.c, toplev.c, + tree-alias-common.c, tree-cfg.c, tree-dfa.c, tree-dump.c, + tree-inline.c, tree-mudflap.c, tree-simple.c, tree-simple.h, + tree-ssa-ccp.c, tree-ssa-pre.c, tree-ssa.c, tree.h, doc/invoke.texi: + Rename SIMPLE to GIMPLE everywhere. + +2003-06-13 Andrew MacLeod + + * tree-cfg.c (bsi_commit_first_edge_insert): Only consider non-abnormal + edges when determining whether an edge needs to be split. + + * tree-ssa-dce.c (process_worklist): When checking for GOTO and + COND_EXPR's that are necessary, check each BB's predecessors only once. + +2003-06-12 Jeff Law + + * tree-ssa.c (avail_expr_eq): Add some checking code to + detect when equal expressions have different hash values. + + * tree.c (iterative_hash_expr): Don't hash types associated + with conversions. Instead hash on the signedness of the + toplevel object and the operand of the conversion. + + * Makefile.in (gimplify.o): Depend on $(RTL_H). Ugh. + * gimplify.c: Include "rtl.h". + (simplify_call_expr): Use call_expr_flags and check for ECF_CONST + rather than checking bits in the tree node directly. + + * fold-const.c (operand_equal_p): CALL_EXPRs with side effects + are never equal. + +2003-06-11 Frank Ch. Eigler + + * gcc.c (MFWRAP_SPEC): Always wrap main(). + * tree-mudflap.c (mudflap_enqueue_decl): Mark enqueued decls + to prevent their repeated processing. + +2003-06-11 Daniel Berlin + + * tree-ssa-pre.c: add graph_dump_file, graph_dump_flags. + (finalize_1): Modify to use temporary in expr_info structure, + remove temporary from arguments. + Use bsi_insert_on_edge for ephi insertions. + Set EREF_TEMP on inserted euses. + (repair_phi_injury): Note (to dump file) injuries we have + repaired already. + (repair_use_injury): Ditto. + (repair_euse_injury): Ditto. + (count_stmts_in_bb): Count both forwards and backwards, and make + sure the numbers agree. This makes sure both the head and end are + updated properly. + (code_motion): Use the EREF_TEMP, rather than calculating the + reaching def, when possible, because it's faster. + Add the phi we created when we insert the ephi. We should always + be able to get the reaching def of the ephi from EREF_TEMP (since + the args should have already been inserted, or in the case of + phi's, have a phi already allocated), so abort if we can't. + (create_expr_ref): Take expr_info parameter. Make a phi for the + ephi's, but don't add to the bb yet. Update all callers. + (get_default_def): New function. + (get_reaching_def): Use it to find the default def when we hit the + top of the dom tree. + (struct expr_info): Add temp. + (new_rename_1): Dump out occurrences after rename 1, but before + rename 2. + (requires_edge_placement): Now that we can insert on edges, we + shouldn't need this, so make it always return false. + Will remove unless something bad comes up. + (pre_expression): Start working on dumping the redundancy graph. + + * tree.h (struct treeeref_common): Add the temp member. + Add EREF_TEMP macro. + (tree_dump_index): Reorder to match actual optimization order. + Add TDI_predot. + + * tree-dump.c: Ditto. + +2003-06-11 Jeff Law + + * gimplify.c (simplify_call_expr): Clear TREE_SIDE_EFFECTS for + calls to "const" functions. + + * tree-inline.c (expand_call_inline): Recalculate TREE_SIDE_EFFECTS + properly when inlining gimplified functions. + + * fold-const.c (operand_equal_p): Handle CALL_EXPRs. + + * tree-cfg.c (first_exec_block): Kill. + (make_edges): Use bb_for_stmt rather than first_exec_block. + (make_ctrl_stmt_edges, make_exit_edges): Likewise. + (make_loop_expr_edges, make_cond_expr_edges): Likewise. + (successor_block): Don't skip empty statements. + + * tree-ssa.c (rewrite_and_optimize_stmt): Do not special case + CALL_EXPRs they're caught by the TREE_SIDE_EFFECTS test. + + * tree-ssa.c (rewrite_and_optimize_stmt): Improve/correct setting of + may_optimize_p. Simplify later code knowing may_optimize_p is + correctly set. + (avail_expr_hash): Do not use iterative_hash_object or deal with + SSA names for real operands. Instead use iterative_hash_expr + which handles both. + (avail_expr_eq): Use operand_equal_p to test for equality. + +2003-06-11 Steven Bosscher + + * tree-flow.h, tree-ssa-ccp.c, tree-ssa-copyprop.c, + tree-ssa-dce.c, tree-ssa-live.c, tree-ssa-live.h: + Convert function prototypes to ISO C. + +2003-06-10 Jeff Law + + * toplev.c (parse_options_and_default_flags): Fix typo in last change. + + * gimplify.c (simplify_expr, case BIT_FIELD_REF): Make sure + to call recalculate_side_effects after gimplifying the + operands. + +2003-06-10 Diego Novillo + + * toplev.c (flag_tree_dom): New variable. + (f_options): Add new entry for -ftree-dominator-opts. + (parse_options_and_default_flags): Enable flag_tree_dom for + -O1 and higher. At -O2 and higher, disable flag_tree_dom is + SSA-PRE is also specified. + * flags.h (flag_tree_dom): Declare. + * doc/invoke.texi: Document -ftree-dominator-opts. + * tree-ssa.c (rewrite_block): Disable tracking of available + expressions when not doing dominator optimizations. + Call rewrite_stmt when not doing dominator optimizations. + Otherwise, call rewrite_and_optimize_stmt. + (rewrite_stmt): Don't optimize the statement. Just rename. + (rewrite_and_optimize_stmt): Optimize the statement while rewriting + its operands. + (lookup_avail_expr): Update comments. + +2003-06-10 Andrew Haley + + * c-simplify.c (c_simplify_stmt): case ASM_STMT: Ensure qualifiers + come from input statement. + +2003-06-09 Andrew MacLeod + + * tree-cfg.c (handle_switch_split): Update PHI nodes when splitting. + (tree_split_edge): Update PHI nodes in destination block. + +2003-06-09 Steven Bosscher + + * basic-block.h, tree-dfa.c, tree-ssa.c, tree-cfg.c, + tree-flow.h: Convert function prototypes to ISO C. + +2003-06-09 Daniel Berlin + + * tree-cfg.c (bsi_commit_edge_inserts): Fix computation of + new_blocks. + +2003-06-08 Diego Novillo + + * tree-cfg.c (handle_switch_split): Don't allocate basic block + annotations more than once. + (bsi_commit_first_edge_insert): Likewise. + +2003-06-07 Jeff Sturm + + * tree-cfg.c (could_trap_p): New function. + (stmt_ends_bb_p): Handle flag_non_call_exceptions. + (make_exit_edges): Handle flag_non_call_exceptions. + (is_ctrl_altering_stmt): Handle flag_non_call_exceptions. + * tree-inline.c (walk_tree): Add case for CHAR_TYPE. + * tree-ssa-dce.c (stmt_useful_p): Keep all CATCH_EXPRs. + +2003-06-05 Jason Merrill + + * stmt.c (asm_op_is_mem_input): New fn. + * tree.h: Declare it. + * gimplify.c (simplify_asm_expr): Call resolve_asm_operand_names. + Use is_simple_modify_expr_lhs for mem input ops. + +2003-06-05 Frank Ch. Eigler + + * c-mudflap.c (mflang_register_call): Give the synthetic decl + undefined (not zero) size. + +2003-06-05 Frank Ch. Eigler + + * tree-mudflap.c (mx_flag): Remove. Update callers to use mf_mark. + (TREE_MUDFLAPPED_P): Remove. Update callers to use mf_marked_p. + (mf_mark, mf_marked_p): Replacement functions to replace old node + marking based on tree flag-bits. + (mf_mostly_copy_tree_r): Preserve markedness across copies. + * tree-mudflap.h: Add new decls + * c-mudflap.c (mx_flag): Remove. Update callers to use mf_mark. + +2003-06-04 Diego Novillo + + * tree-dfa.c (add_stmt_operand): Always consider non-scalar types + virtual operands. + +2003-06-04 Andrew MacLeod + + * toplev.c (parse_options_and_default_flags): Turn tree_copyprop on by + default. + * tree-cfg.c (linearize_control_structures, linearize_cond_expr, + replace_stmt, merge_tree_blocks, remap_stmts): Fix PROTOS. + (find_insert_location): Add additional basic block parameter. Handle + switch stmts. + (handle_switch_split): New. Split edges to switch labels. + (bsi_commit_first_edge_insert): Add extra parameter to + find_insert_location call. Fix split block chaining in THEN & ELSE. + * tree-ssa-live.c (calculate_live_on_entry): Process all PHI def's + after all the arguments have been processed. + * tree-ssa.c (struct ssa_stats_d, struct loops *loops, var_is_live, + rewrite_into_ssa): Remove old UNSSA code. + (rewrite_block): Remove stmt is rewrite_stmt returns 1. + (assign_vars): Remove abort and enable overlapping live ranges. + (replace_variable): New. Replace SSA name with the partition variable. + (rewrite_out_of_ssa): Use replace_variable(). + (dump_tree_ssa_stats): Remove old UNSSA code. + (rewrite_stmt): Return 1 if stmt should be deleted. Remove old + UNSSA code. + +2003-06-03 Diego Novillo + + * gimplify.c (simplify_call_expr): Move code to mark MD builtins + non-simplifiable... + * tree-simple.c (is_simple_call_expr): ... here. + +2003-06-03 Diego Novillo + + * c-parse.in: Fix botched merge. + +2003-06-03 Diego Novillo + + * tree-mudflap.c (MARK_TREE_MUDFLAPPED, TREE_MUDFLAPPED): + Use TREE_VISITED instead of TREE_BOUNDED. + * c-mudflap.c (TREE_MUDFLAPPED): Likewise. + * tree-pretty-print.c (dump_generic_node): Remove + references to TYPE_QUAL_BOUNDED. + +2003-06-03 Jason Merrill + + * gimplify.c (simplify_cond_expr): Call truthvalue_conversion + before invert_truthvalue. + +2003-06-02 Daniel Berlin + + * tree-dfa.c (compute_may_aliases): Call delete_alias_vars whenever we + call create_alias_vars. + + * tree-alias-common (ptr_may_alias_var): Cleanup determination of + global vars and whatnot. + +2003-06-02 Diego Novillo + + * Makefile.in (tree-ssa.o, tree-cfg.o): Add dependency on cfgloop.h + (tree-optimize.o): Remove dependency on cfgloop.h. + * basic-block.h (struct basic_block_def): Fix documentation for + field 'loop_father'. + * tree-dfa.c (add_referenced_var): Fix type of element + pushed into aliased_objects_alias_set. + * tree-optimize.c: Don't include cfgloop.h + (optimize_function_tree): Move code to initialize loop optimizer... + * tree-cfg.c (build_tree_cfg): ... here. + * tree-ssa.c: Include cfgloop.h. + (loops): New file local variable. + (rewrite_into_ssa): Initialize/finalize loop optimizer. + (rewrite_stmt): Call var_is_live when processing redundant + assignments to the same LHS. + (var_is_live): Add heuristic to discover overlapping definitions in + loops that do not have PHI nodes for VAR at the loop header. + +2003-06-02 Jason Merrill + + * gimplify.c (simplify_expr): Only allow a cast from a 'val'. + * tree-simple.c (is_simple_cast): Likewise. + +2003-06-02 Andrew MacLeod + + * tree-cfg.c (bsi_insert_before): Update end of block pointer if we + inserted before the last stmt in a block. (The container changed). + * tree-ssa.c (elim_backward): Inserting copy should be within + conditional check. + (elim_create): Only select one bit instead of the all. + +2003-06-01 Jason Merrill + + * Makefile.in: Remove lots of -Wno-error targets. + + * tree-simple.c (recalculate_side_effects): Check TREE_THIS_VOLATILE. + + * gimplify.c (simplify_compound_lval): Call + recalculate_side_effects on each of the subexpressions. + + * expr.c (expand_expr) : Use the if-statement code if + it's void. + +2003-06-01 Daniel Berlin + + * tree-alias-common.c: Remove setting of DECL_CONTEXT in temp vars, + it's done in create_tmp_alias_var for us. + (ptr_may_alias_var): Check if the variables are memory tags, and get + the associated pointers if they are. + +2003-05-30 Frank Ch. Eigler + + * tree-mudflap.c (mudflap_c_function, enqueue_constant, enqueue_decl): + Rework dumping logic. + +2003-05-27 Jason Merrill + + * tree-ssa.c (avail_expr_hash): Simplify by using iterative_hash_expr + in more places. + * tree.c (iterative_hash_expr): Handle SSA_NAME. + +2003-05-29 Jeff Law + + * tree-ssa.c (rewrite_stmt): Detect and remove redundant + memory loads. + (avail_expr_hash): Use iterative_hash_expr, not iterative_hash_object + as needed. + +2003-05-27 Jason Merrill + + * gimplify.c (shortcut_cond_expr): Avoid jumps to jumps. + +2003-05-26 Jason Merrill + + * c-simplify.c (simplify_switch_stmt): A SWITCH_EXPR also gets the + source location of its first line. + +2003-05-24 Diego Novillo + + Do not consider INDIRECT_REF nodes to be variables. + + * gimplify.c (create_tmp_alias_var): Allow temporaries of + ARRAY_TYPE to be created. + Create new temporaries with function scope. + Don't call build_type_variant. + Mark the temporary volatile if its type is volatile. + + * tree-dfa.c: Change every function that received a variable and + its base symbol to just receive the variable. Update all callers. + (struct alias_set_d): Remove field 'tag_sym'. + Add documentation for fields. + (struct walk_state): Add field 'is_indirect_ref'. + Add documentation for fields. + (opf_ignore_bp): Remove. Update all users. + (aliased_objects_base): Remove. Update all users. + (get_stmt_operands): If the statement had virtual operands, do not + scan them again. + (get_expr_operands): Handle INDIRECT_REF nodes by adding an operand + for the memory tag represented and a use for the base pointer. + Don't add VUSE operands for pointer arguments to functions. + Force a virtual operand when processing ADDR_EXPR nodes. + (add_stmt_operand): If the variable is an alias tag, always add it + as a virtual operand. + Remove code to handle INDIRECT_REF nodes. + Move code to determine if a pointer may point to global memory to + find_vars_r. + Set has_volatile_ops flag in the statement when adding operands for + globals and local statics. + If the variable is an alias tag, mark the statement as making + aliased loads or stores. + (set_def): Mark the variable as having real references. + (add_use): Likewise. + (add_vdef): Remove code to re-add previous virtual operands. + If PREV_VOPS is set, don't add a new virtual operand. + (add_vuse): Likewise. + (dump_variable): Show annotation bitfields 'mem_tag', + 'occurs_in_abnormal_phi', 'is_alias_tag' and 'is_stored'. + (compute_may_aliases): Initialize walk_state.is_indirect_ref to 0. + (compute_alias_sets): Don't remove alias sets with exactly one + entry. + (register_alias_set): Re-implement to support memory tags instead + of INDIRECT_REF nodes. Document algorithm. + (find_alias_for): Likewise. + (may_alias_p): Likewise. + (add_may_alias): Likewise. + (find_vars_r): If a pointer assignment is found and the RHS of the + assignment may access global memory, mark the pointer as pointing + to global memory. + Handle INDIRECT_REF nodes by marking the base pointer as + dereferenced. + Do not share INDIRECT_REF nodes. + (add_referenced_var): Don't handle INDIRECT_REF nodes. + If called from a store operation, mark the variable as stored. + By default mark the variable as not having real references. + When processing a pointer that has been dereferenced, create a + memory tag for the pointer. + (add_indirect_ref_var): Remove. Update all callers. + (get_virtual_var): Don't handle INDIRECT_REF nodes. + (find_hidden_use_vars_r): + + * tree-flow-inline.h (get_var_ann): New function. Change all + functions that called var_ann and create_var_ann to call + get_var_ann. + (get_stmt_ann): Likewise. + (set_indirect_ref): Remove. Update all callers. + (indirect_ref): Remove. Update all callers. + (create_indirect_ref): Remove. Update all callers. + + * tree-flow.h (struct var_ann_d): Remove fields 'is_loaded', + 'unused' and 'indirect_ref'. + Add fields 'mem_tag', 'is_mem_tag', 'is_alias_tag' and + 'has_real_refs'. + (get_var_ann, get_stmt_ann): Declare. + (create_indirect_ref, set_indirect_ref, indirect_ref): Remove. + + * tree-pretty-print.c (dump_generic_node): Don't handle + INDIRECT_REF nodes inside SSA_NAME nodes. + + * tree-simple.c (get_base_symbol): Don't handle INDIRECT_REF nodes. + (is_simple_unary_expr): Don't call STRIP_NOPS. + + * tree-ssa-copyprop.c (get_original): Don't handle INDIRECT_REF + nodes. Allow pointers to be copy propagated. + + * tree-ssa-dce.c (need_to_preserve_store): Don't handle + INDIRECT_REF nodes. + + * tree-ssa-live.c (create_ssa_var_map): Only process variables that + have real references. + + * tree-ssa.c: Update documentation regarding INDIRECT_REF nodes. + (update_indirect_ref_vuses): Remove. Update all users. + (update_pointer_vuses): Remove. Update all users. + (MAY_COPYPROP_P): Remove. Update all users. + (create_temp): Don't handle INDIRECT_REF nodes. + (coalesce_ssa_name): Ignore variables that have no real references. + (rewrite_stmt): Mark the statement modified if a new copy or + constant was propagated into it. + Don't special-case pointers. + (rewrite_operand): Don't handle INDIRECT_REF nodes. + * tree.h (SSA_VAR_P): Remove. Update all users. + (SSA_DECL_P): Rename to SSA_VAR_P. + +2003-05-22 Jeff Law + + * gimplify.c (simplify_expr): Avoid gimplifying expressions which + are already in gimple form. + * tree-simple.c (is_simple_constructor): No longer treat TREE_STATIC + constructors specially. + (is_simple_addr_expr_arg): If we're taking the address of a label + for the first time, then the ADDR_EXPR is not in gimple form. + +2003-05-22 Jason Merrill + + * tree-cfg.c (compute_reachable_eh): Don't skip cleanups. + + * tree-dfa.c (add_referenced_var): Read-only INDIRECT_REFs can + also be clobbered by function calls. + +2003-05-22 Jeff Law + + * expr.c (convert_move): Avoid making silly copies. + (expand_expr, case BIND_EXPR): Correctly determine when the + result of the BIND_EXPR will not be used. + +2003-05-21 Jason Merrill + + * tree-cfg.c (compute_reachable_eh): Handle multiple CATCH_EXPRs. + + * builtins.c (simplify_builtin_next_arg): Split out from... + (expand_builtin_next_arg): ...here. + (simplify_builtin_va_start): Split out from... + (expand_builtin_va_start): ...here. + (simplify_builtin): Call it. + * gimplify.c (simplify_call_expr): If simplify_builtin worked, + just return. + +2003-05-20 Jason Merrill + + * gimplify.c (shortcut_cond_expr, shortcut_cond_r): Rewrite. + (simplify_cond_expr): Also invert ifs with no 'then'. + (build_and_jump): New fn, split out from... + (gimplify_exit_expr): ...here. Don't bother gimplifying the + condition. + + * gimplify.c (simplify_save_expr): Add post-effects to the + postqueue. + + * gimplify.c (mostly_copy_tree_r): Don't unshare constants. + +2003-05-20 Jeff Law + + * expr.c (expand_expr, case COND_EXPR): Avoid useless RTL generation + when the THEN or ELSE arm is empty. + + * tree-cfg.c (make_loop_expr_blocks): Do not accept next_block_link + as an argument, make it a local variable. Callers changed. + + * tree-cfg.c (remove_useless_stmts_and_empty_vars): Eliminate + GOTO_EXPRs which jump to the next statement occuring in an + outer control/block structure nest. + +2003-05-20 Diego Novillo + + * tree-ssa-ccp.c (set_rhs): Fix typo in handling of + RETURN_EXPR nodes. + +2003-05-19 Daniel Berlin + + * tree-alias-common.c (alias_get_name): Handle unnamed variables once + and for all. + +2003-05-19 Jeff Law + + * tree-ssa-dce.c (remove_conditional): If the conditional's block + has no post dominator in the CFG, then wire it to the exit node. + Avoid unnecessary check of bb->succ. + +2003-05-17 Daniel Berlin + + * tree-pretty-print.c (MASK_POINTER): Parameter is P, not node. + +2003-05-17 Daniel Berlin + + * tree-alias-common.c (get_alias_var): Handle REFERENCE_EXPR. + (find_func_aliases): Ditto. + (get_alias_var): Use POINTER_TYPE_P. + +2003-05-16 Frank Ch. Eigler + + * gcc.c (cc1_options): Correct "-fmudflapth" handling. + * tree-mudflap.c (mudflap_c_function, mf_build_check_statement_for): + Use locally cached mask/shift values only in single-threaded mode. + +2003-05-16 Daniel Berlin + + * tree-alias-common.c (ptr_may_alias_var): Fix DECL_CONTEXT + checking. + +2003-05-16 Andrew MacLeod + + * tree-flow.h (ssa_make_edge): Remove prototype. + * tree-ssa-dce.c (remove_dead_stmt): Change comment about removing + conditionals. + (remove_conditional): Don't update PHI nodes or call ssa_make_edge. + * tree-ssa.c (ssa_make_edge): Remove. + +2003-05-16 Jeff Law + + * tree-cfg.c (remove_useless_stmts_and_vars): Handle case where + both arms of an if-then-else simply jump to the same location. + + * tree-ssa-ccp.c (get_rhs): Correctly handle MODIFY_EXPR embedded in + a RETURN_EXPR. + (set_rhs): Likewise. + +2003-05-15 John David Anglin + + * Makefile.in (regmove.o-warn): Change to -Wno-error. + +2003-05-15 Andrew MacLeod + + * tree-cfg.c (enum find_location_action): Enum for find_insert_location. + (bsi_insert_before): Handle insert at start of a BB and update pointers + from parents if appropriate. + (find_insert_location): Handle COND_EXPR properly. Return + an enum type indicating what action to take on the returned value. + (bsi_commit_first_edge_insert): Use new returned action. + +2003-05-15 Jeff Law + + * tree-cfg.c (make_edges): Factor out loop invariants from + code to insert edges from the TRY to the FINALLY block. + Avoid creating unnecessary edges from the end of the + FINALLY block back to the start of the FINALLY block. + +2003-05-15 Diego Novillo + + * tree-ssa.c (rewrite_out_of_ssa): Undo previous patch. + +2003-05-15 Diego Novillo + + * tree-ssa.c (rewrite_out_of_ssa): Don't dump the optimized + function after the SSA->normal pass. + +2003-05-14 Toon Moene + + * Makefile.in: Add additional -Wno-error targets for Alpha. + +2003-05-13 Jason Merrill + + * gdbinit.in (pgs, pge): New macros. + + Implement expression temporary optimization. + * gimplify.c (gimplify_ctx): Add temp_htab field. + (push_gimplify_context): Initialize it. + (pop_gimplify_context): Destroy it. + (simplify_expr): If there's no internal postqueue, generate an + expression temporary. + (gimple_tree_hash, gimple_tree_eq): New fns. + (create_tmp_from_val, lookup_tmp_var): New fns. + (get_formal_tmp_var): New fn. + (internal_get_tmp_var): New fn. + (get_initialized_tmp_var): Use it. + * tree-simple.h: Declare it. + + * gimplify.c (simplify_cond_expr): Reorganize. + (shortcut_cond_expr, shortcut_cond_r): New fns. + (build_and_jump): New fn. + (gimplify_exit_expr): Use it. + + * gimplify.c (simplify_expr): Do better at stripping unnecessary + NOPs. Tidy GOTO_EXPR handling. Don't allow NON_LVALUE_EXPR. + * tree-simple.c (is_simple_modify_expr): Don't allow NON_LVALUE_EXPR. + (is_simple_binary_expr, is_simple_condexpr): Likewise. + (is_simple_unary_expr, is_simple_compound_lval): Likewise. + (is_simple_id): Likewise. + + * tree-ssa.c (rewrite_stmt): Discard redundant assignments. + (avail_expr_eq): Don't test ops1 == ops2. + (avail_expr_hash): Use iterative_hash_object. + +2003-05-13 Jeff Law + + * tree-cfg.c (cleanup_tree_cfg): Update comments. Set repeat + anytime we remove a control structure. + + * tree-flow.h (struct var_ann_d): New field occurs_in_abnormal_phi. + * tree-ssa.c (MAY_COPYPROP_P): Do not allow copy propagations + if either argument occurs in an abnormal phi. + * tree-dfa.c (add_phi_arg): Set occurs_in_abrnomal_phi as needed. + * tree-ssa-copyprop.c (copyprop_stmt): Do not allow copy + propagations if either argument occurs in an abnormal phi. + (copyprop_phi): Likewise. + +2003-05-12 Diego Novillo + + * c-common.h (STATEMENT_CODE_P): Use size_t cast instead + of int. + (INIT_STATEMENT_CODES): Change type of local variable i to + size_t. + +2003-05-12 Diego Novillo + + * c-pretty-print.c (dump_c_node): Call CONSTRUCTOR_ELTS + to access the operand of a CONSTRUCTOR node. + * tree-pretty-print.c (dump_generic_node): Likewise. + +2003-05-11 Diego Novillo + + * c-simplify.c (simplify_if_stmt): Replace calls to + warning_with_file_and_line with warning. + +2003-05-12 Frank Ch. Eigler + + * toplev.c (lang_independent_options): Add "-fmudflapth". + * flags.h (flag_mudflap): Document meaning of >1 value. + * gcc.c (MFWRAP_SPEC, MFLIB_SPEC): Add -fmudflapth support. + (cpp_unique_options, cc1_options): Ditto. + +2003-05-10 Sebastian Pop + + * gimplify.c (simplify_expr): Replace CONST_DECL with its DECL_INITIAL. + +2003-05-09 Sebastian Pop + + * tree-optimize.c (optimize_function_tree): Clarify the use of the + loop analyzer. + +2003-05-09 Jeff Law + + * c-simplify.c (simplify_cleanup): Remove code which optimizes + TRY_FINALLY and TRY_CATCH. It doesn't trigger. + + * tree-cfg.c (remove_useless_stmts_and_vars): Optimize away + TRY_CATCH and TRY_FINALLY blocks when possible. + +2003-05-09 Diego Novillo + + * tree-pretty-print.c (dump_generic_node): CONSTRUCTOR + nodes have only one operand now. + +2003-05-08 Andrew MacLeod + + * tree-cfg.c (pdom_info): New file level static. + (cleanup_tree_cfg): Free dominance info, if it was used. + (bsi_replace): New. Replace a stmt with a new one. + (linearize_cond_expr): Use post dominator info to determine is a + conditional can be safely removed. + (find_insert_location): New. Determine where to insert a new stmt that + is placed on a split edge. + (bsi_commit_first_edge_insert): Use find_insert_location to determine + where to link a stmt when splitting an edge. + (merge_tree_blocks): When deleting a basic block, remove it from the + dominance structure if it exists. + * tree-dfa.c (add_stmt_operand): Don't rename local statics. Treat + them just like globals. + * tree-flow.h (struct var_ann_d): Add root_var_processed bit and + root_index fields. + * tree-ssa-dce.c (process_worklist): Mark conditions feeding PHI's as + necessary as well. + (remove_dead_phis): Add missing debug information. + * tree-ssa-live.c (var_union): Handle combining partitions when one + has a root_variable as a representative. + (compact_var_map): Add comments and use flags. + (init_root_var): Use new root_var fields in struct var_ann_d. + (dump_root_var): Send output to specified file, not stderr. + (dump_var_map): Remove dump_flag parameter & some grotesque debug info. + * tree-ssa-live.h (VAR_ANN_ROOT_INDEX): Define. + (VARMAP_NORMAL, VARMAP_NO_SINGLE_DEFS): Define flags for compact_var_map. + (var_to_partition_to_var): Return NULL if not in a partition. + (find_root_var): Use VAR_ANN_ROOT_INDEX. + * tree-ssa.c (insert_copy_on_edge): Add listing info. + (coalesce_ssa_name): Coalesce live-on-entry variables to their root. + Coalesce partitions across abnormal edges. + (assign_vars): Remove redundant initialization code. Handle root_vars + which have already been coalesced to a partition. + (rewrite_out_of_ssa): Add debug info & remove PHI nodes when processed. + (rewrite_stmt): Don't redefine redundant expressions. + +2003-05-08 Jeff Law + + * c-simplify.c (simplify_expr_stmt): Make sure to + simplify the body of the EXPR_STMT. + + * tree-dfa.c (remove_decl): Accept new argument for the block + to start the search. + * tree-flow.h (remove_decl): Update prototype. + * tree-cfg.c (remove_stmt): Pass the toplevel block to + remove_decl. + + * tree-dfa.c (find_hidden_use_vars): No longer returns a value. + Callers and prototype updated. No longer need to look for + nested functions, instead just mark any variables and + parameters with DECL_NONLOCAL set as having hidden uses. + +2003-05-08 Diego Novillo + + * version.c (version_string): Change format to show daily + datestamp and merged date. + +2003-05-07 Jeff Law + + * tree-cfg.c (remove_useless_stmts_and_vars): Do not remove + the toplevel BIND_EXPR for an inlined function. + + * tree-dfa.c (find_hidden_use_vars): Look at the size of + VAR_DECLs, not the size of ARRAY_TYPES. Also make sure + to reset *inside_vla to its original value when done + processing any particular VAR_DECL. + +2003-05-06 Diego Novillo + + * c-simplify.c (simplify_if_stmt): Warn if + -Wunreachable-code is given and the conditional is always + true or always false. + + * expr.c (expand_expr): Don't try to expand FUNCTION_DECL + nodes when processing BIND_EXPR_VARS. + + * varasm.c (output_constant_def_contents): Re-use the + label when emitting a label for mudflap. + + Disable the following patch: + + 2003-04-30 Steven Bosscher + + * ggc-page.c (TREE_EXP_SIZE): Define. + (extra_order_size_table): New entry for expr trees with + two operands. + +2003-05-06 Jeff Law + + * tree-cfg.c (make_exit_edges): Fix handling of blocks which + end with calls. + + * tree-cfg.c (remove_useless_stmts_and_vars): Remove GOTO_EXPRs + to the immediately following tree node. + + * tree-cfg.c (make_goto_expr_edges): Fix typo in comment. + (remove_useless_stmts_and_vars): New function. + * tree-flow.h (remove_useless_stmts_and_vars): Prototype. + * tree-ssa.c (rewrite_out_of_ssa): After returning to normal + form, call remove_useless_stmts_and_vars. + +2003-05-02 Daniel Berlin + + * tree-alias-common.c (alias_get_name): Given unnamed result decls + a name. + (create_fun_alias_var): Use DECL_RESULT if available. + +2003-05-02 Jeff Law + + * tree-inline.c (expand_call_inline): Avoid creating naked + _DECL nodes for inlined functions which had NRV optimizations + applied. + +2003-05-02 Diego Novillo + + * tree-cfg.c (build_tree_cfg): Update comment. + (make_blocks): Don't skip over empty statements. + Move exception handling code ... + (compute_reachable_eh): ... here. + (set_parent_stmt): Don't skip over empty statements. + (bsi_remove): Don't return early on empty statements. + Don't call STRIP_NOPS. + (remove_stmt): Don't call STRIP_NOPS. + Always compute the block holding the statement. + After replacing the statement with an empty statement, add the + empty statement to the block. + (successor_block): Don't call STRIP_NOPS. + (first_exec_stmt): Likewise. + (first_exec_block): Don't return early for empty statements. + (first_stmt): Don't test for NULL blocks. + Reformat to improve legibility. + (bsi_next_in_bb): Don't call STRIP_NOPS. + Reformat to improve legibility. + (set_bb_for_stmt): Don't ignore empty statements. + + * tree-dfa.c (get_stmt_operands): Don't call STRIP_NOPS. + (create_stmt_ann): Don't abort on emtpy statements. + Don't call STRIP_NOPS. + (copy_stmt): Remove unused function. + * tree-flow.h (copy_stmt): Remove prototype. + + * tree-flow-inline.h: Don't call STRIP_NOPS. + Remove local variable 't'. + (bsi_stmt): Don't return NULL_TREE for empty statements. + Ignore error_mark_node. + + * tree-iterator.h (tsi_next): Don't call STRIP_NOPS. + (tsi_stmt_ptr): Likewise. + (tsi_stmt): Likewise. + Don't return NULL_TREE for empty statements. + + * tree-pretty-print.c (dump_generic_node): Don't ignore empty + statements. + + * tree-ssa-ccp.c (fold_stmt): Don't call STRIP_NOPS. + * tree-ssa-dce.c (find_useful_stmts): Likewise. + (remove_dead_stmt): Likewise. + * tree-ssa.c (mark_def_sites): Likewise. + (rewrite_out_of_ssa): Likewise. + (rewrite_stmt): Likewise. + + * tree.c (make_ssa_name): Don't ignore empty statements. + (body_is_empty): Fix comment. + +2003-05-01 Jeff Law + + * tree-dfa.c (find_hidden_use_vars): Renamed from find_vla_decls. + Now returns a value indicating if nested function was found. + When nested functions are found, mark suitable variables as + having hidden uses. + (find_hidden_use_vars_r): Renamed from find_vla_decls_r. + (compute_may_alias): Corresponding changes. Handle + multiple BLOCKs at the toplevel of a function. + +2003-04-30 Diego Novillo + + * tree.c (build_empty_stmt): New function. + * tree.h (IS_EMPTY_STMT): Define. + (TI_EMPTY_STMT): Remove. + (empty_stmt_node): Remove. + Replace 'X = empty_stmt_node' with 'X = build_empty_stmt ()', + and 'X == empty_stmt_node' with 'IS_EMPTY_STMT (X)' everywhere. + (build_empty_stmt): Declare. + + * cp/cp-simplify.c (cp_simplify_stmt): Use IS_EMPTY_STMT. + + * java/java-tree.h (build_java_empty_stmt): Declare. + * java/expr.c (build_java_empty_stmt): New function. + * java/decl.c (java_init_decl_processing): Don't build empty_stmt_node. + Replace 'X = empty_stmt_node' with 'X = build_java_empty_stmt ()', + and 'X == empty_stmt_node' with 'IS_EMPTY_STMT (X)' everwhere. + +2003-04-30 Jeff Law + + * tree-dfa.c (get_expr_operands): Do not ignore operands of an + an ADDR_EXPR if it is a PARM_DECL or VAR_DECL. + + * tree-dfa.c (get_expr_operands): Look inside operands in + a TREE_LIST. + +2003-04-29 Diego Novillo + + * builtins.def (BUILTIN_CONSTANT_P): Mark as constant. + + * tree-dfa.c (get_expr_operands): Do not add VDEF operands for + dereferenced pointers at call sites. + * tree-ssa.c (assign_vars): Abort if we couldn't coalesce all the + versions together. + +2003-04-29 Andrew MacLeod + + * tree-cfg.c (bsi_start): If there are no stmts in a block, use the + context pointer to represent the basic block. + (bsi_insert_after): Handle inserting into empty blocks better. + (bsi_insert_before): Call bsi_insert_after to handle empty blocks. + * tree-ssa.c (elim_create): Clear bitmap after its been processed + instead of during loop. + +2003-04-27 Diego Novillo + + * Makefile.in (tree-mudflap.o): Add dependency on $(TREE_DUMP_H). + * c-decl.c (c_expand_body_1): Don't call simplify_function_tree + after mudflap_c_function. + Move mudflap instrumentation after SSA optimizers. + * tree-dump.c (dump_files): Add entry for -fdump-tree-mudflap. + * tree.h (enum tree_dump_index): Add TDI_mudflap. + * doc/invoke.texi: Document -fdump-tree-mudflap. + * tree-mudflap.c: Include tree-dump.h. + (dump_file): New local variable. + (dump_flags): New local variable. + (mudflap_c_function): Call dump_begin, dump_end and dump_function. + (mf_decl_cache_locals): Set DECL_CONTEXT for __mf_lookup_shift_l + and __mf_lookup_mask_l to current_function_decl. + (mf_offset_expr_of_array_ref): Likewise for __mf_index_X. + (mf_build_check_statement_for): Re-implement to emit a proper + STMT_EXPR. + (mx_xfn_indirect_ref): Emit detailed debugging info if + -fdump-tree-mudflap-details is given. + (mudflap_enqueue_decl): Likewise + * tree-optimize.c (optimize_function_tree): Don't check for + -fmudflap. + +2003-04-26 Diego Novillo + + * c-simplify.c (build_bc_goto): If the target label couldn't be + found, emit an error message. + +2003-04-25 Andrew MacLeod + + * tree-ssa-live.c (compact_var_map): Add parameter to exclude variables + with a single SSA version. + (init_root_var): Allow that a var_map might not be compacted yet. + * tree-ssa-live.h (compact_var_map): Change Prototype. + * tree-ssa.c (rewrite_out_of_ssa): When coalescing, don't include single + reference variables during the compaction. + +2003-04-25 Jeff Law + + * tree-optimize.c (optimize_function_tree): Simplify slightly. + +2003-04-25 Andrew MacLeod + + * tree-ssa.c (struct _elim_graph): Change type of fields + 'pred' and 'succ' to be bitmaps instead of sbitmaps. + Update all uses. + +2003-04-25 Diego Novillo + + * tree-cfg.c (linearize_cond_expr): Reformat. + * tree-dfa.c (get_expr_operands): Check for read-only + status the dereferenced argument pointer, not the pointer + itself. + (add_stmt_operand): Always consider global variables as + virtual operands. + +2003-04-24 Jason Merrill + + * gimplify.c (simplify_cond_expr): Avoid redundant gimplification. + + Add TREE_VEC of case labels to the SWITCH_EXPR during gimplification. + * tree.def (CASE_LABEL_EXPR): Add an operand for the LABEL_DECL. + * tree.h (SWITCH_LABELS, CASE_LABEL): New macros. + * c-simplify.c (c_simplify_stmt) : Create LABEL_DECL here. + * expr.c (expand_expr) : Not here. + * gimplify.c (gimplify_ctx): Add case_labels field. + (gimplify_switch_expr, gimple_add_case_label): New fns. + (simplify_expr): Use them. + +2003-04-24 Andrew MacLeod + + * tree-flow.h (processed_out_of_ssa): Rename to out_of_ssa_tag. + * tree-ssa-live.c (register_ssa_partition): Add variable to partition. + (change_partition_var): Use out_of_ssa_tag. + (create_ssa_var_map): Add all uses, defs and PHI elements to partition. + (new_tree_live_info): Create a live range info structure. + (delete_tree_live_info): Free storage. + (live_worklist): Fill in the live range info for a variable for the + blocks between the def and all the blocks containing uses. + (set_if_valid): Set partition bit if variable is in a partition. + (add_livein_if_notdef): Set live on entry bit for a var's partition + if a definition has not been seen. + (calculate_live_on_entry): Create partition live on entry bitmaps for + all basic blocks . + (calculate_live_on_exit): Calculate live on exit information for each + basic block. + (init_root_var): Initialize and fill in a root_var structure. + (remove_root_var_partition): remove a partition from a root_var list. + (delete_root_var): Free storage. + (dump_root_var): Display root_var summary. + (dump_var_map): Show extra info for ssa name versions. + * tree-ssa-live.h (NO_PARTITION): Define. + (register_ssa_partition): Remove. + (partition_to_var): Use partition_find after decompressing. + (var_to_partition): Return NO_PARTITION if var is not in a partition. + (struct tree_live_info_d): Define live range info structure. + (partition_is_global): Return 1 if used outside a basic block. + (live_entry_blocks): Return bitmap over blocks that partition is live + on entry to. + (live_on_exit): Return bitmap of partitions live on exit from a block. + (struct root_var_d): Define a root_var structure. + (ROOT_VAR_NONE): Define. + (num_root_vars): Number of variables in root_var object. + (root_var): Return variable for a root_var index. + (first_root_var_partition): Return first partition for a root_var. + (next_root_var_partition): Get next partition for a root_var. + (find_root_var): Find root_var index for a specific partition. + * tree-ssa.c (eliminate_extraneous_phis): Remove. + (set_if_valid): Set partition bit if variable is in a partition. + (add_conflicts_if_valid): Add conflict between variable and all + related partitions set in a bitvector. + (coalesce_ssa_name): Create a conflict graph and coalesce all + partitions which don't conflict and are related by the same root_var. + (assign_vars): Use a root_var object, and assign different real + variables to all partitions. + (rewrite_out_of_ssa): Call compact_var_map() once, and don't call + eliminate_extraneous_phis. + +2003-04-23 Daniel Berlin + + * tree-flow.h (create_global_var): Add prototype. + + * tree-dfa.c (create_global_var): Externalize. + + * tree-alias-common.c: Set DECL_CONTEXT on our temp alias vars. + (call_may_clobber): Make a copy of this function, since our version + will be slightly different soon. + (create_alias_vars): We need global_var, so create it if necessary. + +2003-04-23 Daniel Berlin + + * tree-ssa-pre.c (do_proper_save): Remove old code, since the new + insertion code works okay. + (pre_expression): Use new_rename_1, it removes a *lot* of useless + saves. + +2003-04-23 Jeff Law + + * gimplify.c (simplify_target_expr): Make sure to simplify + the cleanup too. + + * tree-ssa.c (struct def_blocks_d): Add new field phi_insertion_points. + (compute_global_livein): Accept varray rather than bitmaps. Callers + updated. Rewrite to compute global life information for all the + objects in the varray in parallel. + (insert_phis_for_deferred_variables): New function. + (insert_phi_nodes_for): New argument DEF_MAPs. When an object + crosses the threshold for using fully pruned PHI insertions, + push it on the def_maps varray for deferred processing. + (insert_phi_nodes): Initialize def_maps. Pass it to + insert_phi_nodes_for. Drain the def_maps varray as it grows. + Also drain any residual objects in def_maps. Zero def_maps + when complete. + +2003-04-21 Jeff Law + + * tree-cfg.c (find_contained_blocks_and_edge_targets): New function. + (try_finallys): New varray used during edge creation. + (make_edges): Initialize try_finallys varray. After creating + all the "normal" edges, go back and create the special edges + for the try-finally blocks. + (make_ctrl_stmt_edges): Create edges for the EH nodes. Also + make sure to build the try-finally stack. + (make_exit_edges): Create edges from calls which may throw + to any directly reachable exception handlers. + (is_ctrl_altering_stmt): Statements which may throw alter + flow control. + + * tree-cfg.c: Include except.h. + (eh_stack): New file-scoped varray. + (build_tree_cfg): Initialize eh_stack. + (make_catch_expr_blocks): New function. + (make_try_expr_blocks, make_eh_filter_expr_blocks): Likewise. + (make_blocks): Call new functions as needed. When ending a block + due to a statement that may throw, compute the reachable exception + handlers and store it in the statement's annotation. + (is_ctrl_stmt): Handle EH nodes. + (stmt_ends_bb_p): Likewise. + * tree-flow.h (stmt_ann_d): Add new field reachable_exception_handlers. + + * except.c (check_handled): No longer static. + * except.h (check_handled): Prototype. + + * c-simplify.c (c_build_bind_expr): Revert change from earlier today. + + * c-common.h (find_reachable_label): Prototype. + * c-semantics.c (find_reachable_label): No longer static. + * c-simplify.c (c_build_bind_expr): Avoid creating unnecessary + BIND_EXPRs. + (simplify_cleanup): Avoid creating unnecessary TRY_CATCH_EXPRs + or TRY_FINALLY_EXPRs. + (simplify_if_stmt): If the condition is constant and the + unexecuted arm has no reachable code, then just emit + the executed arm. + +2003-04-18 Sebastian Pop + + * cfghooks.h, cfghooks.c: New files. + * Makefile.in (BASIC_BLOCK_H): Depends on cfghooks.h. + (OBJS): Add cfghooks.o. + (tree-optimize.o): Depends on cfgloop.h. + (cfghooks.o): New rule. + * basic-block.h (split_edge): Rename to rtl_split_edge. + (tree_split_edge): Declare. + (create_bb): Declare extern here. + (verify_flow_info): Rename to rtl_verify_flow_info. + (tree_verify_flow_info): Declare. + (cfghooks.h): Included here. + * cfgloop.c (tree.h, tree-flow.h): Included. + (make_forwarder_block): Renamed to rtl_make_forwarder_block. + (tree_make_forwarder_block): New static function. + (blocks_headers): Declared static. + (HEADER_BLOCK): Use blocks_headers instead of bb's .aux field. + (redirect_edge_with_latch_update, make_forwarder_block, + canonicalize_loop_headers): Don't allocate .aux, but makes grow + the blocks_headers array. + (canonicalize_loop_headers): Register tree_make_forwarder_block + into the tree_cfg_hooks and rtl_make_forwarder_block into the + rtl_cfg_hooks structure. + (canonicalize_loop_headers): Initialize/free the blocks_headers + array rather than the bb's .aux field. + * cfgloopmanip.c (loop_split_edge_with_NULL): New static function. + (remove_path, force_single_succ_latches): + Call loop_split_edge_with_NULL instead of loop_split_edge_with. + * cfgrtl.c (split_block): Update the comment. + (split_edge): Renamed rtl_split_edge. + (verify_flow_info): Renamed rtl_verify_flow_info. + * loop-init.c (loop_optimizer_init, loop_optimizer_finalize): + Execute code following the value of cfg_level. + * toplev.c (rest_of_compilation): Call rtl_register_cfg_hooks. + * tree-cfg.c (create_bb): Declared extern. + (build_tree_cfg): Call tree_register_cfg_hooks. + (make_edges, make_exit_edges): Remove the use of EDGE_FALLTHRU. + (bsi_commit_first_edge_insert): Use split_edge. + (tree_split_edge, tree_verify_flow_info): New functions. + * tree-optimize.c (cfgloop.h): Included. + (optimize_function_tree): Add #if 0'ed calls to + loop_optimizer_init and loop_optimizer_finalize. + +2003-04-16 Jeff Law + + * Makefile.in (tree-ssa.o): Depend on langhooks.h. + (tree-dfa.o, tree-cfg.o): Likewise. + * tree-cfg.c: Include langhooks.h + (dump_tree_cfg): Revamp how we get the current function's name + to not rely on current_function_name (and implicitly cfun). + (dump_cfg_stats, tree_cfg2dot): Likewise. + * tree-dfa.c: Include langhooks.h + (dump_immediate_uses): Revamp how we get the current function's name + to not rely on current_function_name (and implicitly cfun). + (dump_dfa_stats, dump_alias_info): Likewise. + * tree-ssa.c: Include langhooks.h + (dump_tree_ssa): Revamp how we get the current function's name + to not rely on current_function_name (and implicitly cfun). + + * tree-cfg.c (make_loop_expr_blocks): When determining the value for + NEXT_BLOCK_LINK, correctly handle empty statement nodes at the + end of the tree. + (make_cond_expr_blocks, make_switch_expr_blocks): Likewise. + (make_bind_expr_blocks): Likewise. + + * gimplify.c (keep_function_tree_in_gimple_form): Move check of + flag_disable_simple here. Include flags.h. + * Makefile.in (gimplify.o): Depends on flags.h + * c-decl.c (c_expand_body_1): No longer check flag_disable_simple. + * tree-inline.c (copy_body_r): Avoid creating non-gimple code + when inlining a function where the RESULT_DECL's initialization + is not on the RETURN_EXPR. + +2003-04-15 Jeff Law + + * tree-flow.h (struct var_ann_d): Renamed is_vla_decl field to + has_hidden_use. + (has_hidden_use, set_has_hidden_use): Renamed from is_vla_decl + and set_vla_decl. + * tree-flow-inline.h (has_hidden_use): Renamed from is_vla_decl. + Updated to use "has_hidden_use" instead of "is_vla_decl" field. + (set_has_hidden_use): Renamed from set_vla_decl. + Updated to use "has_hidden_use" instead of "is_vla_decl" field. + * tree-dfa.c (dump_variable): Corresponding changes. + (find_vla_decls_r): Likewise. + * c-simplify.c (simplify_decl_stmt): Likewise. + * tree-ssa-dce.c: Likewise. + +2003-04-09 Jeff Law + + * tree-dfa.c (struct alias_set_d, field tag_sym_set): Remove + unused field. + (register_alias_set): Rework to avoid incorrect coalescing of + entries. Fix memory leak. No longer set field tag_sym_set. + (get_expr_operands): ADDR_EXPR expressions may have interesting + operands in some cases. + +2003-04-09 Diego Novillo + + * gimplify.c (simplify_expr): Handle VECTOR_CST nodes. + * tree-cfg.c (make_blocks): Ignore empty statement containers. + Create a basic block before processing containers that only have + empty statements. + (make_loop_expr_blocks): Use the container instead of the statement + when setting NEXT_BLOCK_LINK. + (make_cond_expr_blocks): Likewise. + (make_switch_expr_blocks): Likewise. + (make_bind_expr_blocks): Likewise. + (successor_block): If the last statement of the block is the empty + statement, use its container to get NEXT_BLOCK_LINK. + (stmt_starts_bb_p): Return false if the statement is NULL. + * tree-pretty-print.c (dump_generic_node): Handle VECTOR_CST nodes. + * tree-simple.c (is_simple_const): Accept VECTOR_CST as constants. + * objc/objc-lang.c (LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P): + Define. + +2003-04-06 Diego Novillo + + * tree-cfg.c (remove_bb): Call ssa_remove_edge. + (cleanup_cond_expr_graph): Likewise. + (cleanup_switch_expr_graph): Likewise. + (disconnect_unreachable_case_labels): Likewise. + (merge_tree_blocks): Likewise. + Update PHI nodes at BB2's successor. + (dump_tree_bb): Show PHI nodes in the block. + * tree-dfa.c (add_phi_arg): Update comment. + (remove_phi_arg_num): New function. + (remove_phi_arg): Call it. + Move from tree-ssa.c. + (remove_phi_node): Move from tree-ssa.c. + * tree-flow.h (ssa_make_edge): Declare. + (ssa_remove_edge): Declare. + * tree-pretty-print.c (dump_generic_node): Show block where PHI + arguments are coming from. + * tree-ssa-dce.c (pdom_info): New local variable. + (remove_dead_stmts): Initialize it and free it at the end. + (remove_conditional): New function. + (remove_dead_stmt): Call it. + * tree-ssa.c (eliminate_phi): If the edge index is -1, abort + compilation. + (ssa_remove_edge): New function. + (ssa_make_edge): New function. + +2003-04-06 Andrew MacLeod + + * tree-cfg.c (push_bsi): New. Push a block_stmt_iterator onto a stack. + (pop_bsi): New. Pop a block_stmt_iterator off a stack. + * tree-flow-inline.h (struct bsi_list_d): Block iterator stack struct. + (new_bsi_list): Start a new bsi stack. + (empty_bsi_stack): Is stack empty. + (FOR_EACH_BSI_IN_REVERSE): Macro for processing bsi's in reverse. + (FOR_EACH_STMT_IN_REVERSE): Macro for processing stmt's in reverse. + +2003-04-06 Andreas Jaeger + + * treelang/treetree.c (tree_code_create_function_initial): Replace + calls to non-existent function annotate_with_file_line_column with + calls to annotate_with_file_line. + (tree_code_create_variable): Likewise. + +2003-04-05 Diego Novillo + + * tree-dfa.c (get_expr_operands): Do not clobber readonly operands + in CALL_EXPRs. + (find_vars_r): Likewise. + (add_indirect_ref_var): When creating new INDIRECT_REF variables, + copy the readonly attribute from the variable's type. + +2003-04-05 Diego Novillo + + * tree.c (copy_node): Never copy tree annotations. + +2003-04-05 Diego Novillo + + * tree-ssa-ccp.c (visit_cond_stmt): Don't short circuit evaluation + of UNDEFINED conditional expressions. + +2003-04-04 Andrew MacLeod + + * Makefile.in : Add tree-ssa-live.c and tree-ssa-live.h files. + * tree-ssa.c (struct _var_map, create_var_map, delete_var_map, + var_from_partition, get_var_partition, mapped_var_from_ref, + compact_var_map, dump_tree_partition, set_partition_for_var, + set_var_mapping, create_var_partition): Remove. + (create_temp): Allow temps to be created from SSA_NAME vars as well. + (eliminate_name, eliminate_build, elim_backward, elim_create, + eliminate_phi): Use new var map interface. + (coalesce_ssa_name): New. Coalesce ssa_name ranges together. + (assign_vars): Assign real variables to ssa_name partitions. + (rewrite_out_of_ssa): Use new varmap partition and routines. + * tree-ssa-live.h: New file + (var_map): Structure for variable map. + (num_var_partitions): Number of partitions. + (partition_to_var): Return variable for partition. + (var_to_partition): Return partition variable is in. + (var_to_partition_to_var): Return variable representing partition + another variable is in. + (register_ssa_partition): Initialize a partition element as used. + * tree-ssa-live.c: New file. + (init_var_map): Initialize a var_map. + (delete_var_map): Free storage for a var_map. + (var_union): Combine 2 partitions. + (compact_var_map): Reduce the number of partitions in a var_map. + (change_partition_var): Assign a specific var to a partition. + (create_ssa_var_map): Initialize a var_map with referenced variables. + (dump_var_map): Debug output for a var_map. + +2003-04-03 Diego Novillo + + * fold-const.c (fold_relational_hi_lo): Add missing comparison when + folding comparisons to signed_max+1. + +2003-04-02 Jason Merrill + Diego Novillo + + * tree-inline.c (initialize_inlined_parameters): Cast argument + types appropriately when emitting initialization assignments. + +2003-04-01 Andrew MacLeod + + * tree-cfg.c (PENDING_STMT, SET_PENDING_STMT): New Macros. + (bsi_insert_on_edge): Rename to bsi_commit_first_edge_insert. Add an + empty annotation record to the new basic_block. + (bsi_commit_edge_inserts): New. Commit all pending edge inserts. + (bsi_insert_on_edge): New. Add stmt to edge's pending insert list. + * tree-flow-inline.h (phi_arg_from_edge): Return PHI index for an edge. + (phi_element_for_edge): Return PHI element for an edge. + * tree-flow.h (struct var_ann_d): Add auxiallary field and new + bit 'processed_out_of_ssa'. + * tree-ssa.c (_var_map): Structure for variable parition map. + (struct _elim_graph): Elimination graph for out-of-ssa pass. + (create_var_map): Create a new var_map. + (delete_var_map): Delete a var_map. + (var_from_parition): Return var for a specified partition. + (get_var_partition): Return partition a var belongs to. + (mapped_var_from_ref): Get root var for a var's partition. + (compact_var_map): Re-map the partitions to make the list dense. + (dump_var_parition): Print var_map. + (set_partition_for_var): Associate a real var with a partition. + (set_var_mapping): Associate an SSA version var with a real var. + (create_var_partition): Create a partition for processing. + (create_temp): Create a new temp variable for a partition. + (insert_copy_on_edge): Insert a copy between variables on an edge. + (new_elim_graph): Create a new elimination graph. + (clear_elim_graph): clear an elimination graph. + (delete_elim_graph): Delete an elimination graph. + (eliminate_name, eliminate_build, elim_forward, + elim_unvisited_predecessor, elim_backward, elim_create, + eliminate_phi): Routines to implement Morgans PHI elimination algorithm. + (eliminate_extraneous_phis): Eliminate PHI nodes which will never + generate code. + (rewrite_out_of_ssa): Use partitions and PHI elimination algorithm. + +2003-04-01 Jeff Law + + * tree-cfg.c (make_blocks): Make sure the BIND_EXPR's subgraph + actually ended in a statement before seeing of the statement should + end a basic block. + + * tree-cfg.c (dump_tree_cfg): Avoid crashing when cfun is NULL. + (tree_cfg2dot): Likewise. + * tree-dfa.c (dump_immediate_uses): Likewise. + * tree-pretty-print.c (dump_generic_node): Dump the EH_FILTER_FAILURE + nodes attached to an EH_FILTER_EXPR. + + * tree-dfa.c (get_stmt_operands): Add cases for TRY_FINALLY_EXPR, + TRY_CATCH_EXPR, CATCH_EXPR and EH_FILTER_EXPR. + (get_expr_operands): Add case for EXC_PTR_EXPR. + + * tree-dfa.c (compute_may_aliases): Accept FNDECL as an argument. + Use FNDECL instead of relying on CURRENT_FUNCTION_DECL. + * tree-flow.h (compute_may_aliases): Update prototype. + * tree-ssa.c (rewrite_into_ssa): Corresponding changes. + + * tree-inline.c (expand_calls_inline): Correctly handle EH_FILTER_EXPR. + +2003-03-31 Diego Novillo + + * Makefile.in (STRICT_WARN, STRICT2_WARN): Remove -Wtraditional. + * timevar.def (TV_TREE_CLEANUP_CFG): Define. + * tree-cfg.c (set_parent_stmt): Add documentation. + (replace_stmt): New function. + (merge_tree_blocks): New function. + (remap_stmts): New function. + (linearize_cond_expr): New function. + (linearize_control_structures): New function. + (cleanup_tree_cfg): Call it. + Use new timevar TV_TREE_CLEANUP_CFG. + (remove_bb): Update debugging message. + Make sure that bb->head_tree_p and bb->end_tree_p exist before + resetting their basic blocks. + (remove_stmt): When removing a control flow expression, update + basic block flags. + (cleanup_control_flow): Make sure that the block contains + statements. + (last_stmt): Reformat for readability. + (last_stmt_ptr): Return NULL if the block has no statements. + * tree-flow-inline.h (parent_block): Check that the block is not + empty. + * tree-flow.h (bb_empty_p): Remove. + * tree-inline.c (copy_tree_r): Do not copy empty_stmt_node. + * tree-ssa-dce.c (tree_ssa_dce): Call cleanup_tree_cfg. + * tree.c (body_is_empty): New function. + * tree.h (body_is_empty): Declare. + +2003-03-31 Jeff Law + + * tree-ssa-ccp.c (simulate_block): Add abnormal edges out of a + block to the edge worklist after simulating a block for the + first time. If the block has a single outgoing normal edge, + add that edge to the worklist after simulating the block for + the first time. + +2003-03-31 Frank Ch. Eigler + + * gcc.c (MFLIB_SPEC): Remove -ld. + (MFWRAP_SPEC): Remove dlopen wrapping. + +2003-03-28 Diego Novillo + + * tree-ssa.c (rewrite_block): Add new argument 'eq_expr_value'. + Update all users. + If 'eq_expr_value' is given, use it to register a new + value for the variable given on the LHS. + If the block ends in a conditional expression of the form 'X == Y', + propagate 'X = Y' into the THEN_CLAUSE. + (MAY_COPYPROP_P): Define. + (rewrite_stmt): Call it. + (register_new_def): Fix comment. + (get_eq_expr_value): New function. + +2003-03-28 Diego Novillo + + * basic-block.h (BB_COMPOUND_ENTRY): Remove. Update all users + everywhere. + * tree-cfg.c: Minor fixes to various comments. + * tree-optimize.c (optimize_function_tree): Dump optimized function + after SSA->normal conversion. + +2003-03-26 Daniel Berlin + + * tree-ssa-pre.c: Implement open64 renaming algorithm. + (subst_phis): New function. + (generate_expr_as_of_bb): Ditto. + (new_rename_1): Ditto. + (process_delayed_rename): Ditto. + (do_proper_save): Use bsi_* functions for insertion, don't remove + old code quite yet, haven't fully tested. + Also add argument that says whether to insert before use or after use. + (defs_y_dom_x): Factor through injuries properly. + (defs_match_p): Ditto. + (phi_opnd_from_res): Attempt to fix, and remove useless argument. + (reset_can_be_avail): Fix broken condition that would cause infinite + loop. + (update_old_new): #if 0 updating of bb heads. + (finalize_1): We occasionally get 5 + a rather than a + 5, so we + need to make sure 5 is a DECL before trying to get a reaching def. + (repair_use_injury): If we couldn't find a reaching def, we don't need + to repair it. + (assign_new_class): Only push to stack2 if it exists (so we can + share this function in both rename implementations). + (create_ephi_node): Add argument that says whether to add ephi + to block or not (we create them sometimes for validation only). + (tree_perform_ssapre): Skip expressions without any uses. + + * tree.h: Add EREF_DELAYED_RENAME. + (struct tree_eref_common): Add delayed_rename bit. + +2003-03-25 Diego Novillo + + * tree-simple.c: Use tree codes to document grammar for relational + operators &&, || and ^. + +2003-03-25 Diego Novillo + + * cfg.c (dump_edge_info): Add labels for EDGE_TRUE_VALUE, + EDGE_FALSE_VALUE and EDGE_EXECUTABLE. + * tree-cfg.c (dump_tree_bb): Change formatting. Show all + statements in the block. + * tree-simple.c: Update documentation for GIMPLE conditional + expressions. + +2003-03-24 Diego Novillo + + * tree-dfa.c (get_expr_operands): If there are no call clobbered + variables, don't create a VDEF for GLOBAL_VAR at clobbering + CALL_EXPRS. + * tree-flow.h (fold_stmt): Declare. + * tree-ssa-ccp.c (fold_stmt): Change to extern declaration. + * tree-ssa.c (rewrite_stmt): Call it. + +2003-03-22 Diego Novillo + + * Makefile.in (gtype-desc.o): Add dependency on $(TREE_FLOW_H). + + * tree-dfa.c (struct alias_set_d): Add field 'num_elements'. + (struct walk_state): Move declaration earlier in the file. + (create_global_var): New local function. + (num_referenced_vars, num_aliased_objects): Change type to + 'size_t'. Update all users. + (aliased_objects, aliased_objects_base, aliased_objects_aliase_set): + Mark for garbage collection. + (num_call_clobbered_vars, call_clobbered_vars): New global + variable. + (get_expr_operands): For CALL_EXPRs, add a VUSE or VDEF reference + for every pointer argument. If the call may clobber, add a VDEF, + otherwise add a VUSE. + If the call may clobber, add VDEF for GLOBAL_VAR. + (dump_variable): Show whether the variable is call clobbered. + (dump_dfa_stats): Show call clobbered variables. + (compute_may_aliases): Minor formatting changes. + (compute_alias_sets): If the function makes clobbering calls, add + GLOBAL_VAR as an alias to every call-clobbered variable. + Remove alias sets that have exactly one element. + (register_alias_set): Set 'num_elements' to zero for every newly + created alias set. + (find_alias_for): Don't make a second call to add_may_alias to make + alias tags alias themselves. It's redundant. + Increment 'num_elements' when adding a new alias to an alias set. + (may_alias_p): Don't handle GLOBAL_VAR. + Check for structure aliasing when either PTR or VAR are a + structure. Don't do it only when both are structures. + (dump_alias_info): Show all aliases of each variable. + (find_vars_r): When processing a CALL_EXPR node, set + walk_state->is_store if the function may clobber and create a + reference to GLOBAL_VAR. + (add_indirect_ref_var): Change type of second argument from 'void *' + to 'struct walk_state *'. Update all users. + (add_referenced_var): Likewise. If a potentially aliased variabe + is not declared 'const', add it to the list of call clobbered + variables. + + * tree-flow.h (struct var_ann_d): Add field 'is_call_clobbered'. + Change type of field 'uid' to size_t. Update all users. + (stmt_ann_d): Add field 'makes_clobbering_call'. + (next_tree_ref_id): Remove unused variable. + (call_clobbered_vars): Declare. + (num_call_clobbered_vars): Declare. + (call_clobbered_var): New inline function. + + * tree-ssa-ccp.c (visit_phi_node): If the LHS of a PHI node is + volatile, mark the PHI node VARYING without checking its arguments. + (visit_assignment): Likewise. + (set_value): Remove. Update all users. + (likely_value): If the statement makes aliased loads or has + volatile operands, consider it VARYING. + (get_default_value): If a variable is volatile, consider it + VARYING. + + * tree-ssa.c (init_tree_ssa): Initialize num_call_clobbered_vars + and call_clobbered_vars. + Do not create GLOBAL_VAR. Set it to NULL_TREE. + Increase initial size for various hash tables. + (delete_tree_ssa): Reset num_call_clobbered_vars and + call_clobbered_vars. + (get_reaching_def): Rename from currdef_for. Update all users. + Always create default definitions for variables that need them. + Callers that use to call currdef_for with the second argument set + to false now call get_value_for. + (htab_statistics): New function. + (dump_tree_ssa): Call it. + (avail_expr_eq): Also compare VUSE operands. + +2003-03-21 Jeff Law + + * tree-dfa.c: Revert vla changes from yesterday. + (find_vla_decls_r): Do not look inside TYPE_DECLs. + +2003-03-20 Jeff Law + + * gimplify.c (simplify_return_expr): Tighten condition for + converting the RHS of a MODIFY_EXPR in a RETURN_EXPR to a + simple_val. Allow returning a RESULT_DECL directly. + * tree-dfa.c (get_expr_operands): A RESULT_DECL can have + interesting operands. + (clobber_vars_r): Handle RESULT_DECLs. + (compute_may_aliases): Initialize and free vla_htab. + (find_vla_decls): Pass vla_htab to walk_tree. + (find_vla_decls_r): Likewise. + * tree.h (SSA_DECL_P): Accept RESULT_DECLs. + +2003-03-19 Jeff Law + + * gimplify.c (simplify_return_expr): Only allow simple values + on the RHS of a MODIFY_EXPR appearing in a RETURN_EXPR. + * tree-cfg.c (make_exit_edges): We no longer need to look for + CALL_EXPRs on the RHS of a MODIFY_EXPR inside RETURN_EXPRs. + +2003-03-18 Andrew Macleod + + * tree-cfg.c (make_blocks): Use append_stmt_to_bb. Check for NULL + tsi_stmt when deciding whether to start a new block. + (add_stmt_to_bb): Don't update the basic block end pointer. + (append_stmt_to_bb): New. Add stmt and update the BB end pointer. + (first_stmt): Use only 1 return. + (last_stmt): Modified to use bsi_last(). + (last_stmt_ptr): Modified to use bsi_last(). + (bsi_last): New. Return an iterator to the last stmt in a block. + (bsi_from_tsi): Fix bug which wouldn't set the context properly when + within a nested BIND_EXPR. + (bsi_update_from_tsi): Insert helper which is more efficient than + bsi_from_tsi(). + (bsi_link_after): link in a new stmt and update the basic block + data structures. + (bsi_insert_after): Insert a new stmt into a block. + (bsi_insert_before): Insert a new stmt into a block. + (bsi_insert_on_edge): Insert a new stmt on an edge. + * tree-flow-inline.h (is_label_stmt): Return true if stmt can be a + target of a control transfer. + * tree-flow.h (is_label_stmt, bsi_last): New prototypes. + +2003-03-12 Jeff Law + + * c-simplify.c (simplify_switch_stmt): Save the type of the original + condition in TREE_TYPE (SWITCH_EXPR (...)). Annotate the SWITCH_EXPR + with file/line information. + * expr.c (expand_expr, case SWITCH_EXPR): Use expand_end_case_type. + * tree.def (SWITCH_EXPR): Document meaning of TREE_TYPE field of + the SWITCH_EXPR. + + * c-simplify.c (simplify_block): Set the current line number to + the line associated with the end of the block. + + * c-decl.c (finish_function): No longer save/restore the + current filename or linenumber around simplification. Instead + save/restore it around inlining. + (c_expand_body_1): Save/restore current filename and linenumber + around expansion of trees into RTL. + * gimplify.c (simplify_function_tree): Make the current file/line + number match the non-gimple code at the end of a function. + + * tree-cfg.c: Include toplev.h. + (remove_bb): Warn about unreachable code. + + * cfgrtl.c (verify_flow_info): Ignore EDGE_EXECUTABLE, it's for + the CCP optimizer only. + + * ssa.c (convert_to_ssa): Use last_basic_block, not n_basic_blocks. + +2003-03-11 Jeff Law + + * builtins.c: Fix minor comment typo. + (expand_builtin_strcmp, expand_builtin_strncmp): Remove. + (expand_builtin_strcat, expand_builtin_strncat): Likewise. + (expand_builtin_strspn, expand_builtin_strcspn): Likewise. + (expand_builtin_strcopy, expand_builtin_strstr): Likewise. + (expand_builtin_strpbrk, expand_builtin_strchr): Likewise. + (expand_builtin_strrchr, expand_builtin_fputs): Likewise. + (simplify_builtin_memcmp, simplify_builtin_strcmp): New functions. + (simplify_builtin_strpbrk, simplify_builtin_strstr): Likewise + (simplify_builtin_strchr, simplify_builtin_strrchr): Likewise + (simplify_builtin_strcpy, simplify_builtin_strncpy): Likewise + (simplify_builtin_strncmp, simplify_builtin_strcat): Likewise + (simplify_builtin_strncat, simplify_builtin_strspn): Likewise + (simplify_builtin_strcspn, simplify_builtin_fputs): Likewise + (expand_builtin_memcmp): Use simplify_builtin_memcmp. + (simplify_builtin): New function + (expand_builtin): Use simpify_builtin to collapse several common + cases together. + * gimplify.c (simplify_call_expr): Accept new argument. All + callers updated. Call simplify_builtin to try and simplify builtin + function calls before we simplify their arguments. + * tree.h (simplify_builtin): Prototype. + +2003-03-11 Jeff Law + + * timevar.def (TV_TREE_SSA_TO_NORMAL): New timevar. + * tree-cfg.c (remove_stmt): Also remove special annotations + on RHS of MODIFY_EXPR statements. + * tree-dfa.c (create_stmt_ann): Update comments. Fix formatting. + (compute_may_aliases): Make sure timevar encloses entire routine. + * tree-ssa.c (rewrite_out_of_ssa): Enclose with a timevar. + (remove_annotations_r): Avoid walking into subtrees of anything + except container nodes. Remove the special annotation on the + RHS of MODIFY_EXPRs. + +2003-03-10 Frank Ch. Eigler + + * tree-mudflap.c (mx_xfn_indirect_ref): Allow unfolded "& ptr->field" + constructs to pass uninstrumented. Remove TREE_ADDRESSABLE settings. + Keep array accesses to non-ADDRESSABLE objects uninstrumented. Update + __MF_TYPE_* constants for __mf_register calls. + +2003-03-10 Jeff Law + + * c-decl.c (c_expand_body_1): Update comments relating to + re-simplification after mudflap instrumentation. Avoid + unnecessary simplification of the function tree. + * gimplify.c (keep_function_tree_in_gimple_form): New function. + * tree-inline.c: Include tree-iterator.h and tree-simple.h + (struct inline_data): Add new TSI field. + (copy_body_r): Keep tree in gimple form when transforming a + RETURN_EXPR into a MODIFY_EXPR and GOTO_EXPR. + (initialize_inlined_parameters): Use MODIFY_EXPR, not INIT_EXPR + for initialization of inlined parameters. + (expand_call_inline): Save and restore the TSI around the + call to expand_calls_inline. Keep the tree in gimple form + when replacing a CALL_EXPR with a BIND_EXPR for the inlined + body. + (expand_calls_inline): Revamp to provide the current TSI to + expand_call_inline when we're working with gimple form. + * Makefile.in (tree-inline.o): Update dependencies. + * tree.h (keep_function_tree_in_gimple_form): Prototype. + +2003-03-10 Andrew MacLeod + + * Makefile.in (tree.o): Add tree-iterator.h dependancy. + * sbitmap.c (sbitmap_realloc): Grow a sbitmap structure. + * sbitmap.h (sbitmap_realloc): New Prototype. + * tree-cfg.c (remove_bb): Use new format for bsi_remove. + (bsi_remove): Update iterator to refer to the next stmt. + (bsi_prev): Implement previous stmt routine. + (bsi_from_tsi): Create a block iterator from a tree iterator. + * tree-flow-inline.h (bsi_prev): Remove. + (tsi_from_bsi): Create a tree iterator from a block iterator. + * tree-flow.h (bsi_prev,bsi_remove): Update prototypes. + (bsi_from_tsi, tsi_from_bsi, bsi_insert_*): New prototypes. + (bsi_iterator_update): New enum type. + * tree-iterator.h (tree_stmt_anchor, tsi_iterator_update): New type. + (tsi_link_before, tsi_link_after, tsi_delink, tsi_new_stmt_list, + tsi_stmt_list_head): New prototypes. + * tree-ssa-dce.c (remove_dead_stmts): Update removal loop to allow + that remove_dead_stmt update's the iterator. + (remove_dead_stmt): Use a pointer to the iterator since bsi_remove + requires it. + * tree.c (tsi_link_before): New function to link a stmt before an + iterator. + (tsi_link_after): New function links stmt after an iterator. + (tsi_delink): Removes a stmt from a list. + (tsi_new_stmt_list): New function to begin a new stmt list. + (tsi_stmt_list_head): New function to get the first stmt in a list. + +2003-03-07 Diego Novillo + + * tree-cfg.c (remove_stmt): Don't assume that the statement is in + SSA form. + + * tree-flow.h (dump_tree_ssa_stats): Declare. + (debug_tree_ssa_stats): Declare. + (stmt_ann_d): Add new statement flags 'makes_aliased_loads', + 'makes_aliased_stores', and 'has_volatile_ops'. + * tree-dfa.c (add_stmt_operand): Set new statement flags accordingly. + + * tree-pretty-print.c (dump_generic_node): Various cosmetic changes + to the rendering of some expressions. + + * tree-ssa.c (struct var_value_d): Rename from struct currdef_d. + Rename field 'currdef' to 'value'. Update all users. + (avail_exprs): New local hash table. + (const_and_copies): New local hash table. + (struct ssa_stats_d): Declare. + (ssa_stats): New local variable. + (rewrite_into_ssa): Deallocate avail_exprs and const_and_copies + after renaming. + Call dump_tree_ssa_stats() if -fdump-tree-ssa-stats is given. + (rewrite_block): Document the renaming process. + Add new local stack block_avail_exprs to keep track of expressions + made available in this block and its children. + (rewrite_stmts): Move body inside rewrite_block. + (dump_tree_ssa_stats): New function. + (debug_tree_ssa_stats): New function. + (get_def_blocks): New function. + (insert_phi_nodes_for): Call it. + (rewrite_stmt): Add support for keeping track of copies, constants + and globally redundant expressions. + (rewrite_operand): If a pointer has been copy propagated into + another one, rewrite INDIRECT_REF nodes of the original pointer to + refer to the new one. + (register_new_def): Add new argument 'var' indicating which + variable is this new definition for. Update all users. + (update_indirect_ref_vuses): New function. + (update_pointer_vuses): New function. + (init_tree_ssa): Set variable 'ssa_stats' to zero. + Allocate memory for 'avail_exprs' and 'const_and_copies'. + (currdef_for): Don't mark inline. + Call get_value_for and set_value_for. + (set_currdef_for): Remove. Update all users. + (var_value_hash): Rename from currdef_hash. Update all users. + (var_value_eq): Rename from currdef_eq. Update all users. + (get_value_for): New function. + (set_value_for): New function. + (lookup_avail_expr): New function. + (avail_expr_hash): New function. + (avail_expr_eq): New function. + (get_def_blocks_for): New function. + (var_is_live): New function. + +2003-03-06 Diego Novillo + + * tree-ssa-ccp.c (likely_value): Don't assume CONSTANT if the + statement has virtual uses. + +2003-03-05 Diego Novillo + + * tree-dfa.c (opf_none, opf_is_def, opf_force_vop, opf_ignore_bp): + New flags to alter the behavior of add_stmt_operand. + (get_expr_operands): Change operand IS_DEF with FLAGS. Update all + users. + When adding a VUSE for pointer dereferences in function arguments, + don't add a superfluous VUSE for the base pointer. + (add_stmt_operand): Remove operands IS_DEF and FORCE_VOP. Add + operand FLAGS. Update all users. + +2003-03-05 Jason Merrill + + * c-pretty-print.c (do_niy): Only print operands of expressions. + * tree-pretty-print.c: Likewise. + + * c-simplify.c (simplify_decl_stmt): Only simplify DECL_SIZE_UNIT. + * gimplify.c (simplify_array_ref_to_plus): New fn. + (simplify_array_ref): Use it. + (build_addr_expr_with_type): Split out from build_addr_expr. + (simplify_compound_lval): Break out an ARRAY_REF with non-constant + element size. + +2003-03-05 Frank Ch. Eigler + + * gcc.c (MFWRAP_SPEC): Remove most --wrap entries. + +2003-03-03 Daniel Berlin + + * tree-ssa-pre.c (is_strred_cand): Temporarily disable strength + reduction while working on bootstrapping. + (requires_edge_placement): Reenable for now, until an insertion + infrastructure exists that can handle critical edges. + (count_stmts_in_bb): New function, used for verifying we do + insertions properly. + (update_old_new): Fix up bb heads as well. + (do_proper_save): Handle single statement bb properly. + Handle BB's contained in BIND_EXPRS. + (code_motion): Count number of statements in bb before and after + to make sure we don't screw up boundaries. + (finalize_1): Ditto. + (rename_2): Fix subtle rename bug. + (phi_opnd_from_res): Do this the right way, by cloning the + occurrence and modifying it, as every other PRE implementation + does. + (tree_perform_ssapre): Handle comparisons too (unary exprs + currently disabled till load PRE is reimplemented). + (reset_can_be_avail): Fix can_be_avail test. + +2003-03-01 Diego Novillo + + * doc/invoke.texi: Fix typo. + +2003-02-28 Aldy Hernandez + Diego Novillo + + * Makefile.in (OBJS): Add tree-ssa-copyprop.o. + (tree-ssa-copyprop.o): New rule. + (tree-ssa-ccp.o): Add dependency on $(TREE_SIMPLE_H). + + * timevar.def (TV_TREE_COPYPROP): New timevar. + * flags.h (flag_tree_copyprop): Declare. + * toplev.c (flag_tree_copyprop): Define. + (f_options): Add -ftree-copyprop. + * tree.h (tree_dump_index): Add TDI_copyprop. + * tree-dump.c (dump_files): Add entry for -fdump-tree-copyprop. + * doc/invoke.texi: Document -ftree-copyprop and -fdump-tree-copyprop. + + * tree-ssa-copyprop.c: New file. + * tree-flow.h (tree_ssa_copyprop): Declare. + * tree-optimize.c (optimize_function_tree): Call it. + * tree-dfa.c (add_vuse): Make extern. Update all users. + + * tree-ssa.c (mark_def_sites): VUSEs are stored in a varray of trees. + +2003-02-28 Frank Ch. Eigler + + * tree-mudflap.c (mudflap_enqueue_decl): Ignore extern artificial + variable declarations. + +2003-02-27 Diego Novillo + + * tree-dfa.c (get_stmt_operands): INIT_EXPR nodes cannot + appear in GIMPLE form. Don't handle them. + (get_expr_operands): Likewise. + (find_vars_r): Likewise. + * tree-ssa-ccp.c (get_rhs): Likewise. + (set_rhs): Likewise. + * tree-ssa-pre.c (tree_perform_ssapre): Likewise. + +2003-02-27 Diego Novillo + + * tree-ssa-ccp.c (ccp_fold): Fold builtins by replacing and + restoring their arguments. + +2003-02-27 Jeff Law + + * tree-dfa.c (find_vars_r): Clear *walk_subtrees appropriately + to avoid useless walking of subtrees. + + * fold-const.c (nondestructive_fold_binary_to_constant): Renamed + from nondestructive_fold_binary. Update comments slightly. + (nondestructive_fold_unary_to_constant): Similarly. + (fold_relational_hi_lo): Corresponding changes. + * tree-ssa-ccp.c (ccp_fold): Corresponding changes. + * tree.h: Corresponding changes. + +2003-02-26 Jeff Law + + * tree-ssa-ccp.c (ccp_fold): Also handle folding of calls to + builtin functions. + + * fold-const.c (nondestructive_fold_binary): Handle truth ops + when both arguments are constant (duh!). Handle CONJ_EXPR. + +2003-02-26 Daniel Berlin + + * flags.h: Remove flag_ip. + * toplev.c: Ditto. + * tree-alias-ander.c: s/flag_ip/flag_unit_at_a_time/g. + (andersen_cleanup): Set region to null when done. + (andersen_function_call): Check DECL_PTA_TYPEVAR, not + DECL_SAVED_TREE. + * tree-alias-common.c: s/SSA_DECL_P/DECL_P/g. + (get_alias_var_decl): Remove dead code, fix bug in what is a + local alias var. + (find_func_aliases): Use get_alias_var, not create_fun_alias_var. + (create_fun_alias_var): Fix to use DECL_PTA_TYPEVAR. + Use get_alias_var rather than create_alias_var. + (create_fun_alias_var_ptf): Ditto. + (create_alias_vars): Ditto. + * tree-dfa.c (compute_may_aliases): Fix check for + create_alias_vars. + Move deletion of alias vars back to here, from tree-ssa.c + * tree-ssa.c (delete_tree_ssa): Remove delete_alias_vars call. + +2003-02-25 Jeff Law + Diego Novillo + + * tree-ssa-ccp.c (likely_value): If the statement has no + use operands, then return CONSTANT. + + * fold-const.c (nondestructive_fold_binary): Handle TRUTH_AND_EXPR + and TRUTH_OR_EXPR. Placeholder for TRUTH_XOR_EXPR. + * tree-ssa-ccp.c (ccp_fold): Handle TRUTH_{AND,OR,XOR}_EXPR. + (def_to_undefined): Re-enable VARYING->UNDEFINED state transition + sanity check. + + * tree-ssa-ccp.c (likely_value): Renamed from may_fold_p. Now + returns a latticevalue indicating the likely value for the + the RHS of the statement. + (evaluate_stmt): Update to use likely_value instead of may_fold_p. + Statements with UNDEFINED operands produce an UNDEFINED result. + (set_lattice_value): Reenable VARYING->CONSTANT sanity check. + +2003-02-25 Andrew MacLeod + + * tree-cfg.c (bsi_init): Handle BIND_EXPR nodes inside a basic block. + (bsi_next_in_bb): Likewise. + +2003-02-25 Diego Novillo + + * tree-cfg.c (parent_array): Remove. Update all users. + (struct cfg_stats_d): Add field 'num_failed_bind_expr_merges'. + (NEXT_BLOCK_LINK): Define. + (build_tree_cfg): Call alloc_aux_for_blocks instead of + create_block_annotations. + (make_blocks): Rewrite to support basic blocks that can span whole + BIND_EXPR bodies and put control statements at the end of blocks. + Add arguments 'next_block_link' and 'bb'. Replace 'parent_block' + with 'parent_stmt'. Update all users. + (make_loop_expr_blocks): Replace argument 'parent_block' with 'entry'. + Add argument 'next_block_link'. Update all users. + Don't create an empty latch block. + (make_cond_expr_blocks): Add argument 'next_block_link'. Update + all users. + (make_switch_expr_blocks): Likewise. + (make_bind_expr_blocks): Replace 'parent_block' with 'parent_stmt'. + Add argument 'next_block_link' and 'entry'. + Don't create a new block for the BIND_EXPR node. Extend the + existing block. + (add_stmt_to_bb): New function. + (create_bb): Remove argument 'parent_block'. Update all users. + (create_block_annotations): Remove. Update all users. + (make_edges): Don't handle BIND_EXPR nodes. + (make_ctrl_stmt_edges): Don't create an extra edge to the body of + the switch. + (make_loop_expr_edges): Only create an edge to the body of the + loop. + (remove_unreachable_block): Add more documentation for the special + case where a control statement entry is unreachable but its body + isn't. + Remove the basic block annotation from the head and end containers + in the block. + (disconnect_unreachable_case_labels): Don't keep the edge that goes + to the BIND_EXPR at the start of the switch body. + (dump_tree_bb): Call is_latch_block_for. + (dump_cfg_stats): Show stats about basic blocks that could not span + beyond the end of a BIND_EXPR body. + (successor_block): Use NEXT_BLOCK_LINK if the block is the last + inside a control structure. + (is_ctrl_stmt): Update documentation. + (stmt_starts_bb_p): Add new argument 'prev_t'. Update all users. + Only labels may start a new basic block. + (stmt_ends_bb_p): Add LOOP_EXPR, TRY_FINALLY_EXPR and + TRY_CATCH_EXPR to the list. + (latch_block): Remove. + (is_latch_block_for): New function. + (set_bb_for_stmt): Reformat some code. + + * tree-flow-inline.h (set_parent_block): Remove. Update all users. + (parent_stmt): New function. + (parent_block): Call it. + + * tree-flow.h (struct stmt_ann_d): Add field 'parent_stmt'. + (struct bb_ann_d): Remove block parent_block. + + * tree-pretty-print.c (dump_generic_node): Don't handle empty latch + nodes. + + * tree-ssa-ccp.c (def_to_undefined): Temporarily disable check for + VARYING->UNDEFINED transitions. + (set_lattice_value): Likewise for VARYING->CONSTANT transitions. + + * tree-ssa-dce.c (mark_necessary): Use parent_stmt() to traverse + all the control statements that contain the current + statement. + (makr_control_parent_necessary): Remove. Update all users. + (stmt_useful_p): Add BIND_EXPR to the list of useful + statements. + (process_worklist): Check that the statement is + associated to a basic block. + (remove_dead_stmt): Don't assume that the block has a + postdominator. + +2002-02-20 Daniel Berlin + + * tree-alias-ander.c: Store cached ptsets in the typevar, not + a seperate hash table. + (ptset_map): Removed; + (ptset_map_eq): Ditto. + (ptset_map_hash): Ditto. + (andersen_init): Remove ptset_map. + (andersen_cleanup): Ditto. + (andersen_add_var): Ditto. + (andersen_add_var_asm): Ditto. + (andersen_may_alias): Ditto. + * tree-alias-common.c: Store typevars for DECL nodes in the tree_decl + structure. + (get_alias_var_decl): Use DECL_PTA_TYPEVAR for DECL's. + (create_alias_var): Ditto. + (find_func_aliases): CONST functions don't affect aliasing either. + (ptr_may_alias_var): Don't call get_base_symbol. + Remove decl_function_context, use DECL_CONTEXT instead. + For DECL's, use DECL_PTA_TYPEVAR. + * tree-alias-type.c (struct alias_typevar_aterm): Add ptset member. + (ALIAS_TVAR_PTSET): New macro. + * tree.h (DECL_PTA_TYPEVAR): New macro. + (struct tree_decl): Add typevar member. + +2003-02-20 Jeff Law + + * c-simplify.c (simplify_decl_stmt): Call set_vla_decl on the + temporary holding the size and unit size for a VLA. Minor + formatting fixes. + + * ssa.c: Revert caching of immediate dominators change made on + Jan 28, 2003. + + * tree-dfa.c: Fix comment. + +2003-02-20 Jeff Law + + * tree-cfg.c (remove_bb): Update PHI nodes as edges are removed. + (cleanup_cond_expr_graph): Likewise. + (cleanup_switch_expr_graph): Likewise. + (disconnect_unreachable_case_labels): Likewise. + + * tree-ssa-dce.c (mark_control_parent_necessary): Be much more + selective about what statements in the control parents are marked + as necessary. + + * tree-dfa.c (INDIRECT_REFs and ADDRESSABLE_VARs varrays): Replace + with a single ALIASED_OBJECTs set of varrays. + (dump_dfa_stats): Corresponding changes. + (compute_may_aliases, dump_alias_info): Likewise. + (compute_alias_sets): Likesise. Update comments. Register + alias sets for all potentially aliased objects which are stored. + Check each potentially aliased object with the registered alias + sets. + (register_alias_set): If DEREF aliases a single registered _DECL, + then replace the _DECL's entry with DEREF. + (find_alias_for): Update comments. Do not stop the search when + an alias is found. There may be multiple entries with conflicting + alias sets. + (struct walk_state): New structure for statement walker callbacks. + (find_vars_r): Add logic to track loads and stores of potentially + aliased objects separately. Various changes related to + using a single set of varrays for all aliased objects. + (add_referenced_var): Record in the var's annotation if the + var is read or written. Various changes related to using a + single set of varrays for all the aliased objects. + (add_stmt_operand): Only set may_point_to_global_mem for INDIRECT_REFs. + * tree-flow.h (struct var_ann_d): Add new fields indicating if + the var is loaded or stored. Explicitly note unused bitfield + entries. + +2003-02-19 Jeff Law + + * fold-const.c (fold_negate_const): New function. Broken out of + the generic fold code. + (fold_abs_const, fold_relational_const): Likewise. + (fold_relational_hi_lo): Likewise. + (nondestructive_fold_unary, nondestructive_fold_binary): Likewise. + (fold): Use fold_negate_const, fold_abs_const, fold_relational_const, + and fold_relational_hi_lo. + * tree.h (nondestructive_fold_unary): Declare. + (nondestructive_fold_binary): Declare. + * tree-ssa-ccp.c (ccp_fold): New function. + (add_control_edge): Fix trivial formatting bug. + (evaluate_stmt): Rework to use ccp_fold instead of copying + statements. + +2003-02-18 Jeff Law + + * tree-ssa-ccp.c (visit_assignment): For simple copies, copy the + lattice values. + (defs_to_undefined): Add missing abort. + (replace_uses_in): Do not do a replacement if it would create + non GIMPLE trees. + +2002-02-14 Jeff Law + + * tree-ssa-ccp.c (def_to_undefined): Improve sanity checking code + so that it can detect invalid VARYING->UNDEFINED transitions. + (set_lattice_value): Improve sanity checking code so that it + does not trip on valid VARYING->CONSTANT transitions. + + * tree-flow.h (struct stmt_ann_d): Add new field in_ccp_worklist. + * tree-ssa-ccp.c (simulate_stmt): Renamed from simulate_def_use_edges. + (add_var_to_ssa_edges_worklist): New function. Only add statements + to the ssa_edges worklist if they are not already on the worklist. + (def_to_undefined, def_to_varying, set_lattice_value) + (tree_ssa_ccp): Only reevaluate the statement if in_ccp_worklist + is set for the element popped off the ssa_edges worklist. + (simulate_statement): Simplify now that ssa_edges is a worklist + of statements to reevaluate rather than a worklist of defs + that need their immediate uses reevaluated. + (visit_stmt): Clear in_ccp_worklist. + + * tree-ssa-ccp.c (def_to_undefined): Directly store the new + lattice values rather than call set_value. + (def_to_varying): Likewise. + (set_lattice_value): Likewise. + + * tree-ssa-ccp.c (def_to_undefined): Add some state transition + sanity checking. Avoid calling set_value if nothing changed. + (def_to_varying): Avoid calling set_value if nothing changed. + (set_lattice_value): Add some state transition sanity checking + for transitions into the CONSTANT state. If the object's + "constant" value has changed to a new constant value, then the + object has a VARYING value. + + * tree-ssa-ccp.c (tree_ssa_ccp): Work through the entire + ssa_edges worklist each iteration through the main loop. + +2002-02-13 Jeff Law + + * tree-ssa-ccp.c: Fix comment formatting glitches. + + * tree-ssa-ccp.c (may_fold_p): New function. Returns nonzero if + the given statement may fold after replacement of operands with + constants. + (evaluate_stmt): Only create a copy of the statement if there is + a reasonable chance the statement will fold. + +2002-02-13 Diego Novillo + + * Makefile.in (OBJS): Add tree-ssa-pre.o. + +2003-02-13 Daniel Berlin + + * tree-dfa.c (create_stmt_ann): Do stmt part of common annotation. + * tree-flow-inline.h (tree_stmt): Return statement tree is part of. + * tree-flow.h (struct bb_ann_d): Add ephi_nodes. + * tree-optimize.c (optimize_tree): Activate SSAPRE again. + * tree-pretty-print.c (debug_generic_expr): New function. + (debug_generic_stmt): Ditto. + (dump_generic_node): Pretty print EUSE's, EREF's, and EPHI's. + + * tree-ssa-pre.c: Rewrite almost entirely. Now performs more + strength reduction, EPHI minimization, and keeps SSA up to date. + * tree.c (tree_size): Handle EUSE, EPHI, EREF nodes. + (tree_node_structure): Ditto. + (ephi_node_elt_check_failed): New function. + * tree.def: Add EUSE_NODE, ELEFT_NODE, EKILL_NODE, EPHI_NODE, + EEXIT_NODE. + * tree.h (EREF_NODE_CHECK): New. + (EPHI_NODE_ELT_CHECK): New. + (struct tree_eref_common): New. + (struct tree_euse_node): New. + (struct tree_ephi_node): New. + (union tree_node): Add euse, eref, ephi members. + (enum tree_node_structure): Add TS_EPHI_NODE, TS_EUSE_NODE, + TS_EREF_NODE. + +2003-02-13 Daniel Berlin + Andreas Jaeger + + * tree-flow.h: Add some garbage collector marks. + +2003-02-12 Jeff Law + + * Makefile.in (ssa.o): Depends on $(TREE_H) and tree-flow.h + * ssa.c: Include tree.h and tree-flow.h. + (compute_dominance_frontiers_1): Use the sparse bitmap + of dominator children from the basic block's annotation + if it's available. Otherwise build the sparse bitmap + using the result of get_dominated_by. + * tree-ssa.c (rewrite_into_ssa): Reorder things slightly so + that we can use the cached dominator children computed + by mark_def_sites in compute_dominance_frontiers. + +2003-02-12 Andreas Jaeger + + * tree-dfa.c (dump_alias_info): Cast variable of size_t properly. + +2003-02-12 Daniel Berlin + + * tree-dfa.c (find_may_aliases_for): Remove + (compute_may_aliases): Always call compute_alias_sets. + +2003-02-10 Jeff Law + + * ssa.c (compute_dominance_frontiers_1): Use a sparse bitmap + for the frontiers. + (compute_dominance_frontiers): Corresponding changes. + (convert_to_ssa): Similarly. Convert the sparse bitmap to + a simple bitmap to avoid lots of collateral damage. + * ssa.h (compute_dominance_frontiers): Update prototype. + * tree-ssa.c (added, in_work): Kill, no longer needed. + (struct def_blocks_d): Add new bitmap (livein_blocks). + (rewrite_into_ssa): Make dominance frontiers be a sparse + bitmap instead of a simple bitmap. Rename the "nonlocals" + simple bitmap to "globals". Pass it into mark_def_sites. + (compute_global_livein): New function. + (mark_def_sites): Also keep track of variables which are + used before they are set. Allow caller to allocate and + pass in a simple bitmap for global variables. Process + items defined in the statement last. + (set_def_block): Also allocate bitmap for globals. + (set_livein_block): New function. + (def_blocks_free): Free def_blocks correctly. Also free + livein_blocks. + (debug_def_blocks_r): Also dump the livein_blocks. + (insert_phi_nodes): Simplify now that we don't need the + added and in_work varrays. Accept DFS as a sparse bitmap + instead of a simple bitmap. + (insert_phi_nodes_for): Rework significantly. Pre-compute all + the insertion points for semi-pruned form. While computing those + insertion points keep track of how many phi vector entries + would be needed at those insertion points. When the number of + entries gets large (32), compute global life information and + use that to further pruned the number of PHI insertion points + necessary. + +2003-02-09 Diego Novillo + + * tree-dfa.c (find_vars_r): Assume that the RHS of an INDIRECT_REF, + that is also an SSA variable, is a VAR_DECL. + (get_virtual_var): Handle INDIRECT_REF nodes that are not valid SSA + variables. + + * tree-ssa-dce.c (stmt_useful_p): Revert kludge in previous commit. + VA_ARG_EXPR nodes are not inherently live. + + * tree-ssa.c (mark_def_sites): Don't process the LHS of assignments + twice. + The operand of a virtual definition constitutes a use of the + variable which should be considered a non-local if it had not been + killed inside the block. + + * tree.h (SSA_VAR_P): Only return true for INDIRECT_REFs if their + operand is a _DECL node. + +2003-02-09 Diego Novillo + + * config/rs6000/t-rs6000 (simplify-rtx.o): Compile with -Wno-error. + +2003-02-08 Diego Novillo + + * toplev.c (parse_options_and_default_flags): Enable SSA DCE by + default. + + * tree-dfa.c (get_expr_operands): Recurse into LHS of an ARRAY_REF + when it's not a regular variable. Always recurse into the RHS. + (add_stmt_operand): Set may_point_to_global_mem for pointers that + are assigned expressions that may reference global memory. Also + set its dereference variable to be an alias of global memory. + (dump_variable): Show may_point_to_global_mem flag. + (compute_alias_sets): Also dump all referenced variables when + dumping alias information. + (add_may_alias): Check for global memory aliasing. + (may_access_global_mem_p): Rename from may_access_global_mem. + Return true if the expression is a variable that may point to or + alias global memory. + (add_referenced_var): Pointer arguments and global pointers may + point to global memory. + (set_may_alias_global_mem): Move ... + * tree-flow-inline.h (set_may_alias_global_mem): ... here. + (set_may_point_to_global_mem): New function. + (may_point_to_global_mem_p): New function. + + * tree-ssa-dce.c (stmt_useful_p): VA_ARG_EXPRs are inherently live. + * tree-ssa.c (rewrite_into_ssa): Don't call dump_referenced_vars. + +2003-02-06 Diego Novillo + + * tree-dfa.c (struct alias_tags, alias_tags, num_alias_tags): + Remove. Update all users. + (struct alias_set_d): New. + (alias_sets): New file local variable. + (compute_alias_sets): New function. + (compute_may_aliases): Call it when not doing points-to analysis. + (register_alias_set): New function. + (find_alias_for): New function. + (may_alias_p): Declare static. + Don't assume that VAR may not be aliased if it's a non-addressable + _DECL. + If VAR and PTR are aggregate types, check if they can have a field + that points to the other one. + (find_may_aliases_for): Move handling of global memory aliasing ... + (add_may_alias): ... here. + Also accept the base symbols for the variable and its alias. + (register_new_alias): Remove. Update all users. + (find_alias_tag): Remove. Update all users. + (find_vars_r): Update VAR after re-writing *TP when sharing + INDIRECT_REF nodes. + * tree-flow.h (may_alias_p): Remove declaration. + + * tree-ssa.c (rewrite_into_ssa): Include referenced variables in + default debug dumps. + + Support for VLAs. + + * tree-dfa.c (find_vla_decls): New function. + (compute_may_aliases): Call it. + (find_vla_decls_r): New function. + (dump_variable): Show whether the variable is used in a VLA + declaration. + * tree-flow-inline.h (is_vla_decl): New function. + (set_vla_decl): New function. + * tree-flow.h (struct var_ann_d): Add bitfield 'is_vla_decl'. + * tree-ssa-dce.c (need_to_preserve_store): Return true if SYM is + used inside a VLA declaration. + +2003-02-05 Andrew MacLeod + + * Makefile.in : Include new file tree-iterator.h in tree-simple.h + * gimplify.c (simplify_cleanup_point_expr): Use tsi_ rather than gsi_. + * tree-cfg.c (make_blocks, remove_bb): Use tsi_ not gsi_ routines. + (bsi_remove): Renamed from gsi_remove, use bsi_ routines. + (successor_block, first_exec_stmt): Use tsi_ not gsi_ routines. + (first_stmt, last_stmt, last_stmt_ptr): Use bsi_ not gsi_ routines. + (bsi_init): Split out from bsi_start. + (bsi_start): Renamed from gsi_start_bb, use bsi_ routines. + (bsi_next_in_bb): Moved from tree-flow-inline.h and renamed from + gsi_step_in_bb. Also verify BB of new stmt. + * tree-dfa.c (compute_immediate_uses, dump_immediate_uses, + collect_dfa_stats, compute_may_aliases): Use block_stmt_iterator. + * tree-flow-inline.h (gsi_step_in_bb): Moved to tree-cfg.c + (bsi_end_p): Renamed from gsi_end_bb_p. + (bsi_next): renamed from gsi_step_bb + (bsi_prev): New function. + (bsi_stmt_ptr): Block version of gsi_stmt_ptr. + (bsi_stmt): Block version of gsi_stmt. + (bsi_container): Block version of gsi_container. + * tree-flow.h (block_stmt_iterator): New iterator type. + * tree-iterator.h: New include file for tree_iterator. + * tree-simple.h : Include tree-iterator.h + (gimple_stmt_iterator, gsi_start, gsi_end_p, gsi_stmt_ptr, + gsi_stmt, gsi_container): Move to tree-iterator.h and rename to tsi_. + (gsi_step): Move to tree-iterator.h and renamed to tsi_next. + * tree-ssa-ccp.c (simulate_block, substitute_and_fold): Use block + iterators instead of gimple_stmt_iterator. + * tree-ssa-dce.c (mark_control_parent_necessary, find_useful_stmts, + remove_dead_stmts, remove_dead_stmt): Use block_stmt_iterator. + * tree-ssa.c (mark_def_sites, rewrite_out_of_ssa, rewrite_stmts): Use + block_stmt_iterator. + +2003-02-04 Daniel Berlin + + * tree-alias-common.c (get_alias_var_decl): If it's a global var, + make sure it doesn't get added to local_alias_vars. + (get_name): Return the right name for FUNCTION_DECL's. + +2003-02-04 Diego Novillo + + * tree-dfa.c (add_stmt_operand): Do not add a VUSE for a pointer + when clobbering its associated INDIRECT_REF variable. + +2003-02-04 Diego Novillo + + * config/rs6000/t-rs6000 (jump.o, regmove.o, c-typeck.o, cfgrtl.o, + combine.o, fold-const.o, ifcvt.o, reload1.o, rtlanal.o, + cp/decl2.o, cp/pt.o, f/where.o, java/expr.o, objc/objc-act.o, + rs6000.o, insn-emit.o): Compile with -Wno-error. + +2003-02-03 Diego Novillo + Jeff Law + + * tree-cfg.c (make_blocks): Don't always start a new block with + COND_EXPR and SWITCH_EXPR statements. + Call stmt_ends_bb_p to determine if the current statement should be + the last in the block. + (make_cond_expr_blocks): Second argument is now the entry block + to the conditional. + (make_switch_expr_blocks): Second argument is now the entry block + to the switch. + (make_edges, make_ctrl_stmt_edges, make_loop_expr_edges, + cleanup_control_flow, cleanup_cond_expr_graph, + cleanup_switch_expr_graph, disconnect_unreachable_case_labels, + find_taken_edge, successor_block, latch_block, is_latch_block, + switch_parent): Work with the last statement of the block, not the + first. + (is_ctrl_altering_stmt): Pre-compute the code of the statement. + (stmt_starts_bb_p): Declare file local. + Don't call is_ctrl_stmt. Check if T is a LOOP_EXPR instead. + (stmt_ends_bb_p): New function. + + * tree-flow.h (stmt_starts_bb_p): Remove declaration. + +2003-02-03 Diego Novillo + + * tree-dfa.c (find_vars_r): Share INDIRECT_REF nodes whose operand + is a VAR_DECL. + (add_referenced_var): Add additional argument 'sym'. Update all users. + Don't call get_base_symbol. + (add_indirect_ref_var): Rename argument 'var' to 'ptr'. + (htab_hash_var): Remove. Update all users to use htab_hash_pointer. + (htab_var_eq): Remove. Update all users to use htab_eq_pointer. + + * tree-flow-inline.h (var_ann): Don't retrieve the annotation of + the base pointer for INDIRECT_REF variables. + (is_aliased): Remove. Update all users. + (is_dereferenced): Remove. Update all users. + (same_var_p): Remove. Update all users to use pointer equality. + + * tree-simple.c (get_base_symbol): Convert tail recursion into + iteration. + + * tree-ssa.c (rewrite_out_of_ssa): Add FIXME note about overlapping + live ranges for different versions of the same variable. + +2003-02-03 Jeff Law + + * tree-dfa.c (add_referenced_var): Annotate each item in the + REFERENCED_VARS varray with a unique id. + * tree-flow.h (struct var_ann_d): Add new uid field. + * tree-ssa.c (mark_def_sites): Compute the set of variables + live across basic blocks and return them in an sbitmap. + (insert_phi_nodes): Use the set of nonlocal variables computed + by mark_def_sites to reduce the number of PHI nodes inserted. + (rewrite_into_ssa): Updated to deal with changes in + insert_phi_nodes and mark_def_sites. Free the sbitmap returned + by mark_def_sites. + +2003-02-03 Diego Novillo + + * c-common.h (GOTO_DESTINATION): Remove. Fix botched + merge. + +2003-02-03 Diego Novillo + + Fix warnings to allow bootstrapping with -Werror. + + * Makefile.in (c-semantics.o-warn): Add -Wno-error. + (emit-rtl.o-warn): Likewise. + (profile.o-warn): Likewise. + (tree.o-warn): Likewise. + (OBJS): Remove simple-break-elim.o and simple-goto-elim.o. + * c-pretty-print.c (print_function_decl): Remove unused function. + * bitmap.c (bitmap_last_set_bit): Initialize variable 'word'. + * c-typeck.c (build_binary_op): Initialize variable 'type'. + * combine.c (combine_simplify_rtx): Initialize variable 'reversed'. + (make_compound_operation): Initialize variable 'i'. + * dwarf2out.c (dwarf2out_finish): Initialize variable 'context'. + * expr.c (store_constructor): Initialize variables 'lo', 'hi', + 'startb' and 'endb'. + (expand_expr): Initialize variable 'op0'. + * fold-const.c (fold): Initialize variable 'tem'. + * profile.c (branch_prob): Initialize variable 'prev_file_name'. + * reload.c (find_equiv_reg): Initialize variables 'valtry and + 'valueno'. + * rtlanal.c (get_jump_table_offset): Initialize variable 'set'. + * ssa-ccp.c (ssa_const_prop): Fix sign mismatch warning. + * varasm.c (output_constant_def): Initialize variable 'defstr'. + * gimplify.c (simplify_expr): Initialize variables + 'saved_input_filename' and 'saved_lineno'. + (simplify_compound_lval): Initialize variable 'code'. + * tree-alias-ander.c (pta_bottom): De-ansify. + (andersen_cleanup): Remove unused variables. + (andersen_heap_assign): Mark argument lhs ATTRIBUTE_UNUSED. + (pta_bottom): Remove unused function. + (pta_get_ptsize): Remove unused function. + +2003-02-02 Diego Novillo + + * tree-dfa.c (get_expr_operands): Add a VUSE for the dereference of + every pointer passed in a function call. + Move code to add an operand for the base pointer of an + INDIRECT_REF ... + (add_stmt_operand): ... here. + Add a VUSE for the base pointer of every INDIRECT_REF variable. + (find_may_aliases_for): Fix starting index for the loop that scans + INDIRECT_REFs for aliasing. + Factor code that marks two variables aliased into + register_new_alias. + (register_new_alias): New function. + (may_alias_p): Handle aliasing of structure fields. + (add_may_alias): Fix documentation. + (find_vars_r): Factor code that adds a new referenced variable into + add_referenced_var. + (add_referenced_var): New function. + (add_indirect_ref_var): New function. + (get_virtual_var): Handle variables wrapped in SSA_NAMEs. + (set_may_alias_global_mem): Move from ... + * tree-flow-inline.h: ... here. + + * tree-ssa-dce.c (need_to_preserve_store): CALL_EXPRs are + implicitly live. VA_ARG_EXPRs are not. + (stmt_useful_p): + + * tree.h (SSA_NAME_VAR): Rename from SSA_NAME_DECL. Update all + users. + (struct tree_ssa_name): Rename field 'decl' to 'var'. Update all + users. + (SSA_DECL_P): Accept only VAR_DECLs and PARM_DECLs possibly wrapped + inside an SSA_NAME node. + (SSA_VAR_P): Also accept SSA_NAME nodes. + +2003-02-01 Daniel Berlin + + * Makefile.in (tree-ssa-pre2.o): Remove accidental addition. + +2003-01-31 Diego Novillo + + * tree-cfg.c (find_taken_edge_cond_expr): New function. + (find_taken_edge_switch_expr): New function. + (value_matches_some_label): New function. + (find_taken_edge): Re-structure to use the three new functions. + +2003-01-30 Jason Merrill + + * gimplify.c (simplify_function_tree): Set TREE_SIDE_EFFECTS on + the BIND_EXPR wrapper. + +2003-01-30 Diego Novillo + + * tree-dfa.c (call_may_clobber): New function. + (get_expr_operands): Call it. + (find_vars_r): Call it. + +2003-01-30 Jeff Law + + * tree-dfa.c (struct alias_tags): New. Collector for key information + regarding alias tags. + (indirect_refs_base, indirect_refs_alias_set): New varrays. + (addressable_vars_base, addressable_vars_alias_set): Likewise. + (compute_may_aliases): Initialize and finalize the new varrays. + Update allocation of alias tags information. + (find_may_aliases_for): Extract base symbols and alias set + information for V1 and V2 from the virtual arrays and store + them into local variables. Pass them as necessary to + may_alias_p, may_access_global_mem, find_alias_tag. Add base + symbol and alias set when creating a new alias tag. + (find_vars_r): Fill in new varrays as needed. + (may_alias_p): Add new arguments for base and alias set of the + two origianl incoming arguments. No longer call get_base_symbol + or get_alias_set. + (find_alias_tag, may_access_global_mem): Similarly. + (add_stmt_operand): Update to pass additional argument to + may_access_global_mem. + (dump_alias_info): Update to deal with new alias tag structure. + * tree-flow.h (may_alias_p): Update prototype with new arguments. + * tree-ssa-pre.c (process_left_occs_and_kills): Update to pass + new arguments to may_alias_p. + +2003-01-30 Daniel Berlin + + Remove all traces of steensgaard's algorithm. + * tree-alias-steen.c: Removed. + * tree-alias-steen.h: Ditto. + * tree-alias-ecr.c: Ditto. + * tree-alias-ecr.h: Ditto. + * disjoint-set.c: Ditto. + * disjoint-set.h: Ditto. + * Makefile.in: Remove removed files. + * c-config-lang.in: Ditto. + * gengtype.c: Ditto. + * tree-alias-common.c: Don't use steen_alias_ops anymore. + * toplev.c: Remove help text and steen option. + * tree-alias-common.h: Remove PTA_STEEN. + * tree-alias-type.c: Remove all steensgaard related types and + functions. + * tree-alias-type.h: Ditto. + +2003-01-30 Diego Novillo + + * tree-cfg.c (struct cfg_stats_d): New. + (cfg_stats): New file local. + (build_tree_cfg): Start TV_TREE_CFG timer before allocating memory. + Initialize cfg_stats. + (make_blocks): Count coalesced label blocks. + (dump_tree_cfg): Call dump_cfg_stats if TDF_STATS is enabled. + (dump_cfg_stats): New. + (debug_cfg_stats): New. + + * tree-dfa.c (SCALE, LABEL, PERCENT): Move ... + * tree-flow.h: ... here + +2003-01-29 Diego Novillo + + * tree-cfg.c (make_blocks): Do not start a new block if the + previous statement and the current statement are labels of the same + kind. + +2003-01-29 Diego Novillo + + * tree-cfg.c (parent_array): Make file local. + (label_to_block_map): New file local variable. + (build_tree_cfg): Initialize label_to_block_map. + (make_edges): Don't pre-scan all the blocks looking for blocks with + labels. + (make_exit_edges): Remove argument label_to_block_map. Update all + callers. + (make_goto_expr_edges): Likewise. + (dump_tree_bb): Check that the block has a valid annotation. + (set_bb_for_stmt): If the statement is a label, add the label to + the label_to_block_map. + + * tree-pretty-print.c (dump_vops): Check that the block has a valid + annotation. + +2003-01-29 Jeff Law + + * tree-dfa.c (find_may_aliases_for): Just accept the index of + the current indirect_ref. Caller updated. + (num_indirect_refs, num_addressable_vars): New variables. + (indirect_refs, addressable_vars): New varrays. + (dump_dfa_status): Dump info on the indirect refs and + addressable vars. + (dump_alias_info): Similarly. + (compute_may_aliases): Initialize and finalize the new virtual + arrays and hash tables for indirect refs and addressable vars. + Include setup/teardown in the cost for alias analysis. + (find_may_aliases_for): Split main loop into two. The first + walks over the indirect refs and takes advantage of the + symmetric properties of the aliasing relationship to avoid + useless work. The second loop iterates over the addressable + variables. + (find_vars_r): Rework to build all three arrays we need. + +2003-01-29 Andreas Jaeger + + * tree-alias-common.c (find_func_aliases): Remove unused variable. + (display_points_to_set_helper): #if 0 function to avoid warning + about unused function. + + * tree-alias-ecr.c (ECR_new): Remove ISO C style function + definition. + * disjoint-set.c (disjoint_set_new): Likewise. + +2003-01-29 Frank Ch. Eigler + + * tree-mudflap.c (mx_xfn_indirect_ref): Use a stack of flags for + tracking pointer dereference reads vs writes. + (mf_build_check_statement_for): Pass access-type value to __mf_check. + * c-mudflap.c (mflang_register_call): Adapt to mf-runtime.h API change. + +2003-01-29 Diego Novillo + + * Makefile.in (ssa.o): Add dependency on $(TIMEVAR_H). + * timevar.def (TV_DOM_FRONTIERS): Define. + * ssa.c (compute_dominance_frontiers): Use. + +2003-01-29 Diego Novillo + + * tree-ssa-dce.c (remove_dead_stmt): Fix uninitialized use + warning. + +2003-01-28 Diego Novillo + + * timevar.def (TV_TREE_SSA_REWRITE_BLOCKS): Adjust legend. + * tree-ssa.c (rewrite_into_ssa): Use TV_TREE_SSA_REWRITE_BLOCKS. + (mark_def_sites): Add comment. + +2003-01-28 Jeff Law + + * ssa.c (compute_dominance_frontiers_1): Use get_dominated_by + to avoid useless walks over all the basic blocks. Use cache + of immediate dominators to avoid silly calls to get_immediate_dominator. + Do not clear elements of the frontiers bitmap. + (compute_dominance_frontiers): Compute cache of immediate + dominators and pass it to compute_dominance_frontiers_1. Clear + the entire vector of frontiers bitmaps. + + * timevar.def (TV_TREE_SSA_REWRITE_BLOCKS): Renamed from + TV_TREE_BUILD_SSA. + (TV_TREE_SSA_OTHER): New timevar. + * tree-ssa.c (rewrite_into_ssa): Updated. Use new TV_TREE_SSA_OTHER + timevar. + + * tree.h (LABEL_DECL_INDEX): Define for use by CFG builder. + * tree-cfg.c (make_exit_edges): Accept and pass though label to + block mapping array. + (make_goto_expr_edges): For simple gotos, lookup the destination + in the label to block mapping array. Zap old slow code to + handle simple gotos. + (make_edges): Build the label to block mapping array. + + * tree.h (PHI_NODE_ELT_CHECK): Provide version when ENABLE_CHECKING + is not defined. + +2003-01-28 Diego Novillo + + * tree-flow-inline.h (parent_block, set_parent_block, phi_nodes): + Assume that blocks always have valid annotations. + (add_dom_child): New function. + (dominator_children): New function. + + * tree-flow.h (struct bb_ann_d): Add field 'dom_children'. + + * tree-ssa.c (mark_def_sites): Add parameter 'idom'. + Add each block BB to the set of dominator children of BB's + immediate dominator. + (rewrite_block): Remove 'idom' parameter. + Recurse into blocks set in the dominator children bitmap. + +2003-01-28 Diego Novillo + + * flags.h (flag_disable_tree_ssa): New flag. + * c-decl.c (c_expand_body): Use it. + * toplev.c: Declare it. + (f_options): Add help text for -fdisable-tree-ssa. + * doc/invoke.texi: Add documentation for -fdisable-tree-ssa. + +2003-01-28 Diego Novillo + + * Makefile.in (TREE_FLOW_H): Add dependency on $(HASHTAB_H) + (OBJS): Temporarily remove tree-ssa-pre.o. + (tree-ssa.o, c-decl.o): Add dependency on $(TREE_DUMP_H). + + * c-decl.c: Include tree-dump.h + + * c-pretty-print.c (dump_c_node): Fix rendering of GOTO_STMTs to + computed locations. + (op_prio): Don't abort on unknown operators. + + * c-simplify.c (mostly_copy_tree_r): Don't copy statement + annotations. + + * gimplify.c (simplify_addr_expr): Mark the RHS of the simplified + ADDR_EXPR addressable. + (mostly_copy_tree_r): Don't copy statement annotations. + + * old-tree-inline.c (walk_tree): Handle SSA_NAME nodes. + + * timevar.def (TV_TREE_RDEFS): Remove. + (TV_TREE_BUILD_SSA): Define. + (TV_TREE_DFA): Define. + + * tree-cfg.c: Update copyright notices. + Remove doxygen markers everywhere. + (remove_unreachable_block): New local function + (remove_unreachable_blocks): Call it. + (remove_bb): Rename from remove_tree_bb. Update all callers. + (validate_loops): Remove unused function. + (block_invalidates_loop): Remove unused function. + (remove_stmt): Invalidate the defining statement of all the + definitions made by the statement. + Remove the annotation before replacing the statement with + empty_stmt_node. + + * tree-dfa.c: Update copyright notices. + Remove doxygen markers everywhere. + (struct clobber_data_d): Remove existing fields. Add fields 'stmt' + and 'prev_vops'. Update all users. + (alias_tags): Rename from alias_leaders. + (num_alias_tags): Rename from num_alias_leaders. + (struct dfa_stats_d): Declare. + (struct dfa_counts_d): Remove. Update all users. + (TRM_*): Remove. Update all users. + (find_tree_refs): Remove. Update all users. + (get_stmt_operands): Rename from find_refs_in_stmt. Update all users. + (get_expr_operands): Rename from find_refs_in_expr. Update all users. + (add_stmt_operand): New function. + (set_def): New function. + (add_use): New function. + (add_vdef): New function. + (add_vuse): New function. + (create_phi_node): New function. + (copy_stmt): New function. + (compute_immediate_uses): New function. + (compute_immediate_uses_for): New function. + (compute_reached_uses): New function. + (compute_reaching_defs): New function. + (add_immediate_use): New function. + (create_var_ann): New function. + (create_stmt_ann): New function. + (dump_immediate_uses): New function. + (debug_immediate_uses): New function. + (dump_immediate_uses_for): New function. + (debug_immediate_uses_for): New function. + (create_ref_list, empty_ref_list, add_ref_to_list_begin, + add_ref_to_list_end, add_list_to_list_begin, add_list_to_list_end, + find_list_node, rli_start, rli_start_last, rli_start_at, + rli_delete, add_ref_to_list_after, tree_ref_size, create_ref, + add_ephi_arg, add_referenced_var, replace_ref_with, + try_replace_ref_with, replace_ref_r, replace_ref_stmt_with, + remove_ref, remove_def, reset_def_def_links, replace_phi_arg_with, + create_tree_ann, function_may_recurse_p, dump_ref, debug_ref, + dump_ref_list, dump_ref_array, debug_ref_list, debug_ref_array, + dump_phi_args, dump_if_different, count_tree_refs, ref_type_name, + ref_defines, is_killing_def, tree_ref_structure, output_ref): + Remove. Update all users. + (dump_referenced_vars): Remove parameter 'details'. Update all + users. + (dump_variable): Don't abort if the variable is nil. Display all + the aliases for the variable. + (dump_dfa_stats): Handle new counters. + (collect_dfa_stats): Likewise. + (collect_dfa_stats_r): Likewise. + (find_vars_r): New function. + (compute_may_aliases): Call it via walk_tree before computing aliases. + Only use alias tags if -ftree-points-to is not given. + Call add_may_alias. + (find_may_aliases_for): Only use alias tags if -ftree-points-to is + not given. + (add_may_alias): New function. + (find_alias_tag): Rename from find_alias_leader. + (dump_alias_info): New function. + (debug_alias_info): New function. + (htab_hash_var): New function. + (htab_var_eq): New function. + (get_virtual_var): New function. + + * tree-dump.c (struct dump_option_value_info): Rename -block to + -blocks. Add new option -vops. + (dump_function): Don't display which pass enabled the dump. + + * tree-flow-inline.h: Update copyright notices. + (var_ann): New function. + (stmt_ann): New function. + (ann_type): New function. + (bb_ann): Rename from bb_annotation. + (may_aliases): New function. + (set_may_alias_global_mem): New function. + (may_alias_global_mem_p): New function. + (set_indirect_ref): New function. + (indirect_ref): New function. + (is_dereferenced): New function. + (modify_stmt): New function. + (unmodify_stmt): New function. + (stmt_modified_p): New function. + (def_op): New function. + (use_ops): New function. + (vdef_ops): New function. + (vuse_ops): New function. + (immediate_uses): New function. + (reaching_defs): New function. + (phi_nodes): New function. + (same_var_p): New function. + (gsi_step_in_bb): Re-implement. Check if the iterator stepped out + of the block by calling bb_for_stmt. + (gsi_end_bb_p): Rename from gsi_end_bb. Update all users. + Call gsi_stmt to determine if the iterator has reached the end of + the block. + (ref_id, ref_type, ref_bb, ref_stmt, ref_var, imm_uses, + reached_uses, imm_reaching_def, set_imm_reaching_def, + set_phi_arg_def, phi_arg_def, set_phi_arg_edge, phi_arg_edge, + reaching_defs, phi_args, num_phi_args, phi_arg, set_phi_arg, + tree_annotation, tree_refs, add_tree_ref, remove_tree_ref, + alias_leader, set_alias_leader, set_tree_flag, clear_tree_flag, + reset_tree_flags, tree_flags, indirect_var, set_indirect_var, + bb_refs, remove_bb_ref, set_exprref_class, exprref_class, + set_exprref_inserted, exprref_inserted, set_exprref_save, + exprref_save, set_exprref_reload, exprref_reload, + set_exprref_processed, set_exprref_processed2, exprref_processed2i, + exprref_uses, set_exprref_uses, set_expruse_def, expruse_def, + set_expruse_phiop, expruse_phiop, set_expruse_phi, expruse_phi, + set_expruse_has_real_use, expruse_has_real_use, + set_exprphi_phi_args, exprphi_phi_args, num_ephi_args, ephi_arg, + set_ephi_arg, set_exprphi_downsafe, exprphi_downsafe, + set_exprphi_canbeavail, exprphi_canbeavail, set_exprphi_later, + exprphi_later, set_exprphi_extraneous, exprphi_extraneous, + exprphi_willbeavail, is_assignment_stmt, is_may_ref, is_may_def, + is_may_use, is_partial_ref, is_partial_use, is_volatile_ref, + is_volatile_def, is_volatile_use, is_clobbering_def, + is_relocating_def, is_addressof_use, is_pure_use, is_pure_def, + rli_after_end, rli_step, rli_step_rev, rli_ref, get_last_ref, + get_first_ref, ref_list_is_empty): Remove. Update all users. + + * tree-flow.h: Update copyright notices. + Remove doxygen markers. + Include hashtab.h. + (enum tree_ann_type): New. + (struct tree_ann_common_d): New. + (struct var_ann_d): New. + (struct operands_d): New. + (struct voperands_d): New. + (operands_t): New type. + (voperands_t): New type. + (struct dataflow_d): New. + (dataflow_t): New type. + (struct stmt_ann_d): New. + (tree_ann): New type. + (var_ann_t): New type. + (stmt_ann_t): New type. + (bb_ann_t): Rename from bb_ann. + (enum tree_ref_type, TRM_*, struct ref_list_node, struct + ref_list_priv, ref_list, struct tree_ref_common, struct var_ref_d, + struct var_def_d, struct var_phi_d, struct var_use_d, struct + phi_node_arg_d, phi_node_arg, struct expr_ref_common, struct + expr_phi_d, struct expr_use_d, enum tree_ref_structure_enum, union + tree_ref_d, tree_ref, struct tree_ann_d, tree_ann, enum tree_flags, + struct dfa_counts_d, ref_list_iterator): Remove. Update all users. + (TDFA_USE_OPS): Define. + (TDFA_USE_VOPS): Define. + + * tree-inline.c (walk_tree): Handle SSA_NAME nodes. + + * tree-optimize.c: Update copyright notices. + Remove doxygen markers. + (optimize_function_tree): Temporarily disable call to + tree_perform_ssapre. + Remove #if0 code. + + * tree-pretty-print.c (MASK_POINTER): Define. + (dump_vops): New function. + (dump_generic_node): Shorten made-up names for unnamed objects. + Hanlde PHI_NODE, VDEF_EXPR and SSA_NAME nodes. + Keep track of basic block transitions. + Call dump_vops if -vops dump option is given. + (op_prio): Don't abort if the operand is nil. + (dump_block_info): Don't keep track of basic block transitions. + + * tree-simple.c: Update copyright notices. + (get_base_symbol): Call STRIP_NOPS. + Handle SSA_NAME nodes. + + * tree-simple.h: Update copyright notices. + (gsi_end_p): Rename from gsi_end. Update all callers. + + * tree-ssa-ccp.c: Update copyright notices. + Update code to use the new SSA infrastructure. + (const_values): New hash table to keep track of constants. + (struct value_map_d): New. + (cfg_edges): Rename from edges. Update all users. + (set_value): New function. + (get_value): New function. + (get_default_value): New function. + (value_map_hash): New function. + (value_map_eq): New function. + + * tree-ssa-dce.c: Update copyright notice. + Update code to use new SSA infrastructure. Factor some code into + new functions. + (dom_info): Declare with file scope. + (struct stmt_stats): Add fields 'total_phis' and 'removed_phis'. + (needed_stmts): New hash table to keep track of needed statements. + (stmt_useful_p): New function. + (find_useful_stmts): Call it. + (remove_dead_stmt, remove_dead_phis): New functions. + (remove_dead_stmts): Call them. + (need_to_preserve_store): Preserve stores to volatile variables. + (tree_ssa_dce): Rename from tree_ssa_eliminate_dead_code. Update + all users. + + * tree-ssa.c: Update copyright notice. + Change basic algorithm to rewrite the function into SSA form + instead of building factored use-def chains. + Include hashtab.h and tree-dump.h + (next_ssa_version): New global variable. + (def_blocks): New file local variable. + (struct def_blocks_d): New. + (currdefs): New file local variable. + (struct currdef_d): New. + (rewrite_into_ssa): Rename from build_tree_ssa. Update all users. + Call compute_may_aliases, mark_def_sites and rewrite_block. + (rewrite_block): Rename from search_fud_chains. Call + rewrite_stmts. + (mark_def_sites): New function. + (set_def_block): New function. + (rewrite_stmts): New function. + (rewrite_stmt): New function. + (rewrite_operand): New function. + (rewrite_out_of_ssa): New function. + (remove_phi_node): New function. + (register_new_def): New function. + (def_blocks_free): New function. + (def_blocks_hash): New function. + (def_blocks_eq): New function. + (currdef_hash): New function. + (currdef_eq): New function. + (debug_def_blocks): New function. + (debug_def_blocks_r): New function. + (build_fud_chains, compute_reaching_defs, follow_chain, + dump_reaching_defs, debug_reaching_defs, set_ssa_links): Remove. + (remove_phi_arg): Rename from tree_ssa_remove_phi_alternative. + Update all users. + (init_tree_ssa): Set next_ssa_version to 1. + Create hash tables def_blocks and currdefs. + (delete_tree_ssa): Accept a FUNCTION_DECL tree as argument. Update + all users. + (currdef_for): Add new parameter 'create_default'. If nonzero, + create a new SSA name if none is found for the variable. + (set_currdef_for): Search in the currdefs hash table. + + * tree.c (tree_node_kind): Add new values phi_kind and + ssa_name_kind. + (tree_node_kind_names): Likewise. + (tree_size): Handle PHI_NODE and SSA_NAME nodes. + (make_node): Likewise. + (tree_node_structure): Likewise. + (phi_node_elt_check_failed): New function. + (make_phi_node): New function. + (make_ssa_name): New function. + (build_vdef_expr): New function. + + * tree.def (SSA_NAME): New code. + (VDEF_EXPR): New code. + (PHI_NODE): New code. + + * tree.h (union tree_ann_d): Forward declare. + (struct tree_common): Change type of field 'ann'. + (PHI_NODE_ELT_CHECK): Define. + (phi_node_elt_check_failed): Declare. + (VDEF_RESULT): Define. + (VDEF_OP): Define. + (SSA_NAME_DECL): Define. + (SSA_NAME_DEF_STMT): Define. + (SSA_NAME_VERSION): Define. + (struct tree_ssa_name): New. + (PHI_RESULT): Define. + (PHI_NUM_ARGS): Define. + (PHI_ARG_CAPACITY): Define. + (PHI_ARG_ELT): Define. + (PHI_ARG_EDGE): Define. + (PHI_ARG_DEF): Define. + (struct phi_arg_d): New. + (struct tree_phi_node): New. + (SSA_DECL_P): Define. + (SSA_VAR_P): Define. + (enum tree_node_structure_enum): Add values TS_SSA_NAME and + TS_PHI_NODE. + (union tree_node): Add fields 'ssa_name' and 'phi'. + (make_phi_node): Declare. + (make_ssa_name): Declare. + (build_vdef_expr): Declare. + (TDF_BLOCKS): Rename from TDF_BLOCK. + (TDF_VOPS): Define. + + * doc/invoke.texi: Document new tree dump option -vops. Update + documentation for switch -blocks. + +2003-01-27 Jeff Law + + * gimplify.c (simplify_return_expr): Correctly handle return + expressions with side effects in functions returning void. + + * tree-ssa-ccp.c (widen_bitfield): Do not try to widen anything + except constant integers. + +2003-01-26 Jeff Law + + * c-simplify.c (simplify_decl_stmt): Fix comment typo. + Use correct predicate when "simplifying" a static initializer. + +2003-01-26 Andreas Jaeger + + * Makefile.in (gt-dependence.h): New rule. + +2003-01-23 Jeff Law + + * c-simplify.c (simplify_decl_stmt): Arrange to examine initializers + for static variables. + * gimplify.c (simplify_constructor): Kill initial is_simple_constructor + check. + (simplify_modify_expr): Get the type from the destination rather than + the toplevel expression. Handle case where type is ARRAY_TYPE. Ignore + TREE_STATIC for the RHS. + +2003-01-24 Frank Ch. Eigler + + * tree-mudflap.c (mf_varname_tree): Check for non-NULL DECL_NAME + before trying to cplus_demangle it. + +2003-01-23 Jeff Law + + * tree-cfg.c (make_exit_edges): Fix thinkos. + +2003-01-22 Jeff Law + + * tree-cfg.c (make_goto_expr_edges): Check the underlying + LABEL_DECL, not the LABEL_EXPR for FORCED_LABEL and NONLOCAL_LABEL. + + * gimplify.c (simplify_expr, case GOTO_EXPR): Identify and mark + labels which are targets of nonlocal gotos and mark functions which + have labels which are targets of nonlocal gotos. + (simplify_expr, case LABEL_DECL): New case. Mark labels which + have their address taken. + * tree-cfg.c (is_nonlocal_label_block): Remove. All callers + updated. + (make_exit_edges, case GOTO_EXPR): Handle computed gotos sanely. + (make_exit_edges, case CALL_EXPR): Handle abnormal edges from + nonlocal gotos at call sites. + (make_exit_edges, case RETURN_EXPR): Likewise. + (make_exit_edges, case MODIFY_EXPR): New case to handle abnormal + edges from nonlocal gotos as call sites. + (make_goto_expr_edges): Handle computed gotos and nonlocal gotos. + (is_ctrl_altering_stmt): Handle abnormal edges in CALL_EXPRs + functions which receive nonlocal gotos. Similarly for CALL_EXPRs + which occur on the RHS of a MODIFY_EXPR. + * tree.h (FORCED_LABEL, NONLOCAL_LABEL): New defines. + (FUNCTION_RECEIVES_NONLOCAL_GOTO): Likewise. + +2003-01-22 Frank Ch. Eigler + + * doc/invoke.texi: Provide some information about -fmudflap. + + * tree-mudflap.c (mf_varname_tree): Conditionally invoke the C++ + demangler in libiberty. Reduce function printing verbosity. + (mf_file_function_line_tree): Reduce function printing verbosity. + (mudflap_enqueue_decl): Use COMPLETE_TYPE_P to avoid trying to + register (get size of) void-typed objects. + +2003-01-21 Jose Renau + + * tree-flow-inline.h (get_lineno): Return -1 for nodes without + locus information. + (get_filename): Return "???" for nodes without locus information. + +2003-01-21 Jeff Law + + * tree-cfg.c (cleanup_switch_expr_graph): Wrap declaration of + switch_expr with ENABLE_CHECKING block. + + * c-simplify.c (is_last_stmt_of_scope): Wrap definition and + declaration inside and ENABLE_CHECKING block. + +2003-01-20 Frank Ch. Eigler + + * tree-mudflap.c (mx_xfn_indirect_ref): Use new TREE_LOCUS field + as a predicate for finding TREE_FILENAME etc. + +2003-01-16 Daniel Berlin + + * Remove dead PRE code. + * tree-ssa-pre.c (tree_perform_ssapre): Collect left occurrences and + kills *after* finishing collecting all expressions. + +2003-01-15 Jeff Law + + * Death to WFL nodes. + * c-aux-info.c: Replace DECL_SOURCE_FILE and DECL_SOURCE_LINE with + TREE_FILENAME and TREE_LINENO respectively when retrieving file + and line information. Use TREE_LOCUS to copy existing information + from one node to another. Use annotate_with_file_line to add or + replace location information on a node. Remove support for + EXPR_WITH_FILE_LOCATION nodes. Remove STRIP_WFL statements. + * c-common.c, c-parse.in, c-pretty-print.c, dbxout.c: Likewise. + * diagnostic.c, dwarf2out.c, dwarfout.c: Likewise. + * except.c, integrate.c, stmt.c, tree-alias-common.c: Likewise. + * tree-cfg.c, tree-dfa.c, tree-dump.c, tree-flow-inline.h: Likewise. + * tree-mudflap.c, tree-pretty-print.c, tree-simple.c: Likewise. + * tree-ssa-ccp.c, tree-ssa-dce.c, tree-ssa-pre.c: Likewise. + * varasm.c, xcoffout.c: Likewise. + * config/alpha/alpha.c: Likewise. + * config/mips/mips.c: Likewise. + * c-decl.c: Likewise. + (duplicate_decls): Also copy TREE_LOCUS from olddecl to newdecl. + (finish_function): Save and restore the current filename and + linenumber around genericizing of the function tree. + * c-simplify.c (c_simplify_stmt): Use annotate_all_with_file_line + instead of wrap_all_with_wfl. Remove STRIP_WFL statements. + * expr.c (expand_expr): Emit line number notes for expressions + with attached file/line information. Remove EXPR_WITH_FILE_LOCATION + support. + * gimplify.c: Kill STRIP_WFL statements. Remove EXPR_WITH_FILE_LOCATION + support. + (simplify_expr_wfl): Kill. + (annotate_stmt_with_file_line): Renamed from wrap_with_wfl. + (annotate_all_with_file_line): Renamed from wrap_all_with_wfl. + (simplify_expr): Save and restore the current file/line around + simplification of the given expression. Add annotation to more + nodes created during simplification. + (simplify_self_mod_expr): Add file/line location to nodes we create. + (get_initialized_tmp_var): Similarly. + * old-tree-inline.c (expand_call_inline): Use annotate_with_file_line + to add file/line information to nodes instead of wrapping them + with EXPR_WITH_FILE_LOCATION nodes. + * print-tree.c: Use TREE_FILENAME and TREE_LINENO instead of + DECL_SOURCE_FILE and DECL_SOURCE_LINE respectively. Remove + support for EXPR_WITH_FILE_LOCATION nodes. + (print_node): Dump any file/line information that is attached to + the given node. + * tree-inline.c (walk_tree): Set lineno appropriately. + * tree-simple.h (annotate_all_with_file_line): Renamed from + wrap_all_with_wfl. Remove STRIP_WFL statements. + * tree.c (build_expr_wfl): Kill. + (make_node): Use annotate_with_file_line. + (annotate_with_file_line): New function. + * tree.def: Remove EXPR_WITH_FILE_LOCATION. + * tree.h (tree_common): Add locus field. Remove references to + EXPR_WITH_FILE_LOCATION. + (tree_decl): Remove locus field. + (STRIP_WFL, EXPR_WFL_*): Kill. + (DECL_SOURCE_LOCATION, DECL_SOURCE_FILE, DECL_SOURCE_LINE): Kill. + (TREE_LOCUS, TREE_FILENAME, TREE_LINENO): new. + (annotate_with_file_line): Renamed from build_expr_wfl. + + * objc/objc-act.c: Use TREE_FILENAME and TREE_LINENO to + extract file/line information from tree nodes. + +2003-01-14 Frank Ch. Eigler + + * tree-mudflap.c (mx_xfn_indirect_ref): Handle ARRAY_REF of + a COMPONENT_REF specially to avoid unnecessary checks. + +2003-01-13 Frank Ch. Eigler + + Front-end generalization. + * Makefile.in (C_AND_OBJC_OBJS): Add c-mudflap.o and dependencies. + * tree-mudflap.c: Don't include "c-tree.h" any more. + (mf_init_extern_trees): Divert to mflang_lookup_decl(). + (mf_enqueue_register_call, mf_flush_enqueued_calls): Move and rename + these functions. + * tree-mudflap.h: Declare new mflang_* routines. + * c-mudflap.c: New file with C front-end mflang_* routines. + * tree-nomudflap.c (*): Call internal_error instead of abort. + +2003-01-07 Steven Bosscher + + * Makefile.in (check-g95): New test target. + (check-f95): Alias for check-g95. + +2003-01-07 Diego Novillo + + * tree-dump.c (dump_function_to_file): New function. + (dump_function): Call it. + Convert argument declaration to K&R format. + * tree-dump.h: Include splay-tree.h. + (dump_function_to_file): Declare. + + * tree-optimize.c (optimize_function_tree): Remove unused variables + dump_file and dump_flags. + (dump_current_function): Remove. Update all users by calling + dump_function instead. + * tree.h (dump_current_function): Remove declaration. + + * Makefile.in (TREE_DUMP_H): Define. + Update targets depending on tree-dump.h to depend on $(TREE_DUMP_H). + (tree-ssa-cp.o): Remove unused target. + (tree-cfg.o): Add dependency on $(TREE_DUMP_H). + (tree-optimize.o): Likewise. + (tree-ssa-dce.o): Likewise. + (tree-ssa-ccp.o): Likewise. + (tree-ssa-pre.o): Likewise. + +2003-01-02 Daniel Berlin + + * tree-ssa-pre.c (rename_2): Fix a false matching condition. + This is actually fallout from is_default_def change. + +2003-01-02 Jason Merrill + + * c-simplify.c (c_genericize): Dump more info about the function. + Use dump_function. + * tree-dump.c (dump_function): Move from cp/optimize.c. + * tree-dump.h: Declare it. + + * gimplify.c (mostly_copy_tree_r): Remove unnecessary cases. + (unshare_expr): New fn. + * tree-inline.c (mark_local_for_remap_r, unsave_r): New fns, adapted + from C++ versions. + (lhd_unsave_expr_now): Likewise. + * tree.c (unsave_expr_now): Remove. + (unsafe_for_reeval): Labels and BIND_EXPRs are only somewhat unsafe. + + * gimplify.c (simplify_function_tree): Add an outer BIND_EXPR if + needed. + (voidify_wrapper_expr): Not static. Abort if we try to voidify an + expression with TREE_ADDRESSABLE type. Be clever with INDIRECT_REFs. + (foreach_stmt): Avoid redundant work. + (create_tmp_var): Abort if we try to create a temp of ADDRESSABLE type. + (simplify_expr): Simplify VTABLE_REF. + * c-simplify.c (simplify_decl_stmt): Ignore DECL_EXTERNAL decls. + (simplify_stmt_expr): Fix thinko. + (simplify_block): Don't ignore partial scopes. + (simplify_condition): New fn. + (simplify_c_loop, simplify_if_stmt, simplify_switch_stmt): Call it. + * expr.c (expand_expr) [BIND_EXPR]: Handle statics better. + * tree-inline.c (remap_decl): Remap all decls. + (declare_return_variable): Be clever with INDIRECT_REFs. + (expand_call_inline): If we have an explicit return slot, the inlined + body is void. + (walk_tree): Fix type handling. + (copy_tree_r): Don't walk into decls. + * tree-simple.c (is_simple_unary_expr): Handle VTABLE_REF. + (is_simple_id): Allow RESULT_DECL. + * tree-simple.h (gsi_stmt): Strip WFLs and NOPs. + + * gimplify.c (simplify_cond_expr): Handle void arms. Add target parm. + (simplify_modify_expr): Pass it. Add special handling for COND_EXPR + and CONSTRUCTOR (from Daniel Berlin). Add want_value parm. + (simplify_expr): Pass new args. Loop sooner if language-specific + simplification happened. + (simplify_return_expr): Pass the whole MODIFY_EXPR to simplify_expr. + (simplify_target_expr): Simplify. + + * tree.def (CATCH_EXPR, EH_FILTER_EXPR): New tree codes. + * except.c (expand_eh_handler): New fn. + (expand_eh_region_end_allowed): If no types are allowed, hand off to + expand_eh_region_end_must_not_throw. + * except.h: Declare expand_eh_handler. + * expr.c (expand_expr) [TRY_CATCH_EXPR]: Use it. + [CATCH_EXPR, EH_FILTER_EXPR]: New cases. + * gimplify.c (simplify_expr) [EXC_PTR_EXPR, CATCH_EXPR, + EH_FILTER_EXPR]: New cases. + (gimple_build_eh_filter): New fn. + (maybe_protect_cleanup): New fn. + (gimple_push_cleanup): Call it. + (simplify_cleanup_point_expr): Fix thinko. + * c-simplify.c (simplify_cleanup): Call it. + * tree-simple.h: Declare it. + * Makefile.in (gimplify.o): Depend on except.h. + * tree.h (CATCH_TYPES, CATCH_BODY): New macros. + (EH_FILTER_TYPES, EH_FILTER_FAILURE): New macros. + * tree-simple.c (is_simple_id): Allow EXC_PTR_EXPR. + * c-pretty-print.c (dump_c_node) [CLEANUP_POINT_EXPR]: Support. + * tree-pretty-print.c (dump_generic_node): Likewise. + [CATCH_EXPR, EH_FILTER_EXPR, EXC_PTR_EXPR]: Support. + + * c-pretty-print.c (NIY): Print operands. + (dump_c_tree): Don't look at TREE_CHAIN if it doesn't matter. + (dump_c_node) [ARRAY_TYPE]: Handle non-constant array bounds. + [CALL_EXPR]: Pass spc down. + [VTABLE_REF]: Support. + (op_prio) [TARGET_EXPR]: Support. + (print_call_name): Handle function pointers. + * tree-pretty-print.c: Likewise. + +2002-12-31 Steven Bosscher + + * gimplify.c (create_tmp_var_noc): Remove unused function. + * tree-simple.h: Kill prototype. + +2002-12-30 Diego Novillo + + * tree-flow.h (tree_find_loops): Remove unused declaration. + +2002-12-29 Daniel Berlin + + * toplev.c: Add flag_ip, enable by default at -O4+ (This is not + set in stone, and thus, not documented). + (decode_f_option): Add warning if andersen's PTA is selected but + not compiled in. + + * flags.h: Add flag_ip. + + * tree-alias-ander.c: Fix todo. + (andersen_function_call): Return 1 if we don't need to process + the function. + (ptset_map): New map, cache points-to sets. + (andersen_op): We can do IP on all statics without help. + (andersen_init): Only init once if we are doing ip analysis. + (andersen_cleanup): Don't cleanup if we need the info for ip. + (andersen_add_var): Clear points-to set if it exists already. + (andersen_add_var_same): Ditto. + (andersen_function_call): We can do interprocedural analysis on + statics. + (andersen_may_alias): Cache points-to sets. + + * c-decl.c (c_expand_body): Don't throw away tree if flag_ip is + on, even if they are uninlinable, they may be wanted for ip + optimizations. + + * tree-alias-common.c (get_values_from_constructor): New + function to collect alias_typevars from constructors. + (alias_annot): Fix where the GTY is so gengtype picks it up. + (intra_function_call): Ignore non-pointers for global var + assignment. What arguments point to can now point to a global var + as well. + (find_func_aliases): We need to handle decl's with initials as + well. + Only call intra_function_call if we have to. + Handle constructors. + (create_fun_alias_var): Incoming pointer arguments could be + pointing to a global var, unless this is a static function and we + are doing interprocedural analysis. + (create_alias_vars): Take an fndecl argument, and use it. + (init_alias_vars): Handle ip_partial as well. + (ptr_may_alias_var): Simplify, fix. + + * tree-alias-common.h (tree_alias_ops): function_call now returns + an int, and we have an extra member named ip_partial. + + * tree-alias-steen.c (steen_ops): We can't do ip_partial. + (steen_function_call): Update definition and return 1. + + * tree-dfa.c (compute_may_aliases): Call create_alias_vars with + current_function_decl. + + * tree-flow.h (create_alias_vars): Remove proto from here, it's + in tree-alias-common.h. + (tree_perform_ssapre): Take a tree, like the other optimizers. + + * tree-optimize.c (optimize_function_tree): Call + tree_perform_ssapre with a tree. + + * tree-ssa-pre.c: Remove dead, #if 0'd code. + (tree_perform_ssapre): Use passed in tree. + +2002-12-23 Frank Ch. Eigler + + * tree-mudflap.c (mf_decl_cache_locals, mf_decl_clear_locals): New + functions. + (mudflap_c_function): Call them before/after basic transforms. + (mf_cache_shift_decl_l, ..._mask_l): New variables to track local + VAR_DECL shadows of cache parameters. + (mf_build_check_statement_for): Use and update them. + +2002-12-23 Frank Ch. Eigler + + * tree-mudflap.c (mx_register_decls): Trust incoming TREE_ADDRESSABLE + instead of own timetaking analysis. + (mf_find_addrof, mx_xfn_find_addrof): Removed functions. + +2002-12-23 Steven Bosscher + + * tree-dfa.c: Add doxygen markers in comments. + +2002-12-22 Diego Novillo + + * gimplify.c: Undo the following change: + 2002-12-11 Diego Novillo + * gimplify.c (simplify_return_expr): return statements should + only have a GIMPLE value as argument. + + * tree-simple.c: Fix grammar for return statements. + +2002-12-20 Frank Ch. Eigler + + * tree-mudflap.c (mf_init_extern_trees): Rewrite last change + without using statement-expressions. + +2002-12-19 Diego Novillo + + * tree-cfg.c (build_tree_cfg): Make sure that TV_TREE_CFG + is popped properly. + +2002-12-19 Frank Ch. Eigler + + * tree-mudflap.c (mf_init_extern_trees): Abort gracefully if + was not included. + (*): Correct some minor compiler warnings elsewhere. + +2002-12-18 Diego Novillo + + * configure: Regenerate with autoconf 2.13. + +2002-12-17 Ben Elliston + + * tree-optimize.c (optimize_function_tree): Temporarily + disable SSA optimizations if -fmudflap is present. + +2002-12-16 Ben Elliston + + * tree-mudflap.c (mx_flag): Assert that the tree node is valid. + +2002-12-14 Jason Merrill + + * tree-dump.c (dump_files): Add .generic. Move .inlined after it. + * tree.h (tree_dump_index): Likewise. + * c-simplify.c (c_genericize): Emit original and generic dumps here. + * c-decl.c (c_expand_body): Not here. + +2002-12-13 Ben Elliston + + * tree-dfa.c (find_refs_in_expr): Terminate comment. + +2002-12-12 Steven Bosscher + + * tree-cfg.c: Update doxygen documentation. + * tree-dfa.c: Add doxygen documentation. + +2002-12-11 Steven Bosscher + + * tree-cfg.c: Add doxygen markers in comments. + * tree-optimize.c: Likewise. + * tree-ssa.c: Likewise. + +2002-12-11 Diego Novillo + + * gimplify.c (simplify_return_expr): return statements should only + have a GIMPLE value as argument. + * tree-cfg.c (call_expr_flags): New function. + (is_ctrl_altering_stmt): Call it. + * tree-flow.h (extern): Declare it. + +2002-12-06 Diego Novillo + + * tree-cfg.c (make_goto_expr_edges): Temporary hack to prevent + removing blocks with nonlocal labels. + (is_nonlocal_label_block): Return true if DECL_NONLOCAL is set for + the label. + + * tree-dfa.c (alias_leaders): New local array. + (num_alias_leaders): New local variable. + (find_alias_leader): New local function. + (may_access_global_mem): New local function. + (find_may_aliases_for): Call them. + (compute_may_aliases): Allocate and deallocate alias_leaders. + Show alias information if -fdump-tree-...-alias flag is given. + (may_alias_p): Return true if both variables are the same. + (find_refs_in_expr): Strip WFL and NOPs from the parent statement. + If a pointer relocation is due to a function call, assignment from + a global or a function argument, mark the pointer as a may-alias + for global storage. + (dump_referenced_vars): Reformat output. + (dump_variable): Likewise. + + * tree-dump.c (dump_option_value_info): Add entry for TDF_ALIAS. + * tree.h (TDF_ALIAS): Define. + * doc/invoke.texi: Document new flag. + + * tree-flow-inline.h (may_alias_global_mem_p): New function. + * tree-flow.h (enum tree_flags): Add value TF_MAY_ALIAS_GLOBAL_MEM. + (may_alias_global_mem_p): Declare. + + * tree-simple.c (get_base_symbol): Return NULL_TREE, not NULL. + * tree-ssa-ccp.c (tree_ssa_ccp): Remove unused variable. + * tree-ssa-dce.c (need_to_preserve_store): Call + decl_function_context instead of DECL_CONTEXT. + If the symbol may alias global memory, return nonzero. + + * tree-ssa.c (dump_reaching_defs): Reformat output. + (set_currdef_for): Walk the alias leader chain, setting CURRDEF for + all the alias sets that may be affected by the definition. + +2002-12-06 Daniel Berlin + + * tree-dfa.c (may_alias_p): Fix global variables and points-to. + +2002-12-03 Daniel Berlin + + * tree-ssa.c (delete_tree_ssa): Move call to delete_alias_vars + above resetting num_referenced_vars. + +2002-12-03 Diego Novillo + + * Makefile.in: Add dependencies on $(TM_H) and coretypes.h for the + files mentioned below. + * old-tree-inline.c: Include tm.h and coretypes.h. + * c-pretty-print.c: Likewise. + * disjoint-set.c: Likewise. + * tree-alias-ecr.c: Likewise. + * tree-alias-type.c: Likewise. + * tree-alias-ander.c: Likewise. + * tree-alias-steen.c: Likewise. + * tree-alias-common.c: Likewise. + * tree-ssa.c: Likewise. + * tree-ssa-pre.c: Likewise. + * tree-cfg.c: Likewise. + * tree-dfa.c: Likewise. + * tree-optimize.c: Likewise. + * c-simplify.c: Likewise. + * gimplify.c: Likewise. + * tree-browser.c: Likewise. + * simple-break-elim.c: Likewise. + * simple-goto-elim.c: Likewise. + * tree-dchain.c: Likewise. + * c-call-graph.c: Likewise. + * tree-simple.c: Likewise. + * tree-nomudflap.c: Likewise. + * tree-pretty-print.c: Likewise. + * tree-ssa-dce.c: Likewise. + * tree-ssa-ccp.c: Likewise. + * dependence.c: Likewise. + * tree-mudflap.c: Likewise + (mx_xfn_indirect_ref): Use size_type_node instead of c_size_type_node. + +2002-12-03 Diego Novillo + + * tree-dfa.c: Undo this change that causes bootstrap + failures: + + 2002-12-02 Diego Novillo + + * tree-dfa.c (may_alias_p): Artificial variables + can also be aliased. + +2002-12-03 Andreas Jaeger + + * tree-simple.c (right_assocify_expr): Remove unused variable. + +2002-12-02 Andrew MacLeod + + * gimplify.c (simplify_cleanup_point_expr): gsi_stmt can return NULL, + use gsi_end. + * tree-cfg.c (make_blocks): Use gsi_end, gsi_stmt can return NULL. Set + basic_block for empty_stmt_node containers. + (make_edges): Stmt's can be NULL. + (make_ctrl_stmt_edges, make_exit_edges, make_loop_expr_edges, + make_cond_expr_edges, make_goto_expr_edges, is_nonlocal_label_block, + block_invalidates_loop, cleanup_control_flow, cleanup_cond_expr_graph, + cleanup_switch_expr_graph, disconnect_unreachable_case_labels, + find_taken_edge, tree_cfg2dot, successor_block, is_latch_block, + switch_parent, first_stmt, last_stmt): Check for first_stmt() or + last_stmt() returning NULL. + (remove_tree_bb, first_exec_stmt): Use gsi_end. + (last_stmt_ptr): Iterate to find last execuatbel stmt_ptr in a block. + (gsi_start_bb): Return first non-empty stmt, if there is one. + (set_bb_for_stmt): Don't decend into an empty_stmt_node. + * tree-dfa.c (find_tree_refs): Use gsi_end. + (collect_dfa_stats): Use gsi_end_bb. + * tree-flow-inline.h (gsi_step_bb): split. + (gsi_step_in_bb): gsi_step with explicit bb specified. Never return + empty_stmt_node. + (gsi_start_bb): Move to tree-cfg.c. + (gsi_end_bb): New. Have we reached the end of a basic block. + * tree-flow.h (gsi_start_bb): Make external. + (gsi_end_bb, gsi_step_in_bb): New prototypes. + * tree-simple.h (gsi_end): renamed from gsi_after_end. + (gsi_stmt): Return NULL if stmt is an empty_stmt_node or error mark. + * tree-ssa-ccp.c (simulate_block, substitute_and_fold): Use gsi_end. + * tree-ssa-dce.c (mark_control_parent_necessary, find_useful_stmts, + remove_dead_stmts): Use gsi_end_bb. + (process_worklist): Check for NULL last_stmt. + * tree-ssa-pre.c (finalize_1): Use gsi_end_bb, gsi_stmt can be NULL. + +2002-12-02 Diego Novillo + + * tree-dfa.c (dump_ref): Display '' for NULL references. + (dump_phi_args): Handle NULL arguments. + (may_alias_p): Artificial variables can also be aliased. + +2002-12-02 Daniel Berlin + + * tree-ssa-pre.c (okay_injuring_def): inj could be null. + (get_operand): Use instead of special casing INDIRECT_REF and + COMPONENT_REF everywhere. + (names_match_p): Fix. + (defs_match_p): Ignore partial uses. + (rename_2): Fix non-matching condition. + (update_old_new): Update the kills and lefts arrays. + (finalize_1): Set the bb for the new statement. + (update_ssa_for_new_use): Ditto. + (code_motion): Ditto. + (call_modifies_slot): Handle function pointers (where we end up + with a _DECL as our argument). + (pre_part_1_trav): Update the kills and lefts arrays. + Just use TREE_TYPE (ei->expr) for type of expression. + (add_left_occ): New helper function. + (process_left_occs_and_kills): Add other cases we need to handle. + (tree_perform_ssapre): Add new processed array, since for left + occurrences and kills, we need to process *all* statements, not + just ones we might consider candiates for PRE. + +2002-12-02 Diego Novillo + + * tree-dfa.c (find_refs_in_expr): Look for references in + VA_ARG_EXPR nodes. + +2002-12-01 Diego Novillo + + * tree-optimize.c (optimize_function_tree): Undo + inadvertent change in previous commit. + +2002-12-01 Diego Novillo + + * fold-const.c (operand_equal_p): Check for NULL TREE_TYPEs. + + * tree-cfg.c (remove_stmt): Call remove_ref. + (disconnect_unreachable_case_labels): Do not disconnect the edge + going to the block holding the BIND_EXPR node for the switch() + body. + (dump_tree_cfg): Call dump_current_function. + + * Makefile.in (tree-dfa.o): Depend on convert.h. + * tree-dfa.c: Include convert.h. + (remove_def): New local function. + (reset_def_def_links): New local function. + (replace_phi_arg_with): New local function. + (replace_ref_with): New function. + (try_replace_ref_with): Rename from replace_ref_in. + Also look for V_USE references on the LHS of assignments. + When replacing the callee of a CALL_EXPR, make sure that the type + of the new callee is compatible with the old one. + (replace_ref_r): Call operand_equal_p. + (remove_ref): New function. + (same_var_p): New function. + (dump_referenced_vars): Add new flag DETAILS. Update all users. + (debug_referenced_vars): Likewise. + + * tree-ssa.c (dump_reaching_defs): Change output format. + (set_ssa_links): Don't set def-def links for PHI nodes. + + * tree-ssa-ccp.c (replace_uses_in): Add new argument COMMIT. + Update all users. + + * tree-optimize.c (dump_current_function): New function. + (optimize_function_tree): Call it. + * tree.h (dump_current_function): Declare. + * c-decl.c (c_expand_body): Call dump_current_function. + * tree-ssa-dce.c (tree_ssa_eliminate_dead_code): Likewise. + * tree-ssa-pre.c (tree_perform_ssapre): Likewise. + * tree-ssa.c (build_tree_ssa): Likewise. + * tree-ssa-ccp.c (tree_ssa_ccp): Likewise. + Dump variables and reaching definitions if TDF_DETAILS is set. + + * tree-pretty-print.c (print_call_name): Call dump_generic_node for + NOP_EXPR operands. + + * tree-ssa-pre.c: Don't include c-common.h nor c-tree.h + Replace calls to build_modify_expr with build everywhere. + Replace calls to deep_copy_node with copy_node_r everywhere. + +2002-11-29 Andreas Jaeger + + * c-call-graph.c (construct_call_graph): Fix format. + + * tree-alias-ander.c: Declare print_out_result. + + * tree-ssa-pre.c: Declare is_on_lhs and call_modifies_slot. + + * tree.h: Declare expand_asm_expr and add_var_to_bind_expr. + + * tree-inline.c: Declare remap_decls. + +2002-11-28 Daniel Berlin + + * tree-alias-common.h: Start adding doxygen docs. + + * tree-alias-common.c: Ditto + +2002-11-28 Daniel Berlin + + * tree-alias-ander.c: Convert debug defines and ifdefs into + dump_file use. + + * tree.h: Add TDI_pta. + + * tree-dump.c: Add dump-tree-pta and TDI_pta. + +2002-11-28 Diego Novillo + + * Makefile.in (tree-ssa-pre.o, tree-cfg.o, gimplify.o, tree-ssa-dce.o, + tree-ssa-ccp.o): Add dependency on $(TIMEVAR_H). + * timevar.def (TV_TREE_GIMPLIFY, TV_TREE_MAY_ALIAS, + TV_TREE_INSERT_PHI_NODES, TV_TREE_BUILD_FUD_CHAINS, TV_TREE_RDEFS): + New timers. + (TV_TREE_SSA): Remove. + (TV_INTEGRATION, TV_EXPAND): Switch order. + * c-decl.c (c_expand_body): Pop TV_EXPAND before running the tree + optimizers. + * gimplify.c (simplify_function_tree): Push/pop TV_TREE_GIMPLIFY. + * tree-cfg.c (build_tree_cfg): Push/pop TV_TREE_CFG. + * tree-dfa.c (compute_may_aliases): Push/pop TV_TREE_MAY_ALIAS. + * tree-ssa-ccp.c (tree_ssa_ccp): Push/pop TV_TREE_CCP. + * tree-ssa-dce.c (tree_ssa_eliminate_dead_code): Push/pop + TV_TREE_DCE. + Call compute_reaching_defs. + Remove debugging dumps before DCE. + * tree-ssa-pre.c (tree_perform_ssapre): Push/pop TV_TREE_PRE. + * tree-ssa.c (build_tree_ssa): Don't call compute_reaching_defs. + Don't call dump_reaching_defs. + (insert_phi_nodes): Push/pop TV_TREE_INSERT_PHI_NODES. + (build_fud_chains): Push/pop TV_TREE_BUILD_FUD_CHAINS. + (compute_reaching_defs): Push/pop TV_TREE_RDEFS. + Call dump_reaching_defs. + * tree-optimize.c (optimize_function_tree): Remove calls to + timevar_push and timevar_pop. + +2002-11-28 Diego Novillo + + * Makefile.in (tree-ssa.o): Add dependency on $(TIMEVAR_H) and + tree-alias-common.h. + (tree-dfa.o): Likewise. + (tree-optimize.o): Add dependency on $(TIMEVAR_H). + * tree-dfa.c (compute_may_aliases): Move call to delete_alias_vars + * tree-ssa.c (delete_tree_ssa): ... here. + +2002-11-27 Diego Novillo + + * tree-dfa.c (add_may_alias): Remove. Update all users. + (get_alias_index): Remove. Update all users. + (dfa_stats_d): Remove fields num_may_alias, max_num_may_alias, + num_alias_imm_rdefs and max_num_alias_imm_rdefs. Update all users. + (may_alias_p): Make extern. Move declaration to tree-flow.h. + (TRM_DEFAULT): Remove. Update all users. Update values of the + other TRM_* constants. + (create_ref): Don't initialize the PHI argument array with the + number of incoming edges. + (collect_dfa_stats): Do not traverse the function body with + walk_tree. + Free temporary hash table before returning. + (compute_may_aliases): Update comment. + (may_alias_p): Switch arguments if the first argument is not an + INDIRECT_PTR or the artificial global_var. + (find_may_aliases_for): If a pointer aliases a variable, set the + pointer to be the alias leader for the variable. + (ref_defines): Call may_alias_p. + (is_killing_def): Return false if the reaching definition is NULL. + Don't check for volatile definitions. + Change second argument to be a tree. Update all users. + + * tree-flow-inline.h (alias_imm_reaching_def): Remove. Update all + users. + (may_alias): Remove. Update all users. + (set_imm_reaching_def): Check for circularity. + (alias_leader): New function. + (set_alias_leader): New function. + (is_aliased): New function. + (is_default_def): Remove. Update all users. + + * tree-flow.h (struct var_ref_d): Remove field alias_imm_rdefs. + Update all users. + (struct var_def_d): Remove field m_default. Update all users. + (struct tree_ann_d): Remove field may_aliases. Update all users. + Add field alias_leader. + (struct dfa_counts_d): Remove fields num_may_alias and + num_may_alias_imm_rdefs. Update all users. + + * tree-ssa.c: Update documentation on may-alias processing. + (set_ssa_links): Remove third argument. Update all users. + (set_alias_imm_reaching_def): Remove. Update all users. + (create_default_def): Likewise. + (analyze_rdefs): Likewise. + (currdef_for): Move from tree-flow-inline.h + (set_currdef_for): Likewise. + (compute_reaching_defs): Rename from compute_tree_rdefs. Update + all users. + (follow_chain): Call is_killing_def instead of is_partial_def. + (tree_ssa_remove_phi_alternative): Remove unused variable ref. + (set_ssa_links): When processing V_USE references, make sure that + CURRDEF is a definition for the variable or one of its aliases. + +2002-11-26 Sebastian Pop + + * Makefile.in (OBJS): Add tree-browser.o. + (tree-browser.o): New dependency. + * tree-browser.c: New file. + * tree-browser.def: New file. + +2002-11-26 Jason Merrill + + Gimplify C++ cleanups. + * gimplify.c (voidify_wrapper_expr): Split out from... + (simplify_bind_expr): ...here. + (simplify_cleanup_point_expr): New fn. + (simplify_target_expr): New fn. + (gimple_conditional_context): New fn. + (gimple_push_condition, gimple_pop_condition): New fns. + (simplify_expr) [TRY_CATCH_EXPR]: Handle like TRY_FINALLY_EXPR. + * c-simplify.c (simplify_cleanup): New fn. + (c_simplify_stmt): Call it and lang_simplify_stmt. + (simplify_expr_stmt): Wrap the expr in a CLEANUP_POINT_EXPR. + (simplify_return_stmt, simplify_decl_stmt): Likewise. + (simplify_stmt_expr): Handle the STMT_EXPR_NO_SCOPE case. + (is_last_stmt_of_scope): Likewise. + * c-common.h: Declare c_genericize, c_simplify_stmt and + lang_simplify_stmt. + * c-common.c (lang_simplify_stmt): Define. + + Gimplify EXIT_EXPRs. + * gimplify.c (gimplify_loop_expr, gimplify_exit_expr): New fns. + (simplify_expr): Call them. + * expr.c (expand_expr) [LOOP_EXPR]: Pass 1 again for exit_flag. + + * tree-simple.c (right_assocify_expr): Also set TREE_SIDE_EFFECTS. + + * gimplify.c (simplify_expr): Call STRIP_TYPE_NOPS. + [REALPART_EXPR]: Don't just return. + + * tree-pretty-print.c (dump_c_node): Handle REFERENCE_TYPE. + * c-pretty-print.c (dump_c_node): Likewise. Handle null FOR_INIT_STMT. + +2002-11-25 Daniel Berlin + + * config.gcc: Try committing the correct version. + * tree-alias-ander.c (andersen_may_alias): Add "!= NULL" to make + return a bool. + +2002-11-24 Daniel Berlin + + * configure.in: Add --with-libbanshee, passed to us by toplevel if + libbanshee was configured. Substitute appropriate definitions for + Makefile (IE disabling tree-alias-ander building) if it wasn't. + * config.in: Regenerated. + * config.gcc: Rebuild libbanshee with stage1 on darwin to work + around system compiler problem. + * configure: Regenerated. + * Makefile.in: Add banshee stuff. + * tree-alias-ander.c: New file. + * tree-alias-ander.h: New file. + * tree-alias-common.c (get_alias_var): Fix field based stuff. + (find_func_aliases): Don't walk subtrees if we processed the tree. + (ptr_may_alias_var): Fix both field-based and non-field-based lookup. + +2002-11-22 Andrew MacLeod + + * tree-ssa-dce.c (mark_necessary): Split out mark_tree_necessary. Don't + mark if tree is already marked. + (mark_tree_necessary): New. Mark tree without processing control parent. + (mark_control_parent_necessary): Remove recursion, mark trees directly. + (need_to_preserve_store): Can expression/symbol affect external values. + (tree_ssa_eliminate_dead_code): Split. + (find_useful_stmts): Find initial set of needed statements. + (process_worklist): Find statements which calculate needed statements. + (remove_dead_stmts): Delete statements which are dead. + +2002-11-16 Jason Merrill + + Improve tree dumps. + * c-pretty-print.c, tree-pretty-print.c (dump_c_node): Handle + integers larger than a host word. + (op_prio): Handle INIT_EXPR. + * gimplify.c (simplify_bind_expr): Set TREE_SIDE_EFFECTS and type + of void_type_node on the COMPOUND_EXPRs as we walk. + * tree-simple.c (right_assocify_expr): Propagate the type from cur + rather than rhs. + + * c-decl.c (finish_function): Call c_genericize instead of + simplify_function_tree. + * c-simplify.c (c_genericize): New function. + (simplify_stmt_expr): Just genericize. + (simplify_compound_literal_expr): Likewise. + (c_build_bind_expr): Don't build a block for an artificial decl. + (simplify_decl_stmt): Add the variable to the temps list iff it's + artificial. + (c_simplify_expr): Don't call push/pop_context. + * c-decl.c (build_compound_literal): Set DECL_ARTIFICIAL. + * c-tree.h: Declare c_genericize. + + * c-simplify.c (tree_build_scope): Remove. + + Remove INIT_EXPR from GIMPLE. + * c-simplify.c (simplify_decl_stmt): Use MODIFY_EXPR. + * gimplify.c (simplify_bind_expr): Likewise. + (simplify_modify_expr): Convert INIT_EXPR to MODIFY_EXPR. + + * c-simplify.c (create_tmp_var_1): Drop; change all users to call + create_tmp_var. + (gimple_add_tmp_var): Now adds to the external temps list if + available, or directly to the function otherwise. + + Avoid gratuitous unused warnings. + * c-simplify.c (simplify_expr_stmt): Check TREE_SIDE_EFFECTS + directly. Also check for explicit conversions to void. + (expr_has_effect): Remove. + + * Makefile.in (OBJS): Remove tree-dchain.o. + + * stor-layout.c (variable_size): We don't care about + global_bindings_p if the frontend doesn't want a list of the + expressions. + +2002-11-13 Diego Novillo + + * toplev.c (parse_options_and_default_flags): Enable SSA-CCP by + default with optimization >= 1. + * tree-dfa.c (find_refs_in_expr): Clobber '*.GLOBAL_VAR', not + 'GLOBAL_VAR'. + (collect_dfa_stats): Collect statistics on '*.GLOBAL_VAR'. + (compute_may_aliases): Make sure that variable is an INDIRECT_REF. + (may_alias_p): GLOBAL_VAR should alias INDIRECT_REFs. + Only check addressability on VAR_DECLs. + (find_may_aliases_for): Make sure argument is an INDIRECT_REF. + * tree-flow-inline.h (indirect_var): Call DECL_P. + (set_indirect_var): Call DECL_P. + Create annotation if it doesn't exist. + (create_indirect_ref): Move from tree-dfa.c. + * tree-flow.h (create_indirect_ref): Declare. + * tree-ssa-ccp.c (visit_phi_node): Avoid debugging dump from + accessing uninitialized data. + * tree-ssa.c (init_tree_ssa): Create an INDIRECT_REF node for + .GLOBAL_VAR. + +2002-11-12 Diego Novillo + + * tree-cfg.c (delete_tree_cfg): Call free_aux_for_blocks. + Call free_basic_block_vars. + + * gimplify.c (simplify_expr): VA_ARG_EXPR nodes are in GIMPLE form + already. + Gimplify BIT_FIELD_REF nodes. + (simplify_call_expr): Update comment. + * tree-dfa.c (find_refs_in_expr): VA_ARG_EXPR nodes make no + data references. + Handle BIT_FIELD_REF nodes. + * tree-pretty-print.c (op_prio): Don't write an error message if + the operand is not recognized. + * tree-simple.c (is_simple_unary_expr): Handle BIT_FIELD_REFs. + (is_simplifiable_builtin): Only return false for MD builtins. + +2002-11-08 Diego Novillo + + * tree-cfg.c (cleanup_switch_expr_graph): Handle edges going to + EXIT_BLOCK_PTR. + (first_stmt): Return NULL for ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR and + INVALID_BLOCK. + * tree-dfa.c (find_refs_in_expr): Call mark_not_simple. + +2002-11-07 Diego Novillo + + * Makefile.in (tree-ssa.o, tree-cfg.o, tree-dfa.o): Add dependency + on function.h + * tree-cfg.c: Include function.h. + (build_tree_cfg): Set dump_file to NULL after closing the file. + (remove_tree_bb): Don't dump warnings about statements being + removed. + (dump_tree_cfg): Use current_function_name. + Check that the flowgraph is not empty before dumping the function + body. + (tree_cfg2dot): Use current_function_name. + * tree-dfa.c: Include function.h + (dump_dfa_stats): Use current_function_name. + * tree-optimize.c (optimize_function_tree): Set dump_file to NULL + after closing the file. + * tree-pretty-print.c (dump_generic_node): Make sure that the + flowgraph exists before displaying block boundaries. + * tree-ssa-ccp.c (tree_ssa_ccp): Set dump_file to NULL after + closing the file. + * tree-ssa.c: Include function.h. + (build_tree_ssa): Set tree_ssa_dump_file to NULL after closing the + file. + (dump_reaching_defs): Use current_function_name. + (dump_tree_ssa): Likewise. + +2002-11-07 Diego Novillo + + * tree-cfg.c (successor_block): Return EXIT_BLOCK_PTR if no + successor can be found while walking the nesting chain. + +2002-11-07 Diego Novillo + + * tree-cfg.c: Fix some formatting in code and comments. + (set_bb_for_stmt): Move from tree-flow-inline.h + * tree-dfa.c: Fix some formatting in code and comments. + * tree-flow-inline.h: Likewise. + * tree-flow.h: Likewise. + * tree-ssa.c: Likewise. + +2002-11-06 Diego Novillo + + * Makefile.in (tree-ssa-ccp.o): Add dependency on tree-inline.h + * tree-cfg.c (find_taken_edge): New function. + (cleanup_cond_expr_graph): Call it. + (disconnect_unreachable_case_labels): Call it. + + * tree-dfa.c (struct clobber_data_d): Remove field + parent_expr_p. Update all users. + (find_refs_in_expr): Remove argument parent_expr_p. Update all users. + (create_ref): Remove arguments parent_expr_p and operand_p. Update + all users. + (replace_ref_in): Rename from replace_ref_operand_with. Update all + users. Find the operand in the statement and replace it with a new + operand. + (replace_ref_r): New local function. + (is_killing_def): Also handle V_PHI references. + (output_ref): Move from tree-flow-inline.h + + * tree-flow-inline.h (ref_expr): Remove. Update all users. + (restore_ref_operand): Remove. Update all users. + (set_output_ref): Remove. Update all users. + (is_assignment_stmt): New function. + (is_may_def, is_may_use, is_partial_def, is_partial_use, + is_volatile_def, is_volatile_use, is_default_def, + is_clobbering_def, is_initializing_def, is_relocating_def, + is_addressof_use, is_pure_use): Check reference type first. + (is_pure_def): New function. + + * tree-flow.h (struct tree_ref_common): Remove fields expr_p, + operand_p and orig_operand. Update all users. + (struct tree_ann_d): Remove field output_ref. Update all users. + + * tree-ssa-ccp.c: Include tree-inline.h. + (simulate_block): Simulate every statement in the block, not its + references + (simulate_def_use_chains): Simulate statements containing uses + reached by the definition. + (substitute_and_fold): Traverse statements, not references. + Call fold_stmt. + (visit_phi_node): If PHI node is marked volatile, assume varying. + (visit_stmt): Rename from visit_expression_for. Work on a + statement, not a reference. + (visit_assignment): Rename from visit_assignment_for. Work on a + statement, not a reference. + (visit_cond_stmt): Rename from visit_condexpr_for. Work on a + statement, not a reference. + (evaluate_stmt): Rename from evaluate_expr. Work on a statement, + not a reference. + (initialize): Initialize special definitions to varying. + (replace_uses_in): Work on a statement, not an expression. + (fold_stmt): Rename from ccp_fold. Work on a statement, not an + expression. + (get_rhs): New local function. + (set_rhs): New local function. + +2002-11-06 Daniel Berlin + + * tree-flow.h: Prototype set_bb_for_stmt, last_stmt_ptr, + add_ephi_arg, num_ephi_args, set_ephi_arg, ephi_arg. + (enum tree_ref_type): Add E_LEFT, E_KILL, E_EXIT. + + * tree-cfg.c (set_bb_for_stmt): Move to tree-flow-inline.h. + (last_stmt_ptr): New function, gives pointer to last statement in + bb. + + * tree-flow-inline.h: Add exprref_processed, exprref_processed2, + expruse_phi, num_ephi_args, set_ephi_arg, ephi_arg, add_ephi_arg. + + * tree-dfa.c (tree_ref_structure): Handle E_{LEFT,KILL,EXIT}. + (ref_type_name): Ditto. + (tree_ref_size): Ditto. + (dump_ref): E_PHI's phi_args is now a varray of phi_arg structs. + (add_ephi_arg): New function. + (remove_ref_from_list): Fix crash when node not found. + (compute_may_aliases): Add timing for points-to analysis. + + * timevar.def: Add TV_TREE_PTA. + + * tree-ssa-pre.c: Start of massive cleanup and rewriting (in + preparation for load/store PRE). No more uses of ref_expr, proper + call handling. Started removing unnecessary structures and lists, + started removing redundant and inefficient operations (IE O(n^2) + loops to process all phi operands, etc). Basic load PRE implemented. + Code may look ugly due to large pieces commented out waiting for DFA + updating of refs to redo. + +2002-11-05 Diego Novillo + + * tree-cfg.c (create_block_annotations): New local function. + (create_bb_ann): Remove. Update all users. + (parent_array): New local variable. + (build_tree_cfg): Initialize it. + Call create_block_annotations. + (create_bb): Call alloc_block instead of ggc_alloc to allocate + memory for basic blocks. + Don't call set_parent_block. + Grow array parent_array. + (dump_tree_cfg): Change meaning of second argument. Make it accept + any of the TDF_* flags defined in tree.h. + (delete_tree_cfg): Call free_aux_for_blocks. + Free array parent_array. + * tree-flow-inline.h (get_filename): New function. + (is_exec_stmt): return false if T is error_mark_node. + * tree-flow.h (struct var_ref_d): Mark alias_imm_rdefs field for + garbage collection. + (get_filename): Declare. + (struct bb_ann_d): Rename from bb_ann_def. + Remove garbage collection markers. + (referenced_vars): Mark for garbage collection. + (global_var): Likewise. + (create_bb_ann): Remove. + * tree-optimize.c (optimize_function_tree): Remove CFG and SSA + after debugging dumps. + + * diagnostic.h (print_generic_stmt): Rename from print_generic_tree. + Update all users. + (print_generic_expr): Rename from print_generic_node. Update all + users. + (PPF_BRIEF): Remove. Update all users. + (PPF_BLOCK): Remove. Update all users. + (PPF_LINENO): Remove. Update all users. + (PPF_IS_STMT): Remove. Update all users. + * flags.h (flag_dump_tree_all_ssa): Remove. Update all users. + * toplev.c (f_options): Remove entry for -fdump-tree-all-ssa. + Update all users. + * tree-dump.c (dump_enable_all): Rename from dump_enable_all_ssa. + Update all users. + (dump_files): Add entry for -fdump-tree-all. + (dump_option_value_info): Remove entries for TDF_REFS and + TDF_RDEFS. + Add entry for TDF_BLOCK. + (dump_switch_p): If -fdump-tree-all was given, call dump_enable_all. + * tree-pretty-print.c (PPF_BRIEF): Remove. Update all users. + (PPF_BLOCK): Remove. Update all users. + (PPF_LINENO): Remove. Update all users. + (PPF_IS_STMT): Remove. Update all users. + (dumping_stmts): New local variable. + (print_generic_stmt): Rename from print_generic_tree. Update all + users. + Set dumping_stmts to true. + (print_generic_expr): Rename from print_generic_node. Update all + users. + Set dumping_stmts to false. + (maybe_init_pretty_print): Set last_bb to -1. + (dump_block_info): If available, dump file and line number + information for the first statement in the basic block. + * tree-ssa.c (build_tree_ssa): Dump referenced variables and + reaching definition information if -details is given. + * tree.h (enum tree_dump_index): Rename TDI_all to TDI_tu. Update + all users. + Add new index TDI_all. + (TDF_DETAILS): Change value. + (TDF_REFS): Remove. Update all users. + (TDF_RDEFS): Remove. Update all users. + (TDF_BLOCK): Define. + * doc/invoke.texi: Update documentation for -fdump-tree-... flags. + +2002-11-05 Frank Ch. Eigler + + * tree-mudflap.c (mudflap_enqueue_decl, _constant): Use + size_in_bytes, not c_size_in_bytes. + (mf_init_extern_trees): Import uintptr_t typedef node from + mf-runtime.h. + +2002-11-01 Diego Novillo + + * tree-cfg.c (remove_tree_bb): Add new argument remove_stmts. + Update all callers. + (make_ctrl_stmt_edges): Add an edge to the body of a SWITCH_EXPR. + (make_cond_expr_edges): Don't try to linearize the if() subgraph. + (make_case_label_edges): Don't remove the fallthru edge from the + entry block to the switch() subgraph. + (cleanup_tree_cfg): Call cleanup_control_flow. + (remove_unreachable_blocks): Remove blocks of compound structures + before removing the entry block. + (remove_blocks): New local function. + (blocks_unreachable_p): New local function. + (is_nonlocal_label_block): New local function. + (find_subblocks): New local function. + (is_parent): New local function. + (gsi_remove): New function. + (remove_stmt): New local function. + (cleanup_control_flow): New local function. + (cleanup_cond_expr_graph): New local function. + (cleanup_switch_expr_graph): New local function. + (disconnect_unreachable_case_labels): New local function. + + * tree-dfa.c (remove_decl): New function. + (find_decl_location): New function. + + * tree-flow.h (gsi_remove): Declare. + (remove_decl): Declare. + (find_decl_location): Declare. + + * tree-ssa-ccp.c (optimize_unexecutable_edges): Remove. Update all + users. + (ssa_ccp_df_delete_unreachable_insns): Remove. Update all users. + (tree_ssa_ccp): Call print_generic_tree with PPF_BLOCK. + +2002-10-31 Diego Novillo + + * tree-dfa.c (create_indirect_ref): New local function. + (find_refs_in_expr): Call it. + (create_ref): Check E_* reference types with == instead of &. + (dump_ref): Likewise. + (count_tree_refs): Likewise. + * tree-ssa.c (set_ssa_links): Update documentation comment for + save_chain. + +2002-10-31 Diego Novillo + + * tree-cfg.c (remove_tree_bb): Don't walk beyond the end of the + basic block. + +2002-10-26 Daniel Berlin + + * flags.h: Remove flag_tree_points_to from here. + * toplev.c: Include tree-alias-common.h. + (flag_tree_points_to): Now of type enum pta_type, rather than + int. + (lang_independent_options): Remove flag_tree_points_to. + (display_help): Display help for tree-points-to here. + (decode_f_option): Allow selecting of points-to algorithm. + * tree-alias-common.c (varmap): Removed. + (alias_annot): Changed to a hash table. Update all functions + appropriately. + (FIELD_BASED): New macro, switches between field-based analysis, + and field-independent analysis (field-based isn't quite done yet). + (alias_annot_entry): New, used in hash table. + (annot_eq): New function. + (annot_hash): New function. + (find_func_aliases): Handle casts, fix indendation. + (splaycount): Removed. + (splay_tree_count): Removed. + (display_points_to_set): Removed. + (splay_tree_size): Removed. + (alias_get_name): New function. + (ptr_may_alias_var): Globals are a bit funky to handle. + * tree-alias-steen.c: Use alias_get_name, rather than + print_generic_node. + (steen_simple_assign): Handle assignment of PTF's. + (test_assign): Remove. + * tree-alias-common.h (enum pta_type): New. + (alias_get_name): New. + (flag_tree_points_to): New. + +2002-10-26 Diego Novillo + + * tree-cfg.c (cleanup_tree_cfg): Uncomment call to + compact_blocks. + +2002-10-26 Diego Novillo + + * Makefile.in (tree-pretty-print.o): Depend on $(TREE_FLOW_H) + * basic-block.h (BB_COMPOUND_ENTRY): Rename from BB_CONTROL_ENTRY. + * diagnostic.h (dump_generic_tree): Remove extern declaration. + (print_generic_node_brief): Remove. Update all users. + (PPF_BRIEF): Declare. + (PPF_BLOCK): Declare. + (PPF_LINENO): Declare. + (PPF_IS_STMT): Declare. + * tree-pretty-print.c (PPF_BRIEF): New constant. + (PPF_BLOCK): New constant. + (PPF_LINENO): New constant. + (PPF_IS_STMT): New constant. + (dump_block_info): New local function. + (last_bb): New local variable. + (dump_generic_tree): Remove unused function. + (print_generic_tree): Add third argument 'flags'. Update all + users. + (print_generic_node_brief): Remove. Update all users. + (print_generic_node): Add third argument 'flags'. Update all + users. + (dump_generic_node): Add third argument 'flags'. Update all users. + If PPF_BLOCK is set, display basic block information at basic block + boundaries. + If PPF_IS_STMT is set, change the way COMPOUND_EXPR nodes are + rendered. + If PPF_BRIEF is set, don't show the bodies of control statements. + (print_declaration): + + * toplev.c (process_options): Update comment for -fdisable-simple. + + * tree-cfg.c (remove_tree_bb): Rename from tree_delete_bb. + (latch_block): Move declaration to tree-flow.h. Declare extern. + (make_blocks): Start a new block after finding a control flow + altering statement. + (make_loop_expr_blocks): Set the loop entry block to be the parent + block for the loop latch block. + (cleanup_tree_cfg): Rename from tree_cleanup_cfg. + Call compact_blocks. + (remove_tree_bb): Rename from tree_delete_bb. Update all users. + (dump_tree_bb): Rename from dump_tree_bb. Update all users. + Dump information about loop latch blocks. + (debug_tree_bb): Rename from tree_debug_bb. Update all users. + (debug_tree_cfg): Rename from tree_debug_cfg. Update all users. + (dump_tree_cfg): Rename from tree_dump_cfg. Update all users. + By default, dump the function with markers for basic block + boundaries. + (successor_block): If we can't find a successor following the + parent chain, return the next block in the linked list of blocks. + Update documentation comments. + (stmt_starts_bb_p): Don't let RETURN_EXPR start a new block. + (is_latch_block): New function. + (first_exec_stmt): Don't treat BIND_EXPR nodes as a special case. + (first_stmt): Return NULL_TREE if the block does not exist. + (last_stmt): Likewise. + + * tree-dfa.c (find_tree_refs): Rename from tree_find_refs. Update + all users. + (find_refs_in_stmt): Handle BIND_EXPR nodes. + (rli_start): Move from tree-flow-inline.h + (rli_start_last): Likewise. + (rli_start_at): Likewise. + (rli_delete): Likewise. + + * tree-flow-inline.h (gsi_start_bb): Handle NULL blocks. + (ref_list_is_empty): New function. + * tree-flow.h (rli_start): Change declaration to extern. + (rli_start_last): Likewise. + (rli_start_at): Likewise. + (rli_delete): Declare. + (latch_block): Declare. + (is_latch_block): Declare. + (get_last_ref): Change to inline declaration. + (get_first_ref): Likewise. + (ref_list_empty): Declare. + + * tree-optimize.c (delete_tree_ssa): Remove declaration. + + * tree-ssa-dce.c (mark_control_parent_necessary): Call gsi_step_bb + instead of gsi_step. + (tree_ssa_eliminate_dead_code): Likewise. + + * tree-ssa.c (compute_tree_rdefs): Rename from compute_tree_rdefs. + Update all users. + +2002-10-22 Diego Novillo + + * tree-dfa.c (struct dfa_stats_d): Add field size_tree_refs. + (tree_ref_size): New function. + (create_ref): Call it. + (dump_dfa_stats): Get total size from dfa_stats.size_tree_refs. + (count_tree_refs): Call tree_ref_size. + * tree-flow-inline.h (get_last_ref): New function. + (get_first_ref): New function. + * tree-flow.h (struct var_ref_d): Rename from var_ref. + (struct var_def_d): Rename from var_def. + (struct var_phi_d): Rename from var_phi. + (struct var_use_d): Rename from var_use. + (struct expr_phi_d): Rename from expr_phi. + (struct expr_use_d): Rename from expr_use. + * tree-ssa-ccp.c (tree_ssa_ccp): Call get_last_ref. + +2002-10-21 Daniel Berlin + + * timevar.def: Add TV_TREE_{PRE,CCP,DCE,CFG,SSA}} timevars. + + * tree-optimize.c (optimize_function_tree): Push and pop timevars + for the tree optimizers. + +2002-10-21 Diego Novillo + + * Makefile.in (OBJS): Move tree-mudflap.o ... + (C_AND_OBJC_OBJS): ... here. + +2002-10-21 Diego Novillo + + * tree-flow-inline.h (rli_start): New function. + (rli_start_rev): New function. + (rli_start_at): New function. + (rli_after_end): New function. + (rli_step): New function. + (rli_step_rev): New function. + (rli_ref): New function. + * tree-flow.h (struct ref_list_iterator): Declare. + (FOR_REF_BETWEEN, FOR_EACH_REF, FOR_EACH_REF_REV): Replace with new + rli_* iterator functions. Update all users. + +2002-10-21 Frank Ch. Eigler + + * tree-cfg.c (make_blocks): Ignore TRY_FINALLY_EXPR and + TRY_CATCH_EXPR. + * tree-mudflap.c (mx_register_decls): Ignore local decls + of extern variables of unknown size. + +2002-10-20 Daniel Berlin + + * tree-ssa-pre.c (repair_injury): DTRT, rather than abort. + + * tree-dfa.c (ref_type_name): E_* don't have these modifier + fields, but may have the same bits set, so don't print the + modifiers on them. + + * gimplify.c (create_tmp_var): New function, wraps calls to + create_tmp_var_1 with pushing/popping of right context. + All internal gimplify.c now use create_tmp_var_1. + (create_tmp_var_noc): New function, create the var without + pushing/popping, and without exposing internals of create_tmp_var_1. + Only one use of this. + + * tree-simple.h (create_tmp_var_noc): New prototype. + + * c-simplify.c (simplify_stmt_expr): create_tmp_var changed to + create_tmp_var_noc. + + * tree-ssa-pre.c: Add WAITING_FOR_DFA_UPDATE around code waiting for DFA + functions to keep refs up to date. + (add_call_to_ei): occurs and occurstmts is now an + array of tree pointers, not trees. Update approriately. + (insert_occ_in_preorder_dt_order_1): Ditto. + (tree_perform_ssapre): Ditto. + (find_use_for_var): Removed function. + (orig_expr_map): Removed global, removed uses. + (struct ei): Added injfixups member. + (is_strred_cand): STRIP_WFL the expression. + (calculate_increment): Ditto. + (is_injuring_def): Ditto. + (defs_y_dom_x): Ditto. Also account for fact that y is now a full + expression, not just an RHS. + (defs_match_p): Ditto (t2 is no longer just an RHS). + (finalize_1): Do insertion by replacement. + (repair_injury): Clean up, do insertion by replacement. + (find_reaching_def_of_var): Do backwards search in a cleaner way. + (update_ssa_for_new_use): Change how we do replacement. + (code_motion): Insertion by replacement. Print EXPR_WFL_LINENO, not + STMT_LINENO. + (pre_part_1_trav): Just create_tmp_var will now suffice. + +2002-10-18 Diego Novillo + + * tree-dfa.c (find_refs_in_expr): Change type of second argument to + enum tree_ref_type. Add third argument ref_mod. Update all users. + (create_ref): Add third argument ref_mod. Decode bitmask to set + the individual bitfields in the new reference. + * tree-flow-inline.h (is_may_ref): New function. + (is_may_def): New function. + (is_may_use): New function. + (is_partial_ref): New function. + (is_partial_def): New function. + (is_partial_use): New function. + (is_volatile_ref): New function. + (is_volatile_def): New function. + (is_volatile_use): New function. + (is_default_def): New function. + (is_clobbering_def): New function. + (is_initializing_def): New function. + (is_relocating_def): New function. + (is_addressof_use): New function. + (is_pure_use): New function. + * tree-flow.h (V_DEF, V_USE, V_PHI, E_PHI, E_USE, E_KILL): Redefine + inside enum tree_ref_type. Update all users. + (enum tree_ref_type): Define. + (TRM_DEFAULT, TRM_CLOBBER, TRM_MAY, TRM_PARTIAL, TRM_INITIAL, + TRM_VOLATILE, TRM_RELOCATE): Rename from M_*. Update all users. + (struct tree_ref_common): Change type of field 'type' to enum + tree_ref_type. Update all users. + (struct var_ref): Add bitfields 'm_may', 'm_partial' and 'm_volatile'. + (struct var_def): Add bitfield 'm_default', 'm_clobber', 'm_initial' + and 'm_relocate'. + (struct var_use): Add bitfield 'm_addressof'. + (ref_type): Change return type to enum tree_ref_type. Update all + users. + (create_ref): Add new argument ref_mod. Update all users. + (function_may_recurse_p): Change return type to bool. Update all + users. + (ref_type_name): Change argument type to tree_ref. Update all + users. + (validate_ref_type): Remove. + +2002-10-18 Diego Novillo + + * cp/Make-lang.in (CXX_C_OBJS): Remove tree-cfg.o, tree-dfa.o, + tree-optimize.o, tree-ssa.o, tree-ssa-pre.o, gimplify.o, tree-simple.o, + tree-alias-steen.o, tree-alias-ecr.o, tree-alias-type.o, + disjoint-set.o, tree-ssa-ccp.o, tree-dchain.o, tree-alias-common.o, + and tree-ssa-dce.o. + +2002-10-17 Diego Novillo + + * Makefile.in (TREE_FLOW_H): Add bitmap.h, basic-block.h, + hard-reg-set.h and tree-simple.h. Update all users. + (C_AND_OBJC_OBJS): Move tree-cfg.o, tree-dfa.o, + tree-ssa.o, tree-optimize.o, c-simplify.o, c-call-graph.o, + tree-simple.o, simple-break-elim.o, simple-goto-elim.o, tree-dchain.o, + tree-ssa-pre.o, tree-alias-type.o, tree-mudflap.o, gimplify.o, + tree-alias-ecr.o, tree-alias-common.o, tree-alias-steen.o, + disjoint-set.o, tree-ssa-ccp.o and tree-ssa-dce.o ... + (OBJS): ... here. + (gimplify.o): Add dependency on $(TREE_FLOW_H). + (tree-pretty-print.o): New rule. + (GTFILES): Add tree-flow.h + * c-config-lang.in (gtfiles): Remove tree-flow.h + * c-simplify.c (copy_if_shared_r, unmark_visited_r, + unshare_all_trees, mark_not_simple): Move ... + * gimplify.c: ... here. + Include tree-flow.h + * tree-flow.h: Include hard-reg-set.h. + + * c-common.h (print_c_tree, print_c_node, print_c_node_brief, + debug_c_tree, debug_c_node, debug_c_node_brief): Move declarations + from diagnostic.h. + * c-call-graph.c (construct_call_graph): Call get_name. + (print_callee): Likewise. + * c-pretty-print.c (print_declaration): Declare static. + (print_function_decl): Likewise. + (print_struct_decl): Likewise. + (dump_c_tree): Likewise. + (dump_c_node): Likewise. + * diagnostic.h (dump_generic_tree, dump_generic_node, + print_generic_tree, print_generic_node, print_generic_node_brief): + Declare. + * tree-pretty-print.c: New file. + * c-decl.c: Replace calls to print_c_node with print_generic_node. + * tree-alias-common.c: Likewise. + * tree-alias-steen.c: Likewise. + * tree-cfg.c: Likewise. + * tree-dfa.c: Likewise. + * tree-mudflap.c: Likewise. + * tree-optimize.c: Likewise. + * tree-ssa-ccp.c: Likewise. + * tree-ssa-pre.c: Likewise. + * tree-ssa-dce.c: Likewise. + Don't include c-common.h nor c-tree.h + (tree_ssa_eliminate_dead_code): Don't call COMPOUND_BODY. + Replace ASM_STMT with ASM_EXPR. Don't check for EXPR_STMT. + +2002-10-17 Daniel Berlin + Diego Novillo + + * tree-cfg.c (remove_bb_ann): Remove. Update all users. + (delete_tree_cfg): Set bb->aux to NULL in all basic blocks. + * tree-dfa.c: Remove extern declaration for tree_find_refs. + (create_ref_list): Allocate new list with ggc_alloc. + (empty_ref_list): Just set first and last element to NULL. + (delete_ref_list): Remove. Update all users. + (remove_ref_from_list): Don't call free. + (add_ref_to_list_begin): Allocate new node with ggc_alloc. + (add_ref_to_list_end): Likewise. + (add_ref_to_list_after): Likewise. + (create_ref): Call BITMAP_GGC_ALLOC. + (remove_tree_ann): Remove. Update all users. + (tree_ref_structure): New function. + * tree-flow.h (edge, basic_block): Forward declare if necessary. + (struct ref_list_node): Mark for garbage collection. + (struct ref_list_priv): Likewise. + (struct tree_ref_common): Likewise. + (struct var_ref): Likewise. + (struct var_def): Likewise. + (struct var_phi): Likewise. + (struct var_use): Likewise. + (struct phi_node_arg_d): Likewise. + (struct expr_ref_common): Likewise. + (struct expr_phi): Likewise. + (struct expr_use): Likewise. + (union tree_ref_d): Likewise. + (struct tree_ann_d): Likewise. + (struct bb_ann_def): Likewise. + (referenced_vars): Likewise. + (global_var): Likewise. + (enum tree_ref_structure_enum): New. + (call_sites): Remove unused function. + * tree-inline.c (copy_tree_r): Copy the 'ann' field from tree_common. + * old-tree-inline.c (copy_tree_r): Likewise. + * tree-ssa.c (added): Mark for garbage collection. + (in_work): Likewise. + (work_stack): Likewise. + (delete_tree_ssa): Set global_var to NULL_TREE. + * tree.h (struct tree_ann_d): Forward declare. + (struct tree_common): Rename field 'aux' to 'ann'. Update all + users. Don't mark it 'skip' for garbage collection. + +2002-10-16 Daniel Berlin + + * tree-dfa.c (compute_may_aliases): Call create/delete_alias_vars + if flag_tree_points_to is on. + (may_alias_p): Use points-to info if user asked us to generate it. + + * tree-optimize.c (optimize_function_tree): Don't call + create_alias_vars here. + +2002-10-16 Diego Novillo + + * tree-cfg.c (make_cond_expr_edges): If the conditional has known + value, only make the edge to the corresponding branch. + (tree_delete_bb): Write a warning to the dump file when removing + blocks with executable statements. + (first_exec_stmt): Skip over empty BIND_EXPR blocks. + + * tree-dfa.c (find_refs_in_expr): Don't look for references in non + GIMPLE statements. + (remove_tree_ann): Clear the annotation with memset. + (collect_dfa_stats_r): Don't call tree_annotation. + (find_may_aliases_for): Avoid adding the same alias more than once. + (may_alias_p): Fix comment grammar. + + * tree-flow-inline.h (is_exec_stmt): New function. + * tree-flow.h (FOR_EACH_REF): Guard against NULL lists. + (FOR_EACH_REF_REV): Likewise. + (is_exec_stmt): Declare. + + * tree-ssa-ccp.c (visit_phi_node): Reformat debug dumping output. + (visit_expression_for): Move check for clobbering definitions + before check for NULL expressions. + (visit_condexpr_for): Reformat debug dumping output. + (set_lattice_value): Remove stale comments. + (replace_uses_in): Don't clear TF_FOLDED flag from expression. + + * tree-ssa.c (add_phi_node): If possible, associate the PHI node to + a statement. + (create_default_def): Create initial declarations for static + variables with DECL_INITIAL set. + (delete_tree_ssa): Remove annotations from variables. + +2002-10-16 Daniel Berlin + + * tree-alias-type.c (alias_tvar_new_with_aterm): New function. + Update all allocations to allocate right type, rather than the union. + Update to use macros to access members of alias_typevar. + + * tree-alias-type.h: Split alias_typevar into a common, an ECR, and + an aterm, update all users. + Add macros to access members of union. + + * tree-alias-common.c (create_alias_var): Handle function_decl's + properly (needed for proper handling of function pointers). + Updates for macros to access typevars. + Fix some indentation. + + * tree-alias-steen.c: Updates for macros to access typevars. + +2002-10-16 Frank Ch. Eigler + + * c-decl.c (c_expand_body): Enable mudflap, only for gimple. + * c-pretty-print.c (dump_c_node): Render try/catch/finally exprs. + (op_prio): Accept BIND_EXPRs. + * gcc.c (cpp_unique_options): Make -fmudflap -include mf-runtime.h. + * toplev.c (process_options): Complain on -fmudflap -fdisable-simple. + * tree-mudflap.c (*): Reorganize for generic/gimple operation. + (mf_init_extern_trees): Extract decl nodes from -include'd file. + (mf_external_ref, mf_decl_extern_trees): Removed; updated callers. + (mf_offset_expr_of_array_ref): Don't bother store index type as + TREE_PURPOSE. + (mf_build_check_statement_for): Use GIMPLE tree types and builders. + (mx_register_decls): New function, replacing mx_register_decl. + (mx_xfn_xform_decls): Support only GIMPLE input tree types. + (mf_flush_enqueued_calls): Clean up enqueued call statements. + +2002-10-14 Diego Novillo + + * toplev.c (parse_options_and_default_flags): Undo local + hack that slipped in the previous commit. + +2002-10-14 Diego Novillo + + * Makefile.in (c-decl.o): Add dependency on diagnostic.h. + * c-decl.c: Include diagnostic.h + (c_expand_body): Call get_name. + + * basic-block.h (struct basic_block_def): Rename head_tree to + head_tree_p and end_tree to end_tree_p. Change type to tree *. + Update all users. + (BLOCK_HEAD_TREE): Remove. Update all users. + (BLOCK_END_TREE): Remove. Update all users. + * tree-cfg.c (build_tree_cfg): Return if function body is empty. + (make_blocks): Change first argument to tree *. Update all users. + (make_bind_expr_blocks): Likewise. + (make_loop_expr_blocks): Likewise. + (make_cond_expr_blocks): Likewise. + (make_switch_expr_blocks): Likewise. + (create_bb): Likewise. + (first_exec_block): Likewise. + (first_exec_stmt): Likewise. + (tree_delete_bb): Use a gimple statement iterator to unmap + statements. + (insert_stmt_before): Remove empty function. + (replace_expr_in_tree): Remove. Update all users. + (find_expr_in_tree_helper): Likewise. + (find_expr_in_tree): Likewise. + (first_stmt): Call STRIP_NOPS. + (last_stmt): Call STRIP_NOPS. + + * tree-dfa.c (struct clobber_data_d): Rename parent_stmt to + parent_stmt_p and parent_expr to parent_expr_p. Change types to + tree *. Update all users. + (find_refs_in_stmt): Change first argument type to tree *. Update + all users. + (find_refs_in_expr): Chnage arguments parent_stmt and parent_expr + to tree *. Update all users. + (create_ref): Don't add the same reference twice on the same list + when parent_stmt and parent_expr are the same node. + Don't set output_ref when the parent statement is not in GIMPLE + form. + (replace_ref_operand_with): Move from tree-flow-inline.h + (replace_ref_expr_with): New function. + (replace_ref_stmt_with): New function. + (create_tree_ann): Abort if trying to annotate certain nodes. + Don't create an empty ref list. + In the presence of WFL or NOPS wrappers, add the annotation to the + inner node. + (dump_ref): Don't call tree_annotation to access the tree + annotation. + + * tree-flow.h (struct tree_ref_common): Rename field stmt to stmt_p + and field expr to expr_p. Change types to tree *. Update all + users. + (replace_ref_expr_with): Declare. + (replace_ref_stmt_with): Declare. + (insert_stmt_before, insert_stmt_after, replace_expr_in_tree, + find_expr_in_tree): Remove. + * tree-flow-inline.h (ref_expr): Return NULL_TREE if expr_p is + NULL. + (ref_stmt): Return NULL_TREE if stmt_p is NULL. + (tree_annotation): Call STRIP_WFL and STRIP_NOPS before returning + the annotation. + (add_tree_ref): Remove consistency checks. Create an empty list + the first time. + (get_lineno): Return -1 on NULL_TREE. + (set_output_ref): Remove consistency. + (set_tree_flag): Likewise. + (clear_tree_flag): Likewise. + (reset_tree_flags): Likewise. + * tree-simple.h (gimple_stmt_iterator): Rename ptr to tp. Change + type to tree *. Update all users. + (gsi_start): Change argument type to tree *. Update all users. + (gsi_stmt_ptr): New function. + (gsi_container): New function. + + * tree-optimize.c (optimize_function_tree): Don't test fnbody for + NULL. + Re-enable optimizers. + * tree-ssa-ccp.c: Update documentation comments. + Don't include c-common.h and c-tree.h. + (tree_ssa_ccp): Don't call COMPOUND_BODY. + (ccp_fold): New private function. + (substitute_and_fold): Call it. + Call replace_ref_expr_with. + Set TF_FOLDED flag on the statement, not the expression. + (visit_assignment_for): Call STRIP_NOPS and STRIP_WFL. + (evaluate_expr): Call ccp_fold. Only use the RHS of the simplified + value in the case of MODIFY_EXPR or INIT_EXPR. + (restore_expr): + * tree-ssa-dce.c (mark_control_parent_necessary): Use a gimple + iterator. + (tree_ssa_eliminate_dead_code): Likewise. + * tree-ssa-pre.c: Disable and add warning comments for out-of-date + calls to create_ref, find_refs_in_stmt and replace_expr_in_tree. + +2002-10-12 Daniel Berlin + + * tree-alias-type.h (alias_typevar_def): Add struct aterm + as a temporary hack for andersen's analysis. + * tree-alias-common.c (current_alias_ops): New, use it + instead of referring to steen_alias_ops everywhere. + (get_alias_var): Use STRIP_WFL. + (find_func_aliases): Ditto. + (create_alias_vars): Call init function, move deletion to + delete_alias_vars. + (delete_alias_vars): New function, move deletion code to here. + (get_virtual_var): Removed. + (ptr_may_alias_var): New function. + * tree-alias-common.h (struct tree_alias_ops): Add may_alias + function. + * tree-alias-steen.c (steen_may_alias): New function. + +2002-10-10 Falk Hueffner + + * diagnostic.h (dump_c_tree, dump_c_node, + print_declaration, print_function_decl, + print_struct_decl): Fix argument types. + +2002-10-10 Diego Novillo + + * tree.h (struct tree_common): Rename field unused_0 to + not_gimple_flag. + (TREE_NOT_GIMPLE): Define. + * c-simplify.c (mark_not_simple_r): Remove. Update all users. + (mark_not_simple): Set TREE_NOT_GIMPLE. + * gimplify.c (simplify_call_expr): Enable call to mark_not_simple. + * tree-flow.h (TF_NOT_SIMPLE): Remove. Update all users. + + * tree-cfg.c (build_tree_cfg): Rename from tree_find_basic_blocks. + Update all users. + Find the first executable statement before starting basic block 0. + (make_blocks): Do not accept TRY_FINALLY_EXPR and TRY_CATCH_EXPR + nodes. + (make_edges): Always create an edge from entry to basic block 0. + (delete_tree_cfg): Rename from delete_cfg. Update all uses. + (first_exec_stmt): Return the container for the first statement, + not the statement itself. + + * tree-dfa.c (tree_find_refs): Re-implement using a GIMPLE + iterator. + (find_refs_in_stmt): Handle GIMPLE statements. + (find_refs_in_expr): Call flags_from_decl_or_type when handling + CALL_EXPR expressions. + (create_ref): Call DECL_P. + (remove_tree_ann): Call tree_annotation. + + * tree-flow-inline.h (gsi_step_bb): Stop if statement is not inside + a basic block. + + * tree-flow.h (build_tree_cfg): Rename from tree_find_basic_blocks. + Update all users. + (delete_tree_cfg): Rename from delete_cfg. + (tree_find_refs): Declare. + (build_tree_ssa): Rename from tree_build_ssa. + (is_upward_exposed): Remove unused function. + * tree-optimize.c (delete_tree_ssa): Remove declaration. + (optimize_function_tree): Re-enable SSA builder. + * tree-simple.h (gsi_container): New function. + + * Makefile.in (tree-ssa.o): Remove dependencies on c-common.h and + c-tree.h. + * tree-ssa.c: Don't include c-common.h nor c-tree.h. + (tree_find_refs): Remove declaration. + (remove_annotations_r): New local function. + (build_tree_ssa): Rename from tree_build_ssa. Update all users. + (analyze_rdefs): Don't call prep_stmt. + (is_upward_exposed): Remove unused function. + (add_phi_node): Don't associate the PHI node to a statement. + (delete_tree_ssa): Receive the function body as argument. + Walk the function body removing annotations from every tree. + +2002-10-10 Steven Bosscher + + * tree-ssa-dce (tree_ssa_eliminate_dead_code): Initialize prev to + NULL_TREE. + Don't close dump_file until end of function. + Dump the the tree after DCE for -fdump-tree-dce. + +2002-10-08 Richard Henderson + Jason Merrill + Diego Novillo + + * tree-simple.h (gimple_stmt_iterator): New type. + (gsi_start): New function. + (gsi_after_end): New function. + (gsi_step): New function. + (gsi_stmt): New function. + +2002-10-08 Diego Novillo + + * calls.c (flags_from_decl_or_type): Make extern. + (ECF_*): Move ... + * rtl.h (ECF_*): ... here. + (flags_from_decl_or_type): Declare. + + * tree.h (COND_EXPR_COND): Define. + (COND_EXPR_THEN): Define. + (COND_EXPR_ELSE): Define. + (LABEL_EXPR_LABEL): Define. + (optimize_function_tree): Declare. + +2002-10-08 Diego Novillo + + * Makefile.in (TREE_FLOW_H): Define. + (c-decl.o): Remove dependency on tree-optimize.h. + (tree-alias-steen.o, tree-alias-common.o, tree-ssa.o, tree-ssa-pre.o, + tree-cfg.o, tree-dfa.o, tree-optimize.o, c-simplify.o, c-call-graph.o, + tree-ssa-dce.o, tree-ssa-ccp.o): Depend on $(TREE_FLOW_H). + (tree-cfg.o): Remove dependencies on c-tree.h and c-common.h. + * c-call-graph.c (construct_call_graph): Disable calls to removed + functions. + * c-decl.c: Don't include tree-optimize.h. + (c_expand_body): Enable calls to optimize_function_tree. + + * c-pretty-print.c (dump_c_node): Fix printf warnings. + Only dump the first node of a COMPOUND_EXPR when brief_dump is set. + Use COND_EXPR_COND, COND_EXPR_THEN and COND_EXPR_ELSE accessors. + Only dump the opening brace of a BIND_EXPR when brief_dump is set. + + * tree-cfg.c: Don't include tree-optimize.h, c-common.h and c-tree.h. + (binding_stack, make_for_stmt_blocks, make_if_stmt_blocks, + make_while_stmt_blocks, make_switch_stmt_blocks, + make_do_stmt_blocks, create_maximal_bb, make_for_stmt_edges, + make_while_stmt_edges, make_do_stmt_edges, make_if_stmt_edges, + make_break_stmt_edges, make_continue_stmt_edges, create_loop_hdr, + insert_before_ctrl_stmt, insert_before_normal_stmt, + insert_after_ctrl_stmt, insert_after_normal_stmt, + insert_after_loop_body, tree_split_bb, stmt_ends_bb_p): Remove. + Update all users. + (STRIP_CONTAINERS): Define. + (make_bind_expr_blocks): New local function. + (make_cond_expr_blocks): New local function. + (make_loop_expr_blocks): New local function. + (make_switch_expr_blocks): New local function. + (make_loop_expr_edges): New local function. + (make_cond_expr_edges): New local function. + (make_case_label_edges): New local function. + (first_exec_block): New local function. + (make_goto_expr_edges): Rename from make_goto_stmt_edges. + (make_blocks): Remove arguments COMPOUND_STMT and PREV_CHAIN_P. + Use gimple_stmt_iterator to iterate over the statements in the + function. Create maximal basic blocks during traversal. + (create_bb): Remove arguments end, prev_chain_p and binding_scope. + Rename control_parent to parent_block. + (set_bb_for_stmt): Move from tree-flow.h. + (make_edges): Don't assume that basic block 0 contains executable + statements. + Handle BIND_EXPR nodes. + (make_ctrl_stmt_edges): Handle LOOP_EXPR, COND_EXPR and + SWITCH_EXPR. + (make_exit_edges): Handle GOTO_EXPR, CALL_EXPR and RETURN_EXPR. + (tree_delete_bb): Call first_stmt and last_stmt. + (block_invalidates_loop): Call last_stmt. + (replace_expr_in_tree): Don't dump line number information. + (find_expr_in_tree_helper): Don't call statement_code_p. + (tree_dump_bb): Call get_lineno. + (tree_cfg2dot): Ditto. + (successor_block): Use a gimple_stmt_iterator to find the first + executable block after the current one. + (is_ctrl_stmt): Handle COND_EXPR, LOOP_EXPR and SWITCH_EXPR. + (is_ctrl_altering_stmt): Call flags_from_decl_or_type to discover + non-return functions. + (is_loop_stmt): Handle LOOP_EXPR. + (is_computed_goto): Handle GOTO_EXPR. + (stmt_starts_bb_p): Handle CASE_LABEL_EXPR, LABEL_EXPR, RETURN_EXPR + and BIND_EXPR. + (first_exec_stmt): Use a gimple_stmt_iterator to traverse the + statements. + (first_stmt): New function. + (last_stmt): New function. + + * tree-dfa.c: Don't include c-common.h, c-tree.h and + tree-optimize.h. Include diagnostic.h. + (tree_find_refs): Disable. + (find_refs_in_stmt): Disable. + (find_refs_in_expr): Don't call prep_stmt. + (tree_ann): Don't annotate empty_stmt_node. + (find_declaration): Remove. Update all users. + (dump_ref): Call get_lineno. + (is_visible_to): Always return true. + + * tree-flow.h: Include tree-flow-inline.h, basic-block.h and + tree-simple.h. + (tree_ann_d): Remove compound_parent field. + (set_bb_for_stmt): Declare extern. + (compound_parent, set_compound_parent, struct for_header_blocks, + union header_blocks, prev_chain_p, set_prev_chain_p, binding_scope, + set_binding_scope, loop_hdr, for_init_bb, set_for_init_bb, + for_cond_bb, set_for_cond_bb, for_expr_bb, set_for_expr_bb, + end_while_bb, set_end_while_bb, do_cond_bb, set_cond_bb, + stmt_ends_bb_p, loop_parent, latch_block, switch_parent, + first_exec_stmt, last_exec_stmt, is_exec_stmt, + is_statement_expression, first_non_decl_stmt, first_decl_stmt, + first_non_label_in_bb, tree_split_bb, find_declaration): Remove. + Update all users. + (get_lineno): New function. + (struct bb_ann_def): Rename field parent to parent_block. Update + all users. + Remove fields prev_chain_p, loop_hdr and binding_scope. Update all + users. + (parent_block): Rename from bb_parent. + (set_parent_block): Rename from set_bb_parent. + (prev_chain_p): Remove + (bb_empty_p): Return true if block only contains empty_stmt_node. + (gsi_step_bb): New function. + (gsi_start_bb): New function. + (gsi_insert_before, gsi_insert_after, gsi_delete, gsi_replace): + Declare. + (insert_stmt_before): Rename from insert_stmt_tree_before. + (insert_stmt_after): Rename from insert_stmt_tree_after. + (first_stmt): Declare. + (last_stmt): Declare. + (tree_perform_ssapre, tree_ssa_ccp, + tree_ssa_eliminate_dead_code): Move declaration from tree-optimize.h. + * tree-flow-inline.h: New file for all the inline functions + declared in tree-flow.h + + * tree-optimize.c: Don't include tree-optimize.h, c-common.h and + c-tree.h. + (optimize_function_tree): Disable call to double_chain_stmts. + Call init_flow. + Call tree_find_basic_blocks. + Disable calls to tree_build_ssa and optimizers. + (build_tree_ssa): Remove. Update all users. + * tree-optimize.h: Remove. + * tree-ssa-ccp.c: Don't include tree-optimize.h + * tree-ssa-dce.c: Don't include tree-optimize.h. + Include diagnostic.h + * tree-ssa-pre.c: Don't include tree-optimize.h. + (requires_edge_placement): Disable unused function. + (set_need_repair): Disable unused function. + (finalize_1): Disable calls to insert_stmt_tree_before and + insert_stmt_tree_after. + (repair_injury): Ditto. + (code_motion): Ditto. + * tree-ssa.c: Don't include tree-optimize.h. + (insert_phi_nodes_for): Remove unused variable. + (add_phi_node): Don't call statement_code_p. + * cp/optimize.c: Don't include tree-optimize.h + * tree-alias-common.c: Don't include tree-optimize.h. + (find_func_decls): Disable. + (display_points_to_set): Disable. + * tree-alias-steen.c: Don't include tree-optimize.h. + +2002-10-04 Jason Merrill + + * gimplify.c (declare_tmp_vars): Don't add temps to block vars. + * tree-inline.c (remap_decls): Split out from remap_block. + (copy_bind_expr): Remap BIND_EXPR_VARS separately from block vars. + + * c-simplify.c (simplify_expr_stmt): Call set_file_and_line_for_stmt. + + * gimplify.c: New file. + (push_gimplify_context, pop_gimplify_context): New fns. + (gimple_push_bind_expr, gimple_pop_bind_expr): New fns. + (simplify_bind_expr): Use them. + (gimple_current_bind_expr, gimple_add_tmp_var): New fn. + (foreach_stmt): Recurse if necessary. + (various): Use generic interfaces instead of c-specific ones. + * c-simplify.c: Move language-independent code to gimplify.c. + (simplify_c_loop): Use add_tree instead of add_stmt_to_compound. + (various): Use new *_bind_expr interfaces. + * Makefile.in (C_AND_OBJC_OBJS): Add gimplify.o. + (gimplify.o): New rule. + + * c-decl.c (c_expand_body): Dump trees here. + * c-simplify.c (simplify_function_body): Not here. + +2002-10-03 Frank Ch. Eigler + + * tree-mudflap.c (mf_offset_expr_of_array_ref): Don't emit + intermediate variables for constant index values. + (mx_xfn_indirect_ref): For constant valid index values and + known valid array sizes, omit bounds checks. + +2002-10-03 Jason Merrill + + * c-simplify.c (simplify_bind_expr): Don't clear TREE_SIDE_EFFECTS + if we have a block. + + * c-simplify.c (simplify_expr) [TRY_FINALLY_EXPR]: New case. + + * tree-inline.c (copy_body_r) [RETURN_EXPR]: Don't make an extra + copy of the MODIFY_EXPR. Mark the return label used. + (expand_call_inline): Don't push/pop_srcloc. Only emit the return + label if it was used. + + * tree-simple.c (right_assocify_expr): Split out from + rationalize_compound_expr. Don't move non-matching op0's. + * tree-simple.h: Declare it. + * c-simplify.c (simplify_boolean_expr): Call it. + (simplify_cond_expr): Reorganize. Optimize if (a&&b). + + * c-simplify.c (wrap_with_wfl): Drop special loop handling. + (simplify_c_loop): Wrap loop contents in wfls. + + * c-simplify.c (STRIP_WFL): Move... + * tree.h: ...here. + + * c-common.c (c_walk_subtrees): Don't walk TREE_CHAIN. + * tree-inline.c (walk_tree): Call langhook walk_subtrees first. + For expressions, walk TREE_CHAIN if it matters. + +2002-10-01 Frank Ch. Eigler + + * builtins.c (expand_builtin_alloca): Disable if -fmudflap. + * tree-mudflap.c (mudflap_enqueue_decl): Tweak logic to include + more globals. + (mx_xfn_indirect_ref): Handle bitfield COMPONENT_REFs; instrument + BIT_FIELD_REF/INDIRECT_REFs. + +2002-10-01 Jason Merrill + + * c-decl.c (poplevel): Only add undeclared labels to the toplevel + block. + * c-parse.in (label_decl): Push the declared label. + + * c-decl.c (c_expand_body): If we've been simplified, use + expand_expr_stmt_value instead. + + * c-decl.c (c_expand_decl): Rename from c_expand_decl_stmt. + Handle all C-specific expansion semantics. + * c-tree.h: Change prototype. + * langhooks.h (struct lang_hooks): Add expand_decl hook. + * langhooks.c (lhd_expand_decl): Default version. + * langhooks-def.h (LANG_HOOKS_EXPAND_DECL): Provide default. + * c-lang.c (LANG_HOOKS_EXPAND_DECL): Define. + * c-semantics.c (lang_expand_decl_stmt): Remove. + (genrtl_decl_stmt): Use lang_hooks.expand_decl. + * Makefile.in (c-semantics.o): Depend on langhooks.h. + * c-objc-common.c (c_objc_common_init): Don't set + lang_expand_decl_stmt. + + * c-common.def (ASM_STMT): Only 4 operands. + * c-common.h (ASM_CV_QUAL): Remove. + (genrtl_asm_stmt): Adjust prototype. + * c-typeck.c (build_asm_stmt): Adjust. + * c-semantics.c (genrtl_asm_stmt): Change cv_qualifier parm to + volatile_p. + (expand_stmt): Adjust. + + * c-common.h (SWITCH_COND, SWITCH_BODY, CASE_LOW, CASE_HIGH, + CASE_LABEL_DECL, GOTO_DESTINATION, ASM_STRING, ASM_OUTPUTS, + ASM_INPUTS, ASM_CLOBBERS, ASM_VOLATILE_P, ASM_INPUT_P): Move to tree.h. + + * c-pretty-print.c (newline_and_indent): New fn. + (dump_c_tree, dump_c_node): Make spc a plain int. + (dump_c_node): Use output_add_identifier. + Reorganize for bnw-simple; indent in the enclosing node rather + than the subexpression. + [FUNCTION_DECL]: Just print the name for now. + [COMPOUND_EXPR, COND_EXPR]: Handle use as statements. + [BIND_EXPR, GOTO_EXPR, EXIT_EXPR, LOOP_EXPR, LABELED_BLOCK_EXPR, + EXIT_BLOCK_EXPR, RETURN_EXPR, SWITCH_EXPR, ASM_EXPR, + CASE_LABEL_EXPR]: Implement. + (print_declaration): Print 'static'. + * c-tree.h: Move c-pretty-print decls to diagnostic.h. + + * expr.c (store_field): Don't always pass want_value==0 to store_expr. + + * expr.c (expand_expr) [EXIT_EXPR]: Handle EXIT_EXPR_IS_LOOP_COND. + + * expr.c (expand_expr) [LOOP_EXPR]: Pass exit_flag==0 to + exand_start_loop. + [BIND_EXPR]: Adjust for functions-as-trees mode. + [COMPOUND_EXPR]: Avoid recursion if possible. + [SWITCH_EXPR, LABEL_EXPR]: Move handling from java/expr.c. + [CASE_LABEL_EXPR, ASM_EXPR]: New handling. + + * tree.h (struct tree_common): Add visited flag. + (TREE_VISITED): New macro. + * tree.c (copy_node): Clear TREE_VISITED. + * print-tree.c (print_node): Print visted. + + * stmt.c (expand_asm_expr): New fn. + + * tree.c (build1): Always set TREE_SIDE_EFFECTS for 's' codes. + + * tree.h (enum tree_index): Add TI_EMPTY_STMT. + (empty_stmt_node): New macro. + * tree.c (build_common_tree_nodes_2): Initialize it. + + * tree.def: Change some codes from 'e' to 's'. + (CASE_LABEL_EXPR, ASM_EXPR): New codes. + + * tree.def (SWITCH_EXPR): Now has three operands. + + * tree-inline.c: Retarget to generic trees. FIXME FIXME. + * old-tree-inline.c: Old C/Java-specific inliner. + * Makefile.in (old-tree-inline.o): New rule. + * c-common.c (c_walk_subtrees): New fn. + (c_tree_chain_matters_p): New fn. + * c-lang.c: Use them for LANG_HOOKS_TREE_INLINING_WALK_SUBTREES + and LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P. + * c-common.h: Declare them. + (DECL_NUM_STMTS): Move to tree.h. + * c-decl.c (finish_function): Simplify the function trees. + * c-objc-common.c (inline_forbidden_p): Look inside BIND_EXPRs + for nested functions. Don't inline a function with _STMT trees. + + * basic-block.h: Include hard-reg-set.h. + + * c-decl.c (start_function): Don't call make_decl_rtl. + (c_expand_body): Call it here instead. + + * Makefile.in (explow.o): Depend on langhooks.h. + + * unroll.c (copy_loop_body): Don't copy NOTE_INSN_DELETED_LABELs + between copy_notes_from and loop_end, either. + +2002-09-30 Daniel Berlin + + * tree-ssa-pre.c (repair_injury): Start work on updating SSA + representation for strength reduction injuries. + Print a new line after outputting tree node in debug statements. + Fix strength reduction of a candidate with two variables (IE a * + c). + Put the repair after the injuring statement, not at the end of the + block. + Break the RHS use lookup if it's defined by a phi. + (calculate_increment): Ditto on node printing. + (code_motion): Ditto on updating SSA rep for strength reduction + injuries. + (find_rhs_use_for_var): Rewrite to use maybe_find_rhs_use_for_var. + (maybe_find_rhs_use_for_var): Rename from find_rhs_use_for_var, + don't abort, return NULL. + (set_var_phis): Simplify break condition. + Make sure RHS *has* a use before we go and get it. + (rename2): Ditto on RHS checking. + When looking up injuring defs, break on phis. + (phi_opnd_from_res): Ditto. + (defs_y_dom_x): Ditto. + (TODO List): Add new TODO to fix the remapping crud. + +2002-09-27 Daniel Berlin + + * tree-ssa-pre.c (tree_perform_ssapre): Move insertion into + splay tree inside the is_simple_modify_expr block, to prevent + tree check failure. + +2002-09-26 Daniel Berlin + + * tree-ssa-pre.c (update_phis_in_list): New function. + (update_ssa_for_new_use): New function. + (code_motion): Start working on code to update SSA representation. + (find_reaching_def_of_var): New function. + +2002-09-25 Steven Bosscher + + * Makefile.in (tree): Add dependency on c-tree.h + * tree-optimize.c: Include c-tree.h + (optimize_function_tree): React to -fdump-tree-optimized. + +2002-09-25 Daniel Berlin + + * tree-dfa.c (add_list_to_ref_list_end): New function. + (add_list_to_ref_list_begin): Ditto. + (find_list_node): Handle searching in empty lists. + (find_refs_in_stmt): De-staticify. + + * tree-flow.h (add_list_to_ref_list_end): New declaration. + (add_list_to_ref_list_begin): Ditto. + (find_refs_in_stmt): Add prototype. + +2002-09-25 Diego Novillo + + * Makefile.in (tree-dfa.o): Depend on flags.h + * tree-cfg.c (tree_dump_cfg): Alter output format slightly. + (block_invalidates_loop): Look for clobbering definitions of + GLOBAL_VARIABLE. + * tree-simple.c (get_base_symbol): Handle EXPR_WITH_FILE_LOCATION + nodes. + * tree-optimize.c (init_tree_flow): Remove. Update all users. + (build_tree_ssa): Don't call tree_find_refs. + Don't call tree_compute_rdefs. + + * tree-dfa.c: Include flags.h + (dump_file): Remove. + (dump_flags): Remove. + (pointer_refs): Remove. + (struct dfa_stats_d): Add fields max_num_phi_args, num_may_alias, + max_num_may_alias, num_alias_imm_rdefs and max_num_alias_imm_rdefs. + Remove field num_fcalls. + (dfa_counts): Declare. + (tree_find_refs): Declare. + (tree_ssa_dump_file): Declare. + (tree_ssa_dump_flags): Declare. + (dump_if_different): New function. + (add_default_defs): Remove. Update all users. + (add_call_site_clobbers): Remove. Update all users. + (add_ptr_may_refs): Remove. Update all users. + (compute_may_aliases): New function. + (find_may_aliases_for): New function. + (add_may_alias): New function. + (may_alias_p): New function. + (is_visible_to): New function. + (get_alias_index): New function. + (call_sites): Remove. Update all users. + (global_var): Declare. + (E_FCALL): Remove. Adjust other constants. + (M_INDIRECT): Remove. Update all users. + (M_RELOCATE): Declare. + (tree_find_refs): Move debugging dumps to tree_build_ssa. + Move initialization code to init_tree_ssa. + Call compute_may_aliases. + (find_refs_in_expr): For INDIRECT_REF nodes create a reference to + the canonical INDIRECT_REF node associated with the pointer symbol. + Given a pointer p, clobber the canonical INDIRECT_REF of p after + creating a V_DEF for p. + For CALL_EXPR nodes, if the called function is not pure nor + const, create a use and a clobbering definition to GLOBAL_VAR. + (create_ref): Allow INDIRECT_REF variables. + (add_phi_arg): Keep track of number of PHI arguments created. + (function_may_recurse_p): Look for clobbering definitions to + GLOBAL_VAR. + (get_fcalls): Remove unused function. + (is_pure_fcall): Remove unused function. + (fcall_takes_ref_args): Remove unused function. + (find_declaration): Stop iterating at ENTRY_BLOCK_PTR. + (debug_variable): New function. + (dump_variable): New function. + (dump_referenced_vars): Call it. + (dump_phi_args): Don't dump NULL arguments. + (PERCENT): Define. + (dump_dfa_stats): Re-format output. + Add new counters. + Call dump_if_different. + (collect_dfa_stats): Also recurse into GLOBAL_VAR. + (collect_dfa_stats_r): Collect may-alias information. + (count_tree_refs): Collect information about def-def links for + aliases. + Keep track of maximum values for number of PHI arguments, aliases + and def-def links. + (ref_type_name): Handle M_RELOCATE. + (validate_ref_type): Ditto. + + * tree-ssa.c: Add more documentation. + (tree_ssa_dump_file): Rename from dump_file. Declare extern. + (tree_ssa_dump_flags): Rename from dump_flags. Declare extern. + (added): New local varray. + (in_work): New local varray. + (work_stack): New local varray. + (dfa_counts): Declare. + (insert_phi_nodes_for): New local function. + (add_phi_node): New local function. + (set_ssa_links): New local function. + (set_alias_imm_reaching_def): New local function. + (create_default_def): New local function. + (init_tree_ssa): New local function. + (tree_find_refs): Relocate declaration from tree-flow.h + (tree_build_ssa): Call init_tree_ssa. + Call tree_find_refs. + Process all SSA-related dump options. + (insert_phi_nodes): Rename from insert_phi_terms. Update all + users. + Call insert_phi_nodes_for. + (build_fud_chains): Add more documentation. + Initialize save_chain to 0. + (search_fud_chains): Add more documentation. + Call set_ssa_links. + Call create_default_def. + (tree_compute_rdefs): Initialize array marked to 0. + (follow_chain): Follow def-def chains for non-killing definitions + for aliases. + (dump_reaching_defs): Call dump_variable. + + * tree-flow.h (E_FCALL): Remove. Update all users. + (M_INDIRECT): Remove. Update all users. + (M_RELOCATE): Declare. + (struct var_ref): Add field alias_imm_rdefs. + (alias_imm_reaching_def): New inline function. + (struct tree_ann_d): Add field indirect_var. + Add field may_aliases. + (enum tree_flags): Relocate. + (indirect_var): New inline function. + (set_indirect_var): New inline function. + (may_alias): New inline function. + (num_may_alias): New inline function. + (struct dfa_counts_d): Declare. + (global_var): Declare. + (FCALL_NON_PURE, FCALL_PURE, FCALL_BUILT_IN): Remove. + (tree_find_refs): Move to tree-ssa.c. + (dump_variable): Declare. + (debug_variable): Declare. + (get_fcalls): Remove. + (is_pure_fcall): Remove. + (fcall_takes_ref_args): Remove. + (ref_defines): Declare. + (is_killing_def): Declare. + (get_alias_index): Declare. + (delete_tree_ssa): Rename from delete_ssa. Update all users. + (set_currdef_for): Allow INDIRECT_REF nodes. + (bb_annotation): Don't create a new one if the block didn't have an + annotation already. + + * tree-ssa-ccp.c (substitute_and_fold): Rename from + ssa_ccp_substitute_constants. Update all users. + Call replace_uses_in. + (replace_uses_in): New local function. + (evaluate_expr): Call it. + (initialize): Call get_base_symbol. + + * tree-ssa-dce.c (tree_ssa_eliminate_dead_code): Don't handle + E_FCALL. + +2002-09-22 Diego Novillo + + * Makefile.in (tree-dfa.o): Depend on hashtab.h. + * c-simplify.c (get_name): Declare extern. + * tree-cfg.c (tree_dump_cfg): Call it. + (tree_cfg2dot): Call it. + * tree-ssa-ccp.c (tree_ssa_ccp): Call get_name. + * tree-ssa-dce.c (tree_ssa_eliminate_dead_code): Call get_name. + * tree-ssa-pre.c (tree_perform_ssapre): Call get_name. + * tree-ssa.c (analyze_rdefs): Call get_name. + (dump_reaching_defs): Call get_name. + (dump_tree_ssa): Call get_name. + * tree.h (get_name): Declare. + + * tree-dfa.c: Include "hashtab.h" + (struct dfa_stats_d): New. + (collect_dfa_stats): New local function. + (collect_dfa_stats_r): New local function. + (count_tree_refs): New local function. + (count_ref_list_nodes): New local function. + (tree_find_refs): Call dump_begin on entry to the function. + (dump_referenced_vars): Call get_name. + (SCALE): Declare. + (LABEL): Declare. + (dump_dfa_stats): New function. + (debug_dfa_stats): New function. + * tree-dump.c (struct dump_option_value_info): Add entry for TDF_STATS. + * tree-flow.h (has_annotation): Remove. Update all users. + (dump_dfa_stats): Declare. + (debug_dfa_stats): Declare. + (tree_annotation): Don't create one if the tree doesn't have one + already. Update all users to new semantics. + * tree-ssa-dce.c (print_stats): Dump if dump_flags has TDF_STATS bit + set. + * tree-ssa.c (tree_build_ssa): Open dump file on entry. + Call dump_dfa_stats if dump_flags has TDF_STATS bit set. + Call dump_tree_ssa if dump_flags has TDF_DETAILS bit set. + * tree.h (TDF_STATS): Define. + * doc/invoke.texi: Document 'stats' flag for -fdump-tree. + + * tree-dfa.c (next_tree_ref_id): Change type to unsigned long. + Update all users. + tree-flow.h (tree_ref_common): Change type of field 'id' to + unsigned long. Update all users. + (ref_id): Change return type to unsigned long. Update all users. + +2002-09-21 Daniel Berlin + + * tree-ssa-pre.c (struct expr_info): Add repaired member. + (repair_injury): Track which injuries we repaired, so we don't + repair them > 1 time. + +2002-09-20 Diego Novillo + + * c-pretty-print.c (dump_c_node): Fix call to REAL_VALUE_TO_DECIMAL. + +2002-09-20 Diego Novillo + + * tree-dfa.c (find_refs_in_stmt): Fix botched call to + clobber_vars_r with CLEANUP_STMT nodes. + +2002-09-20 Diego Novillo + + * toplev.c (flag_tree_ssa): Remove. Update all users. + +2002-09-20 Frank Ch. Eigler + + * gcc.c (cc1_options): Make -fmudflap imply -fno-merge-constants. + * varasm.c (categorize_decl_for_section): Likewise, for strings. + * tree-mudflap.c (mudflap_enqueue_decl): Don't be interested + in !TREE_USED decls. Fix minor type warning. + (mf_offset_expr_of_array_ref): Create explicit temporary variables + for array index expressions instead of SAVE_EXPRs. Update callers. + (mf_build_check_statement_for): Insert temp variables. + (mx_xfn_indirect_ref): Correct recursion-protection checking + sequence. Tweak array check-base calculation back to "&array[0]". + (*): Use build_function_type_list instead of build_function_type. + (mx_external_ref): Remove unused parameter. Update callers. + +2002-09-19 Diego Novillo + + * c-decl.c (c_expand_body): Invoke tree optimizers with -O1 and + above. + * flags.h (flag_tree_ssa): Remove. + * tree-cfg.c (find_expr_in_tree_helper): Change last argument type + to int. + * tree-dfa.c (create_ref): Ditto. + * tree-flow.h (num_referenced_vars): Change type to unsigned long. + * doc/invoke.texi (-ftree-ssa): Remove. + (-fdump-tree-{pre,ccp,dce}): Add to the summary section. + (-fdump-tree-xxx-details): Update documentation. + (-fdump-tree-ccp): Document. + (-fdump-tree-simple): Move elsewhere. + +2002-09-19 Richard Henderson + + * function.c (insns_for_mem_hash): Cast to size_t first. + * tree-dfa.c (num_referenced_vars): Unsigned long, not size_t. + (dump_referenced_vars): Use %lu for it. + (dump_ref): Use HOST_WIDE_INT_PRINT_DEC. + * tree-nomudflap.c (mudflap_c_function): Use ATTRIBUTE_UNUSED. + (mudflap_enqueue_decl, mudflap_enqueue_constant): Likewise. + * tree-ssa-pre.c (compute_idfs): Cast to size_t first. + + * tree-optimize.c (optimize_function_tree): Fix missed renamings. + * tree-ssa-pre.c (tree_perform_ssapre): Likewise. + +2002-09-19 Jeff Law + + * tree-dfa.c (find_refs_in_stmt): Search for references in the call + address of a CALL_EXPR. + +2002-09-19 Daniel Berlin + + * toplev.c: tree-ssa-* -> tree-*. + + * doc/invoke.texi: Ditto. + +2002-09-19 Daniel Berlin + + * flags.h: flag_tree_ssa_* -> flag_tree_*. + + * toplev.c: Ditto. + + * tree-optimize.c: Ditto. + + * tree-dump.c: dump-tree-ssa-* -> dump-tree-*. + TDI_ssa_* -> TDI_*. + + * tree.h: Ditto + + * tree-ssa-dce.c (tree_ssa_eliminate_dead_code): Fix dump handling. + +2002-09-18 Daniel Berlin + + * tree-dump.c (dump_files): Use dump-tree-ssa-??? for the option names + and "ssa-???" for the dump files. + + * tree.h: TDI_ccp and TDI_dce -> TDI_ssa_ccp and TDI_ssa_dce. + + * tree-ssa-ccp.c: TDI_ccp->TDI_ssa_ccp. + +2002-09-18 Daniel Berlin + + * tree-dump.c: Fix order of dump files + +2002-09-17 Daniel Berlin + + * tree-ssa-pre.c: Remove a lot of finding refs in statements junk. + Start on strength reduction. + Only generate simple statements. + Remove EXPR* macros in favor of inline functions. + Update comparisons and sets to 1 and 0 to true and false where + approriate. + (toplevel): Add DEBUGGING_STRRED define (temporary, for + implementation debugging, *not* useful as a dump option). + Add TODO notes. + Add global avdefs, orig_expr_map, need_repair_map, + strred_candidate. + (set_var_phis): Add struct expr_info * argument. + Update to handle injuring definitions. + (defs_y_dom_x): Ditto. + (phi_opnd_from_res): Ditto. + (phi_for_operand): Remove extra \. + (find_tree_ref_for_var): Renamed to find_use_for_var. Update all + callers. + Use orig_expr_map to lookup original expression, remove statement + searching gunk. + (find_rhs_use_for_var): New function. + (is_strred_cand): New function. + (is_injuring_def): New function. + (calculate_increment): New function. + (repair_injury): New function. + (set_need_repair): New function. + (struct expr_info): Add strred_cand member. + (rename_2): Update to handle injuring definitions. + (expr_phi_insertion): Ditto. + (code_motion): Update to repair injuries. + Only insert SIMPLE statements. + Free avdefs here now. + (finalize_1): Don't free avdefs anymore here. + (tree_perform_ssapre): Record original expresion for + find_use_for_var's benefit. + Determine strength reduction candidates. + + * tree-flow.h: Remove EXPR* macros in favor of inline functions. + Remove E_INJ. + + * tree-dfa.c: Change EXPR* macros to the new functions. + Remove E_INJ. + +2002-09-18 Diego Novillo + + * tree-dfa.c (M_ADDRESSOF): Define. + (find_refs_in_expr): Create addressof-use references for ADDR_EXPR + nodes. + Don't create references for FUNCTION_DECL nodes. + (ref_type_name): Handle M_ADDRESSOF. + (validate_ref_type): Ditto. + (clobber_vars_r): Don't clobber FUNCTION_DECL nodes. + * tree-flow.h (M_ADDRESSOF): Declare. + +2002-09-17 Diego Novillo + + * doc/invoke.texi: Document -ftree-ssa-dce and -fdump-tree-dce. + * cp/Make-lang.in (CXX_C_OBJS): Add tree-ssa-dce.o. + +2002-09-17 Ben Elliston + + * Makefile.in (C_AND_OBJC_OBJS): Add tree-ssa-dce.o. + tree-ssa-dce.o): New target. + * tree-ssa-dce.c: New file. + * flags.h (flag_tree_ssa_dce): Declare flag. + * tree.h (tree_dump_index): Add TDI_dce. + * toplev.c (flag_tree_ssa_dce): New flag. + (f_options): Add "dump-tree-all-ssa" option. + * tree-flow.h (enum tree_flags): Add TF_NECESSARY. + * tree-dump.c (dump_files): Add dump-tree-dce option. + (dump_enable_all_ssa): Enable it when dumping all. + * tree-optimize.h (tree_ssa_eliminate_dead_code): Declare. + * tree-optimize.c (optimize_function_tree): Invoke the + optimisation pass if flag_tree_ssa_dce is set. + +2002-09-17 Diego Novillo + + * Makefile.in (tree-ssa.o): Add dependency on c-tree.h + * c-simplify.c (mark_not_simple_r): Don't mark IDENTIFIER_NODEs. + * tree-dfa.c (function_may_recurse_p): Fix comment. + (dump_ref): Don't dump immediate uses for PHI nodes more than once. + (dump_referenced_vars): Unparse the name of the variable. + * tree-flow.h (dump_tree_ssa): Declare. + (debug_tree_ssa): Declare. + (replace_ref_operand_with): Check if OPERAND_P is NULL. + (restore_ref_operand): Ditto. + (tree_annotation): Check that constants, types and IDENTIFIER_NODEs + are not being annotated. + * tree-ssa.c: Include c-tree.h. + (dump_reaching_defs): Unparse the variable name. + (dump_tree_ssa): New function. + (tree_build_ssa): Call it. + (debug_tree_ssa): New function. + +2002-09-14 Steven Bosscher + + * dwarf2out.c (is_fortran): Return true for + DW_LANG_Fortran95. + (gen_compile_unit_die): Return DW_LANG_Fortran95 if + language is "GNU F95". + +2002-09-13 Daniel Berlin + + * tree-dump.c (dump_switch_p): Get longest match, not first one. + + * tree.h: Put TDI_* back in order, now that we do longest match + matching. + +2002-09-13 Diego Novillo + + * tree-dfa.c (add_call_site_clobbers): Call decl_function_context + instead of DECL_CONTEXT. + * tree-ssa-ccp.c (initialize): Ditto. + * tree-ssa.c (analyze_rdefs): Ditto. + +2002-09-11 Diego Novillo + + * tree-dfa.c (find_refs_in_stmt): Call clobber_vars_r to clobber + CLEANUP_STMT nodes. + (create_ref): Only add _DECL nodes to the list of referenced + variables. + (clobber_vars_r): Create a may-use reference prior to clobbering + the variable. + (add_call_site_clobbers): Ditto. + (add_ptr_may_refs): Move call to find_list_node where it's actually + needed. + * tree-flow.h: Update documentation on M_CLOBBER. + +2002-09-10 Daniel Berlin + + * tree-ssa-pre.c (defs_match_p): Fix typo ( | -> || ). + +2002-09-10 Diego Novillo + + * tree-dfa.c (V_PHI_ARG): Remove. Adjust related constants. + Update all users. + (add_ref_to_list_after): Don't allocate memory for the + node when adding to the beginning or the end of the list. + (add_phi_arg): Don't call create_ref to add a new argument. + (debug_phi_args): New function. + (dump_phi_args): New function. + (dump_ref): Call it. + (dump_referenced_vars): Use 'file' instead of 'dump_file'. + + * tree-flow.h (V_PHI_ARG): Remove. Update all users. + (struct var_ref): Move fields used in distinct + reference types to other structures. Update all users. + (struct var_def): New. + (struct var_phi): New. + (struct var_use): New. + (union tree_ref_d): Add members vdef, vphi, vuse and vphi_arg. + Update all users. + (save_chain): Remove. Update all users. + (set_save_chain): Remove. Update all users. + (marked_with): Remove. Update all users. + (mark_def_with): Remove. Update all users. + (dump_reaching_defs): Declare. + (debug_reaching_defs): Declare. + + (struct phi_node_arg_d): New structure. + (phi_node_arg): New type. + (phi_arg): Change return type to phi_node_arg. + (imm_reaching_def_edge): Rename to phi_arg_edge. + (set_imm_reaching_def_edge): Rename to set_phi_arg_edge. + (phi_arg_def): New inline function. + (set_phi_arg_def): New inline function. + (debug_phi_args): Declare. + (dump_phi_args): Declare. + + * tree-ssa-ccp.c: Use new phi_node_arg type when examining PHI node + arguments. + + * tree-ssa-pre.c: Ditto. + + * tree-ssa.c (save_chain): New local variable. + (build_fud_chains, search_fud_chains): Use it. + (marked): New local variable. + (tree_compute_rdefs, follow_chain): Use it. + (dump_reaching_defs): New function. + (debug_reaching_defs): New function. + +2002-09-09 Daniel Berlin + + * Makefile.in (tree-alias-steen.o): Remove gt-tree-alias-steen.h + (tree-alias-common.o): Add dependency on c-common.h + + * tree-ssa-pre.c: Fix PRE now that V_USE's expr's are the entire + assignment, rather than just the right hand side. + Stop generating our own call clobbers + + * tree-dfa.c (create_ref): Make sure var is not null before checking + TREE_THIS_VOLATILE. + + * tree.h: Reorder TDI_* so ssapre comes before ssa. + + * tree-dump.c: dump-tree-ssapre has to come before dump-tree-ssa + in the table, or else it'll never match. + +2002-09-09 Frank Ch. Eigler + + * tree-mudflap.c (mf_offset_expr_of_array_ref): Fold constants along + the way. + (mf_build_check_statement_for): Ditto. Flag new COMPONENT_REFs. + (mx_xfn_indirect_ref): Instrument COMPONENT_REFs specially. Tweak + ARRAY_REF instrumentation to reduce need of copying and recursion. + +2002-09-09 Diego Novillo + + * tree-ssa.c (analyze_rdefs): Disable uninitialized variable warnings. + +2002-09-09 Diego Novillo + + * Makefile.in (tree-ssa.o): Add dependency on tree-simple.h. + (tree-dfa.o): Add dependency on tree-simple.h and tree-inline.h. + (tree-alias-steen.o): Add dependency on c-common.h. + (tree-optimize.o): Add dependency on c-common.h. + + * c-simplify.c (deep_copy_node): Call walk_tree with mostly_copy_tree_r. + (mostly_copy_tree_r): Also copy flags from original tree. + (mark_not_simple_r): Call set_tree_flag. + + * tree-alias-steen.c: Include c-common.h. + + * tree-cfg.c (map_stmt_to_bb): Remove. + (block_invalidates_loop): Change return type to bool. + (create_loop_hdr): New function. + (create_bb): Call it. + (create_bb_ann): Return newly created annotation object. + (remove_bb_ann): Nullify loop_hdr annotation, if there is one. + (tree_delete_bb): Only remove basic block annotation from + executables statements. + (is_computed_goto): New function. + + * tree-dfa.c (pointer_refs): New file local variable. + (call_sites): New global variable. + (V_DEF, V_USE, V_PHI, V_PHI_ARG, E_FCALL, E_PHI, E_USE, E_KILL, + E_INJ): New global constants. + (M_DEFAULT, M_CLOBBER, M_MAY, M_PARTIAL, M_INITIAL, M_INDIRECT, + M_VOLATILE): New global constants. + (num_referenced_vars): New global variable. + (referenced_vars): Rename from referenced_symbols. Update all + users. + (clobber_vars_r): New function. + (add_default_defs): New function. + (add_call_site_clobbers): New function. + (add_ptr_may_refs): New function. + (add_phi_arg): New function. + (find_list_node): New function. + (remove_ref_from_list): Call it. + (add_ref_to_list_after): New function. + (is_pure_fcall): New function. + (fcall_takes_ref_args): New function. + (dump_referenced_vars): New function. + (debug_referenced_vars): New function. + (ref_type_name): New function. + (validate_ref_type): New function. + (debug_phi_args): Remove. + (dump_phi_args): Remove. + (add_referenced_var): Rename from add_ref_symbol. Update all + users. + (dump_ref): Rename from dump_varref. Update all users. + (debug_ref): Rename from debug_varref. Update all users. + (dump_ref_list): Rename from dump_varref_list. Update all users. + (dump_ref_array): Rename from dump_varref_array. Update all users. + (next_tree_ref_id): Rename from next_varref_id. Update all users. + + (tree_find_refs): Rename from tree_find_varrefs. Update all users. + Call add_default_defs. + Call add_call_site_clobbers. + Call add_ptr_may_refs. + Call dump_referenced_vars. + Create and destroy pointer_refs list. + + (find_refs_in_stmt): Set reference type to clobbering definition + for the ASM_OUTPUTS and ASM_CLOBBERS expressions of an ASM_STMT. + Set reference type to initial definition for the DECL_INITIAL node + of a DECL_STMT. + Clobber everything in CLEANUP_STMT nodes. + + (find_refs_in_expr): Re-write. + Recursively clobber every VAR_DECL contained in non SIMPLE nodes. + Mark indirect pointer references with M_INDIRECT flag. + Add pointer references to pointer_refs list. + Glob references to arrays and structures. + Add function call expressions to call_sites list. + + (empty_ref_list): Do nothing if the list is empty already. + (delete_ref_list): Ditto. + (create_ref): Add new argument ADD_TO_BB. + Set M_VOLATILE modifier if this is a reference to a volatile + variable. + Count number of incoming edges for V_PHI references before + initializing the V_PHI_ARG array. + Only add reference to basic block if ADD_TO_BB is true. + Set output reference for the parent expression for V_DEF + references. + (remove_tree_ann): Do nothing if the tree didn't have an + annotation. + + * tree-flow.h (enum treeref_type): Remove. Update all users. + (union varref_def): Ditto. + (tree_ref): Rename from varref. Update all users. + (V_DEF): Declare. + (V_USE): Declare. + (V_PHI): Declare. + (V_PHI_ARG): Declare. + (E_FCALL): Declare. + (E_PHI): Declare. + (E_USE): Declare. + (E_KILL): Declare. + (E_INJ): Declare. + (M_DEFAULT): Declare. + (M_CLOBBER): Declare. + (M_MAY): Declare. + (M_PARTIAL): Declare. + (M_INITIAL): Declare. + (M_INDIRECT): Declare. + (M_VOLATILE): Declare. + (struct tree_ref_common): Rename from treeref_common. Update all + users. + Change type of field 'type' to HOST_WIDE_INT. + Rename field 'sym' to 'var'. + (struct var_ref): Rename from varref. Update all users. + Join the structures varuse + and vardef into a single structure. + (struct expr_ref_common): Rename from exprref_common. Update all + users. + (struct expr_use): Rename from expruse. Update all users. + (struct expr_phi): Rename from exprphi. Update all users. + (union tree_ref_d): Rename from varref_def. Update all users. + (EXPRPHI_PHI_ARGS): Rename from EXPRPHI_PHI_CHAIN. Update all + users. + (struct tree_ann_d): Rename field 'compound_stmt' to + 'compound_parent'. + Add field 'output_ref'. + (enum tree_flags): New enum. + (TF_REFERENCED): New flag. + (phi_arg): Remove. + (get_num_phi_args): Remove. + (get_phi_arg): Remove. + + (struct vardef): Remove. Update all users. + (VARDEF_IMM_USES): Ditto. + (VARDEF_SAVE_CHAIN): Ditto. + (VARDEF_RUSES): Ditto. + (VARDEF_MARKED): Ditto. + (VARDEF_PHI_ARGS): Ditto. + (struct varuse): Ditto. + (VARUSE_IMM_RDEF): Ditto. + (VARUSE_RDEFS): Ditto. + (VARREF_ID): Ditto. + (VARREF_TYPE): Ditto. + (VARREF_BB): Ditto. + (VARREF_EXPR): Ditto. + (VARREF_OPERAND_P): Ditto. + (VARREF_STMT): Ditto. + (VARREF_SYM): Ditto. + (IS_DEFAULT_DEF): Ditto. + (IS_ARTIFICIAL_REF): Ditto. + (TREE_ANN): Ditto. + (BB_FOR_STMT): Ditto. + (TREE_CURRDEF): Ditto. + (TREE_REFS): Ditto. + (TREE_COMPOUND_STMT): Ditto. + (TREE_FLAGS): Ditto. + (BB_ANN): Ditto. + (BB_PARENT): Ditto. + (BB_REFS): Ditto. + (BB_PREV_CHAIN_P): Ditto. + (BB_BINDING_SCOPE): Ditto. + (BB_LOOP_HDR): Ditto. + (FOR_INIT_STMT_BB): Ditto. + (FOR_COND_BB): Ditto. + (FOR_EXPR_BB): Ditto. + (END_WHILE_BB): Ditto. + (DO_COND_BB): Ditto. + (BB_EMPTY_P): Ditto. + + (ref_type): New inline function. + (ref_var): New inline function. + (ref_stmt): New inline function. + (ref_expr): New inline function. + (ref_bb): New inline function. + (ref_id): New inline function. + (replace_ref_operand_with): New inline function. + (restore_ref_operand): New inline function. + (imm_uses): New inline function. + (save_chain): New inline function. + (set_save_chain): New inline function. + (reached_uses): New inline function. + (marked_with): New inline function. + (mark_def_with): New inline function. + (phi_args): New inline function. + (num_phi_args): New inline function. + (phi_arg): New inline function. + (imm_reaching_def): New inline function. + (set_imm_reaching_def): New inline function. + (imm_reaching_def_edge): New inline function. + (set_imm_reaching_def_edge): New inline function. + (reaching_defs): New inline function. + (tree_annotation): New inline function. + (has_annotation): New inline function. + (bb_for_stmt): New inline function. + (set_bb_for_stmt): New inline function. + (currdef_for): New inline function. + (set_currdef_for): New inline function. + (tree_refs): New inline function. + (add_tree_ref): New inline function. + (remove_tree_ref): New inline function. + (compound_parent): New inline function. + (set_compound_parent): New inline function. + (set_tree_flag): New inline function. + (clear_tree_flag): New inline function. + (tree_flags): New inline function. + (reset_tree_flags): New inline function. + (output_ref): New inline function. + (set_output_ref): New inline function. + (bb_annotation): New inline function. + (bb_parent): New inline function. + (set_bb_parent): New inline function. + (bb_refs): New inline function. + (remove_bb_ref): New inline function. + (prev_chain_p): New inline function. + (set_prev_chain_p): New inline function. + (binding_scope): New inline function. + (set_binding_scope): New inline function. + (header_blocks): New inline function. + (for_init_bb): New inline function. + (set_for_init_bb): New inline function. + (for_cond_bb): New inline function. + (set_for_cond_bb): New inline function. + (for_expr_bb): New inline function. + (set_for_expr_bb): New inline function. + (end_while_bb): New inline function. + (set_end_while_bb): New inline function. + (do_cond_bb): New inline function. + (set_do_cond_bb): New inline function. + (bb_empty_p): New inline function. + + (referenced_vars): Rename from referenced_symbols. Update all + users. + (num_referenced_vars): Declare. + (NREF_SYMBOLS): Remove. Update all users. + (REF_SYMBOL): Ditto. + (ADD_REF_SYMBOL): Ditto. + (referenced_var): New inline function. + (call_sites): Declare. + (next_tree_ref_id): Rename from next_varref_id. Update all users. + (is_computed_goto): Declare. + (is_pure_fcall): Declare. + (fcall_takes_ref_args): Declare. + (add_ref_to_list_after): Declare. + (find_list_node): Declare. + (ref_type_name): Declare. + (validate_ref_type): Declare. + + * tree-optimize.c: Include c-common.h. + (optimize_function_tree): Store DECL_SAVED_TREE in a local + variable. + + * tree-ssa-ccp.c (cp_lattice_meet): New function. + (visit_phi_node): Call it. + (add_outgoing_control_edges): New function. + (visit_expression_for): Call it. + Don't handle static initializers. + Handle computed gotos. + (add_control_edge): New function. + (visit_condexpr_for, simulate_block, add_outgoing_control_edges): Call + it. + (simulate_def_use_chains): Only look at unmodified V_USE references. + (ssa_ccp_substitute_constants): Ditto. + (evaluate_expr): Ditto. + (initialize): Set initial value for incoming parameters and globals + to VARYING. + Set initial value for initialized static variables to VARYING, + unless the variable is read-only. + (set_lattice_value): Don't special case globals, volatiles and + variables with their address taken. + + * tree-ssa.c: Include tree-simple.h. + (tree_build_ssa): Don't add default definitions. + (insert_phi_terms): Add new PHI nodes at the beginning of the list + of references for the basic block. + (search_fud_chains): Add def-def chains for non-killing + definitions. + (delete_ssa): Remove list call_sites. + Set num_referenced_vars to 0. + Set referenced_vars to NULL. + (follow_chain): Follow def-def chains for non-killing definitions. + (is_upward_exposed): Change return type to bool. + (add_phi_arg): Remove. + +2002-09-06 Frank Ch. Eigler + + * tree-mudflap.c (deferred_static_decl*): Correct GTY markup. + (mudflap_enqueue_decl): Correct iteration bounds. + (mf_init_extern_trees): Add more constness to mf_cache_structptr_type. + (mf_offset_expr_of_array_ref): Remove excess mx_flagging. save_expr + array subscripts. + (mf_build_check_statement_for): Reorganize to take explicit + check-base/size arguments, in addition to value argument. save_expr + array subscripts. Copy value/base/size subtrees. + (mx_xfn_indirect_ref): Support marking of subtrees for nontraversal. + Track source line numbers more aggressively. For arrays, check bounds + from base through indexed element, not just the indexed element. + Use nontraversal flagging to eliminate some excess instrumentation. + (mf_xform_derefs): Support nontraversal by a hash table. + (*): Remove "{{{"/"}}}" folding marks. + +2002-09-02 Daniel Berlin + + * tree-alias-common.[ch]: New files. + * tree-alias-steen.[ch]: Split out common stuff into + tree-alias-common.[ch]. + * c-config-lang.in: Modify to use tree-alias-common.[ch] instead of + tree-alias-steen, since this is where the GTY'd stuff is now. + * Makefile.in: Add dependencies for tree-alias-common.[ch]. + +2002-09-03 Diego Novillo + + * c-simplify.c (simplify_goto_stmt): New function. + (simplify_stmt): Call it. + * tree-simple.c: Document grammar for GOTO_STMT nodes. + (rationalize_compound_expr): Wrap it with #if 0/#endif. + (get_base_symbol): Minor comment fixup. + +2002-09-03 Frank Ch. Eigler + + * gcc.c (MFWRAP_SPEC): Add --wrap=alloca. + +2002-09-01 Diego Novillo + + * c-simplify.c (simplify_stmt): Mark CLEANUP_STMTs and ASM_STMTs + not SIMPLE. + (simplify_for_stmt): Do not allow expression sequences in + FOR_INIT_STMT and FOR_EXPR nodes. + * tree-simple.c: Document difference with original SIMPLE grammar. + +2002-08-31 Frank Ch. Eigler + + * tree-mudflap.c (mf_build_check_statement_for): Tolerate dereference + of void pointers. + (mx_register_decl): Correct typo in below patch. + +2002-08-30 Graydon Hoare + + * tree-mudflap.c (mx_register_decl): Mark declarations as + TREE_ADDRESSABLE when mudflap decides to register them. + +2002-08-29 Graydon Hoare + + * tree-mudflap.c (mx_xfn_indirect_ref): Rewrite array references as + pointer dereferences. + (struct mf_xform_decls_data): New member: param_decls. + (mx_register_decl): New function. + (mx_xfn_xform_decls): Factor code out into mx_register_decl. + Register live parameters with mudflap. + (mx_xfn_find_addrof): Notice references to fields of structures + and function parameters. + +2002-08-29 Frank Ch. Eigler + + * c-pretty-print.c (dump_c_tree): Detect loops in statement chains + using a hash table to track visited status. + * Makefile.in: Add hashtab.h dependency. + +2002-08-28 Frank Ch. Eigler + + * tree-mudflap.c (mudflap_enqueue_constant): Register non-string + constants also. + (mf_build_check_statement_for): Include pushlevel/pushdecl/poplevel + for local variables. + +2002-08-27 Frank Ch. Eigler + + Better static registration: + * varasm.c (make_decl_rtl): Handle DECL_RTL_SET_P case for + mudflap static registration. + * tree-mudflap.c (mudflap_enqueue_decl): Rewrite to handle + deferred statics. + (mudflap_finish_file): Call above fn back for deferred statics. + + Cleanup: + * tree-mudflap.c (mf_varname_tree, mf_file_function_line_tree): + Reorganize output_buffer reuse mechanism. + (mf_build_check_statement_for): Set TREE_SIDE_EFFECTS. + (mx_xfn_indirect_ref): Correct file/line collection tests. + + Dynamic linking support: + * gcc.c (MFWRAP_SPEC): Make conditional on -static. Add the + newer wrapped functions dlopen/mmap/munmap. + (MFLIB_SPEC): Be sensitive to -static. Partial support for + dynamic linking. + +2002-08-26 Diego Novillo + + * Makefile.in (tree-ssa.o): Add dependency on ggc.h + (c-simplify.o): Add dependency on langhooks-def.h + * c-simplify.c: Include langhooks-def.h + (simplify_function_tree): Do nothing if the front end does not + support simplification. + + * tree-flow.h (struct vardef): Remove fields 'phi_chain' and + 'phi_chain_bb'. + Add field 'phi_args'. + (VARDEF_PHI_CHAIN): Remove. Update all users. + (VARDEF_PHI_CHAIN_BB): Remove. Update all users. + (VARDEF_PHI_ARGS): Define. + (struct varuse): Rename field 'chain' to 'imm_rdef'. Update all + users. + (VARUSE_IMM_RDEF): Rename from VARUSE_CHAIN. Update all users. + (phi_arg): New structure. + (get_num_phi_args): New function. + (get_phi_arg): New function. + (set_phi_arg): New function. + (add_phi_arg): New function. + (debug_phi_args): Declare. + (dump_phi_args): Declare. + * tree-dfa.c (create_ref): Remove initialization of + VARDEF_PHI_CHAIN and VARDEF_PHI_CHAIN_BB. + Initialize array VARDEF_PHI_ARGS. + (dump_varref): Call dump_phi_args. + (dump_phi_args): New function. + (debug_phi_args): New function. + * tree-ssa-ccp.c (PHI_PARMS): Remove. + (EIE): Remove. + (visit_phi_node): Get the argument's edge directly from the + argument instead of calling find_edge. + (initialize): Cast call to NUM_EDGES to unsigned. + * tree-ssa-pre.c: Update uses of VARDEF_PHI_CHAIN, + VARDEF_PHI_CHAIN_BB and VARUSE_CHAIN everywhere. + * tree-ssa.c: Ditto. + Include ggc.h. + (search_fud_chains): Call add_phi_arg to add arguments to each PHI + node. + (tree_ssa_remove_phi_alternative): Call set_phi_arg to switch the + last element with the element being removed. + +2002-08-26 Diego Novillo + + * c-simplify.c (mostly_copy_tree_r): Unshare STMT_EXPR + nodes. + +2002-08-25 Diego Novillo + + * tree-dfa.c (find_refs_in_stmt): Replace calls to + RETURN_EXPR with RETURN_STMT_EXPR. + * c-simplify.c (simplify_return_stmt): Ditto. + (deep_copy_node): Ditto. + * c-pretty-print.c (dump_c_node): Ditto. + +2002-08-24 Diego Novillo + + * c-pretty-print.c: Add `break' after calls to NIY in + switch statements. + +2002-08-23 Jeffrey A Law (law@redhat.com) + + * tree-ssa-ccp.c (tree_ssa_ccp): Remove #if 0 that accidentally + got checked in. Cleanup the cfg to remove unreachable blocks + discovered by CCP. + + * basic-block.h (EDGE_EXECUTABLE): New edge flag. + + * cfganal.c (find_edge): New function. + + * ssa-ccp.c: Convert to use EDGE_EXECUTABLE bit in the + edge flags rather than a bitmap. Convert edge worklist + into a varray. Avoids expensive find_index_edge calls. + * tree-ssa-ccp.c: Likewise. + + * tree-flow.h (tree_ssa_remove_phi_alternative): Declare. + * tree-ssa.c (tree_ssa_remove_phi_alternative): New function. + * tree-ssa-ccp.c (optimize_unexecutable_edges): Remove + PHI alternatives for unexecutable edges. Also remove + unexecutable edges from the CFG. + +2002-08-22 Jeffrey A Law (law@redhat.com) + + * Makefile.in (tree-optimize.o): Depend on tree-dchain.o + * tree-optimize.c: Include tree-dchain.h. + (optimize_function_tree): Unconditionally build and tear down + the backpointers for the statement chain. + +2002-08-22 Diego Novillo + + * tree-dfa.c (find_refs_in_stmt): Look for VARUSE references in + initialization expressions. + (find_refs_in_expr): Reformat. + (remove_ref_from_list): Optimize for the common case of removing + the head or the tail of the list. + (add_ref_to_list_end): Reformat comment. + (create_ref): Store the reference to LHS of assignment expressions. + (dump_varref): Also dump immediate uses of PHI nodes. + * tree-flow.h (IS_GHOST_DEF): Rename to IS_DEFAULT_DEF. Update all + callers everywhere. + (struct tree_ann_def): Update comments for field 'currdef'. + * tree-ssa-ccp.c (ssa_edges): Change type to ref_list. + (SSA_NAME): Remove. + (initialize): New function + (finalize): New function. + (visit_expression): Rename to visit_expression_for. Update all + callers. + (visit_condexpr_for): New function. + (visit_assignment): Rename to visit_assignment_for. Update all + callers. + (examine_flow_edges): Rename to simulate_block. Update all + callers. + (follow_def_use_chains): Rename to simulate_def_use_chains. Update + all callers. + (evaluate_expr_for): Rename to evaluate_expr. Change argument to + 'tree'. + (set_lattice_value): New function. + (tree_ssa_ccp): Change main loop to visit flow_edges and ssa_edges + alternately. + (visit_phi_node): Do not set the lattice value to UNDEFINED when we + find a non-executable edge. + (visit_expression_for): Default definitions for PARM_DECLs are + assigned a VARYING value. + Default definitions for any other local variables are assigned an + UNDEFINED value. + Clobber VARDEFs that are not the LHS of an assignment. + Clobber VARDEFs that initialize non-const static variables. + * tree-ssa.c (search_fud_chains): Set up def-use edges for PHI + nodes and regular definitions. + + * tree.c (simple_cst_equal): Call simple_cst_list_equal to compare + CONSTRUCTOR_ELTS pointers. + +2002-08-22 Diego Novillo + + * c-pretty-print.c (buffer): New file local variable. + (initialized): New file local variable. + (print_c_tree): Don't call init_output_buffer. Call + maybe_init_pretty_print. + (print_c_node): Ditto. + (print_c_node_brief): Ditto. + (maybe_init_pretty_print): New function. + * tree-mudflap.c (mf_varname_tree): Only call init_output_buffer + once. Call output_clear_message_text before returning. + +2002-08-21 Frank Ch. Eigler + + Support source-file/line coordinates in check/violation messages. + * tree-mudflap.c (mf_init_extern_trees): Add new "location" formal + arg to __mf_check. + (mf_file_function_line_tree): New function to build an actual location + string. + (build_check_statement_for): Call it / pass it. + (mx_xfn_indirect_ref): Track source file/line location via + STMT_LINENO, FILE_STMT, EXPR_WITH_FILE_LOCATION traversal memos. + +2002-08-21 Daniel Berlin + + * dominance.c: Cache immediate dominators. + +2002-08-20 Daniel Berlin + + * tree-alias-steen.h (struct tree_alias_ops): Add flag for + interprocedural. + + * tree-alias-steen.c (steen_alias_ops): Set interprocedural to 0 + for now. + (intra_function_call): New function to handle intraprocedural calling. + (finc_func_aliases): Use it. + Handle *x = *y, *x = &y, and *x = (cast) y. + (display_points_to_set_helper): New function, split from ... + (display_points_to_set): Here. + (create_alias_vars): Try to print all alias vars we find in the + alias_vars array, rather than just those that are linked directly to + trees. + Clear arrays when we finish if we aren't interprocedural. + +2002-08-20 Frank Ch. Eigler + + static object registration support: + * tree-mudflap.c (mudflap_enqueue_decl, mudflap_enqueue_constant): + Replace stubs with real code. + (mf_enqueue_register_call): New function to generate asm-object + call to __mf_register. + (mf_flush_enqueued_calls): New function to emit global ctor function + with enqueued __mf_register calls. + (mf_varname_tree): Tolerate being called from non-function context. + * c-objc-common.c: #include . + + gengtypes support for mudflap: + * Makefile.in (GTFILES): Include tree-mudflap.c. + (gt-tree-mudflap.h): New target. + * tree-mudflap.c: Annotate global tree nodes with GTY(()). + * tree-nomudflap.c: Add dummy ggc root table. + +2002-08-19 Diego Novillo + + * tree-dfa.c (find_refs_in_expr): If the current sub-expression is + not SIMPLE, mark its parent. + (create_ref): If the parent expression is not SIMPLE, create + VARDEFs regardless of the original reference type. + + * tree-ssa-ccp.c (widen_bitfield): New function. + (evaluate_expr_for): Call it. + +2002-08-18 Diego Novillo + + * tree-ssa-ccp.c (evaluate_expr_for): Fix thinko in + 2002-08-17 patch. + +2002-08-17 Diego Novillo + + * tree-ssa-ccp.c (evaluate_expr_for): keep VARREF_SYM in a local + variable. + +2002-08-16 Diego Novillo + + * basic-block.h (BB_CONTROL_EXPR): Update value. + (BB_LOOP_CONTROL_EXPR): Define. + (BB_CONTROL_ENTRY): Update value. + * tree-cfg.c (make_for_stmt_blocks): Flag header blocks withh + BB_LOOP_CONTROL_EXPR. + (make_while_stmt_blocks): Ditto. + (make_do_stmt_blocks): Ditto. + (tree_delete_bb): Update annotations in the loop entry block when + removing one of the loop expression blocks. + + * tree-dfa.c (tree_find_varrefs): Disregard empty blocks. + (find_refs_in_stmt): Handle all the loop expression blocks in + FOR_STMT and DO_STMT nodes. + (find_refs_in_expr): Change first argument to tree *. Update all + callers. + Force all references to be definitions when the expression is not + in SIMPLE form. + Also create references for compound variables and array references. + Not just their individual components. + Always use the original parent expression when making recursive + calls. + (create_ref): Add new argument operand_p. Update all callers. + (remove_tree_ann): New function. + (dump_varref): Don't assume that the referenced symbol is a _DECL + node. + * tree-flow.h (treeref_common): Add field operand_p. + (VARREF_OPERAND_P): Define. + (BB_EMPTY_P): Define. + (remove_tree_ann): Declare. + (create_ref): Add new argument operand_p. + * tree-simple.c (get_base_symbol): New function. + * tree-simple.h (get_base_symbol): Declare. + * tree-ssa-ccp.c (visit_assignment): Call it. + (ssa_ccp_substitute_constants): Use VARREF_OPERAND_P to replace + values into the expression. + (evaluate_expr_for): Ditto. + Do not try to evaluate the expression if the reference is not of + the same type as the expression. + After evaluation, restore the expression to its original form. + * tree-ssa-pre.c (insert_occ_in_preorder_dt_order_): Update calls + to create_ref. + (finalize_): Ditto. + (expr_phi_insertion): Ditto. + * tree-ssa.c (tree_build_ssa): Ditto. + (insert_phi_terms): Ditto. + (delete_ssa): Call remove_tree_ann. + +2002-08-15 Diego Novillo + + * c-pretty-print.c: Move extern definitions to diagnostic.h. + (print_c_node_brief): New function. + (debug_c_node_brief): New function. + (debug_c_node): Add option for showing brief versions of statement + nodes. Update all callers. + (print_declaration): Ditto. + * c-simplify.c (simplify_function_tree): Add newline to debug + output. + * c-tree.h (print_c_node_brief): Declare. + (debug_c_node_brief): Declare. + * tree-cfg.c: Call print_c_node_brief in debugging otuput. + * tree-mudflap.c (dump_c_node): Remove extern declaration. + (mf_varname_tree): Update call to dump_c_node. + +2002-08-15 Daniel Berlin + + * tree-cfg.c (find_expr_in_tree_helper): Renamed from find_expr_in_tree. + (find_expr_in_tree): Redone. + +2002-08-15 Daniel Berlin + + * tree-cfg.c (insert_before_ctrl_stmt): Fix insertion for various + parts of for loop. + + * tree-ssa-pre.c (finalize_1): Set EXPR_STMT type to type of + expression in it. + +2002-08-14 Frank Ch. Eigler + + * gcc.c (LINK_COMMAND_SPEC): Tweak placement of %(mflib). + +2002-08-14 Diego Novillo + + * tree-simple.h (is_simple_decl_stmt): Declare. + +2002-08-13 Frank Ch. Eigler + + * gcc.c (MFWRAP_SPEC, MFLIB_SPEC): New macros, splitting MFLIB_SPEC. + (mfwrap_spec, mflib_spec): Define corresponding vars. + (static_specs): Define correponding spec aliases. + (LINK_COMMAND_SPEC): Include -fmudflap refs to new spec aliases. + (cpp_unique_options): Move -fmudflap MFCPP_SPEC clause here. + (cc1_options): Move -fmudflap MFCC1_SPEC clause here. + (MFCC1_SPEC, MFCPP_SPEC, MFLIB_SPEC): Remove macros and uses. + +2002-08-13 Graydon Hoare + + * tree-mudflap.c (mf_build_check_statement_for): Factor code out of + mx_xfn_indirect_ref for use in ARRAY_REF case. + (mf_build_check_statement_for): Check size of underlying object + rather than size of pointer. + (mx_xfn_indirect_ref): Check ARRAY_REF expressions. + (mf_offset_expr_of_array_ref): New function to calculate array ref + offsets. + +2002-08-13 Diego Novillo + + * tree-simple.c (is_simple_condexpr): Update comment. + * tree-ssa-ccp.c (ssa_ccp_substitute_constants): Add debugging code. + +2002-08-12 Jason Merrill + + * c-typeck.c (build_component_ref): Don't add a NON_LVALUE_EXPR + in C99 mode. + + * c-simplify.c (simplify_expr): Always simplify. Loop if *expr_p + changed. + (simplify_addr_expr): Just replace *expr_p if we have a '&*'. + * tree-simple.c (is_simplifiable_builtin): Add more tree codes. + +2002-08-11 Diego Novillo + + * c-simplify.c: Fix typo. Substitute CHECKING with ENABLE_CHECKING. + * tree-cfg.c: Ditto. + * tree-dfa.c: Ditto. + * tree-ssa-ccp.c: Ditto. + * tree-ssa.c: Ditto. + +2002-08-11 Diego Novillo + + * tree-dfa.c (find_refs_in_expr): Use the given ref_type for some unary + expressions. + (create_ref): Insert ghost definitions at the beginning of the + basic block. + (find_expr_in_tree): Ignore IDENTIFIER_NODE. + * tree-flow.h (treeref_common): Move the id field to the end of the + structure. + (IS_GHOST_DEF): Redefine to return non zero for definitions + without an associated expression in basic block 0. + * tree-ssa-ccp.c (tree_ssa_ccp): Use last_basic_block to allocate + executable_blocks. + (visit_expression): Set the lattice value for ghost definitions to + VARYING. + (examine_flow_edges): Update comments. + * tree-ssa.c (tree_build_ssa): Create ghost definitions in basic + block 0. + (insert_phi_terms): Don't ignore ghost definitions. + + * c-simplify.c (simplify_function_tree): Return 0 if the function's + body is not a COMPOUND_STMT. + Return 0 if simplification failed. + (simplify_expr): Change to return int. Return non zero if + simplification was successful. + (c_simplify_expr): Add default case to avoid compile time warnings. + (create_tmp_alias_var): Reformat comment. + * tree-simple.h (simplify_expr): Change return type to int. + + * c-simplify.c: Guard consistency checks with #if defined CHECKING + everywhere. + * tree-cfg.c: Ditto. + * tree-dfa.c: Ditto. + * tree-ssa-ccp.c: Ditto. + * tree-ssa.c: Ditto. + + * c-simplify.c: Include hard-reg-set.h, basic-block.h and + tree-flow.h. + (mark_not_simple_r): New function. + (simplify_expr): Temporarily mark VA_ARG_EXPR and BIT_FIELD_REF + trees as not simplifiable. + (simplify_call_expr): If the builtin cannot be simplified, flag it. + * Makefile.in (c-simplify.o): Update dependencies. + * tree-dfa.c (create_ref): Variable references inside + non-simplifiable expressions are always considered definitions. + * tree-flow.h (TF_NOT_SIMPLE): New flag. + * tree-simple.c (is_simplifiable_builtin): Update comments. + + * c-pretty-print.c (dump_c_node): Unparse anonymous structures and + unions. + Change rendering for SAVE_EXPR and BIT_FIELD_REF. + + * Makefile.in (tree-mudflap.o, tree-nomudflap.o): Add. + +2002-08-11 Frank Ch. Eigler + + Prototype -fmudflap support. + * Makefile.in (C_AND_OBJC_OBJS): Add tree-mudflap.o. + (OBJS): Add tree-nomudflap.o. + * flags.h (flag_mudflap): New flag. + * toplev.c: Map "-fmudflap" to that flag. + * c-decl.c (c_expand_body): Call mudflap_c_function if flag_mudflap. + * c-objc-common.c (c_objc_common_finish_file): Add mudflap hook. + * varasm.c (make_decl_rtl): Add mudflap hook. + (output_constant_def_contents): Ditto. + * tree-mudflap.c: New file: implement mudflap instrumentation. + * tree-nomudflap.c: New file: stub functions for non-C frontends. + * tree-mudflap.h: New file: define exported functions. + * gcc.c (MFLIB_SPEC, MFCC1_SPEC, MFCPP_SPEC): Add general + -fmudflap spec mappings. + * c-simplify.c (simplify_stmt): Stub: handle CLEANUP_STMT nodes. + * tree-dfa.c (find_refs_in_stmt): Ditto. + * c-pretty-print.c (dump_c_node): Ditto. + (print_declaration): Handle "extern" decls. Handle arrays with + indefinite sizes. + * tree-simple.h (is_simple_stmt, is_simple_compstmt): Remove decls. + +2002-08-11 Jason Merrill + + * c-simplify.c (simplify_self_mod_expr): Unshare the lhs before + using it again. + (simplify_compound_lval): Don't unshare. + + * c-simplify.c (c_simplify_expr): Check statement_code_p. + + * c-simplify.c (maybe_fixup_loop_cond): Move to cp/cp-simplify.c. + (simplify_for_stmt): Don't call it. + (simplify_while_stmt): Don't call it. + +2002-08-11 Diego Novillo + + * c-simplify.c (simplify_compound_lval): Use mostly_copy_tree_r. + +2002-08-09 Jason Merrill + + * langhooks-def.h: Replace the simplify_function_tree hook + with a simplify_expr hook. + * langhooks.h: Likewise. + * langhooks.c: Replace lhd_simplify_function_tree with + lhd_simplify_expr. + * c-lang.c (LANG_HOOKS_SIMPLIFY_FUNCTION_TREE): Don't define. + (LANG_HOOKS_SIMPLIFY_EXPR): Define. + * c-decl.c (c_expand_body): De-hook simplify_function_tree. + * c-common.h: Declare c_simplify_expr. + * c-simplify.c (simplify_function_tree): Rename from + c_simplify_function_tree. Call simplify_expr instead of + simplify_stmt. + (c_simplify_expr): Split out from... + (simplify_expr): ...here. No longer static. Call langhook. + (is_simple_decl_stmt): Move here from tree-simple.c. + * tree-simple.c: Don't include c-tree.h. + (is_simple_stmt, is_simple_compstmt): Remove. + (is_simple_decl_stmt): Move to c-simplify.c. + * tree.h: Declare simplify_function_tree. + * tree-simple.h: Declare simplify_expr, add_tree. + + * tree-simple.c (rationalize_compound_expr): New fn. + +2002-08-07 Diego Novillo + + * basic-block.h (EDGE_TRUE_VALUE): Define. + (EDGE_FALSE_VALUE): Define. + * tree-cfg.c: Include c-tree.h. + (make_for_stmt_edges): Call simple_cst_equal to determine infinite + and zero iteration loops. + Set EDGE_TRUE_VALUE and EDGE_FALSE_VALUE to edges coming out of + predicate block. + (make_while_stmt_edges): Ditto. + (make_do_stmt_edges): Ditto. + (make_if_stmt_edges): Set EDGE_TRUE_VALUE and EDGE_FALSE_VALUE to + edges coming out of predicate block. + + * c-simplify.c (simplify_compound_lval): Unshare the compound + reference before simplification. + + * tree-cfg.c (insert_before_ctrl_stmt): Call print_c_node instead of + print_node_brief. + (insert_before_normal_stmt): Ditto. + (insert_after_ctrl_stmt): Ditto. + (insert_after_normal_stmt): Ditto. + (insert_after_loop_body): Ditto. + (replace_expr_in_tree): Ditto. + (tree_dump_bb): Ditto. + + * tree-dfa.c: Include c-tree.h + (next_varref_id): New global variable. + (tree_find_varrefs): Initialize it to 0. + (create_ref): Increment it after creating a new reference. Store + it in ref.common.id. + Add the new reference to the list of references for the containing + expression. + (dump_varref): Show the reference ID. + * tree-flow.h (treeref_common): Add field 'id'. + (VARREF_ID): Define. + + * tree-dump.c (dump_files): Re-order dump files. + * tree.h (tree_dump_index): Ditto. + + * tree-optimize.c (optimize_function_tree): Remove blank lines. + + * tree-simple.c: Remove unary operator '!' from grammar. + + * tree-flow.h (tree_ann_def): Add field 'flags'. + (TF_FOLD): Define. + (TREE_ANN): Re-define into an lvalue. + (BB_FOR_STMT): Ditto. + (TREE_CURRDEF): Ditto. + (next_varref_id): Declare. + * tree-ssa-ccp.c: Include tree-simple.h + (ssa_edges): Convert sbitmap into varray_type. Update all uses. + (decl_map): Remove. + (SSA_NAME): Use VARREF_ID instead of DECL_UID. + (visit_assignment): New function. + (evaluate_expr_for): New function. + (dump_lattice_value): New function. + (tree_ssa_ccp): Add debugging dumps. + Remove #if 0 code everywhere. + (visit_phi_node): Add debugging dumps. + Also visit PHI arguments. + Remove basic block argument + (visit_expression): Re-implement. + (examine_flow_edges): Add debugging dumps. + (ssa_ccp_substitute_constants): Add debugging dumps. + Update comments. + Mark and fold expressions with substituted constants. + * tree-ssa.c (search_fud_chains): Don't check if BB_REFS(bb) is + empty before iterating. + Add comment explaining how we chain PHI node arguments to their + originating basic block. + + * Makefile.in (tree-cfg.o, tree-dfa.o, tree-ssa-ccp.o): Update + dependencies. + +2002-07-29 Daniel Berlin + + * tree-ssa-pre.c (tree_perform_ssapre): Ben forgot to add a + dump_begin call when he removed the before dump. + +2002-07-24 Daniel Berlin + + * tree-alias-ecr.c (ECR_new_with_type): Use correct number in mapping. + +2002-07-23 Daniel Berlin + + * c-simplify.c (simplify_for_stmt): Deep copy the result of the + tail_expression, so it's unshared. + +2002-07-23 Daniel Berlin + + * tree-flow.h: Add prototype for create_alias_vars. + + * tree-alias-steen.c (display_points_to_set): New function. + (init_alias_vars): Display points to sets when we are done. + + * disjoint-set.h (disjoint_set_def): ptr_alias to ECR_def so that + we mark parent properly. + +2002-07-24 Diego Novillo + + * Makefile.in (GTFILES): Move tree-alias-type.[ch], + tree-alias-ecr.[ch], tree-alias-steen.[ch] from ... + * c-config-lang.in (gtfiles): ... here. + + * tree-simple.c (is_simplifiable_builtin): Replace + BUILT_IN_VARARGS_START with BUILT_IN_VA_START. + +2002-07-23 Andreas Jaeger + + * tree-ssa-pre.c (hash_expr_tree): Remove. + + * c-call-graph.c (write_dtd): Remove. + + * tree-ssa.c (delete_refs): Remove. + +2002-07-23 Andreas Jaeger + + * gengtype.c (open_base_files): Add tree.h. + + * tree-alias-type.h: Remove inclusion of tree.h. + + * tree-alias-steen.c: Include tree.h. + Add prototype for create_fun_alias_var_ptf. + + * tree-alias-ecr.c: Add prototype for ECR_add_pending. + + * tree-ssa-pre.c (calculate_preorder): Remove unused variables. + + * tree-simple.c: Include expr.h and rtl.h for prototypes. + + * tree-optimize.c: Include tree-alias-steen.h for prototypes. + + * Makefile.in (tree-optimize.o): Add tree-alias-steen.h. + (tree-simple.o): Add expr.h and rtl.h. + (tree-alias-steen.o): Add tree.h. + + * diagnostic.h: Add declaration of debug_output_buffer. + + * c-call-graph.c (construct_call_graph): Make static to follow + declaration. + (construct_call_graph): Use #if 0 instead of C++ comments to + disable code. + +2002-07-20 Andreas Jaeger + + * doc/invoke.texi (Option Summary): Fix syntax. + +2002-07-19 Jason Merrill + + * c-simplify.c (simplify_return_stmt): Do simplify a returned + expression in a void function. + + * c-simplify.c (simplify_stmt_expr): Handle C++ return semantics. + +2002-07-19 Jason Merrill + + * c-pretty-print.c (dump_c_node) [TARGET_EXPR]: Handle. + [COND_EXPR]: Print a returned expression in a void function. + +2002-07-19 Ben Elliston + + * tree-ssa-pre.c (tree_perform_ssapre): Don't dump the original + tree before applying this optimisation. + + * flags.h (flag_dump_tree_all_ssa): New flag. + * toplev.c (flag_dump_tree_all_ssa): New flag. + (f_options): Add "dump-tree-all-ssa" option. + (process_options): Process flag_dump_tree_all_ssa. + * tree.h (dump_enable_all_ssa): Declare. + * tree-dump.c (dump_enable_all_ssa): New function. + * doc/invoke.texi (Option Summary): Add -fdump-tree-all-ssa and + -fdump-tree-ssapre options. + (Debugging Options): Describe in more detail. + * c-simplify.c (c_simplify_function_tree): Dump the original tree + only if a TDI_original dump is requested, rather than TDI_simple. + + * tree-dump.c (dump_begin): Include phase number in dump filename. + +2002-07-18 Ben Elliston + + * tree-dump.c (dump_files): Rename "unparse" to "raw". + * tree.h (TDF_UNPARSE): Rename from this .. + (TDF_RAW): .. to this. + * tree-ssa-pre.c (tree_perform_ssapre): Use TDF_RAW and invert the + logical sense of this flag. + * tree-ssa-ccp.c (tree_ssa_ccp): Likewise. + * c-simplify.c (c_simplify_function_tree): Likewise. + +2002-07-18 Daniel Berlin + + * tree-ssa-pre.c (calculate_preorder): New function. + (tree_perform_ssapre): Use it, rather than + flow_compute_preorder_tranversal, which seems to not do + what we want. + +2002-07-18 Daniel Berlin + + * tree-alias-type.c: Move gt-tree-alias-type include to end of file. + + * tree-alias-steen.c: Move gt-tree-alias-steen include to end of file. + +2002-07-18 Daniel Berlin + + * gengtype.c (get_base_file_bitmap): Mark tree-alias-* and + disjoint-set* as c/c++/objc files only. + + * Makefile.in (gt-tree-alias-type.h): Add. + (tree-alias-type.o): Add dependency on gt-tree-alias-type.h. + + * tree-alias-type.c: Include gt-tree-alias-type.h. + (alias_bottom): Add a GTY marked version of alias_bottom here. + + * tree-alias-type.h: Remove the GTY marker from alias_bottom. + +2002-07-17 Daniel Berlin + + * tree-alias-ecr.c (ECR_union_pending_sets): Only clear bitmap if + it's not NULL. + +2002-07-16 Jason Merrill + + * c-simplify.c (add_tree): Build an EXPR_STMT immediately. + (convert_to_stmt_chain): Remove. + (simplify_stmt, simplify_for_stmt, simplify_while_stmt, + simplify_do_stmt, simplify_expr_wfl, tail_expression): Adjust. + +2002-07-17 Daniel Berlin + + * tree-alias-ecr.c: New file. Equivalence Class Representation. + + * tree-alias-steen.c: New file. Steengaard Alias Analysis. + + * disjoint-set.c: New file. Disjoint set data structure. + + * tree-alias-type.c: New file. Alias types. + + * c-simplify.c (create_tmp_alias_var): New function, like + create_tmp_var, but doesn't add it to the current binding. + + * tree-simple.h: Prototype for create_tmp_alias_var. + + * tree-optimize.c (build_tree_ssa): Create alias variables, if + requested. + + * flags.h: Add flag_tree_points_to. + + * toplev.c: Ditto. + + * gengtype.c (open_base_files): Add disjoint-set.h, + tree-alias-ecr.h, tree-alias-type.h, tree-flow.h. + + * Makefile.in (C_AND_OBJC_OBJS): Add disjoint-set.o, + tree-alias-ecr.o, tree-alias-type.o, tree-alias-steen.o. + (tree-alias-steen.o): Add dependencies. + (tree-alias-ecr.o): Ditto. + (tree-alias-type.o): Ditto. + (disjoint-set.o): Ditto. + +2002-07-10 Daniel Berlin + Diego Novillo + + * Makefile.in (C_AND_OBJC_OBJS): Add tree-ssa-ccp.o + * flags.h (flag_tree_ssa_ccp): Declare. + * fold-const.c (eval_subst): Make extern. + * toplev.c (flag_tree_ssa_ccp): Define. + (f_options): Document -ftree-ssa-ccp. + * tree-dump.c (dump_files): Add -fdump-tree-ccp. + * tree-flow.h (tree_perform_ssapre): Move declaration ... + * tree-optimize.h: ... here. + (tree_ssa_ccp): Declare. + * tree-optimize.c (optimize_function_tree): Call tree_ssa_ccp. + * tree-ssa-ccp.c: New file. + * tree.c (next_decl_uid): Remove static declaration. + * tree.h (next_decl_uid): Declare. + (tree_dump_index): Add TDI_ccp. + * cp/Make-lang.in (CXX_C_OBJS): Add tree-ssa-ccp.o. + * doc/invoke.texi: Document -ftree-ssa-pre and -ftree-ssa-ccp. + +2002-07-09 Daniel Berlin + + s/varrays of refs/ref_list of refs/g + + * tree-flow.h: Add ref_list structure. + Add prototypes for ref_list functions. + (FOR_EACH_REF, FOR_EACH_REF_REV): New macros to iterate through + ref lists. + * tree-cfg.c, tree-ssa.c, tree-ssa-pre.c: Update all uses. + + * tree-dfa.c (create_ref_list): New function. + (delete_ref_list): Ditto. + (empty_ref_list): Ditto. + (add_ref_to_list_end): Ditto. + (add_ref_to_list_begin): Ditto. + (remove_ref_from_list): Ditto. + +2002-07-04 Diego Novillo + + * tree-simple.c (is_simplifiable_builtin): Don't simplify target + builtins. + +2002-07-03 Diego Novillo + + * c-simplify.c (simplify_decl_stmt): Unshare the + initializer nodes before simplification. + +2002-06-29 Aldy Hernandez + Diego Novillo + + * c-simplify.c (simplify_call_expr): Do not bail on all builtins. + (is_simple_call_expr): Same. + (simplify_addr_expr): New function. + (simplify_expr): Call it. + + * tree-simple.c (is_simplifiable_builtin): New. + (is_simple_compound_lval): Do not bail on INDIRECT_REF. + + * tree-simple.h: New prototype for is_simplifiable_builtin. + +2002-06-26 Daniel Berlin + + * tree-ssa.c (tree_build_ssa): Call free_dominance_info, not + free, on idom. + + * tree-ssa-pre.c (compute_domchildren): Update to use new + dominance_info structure, rather than idom array. + (tree_perform_ssapre): Don't forget to free the dominance info. + + s/VARRAY_FREE/VARRAY_CLEAR/g now that VARRAY's are ggc allocated. + +2002-06-24 Diego Novillo + + * tree-ssa.c (build_fud_chains): Use dominance_info instead of int *. + (search_fud_chains): Ditto. + Call get_immediate_dominator. + * tree-ssa-pre.c (a_dom_b): Call dominated_by_p. + (pre_idom): Change type to dominance_info. Update all uses. + (pre_doms): Remove. Update all uses. + +2002-06-20 Jason Merrill + + Simplify DECL_STMT, CONSTRUCTOR and COMPOUND_LITERAL_EXPR. + * tree-simple.c (is_simple_decl_stmt): New fn. + (is_simple_constructor, is_simple_constructor_elt): New fns. + (is_simple_stmt, is_simple_unary_expr): Use them. + (is_simple_modify_expr): Accept an INIT_EXPR. + (is_simple_id): Don't allow a COMPOUND_LITERAL_EXPR. + (is_simple_unary_expr): Here either. + * c-simplify.c (simplify_decl_stmt, simplify_constructor): New fns. + (simplify_compound_literal_expr): New fn. + (simplify_stmt, simplify_expr): Use them. + (get_initialized_tmp_var): Use an INIT_EXPR. + (simplify_modify_expr): Accept an INIT_EXPR. + (simplify_for_stmt): Call simplify_decl_stmt. + (get_name): Don't crash if the decl is anonymous. + (tail_expression): New fn. + * tree-simple.h: Declare new fns. + * c-pretty-print.c (dump_c_node) [INIT_EXPR]: Print like MODIFY_EXPR. + (dump_c_node, op_prio): Handle COMPOUND_LITERAL_EXPR. + * c-simplify.c (simplify_expr_wfl): Only wrap pre and post stuff + that came from our subexpression. + (simplify_stmt): Restore stmts_are_full_exprs_p. + + * c-simplify.c (simplify_expr_wfl): Bracket substatements with + FILE_STMTs rather than wrapping them in EXPR_WITH_FILE_LOCATION. + (simplify_stmt): Update lineno and input_filename from stmts. + (simplify_expr et al): Don't copy lineno between stmts. Don't pass + enclosing stmt down. + (update_line_number): Remove. + + * c-simplify.c (simplify_expr_stmt): Don't check + is_last_stmt_of_scope. + (simplify_stmt_expr): Check it here. Set *expr_p to void_zero_node + instead of NULL_TREE. + (expr_has_effect): No need to deal with NULL exprs now. + (simplify_expr_wfl): Likewise. + +2002-06-18 Diego Novillo + + * c-simplify.c (strip_off_ending): Rename to remove_suffix. + Update callers. + (is_last_stmt_of_scope): New function. + (simplify_expr_stmt): Call it. + (stmt_has_effect): Ditto. + (c_simplify_function_tree): Update comment. + +2002-06-18 Jason Merrill + + * c-simplify.c (maybe_fixup_loop_cond): New fn for C++ conditions. + (simplify_for_stmt, simplify_while_stmt): Use it. + + * c-pretty-print.c (dump_c_node) [COMPONENT_REF]: Print "->" if + appropriate. + +2002-06-19 Jason Merrill + + * c-simplify.c (simplify_stmt_expr): New fn. + (simplify_expr): Call it. + (stmt_expr_level): Remove. + (stmt_has_effect, c_simplify_function_tree): Remove refs. + (expr_has_effect): Deal with null expression. + (simplify_expr_wfl): If the subexpression is simplified away, drop + this one, too. Don't wrap statements. + * tree-simple.c (is_simple_unary_expr): Don't allow a STMT_EXPR. + * tree-inline.c (copy_tree_r): Clear the aux field in the copies. + +2002-06-17 Frank Ch. Eigler + + * c-pretty-print.c (dump_c_node): Print pointer-type + integer constants as raw numbers with a "B" (bytes) suffix. + +2002-06-17 Jason Merrill + + * c-simplify.c (simplify_stmt): Take a tree *. + (various): Adjust. + +2002-06-16 Daniel Berlin + + * c-simplify.c (get_name): New function. + (get_initialized_tmp_var): Use it to try to get a prefix for + create_tmp_var from the value we are initializing to. + (simplify_cond_expr): Add prefix for create_tmp_var. + (create_tmp_var): Add prefix argument. + + * tree-simple.h: Change create_tmp_var prototype to match. + + * tree-ssa-pre.c: Change create_tmp_var call. + +2002-06-15 Diego Novillo + + * Makefile.in (c-decl.o): Add dependency on langhooks.h + (c-simplify.o): Add dependency on flags.h, langhooks.h, toplev.h + and rtl.h. + * c-decl.c: Include langhooks.h. + (c_expand_body): Simplify the function. If it succeeds and + -ftree-ssa is enabled, call optimize_function_tree. + * c-simplify.c: Include flags.h, rtl.h and toplev.h. + (simplify_expr_stmt): New function. + (simplify_stmt): Call it. + * tree-optimize.c: Don't include langhooks.h. + (optimize_function_tree): Don't call lang_hooks.simplify_function_tree. + + * c-decl.c (c_expand_body): Do not simplify nor optimize the + function if -fdisable-simple is given. + * c-simplify.c (simplify_expr): Use is_simple_addr_expr_arg when + simplifying ADDR_EXPR nodes. + * flags.h (flag_disable_simple): Declare. + * toplev.c (flag_disable_simple): Define. + (f_options): Document -fdisable-simple. + (process_options): Warn if -fdisable-simple is used with + optimization enabled. + * tree-simple.c (is_simple_addr_expr_arg): New function. + (is_simple_unary_expr): Call it. + * tree-simple.h (is_simple_addr_expr_arg): Declare. + * doc/invoke.texi: Document -fdisable-simple. + + * c-pretty-print.c (dump_c_node): Handle DECL_STMT nodes inside + FOR_INIT_STMT. + * c-simplify.c (c_simplify_function_tree): Don't do anything if the + program had errors. + (simplify_stmt): Skip DECL_STMTs. + (simplify_for_stmt): Handle DECL_STMT nodes inside FOR_INIT_STMT. + (simplify_save_expr): New function. + (simplify_expr): Call it. + (tree_last_decl): Handle cases where DECL_STMTs are found before + the body of the function. + * tree-simple.c (is_simple_stmt): Handle DECL_STMT nodes inside + FOR_INIT_STMT. + (is_simple_compound_lval): Handle nodes wrapped in NON_LVALUE_EXPR. + +2002-06-14 Frank Ch. Eigler + + * c-pretty-print.c (dump_c_node): Print more type qualifiers, + especially for pointers. + +2002-06-11 Diego Novillo + + * c-simplify.c: Remove folding markers. + (insert_before_first): Remove unused function. + * tree-cfg.c: Remove folding markers. + * tree-dfa.c: Ditto. + * tree-flow.h: Ditto. + * tree-optimize.c: Ditto. + * tree-optimize.h: Ditto. + * tree-simple.c: Ditto. + * tree-ssa.c: Ditto. + +2002-06-11 Jason Merrill + + * c-simplify.c (add_tree): Don't deep-copy expressions. + (simplify_for_stmt): Only deep-copy pre_cond_s the first time. + Don't deep copy expr_chain. + +2002-06-10 Diego Novillo + + * tree-cfg.c (remove_bb_ann): Don't call VARRAY_FREE. + * tree-dfa.c (create_ref): Use sizeof (ref) instead of + refs->element_size. + * tree.h (struct tree_common): Skip field 'aux' from GC type + information. + * tree-optimize.c (optimize_function_tree): Don't call + VARRAY_REF. + * tree-ssa.c (insert_phi_terms): Ditto. + (delete_refs): Ditto. + * c-simplify.c (simplify_array_ref): Ditto. + * simple-break-elim.c: Disable whole file. + * simple-goto-elim.c: Disable whole file. + +2002-06-10 Jason Merrill + + * c-simplify.c (simplify_switch_stmt): Let simplify_expr handle + post-effects. Reorder. + (simplify_if_stmt): Likewise. Don't build redundant comparison. + (simplify_do_stmt, simplify_while_stmt): Likewise. + (simplify_for_stmt): Likewise. Remove POST_P parm. + (simplify_stmt): Adjust. + (insert_before_first): #if 0, no longer used. + + * c-pretty-print.c (dump_c_node): Print FIX_TRUNC_EXPR, FLOAT_EXPR + et al as casts. Add parens as needed. + + * tree-simple.c (is_union_based_ref): New fn. + (is_simple_min_lval): Use it. Rename from is_simple_arraybase. + (is_simple_arrayref): Adjust. Use loop instead of recursion. + (is_simple_compref): Likewise. + (is_simple_compref_lhs): Remove. + * tree-simple.h: Adjust. + * c-simplify.c (simplify_array_ref): Adjust. + (simplify_component_ref): Adjust. + + * c-simplify.c (simplify_expr_common): Tweak ordering. + (get_initialized_tmp_var): Let simplify_expr handle post-effects. + * tree-simple.c (is_simple_stmt): Accept an rhs for a return expr. + + * c-simplify.c (simplify_boolean_expr): Avoid redundant tests. + Give the temp the appropriate type for a boolean value, and + reconvert at the end. + + * c-simplify.c (simplify_self_mod_expr): Don't duplicate side-effects. + + * c-simplify.c (simplify_return_stmt): Accept a SIMPLE rhs. + Just hand off to simplify_expr. + + * c-simplify.c (get_initialized_tmp_var): New fn. + (simplify_expr_common): Use it. Handle post-effects internally if + POST_P is NULL. + (is_simple_tmp_var): Rename from simple_tmp_var_p. + * tree-simple.h: Adjust. + +2002-06-09 Diego Novillo + + * c-simplify.c (simplify_return_stmt): Update folding markers. + (build_addr_expr): Ditto. + * langhooks.h (struct langhooks): Document simplify_function_tree + hook. + +2002-06-09 Jason Merrill + + * c-simplify.c (simplify_expr_common): Handle creating both lvalue + and rvalue temps. Add new parameter to specify which. + (simplify_expr): Now just a wrapper. + (simplify_lvalue_expr): Likewise. + (simplify_expr_either): New wrapper. + (simplify_component_ref): Use it instead of simplify_lvalue_expr. + + * c-pretty-print.c (debug_c_tree): Add a trailing newline. + (debug_c_node): Likewise. + * gdbinit.in (pct): New macro, calls debug_c_tree. + +2002-06-08 Jason Merrill + + * tree-simple.c (is_simple_unary_expr): Only allow the address of + a varname. + (is_simple_id): Allow STRING_CST. + * c-simplify.c (simplify_expr_common): Split out from simplify_expr. + Do simplify ADDR_EXPR. + (simplify_lvalue_expr): Use it and build_addr_expr. Take + simple_test_f. + (simplify_modify_expr): Adjust. + (build_addr_expr): New fn. + (simplify_array_ref): Use simplify_lvalue_expr. + (simplify_component_ref): Likewise. + + * tree-simple.c (is_simple_rhs): Remove condexpr rule. + (is_simple_compref_lhs): Remove &ID.idlist rule. + (is_simple_relop): New fn. + (is_simple_binary_expr, is_simple_condexpr): Use it. + * tree-simple.h: Declare it. + + * c-simplify.c (create_tmp_var): Refuse to create an array temp. + (simple_tmp_var_p): New fn. + (simplify_lvalue_expr): Use it; make sure we don't return a temp. + * tree-simple.h: Declare it. + + * c-pretty-print.c (dump_c_node) [ARRAY_REF]: Wrap array in parens + as needed. + [COMPONENT_REF]: Likewise. + [POINTER_TYPE]: Fix pointer-to-function handling. + [ARRAY_TYPE]: Don't try to print an unknown dimension. + + * tree-simple.c (is_simple_arraybase): New function. + (is_simple_arrayref): Use it to check the array base again. + * tree-simple.h: Add declaration. + * c-simplify.c (simplify_array_ref): Do simplify the base. + * expr.c (expand_expr): First make sure the type has a size. + +2002-06-07 Jason Merrill + + * cppexp.c (num_equality_op): Use a temporary variable to work + around gcc 3.0.4 bug. + +2002-06-05 Diego Novillo + + * Makefile.in (BOOT_CFLAGS): Remove -ftree-ssa. + * c-decl.c (c_expand_body): Call optimize_function_tree if tree SSA + is enabled. + * c-lang.c (LANG_HOOKS_SIMPLIFY_FUNCTION_TREE): Define. + * c-simplify.c (simplify_tree): Rename to c_simplify_function_tree. + Update all callers. + Dump function body before and after simplification if + -fdump-tree-simple is used. + (simplify_expr): Document FIXME for simplification of BIT_FIELD_REF + nodes. + * c-tree.h (simplify_tree): Rename to c_simplify_function_tree. + * langhooks-def.h (LANG_HOOKS_SIMPLIFY_FUNCTION_TREE): Define + (LANGHOOKS_INITIALIZER): Add LANG_HOOKS_SIMPLIFY_FUNCTION_TREE. + (lhd_simplify_function_tree): Declare. + * langhooks.c (lhd_simplify_function_tree): New function. + * langhooks.h (lang_hooks): Add simplify_function_tree function + pointer. + * toplev.c (parse_options_and_default_flags): Set flag_tree_ssa to + 1 at optimization levels >= 1. + Revert to default warning when -Wuninitialized is used without -O. + * tree-cfg.c (tree_find_basic_blocks): Rename argument 't' to + 'fnbody'. + * tree-optimize.c: Include langhooks.h. + (optimize_tree): Rename to optimize_function_tree. Update all + users. + Rename argument 't' to 'fndecl'. + Call simplify langhook before building SSA. + (build_tree_ssa): Rename argument 't' to 'fndecl'. + Adjust call to tree_find_basic_blocks to pass body of the function. + * tree-optimize.h (optimize_tree): Rename to + optimize_function_tree. + * tree-simple.c (is_simple_unary_expr): Document FIXME on + BIT_FIELD_REF nodes. + * tree-ssa.c: Add whitespace. + * testsuite/lib/c-torture.exp: Remove -ftree-ssa flag. + +2002-06-03 Daniel Berlin + + * tree-cfg.c (insert_before_*): For insertion into FOR_INIT's, if + we have an expression statement, transform into a compound + expression. + Pick the right place to insert a statement by iterating until we + have a first_exec_stmt (first_non_decl_stmt) that is really the + first executable non decl statement. + (insert_after_*): Ditto. + +2002-06-03 Daniel Berlin + + * tree-ssa-pre.c: Update BB stuff to new basic block structure. + Add some comments throughout (more coming, particularly describing + the algorithm, rather than the implementation). + (free_expr_info): Free refs as well. + (defs_y_dom_x): Handle unary expressions as well. + (insert_euse_in_preorder_dt_order_1): Use block of ref, not block + of statement. + Don't insert exit blocks if we hit them before hitting an + occurrence (it's pointless). + (rename_2): Return set of phi operands we touched, don't forget to + free VARRAY's we allocated. + (rename_1): Correct downsafety computation. Now get exact same + results as Open64. + Correct setting of has_real_use. + (finalize_1): Fix up insertion. + (code_motion): Fix up insertion. + + * tree-dfa.c (dump_varref): Improve dumping of expression + references. + +2002-06-03 Diego Novillo + + * tree-cfg.c (delete_bb): Rename to tree_delete_bb. Update callers. + (tree_find_basic_blocks): Initializer last_basic_block. + (create_bb): Update last_basic_block after creating a new block. + (tree_cleanup_cfg): Delete unreachable blocks by traversing the + linked list, not the array. Update comments. + (delete_bb): Update comments. + (tree_dump_cfg): Also show last_basic_block. + * tree-ssa.c (tree_build_ssa): Use last_basic_block instead of + n_basic_blocks to allocate dominator arrays. + (insert_phi_terms): Ditto. + (search_fud_chains): User FOR_EACH_BB to look for dominator + children. + +2002-05-29 Diego Novillo + + * tree-cfg.c (tree_find_basic_blocks): Set next_bb and prev_bb for + ENTRY_BLOCK_PTR and EXIT_BLOCK_PTR. + (create_bb): Set flag BB_NEW for every newly created block. + Call link_block to add the new block to the linked list. + (tree_split_bb): Traverse basic blocks using FOR_EACH_BB. + (make_goto_stmt_edges): Ditto. + (remove_unreachable_blocks): Add reminder comment to stop + compacting the basic block array every time a block is deleted. + (delete_cfg): Traverse basic blocks using FOR_EACH_BB. + (tree_dump_bb): Ditto. + (tree_dump_cfg): Ditto. + (tree_cfg2dot): Ditto. + * tree-dfa.c (tree_find_varrefs): Ditto. + (create_tree_ann): Ditto. + (get_fcalls): Ditto. + (find_declaration): Ditto. + * tree-ssa.c (tree_build_ssa): Ditto. + +2002-05-28 Diego Novillo + + * Makefile.in: Add -ftree-ssa to BOOT_CFLAGS. + +2002-05-27 Diego Novillo + + * c-decl.c (c_expand_body): Close dump file before simplifying the + function. + * c-pretty-print.c (dump_c_node): Handle COMPLEX_CST, + BIT_FIELD_REF, COMPLEX_EXPR, CONJ_EXPR, REALPART_EXPR, + IMAGPART_EXPR and VA_ARG_EXPR nodes. + Display all type casts, not just pointer casts. + (op_prio): Handle LROTATE_EXPR, RROTATE_EXPR, REALPART_EXPR and + IMAGPART_EXPR. + * c-simplify.c: Include "tree-inline.h" + (dump_file): New local variable. + (dump_flags): New local variable. + (stmt_expr_level): New local variable. + (simplify_tree): Open and close dump file if + -fdump-tree-simple-details is given. + Initialize stmt_expr_level. + (simplify_stmt): Dump statement before and after simplification if + -fdump-tree-simple-detail is given. + Unshare the expression of an EXPR_STMT before simplifying it. + Call simplify_return_stmt to handle RETURN_STMT nodes. + Do not simplify DECL_STMT nodes. + Call stmt_has_effect before re-chaining side effects. + (simplify_for_stmt): Do not return the simplified statement. + Update all callers. + Simplify FOR_BODY after the headers. + Unshare loop header expressions before simplification. + (simplify_while_stmt): Do not return the simplified statement. + Update all callers. + Simplify WHILE_BODY after the headers. + Unshare the loop header expression before simplification. + (simplify_do_stmt): Do not return the simplified statement. Update + all callers. + Unshare the loop header expression before simplification. + (simplify_if_stmt): Do not return the simplified statement. Update + all callers. + Simplify the condition expression before the clauses. + Unshare the condition expression before simplification. + (simplify_switch_stmt): Do not return the simplified statement. + Update all callers. + Simplify the switch expression before the body. + Unshare the switch expression before simplification. + (simplify_decl_stmt): Remove. + (simplify_expr): Remove argument 'needs_lvalue'. + Add argument 'stmt'. + Replace first argument 'expr' with a pointer to the + expression 'expr_p'. + Do not return the simplified expression. + Update all callers and uses. + Handle TRUTH_NOT_EXPR nodes. Simplify SAVE_EXPR nodes into a + SIMPLE id and remove the SAVE_EXPR node. + Do not simplify BIT_FIELD_REF nodes. + Remove code that tried to create new lvalues. + (simplify_array_ref): Replace first argument 'expr' with a pointer + to the expression 'expr_p'. + Do not return the simplified expression. + Add argument 'stmt'. + Update all callers and uses. + (simplify_self_mod_expr): Replace first argument 'expr' with a + pointer to the expression 'expr_p'. + Do not return the simplified expression. + Add argument 'stmt'. + Update all callers and uses. + Call simplify_lvalue_expr to simplify a copy of the LHS into an + lvalue for the new assignment. + Simplify the new binary expression. + (simplify_component_ref): Replace first argument 'expr' with a + pointer to the expression 'expr_p'. + Do not return the simplified expression. + Add argument 'stmt'. + Update all callers and uses. + (simplify_call_expr): Ditto. + (simplify_tree_list): Ditto. + (simplify_cond_expr): Ditto. + Build a replacement IF_STMT and call simplify_if_stmt() to process + it. Set the line number of the new statement from the statement + containing the original expression. + (simplify_modify_expr): Replace first argument 'expr' with a + pointer to the expression 'expr_p'. + Do not return the simplified expression. + Add argument 'stmt'. + Update all callers. + Call simplify_lvalue_expr to simplify the LHS of the assignment. + (simplify_boolean_expr): Replace first argument 'expr' with a + pointer to the expression 'expr_p'. + Do not return the simplified expression. + Add argument 'stmt'. + Update all callers. + Build a new IF_STMT and simplify it all at once by calling + simplify_if_stmt. + (simplify_compound_expr): Replace first argument 'expr' with a + pointer to the expression 'expr_p'. + Do not return the simplified expression. + Add argument 'stmt'. + Update all callers. + (simplify_expr_wfl): Ditto. + (simplify_lvalue_expr): New function. + (add_tree): Create a copy of each expression before adding it to + the list. + (deep_copy_node): Call copy_tree_r to copy expression nodes. + (stmt_has_effect): Return nonzero if the statement may be the last + statement of a statement expression body. + (mostly_copy_tree_r): New function. + * tree-dump.c (dump_options): Add 'details'. + * tree-simple.c: Update documentation about ADDRESSOF expressions. + (is_simple_stmt): Test for SIMPLE values when checking return + statements. + Accept all DECL_STMT nodes. + (is_simple_compstmt): Return nonzero if T is NULL. Do not test + DECL_STMT nodes + (is_simple_expr): Return nonzero if T is NULL. + (is_simple_rhs): Ditto. + (is_simple_modify_expr): Ditto. + (is_simple_modify_expr_lhs): Ditto. + (is_simple_binary_expr): Ditto. + (is_simple_cond_expr): Ditto. + (is_simple_unary_expr): Call STRIP_NOPS before testing T. + Always accept ADDR_EXPR nodes. + Always accept BIT_FIELD_REF nodes. + (is_simple_call_expr): Return nonzero if T is NULL. + (is_simple_const): Ditto. + (is_simple_val): Ditto. + (is_simple_compref): Ditto. + (is_simple_compref_lhs): Ditto. + (is_simple_cast): Ditto. + (is_simple_cast_op): Ditto. + (is_simple_id): Return nonzero if T is NULL. Allow identifiers + wrapped inside NON_LVALUE_EXPR and EXPR_WITH_FILE_LOCATION nodes. + Allow real and imaginary parts of a complex variable. + Allow compound literals. + (is_simple_arrayref): Allow arrays of complex types. + * tree.h (TDF_DETAILS): Define. + * cp/pt.c (tsubst_template_parms): Check that 'parms' is non-NULL + before calling TMPL_PARMS_DEPTH. + * doc/invoke.texi: Document -fdump-tree-simple-details. + +2002-05-10 Daniel Berlin + + * c-pretty-print.c (dump_c_node): Print "" for + types, variables, etc that have no name, rather than printing + nothing. + Handle PMF's properly. + Print out structure initializers in a somewhat sensible way. + Print SAVE_EXPR () around SAVE_EXPRs. + (print_call_name): Handle EXPR_WITH_FILE_LOCATION. + +2002-05-09 Daniel Berlin + + * tree-dfa.c (dump_varref): Tree inlining generates variables with + no name. Don't crash on dumping varref's of them. + + * tree-inline.c (expand_call_inline): Generate a proper STMT_EXPR + (it was missing COMPOUND_STMT). + +2002-05-08 Daniel Berlin + + s/varref_type/treeref_type/g + s/create_varref/create_ref/g + + * tree-flow.h: Add EXPRPHI, EXPRUSE, EXPRKILL, EXPRINJ. + Add structures and macros for each. + Add tree_perform_ssapre prototype. + + * Makefile.in (C_AND_OBJC_OBJS): Add tree-ssa-pre.o + (tree-ssa-pre.o): Add dependencies for tree-ssa-pre.o + + * cp/Make-lang.in: Add tree-ssa-pre.o + + * flags.h: Add flag_tree_ssa_pre. + + * tree-ssa-pre.c: New file, SSA-PRE. + + * toplev.c: Add flag_tree_ssa_pre. + (lang_independent_options): Add tree-ssa-pre. + + * tree-dump.c (dump_files): Add ssapre dump. + + * tree-optimize.c (optimize_tree): Do SSAPRE if requested. + + * tree.h (dump_index): Add TDI_ssa_pre. + + * tree-dfa.c (create_ref): Add support for creating the EXPR*'s refs. + (dump_varref): Add support for dumping EXPR* refs. + + * tree-ssa.c (search_fud_chains): Add BB to VARDEF_PHI_CHAIN_BB. + +2002-05-07 Diego Novillo + + * c-pretty-print.c (op_prio): Handle ABS_EXPR. + Don't abort when the operand is not recognized. + (op_symbol): Don't abort when the operand is not recognized. + * c-simplify.c (simplify_expr): Remove 'const' qualifier from first + argument. + Do not copy incoming expression. + Exclude handling of MODIFY_EXPR, INIT_EXPR, SAVE_EXPR and binary + expression nodes. + (simplify_array_ref): Remove 'const' qualifier from first argument. + Do not copy the incoming expression. + (simplify_self_mod_expr): Ditto. + Do not simplify the first operand twice. + (simplify_component_ref): Remove 'const' qualifier from first + argument. Do not copy the incoming expression. + (simplify_call_expr): Ditto. + (simplify_tree_list): Ditto. + (simplify_cond_expr): Ditto. + (simplify_modify_expr): Ditto. + (simplify_boolean_expr): Ditto. + (simplify_compound_expr): Ditto. + (simplify_save_expr): Ditto. + (simplify_expr_wfl): Ditto. + (tree_build_scope): Re-write. Do nothing if block already contains + a scope. Use chainon to chain the body with the scope closing + node. + (deep_copy_node): Do not check for NULL nodes. Do not deep copy + declarations, types and constants. + +2002-05-06 Daniel Berlin + + * c-simplify.c (deep_copy_node): Don't copy DECL_STMT_DECL's. + +2002-05-06 Daniel Berlin + + * tree-simple.c (is_simple_compstmt): Don't post-initialize + statics or aggregate initializers. + + * c-simplify.c (simplify_decl_stmt): Ditto. + +2002-05-06 Sebastian Pop + + * Makefile.in (simple-break-elim.o, simple-goto-elim.o, tree-dchain.o): + Added. + * c-decl.c: Include tree-dchain.h + (c_expand_body): Add entry point to the goto, break elimination + after the simplification pass. + * simple-break-elim.c: New file. + * simple-goto-elim.c: New file. + * tree-dchain.h: New file. + * tree-dchain.c: New file. + +2002-05-02 Diego Novillo + + * c-simplify.c (simplify_expr): Constify first argument. + Always work on a copy of the input expression. + Do not simplify COMPOUND_LITERAL_EXPR nor CONSTRUCTOR nodes. + (simplify_array_ref): Constify first argument. Always work on a + copy of the input expression. + (simplify_self_mod_expr): Ditto. + (simplify_component_ref): Ditto. + (simplify_call_expr): Ditto. + (simplify_tree_list): Ditto. + (simplify_cond_expr): Ditto. + When building the THEN_CLAUSE and ELSE_CLAUSE for the new IF_STMT, + create a scope for them and simplify the scope, not the expression. + (simplify_modify_expr): Constify first argument. Always work on a + copy of the input expression. + (simplify_boolean_expr): Ditto. + (simplify_compound_expr): Ditto. + (simplify_save_expr): Ditto. + (simplify_expr_wfl): Ditto. + * tree-cfg.c (tree_find_basic_blocks): Update comments for + -fdump-tree-dot. + (tree_dump_cfg): Ditto. + * tree-dump.c (dump_files): Rename -fdump-tree-graphviz to + -fdump-tree-dot. + * tree-simple.c (is_simple_unary_expr): Do not handle &CONST + expressions. + Handle COMPOUND_LITERAL_EXPR and CONSTRUCTOR nodes. + (is_simple_const): Strip NOPS and handle &CONST expressions. + * tree.h (enum tree_dump_index): Remove references to GraphViz. + * doc/invoke.texi: Update documentation for -fdump-tree-dot. + +2002-05-02 Sebastian Pop + + * c-pretty-print.c (dump_c_node): Don't print declarations + from the SCOPE_STMT_BLOCK, use the DECL_STMT instead. + +2002-04-30 Diego Novillo + + * c-pretty-print.c (NIY): Display an error string instead of aborting. + (op_prio): Add support for COMPOUND_EXPR, TRUTH_XOR_EXPR, MIN_EXPR, + MAX_EXPR and NON_LVALUE_EXPR. + For EXPR_WITH_FILE_LOCATION nodes, return the priority of + the internal node. + (op_symbol): Add support for TRUTH_XOR_EXPR. + * c-simplify.c (simplify_stmt): Only remove null statements that + have been nullified by simplification. + Call debug_tree() dump unhandled tree nodes. + (simplify_for_stmt): Always deep-copy PRE_COND_S before adding it + to PRE_P. + (simplify_expr): When simplifying a MODIFY_EXPR node into an + rvalue, return operand 0. + Handle VA_ARG_EXPR, BIT_FIELD_REF and NON_LVALUE_EXPR nodes. + Treat TRUTH_AND_EXPR, TRUTH_OR_EXPR and TRUTH_XOR_EXPR nodes as + regular binary expressions. + Call debug_tree() to dump an unhandled expression. + (simplify_array_ref): Do not simplify the base of an array. + (simplify_call_expr): Do not simplify calls to builtins. + (simplify_cond_expr): Handle conditional expressions of type void. + (simplify_boolean_expr): Return 'T != 0' instead of 'T'. + (simplify_save_expr): Do not wrap statement trees inside SAVE_EXPR + nodes. + (tree_last_decl): Ignore FILE_STMT nodes preceding a SCOPE_STMT. + * tree-simple.c: Update grammar to accept any valid C array as the + array base. + (is_simple_compstmt): Accept DECL_INITIAL expressions for read-only + variables. + (is_simple_expr): Do not abort if the incoming tree is NULL. + (is_simple_modify_expr): Allow SAVE_EXPR, EXPR_WITH_FILE_LOCATION + and NON_LVALUE_EXPR wrappers. + (is_simple_binary_expr): Ditto. + (is_simple_condexpr): Ditto. + Accept TRUTH_AND_EXPR, TRUTH_OR_EXPR and TRUTH_XOR_EXPR. + (is_simple_unary_expr): Do not abort it the incoming tree is NULL. + Allow SAVE_EXPR, EXPR_WITH_FILE_LOCATION and NON_LVALUE_EXPR + wrappers. + Handle BIT_FIELD_REF and VA_ARG_EXPR nodes. + (is_simple_call_expr): Always return 1 for builtin calls. + (is_simple_arrayref): Do not check the array base. + +2002-04-30 Daniel Berlin + + * c-simplify.c (simplify_call_expr): Don't try to simplify + call_expr arglist if it's not there. + +2002-04-27 Diego Novillo + + * c-decl.c (c_expand_body): Call simplify_tree to simplify a + FUNCTION_DECL node. + * c-simplify.c (simplify_tree): New function. + (simplify_stmt): Remove variable 'new_vars'. Update all called + functions. + Remove argument 'scope'. Update all callers. + Do not keep track of new scope statements as they are entered. + Do not call declare_tmp_vars(). + (simplify_for_stmt): Remove argument new_vars_p. Update all callers. + (simplify_while_stmt): Ditto. + (simplify_do_stmt): Ditto. + (simplify_if_stmt): Ditto. + (simplify_switch_stmt): Ditto. + (simplify_decl_stmt): Reformat comments. + (simplify_expr): Remove argument new_vars_p. Update all callers. + Call simplify_save_expr() to simplify SAVE_EXPR nodes. + Call simplify_expr_wfl() to simplify EXPR_WITH_FILE_LOCATION nodes. + Do not call is_unop() and is_binop() when checking for unary and + binary operators. + Do not return early after simplify statement-expressions. + Do not call add_modify_stmt() to create assignment expressions. + (simplify_array_ref): Remove argument new_vars_p. Update all callers. + (simplify_self_mod_expr): Ditto. + (simplify_component_ref): Ditto. + (simplify_call_expr): Ditto. + (simplify_tree_list): Ditto. + (simplify_cond_expr): Ditto. + (simplify_modify_expr): Ditto. + (simplify_boolean_expr): Ditto. + (simplify_compound_expr): Ditto. + (simplify_save_expr): New function. + (simplify_expr_wfl): New function. + (tree_build_scope): Reformat. + (add_tree): Call stmt_has_effect() and expr_has_effect() to decide + whether or not to add a new tree to the list. + (add_modify_stmt): Remove. + (create_tmp_var): Remove 'new_vars_p' argument. + Call pushdecl() to insert the newly created variable in the current + binding scope. + (declare_tmp_vars): Do not create a BLOCK_VARS for the scope. + (is_binop): Remove. + (is_unop): Remove. + (expr_has_effect): New function. + * c-tree.h (simplify_tree): Remove second argument. + * stmt.c (warn_if_unused_value): Check operand 0 of SAVE_EXPR + nodes. + * tree-dfa.c (find_refs_in_expr): Call find_refs_in_expr() to look + inside an EXPR_WITH_FILE_LOCATION node. + * tree-simple.c (is_simple_stmt): Add a case for SCOPE_STMT nodes. + (is_simple_compstmt): Assume that T is the first tree in the + compound statement's body. + Stop when a scope ending SCOPE_STMT node is found. + (is_simple_binary_expr): Don't call is_simple_binop(). + (is_simple_condexpr): Don't call is_simple_relop(). + (is_simple_binop): Remove. + (is_simple_relop): Remove. + (is_simple_unary_expr): Accept any operator with tree code class + '1' followed by a simple value. + Accept simple unary expressions wrapped inside SAVE_EXPR, + EXPR_WITH_FILE_LOCATION and NON_LVALUE_EXPR nodes. + (is_simple_id): Accept simple identifiers wrapped inside SAVE_EXPR, + EXPR_WITH_FILE_LOCATION and NON_LVALUE_EXPR nodes. + * tree-simple.h (create_tmp_var): Remove second argument. + (is_simple_binop): Remove. + (is_simple_relop): Remove. + +2002-04-22 Diego Novillo + + * c-simplify.c (stmt_has_effect): New function. + (simplify_stmt): Fix example code in comment. + Use EXPR_STMT_EXPR to access the expression in an expression + statement. + Call debug_c_node to display unhandled statements. + Call stmt_has_effect to determine whether the statement has been + nullified by the simplification process. + (simplify_for_stmt): Do not simplify the initialization expression + if it's NULL. + Do not convert post_cond_s into a statement chain. + Do not simplify the expression if it's NULL. + (simplify_switch_stmt): initialize post_cond_s to NULL before + simplifying the expression. + (simplify_expr): Rename argument IS_LHS to NEEDS_LVALUE. Update + all uses. + When simplifying assignments, return the LHS of the assignment if + the caller wants to use the assignment as an rvalue. + Do not simplify ADDR_EXPR nodes. + Handle NOP_EXPR, CONVERT_EXPR, FIX_TRUNC_EXPR, FIX_CEIL_EXPR, + FIX_ROUND_EXPR, INDIRECT_REF, NEGATE_EXPR, INTEGER_CST, STRING_CST, + COMPLEX_CST. + Abort if the expression has not been simplified and cannot be used + as an rvalue to assign it to a temporary. + When creating a new temporary to hold an lvalue, if the expression + is an indirect reference, use the address of the referenced object. + When creating an indirect reference, use the pointed-to type as the + type of the reference. + (simplify_self_mod_expr): If the LHS operand needs to be + simplified, simplify twice. Once to produce an lvalue and another + to produce a simple value. + (simplify_modify_expr): Break assignment chains (a = b = c = ...) + into individual assignments. + (simplify_compound_expr): + (create_tmp_var): If the type is an array, use TYPE_POINTER_TO as + the pointer type. + (update_line_number): Fix typo in comment. + (is_unop): Ditto. + (convert_to_stmt_chain): Only add statements that comply with + stmt_has_effect(). + * tree-dfa.c (find_declaration): Fix typo in comment. + (debug_varref): Ditto. + * tree-flow.h: Ditto. + * tree-simple.c (is_simple_stmt): New function. + (is_simple_compstmt): New function. + (is_simple_expr): Fix typo in comment. + (is_simple_rhs): Allow conditional expressions. + (is_simple_modify_expr): Fix typo in comment. + (is_simple_modify_expr_lhs): Ditto. + (is_simple_binary_expr): Ditto. + (is_simple_condexpr): Ditto. + (is_simple_relop): Ditto. + (is_simple_unary_expr): Ditto. + Allow taking the address of a constant (for strings). + (is_simple_call_expr): Fix typo in comment. + Call is_simple_id to determine if the first operand is a SIMPLE + function identifier. + (is_simple_arglist): Fix typo in comment. + (is_simple_varname): Ditto. + (is_simple_const): Don't accept casts of SIMPLE constants. + (is_simple_id): Don't accept casts of SIMPLE identifiers. + (is_simple_val): Fix typo in comment. + (is_simple_arrayref): Ditto. + (is_simple_compref): Ditto. + (is_simple_compref_lhs): Ditto. + (is_simple_cast_op): Ditto. + (is_simple_exprseq): Allow NULL expression sequences. + * tree-simple.h (is_simple_stmt): Declare + (is_simple_compstmt): Declare. + * tree-ssa.c (follow_chain): Fix typo in comment. + +2002-04-22 Diego Novillo + + * c-pretty-print.c (dump_c_node): Don't print function + bodies of FUNCTION_DECL nodes. + +2002-04-19 Andreas Jaeger + + * Makefile.in (c-call-graph.o): New. + +2002-04-18 Sebastian Pop + + * c-pretty-print.c (PRINT_FUNCTION_NAME): Define. + (dump_c_node): Call pretty_print_string to print string. + Call print_call_name to print function names. + (pretty_print_string): New function. + (print_call_name): New function. + +2002-04-17 Diego Novillo + + * c-simplify.c (simplify_do_stmt): Call is_simple_condexpr to test + if the conditional is in SIMPLE form. + (simplify_if_stmt): Ditto. + +2002-04-17 Diego Novillo + + * c-pretty-print.c (dump_c_node): Handle escape sequences in strings. + (op_symbol): Handle TRUTH_NOT_EXPR. + * c-simplify.c: Rename 'after' with 'post' and 'before' with 'pre' + everywhere. + Re-group some functions and add comments. + (simplify_stmt): Update calls to simplify_for_stmt, + simplify_while_stmt, simplify_do_stmt and simplify_switch_stmt. + Call simplify_if_stmt. + Do not test if expression is in SIMPLE form before calling + simplify_expr. + Call convert_to_stmt_chain to emit statement trees for side effects + found while simplifying. + (simplify_for_stmt): Re-implement. Do not change structure of the + statement. Simplify each header expression and emit side effects + at sequence points. + (simplify_while_stmt): Ditto. + (simplify_do_stmt): Ditto. + (simplify_switch_stmt): Ditto. + (new_simplified_if): Rename to simplify_if_stmt. + Call simplify_expr to simplify the conditional. + (simplify_if_stmt): New name for new_simplified_if. + (simplify_expr): Do not default simple_test_f to is_simple_expr. + If simple_test_f is not set, abort. + Handle COMPOUND_EXPR, MODIFY_EXPR, TRUTH_ANDIF_EXPR, + TRUTH_ORIF_EXPR, SAVE_EXPR and EXPR_WITH_FILE_LOCATION. + (simplify_arglist): Rename to simplify_tree_list. + (simplify_tree_list): New name for simplify_arglist. + (simplify_boolean_expr): New function. + (simplify_compound_expr): New function. + (tree_build_scope): Use SCOPE_BEGIN_P instead of TREE_LANG_FLAG_0 + to access scope operands. Use COMPOUND_BODY instead of + TREE_OPERAND to access the body of the compound statement. + (add_tree): Use a TREE_LIST container instead of directly chaining the + trees. + (add_assignment_tree): Rename to add_modify_stmt. Update all + callers. + (add_modify_stmt): New name for add_assignment_tree. + (insert_before_continue_end): Do nothing it the tree to insert is + NULL. + (copy_stmt_chain): Rename to deep_copy_list. Update all callers. + (deep_copy_list): New name for copy_stmt_chain. + (copy_stmt): Rename to deep_copy_node. Update all callers. + (deep_copy_node): New name for copy_stmt. Handle TREE_LIST + trees. + (insert_before_first): New function. + (is_binop): Add COMPOUND_EXPR. + (convert_to_stmt_chain): New function. + * tree-cfg.c (make_for_stmt_blocks): Fix comment. + * tree-simple.c (is_simple_condexpr): New function. + (is_simple_const): Allow casts of SIMPLE constants. + (is_simple_id): Allow casts of SIMPLE identifiers. + (is_simple_cast): Call is_simple_cast_op. + (is_simple_cast_op): New function. + (is_simple_exprseq): New function. + * tree-simple.h (deep_copy_list): Declare. + (deep_copy_node): Declare. + (is_simple_cast_op): Declare. + (is_simple_exprseq): Declare. + +2002-04-03 Diego Novillo + + * c-simplify.c (simplify_expr): Add arguments simple_tree_f and + is_lhs. Update all callers. + Call simplify_call_expr, simplify_cond_expr, simplify_arglist and + simplify_modify_expr. + Call is_unop and is_binop to check for unary and binary operators. + (simplify_binary_expr): Remove. + (simplify_call_expr): New function. + (simplify_arglist): New function. + (simplify_cond_expr): New function. + (simplify_modify_expr): New function. + (keep_stmt_p): Remove. + (is_binop): New function. + (is_unop): New function. + (simplify_stmt): Don't call keep_stmt_p. + (simplify_decl_stmt): Call add_assignment_tree. + * tree-simple.c: Include c-tree.h + Add expression-statements to the SIMPLE grammar. + (is_simple_modify_expr_lhs): New function. + (is_simple_modify_expr): Call it. + (is_simple_relop): Update comment. + (is_simple_unary_expr): Allow expression-statements. + (is_simple_arglist): New function. + (is_simple_call_expr): Call it. + (is_simple_id): Accept expressions taking the address of a + function. + * tree-simple.h (is_simple_modify_expr_lhs): Declare. + (is_simple_arglist): Declare. + +2002-03-21 Diego Novillo + + * Makefile.in (c-simplify.o): Add dependency on varray.h. + * c-simplify.c: Include varray.h. + Remove comments with SIMPLE grammar. + (simplify_array_ref): New. + (simplify_self_mod_expr): New. + (simplify_component_ref): New. + (add_assignment_tree): New. + (simplify_expr): Call simplify_array_ref to simplify array + references. + Call simplify_self_mod_expr to simplify ++, --, += and -= + expressions. + Call simplify_component_ref to simplify references to structures. + (simplify_binary_expr): Do not check whether the expression is + already in SIMPLE form. + * tree-simple.c: Document changes from original SIMPLE grammar. + (is_simple_unary_expr): Add check for *ID. + (is_simple_call_expr): Update comments. + (is_simple_const): Ditto. + (is_simple_id): Do not accept *ID expressions. + (is_simple_val): Update comments. + (is_simple_arrayref): Accept any variable name as the base address. + (is_simple_compref_lhs): New. + (is_simple_compref): Call it. + * tree-simple.h (is_simple_compref_lhs): Declare. + +2002-03-18 Diego Novillo + + * Makefile.in (C_AND_OBJC_OBJS): Add tree-simple.o + (tree-simple.o): New rule. + * c-simplify.c (simplified_p): Remove. + (simplified_rec_p): Remove. + (simplified_condition_p): Remove. + (simplify_for_stmt): Call is_simple_expr instead of + simplified_condition_p. + (simplify_while_stmt): Ditto. + (simplify_do_stmt): Call is_simple_expr instead of simplified_p. + (new_simplified_if): Call is_simple_expr instead of + simplified_rec_p. + (simplify_decl_stmt): Update comment. + (simplify_expr): Return the original expression if it's already + in SIMPLE form. + Do not special case most binary and unary expressions. + When simplifying array references, create temporary variables to + hold the base address for the array. + Simplify COMPONENT_REF expressions separately. + Call simplify_binary_expr to handle most binary expressions. + (simplify_binary_expr): New function. + (keep_stmt_p): Call is_simple_unary_expr to determine whether the + statement should be kept or not. + * tree-simple.c: New file. + * tree-simple.h (is_simple_expr): Declare. + (is_simple_rhs): Declare. + (is_simple_modify_expr): Declare. + (is_simple_binary_expr): Declare. + (is_simple_binop): Declare. + (is_simple_relop): Declare. + (is_simple_unary_expr): Declare. + (is_simple_call_expr): Declare. + (is_simple_const): Declare. + (is_simple_id): Declare. + (is_simple_varname): Declare. + (is_simple_val): Declare. + (is_simple_arrayref): Declare. + (is_simple_compref): Declare. + (is_simple_cast): Declare. + * cp/Make-lang.in (CXX_C_OBJS): Add tree-simple.o + +2002-03-18 Diego Novillo + + * tree-simple.h: New file. + * Makefile.in (c-simplify.o): Add dependency on tree-simple.h + * c-simplify.c: Reformat some comments. + (tree_last_decl): Declare. + +2002-03-18 Sebastian Pop + + * c-simplify.c (insert_stmt_chain): Delete. + (simplified_condition_p, insert_after_case_labels): New. + (simplify_stmt, simplify_for_stmt, simplify_while_stmt, + simplify_do_stmt, new_simplified_if, simplify_switch_stmt): + Returns a single node, generate a chain of statements to be executed + before the if, and a list of new variables. + (new_simplified_if): Simplify clauses. + (simplify_expr): Remove unused parameter scope. + +2002-03-14 Sebastian Pop + + * c-simplify.c (simplify_switch_stmt, simplify_expr): Add scope + parameter. + (simplify_while_stmt, simplify_do_stmt, simplify_for_stmt): Avoid + negating loop condition during simplification. + (new_simplified_if): Don't simplify the IF_BODY. + (copy_stmt_chain): Use copy_stmt. + (copy_stmt): New function. + +2002-02-28 Sebastian Pop + + * tree-dfa.c (find_refs_in_stmt): Changed if/else statements in + a switch. + +2002-02-28 Sebastian Pop + + * c-simplify.c (simplify_if_stmt): Deleted. + (new_simplified_if): New function. + (make_type_writable): New function. + (insert_before_continue_end): New function. + (insert_before_continue): New function. + (copy_stmt_chain): New function. + (insert_stmt_chain): New function. + (update_line_number): New function. + (simplified_p): New function. + (simplified_rec_p) New function. + (simplify_stmt): Modify the way to call simplification + of COMPOUND_STMT, FOR_STMT, WHILE_STMT, DO_STMT, IF_STMT, + and SCOPE_STMT in order to avoid to execute the code after + the switch. Add FILE_STMT, LABEL_STMT, GOTO_STMT, ASM_STMT cases. + Simplified a little the code after the switch. + (simplify_for_stmt): Change functions parameters. + Add code to simplify the FOR_INIT_STMT, FOR_COND, FOR_EXPR. + (simplify_while_stmt): Change functions parameters. + Add code to simplify the WHILE_COND. + (simplify_do_stmt): Change functions parameters. + Add code to simplify the DO_COND. + (simplify_switch_stmt): Change functions parameters. + (simplify_expr): Remove scope parameter. + Avoid to introduce a new temporary variable for an expression + that is already simplified. + ([ARRAY|COMPONENT]_REF, COND_EXPR): Handle them apart. + (TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR): Avoid to evaluate the second + operand if the value can be deduced from the first one. + (keep_stmt_p): Add some other cases in which we don't need to keep + a statement after its simplification. + +2002-02-28 Sebastian Pop + + * Makefile.in: Add c-call-graph.o dependence. + * c-call-graph.c: New file. + * c-decl.c (c_expand_body): Add an entry point for call-graph. + * tree-dump.c (dump_files): Add the flag dump-call-graph. + * tree.h (tree_dump_index): Add TDI_xml. + +2002-02-28 Sebastian Pop + + * c-pretty-print.c (dump_c_tree): Declare it extern. + (dump_c_node): Declare it extern. + (dump_c_scope_vars): Deleted, some code moved in print_declaration (). + (print_declaration): New function. + (print_function_decl): New function. + (print_struct_decl): New function. + (INDENT_PRINT_C_NODE): Deleted. + (INDENT): New macro. + (NIY): Define the macro body in a block. + (dump_c_node): Add dumping for TREE_PURPOSE operand in TREE_LIST. + [VOID|INTEGER|REAL|COMPLEX|VECTOR|ENUMERAL|BOOLEAN|CHAR]_TYPE nodes: + insert some code from print-tree.c:print_node_brief () in order to + stabilise the type printing. + [RECORD|UNION]_TYPE nodes: Don't print their contents by default, + move the existing code in print_struct_decl (). + [POSTDECREMENT|POSTINCREMENT]_EXPR: Print the operand in post postion. + [MIN|MAX|ABS]_EXPR: New code for printing these nodes. + FOR_STMT: Don't print the FOR_BODY if it is not present. + RETURN_STMT: Don't print the return expression for a void function. + ASM_STMT: New code for printing this node. + SCOPE_STMT: Use print_declaration instead of dump_c_scope_vars. + COMPOUND_LITERAL_EXPR: Add the node as not implemented yet. + (op_prio): Fix switch indent. + Add node EXPR_WITH_FILE_LOCATION with priority 16. + (op_symbol): Fix switch indent. + +2002-01-25 Diego Novillo + + * Makefile.in (c-pretty-print.o): Add dependency on errors.h. + * c-decl.c (c_expand_body): React to -ftree-dump-simple. + * c-pretty-print.c: Fix typo in header comment. + (NYI): Flush output buffer, dump the tree and abort. + (dump_c_node): Add unparsing code for ERROR_MARK, IDENTIFIER_NODE, + ARRAY_TYPE, UNION_TYPE, STRING_CST, CEIL_DIV_EXPR, FLOOR_DIV_EXPR, + ROUND_DIV_EXPR, TRUNC_MOD_EXPR, FLOOR_MOD_EXPR, ROUND_MOD_EXPR, + RDIV_EXPR, EXACT_DIV_EXPR, LROTATE_EXPR, RROTATE_EXPR, + BIT_ANDTC_EXPR, BIT_NOT_EXPR, UNORDERED_EXPR, SAVE_EXPR and + EXPR_WITH_FILE_LOCATION. + Unify unparsing code for common binary and unary expressions. + Handle indirect references like any other unary expression. + (dump_c_scope_vars): Remove unused variable 'context'. + Call dump_c_node to print the type. + (dump_c_indirect_ref): Remove. + (op_prio): New function. + (op_symbol): New function. + * c-simplify.c (simplify_stmt): Do not simplify a return + expression, only its second operand. + Fix capitalization in error message. + (simplify_expr): Add documentation. + Fix capitalization in error message. + * tree-dump.c (dump_files): Add entry for -fdump-tree-simple. + (dump_options): Add entry for -unparse. + * tree.h (TDI_simple): Define. + (TDF_UNPARSE): Define. + * doc/invoke.texi: Document -fdump-tree-simple. + +2002-01-23 Sebastian Pop + + * c-pretty-print.c: Clean C++ comments. + (debug_output_buffer): Remove declaration and definition. + * diagnostic.h (debug_output_buffer): Add declaration. + * diagnostic.c (debug_output_buffer): Add definition. + +2002-01-21 Diego Novillo + + * tree-dfa.c (find_refs_in_stmt): Fix capitalization in error + message. + (find_refs_in_expr): Ditto. + +2002-01-20 Diego Novillo + Sebastian Pop + + * Makefile.in: Add c-simplify.o. + * cp/Make-lang.in: Ditto. + * c-decl.c (c_expand_body): Call simplify_stmt() before + calling optimize_tree(). + * c-simplify.c: New file. + * c-tree.h (simplify_stmt): Declare. + (print_c_tree) + * tree-dfa.c (find_refs_in_stmt): Fix error message for unhandled + statement codes. + +2002-01-20 Sebastian Pop + + * Makefile.in: Add c-pretty-print.o. + * cp/Make-lang.in: Ditto. + * c-pretty-print.c: New file. + * c-tree.h (print_c_tree): Declare. + (print_c_node): Declare. + (debug_c_tree): Declare. + (debug_c_node): Declare. + +2001-12-29 Diego Novillo + + * c-lang.c (c_post_options): Move code to enable tree-ssa + if -Wuninitialized is used ... + * c-common.c (c_common_post_options): ... here. + +2001-12-29 Diego Novillo + + * Makefile.in (tree-optimize.o): Don't depend on c-common.h + * tree-cfg.c: Don't include c-tree.h. Explain why we need to + include c-common.h. + * tree-dfa.c: Explain why we need to include c-common.h. + * tree-ssa.c: Ditto. + * tree-optimize.c: Don't include c-common.h + +2001-12-21 Nathan Sidwell + + Revert my patch of 2001-07-23 for the moment. + +2001-10-15 Diego Novillo + + * tree-dfa.c (create_varref): If the new reference is inside a + statement, add it to the list of references for that statement. + +2001-10-14 Diego Novillo + + * Merge from mainline: + + Tue Sep 11 11:37:52 CEST 2001 Jan Hubicka + + * basic-block.h (cached_make_edge): New. + (make_edge): Remove first parameter. + * flow.c (cached_make_edge): Rename from make_edge; return + newly created edge; use obstack allocation. + (make_edge): New. + (flow_call_edges_add): Updaet make_edge call. + (add_noreturn_fake_exit_edges): Likewise. + (connect_infinite_loops_to_exit): Liekwise. + (make_label_edge, make_edges, find_sub_basic_blocks): Use + cached_make_edge. + * profile.c (branch_prob): Update make_edge call. + * ssa-dce.c (ssa_eliminate_dead_code): Likewise. + +2001-10-14 Diego Novillo + + * Makefile.in (tree-ssa.o): Remove dependency on flags.h. + (tree-optimize.o): Add dependency on flags.h. + * bb-reorder.c (fixup_reorder_chain): Update call to make_edge. + * c-lang.c (c_post_options): Set flag_tree_ssa if -Wuninitialized + is given. + * ifcvt.c (find_if_case_1): Update call to make_edge. + * toplev.c (toplev_main): Do not warn about -Wuninitialized without + -O if -ftree-ssa is used. + * tree-cfg.c (dot_dump_file): Remove. + (dot_dump_flags): Remove. + (cfg_dump_file): Rename to dump_file. + (cfg_dump_flags): Rename to dump_flags. + (remove_bb_ann): New function. + (tree_find_basic_blocks): Do not open dump files at the beginning + of the function. + Do not call delete_cfg. + Create annotations for ENTRY_BLOCK_PTR and EXIT_BLOCK_PTR. + (make_for_stmt_blocks): Update FOR_INIT_STMT_BB and FOR_COND_BB + when creating the header blocks. + Create the blocks for the loop body before the expression block. + (make_while_stmt_blocks): Update END_WHILE_BB when creating the + header blocks. + Create the blocks for the loop body before the end-while block. + (make_do_stmt_blocks): Update DO_COND_BB when creating header + blocks. + Create the blocks for the loop body before the block for DO_COND. + (create_bb): When creating loop header blocks, allocate space for + the header_blocks union. + Call create_bb_ann to create a new annotation. + (remove_bb_ann): New function. + (tree_split_bb): New function. + (make_edges): Remove first argument from call to make_edge, + make_ctrl_stmt_edges, make_exit_edges, make_for_stmt_edges, + make_while_stmt_edges, make_do_stmt_edges, make_if_stmt_edges, + make_goto_stmt_edges, make_break_stmt_edges and + make_continue_stmt_edges. + When creating edges for the default label, remove the fallthru edge + that was created for the associated SWITCH_STMT entry block. + Do not call delete_unreachable_blocks. + Call tree_cleanup_cfg. + (make_ctrl_stmt_edges): Remove first argument. + (make_exit_edges): Remove first argument. + If the last element of the block is an EXPR_STMT, assume that it is + the call to a non-returning function and make an edge to the exit + block. + Do not call make_return_stmt_edges. Call make_edge directly. + (make_for_stmt_edges): Remove first argument. + Simplify the graph for infinite and zero-iteration loops. + (make_while_stmt_edges): Remove first argument. + Simplify the graph for infinite and zero-iteration loops. + (make_do_stmt_edges): Remove first argument. + Simplify the graph for infinite and one-iteration loops. + (make_if_stmt_edges): Remove first argument. + Simplify the graph for always-true and always-false conditionals. + (make_goto_stmt_edges): Remove first argument. + (make_break_stmt_edges): Remove first argument. + (make_continue_stmt_edges): Remove first argument. + (make_return_stmt_edges): Remove. + (tree_cleanup_cfg): New function. + (delete_unreachable_blocks): Do not react to -Wunreachable-code. + Write to dump file blocks that have been removed. + Call remove_edge. + (is_ctrl_altering_stmt): If the statement contains a call to a + non-returning function, return 1. + (delete_cfg): Call remove_bb_ann. Also remove annotations for + ENTRY_BLOCK_PTR and EXIT_BLOCK_PTR. + (latch_block): Use WHILE_COND_BB instead of END_WHILE_BB. + (insert_stmt_tree_before): Use cfg_dump_file instead of dump_file. + (insert_before_ctrl_stmt): Ditto. + (insert_before_normal_stmt): Ditto. + (insert_stmt_tree_after): Ditto. + (insert_after_ctrl_stmt): Ditto. + (insert_after_normal_stmt): Ditto. + (replace_expr_in_tree): Ditto. + (insert_bb_before): Ditto. + * tree-dfa.c (tree_find_varrefs): Call find_refs_in_expr when the + tree is not a statement. + (find_refs_in_stmt): Update comments. + Do not deal with FOR_STMT and DO_STMT trees separately. + When processing VAR_DECLs, call find_refs_in_expr with the + declaration, not its initial value. + (find_refs_in_expr): When processing COMPONENT_REFs and ARRAY_REFs, + recurse using the same reference type that was given by the + original caller. + (create_varref): Insert new PHI terms at the beginning of the + BB_REFS array, not the end. + * tree-flow.h (struct for_header_blocks): Declare. + (union header_blocks): Declare. + (struct bb_ann_def): Add new field 'loop_hdr'. + (BB_ANN): Re-define so that it can be used as an lvalue. + (BB_PARENT): Ditto. + (BB_REFS): Ditto. + (BB_PREV_CHAIN): Ditto. + (BB_BINDING_SCOPE): Ditto. + (BB_LOOP_HDR): Define. + (FOR_INIT_STMT_BB): Redefine using BB_LOOP_HDR. + (FOR_COND_BB): Ditto. + (FOR_EXPR_BB): Ditto. + (DO_COND_BB): Ditto. + (END_WHILE_BB): New name for WHILE_COND_BB. + (tree_warn_uninitialized): Declare. + (tree_cleanup_cfg): Declare. + (tree_split_bb): Declare. + * tree-optimize.c: Include flags.h. + (init_tree_flow): New function. + (optimize_tree): Call build_tree_ssa instead of building SSA + in-place. + (build_tree_ssa): New function. + * tree-optimize.h (build_tree_ssa): Declare. + * tree-ssa.c: Don't include toplev.h + (tree_warn_uninitialized): Define. + (tree_compute_rdefs): Do not call is_upward_exposed. Instead + traverse all the uses of each variable and warn if the use is + reached by the ghost definition. + +2001-10-10 Graham Stott + + * tree-cfg.c (create_bb): Add new binding_scope parameter which allows + the binding scope either to be explicitly specified if non-zero. + (make_blocks): Update call to create_bb. + (make_for_stmt_blocks): Ditto. + (make_while_stmt_blocks): Ditto. + (make_do_stmt_blocks): Ditto. + (make_if_stmt_blocks): Ditto. + (make_switch_stmt_blocks): Ditto. + (create_maximal_bb): Ditto. + (make_edges): If a statement expression is in the last basic + block create an edge to EXIT_BLOCK_PTR and not the next block. + (insert_before_normal_stmt): Pass the appropriate binding scope to + create_bb. + +2001-10-01 Graham Stott + Diego Novillo + + * tree-optimize.c (optimize_tree): Early return if the program has + errors. + +2001-09-30 Diego Novillo + + * tree-optimize.c (optimize_tree): Compute reaching definitions + after building SSA. + +2001-09-30 Diego Novillo + + * tree-cfg.c (insert_after_ctrl_stmt): Remove unused argument. + (make_blocks): Pop top element from scope binding stack when an end + of scope statement is found. + (create_bb): Remove code for popping top element from scope binding + stack. + Do not push basic block 0 to initialize scope binding stack. + (insert_stmt_tree_after): Remove unused argument from call to + insert_after_ctrl_stmt. + (tree_dump_bb): Dump BB_BINDING_SCOPE if defined. + * doc/invoke.texi: Document debugging option -ftree-dump-ssa-rdefs. + +2001-09-29 Diego Novillo + + * Makefile.in (tree-ssa.o): Update dependencies. + (tree-cfg.o): Ditto. + (tree-optimize.o): Ditto. + * basic-block.h (BB_CONTROL_EXPR): Define. + (BB_CONTROL_ENTRY): Define. + * c-common.h (TDF_RDEFS): Define. + * c-dump.c (dump_option_value_in): Add entry for TDF_RDEFS. + * tree-cfg.c: Include flags.h and c-tree.h + (binding_stack): New local variable. + (delete_block): Rename to delete_bb. + (tree_find_basic_blocks): Initialize varray 'binding_stack'. + Call make_blocks with an additional argument. + Adjust size of varray 'basic_block_info' after building CFG. + (make_blocks): Add new argument prev_chain_p. + Update all callers and callees. + Create sub-graphs for statement-expressions. + Update prev_chain_p when accessing the next tree in the chain. + (make_for_stmt_blocks): Add new argument prev_chain_p. + Update all callers and callees. + Update flags for control header blocks with BB_CONTROL_ENTRY and/or + BB_CONTROL_EXPR. + (make_while_stmt_blocks): Ditto. + (make_do_stmt_blocks): Ditto. + (make_if_stmt_blocks): Ditto. + (make_switch_stmt_blocks): Ditto. + (create_maximal_bb): Add new argument prev_chain_p. + Update all callers and callees. + (create_bb): Add new argument prev_chain_p. + Push basic block 0 the first time into the binding scope stack. + Associate the new basic block to the binding scope at the top of + the binding stack. + Push new binding scopes when a SCOPE_BEGIN statement is found. + Pop the top binding scope when a SCOPE_END statement is found. + (make_edges): Handle statement expressions. + Handle case labels preceded by scope statements in switch + statements. + (make_for_stmt_edges): Use FOR_INIT_STMT_BB, FOR_COND_BB and + FOR_EXPR_BB to access the header basic blocks. + (delete_unreachable_blocks): Call delete_bb instead of + delete_block. + (delete_block): Rename to delete_bb. + (block_invalidates_loop): Use data references to find calls to + non-pure functions. + (is_ctrl_stmt): Reformat. + (loop_body): New function. + (set_loop_body): New function. + (stmt_starts_bb_p): Statement expression trees also start a new + basic block. + (delete_cfg): Call VARRAY_FREE to delete all the references in each + basic block. + (latch_block): Use FOR_EXPR_BB, WHILE_COND_BB and DO_COND_BB to + find out the latch block for the loop. + (last_exec_stmt): New function. + (is_exec_stmt): Scope statements that begin a scope are also + considered executables. + (is_statement_expression): New function. + (first_non_decl_stmt): New function. + (first_decl_stmt): New function. + (first_non_label_in_bb): New function. + (insert_stmt_tree_before): New function. + (insert_before_ctrl_stmt): New function. + (insert_before_normal_stmt): New function. + (insert_stmt_tree_after): New function. + (insert_after_ctrl_stmt): New function. + (insert_after_normal_stmt): New function. + (insert_after_loop_body): New function. + (replace_expr_in_tree): New function. + (find_expr_in_tree): New function. + (insert_bb_before): New function. + (tree_dump_bb): Display the contents of BB_PREV_CHAIN_P. + * tree-dfa.c (tree_find_varrefs): Use accessor macros for array + 'referenced_symbols'. + (find_refs_in_stmt): Do not process error_mark_node trees. + Handle statement-expression nodes as any other statement tree. + Do not call find_refs_in_stmt_expr. + (find_refs_in_stmt_expr): Remove. + (add_ref_to_sym): Remove. + (add_ref_to_bb): Remove. + (find_refs_in_expr): Do not process error_mark_node trees. + ADDR_EXPR trees are not variable references except if used in a + CALL_EXPR node. + Handle EXPR_WITH_FILE_LOCATION nodes. + (create_varref): Remove variable 'is_new'. + Initialize data-flow arrays VARDEF_IMM_USES, VARDEF_RUSES, + VARDEF_PHI_CHAIN and VARUSE_RDEFS. + Do not call add_ref_to_sym and add_ref_to_bb. + (add_ref_symbol): Use accessor macros for varray + 'referenced_symbols'. + (function_may_recurse_p): New function. + (get_fcalls): New function. + (find_declaration): New function. + (dump_varref): Handle NULL values of VARREF_EXPR. + Use VARDEF_PHI_CHAIN instead of VARPHI_CHAIN. + (dump_varref_list): Check if the list is NULL before traversing it. + * tree-flow.h (struct vardef): Add fields 'ruses', 'marked' and + 'phi_chain'. + (VARDEF_RUSES): Define. + (VARDEF_MARKED): Define. + (VARDEF_PHI_CHAIN): Define. + (VARPHI_CHAIN): Remove. + (struct varphi): Remove. + (struct varuse): Add field 'rdefs'. + (VARUSE_RDEFS): Define. + (union varref_def): Remove field 'phi'. + (IS_GHOST_DEF): Define. + (IS_ARTIFICIAL_REF): Define. + (struct bb_ann_def): Add fields 'prev_chain_p' and 'binding_scope'. + (BB_PREV_CHAIN_P): Define. + (BB_BINDING_SCOPE): Define. + (FOR_INIT_STMT_BB): Define. + (FOR_COND_BB): Define. + (FOR_EXPR_BB): Define. + (WHILE_COND_BB): Define. + (DO_COND_BB): Define. + (IF_COND_BB): Define. + (CASE_COND_BB): Define. + (NREF_SYMBOLS): Define. + (REF_SYMBOL): Define. + (ADD_REF_SYMBOL): Define. + (FCALL_NON_PURE): Define. + (FCALL_PURE): Define. + (FCALL_BUILT_IN): Define. + (loop_body): Declare. + (set_loop_body): Declare. + (last_exec_stmt): Declare. + (is_statement_expression): Declare. + (first_non_decl_stmt): Declare. + (first_decl_stmt): Declare. + (first_non_label_in_bb): Declare. + (insert_stmt_tree_before): Declare. + (insert_stmt_tree_after): Declare. + (replace_expr_in_tree): Declare. + (find_expr_in_tree): Declare. + (insert_bb_before): Declare. + (function_may_recurse_p): Declare. + (get_fcalls): Declare. + (find_declaration): Declare. + (tree_compute_rdefs): Declare. + (analyze_rdefs): Declare. + (is_upward_exposed): Declare. + * tree-optimize.c (optimize_tree): Update name for varray + referenced_symbols. + Free varray referenced_symbols and call delete_ssa on exit. + * tree-ssa.c: Include flags.h, diagnostic.h and toplev.h. + (tree_build_ssa): Create ghost definitions before building FUD + chains. + (insert_phi_terms): Use accessor macros for 'referenced_symbols'. + Ignore ghost definitions when placing PHI terms. + (build_fud_chains): Call get_tree_ann to create an annotation for + the symbol if it doesn't already have one. + (search_fud_chains): Reformat comments. + Do not initialize varray VARDEF_IMM_USES. + If a successor basic block does not have references, continue on to + the next one, do not stop. + Do not initialize varray VARDEF_PHI_CHAIN. + (delete_ssa): New function. + (delete_refs): New function. + (tree_compute_rdefs): New function. + (analyze_rdefs): New function. + (follow_chain): New function. + (is_upward_exposed): New function. + +2001-09-14 Diego Novillo + + * tree-cfg.c (tree_find_basic_blocks): Remove call to + mark_critical_edges. + (create_maximal_bb): Do not create annotations for non-executable + statements. + (map_stmt_to_bb): Rename basic_block_ann with bb_ann. + (delete_cfg): Ditto. + (is_exec_stmt): Reformat. + (create_bb_ann): New function. + * tree-dfa.c (create_node): Remove. + (ref_symbols_list): Remove. + (create_tree_ann): Declare. + (referenced_symbols): Declare. + (tree_find_varrefs): Replace usage of linked lists with variable + arrays. + (create_varref): Remove second argument from call to + add_ref_symbol. + Update comments. + (add_ref_to_sym): Replace usage of linked lists with variable + arrays. + Declare static. + (add_ref_to_bb): Ditto. + (add_ref_symbol): Ditto. + (dump_varref_list): Ditto. + (debug_varref_list): Ditto. + (create_varref_list): Remove. + (push_ref): Remove. + (create_node): Remove. + (delete_varref_list): Remove. + (get_tree_ann): Call create_tree_ann if the tree doesn't have an + annotation already. + (create_tree_ann): New function. + * tree-flow.h (varref_list_def): Remove. + (vardef): Change type of field 'imm_uses' to 'varray_type'. + (varphi): Change type of field 'phi_chain' to 'varray_type'. + (varref_node_def): Remove. + (varref_node): Remove. + (VARREF_NODE_ELEM): Remove. + (VARREF_NODE_NEXT): Remove. + (VARREF_NODE_PREV): Remove. + (varref_list_def): Remove. + (varref_list): Remove. + (VARREF_LIST_FIRST): Remove. + (VARREF_LIST_LAST): Remove. + (tree_ann_def): Change type of field 'refs' to 'varray_type'. + (basic_block_ann_def): Rename to 'bb_ann_def'. + Change type of field 'refs' to 'varray_type'. + (basic_block_ann): Rename to 'bb_ann'. + (ref_symbols_list): Remove. + (referenced_symbols): Declare. + (add_ref_to_sym): Remove. + (add_ref_to_bb): Remove. + (add_ref_symbol): Remove. + (remove_ann_from_sym): Remove. + (create_varref_list): Remove. + (push_ref): Remove. + (delete_varref_list): Remove. + (debug_varref_list): Update argument type to be 'varray_type'. + (dump_varref_list): Ditto. + * tree-optimize.c: Include 'basic-block.h'. + (optimize_tree): Replace references to 'ref_symbols_list' with + 'referenced_symbols'. + Remove call to delete_varref_list. + * tree-ssa.c (insert_phi_terms): Rename 'work_list' to + 'work_stack'. + Use VARRAY_PUSH and VARRAY_TOP to access 'work_stack' instead of + maintaining the stack pointer in 'work_list_top'. + Remove code to grow 'work_stack'. + Remove references to 'work_list_top'. + Replace references to 'ref_symbols_list' with 'referenced_symbols'. + (build_fud_chains): Replace references to 'ref_symbols_list' with + 'referenced_symbols'. + (search_fud_chains): If there are no variable references in the + basic block, return early. + Change usage of linked lists with variable arrays. + +2001-09-07 Diego Novillo + + * tree-cfg.c (tree_find_basic_blocks): Document how to traverse + trees inside a basic block. + (make_for_stmt_blocks): Make sure that there is always a block for + FOR_EXPR, even if the loop does not have an expression. + Create a separate block for FOR_INIT_STMT. + (make_while_stmt_blocks): Always create an "end_while" block. + (make_if_stmt_blocks): Do not store IF_COND in the header block of + an IF statement. + (make_for_stmt_edges): Create an edge from the block header to the + block for FOR_INIT_STMT. + Determine the first block of the loop body calling BB_FOR_STMT on + the first executable statement in the body. + Remove the special case for missing FOR_EXPR trees. + (make_while_stmt_edges): Create a back edge from the end_while + block to the header block. + Determine the first block of the loop body calling BB_FOR_STMT on + the first executable statement in the body. + (make_do_stmt_edges): Determine the first block of the loop body + calling BB_FOR_STMT on the first executable statement in the body. + (condition_block): Rename to latch_block. Return the latch + block for the given loop header. + (make_continue_stmt_edges): Rename condition_block to + latch_block. + (successor_block): Ditto. + * tree-flow.h (condition_block): Rename to latch_block. + +2001-09-06 Diego Novillo + + * tree-dfa.c (tree_find_varrefs): Use TDF_REFS instead of TDF_VARREF. + * tree-flow.h (TDF_VARREF): Remove. + +2001-09-04 Nathan Sidwell + + * c-common.h (tree_dump_index): Add more comments. + (TDF_REFS): New dump flag. + * c-dump.c (dump_files): Name flags `tree' rather than `ast'. + (dump_option_value_info): New struct. + (dump_options): New array. + (dump_switch_p): Parse switch options symbolically. + * doc/invoke.texi (-fdump-ast): Rename to ... + (-fdump-tree): ... here. Document options are symbolic, and + not all are applicable. Combine ssa related flags into the other + tree dump flags. + +2001-08-27 Diego Novillo + + * Makefile.in (tree-ssa.o): Update dependencies. + (tree-cfg.o): Ditto. + (tree-dfa.o): Ditto. + (tree-optimize.o): Ditto. + +2001-08-26 Diego Novillo + + * Makefile.in (C_AND_OBJC_OBJS): Replace tree-opt.o with + tree-optimize.o. + (c-decl.o): Ditto. + (tree-ssa.o): Ditto. + (tree-cfg.o): Ditto. + (tree-dfa.o): Ditto. + (tree-opt.o): Ditto. + * c-decl.c: Replace tree-opt.h with tree-optimize.h. + (c_expand_body): Remove call to init_tree_opt. + * flow.c (flow_loop_dump): Do not display insn UIDs if this is not + an RTL basic block. + * tree-cfg.c: Replace tree-opt.h with tree-optimize.h. + (block_invalidates_loop): New local function. + (validate_loops): New function. + (tree_dump_bb): Display the loop depth of the block. + * tree-dfa.c: Replace tree-opt.h with tree-optimize.h. + * tree-flow.h (validate_loops): Declare. + * tree-opt.c: Rename to tree-optimize.c. + * tree-opt.h: Rename to tree-optimize.h. + * tree-optimize.c: Rename from tree-opt.c. + * tree-optimize.h: Rename from tree-opt.h. + * tree-ssa.c: Replace tree-opt.h with tree-optimize.h. + (tree_build_ssa): Call tree_dump_bb instead of tree_debug_bb. + * cp/Make-lang.in: Replace tree-opt.h with tree-optimize.h. + +2001-08-20 Diego Novillo + + * basic-block.h (basic_block): Remove field 'reachable'. + Add new field 'flags'. + (BB_REACHABLE): Define. + * c-common.h (tree_dump_index): Add TDI_cfg, TDI_dot, TDI_ssa. + * c-decl.c (c_decode_option): Skip '-f' prefix before calling + dump_switch_p. + * c-dump.c (dump_file_info): Add entries for -fdump-tree-cfg, + -fdump-tree-graphviz and -fdump-tree-ssa. + * flow.c (find_unreachable_blocks): Use BB_REACHABLE bit in bb->flags + instead of bb->reachable. + (delete_unreachable_blocks): Ditto. + * tree-cfg.c: Minor formatting changes throughout the file. + (DEBUG_TREE_FLOW): Remove. + (debug_tree_flow): Remove. + (cfg_dump_file): New local variable. + (dot_dump_file): New local variable. + (cfg_dump_flags): New local variable. + (dot_dump_flags): New local variable. + (tree_find_basic_blocks): Remove unused arguments. + Add code to react to -fdump-tree-cfg and -fdump-tree-graphviz. + Remove uses of DEBUG_TREE_FLOW. + (delete_unreachable_blocks): Use BB_REACHABLE bit in bb->flags + instead of bb->reachable. + (tree_dump_cfg): New. + (tree_debug_cfg): Call tree_dump_cfg(). + (tree_cfg2dot): Accept a FILE pointer instead of a file name as + argument. + Name the graph with the current function name. + * tree-dfa.c: Minor formatting changes throughout the file. + (DEBUG_TREE_DFA): Remove. + (debug_tree_dfa): Remove. + (dump_file): New local variable. + (dump_flags): New local variable. + (tree_find_varrefs): Add code to react to -fdump-tree-ssa. + Remove uses of DEBUG_TREE_DFA. + (find_refs_in_expr): Remove uses of DEBUG_TREE_DFA. + (create_varref): Replace VARREF_BLOCK with VARREF_BB. + * tree-flow.h: Minor formatting changes throughout the file. + (VARREF_BLOCK): Rename to VARREF_BB. + (VARREF_NEXT): Remove. + (VARREF_PREV): Remove. + (TDF_VARREF): Define. + (tree_find_basic_blocks): Remove unused arguments. + (tree_dump_cfg): Declare. + (tree_cfg2dot): Change argument to FILE *. + * tree-opt.c: Minor formatting changes throughout the file. + (optimize_tree): Remove unused arguments in call to + tree_find_basic_blocks(). + * tree-opt.h: Ditto. + * tree-ssa.c: Minor formatting changes throughout the file. + (DEBUG_TREE_SSA): Remove. + (debug_tree_ssa): Remove. + (dump_file): New local variable. + (dump_flags): New local variable. + (tree_build_ssa): Add code to react to -fdump-tree-ssa. + Remove uses of DEBUG_TREE_SSA. + (insert_phi_terms): Remove uses of DEBUG_TREE_SSA. + * doc/invoke.texi: Add documentation for -fdump-tree-cfg, + -fdump-tree-graphviz and -fdump-tree-ssa. + Replace existing references to -fdump-tree with -fdump-ast. + +2001-08-10 Diego Novillo + + * basic-block.h (basic_block): Add new field 'reachable'. + (expunge_block): Declare. + * flow.c (ENTRY_BLOCK_PTR): Initialize field 'reachable'. + (EXIT_BLOCK_PTR): Ditto. + (expunge_block): Remove static declaration. + (cleanup_cfg): Clear bb->aux on every basic block. + (find_unreachable_blocks): Use field 'reachable' when computing + reachability. + (delete_unreachable_blocks): Use field 'reachable'. + + * tree-cfg.c: Rename all instance of 'node' with 'block. + (get_successor_block): Rename to successor_block. + (make_compound_stmt_edges): Remove. + (make_switch_stmt_edges): Remove. + (delete_unreachable_blocks): New. + (delete_block): New. + (make_blocks): Add new argument 'compound_stmt'. Do not include + COMPOUND_STMT trees in the flowgraph. + (make_for_stmt_blocks): Include FOR_INIT_STMT in the entry block of + the loop. + If FOR_COND does not exist, create a tree holding the constant 1. + Add new argument 'compound_stmt'. + (make_while_stmt_blocks): Include WHILE_COND in the entry block of + the loop. + Add new argument 'compound_stmt'. + (make_do_stmt_blocks): Add new argument 'compound_stmt'. + (make_if_stmt_blocks): Add new argument 'compound_stmt'. + Include IF_COND in the IF header block. + (make_switch_stmt_blocks): Add new argument 'compound_stmt'. + Include SWITCH_COND in the SWITCH header block. + (create_maximal_bb): Remove argument 'is_loop_header'. + Add new argument 'compound_stmt'. + Update all callers. + Return the newly created basic block instead of its last statement. + Update comments. + Do not store control flow altering statements in bb->exit_stmt. + Only add executable statements to the block. + Annotate with 'compound_stmt' each tree added to the block. + (create_bb): Do not update annotation 'is_loop_header'. + (make_edges): Remove naive reachability analysis. + When a label node is found, add an edge from the immediately + enclosing switch statement. + Call delete_unreachable_blocks() after adding all the edges. + (make_ctrl_stmt_edges): Do not consider COMPOUND_STMT trees. + Do nothing for SWITCH_STMT trees. + (make_exit_edges): Use bb->end_tree instead of BB_EXIT_STMT. + (make_for_stmt_edges): Remove code that added edges for the block + holding FOR_INIT_STMT. + Update comments. + Do not consider the case where FOR_COND is NULL. + Call first_exec_stmt() to determine if FOR_BODY is empty. + Only create an edge from expr_bb to cond_bb if FOR_EXPR is + non-null. + (make_while_stmt_edges): Remove code that added edges for the block + holding WHILE_COND. + Update comments. + Call first_exec_stmt() to determine if WHILE_BODY is empty. + (make_do_stmt_edges): Call first_exec_stmt() to determine if + DO_BODY is empty. + (make_if_stmt_edges): Remove code that added edges for the block + holding IF_COND. + Call first_exec_stmt() to determine if THEN_CLAUSE or ELSE_CLAUSE + are empty. + (make_switch_stmt_edges): Remove. + (make_goto_stmt_edges): Use bb->end_tree instead of BB_EXIT_STMT. + (make_break_stmt_edges): Use bb->end_tree instead of BB_EXIT_STMT. + Call switch_parent() and loop_parent() to determine if the + statement is inside an appropriate control structure. + (make_continue_stmt_edges): Use bb->end_tree instead of + BB_EXIT_STMT. + (make_return_stmt_edges): Ditto. + (get_successor_block): Rename to successor_block. + Call first_exec_stmt() to find the first executable statement in + TREE_CHAIN. + (is_ctrl_stmt): Do not consider COMPOUND_STMT trees. + (stmt_starts_bb_p): Ditto. + (stmt_ends_bb_p): Reformat comments. + (delete_cfg): Reformat comments. + (find_loop_parent): Rename to loop_parent. + (get_condition_block): Rename to condition_block. + Update to use new index numbers for control structure header + blocks. + (switch_parent): New. + (first_exec_stmt): New. + (is_exec_stmt): New. + (tree_cfg2dot): Reformat comments. + * tree-dfa.c (find_refs): Remove. + (find_refs_in_stmt): New + (find_refs_in_stmt_expr): New. + (tree_find_varrefs): Look for variables doing a CFG traversal + instead of the trees. Remove both arguments. + (find_refs_in_expr): Add new argument 'bb'. + Update all recursive calls. + (create_varref): Abort if the basic block 'bb' is NULL. + (add_ref_to_sym): Reformat comments. + (add_ref_symbol): Ditto. + (delete_varref_list): Ditto. + * tree-flow.h (struct tree_ann_def): Add 'compound_stmt'. + (TREE_COMPOUND_STMT): New macro. + (struct basic_block_ann_def): Remove 'exit_stmt' and + 'is_loop_header'. + (BB_EXIT_STMT): Remove. + (BB_IS_LOOP_HEADER): Remove. + * tree-opt.c (optimize_tree): Call tree_find_varrefs() with no + arguments. + Only build DFA and SSA information if n_basic_blocks is greater + than zero. + * tree-ssa.c: Rename all instances of 'node' with 'block'. + (tree_build_ssa): Reformat comments. + (insert_phi_terms): Ditto. + +2001-08-01 Diego Novillo + + * tree-cfg.c (USE_TREE_IL): Remove. + (make_back_edges): Remove. + (make_fallthru_edge): Remove. + (get_outermost_scope_block): Remove. + (is_last_block_of_loop): Remove. + (tree_find_basic_blocks): Do not return early if 'errorcount' is set. + (make_edges): Do not treat back edges as a separate case. + Do not call make_fallthru_edge to create fall-through edges. + Do not emit a warning for unreachable blocks containing a single + closing brace. + (make_do_stmt_edges): Update comment. + (make_goto_stmt_edges): Do not call get_outermost_scope_block(). + (make_break_stmt_edges): Do not call get_outermost_scope_block(). + Do not call make_back_edges(). + (make_continue_stmt_edges): Call find_loop_parent(). Emit an error + if the 'continue' statement is not inside a loop. Call + get_condition_block() to find the target node. + (make_return_stmt_edges): Do not call get_outermost_scope_block(). + (get_successor_block): Return EXIT_BLOCK_PTR if 'bb' is the last + block in the graph. + Return the condition node of the loop if 'bb' doesn't have a + natural successor and its parent is a loop header. + (tree_cfg2dot): Output fake edges with dotted lines. + * tree-dfa.c (USE_TREE_IL): Remove. + * tree-opt.c (USE_TREE_IL): Remove. + * tree-ssa.c (USE_TREE_IL): Remove. + * tree-flow.h (is_last_block_of_loop): Remove. + +2001-07-23 Diego Novillo + + * Makefile.in (C_AND_OBJC_OBJS): Add tree-cfg.o, tree-dfa.o, + tree-ssa.o and tree-opt.o. + (c-decl.o): Add dependency on tree-opt.h + (tree-ssa.o): New rule. + (tree-cfg.o): New rule. + (tree-dfa.o): New rule. + (tree-opt.o): New rule. + * c-decl.c: Include tree-opt.h. + (c_expand_body): Call optimize_tree() when the -ftree-ssa flag is + given. + * flags.h (flag_tree_ssa): Declare. + * toplev.c (flag_tree_ssa): Define. + (lang_independent_options): Add -ftree-ssa. + * tree-cfg.c: New file. + * tree-dfa.c: New file. + * tree-flow.h: New file. + * tree-opt.c: New file. + * tree-opt.h: New file. + * tree-ssa.c: New file. + * cp/Make-lang.in (CXX_C_OBJS): Add tree-cfg.o, tree-dfa.o, + tree-opt.o and tree-ssa.o. + * doc/invoke.texi: Add documentation for -ftree-ssa. + +2001-07-23 Nathan Sidwell + + * Makefile.in (calls.o): Depend on intl.h. + * calls.c: Include intl.h. + (ECF_NEED_STACK_FRAME, ECF_NEED_ARG_FRAME): New flags. + (special_function_p): Detect when we need a stack or arg + frame. Don't optimize on length. + (setjmp_call_p): Remove. + (uninlinable_call_p): New function. + * tree.h (setjmp_call_p): Remove. + (uninlinable_call_p): Declare. + +2001-07-22 Nathan Sidwell + + * params.def (PARAM_MAX_INLINE_AST): New parameter. + (PARAM_ARG_INLINE_AST): New parameter. + * doc/invoke.texi (max-inline-ast, arg-inline-ast): Document + parameters. + +Local Variables: +mode: change-log +change-log-default-name: "ChangeLog.tree-ssa" +End: diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b35159b0be6..bfeaa0c37ca 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -140,7 +140,7 @@ XCFLAGS = TCFLAGS = CFLAGS = -g STAGE1_CFLAGS = -g @stage1_cflags@ -BOOT_CFLAGS = -g -O2 +BOOT_CFLAGS = -g -O2 # Flags to determine code coverage. When coverage is disabled, this will # contain the optimization flags, as you normally want code coverage @@ -192,6 +192,14 @@ c-parse.o-warn = -Wno-error gengtype-lex.o-warn = -Wno-error # SYSCALLS.c misses prototypes SYSCALLS.c.X-warn = -Wno-strict-prototypes -Wno-error +# These files need -Wno-error because the gimplifier triggers hard to fix +# warnings when converting to GIMPLE form. The warnings are triggered because +# moving the condition into the loop prevents the loop optimizer from +# recognizing that the loop will always be executed at least once. We need +# a new loop optimizer. +reload1.o-warn = -Wno-error +# These warnings are due to libbanshee. +tree-alias-ander.o-warn = -Wno-error # All warnings have to be shut off in stage1 if the compiler used then # isn't gcc; configure determines that. WARN_CFLAGS will be either @@ -270,6 +278,12 @@ OUTPUT_OPTION = @OUTPUT_OPTION@ ZLIB = @zlibdir@ -lz ZLIBINC = @zlibinc@ +# How to find GMP +GMPLIBS = @GMPLIBS@ +GMPINC = @GMPINC@ + +BANSHEELIB = @BANSHEELIB@ +BANSHEEINC = @BANSHEEINC@ # Substitution type for target's getgroups 2nd arg. TARGET_GETGROUPS_T = @TARGET_GETGROUPS_T@ @@ -687,6 +701,11 @@ C_TREE_H = c-tree.h $(C_COMMON_H) SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h PREDICT_H = predict.h predict.def CPPLIB_H = cpplib.h line-map.h +TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H) +TREE_SIMPLE_H = tree-simple.h tree-iterator.h +TREE_FLOW_H = tree-flow.h tree-flow-inline.h tree-ssa-operands.h \ + bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h $(TREE_SIMPLE_H) \ + $(HASHTAB_H) PRETTY_PRINT_H = pretty-print.h input.h $(OBSTACK_H) DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) C_PRETTY_PRINT_H = $(PRETTY_PRINT_H) $(C_COMMON_H) $(TREE_H) @@ -713,7 +732,7 @@ LIBIBERTY = ../libiberty/libiberty.a BUILD_LIBIBERTY = @FORBUILD@/libiberty/libiberty.a # Dependencies on the intl and portability libraries. -LIBDEPS= $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) libcpp.a +LIBDEPS= $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) libcpp.a $(BANSHEELIB) # Likewise, for use in the tools that must run on this machine # even if we are cross-building GCC. @@ -721,7 +740,7 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY) # How to link with both our special library facilities # and the system's installed libraries. -LIBS = @LIBS@ libcpp.a $(LIBIBERTY) $(LIBINTL) $(LIBICONV) +LIBS = @LIBS@ libcpp.a $(LIBIBERTY) $(LIBINTL) $(LIBICONV) $(BANSHEELIB) # Any system libraries needed just for GNAT. SYSLIBS = @GNAT_LIBEXC@ @@ -750,7 +769,8 @@ BUILD_VARRAY = $(BUILD_PREFIX)varray.o # currently being compiled, in both source trees, to be examined as well. # libintl.h will be found in ../intl if we are using the included libintl. INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \ - -I$(srcdir)/../include @INCINTL@ + -I$(srcdir)/../include @INCINTL@ \ + $(BANSHEEINC) $(GMPINC) .c.o: $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION) @@ -838,14 +858,23 @@ CXX_TARGET_OBJS=@cxx_target_objs@ C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \ c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \ c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \ - c-objc-common.o c-dump.o c-pch.o $(C_TARGET_OBJS) + c-objc-common.o c-dump.o c-pch.o $(C_TARGET_OBJS) \ + c-simplify.o tree-mudflap.o c-mudflap.o c-pretty-print.o # Language-specific object files for C. -C_OBJS = c-parse.o c-lang.o c-pretty-print.o stub-objc.o $(C_AND_OBJC_OBJS) +C_OBJS = c-parse.o c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) # Language-independent object files. OBJS-common = \ + tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-simple.o \ + tree-alias-type.o gimplify.o tree-pretty-print.o tree-into-ssa.o \ + tree-outof-ssa.o tree-alias-common.o tree-ssa-ccp.o \ + @ANDER@ tree-ssa-dce.o tree-ssa-copy.o tree-nrv.o tree-ssa-copyrename.o \ + tree-ssa-pre.o tree-ssa-live.o tree-ssa-operands.o tree-ssa-alias.o \ + tree-ssa-phiopt.o tree-ssa-forwprop.o tree-nested.o tree-ssa-dse.o \ + tree-ssa-dom.o domwalk.o tree-tailcall.o gimple-low.o tree-iterator.o \ + tree-phinodes.o tree-ssanames.o tree-sra.o tree-complex.o tree-ssa-loop.o \ alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o \ cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \ @@ -863,14 +892,15 @@ OBJS-common = \ real.o recog.o reg-stack.o regclass.o regmove.o regrename.o \ reload.o reload1.o reorg.o resource.o rtl.o rtlanal.o rtl-error.o \ sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o \ - sibcall.o simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o \ + simplify-rtx.o sreal.o stmt.o stor-layout.o stringpool.o \ targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o \ varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \ - et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o + et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o \ + rtl-profile.o tree-profile.o OBJS-md = $(out_object_file) OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o \ - tree-optimize.o cgraph.o cgraphunit.o + cgraph.o cgraphunit.o tree-nomudflap.o OBJS = $(OBJS-common) $(out_object_file) $(OBJS-archive) @@ -1125,9 +1155,9 @@ $(SPECS): xgcc$(exeext) gcc-cross: xgcc$(exeext) cp xgcc$(exeext) gcc-cross$(exeext) -cc1$(exeext): $(C_OBJS) $(BACKEND) $(LIBDEPS) +cc1$(exeext): $(C_OBJS) $(BACKEND) $(LIBDEPS) @TREEBROWSER@ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o cc1$(exeext) \ - $(C_OBJS) $(BACKEND) $(LIBS) + $(C_OBJS) @TREEBROWSER@ $(BACKEND) $(LIBS) # Build the version of limits.h that we will install. xlimits.h: glimits.h limitx.h limity.h @@ -1308,7 +1338,7 @@ c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) $(C_TREE_H) $(GGC_H) $(TARGET_H) flags.h function.h output.h \ $(EXPR_H) debug.h toplev.h intl.h $(TM_P_H) tree-inline.h $(TIMEVAR_H) \ opts.h c-pragma.h gt-c-decl.h cgraph.h $(HASHTAB_H) libfuncs.h except.h \ - $(LANGHOOKS_DEF_H) + $(LANGHOOKS_DEF_H) $(TREE_DUMP_H) c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \ $(TARGET_H) flags.h intl.h output.h $(EXPR_H) $(RTL_H) toplev.h $(TM_P_H) \ langhooks.h @@ -1361,9 +1391,10 @@ c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(OBSTACK_H) $(C_COMMON_H) flags.h toplev.h output.h c-pragma.h intl.h \ $(GGC_H) $(EXPR_H) $(TM_P_H) builtin-types.def builtin-attrs.def \ $(DIAGNOSTIC_H) gt-c-common.h langhooks.h varray.h $(RTL_H) \ - $(TARGET_H) $(C_TREE_H) langhooks.h + $(TARGET_H) $(C_TREE_H) tree-iterator.h langhooks.h c-pretty-print.o : c-pretty-print.c $(C_PRETTY_PRINT_H) \ - $(C_COMMON_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) real.h + $(C_COMMON_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) real.h \ + $(DIAGNOSTIC_H) c-opts.o : c-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) c-pragma.h flags.h toplev.h langhooks.h \ @@ -1390,7 +1421,7 @@ c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE $(EXPR_H) $(PREDICT_H) tree-inline.h c-dump.o : c-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - $(C_TREE_H) tree-dump.h + $(C_TREE_H) $(TREE_DUMP_H) c-pch.o : c-pch.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) $(TREE_H) \ $(C_COMMON_H) output.h toplev.h c-pragma.h $(GGC_H) debug.h \ @@ -1476,7 +1507,7 @@ version.o: version.c version.h gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h \ $(HASHTAB_H) $(TREE_H) $(RTL_H) function.h insn-config.h $(EXPR_H) $(OPTABS_H) \ libfuncs.h debug.h $(GGC_H) bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h \ - cselib.h insn-addr.h + cselib.h insn-addr.h $(TREE_FLOW_H) ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \ $(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h @@ -1506,22 +1537,149 @@ langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(LANGHOOKS_DEF_H) flags.h $(GGC_H) gt-langhooks.h diagnostic.h tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h function.h \ toplev.h $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) langhooks.h \ - real.h gt-tree.h + real.h gt-tree.h tree-iterator.h $(BASIC_BLOCK_H) $(TREE_FLOW_H) tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) flags.h langhooks.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \ - $(EXPR_H) $(SPLAY_TREE_H) tree-dump.h + $(EXPR_H) $(SPLAY_TREE_H) $(TREE_DUMP_H) tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h \ $(INTEGRATE_H) $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \ - langhooks.h $(C_COMMON_H) tree-inline.h cgraph.h intl.h function.h -tree-optimize.o : tree-optimize.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - $(TREE_H) toplev.h langhooks.h cgraph.h $(TIMEVAR_H) function.h $(GGC_H) - + langhooks.h $(C_COMMON_H) tree-inline.h cgraph.h intl.h function.h \ + $(TREE_SIMPLE_H) print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(GGC_H) langhooks.h real.h stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ flags.h function.h $(EXPR_H) $(RTL_H) toplev.h $(GGC_H) $(TM_P_H) $(TARGET_H) \ langhooks.h +tree-alias-type.o: tree-alias-type.c tree-alias-type.h $(SYSTEM_H) $(CONFIG_H) \ + $(GGC_H) $(TM_H) coretypes.h $(VARRAY_H) +tree-alias-ander.o: tree-alias-ander.c tree-alias-ander.h $(SYSTEM_H) \ + $(CONFIG_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) tree-alias-common.h \ + $(TM_H) coretypes.h cgraph.h tree-pass.h +tree-alias-common.o: tree-alias-common.c tree-alias-common.h $(SYSTEM_H) \ + $(CONFIG_H) $(GGC_H) $(TREE_H) gt-tree-alias-common.h $(TREE_FLOW_H) \ + $(TM_H) coretypes.h cgraph.h tree-pass.h $(TIMEVAR_H) +tree-ssa.o : tree-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h diagnostic.h \ + errors.h toplev.h function.h $(TIMEVAR_H) tree-alias-common.h \ + $(TM_H) coretypes.h $(TREE_DUMP_H) langhooks.h cfgloop.h \ + tree-pass.h +tree-into-ssa.o : tree-into-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h diagnostic.h \ + errors.h toplev.h function.h $(TIMEVAR_H) tree-alias-common.h \ + $(TM_H) coretypes.h $(TREE_DUMP_H) langhooks.h domwalk.h tree-pass.h +tree-outof-ssa.o : tree-outof-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h diagnostic.h \ + errors.h toplev.h function.h $(TIMEVAR_H) tree-alias-common.h \ + $(TM_H) coretypes.h $(TREE_DUMP_H) langhooks.h domwalk.h \ + tree-pass.h tree-ssa-live.h +tree-ssa-dse.o : tree-ssa-dse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) errors.h $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ + $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) domwalk.h flags.h +tree-ssa-forwprop.o : tree-ssa-forwprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) errors.h $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ + $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) +tree-ssa-phiopt.o : tree-ssa-phiopt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) errors.h $(GGC_H) $(TREE_H) $(RTL_H) $(TM_P_H) $(BASIC_BLOCK_H) \ + $(TREE_FLOW_H) tree-pass.h $(TREE_DUMP_H) langhooks.h +tree-nrv.o : tree-nrv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) $(RTL_H) function.h $(BASIC_BLOCK_H) $(EXPR_H) \ + diagnostic.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TREE_DUMP_H) tree-pass.h \ + langhooks.h +tree-ssa-copy.o : tree-ssa-copy.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \ + errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ + $(BASIC_BLOCK_H) tree-pass.h langhooks.h +tree-ssa-dom.o : tree-ssa-dom.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \ + errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ + $(BASIC_BLOCK_H) domwalk.h real.h tree-pass.h flags.h langhooks.h +tree-ssanames.o : tree-ssanames.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) varray.h $(GGC_H) gt-tree-ssanames.h +tree-phinodes.o : tree-phinodes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) varray.h $(GGC_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) \ + gt-tree-phinodes.h $(RTL_H) +domwalk.o : domwalk.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TREE_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) domwalk.h $(GGC_H) +tree-ssa-live.o : tree-ssa-live.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \ + errors.h toplev.h function.h $(TIMEVAR_H) tree-alias-common.h \ + $(TM_H) coretypes.h $(TREE_DUMP_H) tree-ssa-live.h +tree-ssa-copyrename.o : tree-ssa-copyrename.c $(TREE_FLOW_H) $(CONFIG_H) \ + $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \ + diagnostic.h errors.h toplev.h function.h $(TIMEVAR_H) tree-pass.h \ + tree-alias-common.h $(TM_H) coretypes.h $(TREE_DUMP_H) tree-ssa-live.h +tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \ + $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) \ + $(GGC_H) output.h diagnostic.h errors.h toplev.h $(TIMEVAR_H) \ + $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h flags.h +tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) flags.h output.h \ + diagnostic.h errors.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \ + $(TREE_DUMP_H) except.h langhooks.h cfgloop.h gt-tree-cfg.h tree-pass.h +tree-tailcall.o : tree-tailcall.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) function.h $(TM_H) coretypes.h \ + $(TREE_DUMP_H) diagnostic.h except.h tree-pass.h flags.h langhooks.h +tree-nested.o: tree-nested.c $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) \ + $(RTL_H) $(TM_P_H) function.h tree-dump.h tree-inline.h tree-iterator.h \ + tree-simple.h cgraph.h $(EXPR_H) langhooks.h $(GGC_H) gt-tree-nested.h +tree-iterator.o : tree-iterator.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ + coretypes.h $(GGC_H) tree-iterator.h tree-simple.h gt-tree-iterator.h +tree-dfa.o : tree-dfa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \ + errors.h tree-inline.h $(HASHTAB_H) flags.h function.h $(TIMEVAR_H) \ + tree-alias-common.h convert.h $(TM_H) coretypes.h langhooks.h \ + $(TREE_DUMP_H) tree-pass.h params.h +tree-ssa-operands.o : tree-ssa-operands.c $(TREE_FLOW_H) $(CONFIG_H) \ + $(SYSTEM_H) $(TREE_H) $(TM_P_H) $(GGC_H) diagnostic.h \ + tree-inline.h flags.h function.h $(TM_H) $(TIMEVAR_H) tree-pass.h +tree-eh.o : tree-eh.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_H) flags.h function.h except.h langhooks.h \ + $(GGC_H) tree-pass.h gt-tree-eh.h +tree-ssa-loop.o : tree-ssa-loop.c $(TREE_FLOW_H) $(CONFIG_H) \ + $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) cfgloop.h \ + output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ + tree-pass.h flags.h tree-inline.h +tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ + $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) tree-inline.h flags.h \ + function.h $(TIMEVAR_H) tree-alias-common.h convert.h $(TM_H) coretypes.h \ + langhooks.h $(TREE_DUMP_H) tree-pass.h params.h +tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) \ + $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) \ + $(GGC_H) output.h diagnostic.h errors.h flags.h tree-alias-common.h \ + $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) toplev.h function.h \ + langhooks.h flags.h cgraph.h tree-inline.h tree-mudflap.h $(GGC_H) \ + cgraph.h tree-pass.h +c-simplify.o : c-simplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ + $(C_TREE_H) $(C_COMMON_H) diagnostic.h $(TREE_SIMPLE_H) varray.h flags.h \ + langhooks.h toplev.h rtl.h $(TREE_FLOW_H) langhooks-def.h \ + $(TM_H) coretypes.h $(C_PRETTY_PRINT_H) cgraph.h +gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ + diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \ + langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \ + flags.h $(RTL_H) function.h $(EXPR_H) output.h $(GGC_H) gt-gimplify.h +gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ + diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \ + langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \ + flags.h $(RTL_H) function.h tree-pass.h +tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ + $(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \ + $(TM_H) coretypes.h +tree-simple.o : tree-simple.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(EXPR_H) \ + $(RTL_H) $(TREE_SIMPLE_H) $(TM_H) coretypes.h bitmap.h $(GGC_H) +tree-mudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ + $(C_TREE_H) $(C_COMMON_H) $(TREE_SIMPLE_H) diagnostic.h $(HASHTAB_H) \ + output.h varray.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h \ + $(TREE_DUMP_H) tree-pass.h +c-mudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ + $(C_TREE_H) $(C_COMMON_H) $(TREE_SIMPLE_H) diagnostic.h $(HASHTAB_H) \ + output.h varray.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h +tree-nomudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ + $(C_TREE_H) $(C_COMMON_H) $(TREE_SIMPLE_H) diagnostic.h $(HASHTAB_H) \ + output.h varray.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h +tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \ + errors.h $(TREE_H) diagnostic.h real.h $(HASHTAB_H) $(TREE_FLOW_H) \ + $(TM_H) coretypes.h tree-iterator.h fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) flags.h real.h toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) $(GGC_H) \ $(TM_P_H) langhooks.h $(MD5_H) @@ -1584,7 +1742,7 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_ function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ flags.h function.h $(EXPR_H) $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h \ insn-config.h $(RECOG_H) output.h toplev.h except.h $(HASHTAB_H) $(GGC_H) \ - $(TM_P_H) langhooks.h gt-function.h $(TARGET_H) + $(TM_P_H) langhooks.h gt-function.h $(TARGET_H) basic-block.h stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \ function.h insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \ $(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H) \ @@ -1597,7 +1755,8 @@ except.o : except.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ expr.o : expr.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) flags.h \ function.h $(REGS_H) $(EXPR_H) $(OPTABS_H) libfuncs.h $(INSN_ATTR_H) insn-config.h \ $(RECOG_H) output.h typeclass.h hard-reg-set.h toplev.h hard-reg-set.h \ - except.h reload.h $(GGC_H) langhooks.h intl.h $(TM_P_H) real.h $(TARGET_H) + except.h reload.h $(GGC_H) langhooks.h intl.h $(TM_P_H) real.h $(TARGET_H) \ + tree-iterator.h dojump.o : dojump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ flags.h function.h $(EXPR_H) $(OPTABS_H) $(INSN_ATTR_H) insn-config.h \ langhooks.h $(GGC_H) gt-dojump.h @@ -1680,14 +1839,26 @@ gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ hard-reg-set.h flags.h real.h insn-config.h $(GGC_H) $(RECOG_H) $(EXPR_H) \ $(BASIC_BLOCK_H) function.h output.h toplev.h $(TM_P_H) $(PARAMS_H) \ except.h gt-gcse.h $(TREE_H) cselib.h -sibcall.o : sibcall.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ - function.h hard-reg-set.h flags.h insn-config.h $(RECOG_H) $(BASIC_BLOCK_H) resource.o : resource.c $(CONFIG_H) $(RTL_H) hard-reg-set.h $(SYSTEM_H) coretypes.h \ $(TM_H) $(BASIC_BLOCK_H) $(REGS_H) flags.h output.h resource.h function.h toplev.h \ $(INSN_ATTR_H) except.h $(PARAMS_H) $(TM_P_H) lcm.o : lcm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ hard-reg-set.h flags.h real.h insn-config.h $(INSN_ATTR_H) $(RECOG_H) $(EXPR_H) \ $(BASIC_BLOCK_H) $(TM_P_H) df.h function.h +tree-ssa-dce.o : tree-ssa-dce.c $(CONFIG_H) system.h errors.h $(TREE_H) \ + $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h $(TIMEVAR_H) $(TM_H) \ + coretypes.h $(TREE_DUMP_H) tree-pass.h flags.h +tree-ssa-ccp.o : tree-ssa-ccp.c $(CONFIG_H) system.h errors.h $(TREE_H) \ + $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h \ + $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SIMPLE_H) \ + $(EXPR_H) tree-pass.h flags.h langhooks.h +tree-sra.o : tree-sra.c $(CONFIG_H) system.h errors.h $(TREE_H) $(RTL_H) \ + $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h \ + $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SIMPLE_H) \ + langhooks.h tree-pass.h flags.h +tree-complex.o : tree-complex.c $(CONFIG_H) system.h $(TREE_H) \ + $(TM_H) $(TREE_FLOW_H) $(TREE_SIMPLE_H) tree-iterator.h tree-pass.h \ + flags.h df.o : df.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ insn-config.h $(RECOG_H) function.h $(REGS_H) alloc-pool.h hard-reg-set.h \ $(BASIC_BLOCK_H) df.h $(FIBHEAP_H) @@ -1698,7 +1869,14 @@ conflict.o : conflict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(OBSTACK_H) $(HASHTAB_H) $(RTL_H) hard-reg-set.h $(BASIC_BLOCK_H) profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \ - toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H) $(TREE_H) value-prof.h + toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h +tree-profile.o : tree-profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(RTL_H) $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \ + toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H) $(TREE_H) value-prof.h \ + tree-pass.h $(TREE_FLOW_H) $(TIMEVAR_H) +rtl-profile.o : tree-profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(RTL_H) $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \ + toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h value-prof.o : value-prof.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(BASIC_BLOCK_H) hard-reg-set.h value-prof.h $(EXPR_H) output.h flags.h \ $(RECOG_H) insn-config.h $(OPTABS_H) $(REGS_H) @@ -1719,9 +1897,9 @@ flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ $(RECOG_H) function.h except.h $(EXPR_H) $(GGC_H) $(TM_P_H) cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h insn-config.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \ - function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h + function.h except.h $(GGC_H) $(TM_P_H) alloc-pool.h $(TIMEVAR_H) cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ - $(BASIC_BLOCK_H) cfglayout.h $(TIMEVAR_H) toplev.h + $(BASIC_BLOCK_H) cfglayout.h $(TREE_FLOW_H) $(TIMEVAR_H) toplev.h cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \ insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \ function.h except.h $(GGC_H) $(TM_P_H) insn-config.h $(EXPR_H) @@ -1837,7 +2015,7 @@ recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) function. $(INSN_ATTR_H) real.h toplev.h output.h reload.h $(TM_P_H) reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ $(RECOG_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h toplev.h reload.h \ - varray.h function.h $(TM_P_H) $(GGC_H) gt-reg-stack.h + varray.h function.h $(TM_P_H) $(GGC_H) gt-reg-stack.h basic-block.h sreal.o: sreal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) sreal.h predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \ flags.h insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \ @@ -2085,7 +2263,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h $(srcdir)/cpplib.h \ $(host_xm_file_list) $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) \ $(srcdir)/bitmap.h $(srcdir)/coverage.c $(srcdir)/function.h $(srcdir)/rtl.h \ $(srcdir)/optabs.h $(srcdir)/tree.h $(srcdir)/libfuncs.h $(srcdir)/hashtable.h \ - $(srcdir)/real.h $(srcdir)/varray.h $(srcdir)/insn-addr.h \ + $(srcdir)/real.h $(srcdir)/varray.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/cgraph.h \ $(srcdir)/c-common.h $(srcdir)/c-tree.h \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ @@ -2098,6 +2276,16 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h $(srcdir)/cpplib.h \ $(srcdir)/reg-stack.c $(srcdir)/cfglayout.c $(srcdir)/langhooks.c \ $(srcdir)/sdbout.c $(srcdir)/stmt.c $(srcdir)/stor-layout.c \ $(srcdir)/stringpool.c $(srcdir)/tree.c $(srcdir)/varasm.c \ + $(srcdir)/tree-mudflap.c $(srcdir)/tree-flow.h \ + $(srcdir)/c-objc-common.c $(srcdir)/c-common.c $(srcdir)/c-parse.in \ + $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c \ + $(srcdir)/tree-phinodes.c $(srcdir)/tree-cfg.c \ + $(srcdir)/tree-dfa.c $(srcdir)/tree-ssa-ccp.c \ + $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \ + $(srcdir)/tree-alias-type.h $(srcdir)/tree-alias-common.h \ + $(srcdir)/tree-alias-type.c $(srcdir)/tree-alias-common.c \ + $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \ + $(srcdir)/tree-profile.c $(srcdir)/rtl-profile.c $(srcdir)/tree-nested.c \ $(out_file) \ @all_gtfiles@ @@ -2114,6 +2302,10 @@ gt-expr.h gt-sdbout.h gt-optabs.h gt-bitmap.h gt-dojump.h \ gt-dwarf2out.h gt-ra-build.h gt-reg-stack.h gt-dwarf2asm.h \ gt-dbxout.h gt-c-common.h gt-c-decl.h gt-c-parse.h \ gt-c-pragma.h gtype-c.h gt-input.h gt-cfglayout.h \ +gt-tree-alias-common.h gt-tree-mudflap.h \ +gt-tree-ssa-ccp.h gt-tree-eh.h \ +gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \ +gt-tree-phinodes.h gt-tree-cfg.h gt-tree-nested.h \ gt-stringpool.h gt-langhooks.h : s-gtype ; @true gtyp-gen.h: s-gtyp-gen ; @true @@ -2670,7 +2862,7 @@ TEXI_GCCINT_FILES = gccint.texi gcc-common.texi contribute.texi makefile.texi \ c-tree.texi rtl.texi md.texi tm.texi hostconfig.texi fragments.texi \ configfiles.texi collect2.texi headerdirs.texi funding.texi gnu.texi \ gpl.texi fdl.texi contrib.texi languages.texi sourcebuild.texi \ - gty.texi libgcc.texi + gty.texi libgcc.texi cfg.texi tree-ssa.texi TEXI_GCCINSTALL_FILES = install.texi install-old.texi fdl.texi diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 0abc8773322..3a057fab8f5 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,12 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. + + * config-lang.in (boot_language, build_by_default): Set + to no. + * utils.c (unchecked_convert): Use OEP_ONLY_CONST. + (max_size): Add static chain op for call_expr. + 2004-05-12 Richard Sandiford PR target/15331 diff --git a/gcc/ada/ChangeLog.tree-ssa b/gcc/ada/ChangeLog.tree-ssa new file mode 100644 index 00000000000..73524e5492b --- /dev/null +++ b/gcc/ada/ChangeLog.tree-ssa @@ -0,0 +1,29 @@ +2004-05-05 Richard Henderson + + * utils.c (unchecked_convert): Use OEP_ONLY_CONST. + +2004-03-25 Diego Novillo + + * config-lang.in: Disable Ada by default. + +2004-02-16 Richard Henderson + + * utils.c (max_size): Add static chain op for call_expr. + +2003-09-25 Jason Merrill + + * trans.c, utils.c: Revert 2003-01-15 change. + +2003-01-15 Jeff Law + + * trans.c (tree_transform): Use annotate_with_file_line to add + file/line information to nodes. + (build_unit_elab): Use TREE_FILENAME and TREE_LINENO to + retrieve file/line information from a node. + * utils.c (create_label_decl): Use annotate_with_file_line to + add file/line information to nodes. + +Local Variables: +mode: change-log +change-log-default-name: "ChangeLog.tree-ssa" +End: diff --git a/gcc/ada/config-lang.in b/gcc/ada/config-lang.in index 9a9599dbf1b..eb044afdb81 100644 --- a/gcc/ada/config-lang.in +++ b/gcc/ada/config-lang.in @@ -27,7 +27,7 @@ # stagestuff - files to add to $(STAGESTUFF) language="ada" -boot_language=yes +boot_language=no boot_language_boot_flags='ADAFLAGS="$(BOOT_ADAFLAGS)"' compilers="gnat1\$(exeext)" @@ -39,3 +39,6 @@ gtfiles="\$(srcdir)/ada/ada-tree.h \$(srcdir)/ada/gigi.h \$(srcdir)/ada/decl.c \ outputs=ada/Makefile target_libs="target-libada" + +# Ada will not work until the front end starts emitting GIMPLE trees. +build_by_default=no diff --git a/gcc/ada/utils.c b/gcc/ada/utils.c index e1aac178a9e..f84907d383b 100644 --- a/gcc/ada/utils.c +++ b/gcc/ada/utils.c @@ -2220,7 +2220,7 @@ max_size (tree exp, int max_p) max_size (TREE_OPERAND (exp, 2), max_p))); else if (code == CALL_EXPR && TREE_OPERAND (exp, 1) != 0) return build (CALL_EXPR, type, TREE_OPERAND (exp, 0), - max_size (TREE_OPERAND (exp, 1), max_p)); + max_size (TREE_OPERAND (exp, 1), max_p), NULL); } } @@ -3432,7 +3432,8 @@ unchecked_convert (tree type, tree expr, int notrunc_p) /* If the sizes of the types differ and this is an VIEW_CONVERT_EXPR, show no longer constant. */ if (TREE_CODE (expr) == VIEW_CONVERT_EXPR - && ! operand_equal_p (TYPE_SIZE_UNIT (type), TYPE_SIZE_UNIT (etype), 1)) + && ! operand_equal_p (TYPE_SIZE_UNIT (type), TYPE_SIZE_UNIT (etype), + OEP_ONLY_CONST)) TREE_CONSTANT (expr) = 0; return expr; diff --git a/gcc/basic-block.h b/gcc/basic-block.h index ccbecf1fdc4..c64b7b0d556 100644 --- a/gcc/basic-block.h +++ b/gcc/basic-block.h @@ -27,9 +27,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "varray.h" #include "partition.h" #include "hard-reg-set.h" +#include "predict.h" /* Head of register set linked list. */ typedef bitmap_head regset_head; + /* A pointer to a regset_head. */ typedef bitmap regset; @@ -121,18 +123,24 @@ do { \ typedef HOST_WIDEST_INT gcov_type; /* Control flow edge information. */ -typedef struct edge_def { +struct edge_def GTY((chain_next ("%h.pred_next"))) +{ /* Links through the predecessor and successor lists. */ - struct edge_def *pred_next, *succ_next; + struct edge_def *pred_next; + struct edge_def *succ_next; /* The two blocks at the ends of the edge. */ - struct basic_block_def *src, *dest; + struct basic_block_def *src; + struct basic_block_def *dest; /* Instructions queued on the edge. */ - rtx insns; + union edge_def_insns { + rtx GTY ((tag ("0"))) r; + tree GTY ((tag ("1"))) t; + } GTY ((desc ("ir_type ()"))) insns; /* Auxiliary info specific to a pass. */ - void *aux; + PTR GTY ((skip (""))) aux; int flags; /* see EDGE_* below */ int probability; /* biased by REG_BR_PROB_BASE */ @@ -140,7 +148,9 @@ typedef struct edge_def { in profile.c */ bool crossing_edge; /* Crosses between hot and cold sections, when we do partitioning. */ -} *edge; +}; + +typedef struct edge_def *edge; #define EDGE_FALLTHRU 1 /* 'Straight line' flow */ #define EDGE_ABNORMAL 2 /* Strange flow, like computed @@ -155,7 +165,13 @@ typedef struct edge_def { #define EDGE_IRREDUCIBLE_LOOP 128 /* Part of irreducible loop. */ #define EDGE_SIBCALL 256 /* Edge from sibcall to exit. */ #define EDGE_LOOP_EXIT 512 /* Exit of a loop. */ -#define EDGE_ALL_FLAGS 1023 +#define EDGE_TRUE_VALUE 1024 /* Edge taken when controlling + predicate is non zero. */ +#define EDGE_FALSE_VALUE 2048 /* Edge taken when controlling + predicate is zero. */ +#define EDGE_EXECUTABLE 4096 /* Edge is executable. Only + valid during SSA-CCP. */ +#define EDGE_ALL_FLAGS 8191 #define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH) @@ -167,6 +183,9 @@ extern const struct gcov_ctr_summary *profile_info; struct loop; struct loops; +/* Declared in tree-flow.h. */ +struct bb_ann_d; + /* A basic block is a sequence of instructions with only entry and only one exit. If any one of the instructions are executed, they will all be executed, and in sequence from first to last. @@ -193,51 +212,54 @@ struct loops; basic blocks. */ /* Basic block information indexed by block number. */ -typedef struct basic_block_def { +struct basic_block_def GTY((chain_next ("%h.next_bb"), chain_prev ("%h.prev_bb"))) +{ /* The first and last insns of the block. */ - rtx head_, end_; + rtx head_; + rtx end_; - /* The first and last trees of the block. */ - tree head_tree; - tree end_tree; + /* Pointers to the first and last trees of the block. */ + tree stmt_list; /* The edges into and out of the block. */ - edge pred, succ; + edge pred; + edge succ; /* Liveness info. */ /* The registers that are modified within this in block. */ - regset local_set; + bitmap GTY ((skip (""))) local_set; /* The registers that are conditionally modified within this block. In other words, registers that are set only as part of a COND_EXEC. */ - regset cond_local_set; + bitmap GTY ((skip (""))) cond_local_set; /* The registers that are live on entry to this block. Note that in SSA form, global_live_at_start does not reflect the use of regs in phi functions, since the liveness of these regs may depend on which edge was taken into the block. */ - regset global_live_at_start; + bitmap GTY ((skip (""))) global_live_at_start; /* The registers that are live on exit from this block. */ - regset global_live_at_end; + bitmap GTY ((skip (""))) global_live_at_end; /* Auxiliary info specific to a pass. */ - void *aux; + PTR GTY ((skip (""))) aux; /* The index of this block. */ int index; /* Previous and next blocks in the chain. */ - struct basic_block_def *prev_bb, *next_bb; + struct basic_block_def *prev_bb; + struct basic_block_def *next_bb; /* The loop depth of this block. */ int loop_depth; - /* Outermost loop containing the block. */ - struct loop *loop_father; + /* Innermost loop containing the block. */ + struct loop * GTY ((skip (""))) loop_father; /* The dominance and postdominance information node. */ - struct et_node *dom[2]; + struct et_node * GTY ((skip (""))) dom[2]; /* Expected number of executions: calculated in profile.c. */ gcov_type count; @@ -251,9 +273,31 @@ typedef struct basic_block_def { /* Which section block belongs in, when partitioning basic blocks. */ int partition; - /* Additional data maintained by cfg_layout routines. */ - struct reorder_block_def *rbi; -} *basic_block; + /* The data used by basic block copying and reordering functions. */ + struct reorder_block_def * GTY ((skip (""))) rbi; + + /* Annotations used at the tree level. */ + struct bb_ann_d *tree_annotations; +}; + +typedef struct basic_block_def *basic_block; + +/* Structure to hold information about the blocks during reordering and + copying. */ + +typedef struct reorder_block_def +{ + rtx header; + rtx footer; + basic_block next; + basic_block original; + /* Used by loop copying. */ + basic_block copy; + int duplicated; + + /* These fields are used by bb-reorder pass. */ + int visited; +} *reorder_block_def; #define BB_FREQ_MAX 10000 @@ -285,7 +329,7 @@ extern int n_edges; /* Index by basic block number, get basic block struct info. */ -extern varray_type basic_block_info; +extern GTY(()) varray_type basic_block_info; #define BASIC_BLOCK(N) (VARRAY_BB (basic_block_info, (N))) @@ -352,9 +396,8 @@ extern struct obstack flow_obstack; #define INVALID_BLOCK (-3) /* Similarly, block pointers for the edge list. */ -extern struct basic_block_def entry_exit_blocks[2]; -#define ENTRY_BLOCK_PTR (&entry_exit_blocks[0]) -#define EXIT_BLOCK_PTR (&entry_exit_blocks[1]) +extern GTY(()) basic_block ENTRY_BLOCK_PTR; +extern GTY(()) basic_block EXIT_BLOCK_PTR; #define BLOCK_NUM(INSN) (BLOCK_FOR_INSN (INSN)->index + 0) #define set_block_for_insn(INSN, BB) (BLOCK_FOR_INSN (INSN) = BB) @@ -374,7 +417,6 @@ extern void commit_edge_insertions_watch_calls (void); extern void remove_fake_edges (void); extern void add_noreturn_fake_exit_edges (void); extern void connect_infinite_loops_to_exit (void); -extern int flow_call_edges_add (sbitmap); extern edge unchecked_make_edge (basic_block, basic_block, int); extern edge cached_make_edge (sbitmap *, basic_block, basic_block, int); extern edge make_edge (basic_block, basic_block, int); @@ -392,6 +434,7 @@ extern int dfs_enumerate_from (basic_block, int, bool (*)(basic_block, void *), basic_block *, int, void *); extern void dump_edge_info (FILE *, edge, int); +extern void brief_dump_cfg (FILE *); extern void clear_edges (void); extern void mark_critical_edges (void); extern rtx first_insn_after_basic_block_note (basic_block); @@ -472,6 +515,7 @@ void free_edge_list (struct edge_list *); void print_edge_list (FILE *, struct edge_list *); void verify_edge_list (FILE *, struct edge_list *); int find_edge_index (struct edge_list *, basic_block, basic_block); +edge find_edge (basic_block, basic_block); enum update_life_extent @@ -554,6 +598,11 @@ extern void expected_value_to_br_prob (void); extern bool maybe_hot_bb_p (basic_block); extern bool probably_cold_bb_p (basic_block); extern bool probably_never_executed_bb_p (basic_block); +extern bool tree_predicted_by_p (basic_block, enum br_predictor); +extern bool rtl_predicted_by_p (basic_block, enum br_predictor); +extern void tree_predict_edge (edge, enum br_predictor, int); +extern void rtl_predict_edge (edge, enum br_predictor, int); +extern void predict_edge_def (edge, enum br_predictor, enum prediction); /* In flow.c */ extern void init_flow (void); @@ -577,7 +626,7 @@ extern bool purge_all_dead_edges (int); extern bool purge_dead_edges (basic_block); extern void find_sub_basic_blocks (basic_block); extern void find_many_sub_basic_blocks (sbitmap); -extern void make_eh_edge (sbitmap *, basic_block, rtx); +extern void rtl_make_eh_edge (sbitmap *, basic_block, rtx); extern bool can_fallthru (basic_block, basic_block); extern void flow_nodes_print (const char *, const sbitmap, FILE *); extern void flow_edge_list_print (const char *, const edge *, int, FILE *); @@ -589,6 +638,10 @@ extern void alloc_aux_for_edge (edge, int); extern void alloc_aux_for_edges (int); extern void clear_aux_for_edges (void); extern void free_aux_for_edges (void); +extern void find_basic_blocks (rtx, int, FILE *); +extern bool cleanup_cfg (int); +extern bool delete_unreachable_blocks (void); +extern bool merge_seq_blocks (void); typedef struct conflict_graph_def *conflict_graph; @@ -624,6 +677,11 @@ extern bool control_flow_insn_p (rtx); extern void reorder_basic_blocks (void); extern void partition_hot_cold_basic_blocks (void); +/* In cfg.c */ +extern void alloc_rbi_pool (void); +extern void initialize_bb_rbi (basic_block bb); +extern void free_rbi_pool (void); + /* In dominance.c */ enum cdi_direction @@ -661,7 +719,7 @@ extern void iterate_fix_dominators (enum cdi_direction, basic_block *, int); extern void verify_dominators (enum cdi_direction); extern basic_block first_dom_son (enum cdi_direction, basic_block); extern basic_block next_dom_son (enum cdi_direction, basic_block); -extern bool try_redirect_by_replacing_jump (edge, basic_block, bool); +extern edge try_redirect_by_replacing_jump (edge, basic_block, bool); extern void break_superblocks (void); #include "cfghooks.h" diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index 5437b8b0349..c461a160313 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -749,7 +749,7 @@ copy_bb (basic_block old_bb, edge e, basic_block bb, int trace) { basic_block new_bb; - new_bb = cfg_layout_duplicate_bb (old_bb, e); + new_bb = duplicate_block (old_bb, e); if (e->dest != new_bb) abort (); if (e->dest->rbi->visited) @@ -1177,7 +1177,7 @@ copy_bb_p (basic_block bb, int code_may_grow) return false; if (!bb->pred || !bb->pred->pred_next) return false; - if (!cfg_layout_can_duplicate_bb_p (bb)) + if (!can_duplicate_block_p (bb)) return false; /* Avoid duplicating blocks which have many successors (PR/13430). */ diff --git a/gcc/bitmap.c b/gcc/bitmap.c index 70e0a93d086..ebbb6ee805f 100644 --- a/gcc/bitmap.c +++ b/gcc/bitmap.c @@ -414,7 +414,9 @@ bitmap_first_set_bit (bitmap a) #else for (word_num = 0; word_num < BITMAP_ELEMENT_WORDS; ++word_num) if ((word = ptr->bits[word_num]) != 0) - break; + goto word_found; + abort (); + word_found: #endif /* Binary search for the first set bit. */ @@ -469,7 +471,9 @@ bitmap_last_set_bit (bitmap a) #else for (word_num = BITMAP_ELEMENT_WORDS; word_num-- > 0; ) if ((word = ptr->bits[word_num]) != 0) - break; + goto word_found; + abort (); + word_found: #endif /* Binary search for the last set bit. */ diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index c6cf5d37e55..a809a477928 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -227,6 +227,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE_COMPLEX_DOUBLE, BT_COMPLEX_DOUBLE, BT_COMPLEX_DOUBLE, BT_COMPLEX_DOUBLE) DEF_FUNCTION_TYPE_2 (BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE, BT_COMPLEX_LONGDOUBLE, BT_COMPLEX_LONGDOUBLE, BT_COMPLEX_LONGDOUBLE) +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTR, BT_VOID, BT_PTR, BT_PTR) DEF_FUNCTION_TYPE_2 (BT_FN_INT_CONST_STRING_PTR_CONST_STRING, BT_INT, BT_CONST_STRING, BT_PTR_CONST_STRING) @@ -270,6 +271,7 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_DOUBLE_DOUBLEPTR_DOUBLEPTR, BT_VOID, BT_DOUBLE, BT_DOUBLE_PTR, BT_DOUBLE_PTR) DEF_FUNCTION_TYPE_3 (BT_FN_VOID_LONGDOUBLE_LONGDOUBLEPTR_LONGDOUBLEPTR, BT_VOID, BT_LONGDOUBLE, BT_LONGDOUBLE_PTR, BT_LONGDOUBLE_PTR) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_PTR_PTR_PTR, BT_VOID, BT_PTR, BT_PTR, BT_PTR) DEF_FUNCTION_TYPE_3 (BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING, BT_INT, BT_CONST_STRING, BT_PTR_CONST_STRING, BT_PTR_CONST_STRING) diff --git a/gcc/builtins.c b/gcc/builtins.c index 33fca2ab32e..b0375c377aa 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -68,11 +68,10 @@ const char *const built_in_names[(int) END_BUILTINS] = tree built_in_decls[(int) END_BUILTINS]; /* Declarations used when constructing the builtin implicitly in the compiler. It may be NULL_TREE when this is invalid (for instance runtime is not - required to implement the function call in all cases. */ + required to implement the function call in all cases). */ tree implicit_built_in_decls[(int) END_BUILTINS]; static int get_pointer_alignment (tree, unsigned int); -static tree c_strlen (tree, int); static const char *c_getstr (tree); static rtx c_readstr (const char *, enum machine_mode); static int target_char_cast (tree, char *); @@ -96,7 +95,6 @@ static void expand_errno_check (tree, rtx); static rtx expand_builtin_mathfn (tree, rtx, rtx); static rtx expand_builtin_mathfn_2 (tree, rtx, rtx); static rtx expand_builtin_mathfn_3 (tree, rtx, rtx); -static rtx expand_builtin_constant_p (tree, enum machine_mode); static rtx expand_builtin_args_info (tree); static rtx expand_builtin_next_arg (tree); static rtx expand_builtin_va_start (tree); @@ -163,6 +161,22 @@ static tree fold_builtin_strcmp (tree); static tree fold_builtin_strncmp (tree); static tree fold_builtin_signbit (tree); +static tree simplify_builtin_memcmp (tree); +static tree simplify_builtin_strcmp (tree); +static tree simplify_builtin_strncmp (tree); +static tree simplify_builtin_strpbrk (tree); +static tree simplify_builtin_strstr (tree); +static tree simplify_builtin_strchr (tree); +static tree simplify_builtin_strrchr (tree); +static tree simplify_builtin_strcat (tree); +static tree simplify_builtin_strncat (tree); +static tree simplify_builtin_strspn (tree); +static tree simplify_builtin_strcspn (tree); +static void simplify_builtin_next_arg (tree); +static void simplify_builtin_va_start (tree); +static tree simplify_builtin_sprintf (tree, int); + + /* Return the alignment in bits of EXP, a pointer valued expression. But don't return more than MAX_ALIGN no matter what. The alignment returned is, by default, the alignment of the thing that @@ -247,7 +261,7 @@ get_pointer_alignment (tree exp, unsigned int max_align) Unfortunately, string_constant can't access the values of const char arrays with initializers, so neither can we do so here. */ -static tree +tree c_strlen (tree src, int only_value) { tree offset_node; @@ -407,6 +421,21 @@ target_char_cast (tree cst, char *p) return 0; } +/* Similar to save_expr, but assumes that arbitrary code is not executed + in between the multiple evaluations. In particular, we assume that a + non-addressable local variable will not be modified. */ + +static tree +builtin_save_expr (tree exp) +{ + if (TREE_ADDRESSABLE (exp) == 0 + && (TREE_CODE (exp) == PARM_DECL + || (TREE_CODE (exp) == VAR_DECL && !TREE_STATIC (exp)))) + return exp; + + return save_expr (exp); +} + /* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT times to get the address of either a higher stack frame, or a return address located within it (depending on FNDECL_CODE). */ @@ -739,6 +768,79 @@ expand_builtin_longjmp (rtx buf_addr, rtx value) } } +/* Expand a call to __builtin_nonlocal_goto. We're passed the target label + and the address of the save area. */ + +static rtx +expand_builtin_nonlocal_goto (tree arglist) +{ + tree t_label, t_save_area; + rtx r_label, r_save_area, r_fp, r_sp, insn; + + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return NULL_RTX; + + t_label = TREE_VALUE (arglist); + arglist = TREE_CHAIN (arglist); + t_save_area = TREE_VALUE (arglist); + + r_label = expand_expr (t_label, NULL_RTX, VOIDmode, 0); + r_save_area = expand_expr (t_save_area, NULL_RTX, VOIDmode, 0); + r_fp = gen_rtx_MEM (Pmode, r_save_area); + r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL), + plus_constant (r_save_area, GET_MODE_SIZE (Pmode))); + + current_function_has_nonlocal_goto = 1; + +#if HAVE_nonlocal_goto + /* ??? We no longer need to pass the static chain value, afaik. */ + if (HAVE_nonlocal_goto) + emit_insn (gen_nonlocal_goto (const0_rtx, r_label, r_sp, r_fp)); + else +#endif + { + r_label = copy_to_reg (r_label); + + emit_insn (gen_rtx_CLOBBER (VOIDmode, + gen_rtx_MEM (BLKmode, + gen_rtx_SCRATCH (VOIDmode)))); + + emit_insn (gen_rtx_CLOBBER (VOIDmode, + gen_rtx_MEM (BLKmode, + hard_frame_pointer_rtx))); + + /* Restore frame pointer for containing function. + This sets the actual hard register used for the frame pointer + to the location of the function's incoming static chain info. + The non-local goto handler will then adjust it to contain the + proper value and reload the argument pointer, if needed. */ + emit_move_insn (hard_frame_pointer_rtx, r_fp); + emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX); + + /* USE of hard_frame_pointer_rtx added for consistency; + not clear if really needed. */ + emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); + emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); + emit_indirect_jump (r_label); + } + + /* Search backwards to the jump insn and mark it as a + non-local goto. */ + for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) + { + if (GET_CODE (insn) == JUMP_INSN) + { + REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, + const0_rtx, REG_NOTES (insn)); + break; + } + else if (GET_CODE (insn) == CALL_INSN) + break; + } + + return const0_rtx; +} + /* __builtin_update_setjmp_buf is passed a pointer to an array of five words (not all will be used on all machines) that was passed to __builtin_setjmp. It updates the stack pointer in that block to correspond to the current @@ -1230,7 +1332,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize) } /* All arguments and registers used for the call are set up by now! */ - function = prepare_call_address (function, NULL_TREE, &call_fusage, 0, 0); + function = prepare_call_address (function, NULL, &call_fusage, 0, 0); /* Ensure address is valid. SYMBOL_REF is already valid, so no need, and we don't want to load it into a register as an optimization, @@ -1384,32 +1486,6 @@ expand_builtin_classify_type (tree arglist) return GEN_INT (no_type_class); } -/* Expand expression EXP, which is a call to __builtin_constant_p. */ - -static rtx -expand_builtin_constant_p (tree arglist, enum machine_mode target_mode) -{ - rtx tmp; - - if (arglist == 0) - return const0_rtx; - arglist = TREE_VALUE (arglist); - - /* We have taken care of the easy cases during constant folding. This - case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE - get a chance to see if it can deduce whether ARGLIST is constant. - If CSE isn't going to run, of course, don't bother waiting. */ - - if (cse_not_expected) - return const0_rtx; - - current_function_calls_constant_p = 1; - - tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0); - tmp = gen_rtx_CONSTANT_P_RTX (target_mode, tmp); - return tmp; -} - /* This helper macro, meant to be used in mathfn_built_in below, determines which among a set of three builtin math functions is appropriate for a given type mode. The `F' and `L' cases are @@ -1682,7 +1758,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) /* Wrap the computation of the argument in a SAVE_EXPR, as we may need to expand the argument again. This way, we will not perform side-effects more the once. */ - narg = save_expr (arg); + narg = builtin_save_expr (arg); if (narg != arg) { arglist = build_tree_list (NULL_TREE, arg); @@ -1821,8 +1897,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) if (! flag_errno_math || ! HONOR_NANS (mode)) errno_set = false; - /* Alway stabilize the argument list. */ - narg = save_expr (arg1); + /* Always stabilize the argument list. */ + narg = builtin_save_expr (arg1); if (narg != arg1) { temp = build_tree_list (NULL_TREE, narg); @@ -1831,7 +1907,7 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) else temp = TREE_CHAIN (arglist); - narg = save_expr (arg0); + narg = builtin_save_expr (arg0); if (narg != arg0) { arglist = tree_cons (NULL_TREE, narg, temp); @@ -3488,8 +3564,8 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode) result = gen_reg_rtx (insn_mode); /* Stabilize the arguments in case gen_cmpstrsi fails. */ - arg1 = save_expr (arg1); - arg2 = save_expr (arg2); + arg1 = builtin_save_expr (arg1); + arg2 = builtin_save_expr (arg2); arg1_rtx = get_memory_rtx (arg1); arg2_rtx = get_memory_rtx (arg2); @@ -3659,9 +3735,9 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode) result = gen_reg_rtx (insn_mode); /* Stabilize the arguments in case gen_cmpstrsi fails. */ - arg1 = save_expr (arg1); - arg2 = save_expr (arg2); - len = save_expr (len); + arg1 = builtin_save_expr (arg1); + arg2 = builtin_save_expr (arg2); + len = builtin_save_expr (len); arg1_rtx = get_memory_rtx (arg1); arg2_rtx = get_memory_rtx (arg2); @@ -3731,7 +3807,7 @@ expand_builtin_strcat (tree arglist, rtx target, enum machine_mode mode) arglist = tree_cons (NULL_TREE, src, arglist); /* We're going to use dst more than once. */ - dst = save_expr (dst); + dst = builtin_save_expr (dst); /* Create strlen (dst). */ newdst = @@ -4401,6 +4477,12 @@ expand_builtin_alloca (tree arglist, rtx target) rtx op0; rtx result; + /* In -fmudflap-instrumented code, alloca() and __builtin_alloca() + should always expand to function calls. These can be intercepted + in libmudflap. */ + if (flag_mudflap) + return 0; + if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE)) return 0; @@ -4748,6 +4830,7 @@ build_string_literal (int len, const char *str) type = build_array_type (elem, index); TREE_TYPE (t) = type; TREE_CONSTANT (t) = 1; + TREE_INVARIANT (t) = 1; TREE_READONLY (t) = 1; TREE_STATIC (t) = 1; @@ -5041,6 +5124,111 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode) return 0; } +/* Expand a call to either the entry or exit function profiler. */ + +static rtx +expand_builtin_profile_func (bool exitp) +{ + rtx this, which; + + this = DECL_RTL (current_function_decl); + if (GET_CODE (this) == MEM) + this = XEXP (this, 0); + else + abort (); + + if (exitp) + which = profile_function_exit_libfunc; + else + which = profile_function_entry_libfunc; + + emit_library_call (which, LCT_NORMAL, VOIDmode, 2, this, Pmode, + expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, + 0, hard_frame_pointer_rtx), + Pmode); + + return const0_rtx; +} + +/* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT. */ + +static rtx +round_trampoline_addr (rtx tramp) +{ + rtx temp, addend, mask; + + /* If we don't need too much alignment, we'll have been guaranteed + proper alignment by get_trampoline_type. */ + if (TRAMPOLINE_ALIGNMENT <= STACK_BOUNDARY) + return tramp; + + /* Round address up to desired boundary. */ + temp = gen_reg_rtx (Pmode); + addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1); + mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT); + + temp = expand_simple_binop (Pmode, PLUS, tramp, addend, + temp, 0, OPTAB_LIB_WIDEN); + tramp = expand_simple_binop (Pmode, AND, temp, mask, + temp, 0, OPTAB_LIB_WIDEN); + + return tramp; +} + +static rtx +expand_builtin_init_trampoline (tree arglist) +{ + tree t_tramp, t_func, t_chain; + rtx r_tramp, r_func, r_chain; +#ifdef TRAMPOLINE_TEMPLATE + rtx blktramp; +#endif + + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, + POINTER_TYPE, VOID_TYPE)) + return NULL_RTX; + + t_tramp = TREE_VALUE (arglist); + arglist = TREE_CHAIN (arglist); + t_func = TREE_VALUE (arglist); + arglist = TREE_CHAIN (arglist); + t_chain = TREE_VALUE (arglist); + + r_tramp = expand_expr (t_tramp, NULL_RTX, VOIDmode, 0); + r_func = expand_expr (t_func, NULL_RTX, VOIDmode, 0); + r_chain = expand_expr (t_chain, NULL_RTX, VOIDmode, 0); + + /* Generate insns to initialize the trampoline. */ + r_tramp = round_trampoline_addr (r_tramp); +#ifdef TRAMPOLINE_TEMPLATE + blktramp = gen_rtx_MEM (BLKmode, r_tramp); + set_mem_align (blktramp, TRAMPOLINE_ALIGNMENT); + emit_block_move (blktramp, assemble_trampoline_template (), + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); +#endif + trampolines_created = 1; + INITIALIZE_TRAMPOLINE (r_tramp, r_func, r_chain); + + return const0_rtx; +} + +static rtx +expand_builtin_adjust_trampoline (tree arglist) +{ + rtx tramp; + + if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE)) + return NULL_RTX; + + tramp = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0); + tramp = round_trampoline_addr (tramp); +#ifdef TRAMPOLINE_ADJUST_ADDRESS + TRAMPOLINE_ADJUST_ADDRESS (tramp); +#endif + + return tramp; +} + /* Expand a call to the built-in signbit, signbitf or signbitl function. Return NULL_RTX if a normal call should be emitted rather than expanding the function in-line. EXP is the expression that is a call to the builtin @@ -5453,13 +5641,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, /* Return the address of the first anonymous stack arg. */ case BUILT_IN_NEXT_ARG: + simplify_builtin_next_arg (arglist); return expand_builtin_next_arg (arglist); case BUILT_IN_CLASSIFY_TYPE: return expand_builtin_classify_type (arglist); case BUILT_IN_CONSTANT_P: - return expand_builtin_constant_p (arglist, target_mode); + return const0_rtx; case BUILT_IN_FRAME_ADDRESS: case BUILT_IN_RETURN_ADDRESS: @@ -5481,6 +5670,18 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; + case BUILT_IN_STACK_ALLOC: + expand_stack_alloc (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist))); + return const0_rtx; + + case BUILT_IN_STACK_SAVE: + return expand_stack_save (); + + case BUILT_IN_STACK_RESTORE: + expand_stack_restore (TREE_VALUE (arglist)); + return const0_rtx; + case BUILT_IN_FFS: case BUILT_IN_FFSL: case BUILT_IN_FFSLL: @@ -5684,6 +5885,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return const0_rtx; } + case BUILT_IN_NONLOCAL_GOTO: + target = expand_builtin_nonlocal_goto (arglist); + if (target) + return target; + break; + /* This updates the setjmp buffer that is its argument with the value of the current stack pointer. */ case BUILT_IN_UPDATE_SETJMP_BUF: @@ -5718,7 +5925,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, if (target) return target; break; - case BUILT_IN_FPUTS_UNLOCKED: target = expand_builtin_fputs (arglist, target, true); if (target) @@ -5792,6 +5998,16 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, expand_builtin_prefetch (arglist); return const0_rtx; + case BUILT_IN_PROFILE_FUNC_ENTER: + return expand_builtin_profile_func (false); + case BUILT_IN_PROFILE_FUNC_EXIT: + return expand_builtin_profile_func (true); + + case BUILT_IN_INIT_TRAMPOLINE: + return expand_builtin_init_trampoline (arglist); + case BUILT_IN_ADJUST_TRAMPOLINE: + return expand_builtin_adjust_trampoline (arglist); + case BUILT_IN_FORK: case BUILT_IN_EXECL: case BUILT_IN_EXECV: @@ -5927,6 +6143,44 @@ fold_builtin_constant_p (tree arglist) return 0; } +/* Fold a call to __builtin_expect, if we expect that a comparison against + the argument will fold to a constant. In practice, this means a true + constant or the address of a non-weak symbol. ARGLIST is the argument + list of the call. */ + +static tree +fold_builtin_expect (tree arglist) +{ + tree arg, inner; + + if (arglist == 0) + return 0; + + arg = TREE_VALUE (arglist); + + /* If the argument isn't invariant, then there's nothing we can do. */ + if (!TREE_INVARIANT (arg)) + return 0; + + /* If we're looking at an address of a weak decl, then do not fold. */ + inner = arg; + STRIP_NOPS (inner); + if (TREE_CODE (inner) == ADDR_EXPR) + { + do + { + inner = TREE_OPERAND (inner, 0); + } + while (TREE_CODE (inner) == COMPONENT_REF + || TREE_CODE (inner) == ARRAY_REF); + if (DECL_P (inner) && DECL_WEAK (inner)) + return 0; + } + + /* Otherwise, ARG already has the proper type for the return value. */ + return arg; +} + /* Fold a call to __builtin_classify_type. */ static tree @@ -6196,13 +6450,13 @@ fold_builtin_cabs (tree arglist, tree type) { tree rpart, ipart, result, arglist; - arg = save_expr (arg); + arg = builtin_save_expr (arg); rpart = fold (build1 (REALPART_EXPR, type, arg)); ipart = fold (build1 (IMAGPART_EXPR, type, arg)); - rpart = save_expr (rpart); - ipart = save_expr (ipart); + rpart = builtin_save_expr (rpart); + ipart = builtin_save_expr (ipart); result = fold (build (PLUS_EXPR, type, fold (build (MULT_EXPR, type, @@ -6995,11 +7249,16 @@ fold_builtin_isascii (tree arglist) /* Transform isascii(c) -> ((c & ~0x7f) == 0). */ tree arg = TREE_VALUE (arglist); - return fold (build (EQ_EXPR, integer_type_node, - build (BIT_AND_EXPR, integer_type_node, arg, - build_int_2 (~ (unsigned HOST_WIDE_INT) 0x7f, - ~ (HOST_WIDE_INT) 0)), - integer_zero_node)); + arg = fold (build (EQ_EXPR, integer_type_node, + build (BIT_AND_EXPR, integer_type_node, arg, + build_int_2 (~ (unsigned HOST_WIDE_INT) 0x7f, + ~ (HOST_WIDE_INT) 0)), + integer_zero_node)); + + if (in_gimple_form && !TREE_CONSTANT (arg)) + return NULL_TREE; + else + return arg; } } @@ -7038,15 +7297,19 @@ fold_builtin_isdigit (tree arglist) build_int_2 (TARGET_DIGIT0, 0))); arg = build (LE_EXPR, integer_type_node, arg, fold_convert (unsigned_type_node, build_int_2 (9, 0))); - return fold (arg); + arg = fold (arg); + if (in_gimple_form && !TREE_CONSTANT (arg)) + return NULL_TREE; + else + return arg; } } /* Used by constant folding to eliminate some builtin calls early. EXP is the CALL_EXPR of a call to a builtin function. */ -tree -fold_builtin (tree exp) +static tree +fold_builtin_1 (tree exp) { tree fndecl = get_callee_fndecl (exp); tree arglist = TREE_OPERAND (exp, 1); @@ -7060,6 +7323,9 @@ fold_builtin (tree exp) case BUILT_IN_CONSTANT_P: return fold_builtin_constant_p (arglist); + case BUILT_IN_EXPECT: + return fold_builtin_expect (arglist); + case BUILT_IN_CLASSIFY_TYPE: return fold_builtin_classify_type (arglist); @@ -7557,6 +7823,24 @@ fold_builtin (tree exp) return 0; } +/* A wrapper function for builtin folding that prevents warnings for + "statement without effect" and the like, caused by removing the + call node earlier than the warning is generated. */ + +tree +fold_builtin (tree exp) +{ + exp = fold_builtin_1 (exp); + if (exp) + { + /* ??? Don't clobber shared nodes such as integer_zero_node. */ + if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c') + exp = build1 (NOP_EXPR, TREE_TYPE (exp), exp); + TREE_NO_WARNING (exp) = 1; + } + return exp; +} + /* Conveniently construct a function call expression. */ tree @@ -7566,7 +7850,7 @@ build_function_call_expr (tree fn, tree arglist) call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), - call_expr, arglist); + call_expr, arglist, NULL_TREE); return fold (call_expr); } @@ -7631,31 +7915,6 @@ default_expand_builtin (tree exp ATTRIBUTE_UNUSED, return NULL_RTX; } -/* Instantiate all remaining CONSTANT_P_RTX nodes. */ - -void -purge_builtin_constant_p (void) -{ - rtx insn, set, arg, new, note; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn) - && (set = single_set (insn)) != NULL_RTX - && (GET_CODE (arg = SET_SRC (set)) == CONSTANT_P_RTX - || (GET_CODE (arg) == SUBREG - && (GET_CODE (arg = SUBREG_REG (arg)) - == CONSTANT_P_RTX)))) - { - arg = XEXP (arg, 0); - new = CONSTANT_P (arg) ? const1_rtx : const0_rtx; - validate_change (insn, &SET_SRC (set), new, 0); - - /* Remove the REG_EQUAL note from the insn. */ - if ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0) - remove_note (insn, note); - } -} - /* Returns true is EXP represents data that would potentially reside in a readonly section. */ @@ -7669,3 +7928,1105 @@ readonly_data_expr (tree exp) else return false; } + +/* Front-end to the simplify_builtin_XXX routines. + + EXP is a call to a builtin function. If possible try to simplify + that into a constant, expression or call to a more efficient + builtin function. + + If IGNORE is nonzero, then the result of this builtin function + call is ignored. + + If simplification is possible, return the simplified tree, otherwise + return NULL_TREE. */ + +tree +simplify_builtin (tree exp, int ignore) +{ + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + tree arglist = TREE_OPERAND (exp, 1); + enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); + tree val; + + switch (fcode) + { + case BUILT_IN_FPUTS: + val = simplify_builtin_fputs (arglist, ignore, 0, NULL_TREE); + break; + case BUILT_IN_FPUTS_UNLOCKED: + val = simplify_builtin_fputs (arglist, ignore, 1, NULL_TREE); + break; + case BUILT_IN_STRSTR: + val = simplify_builtin_strstr (arglist); + break; + case BUILT_IN_STRCAT: + val = simplify_builtin_strcat (arglist); + break; + case BUILT_IN_STRNCAT: + val = simplify_builtin_strncat (arglist); + break; + case BUILT_IN_STRSPN: + val = simplify_builtin_strspn (arglist); + break; + case BUILT_IN_STRCSPN: + val = simplify_builtin_strcspn (arglist); + break; + case BUILT_IN_STRCHR: + case BUILT_IN_INDEX: + val = simplify_builtin_strchr (arglist); + break; + case BUILT_IN_STRRCHR: + case BUILT_IN_RINDEX: + val = simplify_builtin_strrchr (arglist); + break; + case BUILT_IN_STRCPY: + val = simplify_builtin_strcpy (arglist, NULL_TREE); + break; + case BUILT_IN_STRNCPY: + val = simplify_builtin_strncpy (arglist, NULL_TREE); + break; + case BUILT_IN_STRCMP: + val = simplify_builtin_strcmp (arglist); + break; + case BUILT_IN_STRNCMP: + val = simplify_builtin_strncmp (arglist); + break; + case BUILT_IN_STRPBRK: + val = simplify_builtin_strpbrk (arglist); + break; + case BUILT_IN_BCMP: + case BUILT_IN_MEMCMP: + val = simplify_builtin_memcmp (arglist); + break; + case BUILT_IN_VA_START: + simplify_builtin_va_start (arglist); + val = NULL_TREE; + break; + case BUILT_IN_SPRINTF: + val = simplify_builtin_sprintf (arglist, ignore); + break; + case BUILT_IN_CONSTANT_P: + val = fold_builtin_constant_p (arglist); + /* Gimplification will pull the CALL_EXPR for the builtin out of + an if condition. When not optimizing, we'll not CSE it back. + To avoid link error types of regressions, return false now. */ + if (!val && !optimize) + val = integer_zero_node; + break; + default: + val = NULL_TREE; + break; + } + + if (val) + val = convert (TREE_TYPE (exp), val); + return val; +} + +/* Simplify a call to the strstr builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strstr (tree arglist) +{ + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else + { + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree fn; + const char *p1, *p2; + + p2 = c_getstr (s2); + if (p2 == NULL) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + const char *r = strstr (p1, p2); + + /* Return an offset into the constant string argument. */ + if (r == NULL) + return integer_zero_node; + else + return fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))); + } + + if (p2[0] == '\0') + return s1; + + if (p2[1] != '\0') + return 0; + + fn = implicit_built_in_decls[BUILT_IN_STRCHR]; + if (!fn) + return 0; + + /* New argument list transforming strstr(s1, s2) to + strchr(s1, s2[0]). */ + arglist = build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = tree_cons (NULL_TREE, s1, arglist); + return build_function_call_expr (fn, arglist); + } +} + +/* Simplify a call to the strstr builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strchr (tree arglist) +{ + if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else + { + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + const char *p1; + + if (TREE_CODE (s2) != INTEGER_CST) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + char c; + const char *r; + + if (target_char_cast (s2, &c)) + return 0; + + r = strchr (p1, c); + + if (r == NULL) + return integer_zero_node; + + /* Return an offset into the constant string argument. */ + return fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))); + } + + /* FIXME: Should use here strchrM optab so that ports can optimize + this. */ + return 0; + } +} + +/* Simplify a call to the strrchr builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strrchr (tree arglist) +{ + if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else + { + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree fn; + const char *p1; + + if (TREE_CODE (s2) != INTEGER_CST) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + char c; + const char *r; + + if (target_char_cast (s2, &c)) + return 0; + + r = strrchr (p1, c); + + if (r == NULL) + return integer_zero_node; + + /* Return an offset into the constant string argument. */ + return fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))); + } + + if (! integer_zerop (s2)) + return 0; + + fn = implicit_built_in_decls[BUILT_IN_STRCHR]; + if (!fn) + return 0; + + /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */ + return build_function_call_expr (fn, arglist); + } +} + +/* Simplify a call to the strpbrk builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strpbrk (tree arglist) +{ + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else + { + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + tree fn; + const char *p1, *p2; + + p2 = c_getstr (s2); + if (p2 == NULL) + return 0; + + p1 = c_getstr (s1); + if (p1 != NULL) + { + const char *r = strpbrk (p1, p2); + + if (r == NULL) + return integer_zero_node; + + /* Return an offset into the constant string argument. */ + return fold (build (PLUS_EXPR, TREE_TYPE (s1), + s1, convert (TREE_TYPE (s1), + ssize_int (r - p1)))); + } + + if (p2[0] == '\0') + { + /* strpbrk(x, "") == NULL. + Evaluate and ignore the arguments in case they had + side-effects. */ + return build (COMPOUND_EXPR, integer_type_node, s1, + integer_zero_node); + } + + if (p2[1] != '\0') + return 0; /* Really call strpbrk. */ + + fn = implicit_built_in_decls[BUILT_IN_STRCHR]; + if (!fn) + return 0; + + /* New argument list transforming strpbrk(s1, s2) to + strchr(s1, s2[0]). */ + arglist = + build_tree_list (NULL_TREE, build_int_2 (p2[0], 0)); + arglist = tree_cons (NULL_TREE, s1, arglist); + return build_function_call_expr (fn, arglist); + } +} + +/* Simplify a call to the strcpy builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +tree +simplify_builtin_strcpy (tree arglist, tree len) +{ + tree fn; + + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; + + if (!len) + { + len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1); + if (!len) + return 0; + if (TREE_SIDE_EFFECTS (len)) + return 0; + } + + len = size_binop (PLUS_EXPR, len, ssize_int (1)); + chainon (arglist, build_tree_list (NULL_TREE, len)); + return build_function_call_expr (fn, arglist); +} + +/* Simplify a call to the strncpy builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +tree +simplify_builtin_strncpy (tree arglist, tree slen) +{ + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else + { + tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + tree fn; + + /* We must be passed a constant len parameter. */ + if (TREE_CODE (len) != INTEGER_CST) + return 0; + + /* If the len parameter is zero, return the dst parameter. */ + if (integer_zerop (len)) + { + /* Evaluate and ignore the src argument in case it has + side-effects and return the dst parameter. */ + return build (COMPOUND_EXPR, TREE_TYPE (TREE_VALUE (arglist)), + TREE_VALUE (TREE_CHAIN (arglist)), + TREE_VALUE (arglist)); + } + + if (!slen) + slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 0); + + /* Now, we must be passed a constant src ptr parameter. */ + if (slen == 0 || TREE_CODE (slen) != INTEGER_CST) + return 0; + + slen = size_binop (PLUS_EXPR, slen, ssize_int (1)); + + /* We do not support simplification of this case, though we do + support it when expanding trees into RTL. */ + /* FIXME: generate a call to __builtin_memset. */ + if (tree_int_cst_lt (slen, len)) + return 0; + + /* OK transform into builtin memcpy. */ + fn = implicit_built_in_decls[BUILT_IN_MEMCPY]; + if (!fn) + return 0; + return build_function_call_expr (fn, arglist); + } +} + +/* Simplify a call to the memcmp builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_memcmp (tree arglist) +{ + tree arg1, arg2, len; + const char *p1, *p2; + + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + + /* If the len parameter is zero, return zero. */ + if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0) + { + /* Evaluate and ignore arg1 and arg2 in case they have + side-effects. */ + return build (COMPOUND_EXPR, integer_type_node, arg1, + build (COMPOUND_EXPR, integer_type_node, + arg2, integer_zero_node)); + } + + p1 = c_getstr (arg1); + p2 = c_getstr (arg2); + + /* If all arguments are constant, and the value of len is not greater + than the lengths of arg1 and arg2, evaluate at compile-time. */ + if (host_integerp (len, 1) && p1 && p2 + && compare_tree_int (len, strlen (p1) + 1) <= 0 + && compare_tree_int (len, strlen (p2) + 1) <= 0) + { + const int r = memcmp (p1, p2, tree_low_cst (len, 1)); + + return (r < 0 + ? integer_minus_one_node + : (r > 0 ? integer_one_node : integer_zero_node)); + } + + /* If len parameter is one, return an expression corresponding to + (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ + if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1) + { + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + tree ind1 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg1)))); + tree ind2 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg2)))); + return fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); + } + + return 0; +} + +/* Simplify a call to the strcmp builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strcmp (tree arglist) +{ + tree arg1, arg2; + const char *p1, *p2; + + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + + /* If both arguments are equal (and not volatile), return zero. */ + if (operand_equal_p (arg1, arg2, 0)) + return integer_zero_node; + + p1 = c_getstr (arg1); + p2 = c_getstr (arg2); + + if (p1 && p2) + { + const int i = strcmp (p1, p2); + return (i < 0 + ? integer_minus_one_node + : (i > 0 ? integer_one_node : integer_zero_node)); + } + + /* If either arg is "", return an expression corresponding to + (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */ + if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) + { + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + tree ind1 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg1)))); + tree ind2 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg2)))); + return fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); + } + + return 0; +} + +/* Simplify a call to the strncmp builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strncmp (tree arglist) +{ + tree arg1, arg2, arg3; + const char *p1, *p2; + + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + + /* If the len parameter is zero, return zero. */ + if (integer_zerop (arg3)) + { + /* Evaluate and ignore arg1 and arg2 in case they have + side-effects. */ + return build (COMPOUND_EXPR, integer_type_node, arg1, + build (COMPOUND_EXPR, integer_type_node, + arg2, integer_zero_node)); + } + + /* If arg1 and arg2 are equal (and not volatile), return zero. */ + if (operand_equal_p (arg1, arg2, 0)) + { + /* Evaluate and ignore arg3 in case it has side-effects. */ + return build (COMPOUND_EXPR, integer_type_node, arg3, integer_zero_node); + } + + p1 = c_getstr (arg1); + p2 = c_getstr (arg2); + + /* If all arguments are constant, evaluate at compile-time. */ + if (host_integerp (arg3, 1) && p1 && p2) + { + const int r = strncmp (p1, p2, tree_low_cst (arg3, 1)); + return (r < 0 + ? integer_minus_one_node + : (r > 0 ? integer_one_node : integer_zero_node)); + } + + /* If len == 1 or (either string parameter is "" and (len >= 1)), + return (*(const u_char*)arg1 - *(const u_char*)arg2). */ + if (host_integerp (arg3, 1) + && (tree_low_cst (arg3, 1) == 1 + || (tree_low_cst (arg3, 1) > 1 + && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))))) + { + tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0); + tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node); + tree ind1 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg1)))); + tree ind2 = + fold (build1 (CONVERT_EXPR, integer_type_node, + build1 (INDIRECT_REF, cst_uchar_node, + build1 (NOP_EXPR, cst_uchar_ptr_node, arg2)))); + return fold (build (MINUS_EXPR, integer_type_node, ind1, ind2)); + } + + return 0; +} + +/* Simplify a call to the strcat builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strcat (tree arglist) +{ + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else + { + tree dst = TREE_VALUE (arglist), + src = TREE_VALUE (TREE_CHAIN (arglist)); + const char *p = c_getstr (src); + + /* If the string length is zero, return the dst parameter. */ + if (p && *p == '\0') + return dst; + + return 0; + } +} + +/* Simplify a call to the strncat builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strncat (tree arglist) +{ + if (!validate_arglist (arglist, + POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return 0; + else + { + tree dst = TREE_VALUE (arglist); + tree src = TREE_VALUE (TREE_CHAIN (arglist)); + tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + const char *p = c_getstr (src); + + /* If the requested length is zero, or the src parameter string + length is zero, return the dst parameter. */ + if (integer_zerop (len) || (p && *p == '\0')) + return build (COMPOUND_EXPR, TREE_TYPE (dst), src, + build (COMPOUND_EXPR, integer_type_node, len, dst)); + + /* If the requested len is greater than or equal to the string + length, call strcat. */ + if (TREE_CODE (len) == INTEGER_CST && p + && compare_tree_int (len, strlen (p)) >= 0) + { + tree newarglist + = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src)); + tree fn = implicit_built_in_decls[BUILT_IN_STRCAT]; + + /* If the replacement _DECL isn't initialized, don't do the + transformation. */ + if (!fn) + return 0; + + return build_function_call_expr (fn, newarglist); + } + return 0; + } +} + +/* Simplify a call to the strspn builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strspn (tree arglist) +{ + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else + { + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); + + /* If both arguments are constants, evaluate at compile-time. */ + if (p1 && p2) + { + const size_t r = strspn (p1, p2); + return size_int (r); + } + + /* If either argument is "", return 0. */ + if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')) + { + /* Evaluate and ignore both arguments in case either one has + side-effects. */ + return build (COMPOUND_EXPR, integer_type_node, s1, + build (COMPOUND_EXPR, integer_type_node, + s2, integer_zero_node)); + } + return 0; + } +} + +/* Simplify a call to the strcspn builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. */ + +static tree +simplify_builtin_strcspn (tree arglist) +{ + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + else + { + tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist)); + const char *p1 = c_getstr (s1), *p2 = c_getstr (s2); + + /* If both arguments are constants, evaluate at compile-time. */ + if (p1 && p2) + { + const size_t r = strcspn (p1, p2); + return size_int (r); + } + + /* If the first argument is "", return 0. */ + if (p1 && *p1 == '\0') + { + /* Evaluate and ignore argument s2 in case it has + side-effects. */ + return build (COMPOUND_EXPR, integer_type_node, + s2, integer_zero_node); + } + + /* If the second argument is "", return __builtin_strlen(s1). */ + if (p2 && *p2 == '\0') + { + tree newarglist = build_tree_list (NULL_TREE, s1), + fn = implicit_built_in_decls[BUILT_IN_STRLEN]; + + /* If the replacement _DECL isn't initialized, don't do the + transformation. */ + if (!fn) + return 0; + + return build_function_call_expr (fn, newarglist); + } + return 0; + } +} + +/* Simplify a call to the fputs builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. + + The simplified form may be a constant or other expression which + computes the same value, but in a more efficient manner (including + calls to other builtin functions). + + The call may contain arguments which need to be evaluated, but + which are not useful to determine the result of the call. In + this case we return a chain of COMPOUND_EXPRs. The LHS of each + COMPOUND_EXPR will be an argument which must be evaluated. + COMPOUND_EXPRs are chained through their RHS. The RHS of the last + COMPOUND_EXPR in the chain will contain the tree for the simplified + form of the builtin function call. + + If KNOWN_LEN is non-NULL, it represents the known length of the string. + This is determined by SSA-CCP in cases where the string itself is not + known to be constant but its length is always the same constant. */ + +tree +simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len) +{ + tree len, fn; + tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_FPUTC]; + tree fn_fwrite = unlocked ? implicit_built_in_decls[BUILT_IN_FWRITE_UNLOCKED] + : implicit_built_in_decls[BUILT_IN_FWRITE]; + + /* If the return value is used, or the replacement _DECL isn't + initialized, don't do the transformation. */ + if (!ignore || !fn_fputc || !fn_fwrite) + return 0; + + /* Verify the arguments in the original call. */ + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return 0; + + len = (known_len) ? known_len : c_strlen (TREE_VALUE (arglist), 0); + + /* Get the length of the string passed to fputs. If the length + can't be determined, punt. */ + if (!len + || TREE_CODE (len) != INTEGER_CST) + return 0; + + switch (compare_tree_int (len, 1)) + { + case -1: /* length is 0, delete the call entirely . */ + { + return build (COMPOUND_EXPR, integer_type_node, + TREE_VALUE (TREE_CHAIN (arglist)), integer_zero_node); + } + case 0: /* length is 1, call fputc. */ + { + const char *p = c_getstr (TREE_VALUE (arglist)); + + if (p != NULL) + { + /* New argument list transforming fputs(string, stream) to + fputc(string[0], stream). */ + arglist = + build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist))); + arglist = + tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist); + fn = fn_fputc; + break; + } + } + /* FALLTHROUGH */ + case 1: /* length is greater than 1, call fwrite. */ + { + tree string_arg; + + /* If optimizing for size keep fputs. */ + if (optimize_size) + return 0; + string_arg = TREE_VALUE (arglist); + /* New argument list transforming fputs(string, stream) to + fwrite(string, 1, len, stream). */ + arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist))); + arglist = tree_cons (NULL_TREE, len, arglist); + arglist = tree_cons (NULL_TREE, size_one_node, arglist); + arglist = tree_cons (NULL_TREE, string_arg, arglist); + fn = fn_fwrite; + break; + } + default: + abort (); + } + + return build_function_call_expr (fn, arglist); +} + +static void +simplify_builtin_va_start (tree arglist) +{ + tree chain = TREE_CHAIN (arglist); + + if (TREE_CHAIN (chain)) + error ("too many arguments to function `va_start'"); + + simplify_builtin_next_arg (chain); +} + +static void +simplify_builtin_next_arg (tree arglist) +{ + 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 ("`va_start' used in function with fixed args"); + else if (arglist) + { + tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl)); + tree arg = TREE_VALUE (arglist); + + /* Strip off all nops for the sake of the comparison. This + is not quite the same as STRIP_NOPS. It does more. + We must also strip off INDIRECT_EXPR for C++ reference + parameters. */ + while (TREE_CODE (arg) == NOP_EXPR + || TREE_CODE (arg) == CONVERT_EXPR + || TREE_CODE (arg) == NON_LVALUE_EXPR + || TREE_CODE (arg) == INDIRECT_REF) + arg = TREE_OPERAND (arg, 0); + if (arg != last_parm) + warning ("second parameter of `va_start' not last named argument"); + TREE_VALUE (arglist) = arg; + } + else + /* Evidently an out of date version of ; can't validate + va_start's second argument, but can still work as intended. */ + warning ("`__builtin_next_arg' called without an argument"); +} + + +/* Simplify a call to the sprintf builtin. + + Return 0 if no simplification was possible, otherwise return the + simplified form of the call as a tree. If IGNORED is true, it means that + the caller does not use the returned value of the function. */ + +static tree +simplify_builtin_sprintf (tree arglist, int ignored) +{ + tree call, retval, dest, fmt; + const char *fmt_str = NULL; + + /* Verify the required arguments in the original call. We deal with two + types of sprintf() calls: 'sprintf (str, fmt)' and + 'sprintf (dest, "%s", orig)'. */ + if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE) + && !validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, POINTER_TYPE, + VOID_TYPE)) + return NULL_TREE; + + /* Get the destination string and the format specifier. */ + dest = TREE_VALUE (arglist); + fmt = TREE_VALUE (TREE_CHAIN (arglist)); + + /* Check whether the format is a literal string constant. */ + fmt_str = c_getstr (fmt); + if (fmt_str == NULL) + return NULL_TREE; + + call = NULL_TREE; + retval = NULL_TREE; + + /* If the format doesn't contain % args or %%, use strcpy. */ + if (strchr (fmt_str, '%') == NULL) + { + tree fn = implicit_built_in_decls[BUILT_IN_STRCPY]; + + if (!fn) + return NULL_TREE; + + /* Convert sprintf (str, fmt) into strcpy (str, fmt) when + 'format' is known to contain no % formats. */ + arglist = build_tree_list (NULL_TREE, fmt); + arglist = tree_cons (NULL_TREE, dest, arglist); + call = build_function_call_expr (fn, arglist); + if (!ignored) + retval = build_int_2 (strlen (fmt_str), 0); + } + + /* If the format is "%s", use strcpy if the result isn't used. */ + else if (fmt_str && strcmp (fmt_str, "%s") == 0) + { + tree fn, orig; + fn = implicit_built_in_decls[BUILT_IN_STRCPY]; + + if (!fn) + return NULL_TREE; + + /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2). */ + orig = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + arglist = build_tree_list (NULL_TREE, orig); + arglist = tree_cons (NULL_TREE, dest, arglist); + if (!ignored) + { + retval = c_strlen (orig, 1); + if (!retval || TREE_CODE (retval) != INTEGER_CST) + return NULL_TREE; + } + call = build_function_call_expr (fn, arglist); + } + + if (call && retval) + { + retval = convert + (TREE_TYPE (TREE_TYPE (implicit_built_in_decls[BUILT_IN_SPRINTF])), + retval); + return build (COMPOUND_EXPR, TREE_TYPE (retval), call, retval); + } + else + return call; +} diff --git a/gcc/builtins.def b/gcc/builtins.def index 297d9eed738..f52b128d2e5 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -593,6 +593,9 @@ DEF_GCC_BUILTIN (BUILT_IN_RETURN, "return", BT_FN_VOID_PTR, ATTR_NORETURN DEF_GCC_BUILTIN (BUILT_IN_RETURN_ADDRESS, "return_address", BT_FN_PTR_UNSIGNED, ATTR_NULL) DEF_GCC_BUILTIN (BUILT_IN_SAVEREGS, "saveregs", BT_FN_PTR_VAR, ATTR_NULL) DEF_GCC_BUILTIN (BUILT_IN_SETJMP, "setjmp", BT_FN_INT_PTR, ATTR_NULL) +DEF_GCC_BUILTIN (BUILT_IN_STACK_ALLOC, "stack_alloc", BT_FN_VOID_PTR_SIZE, ATTR_NULL) +DEF_GCC_BUILTIN (BUILT_IN_STACK_SAVE, "stack_save", BT_FN_PTR, ATTR_NULL) +DEF_GCC_BUILTIN (BUILT_IN_STACK_RESTORE, "stack_restore", BT_FN_VOID_PTR, ATTR_NULL) DEF_GCC_BUILTIN (BUILT_IN_STDARG_START, "stdarg_start", BT_FN_VOID_VALIST_REF_VAR, ATTR_NULL) DEF_EXT_LIB_BUILTIN (BUILT_IN_STRFMON, "strfmon", BT_FN_SSIZE_STRING_SIZE_CONST_STRING_VAR, ATTR_FORMAT_STRFMON_3_4) DEF_LIB_BUILTIN (BUILT_IN_STRFTIME, "strftime", BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_PTR, ATTR_FORMAT_STRFTIME_3_0) @@ -604,3 +607,12 @@ DEF_GCC_BUILTIN (BUILT_IN_VA_END, "va_end", BT_FN_VOID_VALIST_REF, ATTR_N DEF_GCC_BUILTIN (BUILT_IN_VA_START, "va_start", BT_FN_VOID_VALIST_REF_VAR, ATTR_NULL) DEF_EXT_LIB_BUILTIN (BUILT_IN__EXIT, "_exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST) DEF_C99_BUILTIN (BUILT_IN__EXIT2, "_Exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST) +DEF_GCC_BUILTIN (BUILT_IN_INIT_TRAMPOLINE, "init_trampoline", BT_FN_VOID_PTR_PTR_PTR, ATTR_NOTHROW_LIST) +DEF_GCC_BUILTIN (BUILT_IN_ADJUST_TRAMPOLINE, "adjust_trampoline", BT_FN_PTR_PTR, ATTR_CONST_NOTHROW_LIST) +DEF_GCC_BUILTIN (BUILT_IN_NONLOCAL_GOTO, "nonlocal_goto", BT_FN_PTR_PTR, ATTR_NORETURN_NOTHROW_LIST) + +/* Profiling hooks. */ +DEF_GCC_BUILTIN (BUILT_IN_PROFILE_FUNC_ENTER, "profile_func_enter", + BT_FN_VOID, ATTR_NULL) +DEF_GCC_BUILTIN (BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit", + BT_FN_VOID, ATTR_NULL) diff --git a/gcc/c-common.c b/gcc/c-common.c index 15d7e686841..9b7206a94c7 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -42,6 +42,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree-inline.h" #include "c-tree.h" #include "toplev.h" +#include "tree-iterator.h" +#include "hashtab.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -681,6 +683,15 @@ tree *ridpointers; tree (*make_fname_decl) (tree, int); +/* If non-NULL, the address of a language-specific function that + returns 1 for language-specific statement codes. */ +int (*lang_statement_code_p) (enum tree_code); + +/* If non-NULL, the address of a language-specific function that does any + language-specific gimplification for _STMT nodes and returns 1 iff + handled. */ +int (*lang_gimplify_stmt) (tree *, tree *); + /* If non-NULL, the address of a language-specific function that takes any action required right before expand_function_end is called. */ void (*lang_expand_function_end) (void); @@ -918,7 +929,7 @@ c_expand_end_cond (void) if_stack_pointer--; if (if_stack[if_stack_pointer].needs_warning) warning ("%Hsuggest explicit braces to avoid ambiguous `else'", - &if_stack[if_stack_pointer].locus); + &if_stack[if_stack_pointer].locus); last_expr_type = NULL_TREE; } @@ -1183,6 +1194,7 @@ fix_string_type (tree value) build_index_type (build_int_2 (nchars - 1, 0))); TREE_CONSTANT (value) = 1; + TREE_INVARIANT (value) = 1; TREE_READONLY (value) = 1; TREE_STATIC (value) = 1; return value; @@ -1315,7 +1327,7 @@ convert_and_check (tree type, tree expr) || TYPE_UNSIGNED (type) || ! constant_fits_type_p (expr, c_common_unsigned_type (type))) - && skip_evaluation == 0) + && skip_evaluation == 0) warning ("overflow in implicit constant conversion"); } else @@ -1851,7 +1863,7 @@ c_common_type_for_mode (enum machine_mode mode, int unsignedp) if (mode == TYPE_MODE (widest_integer_literal_type_node)) return unsignedp ? widest_unsigned_literal_type_node - : widest_integer_literal_type_node; + : widest_integer_literal_type_node; if (mode == QImode) return unsignedp ? unsigned_intQI_type_node : intQI_type_node; @@ -2473,9 +2485,6 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) { tree size_exp; - tree result; - tree folded; - /* The result is a pointer of the same type that is being added. */ tree result_type = TREE_TYPE (ptrop); @@ -2549,13 +2558,7 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) convert (TREE_TYPE (intop), size_exp), 1)); /* Create the sum or difference. */ - - result = build (resultcode, result_type, ptrop, intop); - - folded = fold (result); - if (folded == result) - TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop); - return folded; + return fold (build (resultcode, result_type, ptrop, intop)); } /* Prepare expr to be an argument of a TRUTH_NOT_EXPR, @@ -2796,6 +2799,49 @@ c_apply_type_quals_to_decl (int type_quals, tree decl) } } +/* Hash function for the problem of multiple type definitions in + different files. This must hash all types that will compare + equal via comptypes to the same value. In practice it hashes + on some of the simple stuff and leaves the details to comptypes. */ + +static hashval_t +c_type_hash (const void *p) +{ + int i = 0; + int shift, size; + tree t = (tree)p; + tree t2; + switch (TREE_CODE (t)) + { + /* For pointers, hash on pointee type plus some swizzling. */ + case POINTER_TYPE: + return c_type_hash (TREE_TYPE (t)) ^ 0x3003003; + /* Hash on number of elements and total size. */ + case ENUMERAL_TYPE: + shift = 3; + t2 = TYPE_VALUES (t); + break; + case RECORD_TYPE: + shift = 0; + t2 = TYPE_FIELDS (t); + break; + case QUAL_UNION_TYPE: + shift = 1; + t2 = TYPE_FIELDS (t); + break; + case UNION_TYPE: + shift = 2; + t2 = TYPE_FIELDS (t); + break; + default: + abort (); + } + for (; t2; t2 = TREE_CHAIN (t2)) + i++; + size = TREE_INT_CST_LOW (TYPE_SIZE (t)); + return ((size << 24) | (i << shift)); +} + /* Return the typed-based alias set for T, which may be an expression or a type. Return -1 if we don't do anything special. */ @@ -2803,6 +2849,8 @@ HOST_WIDE_INT c_common_get_alias_set (tree t) { tree u; + PTR *slot; + static htab_t type_hash_table; /* Permit type-punning when accessing a union, provided the access is directly through the union. For example, this code does not @@ -2859,14 +2907,14 @@ c_common_get_alias_set (tree t) technically, an `int **' and `const int **' cannot point at the same thing. - But, the standard is wrong. In particular, this code is + But, the standard is wrong. In particular, this code is legal C++: int *ip; int **ipp = &ip; const int* const* cipp = ipp; - And, it doesn't make sense for that to be legal unless you + And, it doesn't make sense for that to be legal unless you can dereference IPP and CIPP. So, we ignore cv-qualifiers on the pointed-to types. This issue has been reported to the C++ committee. */ @@ -2875,6 +2923,63 @@ c_common_get_alias_set (tree t) return get_alias_set (t1); } + /* Handle the case of multiple type nodes referring to "the same" type, + which occurs with IMA. These share an alias set. FIXME: Currently only + C90 is handled. (In C99 type compatibility is not transitive, which + complicates things mightily. The alias set splay trees can theoretically + represent this, but insertion is tricky when you consider all the + different orders things might arrive in.) */ + + if (c_language != clk_c || flag_isoc99) + return -1; + + /* Save time if there's only one input file. */ + if (!current_file_decl || TREE_CHAIN (current_file_decl) == NULL_TREE) + return -1; + + /* Pointers need special handling if they point to any type that + needs special handling (below). */ + if (TREE_CODE (t) == POINTER_TYPE) + { + tree t2; + /* Find bottom type under any nested POINTERs. */ + for (t2 = TREE_TYPE (t); + TREE_CODE (t2) == POINTER_TYPE; + t2 = TREE_TYPE (t2)) + ; + if (TREE_CODE (t2) != RECORD_TYPE + && TREE_CODE (t2) != ENUMERAL_TYPE + && TREE_CODE (t2) != QUAL_UNION_TYPE + && TREE_CODE (t2) != UNION_TYPE) + return -1; + if (TYPE_SIZE (t2) == 0) + return -1; + } + /* These are the only cases that need special handling. */ + if (TREE_CODE (t) != RECORD_TYPE + && TREE_CODE (t) != ENUMERAL_TYPE + && TREE_CODE (t) != QUAL_UNION_TYPE + && TREE_CODE (t) != UNION_TYPE + && TREE_CODE (t) != POINTER_TYPE) + return -1; + /* Undefined? */ + if (TYPE_SIZE (t) == 0) + return -1; + + /* Look up t in hash table. Only one of the compatible types within each + alias set is recorded in the table. */ + if (!type_hash_table) + type_hash_table = htab_create (1021, c_type_hash, + (htab_eq) lang_hooks.types_compatible_p, + NULL); + slot = htab_find_slot (type_hash_table, t, INSERT); + if (*slot != NULL) + return TYPE_ALIAS_SET ((tree)*slot); + else + /* Our caller will assign and record (in t) a new alias set; all we need + to do is remember t in the hash table. */ + *slot = t; + return -1; } @@ -3413,7 +3518,7 @@ c_common_nodes_and_builtins (void) \ built_in_decls[(int) ENUM] = decl; \ if (IMPLICIT) \ - implicit_built_in_decls[(int) ENUM] = decl; \ + implicit_built_in_decls[(int) ENUM] = decl; \ } #include "builtins.def" #undef DEF_BUILTIN @@ -3843,19 +3948,12 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value, splay_tree_node node; /* Create the LABEL_DECL itself. */ - label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); - DECL_CONTEXT (label) = current_function_decl; + label = create_artificial_label (); /* If there was an error processing the switch condition, bail now before we get more confused. */ if (!cond || cond == error_mark_node) - { - /* Add a label anyhow so that the back-end doesn't think that - the beginning of the switch is unreachable. */ - if (!cases->root) - add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); - return error_mark_node; - } + goto error_out; if ((low_value && TREE_TYPE (low_value) && POINTER_TYPE_P (TREE_TYPE (low_value))) @@ -3881,11 +3979,7 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value, /* If an error has occurred, bail out now. */ if (low_value == error_mark_node || high_value == error_mark_node) - { - if (!cases->root) - add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); - return error_mark_node; - } + goto error_out; /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't really a case range, even though it was written that way. Remove @@ -3958,8 +4052,7 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value, error ("multiple default labels in one switch"); error ("%Jthis is the first default label", duplicate); } - if (!cases->root) - add_stmt (build_case_label (NULL_TREE, NULL_TREE, label)); + goto error_out; } /* Add a CASE_LABEL to the statement-tree. */ @@ -3970,6 +4063,160 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value, (splay_tree_value) case_label); return case_label; + + error_out: + /* Add a label so that the back-end doesn't think that the beginning o + the switch is unreachable. Note that we do not add a case label, as + that just leads to duplicates and thence to aborts later on. */ + if (!cases->root) + { + tree t = create_artificial_label (); + add_stmt (build_stmt (LABEL_STMT, t)); + } + return error_mark_node; +} + +/* Subroutines of c_do_switch_warnings, called via splay_tree_foreach. + Used to verify that case values match up with enumerator values. */ + +static void +match_case_to_enum_1 (tree key, tree type, tree label) +{ + char buf[2 + 2*HOST_BITS_PER_WIDE_INT/4 + 1]; + + /* ??? Not working too hard to print the double-word value. + Should perhaps be done with %lwd in the diagnostic routines? */ + if (TREE_INT_CST_HIGH (key) == 0) + snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_UNSIGNED, + TREE_INT_CST_LOW (key)); + else if (!TYPE_UNSIGNED (type) + && TREE_INT_CST_HIGH (key) == -1 + && TREE_INT_CST_LOW (key) != 0) + snprintf (buf, sizeof (buf), "-" HOST_WIDE_INT_PRINT_UNSIGNED, + -TREE_INT_CST_LOW (key)); + else + snprintf (buf, sizeof (buf), HOST_WIDE_INT_PRINT_DOUBLE_HEX, + TREE_INT_CST_HIGH (key), TREE_INT_CST_LOW (key)); + + if (TYPE_NAME (type) == 0) + warning ("%Jcase value `%s' not in enumerated type", + CASE_LABEL_DECL (label), buf); + else + warning ("%Jcase value `%s' not in enumerated type `%T'", + CASE_LABEL_DECL (label), buf, type); +} + +static int +match_case_to_enum (splay_tree_node node, void *data) +{ + tree label = (tree) node->value; + tree type = data; + + /* Skip default case. */ + if (!CASE_LOW (label)) + return 0; + + /* If TREE_ADDRESSABLE is not set, that means CASE_LOW did not appear + when we did our enum->case scan. Reset our scratch bit after. */ + if (!TREE_ADDRESSABLE (label)) + match_case_to_enum_1 (CASE_LOW (label), type, label); + else + TREE_ADDRESSABLE (label) = 0; + + /* If CASE_HIGH is non-null, we have a range. Here we must search. + Note that the old code in stmt.c did not check for the values in + the range either, just the endpoints. */ + if (CASE_HIGH (label)) + { + tree chain, key = CASE_HIGH (label); + + for (chain = TYPE_VALUES (type); + chain && !tree_int_cst_equal (key, TREE_VALUE (chain)); + chain = TREE_CHAIN (chain)) + continue; + if (!chain) + match_case_to_enum_1 (key, type, label); + } + + return 0; +} + +/* Handle -Wswitch*. Called from the front end after parsing the switch + construct. */ +/* ??? Should probably be somewhere generic, since other languages besides + C and C++ would want this. We'd want to agree on the datastructure, + however, which is a problem. Alternately, we operate on gimplified + switch_exprs, which I don't especially like. At the moment, however, + C/C++ are the only tree-ssa languages that support enumerations at all, + so the point is moot. */ + +void +c_do_switch_warnings (splay_tree cases, tree switch_stmt) +{ + splay_tree_node default_node; + location_t *switch_locus; + tree type; + + if (!warn_switch && !warn_switch_enum && !warn_switch_default) + return; + + switch_locus = EXPR_LOCUS (switch_stmt); + if (!switch_locus) + switch_locus = &input_location; + type = SWITCH_TYPE (switch_stmt); + + default_node = splay_tree_lookup (cases, (splay_tree_key) NULL); + if (warn_switch_default && !default_node) + warning ("%Hswitch missing default case", switch_locus); + + /* If the switch expression was an enumerated type, check that + exactly all enumeration literals are covered by the cases. + The check is made when -Wswitch was specified and there is no + default case, or when -Wswitch-enum was specified. */ + if (((warn_switch && !default_node) || warn_switch_enum) + && type && TREE_CODE (type) == ENUMERAL_TYPE + && TREE_CODE (SWITCH_COND (switch_stmt)) != INTEGER_CST) + { + tree chain; + + /* The time complexity here is O(N*lg(N)) worst case, but for the + common case of monotonically increasing enumerators, it is + O(N), since the nature of the splay tree will keep the next + element adjacent to the root at all times. */ + + for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain)) + { + splay_tree_node node + = splay_tree_lookup (cases, (splay_tree_key) TREE_VALUE (chain)); + + if (node) + { + /* Mark the CASE_LOW part of the case entry as seen, so + that we save time later. Choose TREE_ADDRESSABLE + randomly as a bit that won't have been set to-date. */ + tree label = (tree) node->value; + TREE_ADDRESSABLE (label) = 1; + } + else + { + /* Warn if there are enumerators that don't correspond to + case expressions. */ + warning ("%Henumeration value `%E' not handled in switch", + switch_locus, TREE_PURPOSE (chain)); + } + } + + /* Warn if there are case expressions that don't correspond to + enumerators. This can occur since C and C++ don't enforce + type-checking of assignments to enumeration variables. + + The time complexity here is O(N**2) worst case, since we've + not sorted the enumeration values. However, in the absence + of case ranges this is O(N), since all single cases that + corresponded to enumerations have been marked above. */ + + splay_tree_foreach (cases, match_case_to_enum, type); + } } /* Finish an expression taking the address of LABEL (an @@ -3993,7 +4240,6 @@ finish_label_address_expr (tree label) { TREE_USED (label) = 1; result = build1 (ADDR_EXPR, ptr_type_node, label); - TREE_CONSTANT (result) = 1; /* The current function in not necessarily uninlinable. Computed gotos are incompatible with inlining, but the value here could be used only in a diagnostic, for example. */ @@ -4003,6 +4249,9 @@ finish_label_address_expr (tree label) } /* Hook used by expand_expr to expand language-specific tree codes. */ +/* The only things that should go here are bits needed to expand + constant initalizers. Everything else should be handled by the + gimplification routines. */ rtx c_expand_expr (tree exp, rtx target, enum machine_mode tmode, @@ -4011,88 +4260,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode, { switch (TREE_CODE (exp)) { - case STMT_EXPR: - { - tree rtl_expr; - rtx result; - bool preserve_result = false; - - if (STMT_EXPR_WARN_UNUSED_RESULT (exp) && target == const0_rtx) - { - tree stmt = STMT_EXPR_STMT (exp); - tree scope; - - for (scope = COMPOUND_BODY (stmt); - scope && TREE_CODE (scope) != SCOPE_STMT; - scope = TREE_CHAIN (scope)); - - if (scope && SCOPE_STMT_BLOCK (scope)) - warning ("%Hignoring return value of `%D', " - "declared with attribute warn_unused_result", - &expr_wfl_stack->location, - BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope))); - else - warning ("%Hignoring return value of function " - "declared with attribute warn_unused_result", - &expr_wfl_stack->location); - } - - /* Since expand_expr_stmt calls free_temp_slots after every - expression statement, we must call push_temp_slots here. - Otherwise, any temporaries in use now would be considered - out-of-scope after the first EXPR_STMT from within the - STMT_EXPR. */ - push_temp_slots (); - rtl_expr = expand_start_stmt_expr (!STMT_EXPR_NO_SCOPE (exp)); - - /* If we want the result of this expression, find the last - EXPR_STMT in the COMPOUND_STMT and mark it as addressable. */ - if (target != const0_rtx - && TREE_CODE (STMT_EXPR_STMT (exp)) == COMPOUND_STMT - && TREE_CODE (COMPOUND_BODY (STMT_EXPR_STMT (exp))) == SCOPE_STMT) - { - tree expr = COMPOUND_BODY (STMT_EXPR_STMT (exp)); - tree last = TREE_CHAIN (expr); - - while (TREE_CHAIN (last)) - { - expr = last; - last = TREE_CHAIN (last); - } - - if (TREE_CODE (last) == SCOPE_STMT - && TREE_CODE (expr) == EXPR_STMT) - { - /* Otherwise, note that we want the value from the last - expression. */ - TREE_ADDRESSABLE (expr) = 1; - preserve_result = true; - } - } - - expand_stmt (STMT_EXPR_STMT (exp)); - expand_end_stmt_expr (rtl_expr); - - result = expand_expr_real (rtl_expr, target, tmode, modifier, alt_rtl); - if (preserve_result && GET_CODE (result) == MEM) - { - if (GET_MODE (result) != BLKmode) - result = copy_to_reg (result); - else - preserve_temp_slots (result); - } - - /* If the statment-expression does not have a scope, then the - new temporaries we created within it must live beyond the - statement-expression. */ - if (STMT_EXPR_NO_SCOPE (exp)) - preserve_temp_slots (NULL_RTX); - - pop_temp_slots (); - return result; - } - break; - case COMPOUND_LITERAL_EXPR: { /* Initialize the anonymous variable declared in the compound @@ -4105,9 +4272,6 @@ c_expand_expr (tree exp, rtx target, enum machine_mode tmode, default: abort (); } - - abort (); - return NULL; } /* Hook used by safe_from_p to handle language-specific tree codes. */ @@ -4684,7 +4848,7 @@ handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, && ! TREE_STATIC (decl)) { error ("%Jsection attribute cannot be specified for " - "local variables", decl); + "local variables", decl); *no_add_attrs = true; } @@ -4695,7 +4859,7 @@ handle_section_attribute (tree *node, tree name ATTRIBUTE_UNUSED, tree args, TREE_STRING_POINTER (TREE_VALUE (args))) != 0) { error ("%Jsection of '%D' conflicts with previous declaration", - *node, *node); + *node, *node); *no_add_attrs = true; } else @@ -4848,7 +5012,10 @@ handle_alias_attribute (tree *node, tree name, tree args, if (TREE_CODE (decl) == FUNCTION_DECL) DECL_INITIAL (decl) = error_mark_node; else - DECL_EXTERNAL (decl) = 0; + { + DECL_EXTERNAL (decl) = 0; + TREE_STATIC (decl) = 1; + } } else { @@ -5191,7 +5358,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED, if (! TYPE_ARG_TYPES (type)) { error ("nonnull attribute without arguments on a non-prototype"); - *no_add_attrs = true; + *no_add_attrs = true; } return NULL_TREE; } @@ -5201,7 +5368,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED, for (attr_arg_num = 1; args; args = TREE_CHAIN (args)) { tree argument; - unsigned HOST_WIDE_INT arg_num, ck_num; + unsigned HOST_WIDE_INT arg_num = 0, ck_num; if (! get_nonnull_operand (TREE_VALUE (args), &arg_num)) { @@ -5221,7 +5388,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED, argument = TREE_CHAIN (argument); } - if (! argument + if (! argument || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE) { error ("nonnull argument with out-of-range operand number (arg %lu, operand %lu)", @@ -5230,7 +5397,7 @@ handle_nonnull_attribute (tree *node, tree name ATTRIBUTE_UNUSED, return NULL_TREE; } - if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) + if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE) { error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)", (unsigned long) attr_arg_num, (unsigned long) arg_num); @@ -5256,22 +5423,22 @@ check_function_nonnull (tree attrs, tree params) { if (is_attribute_p ("nonnull", TREE_PURPOSE (a))) { - args = TREE_VALUE (a); + args = TREE_VALUE (a); - /* Walk the argument list. If we encounter an argument number we - should check for non-null, do it. If the attribute has no args, - then every pointer argument is checked (in which case the check + /* Walk the argument list. If we encounter an argument number we + should check for non-null, do it. If the attribute has no args, + then every pointer argument is checked (in which case the check for pointer type is done in check_nonnull_arg). */ - for (param = params, param_num = 1; ; - param_num++, param = TREE_CHAIN (param)) - { - if (! param) + for (param = params, param_num = 1; ; + param_num++, param = TREE_CHAIN (param)) + { + if (! param) break; - if (! args || nonnull_check_p (args, param_num)) + if (! args || nonnull_check_p (args, param_num)) check_function_arguments_recurse (check_nonnull_arg, NULL, TREE_VALUE (param), param_num); - } + } } } } @@ -5283,12 +5450,12 @@ check_function_nonnull (tree attrs, tree params) static bool nonnull_check_p (tree args, unsigned HOST_WIDE_INT param_num) { - unsigned HOST_WIDE_INT arg_num; + unsigned HOST_WIDE_INT arg_num = 0; for (; args; args = TREE_CHAIN (args)) { if (! get_nonnull_operand (TREE_VALUE (args), &arg_num)) - abort (); + abort (); if (arg_num == param_num) return true; @@ -5313,7 +5480,7 @@ check_nonnull_arg (void *ctx ATTRIBUTE_UNUSED, tree param, if (integer_zerop (param)) warning ("null argument where non-null required (arg %lu)", - (unsigned long) param_num); + (unsigned long) param_num); } /* Helper for nonnull attribute handling; fetch the operand number @@ -5447,7 +5614,7 @@ check_function_arguments_recurse (void (*callback) { /* Strip coercion. */ check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 0), param_num); + TREE_OPERAND (param, 0), param_num); return; } @@ -5509,15 +5676,74 @@ check_function_arguments_recurse (void (*callback) { /* Check both halves of the conditional expression. */ check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 1), param_num); + TREE_OPERAND (param, 1), param_num); check_function_arguments_recurse (callback, ctx, - TREE_OPERAND (param, 2), param_num); + TREE_OPERAND (param, 2), param_num); return; } (*callback) (ctx, param, param_num); } +/* C implementation of lang_hooks.tree_inlining.walk_subtrees. Tracks the + locus from EXPR_LOCUS and handles DECL_STMT specially. */ + +tree +c_walk_subtrees (tree *tp, int *walk_subtrees_p ATTRIBUTE_UNUSED, + walk_tree_fn func, void *data, void *htab) +{ + enum tree_code code = TREE_CODE (*tp); + location_t save_locus; + tree result; + +#define WALK_SUBTREE(NODE) \ + do \ + { \ + result = walk_tree (&(NODE), func, data, htab); \ + if (result) goto out; \ + } \ + while (0) + + if (code != DECL_STMT) + return NULL_TREE; + + /* Set input_location here so we get the right instantiation context + if we call instantiate_decl from inlinable_function_p. */ + save_locus = input_location; + if (EXPR_LOCUS (*tp)) + input_location = *EXPR_LOCUS (*tp); + + /* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk + into declarations that are just mentioned, rather than + declared; they don't really belong to this part of the tree. + And, we can see cycles: the initializer for a declaration can + refer to the declaration itself. */ + WALK_SUBTREE (DECL_INITIAL (DECL_STMT_DECL (*tp))); + WALK_SUBTREE (DECL_SIZE (DECL_STMT_DECL (*tp))); + WALK_SUBTREE (DECL_SIZE_UNIT (DECL_STMT_DECL (*tp))); + WALK_SUBTREE (TREE_CHAIN (*tp)); + *walk_subtrees_p = 0; + + /* We didn't find what we were looking for. */ + out: + input_location = save_locus; + return result; + +#undef WALK_SUBTREE +} + +/* C implementation of lang_hooks.tree_inlining.tree_chain_matters_p. + Apart from TREE_LISTs, the only trees whose TREE_CHAIN we care about are + _STMT nodes. */ + +int +c_tree_chain_matters_p (tree t) +{ + /* For statements, we also walk the chain so that we cover the + entire statement tree. */ + return STATEMENT_CODE_P (TREE_CODE (t)); +} + /* Function to help qsort sort FIELD_DECLs by name order. */ int @@ -5573,15 +5799,15 @@ resort_field_decl_cmp (const void *x_p, const void *y_p) void resort_sorted_fields (void *obj, - void *orig_obj ATTRIBUTE_UNUSED , - gt_pointer_operator new_value, - void *cookie) + void *orig_obj ATTRIBUTE_UNUSED , + gt_pointer_operator new_value, + void *cookie) { struct sorted_fields_type *sf = obj; resort_data.new_value = new_value; resort_data.cookie = cookie; qsort (&sf->elts[0], sf->len, sizeof (tree), - resort_field_decl_cmp); + resort_field_decl_cmp); } /* Used by estimate_num_insns. Estimate number of instructions seen @@ -5675,14 +5901,12 @@ c_estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) case EXIT_EXPR: case LABELED_BLOCK_EXPR: case EXIT_BLOCK_EXPR: - case EXPR_WITH_FILE_LOCATION: case EXPR_STMT: case COMPOUND_STMT: case RETURN_STMT: case LABEL_STMT: case SCOPE_STMT: - case FILE_STMT: case CASE_LABEL: case STMT_EXPR: case CLEANUP_STMT: @@ -5711,37 +5935,6 @@ c_estimate_num_insns (tree decl) return num; } -/* Used by c_decl_uninit to find where expressions like x = x + 1; */ - -static tree -c_decl_uninit_1 (tree *t, int *walk_sub_trees, void *x) -{ - /* If x = EXP(&x)EXP, then do not warn about the use of x. */ - if (TREE_CODE (*t) == ADDR_EXPR && TREE_OPERAND (*t, 0) == x) - { - *walk_sub_trees = 0; - return NULL_TREE; - } - if (*t == x) - return *t; - return NULL_TREE; -} - -/* Find out if a variable is uninitialized based on DECL_INITIAL. */ - -bool -c_decl_uninit (tree t) -{ - /* int x = x; is GCC extension to turn off this warning, only if warn_init_self is zero. */ - if (DECL_INITIAL (t) == t) - return warn_init_self ? true : false; - - /* Walk the trees looking for the variable itself. */ - if (walk_tree_without_duplicates (&DECL_INITIAL (t), c_decl_uninit_1, t)) - return true; - return false; -} - /* Issue the error given by MSGID, indicating that it occurred before TOKEN, which had the associated VALUE. */ @@ -5774,4 +5967,74 @@ c_parse_error (const char *msgid, enum cpp_ttype token, tree value) error ("%s", string); } +/* Walk a gimplified function and warn for functions whose return value is + ignored and attribute((warn_unused_result)) is set. This is done before + inlining, so we don't have to worry about that. */ + +void +c_warn_unused_result (tree *top_p) +{ + tree t = *top_p; + tree_stmt_iterator i; + tree fdecl, ftype; + + switch (TREE_CODE (t)) + { + case STATEMENT_LIST: + for (i = tsi_start (*top_p); !tsi_end_p (i); tsi_next (&i)) + c_warn_unused_result (tsi_stmt_ptr (i)); + break; + + case COND_EXPR: + c_warn_unused_result (&COND_EXPR_THEN (t)); + c_warn_unused_result (&COND_EXPR_ELSE (t)); + break; + case BIND_EXPR: + c_warn_unused_result (&BIND_EXPR_BODY (t)); + break; + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + c_warn_unused_result (&TREE_OPERAND (t, 0)); + c_warn_unused_result (&TREE_OPERAND (t, 1)); + break; + case CATCH_EXPR: + c_warn_unused_result (&CATCH_BODY (t)); + break; + case EH_FILTER_EXPR: + c_warn_unused_result (&EH_FILTER_FAILURE (t)); + break; + + case CALL_EXPR: + /* This is a naked call, as opposed to a CALL_EXPR nested inside + a MODIFY_EXPR. All calls whose value is ignored should be + represented like this. Look for the attribute. */ + fdecl = get_callee_fndecl (t); + if (fdecl) + ftype = TREE_TYPE (fdecl); + else + { + ftype = TREE_TYPE (TREE_OPERAND (t, 0)); + /* Look past pointer-to-function to the function type itself. */ + ftype = TREE_TYPE (ftype); + } + + if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype))) + { + if (fdecl) + warning ("%Hignoring return value of `%D', " + "declared with attribute warn_unused_result", + EXPR_LOCUS (t), fdecl); + else + warning ("%Hignoring return value of function " + "declared with attribute warn_unused_result", + EXPR_LOCUS (t)); + } + break; + + default: + /* Not a container, not a call, or a call whose value is used. */ + break; + } +} + #include "gt-c-common.h" diff --git a/gcc/c-common.def b/gcc/c-common.def index dfdec8c4df0..3282cc603e4 100644 --- a/gcc/c-common.def +++ b/gcc/c-common.def @@ -79,7 +79,7 @@ DEFTREECODE (GOTO_STMT, "goto_stmt", 'e', 1) DEFTREECODE (LABEL_STMT, "label_stmt", 'e', 1) /* Used to represent an inline assembly statement. */ -DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 5) +DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 4) /* A SCOPE_STMT marks the beginning or end of a scope. If SCOPE_BEGIN_P holds, then this is the start of a scope. If @@ -89,10 +89,6 @@ DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 5) variables declared in this scope. */ DEFTREECODE (SCOPE_STMT, "scope_stmt", 'e', 1) -/* A FILE_STMT marks the spot where a function changes files. It has no - other semantics. FILE_STMT_FILENAME gives the name. */ -DEFTREECODE (FILE_STMT, "file_stmt", 'e', 1) - /* Used to represent a CASE_LABEL. The operands are CASE_LOW and CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a 'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case diff --git a/gcc/c-common.h b/gcc/c-common.h index 7a0a6e6ad39..74999104428 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -37,10 +37,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA STMT_EXPR_NO_SCOPE (in STMT_EXPR) 1: C_DECLARED_LABEL_FLAG (in LABEL_DECL) STMT_IS_FULL_EXPR_P (in _STMT) - 2: STMT_LINENO_FOR_FN_P (in _STMT) + 2: unused 3: SCOPE_NO_CLEANUPS_P (in SCOPE_STMT) COMPOUND_STMT_BODY_BLOCK (in COMPOUND_STMT) - STMT_EXPR_WARN_UNUSED_RESULT (in STMT_EXPR) 4: SCOPE_PARTIAL_P (in SCOPE_STMT) */ @@ -321,8 +320,7 @@ struct c_language_function GTY(()) { /* Language-specific hooks. */ -extern void (*lang_expand_stmt) (tree); -extern void (*lang_expand_decl_stmt) (tree); +extern int (*lang_gimplify_stmt) (tree *, tree *); extern void (*lang_expand_function_end) (void); /* Callback that determines if it's ok for a function to have no @@ -342,7 +340,6 @@ extern void finish_stmt_tree (tree *); extern tree walk_stmt_tree (tree *, walk_tree_fn, void *); extern void prep_stmt (tree); -extern void expand_stmt (tree); extern tree c_begin_if_stmt (void); extern tree c_begin_while_stmt (void); extern void c_finish_while_stmt_cond (tree, tree); @@ -999,22 +996,9 @@ extern void finish_file (void); #define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2) #define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3) -/* SWITCH_STMT accessors. These give access to the condition, body and - original condition type (before any compiler conversions) - of the switch statement, respectively. */ -#define SWITCH_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0) -#define SWITCH_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1) #define SWITCH_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2) - -/* CASE_LABEL accessors. These give access to the high and low values - of a case label, respectively. */ -#define CASE_LOW(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 0) -#define CASE_HIGH(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 1) #define CASE_LABEL_DECL(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 2) -/* GOTO_STMT accessor. This gives access to the label associated with - a goto statement. */ -#define GOTO_DESTINATION(NODE) TREE_OPERAND (GOTO_STMT_CHECK (NODE), 0) /* True for goto created artificially by the compiler. */ #define GOTO_FAKE_P(NODE) (TREE_LANG_FLAG_0 (GOTO_STMT_CHECK (NODE))) @@ -1024,16 +1008,6 @@ extern void finish_file (void); calling TREE_CHAIN on a node in the list. */ #define COMPOUND_BODY(NODE) TREE_OPERAND (COMPOUND_STMT_CHECK (NODE), 0) -/* ASM_STMT accessors. ASM_STRING returns a STRING_CST for the - instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and - ASM_CLOBBERS represent the outputs, inputs, and clobbers for the - statement. */ -#define ASM_CV_QUAL(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 0) -#define ASM_STRING(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 1) -#define ASM_OUTPUTS(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 2) -#define ASM_INPUTS(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 3) -#define ASM_CLOBBERS(NODE) TREE_OPERAND (ASM_STMT_CHECK (NODE), 4) - /* DECL_STMT accessor. This gives access to the DECL associated with the given declaration statement. */ #define DECL_STMT_DECL(NODE) TREE_OPERAND (DECL_STMT_CHECK (NODE), 0) @@ -1045,11 +1019,6 @@ extern void finish_file (void); #define STMT_EXPR_NO_SCOPE(NODE) \ TREE_LANG_FLAG_0 (STMT_EXPR_CHECK (NODE)) -/* Nonzero if this statement-expression should cause warning if its result - is not used. */ -#define STMT_EXPR_WARN_UNUSED_RESULT(NODE) \ - TREE_LANG_FLAG_3 (STMT_EXPR_CHECK (NODE)) - /* LABEL_STMT accessor. This gives access to the label associated with the given label statement. */ #define LABEL_STMT_LABEL(NODE) TREE_OPERAND (LABEL_STMT_CHECK (NODE), 0) @@ -1097,10 +1066,6 @@ extern void finish_file (void); #define SCOPE_PARTIAL_P(NODE) \ (TREE_LANG_FLAG_4 (SCOPE_STMT_CHECK (NODE))) -/* Nonzero for an ASM_STMT if the assembly statement is volatile. */ -#define ASM_VOLATILE_P(NODE) \ - (ASM_CV_QUAL (ASM_STMT_CHECK (NODE)) != NULL_TREE) - /* The VAR_DECL to clean up in a CLEANUP_STMT. */ #define CLEANUP_DECL(NODE) \ TREE_OPERAND (CLEANUP_STMT_CHECK (NODE), 0) @@ -1108,31 +1073,10 @@ extern void finish_file (void); #define CLEANUP_EXPR(NODE) \ TREE_OPERAND (CLEANUP_STMT_CHECK (NODE), 1) -/* The filename we are changing to as of this FILE_STMT. */ -#define FILE_STMT_FILENAME_NODE(NODE) \ - (TREE_OPERAND (FILE_STMT_CHECK (NODE), 0)) -#define FILE_STMT_FILENAME(NODE) \ - (IDENTIFIER_POINTER (FILE_STMT_FILENAME_NODE (NODE))) - -/* The line-number at which a statement began. But if - STMT_LINENO_FOR_FN_P does holds, then this macro gives the - line number for the end of the current function instead. */ -#define STMT_LINENO(NODE) \ - (TREE_COMPLEXITY ((NODE))) - -/* If nonzero, the STMT_LINENO for NODE is the line at which the - function ended. */ -#define STMT_LINENO_FOR_FN_P(NODE) \ - (TREE_LANG_FLAG_2 ((NODE))) - /* Nonzero if we want the new ISO rules for pushing a new scope for `for' initialization variables. */ #define NEW_FOR_SCOPE_P(NODE) (TREE_LANG_FLAG_0 (NODE)) -/* Nonzero if we want to create an ASM_INPUT instead of an - ASM_OPERAND with no operands. */ -#define ASM_INPUT_P(NODE) (TREE_LANG_FLAG_0 (NODE)) - #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM, enum c_tree_code { @@ -1149,7 +1093,7 @@ enum c_tree_code { WHILE_STMT, DO_STMT, RETURN_STMT, \ BREAK_STMT, CONTINUE_STMT, SCOPE_STMT, \ SWITCH_STMT, GOTO_STMT, LABEL_STMT, \ - ASM_STMT, FILE_STMT, CASE_LABEL + ASM_STMT, CASE_LABEL /* TRUE if a code represents a statement. The front end init langhook should take care of initialization of this array. */ @@ -1165,24 +1109,6 @@ extern bool statement_code_p[MAX_TREE_CODES]; statement_code_p[STMT_CODES[i]] = true; \ } while (0) -extern void genrtl_do_pushlevel (void); -extern void genrtl_goto_stmt (tree); -extern void genrtl_expr_stmt (tree); -extern void genrtl_expr_stmt_value (tree, int, int); -extern void genrtl_decl_stmt (tree); -extern void genrtl_if_stmt (tree); -extern void genrtl_while_stmt (tree); -extern void genrtl_do_stmt (tree); -extern void genrtl_return_stmt (tree); -extern void genrtl_for_stmt (tree); -extern void genrtl_break_stmt (void); -extern void genrtl_continue_stmt (void); -extern void genrtl_scope_stmt (tree); -extern void genrtl_switch_stmt (tree); -extern void genrtl_case_label (tree); -extern void genrtl_compound_stmt (tree); -extern void genrtl_asm_stmt (tree, tree, tree, tree, tree, int); -extern void genrtl_cleanup_stmt (tree); extern int stmts_are_full_exprs_p (void); extern int anon_aggr_type_p (tree); @@ -1198,13 +1124,8 @@ extern int anon_aggr_type_p (tree); #define CLEAR_DECL_C_BIT_FIELD(NODE) \ (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 0) -/* In a VAR_DECL, nonzero if the decl is a register variable with - an explicit asm specification. */ -#define DECL_C_HARD_REGISTER(DECL) DECL_LANG_FLAG_4 (VAR_DECL_CHECK (DECL)) - extern void emit_local_var (tree); extern void make_rtl_for_local_static (tree); -extern tree expand_cond (tree); extern tree c_expand_return (tree); extern tree do_case (tree, tree); extern tree build_stmt (enum tree_code, ...); @@ -1249,6 +1170,8 @@ extern int case_compare (splay_tree_key, splay_tree_key); extern tree c_add_case_label (splay_tree, tree, tree, tree); +extern void c_do_switch_warnings (splay_tree, tree); + extern tree build_function_call (tree, tree); extern tree finish_label_address_expr (tree); @@ -1289,6 +1212,17 @@ extern void dump_time_statistics (void); extern bool c_dump_tree (void *, tree); +extern int c_gimplify_expr (tree *, tree *, tree *); +extern tree c_walk_subtrees (tree*, int*, walk_tree_fn, void*, void*); +extern int c_tree_chain_matters_p (tree); + +extern void c_warn_unused_result (tree *); + +/* In c-simplify.c */ +extern void c_genericize (tree); +extern int c_gimplify_stmt (tree *); +extern tree stmt_expr_last_stmt (tree); + extern void pch_init (void); extern int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd); extern void c_common_read_pch (cpp_reader *pfile, const char *name, int fd, @@ -1299,7 +1233,6 @@ extern void builtin_define_with_value (const char *, const char *, int); extern void c_stddef_cpp_builtins (void); extern void fe_file_change (const struct line_map *); extern int c_estimate_num_insns (tree decl); -extern bool c_decl_uninit (tree t); extern void c_parse_error (const char *, enum cpp_ttype, tree); /* The following have been moved here from c-tree.h, since they're needed diff --git a/gcc/c-convert.c b/gcc/c-convert.c index 582ec8bfe34..3067137c372 100644 --- a/gcc/c-convert.c +++ b/gcc/c-convert.c @@ -114,6 +114,9 @@ convert (tree type, tree expr) return fold (convert_to_complex (type, e)); if (code == VECTOR_TYPE) return fold (convert_to_vector (type, e)); + if ((code == RECORD_TYPE || code == UNION_TYPE) + && lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) + return e; error ("conversion to non-scalar type requested"); return error_mark_node; diff --git a/gcc/c-decl.c b/gcc/c-decl.c index b03ba809e3c..d0fc708ea05 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -49,6 +49,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "timevar.h" #include "c-common.h" #include "c-pragma.h" +#include "langhooks.h" +#include "tree-mudflap.h" +#include "tree-simple.h" +#include "diagnostic.h" +#include "tree-dump.h" #include "cgraph.h" #include "hashtab.h" #include "libfuncs.h" @@ -1664,7 +1669,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) static bool duplicate_decls (tree newdecl, tree olddecl) { - tree newtype, oldtype; + tree newtype = NULL, oldtype = NULL; if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype)) return false; @@ -2113,10 +2118,6 @@ lookup_label (tree name) any that may be inherited from containing functions or containing scopes. This is called for __label__ declarations. */ -/* Note that valid use, if the label being shadowed comes from another - scope in the same function, requires calling declare_nonlocal_label - right away. (Is this still true? -zw 2003-07-17) */ - tree declare_label (tree name) { @@ -2936,7 +2937,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree) in a particular register. */ if (C_DECL_REGISTER (decl)) { - DECL_C_HARD_REGISTER (decl) = 1; + DECL_HARD_REGISTER (decl) = 1; /* This cannot be done for a structure with volatile fields, on which DECL_REGISTER will have been reset. */ @@ -3304,11 +3305,14 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name) else w = tree_low_cst (*width, 1); - if (TREE_CODE (*type) == ENUMERAL_TYPE - && (w < min_precision (TYPE_MIN_VALUE (*type), TYPE_UNSIGNED (*type)) - || w < min_precision (TYPE_MAX_VALUE (*type), - TYPE_UNSIGNED (*type)))) - warning ("`%s' is narrower than values of its type", name); + if (TREE_CODE (*type) == ENUMERAL_TYPE) + { + struct lang_type *lt = TYPE_LANG_SPECIFIC (*type); + if (!lt + || w < min_precision (lt->enum_min, TYPE_UNSIGNED (*type)) + || w < min_precision (lt->enum_max, TYPE_UNSIGNED (*type))) + warning ("`%s' is narrower than values of its type", name); + } } /* Given declspecs and a declarator, @@ -4059,6 +4063,11 @@ grokdeclarator (tree declarator, tree declspecs, TYPE_SIZE (type) = bitsize_zero_node; TYPE_SIZE_UNIT (type) = size_zero_node; } + else if (declarator && TREE_CODE (declarator) == INDIRECT_REF) + /* We can never complete an array type which is the target of a + pointer, so go ahead and lay it out. */ + layout_type (type); + if (decl_context != PARM && (array_ptr_quals != NULL_TREE || array_parm_static)) { @@ -5251,7 +5260,7 @@ finish_struct (tree t, tree fieldlist, tree attributes) ensure that this lives as long as the rest of the struct decl. All decls in an inline function need to be saved. */ - space = ggc_alloc (sizeof (struct lang_type)); + space = ggc_alloc_cleared (sizeof (struct lang_type)); space2 = ggc_alloc (sizeof (struct sorted_fields_type) + len * sizeof (tree)); len = 0; @@ -5386,9 +5395,10 @@ tree finish_enum (tree enumtype, tree values, tree attributes) { tree pair, tem; - tree minnode = 0, maxnode = 0, enum_value_type; + tree minnode = 0, maxnode = 0; int precision, unsign; bool toplevel = (file_scope == current_scope); + struct lang_type *lt; decl_attributes (&enumtype, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); @@ -5418,27 +5428,20 @@ finish_enum (tree enumtype, tree values, tree attributes) min_precision (maxnode, unsign)); if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node)) { - tree narrowest = c_common_type_for_size (precision, unsign); - if (narrowest == 0) + tem = c_common_type_for_size (precision, unsign); + if (tem == NULL) { warning ("enumeration values exceed range of largest integer"); - narrowest = long_long_integer_type_node; + tem = long_long_integer_type_node; } - - precision = TYPE_PRECISION (narrowest); } else - precision = TYPE_PRECISION (integer_type_node); - - if (precision == TYPE_PRECISION (integer_type_node)) - enum_value_type = c_common_type_for_size (precision, 0); - else - enum_value_type = enumtype; + tem = unsign ? unsigned_type_node : integer_type_node; - TYPE_MIN_VALUE (enumtype) = minnode; - TYPE_MAX_VALUE (enumtype) = maxnode; - TYPE_PRECISION (enumtype) = precision; - TYPE_UNSIGNED (enumtype) = unsign; + TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); + TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); + TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); TYPE_SIZE (enumtype) = 0; layout_type (enumtype); @@ -5454,6 +5457,7 @@ finish_enum (tree enumtype, tree values, tree attributes) for (pair = values; pair; pair = TREE_CHAIN (pair)) { tree enu = TREE_PURPOSE (pair); + tree ini = DECL_INITIAL (enu); TREE_TYPE (enu) = enumtype; @@ -5464,18 +5468,27 @@ finish_enum (tree enumtype, tree values, tree attributes) when comparing integers with enumerators that fit in the int range. When -pedantic is given, build_enumerator() would have already taken care of those that don't fit. */ - if (int_fits_type_p (DECL_INITIAL (enu), enum_value_type)) - DECL_INITIAL (enu) = convert (enum_value_type, DECL_INITIAL (enu)); + if (int_fits_type_p (ini, integer_type_node)) + tem = integer_type_node; else - DECL_INITIAL (enu) = convert (enumtype, DECL_INITIAL (enu)); + tem = enumtype; + ini = convert (tem, ini); + DECL_INITIAL (enu) = ini; TREE_PURPOSE (pair) = DECL_NAME (enu); - TREE_VALUE (pair) = DECL_INITIAL (enu); + TREE_VALUE (pair) = ini; } TYPE_VALUES (enumtype) = values; } + /* Record the min/max values so that we can warn about bit-field + enumerations that are too small for the values. */ + lt = ggc_alloc_cleared (sizeof (struct lang_type)); + lt->enum_min = minnode; + lt->enum_max = maxnode; + TYPE_LANG_SPECIFIC (enumtype) = lt; + /* Fix up all variant types of this enum type. */ for (tem = TYPE_MAIN_VARIANT (enumtype); tem; tem = TYPE_NEXT_VARIANT (tem)) { @@ -5491,6 +5504,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); + TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); } /* Finish debugging output for this type. */ @@ -6085,6 +6099,25 @@ store_parm_decls_oldstyle (tree fndecl, tree arg_info) } } +/* A subroutine of store_parm_decls called via walk_tree. Mark all + decls non-local. */ + +static tree +set_decl_nonlocal (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +{ + tree t = *tp; + + if (DECL_P (t)) + { + DECL_NONLOCAL (t) = 1; + *walk_subtrees = 0; + } + else if (TYPE_P (t)) + *walk_subtrees = 0; + + return NULL; +} + /* Store the parameter declarations into the current function declaration. This is called after parsing the parameter declarations, before digesting the body of the function. @@ -6142,7 +6175,14 @@ store_parm_decls (void) for (t = DECL_LANG_SPECIFIC (fndecl)->pending_sizes; t; t = TREE_CHAIN (t)) - SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = context; + { + /* We will have a nonlocal use of whatever variables are + buried inside here. */ + walk_tree (&TREE_OPERAND (TREE_VALUE (t), 0), + set_decl_nonlocal, NULL, NULL); + + SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = context; + } } /* This function is being processed in whole-function mode. */ @@ -6156,6 +6196,32 @@ store_parm_decls (void) cfun->x_dont_save_pending_sizes_p = 1; } +/* Give FNDECL and all its nested functions to cgraph for compilation. */ + +static void +c_finalize (tree fndecl) +{ + struct cgraph_node *cgn; + + /* Handle attribute((warn_unused_result)). Relies on gimple input. */ + c_warn_unused_result (&DECL_SAVED_TREE (fndecl)); + + /* ??? Objc emits functions after finalizing the compilation unit. + This should be cleaned up later and this conditional removed. */ + if (cgraph_global_info_ready) + { + c_expand_body (fndecl); + return; + } + + /* Finalize all nested functions now. */ + cgn = cgraph_node (fndecl); + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + c_finalize (cgn->decl); + + cgraph_finalize_function (fndecl, false); +} + /* Finish up a function declaration and compile that function all the way to assembler language output. The free the storage for the function definition. @@ -6253,17 +6319,44 @@ finish_function (void) && current_function_returns_null) warning ("this function may return with or without a value"); + /* Store the end of the function, so that we get good line number + info for the epilogue. */ + cfun->function_end_locus = input_location; + + /* If we don't have ctors/dtors sections, and this is a static + constructor or destructor, it must be recorded now. */ + if (DECL_STATIC_CONSTRUCTOR (fndecl) + && !targetm.have_ctors_dtors) + static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors); + if (DECL_STATIC_DESTRUCTOR (fndecl) + && !targetm.have_ctors_dtors) + static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors); + + /* Genericize before inlining. Delay genericizing nested functions + until their parent function is genericized. Since finalizing + requires GENERIC, delay that as well. */ + + if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node) + { + if (!decl_function_context (fndecl)) + { + c_genericize (fndecl); + lower_nested_functions (fndecl); + c_finalize (fndecl); + } + else + { + /* Register this function with cgraph just far enough to get it + added to our parent's nested function list. Handy, since the + C front end doesn't have such a list. */ + (void) cgraph_node (fndecl); + } + } + /* We're leaving the context of this function, so zap cfun. - It's still in DECL_STRUCT_FUNCTION , and we'll restore it in + It's still in DECL_STRUCT_FUNCTION, and we'll restore it in tree_rest_of_compilation. */ cfun = NULL; - - /* ??? Objc emits functions after finalizing the compilation unit. - This should be cleaned up later and this conditional removed. */ - if (!cgraph_global_info_ready) - cgraph_finalize_function (fndecl, false); - else - c_expand_body (fndecl); current_function_decl = NULL; } @@ -6290,23 +6383,14 @@ c_expand_body_1 (tree fndecl, int nested_p) /* Return to the enclosing function. */ pop_function_context (); - if (DECL_STATIC_CONSTRUCTOR (fndecl)) - { - if (targetm.have_ctors_dtors) - targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0), - DEFAULT_INIT_PRIORITY); - else - static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors); - } - - if (DECL_STATIC_DESTRUCTOR (fndecl)) - { - if (targetm.have_ctors_dtors) - targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0), - DEFAULT_INIT_PRIORITY); - else - static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors); - } + if (DECL_STATIC_CONSTRUCTOR (fndecl) + && targetm.have_ctors_dtors) + targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0), + DEFAULT_INIT_PRIORITY); + if (DECL_STATIC_DESTRUCTOR (fndecl) + && targetm.have_ctors_dtors) + targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0), + DEFAULT_INIT_PRIORITY); } /* Like c_expand_body_1 but only for unnested functions. */ @@ -6512,19 +6596,32 @@ c_begin_compound_stmt (void) return stmt; } -/* Expand T (a DECL_STMT) if it declares an entity not handled by the +/* Expand DECL if it declares an entity not handled by the common code. */ -void -c_expand_decl_stmt (tree t) +int +c_expand_decl (tree decl) { - tree decl = DECL_STMT_DECL (t); - + if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl)) + { + /* Let the back-end know about this variable. */ + if (!anon_aggr_type_p (TREE_TYPE (decl))) + emit_local_var (decl); + else + expand_anon_union_decl (decl, NULL_TREE, + DECL_ANON_UNION_ELEMS (decl)); + } + else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) + make_rtl_for_local_static (decl); /* Expand nested functions. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_CONTEXT (decl) == current_function_decl - && DECL_SAVED_TREE (decl)) + else if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_CONTEXT (decl) == current_function_decl + && DECL_SAVED_TREE (decl)) c_expand_body_1 (decl, 1); + else + return 0; + + return 1; } /* Return the global value of T as a symbol. */ diff --git a/gcc/c-dump.c b/gcc/c-dump.c index 5403bf88601..859d8504169 100644 --- a/gcc/c-dump.c +++ b/gcc/c-dump.c @@ -32,7 +32,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA void dump_stmt (dump_info_p di, tree t) { - dump_int (di, "line", STMT_LINENO (t)); + location_t *locus = EXPR_LOCUS (t); + if (locus) + dump_int (di, "line", locus->line); } /* Dump the next statement after STMT. */ diff --git a/gcc/c-format.c b/gcc/c-format.c index 3a51c6b63b4..17ef68a608a 100644 --- a/gcc/c-format.c +++ b/gcc/c-format.c @@ -86,7 +86,7 @@ handle_format_arg_attribute (tree *node, tree name ATTRIBUTE_UNUSED, { tree type = *node; tree format_num_expr = TREE_VALUE (args); - unsigned HOST_WIDE_INT format_num; + unsigned HOST_WIDE_INT format_num = 0; tree argument; if (!get_constant (format_num_expr, &format_num, 0)) diff --git a/gcc/c-lang.c b/gcc/c-lang.c index 93dc4052916..cf422cb3cc5 100644 --- a/gcc/c-lang.c +++ b/gcc/c-lang.c @@ -30,6 +30,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "ggc.h" #include "langhooks.h" #include "langhooks-def.h" +#include "tree-inline.h" #include "diagnostic.h" #include "c-pretty-print.h" @@ -63,6 +64,8 @@ enum c_language_kind c_language = clk_c; #define LANG_HOOKS_SAFE_FROM_P c_safe_from_p #undef LANG_HOOKS_EXPAND_EXPR #define LANG_HOOKS_EXPAND_EXPR c_expand_expr +#undef LANG_HOOKS_EXPAND_DECL +#define LANG_HOOKS_EXPAND_DECL c_expand_decl #undef LANG_HOOKS_MARK_ADDRESSABLE #define LANG_HOOKS_MARK_ADDRESSABLE c_mark_addressable #undef LANG_HOOKS_PARSE_FILE @@ -89,13 +92,10 @@ enum c_language_kind c_language = clk_c; #define LANG_HOOKS_FUNCTION_ENTER_NESTED c_push_function_context #undef LANG_HOOKS_FUNCTION_LEAVE_NESTED #define LANG_HOOKS_FUNCTION_LEAVE_NESTED c_pop_function_context +#undef LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P +#define LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P c_missing_noreturn_ok_p #undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL #define LANG_HOOKS_DUP_LANG_SPECIFIC_DECL c_dup_lang_specific_decl -#undef LANG_HOOKS_DECL_UNINIT -#define LANG_HOOKS_DECL_UNINIT c_decl_uninit - -#undef LANG_HOOKS_RTL_EXPAND_STMT -#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE @@ -103,20 +103,24 @@ enum c_language_kind c_language = clk_c; #undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE #define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE c_common_format_attribute_table +#undef LANG_HOOKS_TREE_INLINING_WALK_SUBTREES +#define LANG_HOOKS_TREE_INLINING_WALK_SUBTREES \ + c_walk_subtrees #undef LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN #define LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN \ c_cannot_inline_tree_fn #undef LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS #define LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS \ c_disregard_inline_limits +#undef LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P +#define LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P \ + c_tree_chain_matters_p #undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P #define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P \ anon_aggr_type_p #undef LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING #define LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING \ c_convert_parm_for_inlining -#undef LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS -#define LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS c_estimate_num_insns #undef LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN #define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN c_dump_tree @@ -156,6 +160,13 @@ enum c_language_kind c_language = clk_c; #undef LANG_HOOKS_WRITE_GLOBALS #define LANG_HOOKS_WRITE_GLOBALS c_write_global_declarations +/* Hooks for tree gimplification. */ +#undef LANG_HOOKS_GIMPLIFY_EXPR +#define LANG_HOOKS_GIMPLIFY_EXPR c_gimplify_expr + +#undef LANG_HOOKS_TYPES_COMPATIBLE_P +#define LANG_HOOKS_TYPES_COMPATIBLE_P c_types_compatible_p + /* ### When changing hooks, consider if ObjC needs changing too!! ### */ /* Each front end provides its own. */ @@ -202,6 +213,11 @@ finish_file (void) c_objc_common_finish_file (); } +int +c_types_compatible_p (tree x, tree y) +{ + return comptypes (TYPE_MAIN_VARIANT (x), TYPE_MAIN_VARIANT (y), 0); +} static void c_initialize_diagnostics (diagnostic_context *context) { diff --git a/gcc/c-mudflap.c b/gcc/c-mudflap.c new file mode 100644 index 00000000000..e2fa5b1a438 --- /dev/null +++ b/gcc/c-mudflap.c @@ -0,0 +1,100 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting: + C front-end interface. + + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" +#include "errors.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tree-inline.h" +#include "c-tree.h" +#include "c-common.h" +#include "diagnostic.h" +#include "output.h" +#include "varray.h" +#include "tree-mudflap.h" +#include "target.h" +#include "flags.h" +#include "rtl.h" +#include "toplev.h" +#include "function.h" + + + +/* ------------------------------------------------------------------------ */ + + +/* Initialize the global tree nodes that correspond to mf-runtime.h + declarations. */ +tree +mflang_lookup_decl (const char* name) +{ + tree decl = lookup_name (get_identifier (name)); + if (decl == NULL_TREE) + internal_error ("mudflap: cannot find declaration of `%s' from mf-runtime.h", + name); + + return decl; +} + + +/* Emit a synthetic CTOR function for the current file. Populate it from + the enqueued __mf_register calls. Compile the function. */ + +void +mflang_flush_calls (tree enqueued_call_stmt_chain) +{ + tree fnname, t1, t2, body, block, scope; + + /* Short-circuit! */ + if (enqueued_call_stmt_chain == NULL_TREE) + return; + + fnname = get_identifier ("__mudflap_static_initializer"); + t1 = build_tree_list (NULL_TREE, void_type_node); + t2 = tree_cons (NULL, NULL, t1); + start_function (t1, build_nt (CALL_EXPR, fnname, t2, NULL), NULL); + store_parm_decls (); + + DECL_STATIC_CONSTRUCTOR (current_function_decl) = 1; + TREE_PUBLIC (current_function_decl) = 0; + TREE_USED (current_function_decl) = 1; + mf_mark (current_function_decl); + + body = c_begin_compound_stmt (); + push_scope (); + clear_last_expr (); + add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); + + c_expand_expr_stmt (enqueued_call_stmt_chain); + + scope = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + block = pop_scope (); + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope)) = block; + SCOPE_STMT_BLOCK (TREE_VALUE (scope)) = block; + RECHAIN_STMTS (body, COMPOUND_BODY (body)); + finish_function (); +} diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index e736110e6be..f7e7c8acb10 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -36,14 +36,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "varray.h" #include "ggc.h" #include "langhooks.h" +#include "tree-mudflap.h" #include "target.h" #include "cgraph.h" static bool c_tree_printer (pretty_printer *, text_info *); -static tree start_cdtor (int); -static void finish_cdtor (tree); -int +bool c_missing_noreturn_ok_p (tree decl) { /* A missing noreturn is not ok for freestanding implementations and @@ -166,13 +165,10 @@ c_objc_common_init (void) if (c_common_init () == false) return false; - lang_expand_decl_stmt = c_expand_decl_stmt; - /* These were not defined in the Objective-C front end, but I'm putting them here anyway. The diagnostic format decoder might want an enhanced ObjC implementation. */ diagnostic_format_decoder (global_dc) = &c_tree_printer; - lang_missing_noreturn_ok_p = &c_missing_noreturn_ok_p; /* If still unspecified, make it match -std=c99 (allowing for -pedantic-errors). */ @@ -187,40 +183,33 @@ c_objc_common_init (void) return true; } -static tree -start_cdtor (int method_type) +/* Synthesize a function which calls all the global ctors or global dtors + in this file. */ +static void +build_cdtor (int method_type, tree cdtors) { tree fnname = get_file_function_name (method_type); - tree void_list_node_1 = build_tree_list (NULL_TREE, void_type_node); tree body; + tree scope; + tree block; - start_function (void_list_node_1, + start_function (void_list_node, build_nt (CALL_EXPR, fnname, - tree_cons (NULL_TREE, NULL_TREE, void_list_node_1), + tree_cons (NULL_TREE, NULL_TREE, void_list_node), NULL_TREE), NULL_TREE); store_parm_decls (); - current_function_cannot_inline - = "static constructors and destructors cannot be inlined"; - body = c_begin_compound_stmt (); - - push_scope (); - clear_last_expr (); add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); - return body; -} - -static void -finish_cdtor (tree body) -{ - tree scope; - tree block; + for (; cdtors; cdtors = TREE_CHAIN (cdtors)) + add_stmt (build_stmt (EXPR_STMT, + build_function_call (TREE_VALUE (cdtors), 0))); scope = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); - block = pop_scope (); + + block = make_node (BLOCK); SCOPE_STMT_BLOCK (TREE_PURPOSE (scope)) = block; SCOPE_STMT_BLOCK (TREE_VALUE (scope)) = block; @@ -237,30 +226,22 @@ c_objc_common_finish_file (void) if (pch_file) c_common_write_pch (); - cgraph_finalize_compilation_unit (); - cgraph_optimize (); - if (static_ctors) { - tree body = start_cdtor ('I'); - - for (; static_ctors; static_ctors = TREE_CHAIN (static_ctors)) - c_expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors), - NULL_TREE)); - - finish_cdtor (body); + build_cdtor ('I', static_ctors); + static_ctors = 0; } - if (static_dtors) { - tree body = start_cdtor ('D'); + build_cdtor ('D', static_dtors); + static_dtors = 0; + } - for (; static_dtors; static_dtors = TREE_CHAIN (static_dtors)) - c_expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors), - NULL_TREE)); + cgraph_finalize_compilation_unit (); + cgraph_optimize (); - finish_cdtor (body); - } + if (flag_mudflap) + mudflap_finish_file (); } /* Called during diagnostic message formatting process to print a diff --git a/gcc/c-opts.c b/gcc/c-opts.c index 8dc308ca4bb..1300b69cd0b 100644 --- a/gcc/c-opts.c +++ b/gcc/c-opts.c @@ -733,11 +733,6 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->dollars_in_ident = value; break; - case OPT_fdump_: - if (!dump_switch_p (arg)) - result = 0; - break; - case OPT_ffreestanding: value = !value; /* Fall through.... */ @@ -1100,17 +1095,13 @@ c_common_post_options (const char **pfilename) flag_inline_trees = 1; - /* Use tree inlining if possible. Function instrumentation is only - done in the RTL level, so we disable tree inlining. */ - if (! flag_instrument_function_entry_exit) + /* Use tree inlining. */ + if (!flag_no_inline) + flag_no_inline = 1; + if (flag_inline_functions) { - if (!flag_no_inline) - flag_no_inline = 1; - if (flag_inline_functions) - { - flag_inline_trees = 2; - flag_inline_functions = 0; - } + flag_inline_trees = 2; + flag_inline_functions = 0; } /* -Wextra implies -Wsign-compare, but not if explicitly diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 91a42d91814..07854c48d6b 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -661,6 +661,7 @@ primary: last_expr_type = void_type_node; $$ = build1 (STMT_EXPR, last_expr_type, $1); TREE_SIDE_EFFECTS ($$) = 1; + annotate_with_locus ($$, input_location); } | compstmt_primary_start error ')' { @@ -2130,7 +2131,7 @@ simple_if: if_prefix: /* We must build the IF_STMT node before parsing its - condition so that STMT_LINENO refers to the line + condition so that EXPR_LOCUS refers to the line containing the "if", and not the line containing the close-parenthesis. @@ -2194,12 +2195,8 @@ lineno_stmt: save_location stmt { if ($2) { - STMT_LINENO ($2) = $1.line; - /* ??? We currently have no way of recording - the filename for a statement. This probably - matters little in practice at the moment, - but I suspect that problems will occur when - doing inlining at the tree level. */ + SET_EXPR_LOCUS ($2, NULL); + annotate_with_locus ($2, $1); } } ; @@ -2208,7 +2205,8 @@ lineno_label: save_location label { if ($2) { - STMT_LINENO ($2) = $1.line; + SET_EXPR_LOCUS ($2, NULL); + annotate_with_locus ($2, $1); } } ; @@ -2237,7 +2235,7 @@ select_or_iter_stmt: | simple_if ELSE error { c_expand_end_cond (); } /* We must build the WHILE_STMT node before parsing its - condition so that STMT_LINENO refers to the line + condition so that EXPR_LOCUS refers to the line containing the "while", and not the line containing the close-parenthesis. diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c index 10c8caea35d..31a17a109d2 100644 --- a/gcc/c-pragma.c +++ b/gcc/c-pragma.c @@ -352,7 +352,6 @@ maybe_apply_pragma_weak (tree decl ATTRIBUTE_UNUSED) static GTY(()) tree pending_redefine_extname; -#ifdef HANDLE_PRAGMA_REDEFINE_EXTNAME static void handle_pragma_redefine_extname (cpp_reader *); /* #pragma redefined_extname oldname newname */ @@ -388,7 +387,6 @@ handle_pragma_redefine_extname (cpp_reader *dummy ATTRIBUTE_UNUSED) else add_to_renaming_pragma_list(oldname, newname); } -#endif void add_to_renaming_pragma_list (tree oldname, tree newname) @@ -502,6 +500,9 @@ init_pragma (void) #endif #ifdef HANDLE_PRAGMA_REDEFINE_EXTNAME c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname); +#else + if (flag_mudflap) + c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname); #endif #ifdef HANDLE_PRAGMA_EXTERN_PREFIX c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix); diff --git a/gcc/c-pretty-print.c b/gcc/c-pretty-print.c index 5673d73c7c1..e73ab1b51e3 100644 --- a/gcc/c-pretty-print.c +++ b/gcc/c-pretty-print.c @@ -26,6 +26,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "real.h" #include "c-pretty-print.h" #include "c-tree.h" +#include "diagnostic.h" /* The pretty-printer code is primarily designed to closely follow (GNU) C and C++ grammars. That is to be contrasted with spaghetti @@ -280,7 +281,7 @@ pp_c_type_specifier (c_pretty_printer *pp, tree t) break; case IDENTIFIER_NODE: - pp_c_tree_identifier (pp, t); + pp_c_tree_decl_identifier (pp, t); break; case VOID_TYPE: @@ -561,11 +562,10 @@ pp_c_direct_declarator (c_pretty_printer *pp, tree t) case TYPE_DECL: case FIELD_DECL: case LABEL_DECL: - if (DECL_NAME (t)) - { - pp_c_space_for_pointer_operator (pp, TREE_TYPE (t)); - pp_c_tree_identifier (pp, DECL_NAME (t)); - } + pp_c_space_for_pointer_operator (pp, TREE_TYPE (t)); + pp_c_tree_decl_identifier (pp, t); + break; + case ARRAY_TYPE: case POINTER_TYPE: pp_abstract_declarator (pp, TREE_TYPE (t)); @@ -578,7 +578,7 @@ pp_c_direct_declarator (c_pretty_printer *pp, tree t) case FUNCTION_DECL: pp_c_space_for_pointer_operator (pp, TREE_TYPE (TREE_TYPE (t))); - pp_c_tree_identifier (pp, DECL_NAME (t)); + pp_c_tree_decl_identifier (pp, t); if (pp_c_base (pp)->flags & pp_c_flag_abstract) pp_abstract_declarator (pp, TREE_TYPE (t)); else @@ -960,8 +960,9 @@ pp_c_primary_expression (c_pretty_printer *pp, tree e) case CONST_DECL: case FUNCTION_DECL: case LABEL_DECL: - e = DECL_NAME (e); - /* Fall through. */ + pp_c_tree_decl_identifier (pp, e); + break; + case IDENTIFIER_NODE: pp_c_tree_identifier (pp, e); break; @@ -980,6 +981,22 @@ pp_c_primary_expression (c_pretty_printer *pp, tree e) pp_c_constant (pp, e); break; + case TARGET_EXPR: + pp_c_identifier (pp, "__builtin_memcpy"); + pp_c_left_paren (pp); + pp_ampersand (pp); + pp_primary_expression (pp, TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_ampersand (pp); + pp_initializer (pp, TREE_OPERAND (e, 1)); + if (TREE_OPERAND (e, 2)) + { + pp_separate_with (pp, ','); + pp_c_expression (pp, TREE_OPERAND (e, 2)); + } + pp_c_right_paren (pp); + break; + case STMT_EXPR: pp_c_left_paren (pp); pp_statement (pp, STMT_EXPR_STMT (e)); @@ -1005,13 +1022,7 @@ static void pp_c_initializer (c_pretty_printer *pp, tree e) { if (TREE_CODE (e) == CONSTRUCTOR) - { - enum tree_code code = TREE_CODE (TREE_TYPE (e)); - if (code == RECORD_TYPE || code == UNION_TYPE || code == ARRAY_TYPE) - pp_c_brace_enclosed_initializer_list (pp, e); - else - pp_unsupported_tree (pp, TREE_OPERAND (e, 1)); - } + pp_c_brace_enclosed_initializer_list (pp, e); else pp_expression (pp, e); } @@ -1099,25 +1110,36 @@ pp_c_initializer_list (c_pretty_printer *pp, tree e) pp_separate_with (pp, ','); } } - break; + return; case VECTOR_TYPE: - pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e)); - break; + if (TREE_CODE (e) == VECTOR_CST) + pp_c_expression_list (pp, TREE_VECTOR_CST_ELTS (e)); + else if (TREE_CODE (e) == CONSTRUCTOR) + pp_c_expression_list (pp, CONSTRUCTOR_ELTS (e)); + else + break; + return; case COMPLEX_TYPE: - { - const bool cst = TREE_CODE (e) == COMPLEX_CST; - pp_expression (pp, cst ? TREE_REALPART (e) : TREE_OPERAND (e, 0)); - pp_separate_with (pp, ','); - pp_expression (pp, cst ? TREE_IMAGPART (e) : TREE_OPERAND (e, 1)); - } - break; + if (TREE_CODE (e) == CONSTRUCTOR) + pp_c_expression_list (pp, CONSTRUCTOR_ELTS (e)); + else if (TREE_CODE (e) == COMPLEX_CST || TREE_CODE (e) == COMPLEX_EXPR) + { + const bool cst = TREE_CODE (e) == COMPLEX_CST; + pp_expression (pp, cst ? TREE_REALPART (e) : TREE_OPERAND (e, 0)); + pp_separate_with (pp, ','); + pp_expression (pp, cst ? TREE_IMAGPART (e) : TREE_OPERAND (e, 1)); + } + else + break; + return; default: - pp_unsupported_tree (pp, type); break; } + + pp_unsupported_tree (pp, type); } /* Pretty-print a brace-enclosed initializer-list. */ @@ -1149,7 +1171,9 @@ pp_c_id_expression (c_pretty_printer *pp, tree t) case FUNCTION_DECL: case FIELD_DECL: case LABEL_DECL: - t = DECL_NAME (t); + pp_c_tree_decl_identifier (pp, t); + break; + case IDENTIFIER_NODE: pp_c_tree_identifier (pp, t); break; @@ -1862,7 +1886,7 @@ pp_c_statement (c_pretty_printer *pp, tree stmt) else pp_indentation (pp) -= 3; if (code == LABEL_STMT) - pp_tree_identifier (pp, DECL_NAME (LABEL_STMT_LABEL (stmt))); + pp_c_tree_decl_identifier (pp, LABEL_STMT_LABEL (stmt)); else if (code == CASE_LABEL) { if (CASE_LOW (stmt) == NULL_TREE) @@ -2121,16 +2145,6 @@ pp_c_statement (c_pretty_printer *pp, tree stmt) } break; - case FILE_STMT: - pp_c_identifier (pp, "__FILE__"); - pp_space (pp); - pp_equal (pp); - pp_c_whitespace (pp); - pp_c_identifier (pp, FILE_STMT_FILENAME (stmt)); - pp_c_semicolon (pp); - pp_needs_newline (pp) = true; - break; - default: pp_unsupported_tree (pp, stmt); } @@ -2170,3 +2184,60 @@ pp_c_pretty_printer_init (c_pretty_printer *pp) pp->assignment_expression = pp_c_assignment_expression; pp->expression = pp_c_expression; } + + +/* Print the tree T in full, on file FILE. */ + +void +print_c_tree (FILE *file, tree t) +{ + static c_pretty_printer pp_rec; + static bool initialized = 0; + c_pretty_printer *pp = &pp_rec; + + if (!initialized) + { + initialized = 1; + pp_construct (pp_base (pp), NULL, 0); + pp_c_pretty_printer_init (pp); + pp_needs_newline (pp) = true; + } + pp_base (pp)->buffer->stream = file; + + pp_statement (pp, t); + + pp_newline (pp); + pp_flush (pp); +} + +/* Print the tree T in full, on stderr. */ + +void +debug_c_tree (tree t) +{ + print_c_tree (stderr, t); + fputc ('\n', stderr); +} + +/* Output the DECL_NAME of T. If T has no DECL_NAME, output a string made + up of T's memory address. */ + +void +pp_c_tree_decl_identifier (c_pretty_printer *pp, tree t) +{ + const char *name; + + if (!DECL_P (t)) + abort (); + + if (DECL_NAME (t)) + name = IDENTIFIER_POINTER (DECL_NAME (t)); + else + { + static char xname[8]; + sprintf (xname, "", ((unsigned)((unsigned long)(t) & 0xffff))); + name = xname; + } + + pp_c_identifier (pp, name); +} diff --git a/gcc/c-pretty-print.h b/gcc/c-pretty-print.h index 39e0be77d2d..efffa234d4b 100644 --- a/gcc/c-pretty-print.h +++ b/gcc/c-pretty-print.h @@ -95,7 +95,7 @@ struct c_pretty_print_info #undef pp_base #define pp_base(PP) (&pp_c_base (PP)->base) - + #define pp_c_tree_identifier(PPI, ID) \ pp_c_identifier (PPI, IDENTIFIER_POINTER (ID)) @@ -166,6 +166,7 @@ void pp_c_semicolon (c_pretty_printer *); void pp_c_space_for_pointer_operator (c_pretty_printer *, tree); /* Declarations. */ +void pp_c_tree_decl_identifier (c_pretty_printer *, tree); void pp_c_function_definition (c_pretty_printer *, tree); void pp_c_attributes (c_pretty_printer *, tree); void pp_c_type_qualifier_list (c_pretty_printer *, tree); @@ -197,4 +198,6 @@ void pp_c_id_expression (c_pretty_printer *, tree); void pp_c_identifier (c_pretty_printer *, const char *); void pp_c_string_literal (c_pretty_printer *, tree); +void print_c_tree (FILE *file, tree t); + #endif /* GCC_C_PRETTY_PRINTER */ diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index a8693f9b3f1..b74fda6302a 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -44,23 +44,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "timevar.h" #include "predict.h" #include "tree-inline.h" - -/* If non-NULL, the address of a language-specific function for - expanding statements. */ -void (*lang_expand_stmt) (tree); - -/* If non-NULL, the address of a language-specific function for - expanding a DECL_STMT. After the language-independent cases are - handled, this function will be called. If this function is not - defined, it is assumed that declarations other than those for - variables and labels do not require any RTL generation. */ -void (*lang_expand_decl_stmt) (tree); - -static tree find_reachable_label_1 (tree *, int *, void *); -static tree find_reachable_label (tree); -static bool expand_unreachable_if_stmt (tree); -static tree expand_unreachable_stmt (tree, int); -static void genrtl_do_stmt_1 (tree, tree); +#include "langhooks.h" /* Create an empty statement tree rooted at T. */ @@ -81,18 +65,8 @@ begin_stmt_tree (tree *t) tree add_stmt (tree t) { - if (input_filename != last_expr_filename) - { - /* If the filename has changed, also add in a FILE_STMT. Do a string - compare first, though, as it might be an equivalent string. */ - int add = (strcmp (input_filename, last_expr_filename) != 0); - last_expr_filename = input_filename; - if (add) - { - tree pos = build_nt (FILE_STMT, get_identifier (input_filename)); - add_stmt (pos); - } - } + if (!EXPR_LOCUS (t)) + annotate_with_locus (t, input_location); /* Add T to the statement-tree. */ TREE_CHAIN (last_tree) = t; @@ -171,58 +145,53 @@ finish_stmt_tree (tree *t) stmt = TREE_CHAIN (*t); *t = stmt; last_tree = NULL_TREE; - - if (cfun && stmt) - { - /* The line-number recorded in the outermost statement in a function - is the line number of the end of the function. */ - STMT_LINENO (stmt) = input_line; - STMT_LINENO_FOR_FN_P (stmt) = 1; - } } /* Build a generic statement based on the given type of node and arguments. Similar to `build_nt', except that we set - STMT_LINENO to be the current line number. */ + EXPR_LOCUS to be the current source location. */ /* ??? This should be obsolete with the lineno_stmt productions in the grammar. */ tree build_stmt (enum tree_code code, ...) { - tree t; - int length; - int i; + tree ret; + int length, i; va_list p; + bool side_effects; va_start (p, code); - t = make_node (code); + ret = make_node (code); length = TREE_CODE_LENGTH (code); - STMT_LINENO (t) = input_line; - - for (i = 0; i < length; i++) - TREE_OPERAND (t, i) = va_arg (p, tree); - - va_end (p); - return t; -} + annotate_with_locus (ret, input_location); -/* Some statements, like for-statements or if-statements, require a - condition. This condition can be a declaration. If T is such a - declaration it is processed, and an expression appropriate to use - as the condition is returned. Otherwise, T itself is returned. */ + /* Most statements have implicit side effects all on their own, + such as control transfer. For those that do, we'll compute + the real value of TREE_SIDE_EFFECTS from its arguments. */ + switch (code) + { + case EXPR_STMT: + side_effects = false; + break; + default: + side_effects = true; + break; + } -tree -expand_cond (tree t) -{ - if (t && TREE_CODE (t) == TREE_LIST) + for (i = 0; i < length; i++) { - expand_stmt (TREE_PURPOSE (t)); - return TREE_VALUE (t); + tree t = va_arg (p, tree); + if (t && IS_NON_TYPE_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t)))) + side_effects |= TREE_SIDE_EFFECTS (t); + TREE_OPERAND (ret, i) = t; } - else - return t; + + TREE_SIDE_EFFECTS (ret) = side_effects; + + va_end (p); + return ret; } /* Create RTL for the local static variable DECL. */ @@ -268,7 +237,7 @@ emit_local_var (tree decl) /* Create RTL for this variable. */ if (!DECL_RTL_SET_P (decl)) { - if (DECL_C_HARD_REGISTER (decl)) + if (DECL_HARD_REGISTER (decl)) /* The user specified an assembler name for this variable. Set that up now. */ rest_of_decl_compilation @@ -291,214 +260,6 @@ emit_local_var (tree decl) } } -/* Helper for generating the RTL at the beginning of a scope. */ - -void -genrtl_do_pushlevel (void) -{ - emit_line_note (input_location); - clear_last_expr (); -} - -/* Generate the RTL for DESTINATION, which is a GOTO_STMT. */ - -void -genrtl_goto_stmt (tree destination) -{ - if (TREE_CODE (destination) == IDENTIFIER_NODE) - abort (); - - /* We warn about unused labels with -Wunused. That means we have to - mark the used labels as used. */ - if (TREE_CODE (destination) == LABEL_DECL) - TREE_USED (destination) = 1; - - emit_line_note (input_location); - - if (TREE_CODE (destination) == LABEL_DECL) - { - label_rtx (destination); - expand_goto (destination); - } - else - expand_computed_goto (destination); -} - -/* Generate the RTL for EXPR, which is an EXPR_STMT. Provided just - for backward compatibility. genrtl_expr_stmt_value() should be - used for new code. */ - -void -genrtl_expr_stmt (tree expr) -{ - genrtl_expr_stmt_value (expr, -1, 1); -} - -/* Generate the RTL for EXPR, which is an EXPR_STMT. WANT_VALUE tells - whether to (1) save the value of the expression, (0) discard it or - (-1) use expr_stmts_for_value to tell. The use of -1 is - deprecated, and retained only for backward compatibility. - MAYBE_LAST is nonzero if this EXPR_STMT might be the last statement - in expression statement. */ - -void -genrtl_expr_stmt_value (tree expr, int want_value, int maybe_last) -{ - if (expr != NULL_TREE) - { - emit_line_note (input_location); - - if (stmts_are_full_exprs_p ()) - expand_start_target_temps (); - - if (expr != error_mark_node) - expand_expr_stmt_value (expr, want_value, maybe_last); - - if (stmts_are_full_exprs_p ()) - expand_end_target_temps (); - } -} - -/* Generate the RTL for T, which is a DECL_STMT. */ - -void -genrtl_decl_stmt (tree t) -{ - tree decl; - emit_line_note (input_location); - decl = DECL_STMT_DECL (t); - /* If this is a declaration for an automatic local - variable, initialize it. Note that we might also see a - declaration for a namespace-scope object (declared with - `extern'). We don't have to handle the initialization - of those objects here; they can only be declarations, - rather than definitions. */ - if (TREE_CODE (decl) == VAR_DECL - && !TREE_STATIC (decl) - && !DECL_EXTERNAL (decl)) - { - /* Let the back-end know about this variable. */ - if (!anon_aggr_type_p (TREE_TYPE (decl))) - emit_local_var (decl); - else - expand_anon_union_decl (decl, NULL_TREE, - DECL_ANON_UNION_ELEMS (decl)); - } - else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) - make_rtl_for_local_static (decl); - else if (TREE_CODE (decl) == LABEL_DECL - && C_DECLARED_LABEL_FLAG (decl)) - declare_nonlocal_label (decl); - else if (TREE_CODE (decl) == TYPE_DECL) - force_type_save_exprs (TREE_TYPE (decl)); - else if (lang_expand_decl_stmt) - (*lang_expand_decl_stmt) (t); -} - -/* Generate the RTL for T, which is an IF_STMT. */ - -void -genrtl_if_stmt (tree t) -{ - tree cond; - genrtl_do_pushlevel (); - cond = expand_cond (IF_COND (t)); - emit_line_note (input_location); - expand_start_cond (cond, 0); - if (THEN_CLAUSE (t)) - { - tree nextt = THEN_CLAUSE (t); - - if (cond && integer_zerop (cond)) - nextt = expand_unreachable_stmt (nextt, warn_notreached); - expand_stmt (nextt); - } - - if (ELSE_CLAUSE (t)) - { - tree nextt = ELSE_CLAUSE (t); - expand_start_else (); - if (cond && integer_nonzerop (cond)) - nextt = expand_unreachable_stmt (nextt, warn_notreached); - expand_stmt (nextt); - } - expand_end_cond (); -} - -/* Generate the RTL for T, which is a WHILE_STMT. */ - -void -genrtl_while_stmt (tree t) -{ - tree cond = WHILE_COND (t); - - emit_line_note (input_location); - expand_start_loop (1); - genrtl_do_pushlevel (); - - if (cond && !integer_nonzerop (cond)) - { - cond = expand_cond (cond); - emit_line_note (input_location); - expand_exit_loop_top_cond (0, cond); - genrtl_do_pushlevel (); - } - - expand_stmt (WHILE_BODY (t)); - - expand_end_loop (); -} - -/* Generate the RTL for a DO_STMT with condition COND and loop BODY - body. This is reused for expanding unreachable WHILE_STMTS. */ - -static void -genrtl_do_stmt_1 (tree cond, tree body) -{ - /* Recognize the common special-case of do { ... } while (0) and do - not emit the loop widgetry in this case. In particular this - avoids cluttering the rtl with dummy loop notes, which can affect - alignment of adjacent labels. COND can be NULL due to parse - errors. */ - if (!cond || integer_zerop (cond)) - { - expand_start_null_loop (); - expand_stmt (body); - expand_end_null_loop (); - } - else if (integer_nonzerop (cond)) - { - emit_line_note (input_location); - expand_start_loop (1); - - expand_stmt (body); - - emit_line_note (input_location); - expand_end_loop (); - } - else - { - emit_line_note (input_location); - expand_start_loop_continue_elsewhere (1); - - expand_stmt (body); - - expand_loop_continue_here (); - cond = expand_cond (cond); - emit_line_note (input_location); - expand_exit_loop_if_false (0, cond); - expand_end_loop (); - } -} - -/* Generate the RTL for T, which is a DO_STMT. */ - -void -genrtl_do_stmt (tree t) -{ - genrtl_do_stmt_1 (DO_COND (t), DO_BODY (t)); -} - /* Build the node for a return statement and return it. */ tree @@ -507,74 +268,6 @@ build_return_stmt (tree expr) return (build_stmt (RETURN_STMT, expr)); } -/* Generate the RTL for STMT, which is a RETURN_STMT. */ - -void -genrtl_return_stmt (tree stmt) -{ - tree expr; - - expr = RETURN_STMT_EXPR (stmt); - - emit_line_note (input_location); - if (!expr) - expand_null_return (); - else - { - expand_start_target_temps (); - expand_return (expr); - expand_end_target_temps (); - } -} - -/* Generate the RTL for T, which is a FOR_STMT. */ - -void -genrtl_for_stmt (tree t) -{ - tree cond = FOR_COND (t); - location_t saved_loc; - - if (NEW_FOR_SCOPE_P (t)) - genrtl_do_pushlevel (); - - expand_stmt (FOR_INIT_STMT (t)); - - /* Expand the initialization. */ - emit_line_note (input_location); - if (FOR_EXPR (t)) - expand_start_loop_continue_elsewhere (1); - else - expand_start_loop (1); - genrtl_do_pushlevel (); - - /* Save the filename and line number so that we expand the FOR_EXPR - we can reset them back to the saved values. */ - saved_loc = input_location; - - /* Expand the condition. */ - if (cond && !integer_nonzerop (cond)) - { - cond = expand_cond (cond); - emit_line_note (input_location); - expand_exit_loop_top_cond (0, cond); - genrtl_do_pushlevel (); - } - - /* Expand the body. */ - expand_stmt (FOR_BODY (t)); - - /* Expand the increment expression. */ - input_location = saved_loc; - emit_line_note (input_location); - if (FOR_EXPR (t)) - { - expand_loop_continue_here (); - genrtl_expr_stmt (FOR_EXPR (t)); - } - expand_end_loop (); -} - /* Build a break statement node and return it. */ tree @@ -583,16 +276,6 @@ build_break_stmt (void) return (build_stmt (BREAK_STMT)); } -/* Generate the RTL for a BREAK_STMT. */ - -void -genrtl_break_stmt (void) -{ - emit_line_note (input_location); - if ( ! expand_exit_something ()) - abort (); -} - /* Build a continue statement node and return it. */ tree @@ -601,80 +284,6 @@ build_continue_stmt (void) return (build_stmt (CONTINUE_STMT)); } -/* Generate the RTL for a CONTINUE_STMT. */ - -void -genrtl_continue_stmt (void) -{ - emit_line_note (input_location); - if (! expand_continue_loop (0)) - abort (); -} - -/* Generate the RTL for T, which is a SCOPE_STMT. */ - -void -genrtl_scope_stmt (tree t) -{ - tree block = SCOPE_STMT_BLOCK (t); - - if (!SCOPE_NO_CLEANUPS_P (t)) - { - if (SCOPE_BEGIN_P (t)) - expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), block); - else if (SCOPE_END_P (t)) - expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0); - } - else if (!SCOPE_NULLIFIED_P (t)) - { - rtx note = emit_note (SCOPE_BEGIN_P (t) - ? NOTE_INSN_BLOCK_BEG : NOTE_INSN_BLOCK_END); - NOTE_BLOCK (note) = block; - } - - /* If we're at the end of a scope that contains inlined nested - functions, we have to decide whether or not to write them out. */ - if (block && SCOPE_END_P (t)) - { - tree fn; - - for (fn = BLOCK_VARS (block); fn; fn = TREE_CHAIN (fn)) - { - if (TREE_CODE (fn) == FUNCTION_DECL - && DECL_CONTEXT (fn) == current_function_decl - && DECL_STRUCT_FUNCTION (fn) - && DECL_STRUCT_FUNCTION (fn)->saved_for_inline - && !TREE_ASM_WRITTEN (fn) - && TREE_ADDRESSABLE (fn)) - { - push_function_context (); - output_inline_function (fn); - pop_function_context (); - } - } - } -} - -/* Generate the RTL for T, which is a SWITCH_STMT. */ - -void -genrtl_switch_stmt (tree t) -{ - tree cond; - genrtl_do_pushlevel (); - - cond = expand_cond (SWITCH_COND (t)); - if (cond == error_mark_node) - /* The code is in error, but we don't want expand_end_case to - crash. */ - cond = truthvalue_false_node; - - emit_line_note (input_location); - expand_start_case (1, cond, TREE_TYPE (cond), "switch statement"); - expand_stmt (expand_unreachable_stmt (SWITCH_BODY (t), warn_notreached)); - expand_end_case_type (cond, SWITCH_TYPE (t)); -} - /* Create a CASE_LABEL tree node and return it. */ tree @@ -683,378 +292,13 @@ build_case_label (tree low_value, tree high_value, tree label_decl) return build_stmt (CASE_LABEL, low_value, high_value, label_decl); } - -/* Generate the RTL for a CASE_LABEL. */ - -void -genrtl_case_label (tree case_label) -{ - tree duplicate; - tree cleanup; - - cleanup = last_cleanup_this_contour (); - if (cleanup) - { - static int explained = 0; - warning ("destructor needed for `%D'", (TREE_PURPOSE (cleanup))); - warning ("where case label appears here"); - if (!explained) - { - warning ("(enclose actions of previous case statements requiring destructors in their own scope.)"); - explained = 1; - } - } - - add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label), - CASE_LABEL_DECL (case_label), &duplicate); -} - -/* Generate the RTL for T, which is a COMPOUND_STMT. */ - -void -genrtl_compound_stmt (tree t) -{ -#ifdef ENABLE_CHECKING - struct nesting *n = current_nesting_level (); -#endif - - expand_stmt (COMPOUND_BODY (t)); - -#ifdef ENABLE_CHECKING - /* Make sure that we've pushed and popped the same number of levels. */ - if (!COMPOUND_STMT_NO_SCOPE (t) && n != current_nesting_level ()) - abort (); -#endif -} - -/* Generate the RTL for an ASM_STMT. */ - -void -genrtl_asm_stmt (tree cv_qualifier, tree string, tree output_operands, - tree input_operands, tree clobbers, int asm_input_p) -{ - if (cv_qualifier != NULL_TREE - && cv_qualifier != ridpointers[(int) RID_VOLATILE]) - { - warning ("%s qualifier ignored on asm", - IDENTIFIER_POINTER (cv_qualifier)); - cv_qualifier = NULL_TREE; - } - - emit_line_note (input_location); - if (asm_input_p) - expand_asm (string, cv_qualifier != NULL_TREE); - else - c_expand_asm_operands (string, output_operands, input_operands, - clobbers, cv_qualifier != NULL_TREE, - input_location); -} - -/* Generate the RTL for a CLEANUP_STMT. */ - -void -genrtl_cleanup_stmt (tree t) -{ - tree decl = CLEANUP_DECL (t); - if (!decl || !DECL_P (decl) - || (DECL_SIZE (decl) && TREE_TYPE (decl) != error_mark_node)) - expand_decl_cleanup_eh (decl, CLEANUP_EXPR (t), CLEANUP_EH_ONLY (t)); -} - /* We're about to expand T, a statement. Set up appropriate context for the substitution. */ void prep_stmt (tree t) { - if (!STMT_LINENO_FOR_FN_P (t)) - input_line = STMT_LINENO (t); + if (EXPR_LOCUS (t)) + input_location = *EXPR_LOCUS (t); current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t); } - -/* Generate the RTL for the statement T, its substatements, and any - other statements at its nesting level. */ - -void -expand_stmt (tree t) -{ - while (t && t != error_mark_node) - { - int saved_stmts_are_full_exprs_p; - - /* Set up context appropriately for handling this statement. */ - saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); - prep_stmt (t); - - switch (TREE_CODE (t)) - { - case FILE_STMT: - input_filename = FILE_STMT_FILENAME (t); - break; - - case RETURN_STMT: - genrtl_return_stmt (t); - t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); - goto process_t; - - case EXPR_STMT: - genrtl_expr_stmt_value (EXPR_STMT_EXPR (t), TREE_ADDRESSABLE (t), - TREE_CHAIN (t) == NULL - || (TREE_CODE (TREE_CHAIN (t)) == SCOPE_STMT - && TREE_CHAIN (TREE_CHAIN (t)) == NULL)); - break; - - case DECL_STMT: - genrtl_decl_stmt (t); - break; - - case FOR_STMT: - genrtl_for_stmt (t); - break; - - case WHILE_STMT: - genrtl_while_stmt (t); - break; - - case DO_STMT: - genrtl_do_stmt (t); - break; - - case IF_STMT: - genrtl_if_stmt (t); - break; - - case COMPOUND_STMT: - genrtl_compound_stmt (t); - break; - - case BREAK_STMT: - genrtl_break_stmt (); - t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); - goto process_t; - - case CONTINUE_STMT: - genrtl_continue_stmt (); - t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); - goto process_t; - - case SWITCH_STMT: - genrtl_switch_stmt (t); - break; - - case CASE_LABEL: - genrtl_case_label (t); - break; - - case LABEL_STMT: - expand_label (LABEL_STMT_LABEL (t)); - break; - - case GOTO_STMT: - /* Emit information for branch prediction. */ - if (!GOTO_FAKE_P (t) - && TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL - && flag_guess_branch_prob) - { - rtx note = emit_note (NOTE_INSN_PREDICTION); - - NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_GOTO, NOT_TAKEN); - } - genrtl_goto_stmt (GOTO_DESTINATION (t)); - t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached); - goto process_t; - - case ASM_STMT: - genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t), - ASM_OUTPUTS (t), ASM_INPUTS (t), - ASM_CLOBBERS (t), ASM_INPUT_P (t)); - break; - - case SCOPE_STMT: - genrtl_scope_stmt (t); - break; - - case CLEANUP_STMT: - genrtl_cleanup_stmt (t); - break; - - default: - if (lang_expand_stmt) - (*lang_expand_stmt) (t); - else - abort (); - break; - } - - /* Go on to the next statement in this scope. */ - t = TREE_CHAIN (t); - - process_t: - /* Restore saved state. */ - current_stmt_tree ()->stmts_are_full_exprs_p - = saved_stmts_are_full_exprs_p; - } -} - -/* If *TP is a potentially reachable label, return nonzero. */ - -static tree -find_reachable_label_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - switch (TREE_CODE (*tp)) - { - case LABEL_STMT: - case CASE_LABEL: - return *tp; - - default: - break; - } - return NULL_TREE; -} - -/* Determine whether expression EXP contains a potentially - reachable label. */ -static tree -find_reachable_label (tree exp) -{ - location_t saved_loc = input_location; - tree ret = walk_tree_without_duplicates - (&exp, find_reachable_label_1, NULL); - input_location = saved_loc; - return ret; -} - -/* Expand an unreachable if statement, T. This function returns - true if the IF_STMT contains a potentially reachable code_label. */ -static bool -expand_unreachable_if_stmt (tree t) -{ - tree n; - - if (find_reachable_label (IF_COND (t)) != NULL_TREE) - { - genrtl_if_stmt (t); - return true; - } - - if (THEN_CLAUSE (t) && ELSE_CLAUSE (t)) - { - n = expand_unreachable_stmt (THEN_CLAUSE (t), 0); - - if (n != NULL_TREE) - { - rtx label; - expand_stmt (n); - label = gen_label_rtx (); - emit_jump (label); - expand_stmt (expand_unreachable_stmt (ELSE_CLAUSE (t), 0)); - emit_label (label); - return true; - } - else - n = expand_unreachable_stmt (ELSE_CLAUSE (t), 0); - } - else if (THEN_CLAUSE (t)) - n = expand_unreachable_stmt (THEN_CLAUSE (t), 0); - else if (ELSE_CLAUSE (t)) - n = expand_unreachable_stmt (ELSE_CLAUSE (t), 0); - else - n = NULL_TREE; - - expand_stmt (n); - - return n != NULL_TREE; -} - -/* Expand an unreachable statement list. This function skips all - statements preceding the first potentially reachable label and - then returns the label (or, in same cases, the statement after - one containing the label). */ -static tree -expand_unreachable_stmt (tree t, int warn) -{ - int saved; - - while (t && t != error_mark_node) - { - if (warn) - switch (TREE_CODE (t)) - { - case BREAK_STMT: - case CONTINUE_STMT: - case EXPR_STMT: - case GOTO_STMT: - case IF_STMT: - case RETURN_STMT: - if (!STMT_LINENO_FOR_FN_P (t)) - input_line = STMT_LINENO (t); - warning("will never be executed"); - warn = false; - break; - - default: - break; - } - - switch (TREE_CODE (t)) - { - case GOTO_STMT: - case CONTINUE_STMT: - case BREAK_STMT: - break; - - case FILE_STMT: - input_filename = FILE_STMT_FILENAME (t); - break; - - case RETURN_STMT: - if (find_reachable_label (RETURN_STMT_EXPR (t)) != NULL_TREE) - return t; - break; - - case EXPR_STMT: - if (find_reachable_label (EXPR_STMT_EXPR (t)) != NULL_TREE) - return t; - break; - - case IF_STMT: - if (expand_unreachable_if_stmt (t)) - return TREE_CHAIN (t); - break; - - case WHILE_STMT: - /* If the start of a while statement is unreachable, there is - no need to rotate the loop, instead the WHILE_STMT can be - expanded like a DO_STMT. */ - genrtl_do_stmt_1 (WHILE_COND (t), WHILE_BODY (t)); - return TREE_CHAIN (t); - - case COMPOUND_STMT: - { - tree n; - n = expand_unreachable_stmt (COMPOUND_BODY (t), warn); - if (n != NULL_TREE) - { - expand_stmt (n); - return TREE_CHAIN (t); - } - warn = false; - break; - } - - case SCOPE_STMT: - saved = stmts_are_full_exprs_p (); - prep_stmt (t); - genrtl_scope_stmt (t); - current_stmt_tree ()->stmts_are_full_exprs_p = saved; - break; - - default: - return t; - } - t = TREE_CHAIN (t); - } - return NULL_TREE; -} diff --git a/gcc/c-simplify.c b/gcc/c-simplify.c new file mode 100644 index 00000000000..bd50b5e025b --- /dev/null +++ b/gcc/c-simplify.c @@ -0,0 +1,1102 @@ +/* Tree lowering pass. This pass gimplifies the tree representation built + by the C-based front ends. The structure of gimplified, or + language-independent, trees is dictated by the grammar described in this + file. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Lowering of expressions contributed by Sebastian Pop + Re-written to support lowering of whole function trees, documentation + and miscellaneous cleanups by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "errors.h" +#include "varray.h" +#include "c-tree.h" +#include "c-common.h" +#include "tree-simple.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "flags.h" +#include "rtl.h" +#include "toplev.h" +#include "tree-dump.h" +#include "c-pretty-print.h" +#include "cgraph.h" + + +/* The gimplification pass converts the language-dependent trees + (ld-trees) emitted by the parser into language-independent trees + (li-trees) that are the target of SSA analysis and transformations. + + Language-independent trees are based on the SIMPLE intermediate + representation used in the McCAT compiler framework: + + "Designing the McCAT Compiler Based on a Family of Structured + Intermediate Representations," + L. Hendren, C. Donawa, M. Emami, G. Gao, Justiani, and B. Sridharan, + Proceedings of the 5th International Workshop on Languages and + Compilers for Parallel Computing, no. 757 in Lecture Notes in + Computer Science, New Haven, Connecticut, pp. 406-420, + Springer-Verlag, August 3-5, 1992. + + http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html + + Basically, we walk down gimplifying the nodes that we encounter. As we + walk back up, we check that they fit our constraints, and copy them + into temporaries if not. */ + +/* Local declarations. */ + +static enum gimplify_status gimplify_expr_stmt (tree *); +static enum gimplify_status gimplify_decl_stmt (tree *); +static enum gimplify_status gimplify_for_stmt (tree *, tree *); +static enum gimplify_status gimplify_while_stmt (tree *); +static enum gimplify_status gimplify_do_stmt (tree *); +static enum gimplify_status gimplify_if_stmt (tree *); +static enum gimplify_status gimplify_switch_stmt (tree *); +static enum gimplify_status gimplify_return_stmt (tree *); +static enum gimplify_status gimplify_stmt_expr (tree *); +static enum gimplify_status gimplify_compound_literal_expr (tree *); +#if defined ENABLE_CHECKING +static int is_last_stmt_of_scope (tree); +#endif +static enum gimplify_status gimplify_block (tree *, tree *); +static enum gimplify_status gimplify_cleanup (tree *, tree *); +static tree gimplify_c_loop (tree, tree, tree, bool); +static void push_context (void); +static void pop_context (void); +static tree c_build_bind_expr (tree, tree); +static void add_block_to_enclosing (tree); +static void gimplify_condition (tree *); + +enum bc_t { bc_break = 0, bc_continue = 1 }; +static tree begin_bc_block (enum bc_t); +static tree finish_bc_block (tree, tree); +static tree build_bc_goto (enum bc_t); + +static struct c_gimplify_ctx +{ + /* For handling break and continue. */ + tree current_bc_label; + tree bc_id[2]; +} *ctxp; + +static void +push_context (void) +{ + if (ctxp) + abort (); + ctxp = (struct c_gimplify_ctx *) xcalloc (1, sizeof (struct c_gimplify_ctx)); + ctxp->bc_id[bc_continue] = get_identifier ("continue"); + ctxp->bc_id[bc_break] = get_identifier ("break"); +} + +static void +pop_context (void) +{ + if (!ctxp || ctxp->current_bc_label) + abort (); + free (ctxp); + ctxp = NULL; +} + +/* Gimplification of statement trees. */ + +/* Convert the tree representation of FNDECL from C frontend trees to + GENERIC. */ + +void +c_genericize (tree fndecl) +{ + FILE *dump_file; + int local_dump_flags; + struct cgraph_node *cgn; + + /* Dump the C-specific tree IR. */ + dump_file = dump_begin (TDI_original, &local_dump_flags); + if (dump_file) + { + fprintf (dump_file, "\n;; Function %s", + (*lang_hooks.decl_printable_name) (fndecl, 2)); + fprintf (dump_file, " (%s)\n", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))); + fprintf (dump_file, ";; enabled by -%s\n", dump_flag_name (TDI_original)); + fprintf (dump_file, "\n"); + + if (local_dump_flags & TDF_RAW) + dump_node (DECL_SAVED_TREE (fndecl), + TDF_SLIM | local_dump_flags, dump_file); + else + print_c_tree (dump_file, DECL_SAVED_TREE (fndecl)); + fprintf (dump_file, "\n"); + + dump_end (TDI_original, dump_file); + } + + /* Go ahead and gimplify for now. */ + push_context (); + gimplify_function_tree (fndecl); + pop_context (); + + /* Dump the genericized tree IR. */ + dump_function (TDI_generic, fndecl); + + /* Genericize all nested functions now. We do things in this order so + that items like VLA sizes are expanded properly in the context of + the correct function. */ + cgn = cgraph_node (fndecl); + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + c_genericize (cgn->decl); +} + +/* Entry point for the tree lowering pass. Recursively scan + *STMT_P and convert it to a GIMPLE tree. */ + +int +c_gimplify_stmt (tree *stmt_p) +{ + tree stmt, next; + tree outer_pre = NULL_TREE; + + /* PRE and POST are tree chains that contain the side-effects of the + gimplified tree. For instance, given the expression tree: + + c = ++a * 3 + b++; + + After gimplification, the tree will be re-written as: + + a = a + 1; + t1 = a * 3; <-- PRE + c = t1 + b; + b = b + 1; <-- POST */ + + for (stmt = *stmt_p; stmt && stmt != error_mark_node; stmt = next) + { + tree pre, post; + int saved_stmts_are_full_exprs_p; + location_t stmt_locus; + enum gimplify_status ret; + + /* Set up context appropriately for handling this statement. */ + saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); + prep_stmt (stmt); + stmt_locus = input_location; + + pre = NULL_TREE; + post = NULL_TREE; + + next = TREE_CHAIN (stmt); + + switch (TREE_CODE (stmt)) + { + case COMPOUND_STMT: + stmt = COMPOUND_BODY (stmt); + ret = GS_OK; + break; + + case SCOPE_STMT: + ret = gimplify_block (&stmt, &next); + break; + + case FOR_STMT: + ret = gimplify_for_stmt (&stmt, &next); + break; + + case WHILE_STMT: + ret = gimplify_while_stmt (&stmt); + break; + + case DO_STMT: + ret = gimplify_do_stmt (&stmt); + break; + + case IF_STMT: + ret = gimplify_if_stmt (&stmt); + break; + + case SWITCH_STMT: + ret = gimplify_switch_stmt (&stmt); + break; + + case EXPR_STMT: + ret = gimplify_expr_stmt (&stmt); + break; + + case RETURN_STMT: + ret = gimplify_return_stmt (&stmt); + break; + + case DECL_STMT: + ret = gimplify_decl_stmt (&stmt); + break; + + case LABEL_STMT: + stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt)); + ret = GS_OK; + break; + + case GOTO_STMT: + stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt)); + ret = GS_OK; + break; + + case CASE_LABEL: + { + tree label = create_artificial_label (); + stmt = build (CASE_LABEL_EXPR, void_type_node, + CASE_LOW (stmt), CASE_HIGH (stmt), label); + ret = GS_OK; + } + break; + + case CONTINUE_STMT: + stmt = build_bc_goto (bc_continue); + ret = GS_OK; + break; + + case BREAK_STMT: + stmt = build_bc_goto (bc_break); + ret = GS_OK; + break; + + case CLEANUP_STMT: + ret = gimplify_cleanup (&stmt, &next); + break; + + case ASM_STMT: + { + tree new_stmt = build (ASM_EXPR, void_type_node, ASM_STRING (stmt), + ASM_OUTPUTS (stmt), ASM_INPUTS (stmt), + ASM_CLOBBERS (stmt)); + ASM_INPUT_P (new_stmt) = ASM_INPUT_P (stmt); + ASM_VOLATILE_P (new_stmt) = ASM_VOLATILE_P (stmt); + stmt = new_stmt; + ret = GS_OK; + } + break; + + default: + if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt, &next)) + { + ret = GS_OK; + break; + } + + fprintf (stderr, "unhandled statement node in c_gimplify_stmt:\n"); + debug_tree (stmt); + abort (); + break; + } + + switch (ret) + { + case GS_ERROR: + goto cont; + case GS_OK: + gimplify_stmt (&stmt); + break; + case GS_ALL_DONE: + break; + default: + abort (); + } + + /* PRE and POST now contain a list of statements for all the + side-effects in STMT. */ + + append_to_statement_list (stmt, &pre); + append_to_statement_list (post, &pre); + annotate_all_with_locus (&pre, stmt_locus); + + append_to_statement_list (pre, &outer_pre); + cont: + /* Restore saved state. */ + current_stmt_tree ()->stmts_are_full_exprs_p + = saved_stmts_are_full_exprs_p; + } + append_to_statement_list (stmt, &outer_pre); + *stmt_p = outer_pre; + + return GS_ALL_DONE; +} + +static void +add_block_to_enclosing (tree block) +{ + tree enclosing; + + for (enclosing = gimple_current_bind_expr (); + enclosing; enclosing = TREE_CHAIN (enclosing)) + if (BIND_EXPR_BLOCK (enclosing)) + break; + + enclosing = BIND_EXPR_BLOCK (enclosing); + BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block); +} + +/* Genericize a scope by creating a new BIND_EXPR. + BLOCK is either a BLOCK representing the scope or a chain of _DECLs. + In the latter case, we need to create a new BLOCK and add it to the + BLOCK_SUBBLOCKS of the enclosing block. + BODY is a chain of C _STMT nodes for the contents of the scope, to be + genericized. */ + +static tree +c_build_bind_expr (tree block, tree body) +{ + tree decls, bind; + + if (block == NULL_TREE) + decls = NULL_TREE; + else if (TREE_CODE (block) == BLOCK) + decls = BLOCK_VARS (block); + else + { + decls = block; + if (DECL_ARTIFICIAL (decls)) + block = NULL_TREE; + else + { + block = make_node (BLOCK); + BLOCK_VARS (block) = decls; + add_block_to_enclosing (block); + } + } + + if (!body) + body = build_empty_stmt (); + + bind = build (BIND_EXPR, void_type_node, decls, body, block); + TREE_SIDE_EFFECTS (bind) = 1; + + return bind; +} + +/* Genericize a syntactic block by removing the bracketing SCOPE_STMTs and + wrapping the intervening code in a BIND_EXPR. This function assumes + that matching SCOPE_STMTs will always appear in the same statement + sequence. */ + +static enum gimplify_status +gimplify_block (tree *stmt_p, tree *next_p) +{ + tree *p; + tree block; + tree bind; + int depth; + location_t stmt_locus; + + if (!SCOPE_BEGIN_P (*stmt_p)) + { + /* Can wind up mismatched with syntax errors. */ + if (!errorcount && !sorrycount) + abort (); + *stmt_p = NULL; + return GS_ERROR; + } + + block = SCOPE_STMT_BLOCK (*stmt_p); + + /* Find the matching ending SCOPE_STMT. */ + depth = 1; + for (p = &TREE_CHAIN (*stmt_p);; p = &TREE_CHAIN (*p)) + { + if (*p == NULL) + break; + if (TREE_CODE (*p) == SCOPE_STMT) + { + if (SCOPE_BEGIN_P (*p)) + ++depth; + else if (--depth == 0) + break; + } + } + + stmt_locus = input_location; + if (*p) + { + if (SCOPE_STMT_BLOCK (*p) != block) + abort (); + if (EXPR_LOCUS (*p)) + stmt_locus = *EXPR_LOCUS (*p); + *next_p = TREE_CHAIN (*p); + *p = NULL_TREE; + } + else + { + /* Can wind up mismatched with syntax errors. */ + if (!errorcount && !sorrycount) + abort (); + } + + bind = c_build_bind_expr (block, TREE_CHAIN (*stmt_p)); + *stmt_p = bind; + input_location = stmt_locus; + + return GS_OK; +} + +/* Genericize a CLEANUP_STMT. Just wrap everything from here to the end of + the block in a TRY_FINALLY_EXPR. Or a TRY_CATCH_EXPR, if it's an + EH-only cleanup. */ + +static enum gimplify_status +gimplify_cleanup (tree *stmt_p, tree *next_p) +{ + tree stmt = *stmt_p; + tree body = TREE_CHAIN (stmt); + tree cleanup = CLEANUP_EXPR (stmt); + enum tree_code code + = (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR); + + if (!body) + body = build_empty_stmt (); + if (!cleanup) + cleanup = build_empty_stmt (); + + *stmt_p = build (code, void_type_node, body, cleanup); + *next_p = NULL_TREE; + + return GS_OK; +} + +/* Gimplify an EXPR_STMT node. + + STMT is the statement node. + + PRE_P points to the list where side effects that must happen before + STMT should be stored. + + POST_P points to the list where side effects that must happen after + STMT should be stored. */ + +static enum gimplify_status +gimplify_expr_stmt (tree *stmt_p) +{ + tree stmt = EXPR_STMT_EXPR (*stmt_p); + + if (stmt == error_mark_node) + stmt = NULL; + + /* Gimplification of a statement expression will nullify the + statement if all its side effects are moved to *PRE_P and *POST_P. + + In this case we will not want to emit the gimplified statement. + However, we may still want to emit a warning, so we do that before + gimplification. */ + if (stmt && (extra_warnings || warn_unused_value)) + { + if (!TREE_SIDE_EFFECTS (stmt)) + { + if (!IS_EMPTY_STMT (stmt) + && !VOID_TYPE_P (TREE_TYPE (stmt)) + && !TREE_NO_WARNING (stmt)) + warning ("statement with no effect"); + } + else if (warn_unused_value) + { + /* Kludge for 20020220-2.c. warn_if_unused_value shouldn't use + the stmt file location info. */ + set_file_and_line_for_stmt (input_location); + warn_if_unused_value (stmt); + } + } + + if (stmt == NULL_TREE) + stmt = build_empty_stmt (); + else if (stmts_are_full_exprs_p ()) + stmt = build1 (CLEANUP_POINT_EXPR, void_type_node, stmt); + + *stmt_p = stmt; + + return GS_OK; +} + +/* If the condition for a loop (or the like) is a decl, it will be a + TREE_LIST where the TREE_PURPOSE is a DECL_STMT and the TREE_VALUE is + a use of the decl. Turn such a thing into a COMPOUND_EXPR. */ + +static void +gimplify_condition (tree *cond_p) +{ + tree cond = *cond_p; + if (cond && TREE_CODE (cond) == TREE_LIST) + { + tree decl = TREE_PURPOSE (cond); + tree value = TREE_VALUE (cond); + c_gimplify_stmt (&decl); + *cond_p = build (COMPOUND_EXPR, TREE_TYPE (value), decl, value); + } +} + +/* Begin a scope which can be exited by a break or continue statement. BC + indicates which. + + Just creates a label and pushes it into the current context. */ + +static tree +begin_bc_block (enum bc_t bc) +{ + tree label = create_artificial_label (); + DECL_NAME (label) = ctxp->bc_id[bc]; + TREE_CHAIN (label) = ctxp->current_bc_label; + ctxp->current_bc_label = label; + return label; +} + +/* Finish a scope which can be exited by a break or continue statement. + LABEL was returned from the most recent call to begin_bc_block. BODY is + an expression for the contents of the scope. + + If we saw a break (or continue) in the scope, append a LABEL_EXPR to + body. Otherwise, just forget the label. */ + +static tree +finish_bc_block (tree label, tree body) +{ + if (label != ctxp->current_bc_label) + abort (); + + if (TREE_USED (label)) + { + tree t, sl = NULL; + + /* Clear the name so flow can delete the label. */ + DECL_NAME (label) = NULL_TREE; + t = build1 (LABEL_EXPR, void_type_node, label); + + append_to_statement_list (body, &sl); + append_to_statement_list (t, &sl); + body = sl; + } + + ctxp->current_bc_label = TREE_CHAIN (label); + TREE_CHAIN (label) = NULL_TREE; + return body; +} + +/* Build a GOTO_EXPR to represent a break or continue statement. BC + indicates which. */ + +static tree +build_bc_goto (enum bc_t bc) +{ + tree label; + tree target_name = ctxp->bc_id[bc]; + + /* Look for the appropriate type of label. */ + for (label = ctxp->current_bc_label; + label; + label = TREE_CHAIN (label)) + if (DECL_NAME (label) == target_name) + break; + + if (label == NULL_TREE) + { + if (bc == bc_break) + error ("break statement not within loop or switch"); + else + error ("continue statement not within loop or switch"); + + return NULL_TREE; + } + + /* Mark the label used for finish_bc_block. */ + TREE_USED (label) = 1; + return build1 (GOTO_EXPR, void_type_node, label); +} + +/* Build a generic representation of one of the C loop forms. COND is the + loop condition or NULL_TREE. BODY is the (possibly compound) statement + controlled by the loop. INCR is the increment expression of a for-loop, + or NULL_TREE. COND_IS_FIRST indicates whether the condition is + evaluated before the loop body as in while and for loops, or after the + loop body as in do-while loops. */ + +static tree +gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first) +{ + tree top, entry, exit, cont_block, break_block, stmt_list, t; + location_t stmt_locus; + + stmt_locus = input_location; + + /* Detect do { ... } while (0) and don't generate loop construct. */ + if (!cond_is_first && cond && integer_zerop (cond)) + top = cond = NULL; + else + { + /* If we use a LOOP_EXPR here, we have to feed the whole thing + back through the main gimplifier to lower it. Given that we + have to gimplify the loop body NOW so that we can resolve + break/continue stmts, seems easier to just expand to gotos. */ + top = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + } + + break_block = begin_bc_block (bc_break); + + if (top) + { + /* If we have an exit condition, then we build an IF with gotos either + out of the loop, or to the top of it. If there's no exit condition, + then we just build a jump back to the top. */ + exit = build_and_jump (&LABEL_EXPR_LABEL (top)); + if (cond) + { + gimplify_condition (&cond); + t = build_bc_goto (bc_break); + exit = build (COND_EXPR, void_type_node, cond, exit, t); + exit = fold (exit); + gimplify_stmt (&exit); + } + } + else + exit = NULL_TREE; + + cont_block = begin_bc_block (bc_continue); + + gimplify_stmt (&body); + if (incr && stmts_are_full_exprs_p ()) + incr = fold (build1 (CLEANUP_POINT_EXPR, void_type_node, incr)); + gimplify_stmt (&incr); + + body = finish_bc_block (cont_block, body); + + stmt_list = NULL; + + if (cond_is_first && cond) + { + entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + t = build_and_jump (&LABEL_EXPR_LABEL (entry)); + append_to_statement_list (t, &stmt_list); + } + else + entry = NULL_TREE; + + append_to_statement_list (top, &stmt_list); + append_to_statement_list (body, &stmt_list); + append_to_statement_list (incr, &stmt_list); + append_to_statement_list (entry, &stmt_list); + append_to_statement_list (exit, &stmt_list); + + annotate_all_with_locus (&stmt_list, stmt_locus); + + return finish_bc_block (break_block, stmt_list); +} + +/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the + prequeue and hand off to gimplify_c_loop. */ + +static enum gimplify_status +gimplify_for_stmt (tree *stmt_p, tree *next_p) +{ + tree stmt = *stmt_p; + tree init = FOR_INIT_STMT (stmt); + + if (init) + { + /* Reorganize the statements so that we do the right thing with a + CLEANUP_STMT. We want the FOR_STMT and nothing else to be in the + scope of the cleanup, so play with pointers to accomplish that. */ + FOR_INIT_STMT (stmt) = NULL_TREE; + chainon (init, stmt); + *stmt_p = init; + *next_p = TREE_CHAIN (stmt); + TREE_CHAIN (stmt) = NULL_TREE; + c_gimplify_stmt (stmt_p); + } + else + *stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt), + FOR_EXPR (stmt), 1); + + return GS_ALL_DONE; +} + +/* Gimplify a WHILE_STMT node. */ + +static enum gimplify_status +gimplify_while_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + *stmt_p = gimplify_c_loop (WHILE_COND (stmt), WHILE_BODY (stmt), + NULL_TREE, 1); + return GS_ALL_DONE; +} + +/* Gimplify a DO_STMT node. */ + +static enum gimplify_status +gimplify_do_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + *stmt_p = gimplify_c_loop (DO_COND (stmt), DO_BODY (stmt), + NULL_TREE, 0); + return GS_ALL_DONE; +} + +/* Genericize an IF_STMT by turning it into a COND_EXPR. */ + +static enum gimplify_status +gimplify_if_stmt (tree *stmt_p) +{ + tree stmt, then_, else_; + + stmt = *stmt_p; + restart: + then_ = THEN_CLAUSE (stmt); + else_ = ELSE_CLAUSE (stmt); + + if (!then_) + then_ = build_empty_stmt (); + if (!else_) + else_ = build_empty_stmt (); + + stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_); + gimplify_condition (& TREE_OPERAND (stmt, 0)); + *stmt_p = stmt; + + /* Handle properly nested if-else chains via iteration instead of + mutual recursion between gimplify.c and c-simplify.c. */ + annotate_with_locus (stmt, input_location); + if (TREE_CODE (else_) == IF_STMT && !TREE_CHAIN (else_)) + { + stmt_p = &COND_EXPR_ELSE (stmt); + stmt = else_; + prep_stmt (stmt); + goto restart; + } + + return GS_OK; +} + +/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */ + +static enum gimplify_status +gimplify_switch_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + tree break_block, body; + location_t stmt_locus = input_location; + + break_block = begin_bc_block (bc_break); + + gimplify_condition (&SWITCH_COND (stmt)); + + body = SWITCH_BODY (stmt); + if (!body) + body = build_empty_stmt (); + + *stmt_p = build (SWITCH_EXPR, SWITCH_TYPE (stmt), SWITCH_COND (stmt), + body, NULL_TREE); + annotate_with_locus (*stmt_p, stmt_locus); + gimplify_stmt (stmt_p); + + *stmt_p = finish_bc_block (break_block, *stmt_p); + return GS_ALL_DONE; +} + +/* Genericize a RETURN_STMT by turning it into a RETURN_EXPR. */ + +static enum gimplify_status +gimplify_return_stmt (tree *stmt_p) +{ + tree expr = RETURN_STMT_EXPR (*stmt_p); + expr = build1 (RETURN_EXPR, void_type_node, expr); + if (stmts_are_full_exprs_p ()) + expr = build1 (CLEANUP_POINT_EXPR, void_type_node, expr); + *stmt_p = expr; + return GS_OK; +} + +/* Gimplifies a DECL_STMT node T. + + If a declaration V has an initial value I, create an expression 'V = I' + and insert it after the DECL_STMT. + + PRE_P is a queue for effects that should happen before the DECL_STMT. + + MID_P is a queue for effects that should happen after the DECL_STMT, + but before uses of the initialized decl. + + POST_P is a queue for effects that should happen after uses of the + initialized decl. + + Usually these last two will be the same, but they may need to be + different if the DECL_STMT is somehow embedded in an expression. */ + +static enum gimplify_status +gimplify_decl_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + tree decl = DECL_STMT_DECL (stmt); + tree pre = NULL_TREE; + tree post = NULL_TREE; + + if (TREE_TYPE (decl) == error_mark_node) + { + *stmt_p = NULL; + return GS_ERROR; + } + + if (TREE_CODE (decl) == TYPE_DECL) + { + tree type = TREE_TYPE (decl); + if (TYPE_SIZE_UNIT (type) + && !TREE_CONSTANT (TYPE_SIZE_UNIT (type))) + { + /* This is a variable-sized array type. Simplify its size. */ + tree temp = TYPE_SIZE_UNIT (type); + gimplify_expr (&temp, &pre, &post, is_gimple_val, fb_rvalue); + } + } + + if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) + { + tree init = DECL_INITIAL (decl); + + if (!TREE_CONSTANT (DECL_SIZE (decl))) + { + tree pt_type = build_pointer_type (TREE_TYPE (decl)); + tree alloc, size; + + /* This is a variable-sized decl. Simplify its size and mark it + for deferred expansion. Note that mudflap depends on the format + of the emitted code: see mx_register_decls(). */ + + size = get_initialized_tmp_var (DECL_SIZE_UNIT (decl), &pre, &post); + DECL_DEFER_OUTPUT (decl) = 1; + alloc = build_function_call_expr + (implicit_built_in_decls[BUILT_IN_STACK_ALLOC], + tree_cons (NULL_TREE, + build1 (ADDR_EXPR, pt_type, decl), + tree_cons (NULL_TREE, size, NULL_TREE))); + append_to_compound_expr (alloc, &pre); + } + + if (init && init != error_mark_node) + { + if (!TREE_STATIC (decl)) + { + /* Do not warn about int x = x; as it is a GCC extension + to turn off this warning but only if warn_init_self + is zero. */ + if (init == decl && !warn_init_self) + TREE_NO_WARNING (decl) = 1; + + DECL_INITIAL (decl) = NULL_TREE; + init = build (MODIFY_EXPR, void_type_node, decl, init); + if (stmts_are_full_exprs_p ()) + init = build1 (CLEANUP_POINT_EXPR, void_type_node, init); + append_to_compound_expr (init, &pre); + } + else + { + /* We must still examine initializers for static variables + as they may contain a label address. */ + walk_tree (&init, force_labels_r, NULL, NULL); + } + } + + /* This decl isn't mentioned in the enclosing block, so add it to the + list of temps. FIXME it seems a bit of a kludge to say that + anonymous artificial vars aren't pushed, but everything else is. */ + if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE) + gimple_add_tmp_var (decl); + } + + append_to_compound_expr (post, &pre); + *stmt_p = pre; + return GS_OK; +} + +/* Gimplification of expression trees. */ + +/* Gimplify a C99 compound literal expression. This just means adding the + DECL_STMT before the current EXPR_STMT and using its anonymous decl + instead. */ + +static enum gimplify_status +gimplify_compound_literal_expr (tree *expr_p) +{ + tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p); + tree decl = DECL_STMT_DECL (decl_s); + + /* This decl isn't mentioned in the enclosing block, so add it to the + list of temps. FIXME it seems a bit of a kludge to say that + anonymous artificial vars aren't pushed, but everything else is. */ + if (DECL_NAME (decl) == NULL_TREE) + gimple_add_tmp_var (decl); + + gimplify_decl_stmt (&decl_s); + *expr_p = decl_s ? decl_s : decl; + return GS_OK; +} + +/* Do C-specific gimplification. Args are as for gimplify_expr. */ + +int +c_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, + tree *post_p ATTRIBUTE_UNUSED) +{ + enum tree_code code = TREE_CODE (*expr_p); + + if (STATEMENT_CODE_P (code)) + return c_gimplify_stmt (expr_p); + + switch (code) + { + case COMPOUND_LITERAL_EXPR: + return gimplify_compound_literal_expr (expr_p); + + case STMT_EXPR: + return gimplify_stmt_expr (expr_p); + + default: + return GS_UNHANDLED; + } +} + +/* Returns the final EXPR_STMT which represents the return value of a + STMT_EXPR, or NULL_TREE if none. */ + +tree +stmt_expr_last_stmt (tree stmt_expr) +{ + tree body = STMT_EXPR_STMT (stmt_expr); + tree last_stmt, substmt; + + /* Splice the last expression out of the STMT chain. */ + last_stmt = NULL_TREE; + for (substmt = COMPOUND_BODY (body); substmt; + substmt = TREE_CHAIN (substmt)) + if (TREE_CODE (substmt) != SCOPE_STMT) + last_stmt = substmt; + + if (last_stmt == NULL_TREE + || TREE_CODE (last_stmt) != EXPR_STMT + || (TREE_TYPE (last_stmt) + && VOID_TYPE_P (TREE_TYPE (last_stmt)))) + { + location_t loc; + if (last_stmt && EXPR_LOCUS (last_stmt)) + loc = *EXPR_LOCUS (last_stmt); + else if (EXPR_LOCUS (stmt_expr)) + loc = *EXPR_LOCUS (stmt_expr); + else + loc = input_location; + warning ("%Hstatement-expressions should end with a " + "non-void expression", &loc); + last_stmt = NULL_TREE; + } + +#if defined ENABLE_CHECKING + if (last_stmt && !is_last_stmt_of_scope (last_stmt)) + abort (); +#endif + + return last_stmt; +} + +/* Gimplify a STMT_EXPR. EXPR_P points to the expression to gimplify. + After gimplification, if the STMT_EXPR returns a value, EXPR_P will + point to a new temporary that holds that value; otherwise it will be + null. + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_stmt_expr (tree *expr_p) +{ + tree body = STMT_EXPR_STMT (*expr_p); + + if (VOID_TYPE_P (TREE_TYPE (*expr_p))) + { + *expr_p = body; + return c_gimplify_stmt (expr_p); + } + else + { + tree last_stmt = stmt_expr_last_stmt (*expr_p); + tree last_expr = NULL_TREE; + + if (last_stmt) + { + last_expr = EXPR_STMT_EXPR (last_stmt); + + if (stmts_are_full_exprs_p ()) + last_expr = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (last_expr), + last_expr); + EXPR_STMT_EXPR (last_stmt) = NULL_TREE; + } + + /* Genericize the block. */ + c_gimplify_stmt (&body); + + /* Now retrofit that last expression into the BIND_EXPR. */ + if (last_expr) + { + tree *sub_p; + + if (!STMT_EXPR_NO_SCOPE (*expr_p)) + { + /* Our BIND_EXPR will always be hidden within + a STATEMENT_LIST. Discard that. */ + body = expr_first (body); + sub_p = &BIND_EXPR_BODY (body); + + /* Append the last expression to the end of the BIND_EXPR. + We'll now re-process this, and let voidify_wrapper_expr + do its job. */ + append_to_statement_list_force (last_expr, sub_p); + TREE_TYPE (body) = TREE_TYPE (last_expr); + } + else + append_to_compound_expr (last_expr, &body); + } + + *expr_p = body; + return GS_OK; + } +} + +/* Code generation. */ + +/* Miscellaneous helpers. */ + +#if defined ENABLE_CHECKING +/* Return nonzero if STMT is the last statement of its scope. */ + +static int +is_last_stmt_of_scope (tree stmt) +{ + return (TREE_CHAIN (stmt) == NULL_TREE + || (TREE_CODE (TREE_CHAIN (stmt)) == SCOPE_STMT + && SCOPE_END_P (TREE_CHAIN (stmt)))); +} +#endif diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 01f86e999f2..da41c3a5c7a 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -29,6 +29,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #define C_SIZEOF_STRUCT_LANG_IDENTIFIER \ (sizeof (struct c_common_identifier) + 3 * sizeof (void *)) +/* For gc purposes, return the most likely link for the longest chain. */ +#define C_LANG_TREE_NODE_CHAIN_NEXT(T) \ + ((union lang_tree_node *) \ + (TREE_CODE (T) == INTEGER_TYPE ? TYPE_NEXT_VARIANT (T) \ + : TREE_CODE (T) == COMPOUND_EXPR ? TREE_OPERAND (T, 1) \ + : TREE_CHAIN (T))) + /* Language-specific declaration information. */ struct lang_decl GTY(()) @@ -58,10 +65,13 @@ struct lang_decl GTY(()) and C_RID_YYCODE is the token number wanted by Yacc. */ #define C_IS_RESERVED_WORD(ID) TREE_LANG_FLAG_0 (ID) -/* In a RECORD_TYPE, a sorted array of the fields of the type. */ struct lang_type GTY(()) { + /* In a RECORD_TYPE, a sorted array of the fields of the type. */ struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields"))) s; + /* In an ENUMERAL_TYPE, the min and max values. */ + tree enum_min; + tree enum_max; }; /* Record whether a type or decl was written with nonconstant size. @@ -182,7 +192,7 @@ extern tree start_struct (enum tree_code, tree); extern void store_parm_decls (void); extern tree xref_tag (enum tree_code, tree); extern tree c_begin_compound_stmt (void); -extern void c_expand_decl_stmt (tree); +extern int c_expand_decl (tree); extern void c_static_assembler_name (tree); extern tree make_pointer_declarator (tree, tree); @@ -190,8 +200,8 @@ extern tree make_pointer_declarator (tree, tree); extern int c_disregard_inline_limits (tree); extern int c_cannot_inline_tree_fn (tree *); extern bool c_objc_common_init (void); +extern bool c_missing_noreturn_ok_p (tree); extern tree c_objc_common_truthvalue_conversion (tree expr); -extern int c_missing_noreturn_ok_p (tree); extern void c_objc_common_finish_file (void); extern int defer_fn (tree); extern bool c_warn_unused_global_decl (tree); @@ -248,6 +258,7 @@ extern void c_finish_case (void); extern tree build_asm_expr (tree, tree, tree, tree, bool); extern tree build_asm_stmt (tree, tree); extern tree c_convert_parm_for_inlining (tree, tree, tree, int); +extern int c_types_compatible_p (tree, tree); /* Set to 0 at beginning of a function definition, set to 1 if a return statement that specifies a return value is seen. */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index c744cd6b131..14270b971ca 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -687,7 +687,9 @@ tagged_types_tu_compatible_p (tree t1, tree t2, int flags) /* We have to verify that the tags of the types are the same. This is harder than it looks because this may be a typedef, so we have to go look at the original type. It may even be a typedef of a - typedef... */ + typedef... + In the case of compiler-created builtin structs the TYPE_DECL + may be a dummy, with no DECL_ORIGINAL_TYPE. Don't fault. */ while (TYPE_NAME (t1) && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL && DECL_ORIGINAL_TYPE (TYPE_NAME (t1))) @@ -1143,7 +1145,6 @@ default_function_array_conversion (tree exp) adr = build1 (ADDR_EXPR, ptrtype, exp); if (!c_mark_addressable (exp)) return error_mark_node; - TREE_CONSTANT (adr) = staticp (exp); TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */ return adr; } @@ -1489,8 +1490,7 @@ build_array_ref (tree array, tree index) || TREE_TYPE (index) == error_mark_node) return error_mark_node; - if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE - && TREE_CODE (array) != INDIRECT_REF) + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) { tree rval, type; @@ -1660,6 +1660,7 @@ build_external_ref (tree id, int fun) { ref = DECL_INITIAL (ref); TREE_CONSTANT (ref) = 1; + TREE_INVARIANT (ref) = 1; } else if (current_function_decl != 0 && !DECL_FILE_SCOPE_P (current_function_decl) @@ -2088,14 +2089,12 @@ parser_build_binary_op (enum tree_code code, tree arg1, tree arg2) C_SET_EXP_ORIGINAL_CODE (result, code); else { - int flag = TREE_CONSTANT (result); /* We used to use NOP_EXPR rather than NON_LVALUE_EXPR so that convert_for_assignment wouldn't strip it. That way, we got warnings for things like p = (1 - 1). But it turns out we should not get those warnings. */ result = build1 (NON_LVALUE_EXPR, TREE_TYPE (result), result); C_SET_EXP_ORIGINAL_CODE (result, code); - TREE_CONSTANT (result) = flag; } return result; @@ -2127,7 +2126,6 @@ c_tree_expr_nonnegative_p (tree t) static tree pointer_diff (tree op0, tree op1) { - tree result, folded; tree restype = ptrdiff_type_node; tree target_type = TREE_TYPE (TREE_TYPE (op0)); @@ -2191,13 +2189,7 @@ pointer_diff (tree op0, tree op1) op1 = c_size_in_bytes (target_type); /* Divide by the size, in easiest possible way. */ - - result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1)); - - folded = fold (result); - if (folded == result) - TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); - return folded; + return fold (build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1))); } /* Construct and perhaps optimize a tree representation @@ -2420,7 +2412,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag) TREE_SIDE_EFFECTS (val) = 1; val = convert (result_type, val); if (TREE_CODE (val) != code) - TREE_NO_UNUSED_WARNING (val) = 1; + TREE_NO_WARNING (val) = 1; return val; } @@ -2492,12 +2484,6 @@ build_unary_op (enum tree_code code, tree xarg, int flag) else addr = build1 (code, argtype, arg); - /* Address of a static or external variable or - file-scope function counts as a constant. */ - if (staticp (arg) - && ! (TREE_CODE (arg) == FUNCTION_DECL - && !DECL_FILE_SCOPE_P (arg))) - TREE_CONSTANT (addr) = 1; return addr; } @@ -2933,6 +2919,7 @@ build_c_cast (tree type, tree expr) build_tree_list (field, value)), 0); TREE_CONSTANT (t) = TREE_CONSTANT (value); + TREE_INVARIANT (t) = TREE_INVARIANT (value); return t; } error ("cast to union type from type not present in union"); @@ -4758,7 +4745,7 @@ pop_init_level (int implicit) constructor = build_constructor (constructor_type, nreverse (constructor_elements)); if (constructor_constant) - TREE_CONSTANT (constructor) = 1; + TREE_CONSTANT (constructor) = TREE_INVARIANT (constructor) = 1; if (constructor_constant && constructor_simple) TREE_STATIC (constructor) = 1; } @@ -6052,8 +6039,8 @@ process_init_element (tree value) tree build_asm_stmt (tree cv_qualifier, tree args) { - if (!TREE_OPERAND (args, 0)) - TREE_OPERAND (args, 0) = cv_qualifier; + if (!ASM_VOLATILE_P (args) && cv_qualifier) + ASM_VOLATILE_P (args) = 1; return add_stmt (args); } @@ -6068,36 +6055,42 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers, { tree tail; tree args; + int i; + const char *constraint; + bool allows_mem, allows_reg, is_inout; + int ninputs; + int noutputs; + + ninputs = list_length (inputs); + noutputs = list_length (outputs); - /* We can remove output conversions that change the type, - but not the mode. */ - for (tail = outputs; tail; tail = TREE_CHAIN (tail)) + /* Remove output conversions that change the type but not the mode. */ + for (i = 0, tail = outputs; tail; ++i, tail = TREE_CHAIN (tail)) { tree output = TREE_VALUE (tail); - STRIP_NOPS (output); TREE_VALUE (tail) = output; + lvalue_or_else (output, "invalid lvalue in asm statement"); - /* Allow conversions as LHS here. build_modify_expr as called below - will do the right thing with them. */ - while (TREE_CODE (output) == NOP_EXPR - || TREE_CODE (output) == CONVERT_EXPR - || TREE_CODE (output) == FLOAT_EXPR - || TREE_CODE (output) == FIX_TRUNC_EXPR - || TREE_CODE (output) == FIX_FLOOR_EXPR - || TREE_CODE (output) == FIX_ROUND_EXPR - || TREE_CODE (output) == FIX_CEIL_EXPR) - output = TREE_OPERAND (output, 0); + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail))); - lvalue_or_else (TREE_VALUE (tail), "invalid lvalue in asm statement"); - } + if (!parse_output_constraint (&constraint, i, ninputs, noutputs, + &allows_mem, &allows_reg, &is_inout)) + { + /* By marking this operand as erroneous, we will not try + to process this operand again in expand_asm_operands. */ + TREE_VALUE (tail) = error_mark_node; + continue; + } - /* Remove output conversions that change the type but not the mode. */ - for (tail = outputs; tail; tail = TREE_CHAIN (tail)) - { - tree output = TREE_VALUE (tail); - STRIP_NOPS (output); - TREE_VALUE (tail) = output; + /* If the operand is a DECL that is going to end up in + memory, assume it is addressable. This is a bit more + conservative than it would ideally be; the exact test is + buried deep in expand_asm_operands and depends on the + DECL_RTL for the OPERAND -- which we don't have at this + point. */ + if (!allows_reg && DECL_P (output)) + c_mark_addressable (output); } /* Perform default conversions on array and function inputs. @@ -6106,12 +6099,12 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers, for (tail = inputs; tail; tail = TREE_CHAIN (tail)) TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail)); - args = build_stmt (ASM_STMT, 0, string, outputs, inputs, clobbers); + args = build_stmt (ASM_STMT, string, outputs, inputs, clobbers); /* Simple asm statements are treated as volatile. */ if (simple) { - TREE_OPERAND (args, 0) = ridpointers[RID_VOLATILE]; + ASM_VOLATILE_P (args) = 1; ASM_INPUT_P (args) = 1; } return args; @@ -6375,6 +6368,9 @@ c_finish_case (void) { struct c_switch *cs = switch_stack; + /* Emit warnings as needed. */ + c_do_switch_warnings (cs->cases, cs->switch_stmt); + /* Rechain the next statements to the SWITCH_STMT. */ last_tree = cs->switch_stmt; @@ -7103,16 +7099,14 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, { tree result = build (resultcode, build_type, op0, op1); - tree folded; /* Treat expressions in initializers specially as they can't trap. */ - folded = initializer_stack ? fold_initializer (result) + result = initializer_stack ? fold_initializer (result) : fold (result); - if (folded == result) - TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + if (final_type != 0) - return convert (final_type, folded); - return folded; + result = convert (final_type, result); + return result; } } diff --git a/gcc/c.opt b/gcc/c.opt index 83dc98de28d..bafe6a14d8b 100644 --- a/gcc/c.opt +++ b/gcc/c.opt @@ -469,10 +469,6 @@ fdollars-in-identifiers C ObjC C++ ObjC++ Permit '$' as an identifier character -fdump- -C ObjC C++ ObjC++ Joined RejectNegative --fdump- Dump various compiler internals to a file - felide-constructors C++ ObjC++ diff --git a/gcc/calls.c b/gcc/calls.c index 49be7436ae1..e15a96b9c37 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -120,7 +120,7 @@ int stack_arg_under_construction; static int calls_function (tree, int); static int calls_function_1 (tree, int); -static void emit_call_1 (rtx, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT, +static void emit_call_1 (rtx, tree, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT, rtx, rtx, int, rtx, int, CUMULATIVE_ARGS *); static void precompute_register_parameters (int, struct arg_data *, int *); @@ -134,7 +134,7 @@ static void initialize_argument_information (int, struct arg_data *, struct args_size *, int, tree, tree, CUMULATIVE_ARGS *, int, rtx *, int *, int *, int *, - bool); + bool *, bool); static void compute_argument_addresses (struct arg_data *, rtx, int); static rtx rtx_for_function_call (tree, tree); static void load_register_parameters (struct arg_data *, int, rtx *, int, @@ -142,7 +142,6 @@ static void load_register_parameters (struct arg_data *, int, rtx *, int, static rtx emit_library_call_value_1 (int, rtx, rtx, enum libcall_type, enum machine_mode, int, va_list); static int special_function_p (tree, int); -static rtx try_to_integrate (tree, tree, rtx, int, tree, rtx); static int check_sibcall_argument_overlap_1 (rtx); static int check_sibcall_argument_overlap (rtx, struct arg_data *, int); @@ -280,17 +279,11 @@ calls_function_1 (tree exp, int which) CALL_INSN_FUNCTION_USAGE information. */ rtx -prepare_call_address (rtx funexp, tree fndecl, rtx *call_fusage, - int reg_parm_seen, int sibcallp) +prepare_call_address (rtx funexp, rtx static_chain_value, + rtx *call_fusage, int reg_parm_seen, int sibcallp) { - rtx static_chain_value = 0; - funexp = protect_from_queue (funexp, 0); - if (fndecl != 0) - /* Get possible static chain value for nested function in C. */ - static_chain_value = lookup_static_chain (fndecl); - /* Make a valid memory address and copy constants through pseudo-regs, but not for a constant address if -fno-function-cse. */ if (GET_CODE (funexp) != SYMBOL_REF) @@ -362,7 +355,8 @@ prepare_call_address (rtx funexp, tree fndecl, rtx *call_fusage, denote registers used by the called function. */ static void -emit_call_1 (rtx funexp, tree fndecl ATTRIBUTE_UNUSED, tree funtype ATTRIBUTE_UNUSED, +emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED, + tree funtype ATTRIBUTE_UNUSED, HOST_WIDE_INT stack_size ATTRIBUTE_UNUSED, HOST_WIDE_INT rounded_stack_size, HOST_WIDE_INT struct_value_size ATTRIBUTE_UNUSED, @@ -506,7 +500,16 @@ emit_call_1 (rtx funexp, tree fndecl ATTRIBUTE_UNUSED, tree funtype ATTRIBUTE_UN REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, const0_rtx, REG_NOTES (call_insn)); else - note_eh_region_may_contain_throw (); + { + int rn = lookup_stmt_eh_region (fntree); + + /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't + throw, which we already took care of. */ + if (rn > 0) + REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (rn), + REG_NOTES (call_insn)); + note_current_region_may_contain_throw (); + } if (ecf_flags & ECF_NORETURN) REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_NORETURN, const0_rtx, @@ -590,8 +593,7 @@ emit_call_1 (rtx funexp, tree fndecl ATTRIBUTE_UNUSED, tree funtype ATTRIBUTE_UN static int special_function_p (tree fndecl, int flags) { - if (! (flags & ECF_MALLOC) - && fndecl && DECL_NAME (fndecl) + if (fndecl && DECL_NAME (fndecl) && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17 /* Exclude functions not at the file scope, or not `extern', since they are not the magic functions we would otherwise @@ -714,6 +716,8 @@ flags_from_decl_or_type (tree exp) if (TREE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) flags |= ECF_LIBCALL_BLOCK | ECF_CONST; + + flags = special_function_p (exp, flags); } else if (TYPE_P (exp) && TYPE_READONLY (exp) && ! TREE_THIS_VOLATILE (exp)) flags |= ECF_CONST; @@ -1012,6 +1016,9 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer flags which may may be modified by this routine. + MAY_TAILCALL is cleared if we encounter an invisible pass-by-reference + that requires allocation of stack space. + CALL_FROM_THUNK_P is true if this call is the jump from a thunk to the thunked-to function. */ @@ -1025,7 +1032,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, int reg_parm_stack_space, rtx *old_stack_level, int *old_pending_adj, int *must_preallocate, int *ecf_flags, - bool call_from_thunk_p) + bool *may_tailcall, bool call_from_thunk_p) { /* 1 if scanning parms front to back, -1 if scanning back to front. */ int inc; @@ -1138,6 +1145,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, build_pointer_type (type), args[i].tree_value); type = build_pointer_type (type); + *may_tailcall = false; } else { @@ -1177,6 +1185,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, build_pointer_type (type), make_tree (type, copy)); type = build_pointer_type (type); + *may_tailcall = false; } } @@ -1705,120 +1714,6 @@ load_register_parameters (struct arg_data *args, int num_actuals, } } -/* Try to integrate function. See expand_inline_function for documentation - about the parameters. */ - -static rtx -try_to_integrate (tree fndecl, tree actparms, rtx target, int ignore, - tree type, rtx structure_value_addr) -{ - rtx temp; - rtx before_call; - int i; - rtx old_stack_level = 0; - int reg_parm_stack_space = 0; - -#ifdef REG_PARM_STACK_SPACE - reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl); -#endif - - before_call = get_last_insn (); - - timevar_push (TV_INTEGRATION); - - temp = expand_inline_function (fndecl, actparms, target, - ignore, type, - structure_value_addr); - - timevar_pop (TV_INTEGRATION); - - /* If inlining succeeded, return. */ - if (temp != (rtx) (size_t) - 1) - { - if (ACCUMULATE_OUTGOING_ARGS) - { - /* If the outgoing argument list must be preserved, push - the stack before executing the inlined function if it - makes any calls. */ - - i = reg_parm_stack_space; - if (i > highest_outgoing_arg_in_use) - i = highest_outgoing_arg_in_use; - while (--i >= 0 && stack_usage_map[i] == 0) - ; - - if (stack_arg_under_construction || i >= 0) - { - rtx first_insn - = before_call ? NEXT_INSN (before_call) : get_insns (); - rtx insn = NULL_RTX, seq; - - /* Look for a call in the inline function code. - If DECL_STRUCT_FUNCTION (fndecl)->outgoing_args_size is - nonzero then there is a call and it is not necessary - to scan the insns. */ - - if (DECL_STRUCT_FUNCTION (fndecl)->outgoing_args_size == 0) - for (insn = first_insn; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN) - break; - - if (insn) - { - /* Reserve enough stack space so that the largest - argument list of any function call in the inline - function does not overlap the argument list being - evaluated. This is usually an overestimate because - allocate_dynamic_stack_space reserves space for an - outgoing argument list in addition to the requested - space, but there is no way to ask for stack space such - that an argument list of a certain length can be - safely constructed. - - Add the stack space reserved for register arguments, if - any, in the inline function. What is really needed is the - largest value of reg_parm_stack_space in the inline - function, but that is not available. Using the current - value of reg_parm_stack_space is wrong, but gives - correct results on all supported machines. */ - - int adjust = - (DECL_STRUCT_FUNCTION (fndecl)->outgoing_args_size - + reg_parm_stack_space); - - start_sequence (); - emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX); - allocate_dynamic_stack_space (GEN_INT (adjust), - NULL_RTX, BITS_PER_UNIT); - seq = get_insns (); - end_sequence (); - emit_insn_before (seq, first_insn); - emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); - } - } - } - - /* If the result is equivalent to TARGET, return TARGET to simplify - checks in store_expr. They can be equivalent but not equal in the - case of a function that returns BLKmode. */ - if (temp != target && rtx_equal_p (temp, target)) - return target; - return temp; - } - - /* If inlining failed, mark FNDECL as needing to be compiled - separately after all. If function was declared inline, - give a warning. */ - if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline - && optimize > 0 && !TREE_ADDRESSABLE (fndecl)) - { - warning ("%Jinlining failed in call to '%F'", fndecl, fndecl); - warning ("called from here"); - } - lang_hooks.mark_addressable (fndecl); - return (rtx) (size_t) - 1; -} - /* We need to pop PENDING_STACK_ADJUST bytes. But, if the arguments wouldn't fill up an even multiple of PREFERRED_UNIT_STACK_BOUNDARY bytes, then we would need to push some additional bytes to pad the @@ -2029,6 +1924,69 @@ shift_returned_value (tree type, rtx *value) return false; } +/* Remove all REG_EQUIV notes found in the insn chain. */ + +static void +purge_reg_equiv_notes (void) +{ + rtx insn; + + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + while (1) + { + rtx note = find_reg_note (insn, REG_EQUIV, 0); + if (note) + { + /* Remove the note and keep looking at the notes for + this insn. */ + remove_note (insn, note); + continue; + } + break; + } + } +} + +/* Clear RTX_UNCHANGING_P flag of incoming argument MEMs. */ + +static void +purge_mem_unchanging_flag (rtx x) +{ + RTX_CODE code; + int i, j; + const char *fmt; + + if (x == NULL_RTX) + return; + + code = GET_CODE (x); + + if (code == MEM) + { + if (RTX_UNCHANGING_P (x) + && (XEXP (x, 0) == current_function_internal_arg_pointer + || (GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == + current_function_internal_arg_pointer + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))) + RTX_UNCHANGING_P (x) = 0; + return; + } + + /* Scan all subexpressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) + { + if (*fmt == 'e') + purge_mem_unchanging_flag (XEXP (x, i)); + else if (*fmt == 'E') + for (j = 0; j < XVECLEN (x, i); j++) + purge_mem_unchanging_flag (XVECEXP (x, i, j)); + } +} + + /* 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. @@ -2045,11 +2003,9 @@ expand_call (tree exp, rtx target, int ignore) tree actparms = TREE_OPERAND (exp, 1); /* RTX for the function to be called. */ rtx funexp; - /* Sequence of insns to perform a tail recursive "call". */ - rtx tail_recursion_insns = NULL_RTX; /* Sequence of insns to perform a normal "call". */ rtx normal_call_insns = NULL_RTX; - /* Sequence of insns to perform a tail recursive "call". */ + /* Sequence of insns to perform a tail "call". */ rtx tail_call_insns = NULL_RTX; /* Data type of the function. */ tree funtype; @@ -2059,9 +2015,7 @@ expand_call (tree exp, rtx target, int ignore) tree fndecl = 0; /* The type of the function being called. */ tree fntype; - rtx insn; - int try_tail_call = 1; - int try_tail_recursion = 1; + bool try_tail_call = CALL_EXPR_TAILCALL (exp); int pass; /* Register in which non-BLKmode value will be returned, @@ -2122,8 +2076,6 @@ expand_call (tree exp, rtx target, int ignore) /* Mask of ECF_ flags. */ int flags = 0; - /* Nonzero if this is a call to an inline function. */ - int is_integrable = 0; #ifdef REG_PARM_STACK_SPACE /* Define the boundary of the register parm stack space that needs to be saved, if any. */ @@ -2132,7 +2084,6 @@ expand_call (tree exp, rtx target, int ignore) #endif int initial_highest_arg_in_use = highest_outgoing_arg_in_use; - rtx temp_target = 0; char *initial_stack_usage_map = stack_usage_map; int old_stack_allocated; @@ -2156,58 +2107,23 @@ expand_call (tree exp, rtx target, int ignore) HOST_WIDE_INT preferred_stack_boundary; /* The alignment of the stack, in bytes. */ HOST_WIDE_INT preferred_unit_stack_boundary; - + /* The static chain value to use for this call. */ + rtx static_chain_value; /* See if this is "nothrow" function call. */ if (TREE_NOTHROW (exp)) flags |= ECF_NOTHROW; - /* 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. */ - + /* See if we can find a DECL-node for the actual function, and get the + function attributes (flags) from the function decl or type node. */ fndecl = get_callee_fndecl (exp); if (fndecl) { fntype = TREE_TYPE (fndecl); - if (!flag_no_inline - && fndecl != current_function_decl - && DECL_INLINE (fndecl) - && DECL_STRUCT_FUNCTION (fndecl) - && DECL_STRUCT_FUNCTION (fndecl)->inlinable) - is_integrable = 1; - else if (! TREE_ADDRESSABLE (fndecl)) - { - /* In case this function later becomes inlinable, - record that there was already a non-inline call to it. - - Use abstraction instead of setting TREE_ADDRESSABLE - directly. */ - if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline - && optimize > 0) - { - warning ("%Jcan't inline call to '%F'", fndecl, fndecl); - warning ("called from here"); - } - lang_hooks.mark_addressable (fndecl); - } - - if (ignore - && lookup_attribute ("warn_unused_result", - TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) - warning ("ignoring return value of `%D', " - "declared with attribute warn_unused_result", fndecl); - flags |= flags_from_decl_or_type (fndecl); } - - /* If we don't have specific function to call, see if we have a - attributes set in the type. */ else { fntype = TREE_TYPE (TREE_TYPE (p)); - if (ignore - && lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (fntype))) - warning ("ignoring return value of function " - "declared with attribute warn_unused_result"); flags |= flags_from_decl_or_type (fntype); } @@ -2264,15 +2180,6 @@ expand_call (tree exp, rtx target, int ignore) #ifdef PCC_STATIC_STRUCT_RETURN { pcc_struct_value = 1; - /* Easier than making that case work right. */ - if (is_integrable) - { - /* In case this is a static function, note that it has been - used. */ - if (! TREE_ADDRESSABLE (fndecl)) - lang_hooks.mark_addressable (fndecl); - is_integrable = 0; - } } #else /* not PCC_STATIC_STRUCT_RETURN */ { @@ -2305,17 +2212,6 @@ expand_call (tree exp, rtx target, int ignore) #endif /* not PCC_STATIC_STRUCT_RETURN */ } - /* If called function is inline, try to integrate it. */ - - if (is_integrable) - { - rtx temp = try_to_integrate (fndecl, actparms, target, - ignore, TREE_TYPE (exp), - structure_value_addr); - if (temp != (rtx) (size_t) - 1) - return temp; - } - /* Figure out the amount to which the stack should be aligned. */ preferred_stack_boundary = PREFERRED_STACK_BOUNDARY; if (fndecl) @@ -2341,10 +2237,6 @@ expand_call (tree exp, rtx target, int ignore) else type_arg_types = TYPE_ARG_TYPES (funtype); - /* See if this is a call to a function that can return more than once - or a call to longjmp or malloc. */ - flags |= special_function_p (fndecl, flags); - if (flags & ECF_MAY_BE_ALLOCA) current_function_calls_alloca = 1; @@ -2427,7 +2319,7 @@ expand_call (tree exp, rtx target, int ignore) &args_so_far, reg_parm_stack_space, &old_stack_level, &old_pending_adj, &must_preallocate, &flags, - CALL_FROM_THUNK_P (exp)); + &try_tail_call, CALL_FROM_THUNK_P (exp)); if (args_size.var) { @@ -2476,14 +2368,9 @@ expand_call (tree exp, rtx target, int ignore) || !rtx_equal_function_value_matters || current_nesting_level () == 0 || any_pending_cleanups () - || args_size.var) - try_tail_call = try_tail_recursion = 0; - - /* Tail recursion fails, when we are not dealing with recursive calls. */ - if (!try_tail_recursion - || TREE_CODE (addr) != ADDR_EXPR - || TREE_OPERAND (addr, 0) != current_function_decl) - try_tail_recursion = 0; + || args_size.var + || lookup_stmt_eh_region (exp) >= 0) + try_tail_call = 0; /* Rest of purposes for tail call optimizations to fail. */ if ( @@ -2521,7 +2408,7 @@ expand_call (tree exp, rtx target, int ignore) || !lang_hooks.decls.ok_for_sibcall (fndecl)) try_tail_call = 0; - if (try_tail_call || try_tail_recursion) + if (try_tail_call) { int end, inc; actparms = NULL_TREE; @@ -2556,11 +2443,6 @@ expand_call (tree exp, rtx target, int ignore) for (; i != end; i += inc) { args[i].tree_value = fix_unsafe_tree (args[i].tree_value); - /* We need to build actparms for optimize_tail_recursion. We can - safely trash away TREE_PURPOSE, since it is unused by this - function. */ - if (try_tail_recursion) - actparms = tree_cons (NULL_TREE, args[i].tree_value, actparms); } /* Do the same for the function address if it is an expression. */ if (!fndecl) @@ -2568,50 +2450,9 @@ expand_call (tree exp, rtx target, int ignore) /* Expanding one of those dangerous arguments could have added cleanups, but otherwise give it a whirl. */ if (any_pending_cleanups ()) - try_tail_call = try_tail_recursion = 0; + try_tail_call = 0; } - /* Generate a tail recursion sequence when calling ourselves. */ - - if (try_tail_recursion) - { - /* We want to emit any pending stack adjustments before the tail - recursion "call". That way we know any adjustment after the tail - recursion call can be ignored if we indeed use the tail recursion - call expansion. */ - int save_pending_stack_adjust = pending_stack_adjust; - int save_stack_pointer_delta = stack_pointer_delta; - - /* Emit any queued insns now; otherwise they would end up in - only one of the alternates. */ - emit_queue (); - - /* Use a new sequence to hold any RTL we generate. We do not even - know if we will use this RTL yet. The final decision can not be - made until after RTL generation for the entire function is - complete. */ - start_sequence (); - /* If expanding any of the arguments creates cleanups, we can't - do a tailcall. So, we'll need to pop the pending cleanups - list. If, however, all goes well, and there are no cleanups - then the call to expand_start_target_temps will have no - effect. */ - expand_start_target_temps (); - if (optimize_tail_recursion (actparms, get_last_insn ())) - { - if (any_pending_cleanups ()) - try_tail_call = try_tail_recursion = 0; - else - tail_recursion_insns = get_insns (); - } - expand_end_target_temps (); - end_sequence (); - - /* Restore the original pending stack adjustment for the sibling and - normal call cases below. */ - pending_stack_adjust = save_pending_stack_adjust; - stack_pointer_delta = save_stack_pointer_delta; - } /* Ensure current function's preferred stack boundary is at least what we need. We don't have to increase alignment for recursive @@ -2634,7 +2475,7 @@ expand_call (tree exp, rtx target, int ignore) int sibcall_failure = 0; /* We want to emit any pending stack adjustments before the tail recursion "call". That way we know any adjustment after the tail - recursion call can be ignored if we indeed use the tail recursion + recursion call can be ignored if we indeed use the tail call expansion. */ int save_pending_stack_adjust = 0; int save_stack_pointer_delta = 0; @@ -2966,6 +2807,12 @@ expand_call (tree exp, rtx target, int ignore) once we have started filling any specific hard regs. */ precompute_register_parameters (num_actuals, args, ®_parm_seen); + if (TREE_OPERAND (exp, 2)) + static_chain_value = expand_expr (TREE_OPERAND (exp, 2), + NULL_RTX, VOIDmode, 0); + else + static_chain_value = 0; + #ifdef REG_PARM_STACK_SPACE /* Save the fixed argument area if it's part of the caller's frame and is clobbered by argument setup for this call. */ @@ -3056,8 +2903,8 @@ expand_call (tree exp, rtx target, int ignore) use_reg (&call_fusage, struct_value); } - funexp = prepare_call_address (funexp, fndecl, &call_fusage, - reg_parm_seen, pass == 0); + funexp = prepare_call_address (funexp, static_chain_value, + &call_fusage, reg_parm_seen, pass == 0); load_register_parameters (args, num_actuals, &call_fusage, flags, pass == 0, &sibcall_failure); @@ -3088,7 +2935,7 @@ expand_call (tree exp, rtx target, int ignore) abort (); /* Generate the actual call instruction. */ - emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size, + emit_call_1 (funexp, exp, fndecl, funtype, unadjusted_args_size, adjusted_args_size.constant, struct_value_size, next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage, flags, & args_so_far); @@ -3255,11 +3102,7 @@ expand_call (tree exp, rtx target, int ignore) The Irix 6 ABI has examples of this. */ else if (GET_CODE (valreg) == PARALLEL) { - /* Second condition is added because "target" is freed at the - the end of "pass0" for -O2 when call is made to - expand_end_target_temps (). Its "in_use" flag has been set - to false, so allocate a new temp. */ - if (target == 0 || (pass == 1 && target == temp_target)) + if (target == 0) { /* This will only be assigned once, so it can be readonly. */ tree nt = build_qualified_type (TREE_TYPE (exp), @@ -3267,7 +3110,6 @@ expand_call (tree exp, rtx target, int ignore) | TYPE_QUAL_CONST)); target = assign_temp (nt, 0, 1, 1); - temp_target = target; preserve_temp_slots (target); } @@ -3392,8 +3234,8 @@ expand_call (tree exp, rtx target, int ignore) Check for the handler slots since we might not have a save area for non-local gotos. */ - if ((flags & ECF_MAY_BE_ALLOCA) && nonlocal_goto_handler_slots != 0) - emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX); + if ((flags & ECF_MAY_BE_ALLOCA) && cfun->nonlocal_goto_save_area != 0) + update_nonlocal_goto_save_area (); /* Free up storage we no longer need. */ for (i = 0; i < num_actuals; ++i) @@ -3462,48 +3304,16 @@ expand_call (tree exp, rtx target, int ignore) zero out the sequence. */ if (sibcall_failure) tail_call_insns = NULL_RTX; + else + break; } - /* The function optimize_sibling_and_tail_recursive_calls doesn't - handle CALL_PLACEHOLDERs inside other CALL_PLACEHOLDERs. This - can happen if the arguments to this function call an inline - function who's expansion contains another CALL_PLACEHOLDER. - - If there are any C_Ps in any of these sequences, replace them - with their normal call. */ - - for (insn = normal_call_insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - replace_call_placeholder (insn, sibcall_use_normal); - - for (insn = tail_call_insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - replace_call_placeholder (insn, sibcall_use_normal); - - for (insn = tail_recursion_insns; insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - replace_call_placeholder (insn, sibcall_use_normal); - - /* If this was a potential tail recursion site, then emit a - CALL_PLACEHOLDER with the normal and the tail recursion streams. - One of them will be selected later. */ - if (tail_recursion_insns || tail_call_insns) + /* If tail call production suceeded, we need to remove REG_EQUIV notes on + arguments too, as argument area is now clobbered by the call. */ + if (tail_call_insns) { - /* The tail recursion label must be kept around. We could expose - its use in the CALL_PLACEHOLDER, but that creates unwanted edges - and makes determining true tail recursion sites difficult. - - So we set LABEL_PRESERVE_P here, then clear it when we select - one of the call sequences after rtl generation is complete. */ - if (tail_recursion_insns) - LABEL_PRESERVE_P (tail_recursion_label) = 1; - emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, normal_call_insns, - tail_call_insns, - tail_recursion_insns, - tail_recursion_label)); + emit_insn (tail_call_insns); + cfun->tail_call_emit = true; } else emit_insn (normal_call_insns); @@ -3524,6 +3334,47 @@ expand_call (tree exp, rtx target, int ignore) return target; } +/* A sibling call sequence invalidates any REG_EQUIV notes made for + this function's incoming arguments. + + At the start of RTL generation we know the only REG_EQUIV notes + in the rtl chain are those for incoming arguments, so we can safely + flush any REG_EQUIV note. + + This is (slight) overkill. We could keep track of the highest + argument we clobber and be more selective in removing notes, but it + does not seem to be worth the effort. */ +void +fixup_tail_calls (void) +{ + rtx insn; + tree arg; + + purge_reg_equiv_notes (); + + /* A sibling call sequence also may invalidate RTX_UNCHANGING_P + flag of some incoming arguments MEM RTLs, because it can write into + those slots. We clear all those bits now. + + This is (slight) overkill, we could keep track of which arguments + we actually write into. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + { + if (INSN_P (insn)) + purge_mem_unchanging_flag (PATTERN (insn)); + } + + /* Similarly, invalidate RTX_UNCHANGING_P for any incoming + arguments passed in registers. */ + for (arg = DECL_ARGUMENTS (current_function_decl); + arg; + arg = TREE_CHAIN (arg)) + { + if (REG_P (DECL_RTL (arg))) + RTX_UNCHANGING_P (DECL_RTL (arg)) = false; + } +} + /* Traverse an argument list in VALUES and expand all complex arguments into their components. */ tree @@ -4135,7 +3986,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, else argnum = 0; - fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0, 0); + fun = prepare_call_address (fun, NULL, &call_fusage, 0, 0); /* Now load any reg parms into their regs. */ @@ -4197,7 +4048,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, always signed. We also assume that the list of arguments passed has no impact, so we pretend it is unknown. */ - emit_call_1 (fun, + emit_call_1 (fun, NULL, get_identifier (XSTR (orgfun, 0)), build_function_type (tfom, NULL_TREE), original_args_size.constant, args_size.constant, diff --git a/gcc/cfg.c b/gcc/cfg.c index 5eb9c248c5b..4b6de6d66a8 100644 --- a/gcc/cfg.c +++ b/gcc/cfg.c @@ -62,20 +62,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm_p.h" #include "obstack.h" #include "alloc-pool.h" +#include "timevar.h" +#include "ggc.h" /* The obstack on which the flow graph components are allocated. */ struct obstack flow_obstack; static char *flow_firstobj; -/* Basic block object pool. */ - -static alloc_pool bb_pool; - -/* Edge object pool. */ - -static alloc_pool edge_pool; - /* Number of basic blocks in the current function. */ int n_basic_blocks; @@ -93,56 +87,10 @@ int n_edges; varray_type basic_block_info; /* The special entry and exit blocks. */ +basic_block ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR; -struct basic_block_def entry_exit_blocks[2] -= {{NULL, /* head */ - NULL, /* end */ - NULL, /* head_tree */ - NULL, /* end_tree */ - NULL, /* pred */ - NULL, /* succ */ - NULL, /* local_set */ - NULL, /* cond_local_set */ - NULL, /* global_live_at_start */ - NULL, /* global_live_at_end */ - NULL, /* aux */ - ENTRY_BLOCK, /* index */ - NULL, /* prev_bb */ - EXIT_BLOCK_PTR, /* next_bb */ - 0, /* loop_depth */ - NULL, /* loop_father */ - { NULL, NULL }, /* dom */ - 0, /* count */ - 0, /* frequency */ - 0, /* flags */ - 0, /* partition */ - NULL /* rbi */ - }, - { - NULL, /* head */ - NULL, /* end */ - NULL, /* head_tree */ - NULL, /* end_tree */ - NULL, /* pred */ - NULL, /* succ */ - NULL, /* local_set */ - NULL, /* cond_local_set */ - NULL, /* global_live_at_start */ - NULL, /* global_live_at_end */ - NULL, /* aux */ - EXIT_BLOCK, /* index */ - ENTRY_BLOCK_PTR, /* prev_bb */ - NULL, /* next_bb */ - 0, /* loop_depth */ - NULL, /* loop_father */ - { NULL, NULL }, /* dom */ - 0, /* count */ - 0, /* frequency */ - 0, /* flags */ - 0, /* partition */ - NULL /* rbi */ - } -}; +/* Memory alloc pool for bb member rbi. */ +alloc_pool rbi_pool; void debug_flow_info (void); static void free_edge (edge); @@ -164,25 +112,26 @@ init_flow (void) } else { - free_alloc_pool (bb_pool); - free_alloc_pool (edge_pool); obstack_free (&flow_obstack, flow_firstobj); flow_firstobj = obstack_alloc (&flow_obstack, 0); } - bb_pool = create_alloc_pool ("Basic block pool", - sizeof (struct basic_block_def), 100); - edge_pool = create_alloc_pool ("Edge pool", - sizeof (struct edge_def), 100); + + ENTRY_BLOCK_PTR = ggc_alloc_cleared (sizeof (*ENTRY_BLOCK_PTR)); + ENTRY_BLOCK_PTR->index = ENTRY_BLOCK; + EXIT_BLOCK_PTR = ggc_alloc_cleared (sizeof (*EXIT_BLOCK_PTR)); + EXIT_BLOCK_PTR->index = EXIT_BLOCK; + ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; + EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; } /* Helper function for remove_edge and clear_edges. Frees edge structure without actually unlinking it from the pred/succ lists. */ static void -free_edge (edge e) +free_edge (edge e ATTRIBUTE_UNUSED) { n_edges--; - pool_free (edge_pool, e); + /* ggc_free (e); */ } /* Free the memory associated with the edge structures. */ @@ -231,11 +180,40 @@ basic_block alloc_block (void) { basic_block bb; - bb = pool_alloc (bb_pool); - memset (bb, 0, sizeof (*bb)); + bb = ggc_alloc_cleared (sizeof (*bb)); return bb; } +/* Create memory pool for rbi_pool. */ + +void +alloc_rbi_pool (void) +{ + rbi_pool = create_alloc_pool ("rbi pool", + sizeof (struct reorder_block_def), + n_basic_blocks + 2); +} + +/* Free rbi_pool. */ + +void +free_rbi_pool (void) +{ + free_alloc_pool (rbi_pool); +} + +/* Initialize rbi (the structure containing data used by basic block + duplication and reordering) for the given basic block. */ + +void +initialize_bb_rbi (basic_block bb) +{ + if (bb->rbi) + abort (); + bb->rbi = pool_alloc (rbi_pool); + memset (bb->rbi, 0, sizeof (struct reorder_block_def)); +} + /* Link block B to chain after AFTER. */ void link_block (basic_block b, basic_block after) @@ -252,6 +230,8 @@ unlink_block (basic_block b) { b->next_bb->prev_bb = b->prev_bb; b->prev_bb->next_bb = b->next_bb; + b->prev_bb = NULL; + b->next_bb = NULL; } /* Sequentially order blocks and compact the arrays. */ @@ -272,6 +252,9 @@ compact_blocks (void) if (i != n_basic_blocks) abort (); + for (; i < last_basic_block; i++) + BASIC_BLOCK (i) = NULL; + last_basic_block = n_basic_blocks; } @@ -283,7 +266,7 @@ expunge_block (basic_block b) unlink_block (b); BASIC_BLOCK (b->index) = NULL; n_basic_blocks--; - pool_free (bb_pool, b); + /* ggc_free (b); */ } /* Create an edge connecting SRC and DEST with flags FLAGS. Return newly @@ -294,8 +277,7 @@ edge unchecked_make_edge (basic_block src, basic_block dst, int flags) { edge e; - e = pool_alloc (edge_pool); - memset (e, 0, sizeof (*e)); + e = ggc_alloc_cleared (sizeof (*e)); n_edges++; e->succ_next = src->succ; @@ -490,54 +472,56 @@ void dump_flow_info (FILE *file) { int i; - int max_regno = max_reg_num (); basic_block bb; static const char * const reg_class_names[] = REG_CLASS_NAMES; - fprintf (file, "%d registers.\n", max_regno); if (reg_n_info) - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (REG_N_REFS (i)) - { - enum reg_class class, altclass; - - fprintf (file, "\nRegister %d used %d times across %d insns", - i, REG_N_REFS (i), REG_LIVE_LENGTH (i)); - if (REG_BASIC_BLOCK (i) >= 0) - fprintf (file, " in block %d", REG_BASIC_BLOCK (i)); - if (REG_N_SETS (i)) - fprintf (file, "; set %d time%s", REG_N_SETS (i), - (REG_N_SETS (i) == 1) ? "" : "s"); - if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i])) - fprintf (file, "; user var"); - if (REG_N_DEATHS (i) != 1) - fprintf (file, "; dies in %d places", REG_N_DEATHS (i)); - if (REG_N_CALLS_CROSSED (i) == 1) - fprintf (file, "; crosses 1 call"); - else if (REG_N_CALLS_CROSSED (i)) - fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i)); - if (regno_reg_rtx[i] != NULL - && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD) - fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i)); - - class = reg_preferred_class (i); - altclass = reg_alternate_class (i); - if (class != GENERAL_REGS || altclass != ALL_REGS) - { - if (altclass == ALL_REGS || class == ALL_REGS) - fprintf (file, "; pref %s", reg_class_names[(int) class]); - else if (altclass == NO_REGS) - fprintf (file, "; %s or none", reg_class_names[(int) class]); - else - fprintf (file, "; pref %s, else %s", - reg_class_names[(int) class], - reg_class_names[(int) altclass]); - } - - if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i])) - fprintf (file, "; pointer"); - fprintf (file, ".\n"); - } + { + int max_regno = max_reg_num (); + 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, altclass; + + fprintf (file, "\nRegister %d used %d times across %d insns", + i, REG_N_REFS (i), REG_LIVE_LENGTH (i)); + if (REG_BASIC_BLOCK (i) >= 0) + fprintf (file, " in block %d", REG_BASIC_BLOCK (i)); + if (REG_N_SETS (i)) + fprintf (file, "; set %d time%s", REG_N_SETS (i), + (REG_N_SETS (i) == 1) ? "" : "s"); + if (regno_reg_rtx[i] != NULL && REG_USERVAR_P (regno_reg_rtx[i])) + fprintf (file, "; user var"); + if (REG_N_DEATHS (i) != 1) + fprintf (file, "; dies in %d places", REG_N_DEATHS (i)); + if (REG_N_CALLS_CROSSED (i) == 1) + fprintf (file, "; crosses 1 call"); + else if (REG_N_CALLS_CROSSED (i)) + fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i)); + if (regno_reg_rtx[i] != NULL + && PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD) + fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i)); + + class = reg_preferred_class (i); + altclass = reg_alternate_class (i); + if (class != GENERAL_REGS || altclass != ALL_REGS) + { + if (altclass == ALL_REGS || class == ALL_REGS) + fprintf (file, "; pref %s", reg_class_names[(int) class]); + else if (altclass == NO_REGS) + fprintf (file, "; %s or none", reg_class_names[(int) class]); + else + fprintf (file, "; pref %s, else %s", + reg_class_names[(int) class], + reg_class_names[(int) altclass]); + } + + if (regno_reg_rtx[i] != NULL && REG_POINTER (regno_reg_rtx[i])) + fprintf (file, "; pointer"); + fprintf (file, ".\n"); + } + } fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges); FOR_EACH_BB (bb) @@ -546,8 +530,7 @@ dump_flow_info (FILE *file) int sum; gcov_type lsum; - fprintf (file, "\nBasic block %d: first insn %d, last %d, ", - bb->index, INSN_UID (BB_HEAD (bb)), INSN_UID (BB_END (bb))); + fprintf (file, "\nBasic block %d ", bb->index); fprintf (file, "prev %d, next %d, ", bb->prev_bb->index, bb->next_bb->index); fprintf (file, "loop_depth %d, count ", bb->loop_depth); @@ -641,7 +624,8 @@ dump_edge_info (FILE *file, edge e, int do_succ) { static const char * const bitnames[] = { "fallthru", "ab", "abcall", "eh", "fake", "dfs_back", - "can_fallthru", "irreducible", "sibcall", "loop_exit" + "can_fallthru", "irreducible", "sibcall", "loop_exit", + "true", "false", "exec" }; int comma = 0; int i, flags = e->flags; @@ -825,3 +809,55 @@ debug_bb_n (int n) dump_bb (bb, stderr, 0); return bb; } + +/* Dumps cfg related information about basic block BB to FILE. */ + +static void +dump_cfg_bb_info (FILE *file, basic_block bb) +{ + unsigned i; + bool first = true; + static const char * const bb_bitnames[] = + { + "dirty", "new", "reachable", "visited", "irreducible_loop", "superblock" + }; + const unsigned n_bitnames = sizeof (bb_bitnames) / sizeof (char *); + edge e; + + fprintf (file, "Basic block %d", bb->index); + for (i = 0; i < n_bitnames; i++) + if (bb->flags & (1 << i)) + { + if (first) + fprintf (file, " ("); + else + fprintf (file, ", "); + first = false; + fprintf (file, bb_bitnames[i]); + } + if (!first) + fprintf (file, ")"); + fprintf (file, "\n"); + + fprintf (file, "Predecessors: "); + for (e = bb->pred; e; e = e->pred_next) + dump_edge_info (file, e, 0); + + fprintf (file, "\nSuccessors: "); + for (e = bb->succ; e; e = e->succ_next) + dump_edge_info (file, e, 1); + fprintf (file, "\n\n"); +} + +/* Dumps a brief description of cfg to FILE. */ + +void +brief_dump_cfg (FILE *file) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + dump_cfg_bb_info (file, bb); + } +} diff --git a/gcc/cfganal.c b/gcc/cfganal.c index 00771b47703..1a7d280513f 100644 --- a/gcc/cfganal.c +++ b/gcc/cfganal.c @@ -52,7 +52,6 @@ static void flow_dfs_compute_reverse_add_bb (depth_first_search_ds, static basic_block flow_dfs_compute_reverse_execute (depth_first_search_ds); static void flow_dfs_compute_reverse_finish (depth_first_search_ds); static void remove_fake_successors (basic_block); -static bool need_fake_edge_p (rtx); static bool flow_active_insn_p (rtx); /* Like active_insn_p, except keep the return value clobber around @@ -242,169 +241,6 @@ set_edge_can_fallthru_flag (void) } } -/* Return true if we need to add fake edge to exit. - Helper function for the flow_call_edges_add. */ - -static bool -need_fake_edge_p (rtx insn) -{ - if (!INSN_P (insn)) - return false; - - if ((GET_CODE (insn) == CALL_INSN - && !SIBLING_CALL_P (insn) - && !find_reg_note (insn, REG_NORETURN, NULL) - && !find_reg_note (insn, REG_ALWAYS_RETURN, NULL) - && !CONST_OR_PURE_CALL_P (insn))) - return true; - - return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS - && MEM_VOLATILE_P (PATTERN (insn))) - || (GET_CODE (PATTERN (insn)) == PARALLEL - && asm_noperands (insn) != -1 - && MEM_VOLATILE_P (XVECEXP (PATTERN (insn), 0, 0))) - || GET_CODE (PATTERN (insn)) == ASM_INPUT); -} - -/* Add fake edges to the function exit for any non constant and non noreturn - calls, volatile inline assembly in the bitmap of blocks specified by - BLOCKS or to the whole CFG if BLOCKS is zero. Return the number of blocks - that were split. - - The goal is to expose cases in which entering a basic block does not imply - that all subsequent instructions must be executed. */ - -int -flow_call_edges_add (sbitmap blocks) -{ - int i; - int blocks_split = 0; - int last_bb = last_basic_block; - bool check_last_block = false; - - if (n_basic_blocks == 0) - return 0; - - if (! blocks) - check_last_block = true; - else - check_last_block = TEST_BIT (blocks, EXIT_BLOCK_PTR->prev_bb->index); - - /* In the last basic block, before epilogue generation, there will be - a fallthru edge to EXIT. Special care is required if the last insn - of the last basic block is a call because make_edge folds duplicate - edges, which would result in the fallthru edge also being marked - fake, which would result in the fallthru edge being removed by - remove_fake_edges, which would result in an invalid CFG. - - Moreover, we can't elide the outgoing fake edge, since the block - profiler needs to take this into account in order to solve the minimal - spanning tree in the case that the call doesn't return. - - Handle this by adding a dummy instruction in a new last basic block. */ - if (check_last_block) - { - basic_block bb = EXIT_BLOCK_PTR->prev_bb; - rtx insn = BB_END (bb); - - /* Back up past insns that must be kept in the same block as a call. */ - while (insn != BB_HEAD (bb) - && keep_with_call_p (insn)) - insn = PREV_INSN (insn); - - if (need_fake_edge_p (insn)) - { - edge e; - - for (e = bb->succ; e; e = e->succ_next) - if (e->dest == EXIT_BLOCK_PTR) - { - insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e); - commit_edge_insertions (); - break; - } - } - } - - /* Now add fake edges to the function exit for any non constant - calls since there is no way that we can determine if they will - return or not... */ - - for (i = 0; i < last_bb; i++) - { - basic_block bb = BASIC_BLOCK (i); - rtx libcall_end = NULL_RTX; - rtx insn; - rtx prev_insn; - - if (!bb) - continue; - - if (blocks && !TEST_BIT (blocks, i)) - continue; - - for (insn = BB_END (bb); ; insn = prev_insn) - { - prev_insn = PREV_INSN (insn); - if (need_fake_edge_p (insn)) - { - edge e; - rtx split_at_insn = insn; - - /* Don't split libcalls. */ - if (libcall_end) - split_at_insn = libcall_end; - - /* Don't split the block between a call and an insn that should - remain in the same block as the call. */ - else if (GET_CODE (insn) == CALL_INSN) - while (split_at_insn != BB_END (bb) - && keep_with_call_p (NEXT_INSN (split_at_insn))) - split_at_insn = NEXT_INSN (split_at_insn); - - /* The handling above of the final block before the epilogue - should be enough to verify that there is no edge to the exit - block in CFG already. Calling make_edge in such case would - cause us to mark that edge as fake and remove it later. */ - -#ifdef ENABLE_CHECKING - if (split_at_insn == BB_END (bb)) - for (e = bb->succ; e; e = e->succ_next) - if (e->dest == EXIT_BLOCK_PTR) - abort (); -#endif - - /* Note that the following may create a new basic block - and renumber the existing basic blocks. */ - if (split_at_insn != BB_END (bb)) - { - e = split_block (bb, split_at_insn); - if (e) - blocks_split++; - } - - make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE); - } - - /* Watch out for REG_LIBCALL/REG_RETVAL notes so that we know - whether we are currently in a libcall or not. Remember that - we are scanning backwards! */ - if (find_reg_note (insn, REG_RETVAL, NULL_RTX)) - libcall_end = insn; - if (find_reg_note (insn, REG_LIBCALL, NULL_RTX)) - libcall_end = NULL_RTX; - - if (insn == BB_HEAD (bb)) - break; - } - } - - if (blocks_split) - verify_flow_info (); - - return blocks_split; -} - /* Find unreachable blocks. An unreachable block will have 0 in the reachable bit in block->flags. A nonzero value indicates the block is reachable. */ @@ -603,6 +439,21 @@ verify_edge_list (FILE *f, struct edge_list *elist) } } +/* Given PRED and SUCC blocks, return the edge which connects the blocks. + If no such edge exists, return NULL. */ + +edge +find_edge (basic_block pred, basic_block succ) +{ + edge e; + + for (e = pred->succ; e; e = e->succ_next) + if (e->dest == succ) + return e; + + return NULL; +} + /* This routine will determine what, if any, edge there is between a specified predecessor and successor. */ diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c index cd936a27b9d..3e9a36cca4d 100644 --- a/gcc/cfgbuild.c +++ b/gcc/cfgbuild.c @@ -240,7 +240,7 @@ make_label_edge (sbitmap *edge_cache, basic_block src, rtx label, int flags) /* Create the edges generated by INSN in REGION. */ void -make_eh_edge (sbitmap *edge_cache, basic_block src, rtx insn) +rtl_make_eh_edge (sbitmap *edge_cache, basic_block src, rtx insn) { int is_call = GET_CODE (insn) == CALL_INSN ? EDGE_ABNORMAL_CALL : 0; rtx handlers, i; @@ -325,7 +325,7 @@ make_edges (rtx label_value_list, basic_block min, basic_block max, int update_p /* Recognize exception handling placeholders. */ if (GET_CODE (PATTERN (insn)) == RESX) - make_eh_edge (edge_cache, bb, insn); + rtl_make_eh_edge (edge_cache, bb, insn); /* Recognize a non-local goto as a branch outside the current function. */ @@ -405,7 +405,7 @@ make_edges (rtx label_value_list, basic_block min, basic_block max, int update_p else if (code == CALL_INSN || flag_non_call_exceptions) { /* Add any appropriate EH edges. */ - make_eh_edge (edge_cache, bb, insn); + rtl_make_eh_edge (edge_cache, bb, insn); if (code == CALL_INSN && nonlocal_goto_handler_labels) { @@ -610,7 +610,7 @@ find_basic_blocks (rtx f, int nregs ATTRIBUTE_UNUSED, FOR_EACH_BB (bb) bb->aux = NULL; - VARRAY_FREE (basic_block_info); + basic_block_info = NULL; } n_basic_blocks = count_basic_blocks (f); diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 51182e3f400..10d9e96c135 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -1368,7 +1368,7 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2) /* The labels should never be the same rtx. If they really are same the jump tables are same too. So disable crossjumping of blocks BB1 and BB2 because when deleting the common insns in the end of BB1 - by delete_block () the jump table would be deleted too. */ + by delete_basic_block () the jump table would be deleted too. */ /* If LABEL2 is referenced in BB1->END do not do anything because we would loose information when replacing LABEL1 by LABEL2 and then LABEL2 by LABEL1 in BB1->END. */ @@ -1501,6 +1501,8 @@ try_crossjump_to_edge (int mode, edge e1, edge e2) rtx newpos1, newpos2; edge s; + newpos1 = newpos2 = NULL_RTX; + /* If we have partitioned hot/cold basic blocks, it is a bad idea to try this optimization. */ @@ -2033,6 +2035,32 @@ delete_unreachable_blocks (void) tidy_fallthru_edges (); return changed; } + +/* Merges sequential blocks if possible. */ + +bool +merge_seq_blocks (void) +{ + basic_block bb; + bool changed = false; + + for (bb = ENTRY_BLOCK_PTR->next_bb; bb != EXIT_BLOCK_PTR; ) + { + if (bb->succ + && !bb->succ->succ_next + && can_merge_blocks_p (bb, bb->succ->dest)) + { + /* Merge the blocks and retry. */ + merge_blocks (bb, bb->succ->dest); + changed = true; + continue; + } + + bb = bb->next_bb; + } + + return changed; +} /* Tidy the CFG by deleting unreachable code and whatnot. */ diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c index 001dfe29bd4..29f5dfd1695 100644 --- a/gcc/cfghooks.c +++ b/gcc/cfghooks.c @@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA. */ #include "tree.h" #include "rtl.h" #include "basic-block.h" +#include "tree-flow.h" #include "timevar.h" #include "toplev.h" @@ -46,6 +47,22 @@ cfg_layout_rtl_register_cfg_hooks (void) cfg_hooks = &cfg_layout_rtl_cfg_hooks; } +/* Initialization of functions specific to the tree IR. */ + +void +tree_register_cfg_hooks (void) +{ + cfg_hooks = &tree_cfg_hooks; +} + +/* Returns current ir type (rtl = 0, trees = 1). */ + +int +ir_type (void) +{ + return cfg_hooks == &tree_cfg_hooks ? 1 : 0; +} + /* Verify the CFG consistency. Currently it does following: checks edge and basic block list correctness @@ -246,10 +263,10 @@ dump_bb (basic_block bb, FILE *outf, int indent) be equivalent to E in the case of duplicate edges being removed) or NULL if edge is not easily redirectable for whatever reason. */ -bool +edge redirect_edge_and_branch (edge e, basic_block dest) { - bool ret; + edge ret; if (!cfg_hooks->redirect_edge_and_branch) internal_error ("%s does not support redirect_edge_and_branch.", @@ -286,7 +303,6 @@ edge split_block (basic_block bb, void *i) { basic_block new_bb; - edge e; if (!cfg_hooks->split_block) internal_error ("%s does not support split_block.", cfg_hooks->name); @@ -305,11 +321,7 @@ split_block (basic_block bb, void *i) set_immediate_dominator (CDI_DOMINATORS, new_bb, bb); } - e = make_edge (bb, new_bb, EDGE_FALLTHRU); - e->probability = REG_BR_PROB_BASE; - e->count = bb->count; - - return e; + return make_edge (bb, new_bb, EDGE_FALLTHRU); } /* Splits block BB just after labels. The newly created edge is returned. */ @@ -464,6 +476,24 @@ can_merge_blocks_p (basic_block bb1, basic_block bb2) return ret; } +void +predict_edge (edge e, enum br_predictor predictor, int probability) +{ + if (!cfg_hooks->predict_edge) + internal_error ("%s does not support predict_edge.", cfg_hooks->name); + + cfg_hooks->predict_edge (e, predictor, probability); +} + +bool +predicted_by_p (basic_block bb, enum br_predictor predictor) +{ + if (!cfg_hooks->predict_edge) + internal_error ("%s does not support predicted_by_p.", cfg_hooks->name); + + return cfg_hooks->predicted_by_p (bb, predictor); +} + /* Merges basic block B into basic block A. */ void @@ -605,3 +635,140 @@ tidy_fallthru_edges (void) tidy_fallthru_edge (s); } } + +/* Returns true if we can duplicate basic block BB. */ + +bool +can_duplicate_block_p (basic_block bb) +{ + edge e; + + if (!cfg_hooks->can_duplicate_block_p) + internal_error ("%s does not support can_duplicate_block_p.", + cfg_hooks->name); + + if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR) + return false; + + /* Duplicating fallthru block to exit would require adding a jump + and splitting the real last BB. */ + for (e = bb->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR && e->flags & EDGE_FALLTHRU) + return false; + + return cfg_hooks->can_duplicate_block_p (bb); +} + +/* Duplicates basic block BB and redirects edge E to it. Returns the + new basic block. */ + +basic_block +duplicate_block (basic_block bb, edge e) +{ + edge s, n; + basic_block new_bb; + gcov_type new_count = e ? e->count : 0; + + if (!cfg_hooks->duplicate_block) + internal_error ("%s does not support duplicate_block.", + cfg_hooks->name); + + if (bb->count < new_count) + new_count = bb->count; + if (!bb->pred) + abort (); +#ifdef ENABLE_CHECKING + if (!can_duplicate_block_p (bb)) + abort (); +#endif + + new_bb = cfg_hooks->duplicate_block (bb); + + new_bb->loop_depth = bb->loop_depth; + new_bb->flags = bb->flags; + for (s = bb->succ; s; s = s->succ_next) + { + /* Since we are creating edges from a new block to successors + of another block (which therefore are known to be disjoint), there + is no need to actually check for duplicated edges. */ + n = unchecked_make_edge (new_bb, s->dest, s->flags); + n->probability = s->probability; + if (e && bb->count) + { + /* Take care for overflows! */ + n->count = s->count * (new_count * 10000 / bb->count) / 10000; + s->count -= n->count; + } + else + n->count = s->count; + n->aux = s->aux; + } + + if (e) + { + new_bb->count = new_count; + bb->count -= new_count; + + new_bb->frequency = EDGE_FREQUENCY (e); + bb->frequency -= EDGE_FREQUENCY (e); + + redirect_edge_and_branch_force (e, new_bb); + + if (bb->count < 0) + bb->count = 0; + if (bb->frequency < 0) + bb->frequency = 0; + } + else + { + new_bb->count = bb->count; + new_bb->frequency = bb->frequency; + } + + new_bb->rbi->original = bb; + bb->rbi->copy = new_bb; + + return new_bb; +} + +/* Return 1 if BB ends with a call, possibly followed by some + instructions that must stay with the call, 0 otherwise. */ + +bool +block_ends_with_call_p (basic_block bb) +{ + if (!cfg_hooks->block_ends_with_call_p) + internal_error ("%s does not support block_ends_with_call_p", cfg_hooks->name); + + return (cfg_hooks->block_ends_with_call_p) (bb); +} + +/* Return 1 if BB ends with a conditional branch, 0 otherwise. */ + +bool +block_ends_with_condjump_p (basic_block bb) +{ + if (!cfg_hooks->block_ends_with_condjump_p) + internal_error ("%s does not support block_ends_with_condjump_p", + cfg_hooks->name); + + return (cfg_hooks->block_ends_with_condjump_p) (bb); +} + +/* Add fake edges to the function exit for any non constant and non noreturn + calls, volatile inline assembly in the bitmap of blocks specified by + BLOCKS or to the whole CFG if BLOCKS is zero. Return the number of blocks + that were split. + + The goal is to expose cases in which entering a basic block does not imply + that all subsequent instructions must be executed. */ + +int +flow_call_edges_add (sbitmap blocks) +{ + if (!cfg_hooks->flow_call_edges_add) + internal_error ("%s does not support flow_call_edges_add", + cfg_hooks->name); + + return (cfg_hooks->flow_call_edges_add) (blocks); +} diff --git a/gcc/cfghooks.h b/gcc/cfghooks.h index 4bffe74be9f..7cbe700df36 100644 --- a/gcc/cfghooks.h +++ b/gcc/cfghooks.h @@ -37,9 +37,10 @@ struct cfg_hooks basic_block (*create_basic_block) (void *head, void *end, basic_block after); /* Redirect edge E to the given basic block B and update underlying program - representation. Returns false when edge is not easily redirectable for - whatever reason. */ - bool (*redirect_edge_and_branch) (edge e, basic_block b); + representation. Returns edge representing redirected branch (that may not + be equivalent to E in the case of duplicate edges being removed) or NULL + if edge is not easily redirectable for whatever reason. */ + edge (*redirect_edge_and_branch) (edge e, basic_block b); /* Same as the above but allows redirecting of fallthru edges. In that case newly created forwarder basic block is returned. It aborts when called @@ -62,6 +63,19 @@ struct cfg_hooks /* Merge blocks A and B. */ void (*merge_blocks) (basic_block a, basic_block b); + /* Predict edge E using PREDICTOR to given PROBABILITY. */ + void (*predict_edge) (edge e, enum br_predictor predictor, int probability); + + /* Return true if the one of outgoing edges is already predicted by + PREDICTOR. */ + bool (*predicted_by_p) (basic_block bb, enum br_predictor predictor); + + /* Return true when block A can be duplicated. */ + bool (*can_duplicate_block_p) (basic_block a); + + /* Duplicate block A. */ + basic_block (*duplicate_block) (basic_block a); + /* Higher level functions representable by primitive operations above if we didn't have some oddities in RTL and Tree representations. */ basic_block (*split_edge) (edge); @@ -69,11 +83,28 @@ struct cfg_hooks /* Tries to make the edge fallthru. */ void (*tidy_fallthru_edge) (edge); + + /* Say whether a block ends with a call, possibly followed by some + other code that must stay with the call. */ + bool (*block_ends_with_call_p) (basic_block); + + /* Say whether a block ends with a conditional branch. Switches + and unconditional branches do not qualify. */ + bool (*block_ends_with_condjump_p) (basic_block); + + /* Add fake edges to the function exit for any non constant and non noreturn + calls, volatile inline assembly in the bitmap of blocks specified by + BLOCKS or to the whole CFG if BLOCKS is zero. Return the number of blocks + that were split. + + The goal is to expose cases in which entering a basic block does not imply + that all subsequent instructions must be executed. */ + int (*flow_call_edges_add) (sbitmap); }; extern void verify_flow_info (void); extern void dump_bb (basic_block, FILE *, int); -extern bool redirect_edge_and_branch (edge, basic_block); +extern edge redirect_edge_and_branch (edge, basic_block); extern basic_block redirect_edge_and_branch_force (edge, basic_block); extern edge split_block (basic_block, void *); extern edge split_block_after_labels (basic_block); @@ -88,13 +119,23 @@ extern edge make_forwarder_block (basic_block, bool (*)(edge), void (*) (basic_block)); extern void tidy_fallthru_edge (edge); extern void tidy_fallthru_edges (void); +extern void predict_edge (edge e, enum br_predictor predictor, int probability); +extern bool predicted_by_p (basic_block bb, enum br_predictor predictor); +extern bool can_duplicate_block_p (basic_block); +extern basic_block duplicate_block (basic_block, edge); +extern bool block_ends_with_call_p (basic_block bb); +extern bool block_ends_with_condjump_p (basic_block bb); +extern int flow_call_edges_add (sbitmap); /* Hooks containers. */ +extern struct cfg_hooks tree_cfg_hooks; extern struct cfg_hooks rtl_cfg_hooks; extern struct cfg_hooks cfg_layout_rtl_cfg_hooks; /* Declarations. */ +extern int ir_type (void); extern void rtl_register_cfg_hooks (void); extern void cfg_layout_rtl_register_cfg_hooks (void); +extern void tree_register_cfg_hooks (void); #endif /* GCC_CFGHOOKS_H */ diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index e62c60ab83f..8a57c68c2b2 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -41,8 +41,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA in this obstack, and all are freed at the end of the function. */ extern struct obstack flow_obstack; -alloc_pool cfg_layout_pool; - /* Holds the interesting trailing notes for the function. */ rtx cfg_layout_function_footer, cfg_layout_function_header; @@ -311,10 +309,14 @@ insn_locators_initialize (void) switch (NOTE_LINE_NUMBER (insn)) { case NOTE_INSN_BLOCK_BEG: + if (cfun->dont_emit_block_notes) + abort (); block = NOTE_BLOCK (insn); delete_insn (insn); break; case NOTE_INSN_BLOCK_END: + if (cfun->dont_emit_block_notes) + abort (); block = BLOCK_SUPERCONTEXT (block); if (block && TREE_CODE (block) == FUNCTION_DECL) block = 0; @@ -329,11 +331,17 @@ insn_locators_initialize (void) break; } } + + if (cfun->dont_emit_block_notes) + check_block_change (insn, &block); } /* Tag the blocks with a depth number so that change_scope can find the common parent easily. */ set_block_levels (DECL_INITIAL (cfun->decl), 0); + + if (cfun->dont_emit_block_notes) + free_block_changes (); } /* For each lexical block, set BLOCK_NUMBER to the depth at which it is @@ -771,7 +779,7 @@ fixup_reorder_chain (void) nb = force_nonfallthru (e_fall); if (nb) { - cfg_layout_initialize_rbi (nb); + initialize_bb_rbi (nb); nb->rbi->visited = 1; nb->rbi->next = bb->rbi->next; bb->rbi->next = nb; @@ -933,20 +941,15 @@ fixup_fallthru_exit_predecessor (void) /* Return true in case it is possible to duplicate the basic block BB. */ +/* We do not want to declare the function in a header file, since it should + only be used through the cfghooks interface, and we do not want to move + it to cfgrtl.c since it would require also moving quite a lot of related + code. */ +extern bool cfg_layout_can_duplicate_bb_p (basic_block); + bool cfg_layout_can_duplicate_bb_p (basic_block bb) { - edge s; - - if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR) - return false; - - /* Duplicating fallthru block to exit would require adding a jump - and splitting the real last BB. */ - for (s = bb->succ; s; s = s->succ_next) - if (s->dest == EXIT_BLOCK_PTR && s->flags & EDGE_FALLTHRU) - return false; - /* Do not attempt to duplicate tablejumps, as we need to unshare the dispatch table. This is difficult to do, as the instructions computing jump destination may be hoisted outside the basic block. */ @@ -1062,26 +1065,19 @@ duplicate_insn_chain (rtx from, rtx to) delete_insn (last); return insn; } -/* Create a duplicate of the basic block BB and redirect edge E into it. - If E is not specified, BB is just copied, but updating the frequencies - etc. is left to the caller. */ +/* Create a duplicate of the basic block BB. */ + +/* We do not want to declare the function in a header file, since it should + only be used through the cfghooks interface, and we do not want to move + it to cfgrtl.c since it would require also moving quite a lot of related + code. */ +extern basic_block cfg_layout_duplicate_bb (basic_block); basic_block -cfg_layout_duplicate_bb (basic_block bb, edge e) +cfg_layout_duplicate_bb (basic_block bb) { rtx insn; - edge s, n; basic_block new_bb; - gcov_type new_count = e ? e->count : 0; - - if (bb->count < new_count) - new_count = bb->count; - if (!bb->pred) - abort (); -#ifdef ENABLE_CHECKING - if (!cfg_layout_can_duplicate_bb_p (bb)) - abort (); -#endif insn = duplicate_insn_chain (BB_HEAD (bb), BB_END (bb)); new_bb = create_basic_block (insn, @@ -1116,62 +1112,9 @@ cfg_layout_duplicate_bb (basic_block bb, edge e) COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end); } - new_bb->loop_depth = bb->loop_depth; - new_bb->flags = bb->flags; - for (s = bb->succ; s; s = s->succ_next) - { - /* Since we are creating edges from a new block to successors - of another block (which therefore are known to be disjoint), there - is no need to actually check for duplicated edges. */ - n = unchecked_make_edge (new_bb, s->dest, s->flags); - n->probability = s->probability; - if (e && bb->count) - { - /* Take care for overflows! */ - n->count = s->count * (new_count * 10000 / bb->count) / 10000; - s->count -= n->count; - } - else - n->count = s->count; - n->aux = s->aux; - } - - if (e) - { - new_bb->count = new_count; - bb->count -= new_count; - - new_bb->frequency = EDGE_FREQUENCY (e); - bb->frequency -= EDGE_FREQUENCY (e); - - redirect_edge_and_branch_force (e, new_bb); - - if (bb->count < 0) - bb->count = 0; - if (bb->frequency < 0) - bb->frequency = 0; - } - else - { - new_bb->count = bb->count; - new_bb->frequency = bb->frequency; - } - - new_bb->rbi->original = bb; - bb->rbi->copy = new_bb; - return new_bb; } -void -cfg_layout_initialize_rbi (basic_block bb) -{ - if (bb->rbi) - abort (); - bb->rbi = pool_alloc (cfg_layout_pool); - memset (bb->rbi, 0, sizeof (struct reorder_block_def)); -} - /* Main entry point to this module - initialize the data structures for CFG layout changes. It keeps LOOPS up-to-date if not null. */ @@ -1180,13 +1123,12 @@ cfg_layout_initialize (void) { basic_block bb; - /* Our algorithm depends on fact that there are now dead jumptables + /* Our algorithm depends on fact that there are no dead jumptables around the code. */ - cfg_layout_pool = - create_alloc_pool ("cfg layout pool", sizeof (struct reorder_block_def), - n_basic_blocks + 2); + alloc_rbi_pool (); + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) - cfg_layout_initialize_rbi (bb); + initialize_bb_rbi (bb); cfg_layout_rtl_register_cfg_hooks (); @@ -1242,7 +1184,7 @@ cfg_layout_finalize (void) verify_insn_chain (); #endif - free_alloc_pool (cfg_layout_pool); + free_rbi_pool (); FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) bb->rbi = NULL; @@ -1275,7 +1217,7 @@ can_copy_bbs_p (basic_block *bbs, unsigned n) goto end; } - if (!cfg_layout_can_duplicate_bb_p (bbs[i])) + if (!can_duplicate_block_p (bbs[i])) { ret = false; break; @@ -1318,7 +1260,7 @@ copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs, { /* Duplicate. */ bb = bbs[i]; - new_bb = new_bbs[i] = cfg_layout_duplicate_bb (bb, NULL); + new_bb = new_bbs[i] = duplicate_block (bb, NULL); bb->rbi->duplicated = 1; /* Add to loop. */ add_bb_to_loop (new_bb, bb->loop_father->copy); diff --git a/gcc/cfglayout.h b/gcc/cfglayout.h index 0361dc68e05..b074f642633 100644 --- a/gcc/cfglayout.h +++ b/gcc/cfglayout.h @@ -18,31 +18,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* Structure to hold information about the blocks during reordering. */ -typedef struct reorder_block_def -{ - rtx header; - rtx footer; - basic_block next; - basic_block original; - /* Used by loop copying. */ - basic_block copy; - int duplicated; - - /* These fields are used by bb-reorder pass. */ - int visited; -} *reorder_block_def; - extern rtx cfg_layout_function_footer; extern void cfg_layout_initialize (void); extern void cfg_layout_finalize (void); -extern bool cfg_layout_can_duplicate_bb_p (basic_block); -extern basic_block cfg_layout_duplicate_bb (basic_block, edge); extern void insn_locators_initialize (void); extern void reemit_insn_block_notes (void); extern bool can_copy_bbs_p (basic_block *, unsigned); extern void copy_bbs (basic_block *, unsigned, basic_block *, edge *, unsigned, edge *, struct loop *); -extern void cfg_layout_initialize_rbi (basic_block); extern bool scan_ahead_for_unlikely_executed_note (rtx); diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c index 2be4b7cc0b7..3d13386ba4e 100644 --- a/gcc/cfgloop.c +++ b/gcc/cfgloop.c @@ -28,6 +28,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "toplev.h" #include "cfgloop.h" #include "flags.h" +#include "tree.h" +#include "tree-flow.h" /* Ratio of frequencies of edges so that one of more latch edges is considered to belong to inner loop with same header. */ diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index b233d2652c6..d9c758408f2 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -237,6 +237,7 @@ extern void flow_loop_dump (const struct loop *, FILE *, extern int flow_loop_scan (struct loop *, int); extern void flow_loop_free (struct loop *); void mark_irreducible_loops (struct loops *); +extern void create_loop_notes (void); /* Loop data structure manipulation/querying. */ extern void flow_loop_tree_node_add (struct loop *, struct loop *); diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c index e3807801d23..9e10d8e6ccb 100644 --- a/gcc/cfgloopmanip.c +++ b/gcc/cfgloopmanip.c @@ -1242,3 +1242,99 @@ loop_split_edge_with (edge e, rtx insns) return new_bb; } + +/* Uses the natural loop discovery to recreate loop notes. */ +void +create_loop_notes (void) +{ + rtx insn, head, end; + struct loops loops; + struct loop *loop; + basic_block *first, *last, bb, pbb; + struct loop **stack, **top; + +#ifdef ENABLE_CHECKING + /* Verify that there really are no loop notes. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == NOTE + && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) + abort (); +#endif + + flow_loops_find (&loops, LOOP_TREE); + free_dominance_info (CDI_DOMINATORS); + if (loops.num > 1) + { + last = xcalloc (loops.num, sizeof (basic_block)); + + FOR_EACH_BB (bb) + { + for (loop = bb->loop_father; loop->outer; loop = loop->outer) + last[loop->num] = bb; + } + + first = xcalloc (loops.num, sizeof (basic_block)); + stack = xcalloc (loops.num, sizeof (struct loop *)); + top = stack; + + FOR_EACH_BB (bb) + { + for (loop = bb->loop_father; loop->outer; loop = loop->outer) + { + if (!first[loop->num]) + { + *top++ = loop; + first[loop->num] = bb; + } + + if (bb == last[loop->num]) + { + /* Prevent loops from overlapping. */ + while (*--top != loop) + last[(*top)->num] = EXIT_BLOCK_PTR; + + /* If loop starts with jump into it, place the note in + front of the jump. */ + insn = PREV_INSN (BB_HEAD (first[loop->num])); + if (insn + && GET_CODE (insn) == BARRIER) + insn = PREV_INSN (insn); + + if (insn + && GET_CODE (insn) == JUMP_INSN + && any_uncondjump_p (insn) + && onlyjump_p (insn)) + { + pbb = BLOCK_FOR_INSN (insn); + if (!pbb || !pbb->succ || pbb->succ->succ_next) + abort (); + + if (!flow_bb_inside_loop_p (loop, pbb->succ->dest)) + insn = BB_HEAD (first[loop->num]); + } + else + insn = BB_HEAD (first[loop->num]); + + head = BB_HEAD (first[loop->num]); + emit_note_before (NOTE_INSN_LOOP_BEG, insn); + BB_HEAD (first[loop->num]) = head; + + /* Position the note correctly wrto barrier. */ + insn = BB_END (last[loop->num]); + if (NEXT_INSN (insn) + && GET_CODE (NEXT_INSN (insn)) == BARRIER) + insn = NEXT_INSN (insn); + + end = BB_END (last[loop->num]); + emit_note_after (NOTE_INSN_LOOP_END, insn); + BB_END (last[loop->num]) = end; + } + } + } + + free (first); + free (last); + free (stack); + } + flow_loops_free (&loops); +} diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 461eb34a6f7..486128a0074 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -74,12 +74,12 @@ static basic_block rtl_split_edge (edge); static bool rtl_move_block_after (basic_block, basic_block); static int rtl_verify_flow_info (void); static basic_block cfg_layout_split_block (basic_block, void *); -static bool cfg_layout_redirect_edge_and_branch (edge, basic_block); +static edge cfg_layout_redirect_edge_and_branch (edge, basic_block); static basic_block cfg_layout_redirect_edge_and_branch_force (edge, basic_block); static void cfg_layout_delete_block (basic_block); static void rtl_delete_block (basic_block); static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block); -static bool rtl_redirect_edge_and_branch (edge, basic_block); +static edge rtl_redirect_edge_and_branch (edge, basic_block); static basic_block rtl_split_block (basic_block, void *); static void rtl_dump_bb (basic_block, FILE *, int); static int rtl_verify_flow_info_1 (void); @@ -259,7 +259,6 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after) basic_block bb; if (bb_note - && ! RTX_INTEGRATED_P (bb_note) && (bb = NOTE_BASIC_BLOCK (bb_note)) != NULL && bb->aux == NULL) { @@ -354,7 +353,7 @@ cfg_layout_create_basic_block (void *head, void *end, basic_block after) { basic_block newbb = rtl_create_basic_block (head, end, after); - cfg_layout_initialize_rbi (newbb); + initialize_bb_rbi (newbb); return newbb; } @@ -392,8 +391,6 @@ rtl_delete_block (basic_block b) insn = BB_HEAD (b); - never_reached_warning (insn, BB_END (b)); - if (GET_CODE (insn) == CODE_LABEL) maybe_remove_eh_handler (insn); @@ -666,7 +663,7 @@ block_label (basic_block block) apply only if all edges now point to the same block. The parameters and return values are equivalent to redirect_edge_and_branch. */ -bool +edge try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) { basic_block src = e->src; @@ -690,14 +687,14 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) break; if (tmp || !onlyjump_p (insn)) - return false; + return NULL; if ((!optimize || reload_completed) && tablejump_p (insn, NULL, NULL)) - return false; + return NULL; /* Avoid removing branch with side effects. */ set = single_set (insn); if (!set || side_effects_p (set)) - return false; + return NULL; /* In case we zap a conditional jump, we'll need to kill the cc0 setter too. */ @@ -746,21 +743,21 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) else if (simplejump_p (insn)) { if (e->dest == target) - return false; + return NULL; if (dump_file) fprintf (dump_file, "Redirecting jump %i from %i to %i.\n", INSN_UID (insn), e->dest->index, target->index); if (!redirect_jump (insn, block_label (target), 0)) { if (target == EXIT_BLOCK_PTR) - return false; + return NULL; abort (); } } /* Cannot do anything for target exit block. */ else if (target == EXIT_BLOCK_PTR) - return false; + return NULL; /* Or replace possibly complicated jump insn by simple jump insn. */ else @@ -834,7 +831,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) if (e->dest != target) redirect_edge_succ (e, target); - return true; + return e; } /* Return last loop_beg note appearing after INSN, before start of next @@ -859,8 +856,9 @@ last_loop_beg_note (rtx insn) return last; } -/* Redirect edge representing branch of (un)conditional jump or tablejump. */ -static bool +/* Redirect edge representing branch of (un)conditional jump or tablejump, + NULL on failure */ +static edge redirect_branch_edge (edge e, basic_block target) { rtx tmp; @@ -870,9 +868,9 @@ redirect_branch_edge (edge e, basic_block target) /* We can only redirect non-fallthru edges of jump insn. */ if (e->flags & EDGE_FALLTHRU) - return false; + return NULL; else if (GET_CODE (insn) != JUMP_INSN) - return false; + return NULL; /* Recognize a tablejump and adjust all matching cases. */ if (tablejump_p (insn, NULL, &tmp)) @@ -882,7 +880,7 @@ redirect_branch_edge (edge e, basic_block target) rtx new_label = block_label (target); if (target == EXIT_BLOCK_PTR) - return false; + return NULL; if (GET_CODE (PATTERN (tmp)) == ADDR_VEC) vec = XVEC (PATTERN (tmp), 0); else @@ -917,7 +915,7 @@ redirect_branch_edge (edge e, basic_block target) if (computed_jump_p (insn) /* A return instruction can't be redirected. */ || returnjump_p (insn)) - return false; + return NULL; /* If the insn doesn't go where we think, we're confused. */ if (JUMP_LABEL (insn) != old_label) @@ -929,7 +927,7 @@ redirect_branch_edge (edge e, basic_block target) if (!redirect_jump (insn, block_label (target), 0)) { if (target == EXIT_BLOCK_PTR) - return false; + return NULL; abort (); } } @@ -939,8 +937,8 @@ redirect_branch_edge (edge e, basic_block target) e->src->index, e->dest->index, target->index); if (e->dest != target) - redirect_edge_succ_nodup (e, target); - return true; + e = redirect_edge_succ_nodup (e, target); + return e; } /* Attempt to change code to redirect edge E to TARGET. Don't do that on @@ -949,32 +947,35 @@ redirect_branch_edge (edge e, basic_block target) Function can be also called with edge destination equivalent to the TARGET. Then it should try the simplifications and do nothing if none is possible. - Return true if transformation succeeded. We still return false in case E - already destinated TARGET and we didn't managed to simplify instruction - stream. */ + Return edge representing the branch if transformation succeeded. Return NULL + on failure. + We still return NULL in case E already destinated TARGET and we didn't + managed to simplify instruction stream. */ -static bool +static edge rtl_redirect_edge_and_branch (edge e, basic_block target) { + edge ret; basic_block src = e->src; if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH)) - return false; + return NULL; if (e->dest == target) - return true; + return e; - if (try_redirect_by_replacing_jump (e, target, false)) + if ((ret = try_redirect_by_replacing_jump (e, target, false)) != NULL) { src->flags |= BB_DIRTY; - return true; + return ret; } - if (!redirect_branch_edge (e, target)) - return false; + ret = redirect_branch_edge (e, target); + if (!ret) + return NULL; src->flags |= BB_DIRTY; - return true; + return ret; } /* Like force_nonfallthru below, but additionally performs redirection @@ -1376,14 +1377,14 @@ insert_insn_on_edge (rtx pattern, edge e) if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e)) abort (); - if (e->insns == NULL_RTX) + if (e->insns.r == NULL_RTX) start_sequence (); else - push_to_sequence (e->insns); + push_to_sequence (e->insns.r); emit_insn (pattern); - e->insns = get_insns (); + e->insns.r = get_insns (); end_sequence (); } @@ -1491,8 +1492,8 @@ commit_one_edge_insertion (edge e, int watch_calls) basic_block bb = NULL; /* Pull the insns off the edge now since the edge might go away. */ - insns = e->insns; - e->insns = NULL_RTX; + insns = e->insns.r; + e->insns.r = NULL_RTX; /* Special case -- avoid inserting code between call and storing its return value. */ @@ -1663,10 +1664,10 @@ commit_edge_insertions (void) for (e = bb->succ; e; e = next) { next = e->succ_next; - if (e->insns) + if (e->insns.r) { - changed = true; - commit_one_edge_insertion (e, false); + changed = true; + commit_one_edge_insertion (e, false); } } } @@ -1711,7 +1712,7 @@ commit_edge_insertions_watch_calls (void) for (e = bb->succ; e; e = next) { next = e->succ_next; - if (e->insns) + if (e->insns.r) { changed = true; commit_one_edge_insertion (e, true); @@ -2467,23 +2468,23 @@ cfg_layout_split_block (basic_block bb, void *insnp) /* Redirect Edge to DEST. */ -static bool +static edge cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) { basic_block src = e->src; - bool ret; + edge ret; if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH)) - return false; + return NULL; if (e->dest == dest) - return true; + return e; if (e->src != ENTRY_BLOCK_PTR - && try_redirect_by_replacing_jump (e, dest, true)) + && (ret = try_redirect_by_replacing_jump (e, dest, true))) { src->flags |= BB_DIRTY; - return true; + return ret; } if (e->src == ENTRY_BLOCK_PTR @@ -2495,7 +2496,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) e->src->flags |= BB_DIRTY; redirect_edge_succ (e, dest); - return true; + return e; } /* Redirect_edge_and_branch may decide to turn branch into fallthru edge @@ -2518,7 +2519,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) abort (); e->flags |= EDGE_FALLTHRU; e->src->flags |= BB_DIRTY; - return true; + return e; } /* In case we are redirecting fallthru edge to the branch edge of conditional jump, remove it. */ @@ -2531,13 +2532,10 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest) && onlyjump_p (BB_END (src))) delete_insn (BB_END (src)); } - + ret = redirect_edge_succ_nodup (e, dest); if (dump_file) fprintf (dump_file, "Fallthru edge %i->%i redirected to %i\n", e->src->index, e->dest->index, dest->index); - redirect_edge_succ_nodup (e, dest); - - ret = true; } else ret = redirect_branch_edge (e, dest); @@ -2781,6 +2779,179 @@ rtl_make_forwarder_block (edge fallthru ATTRIBUTE_UNUSED) { } +/* Return 1 if BB ends with a call, possibly followed by some + instructions that must stay with the call, 0 otherwise. */ + +static bool +rtl_block_ends_with_call_p (basic_block bb) +{ + rtx insn = BB_END (bb); + + while (GET_CODE (insn) != CALL_INSN + && insn != BB_HEAD (bb) + && keep_with_call_p (insn)) + insn = PREV_INSN (insn); + return (GET_CODE (insn) == CALL_INSN); +} + +/* Return 1 if BB ends with a conditional branch, 0 otherwise. */ + +static bool +rtl_block_ends_with_condjump_p (basic_block bb) +{ + return any_condjump_p (BB_END (bb)); +} + +/* Return true if we need to add fake edge to exit. + Helper function for rtl_flow_call_edges_add. */ + +static bool +need_fake_edge_p (rtx insn) +{ + if (!INSN_P (insn)) + return false; + + if ((GET_CODE (insn) == CALL_INSN + && !SIBLING_CALL_P (insn) + && !find_reg_note (insn, REG_NORETURN, NULL) + && !find_reg_note (insn, REG_ALWAYS_RETURN, NULL) + && !CONST_OR_PURE_CALL_P (insn))) + return true; + + return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS + && MEM_VOLATILE_P (PATTERN (insn))) + || (GET_CODE (PATTERN (insn)) == PARALLEL + && asm_noperands (insn) != -1 + && MEM_VOLATILE_P (XVECEXP (PATTERN (insn), 0, 0))) + || GET_CODE (PATTERN (insn)) == ASM_INPUT); +} + +/* Add fake edges to the function exit for any non constant and non noreturn + calls, volatile inline assembly in the bitmap of blocks specified by + BLOCKS or to the whole CFG if BLOCKS is zero. Return the number of blocks + that were split. + + The goal is to expose cases in which entering a basic block does not imply + that all subsequent instructions must be executed. */ + +static int +rtl_flow_call_edges_add (sbitmap blocks) +{ + int i; + int blocks_split = 0; + int last_bb = last_basic_block; + bool check_last_block = false; + + if (n_basic_blocks == 0) + return 0; + + if (! blocks) + check_last_block = true; + else + check_last_block = TEST_BIT (blocks, EXIT_BLOCK_PTR->prev_bb->index); + + /* In the last basic block, before epilogue generation, there will be + a fallthru edge to EXIT. Special care is required if the last insn + of the last basic block is a call because make_edge folds duplicate + edges, which would result in the fallthru edge also being marked + fake, which would result in the fallthru edge being removed by + remove_fake_edges, which would result in an invalid CFG. + + Moreover, we can't elide the outgoing fake edge, since the block + profiler needs to take this into account in order to solve the minimal + spanning tree in the case that the call doesn't return. + + Handle this by adding a dummy instruction in a new last basic block. */ + if (check_last_block) + { + basic_block bb = EXIT_BLOCK_PTR->prev_bb; + rtx insn = BB_END (bb); + + /* Back up past insns that must be kept in the same block as a call. */ + while (insn != BB_HEAD (bb) + && keep_with_call_p (insn)) + insn = PREV_INSN (insn); + + if (need_fake_edge_p (insn)) + { + edge e; + + for (e = bb->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR) + { + insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e); + commit_edge_insertions (); + break; + } + } + } + + /* Now add fake edges to the function exit for any non constant + calls since there is no way that we can determine if they will + return or not... */ + + for (i = 0; i < last_bb; i++) + { + basic_block bb = BASIC_BLOCK (i); + rtx insn; + rtx prev_insn; + + if (!bb) + continue; + + if (blocks && !TEST_BIT (blocks, i)) + continue; + + for (insn = BB_END (bb); ; insn = prev_insn) + { + prev_insn = PREV_INSN (insn); + if (need_fake_edge_p (insn)) + { + edge e; + rtx split_at_insn = insn; + + /* Don't split the block between a call and an insn that should + remain in the same block as the call. */ + if (GET_CODE (insn) == CALL_INSN) + while (split_at_insn != BB_END (bb) + && keep_with_call_p (NEXT_INSN (split_at_insn))) + split_at_insn = NEXT_INSN (split_at_insn); + + /* The handling above of the final block before the epilogue + should be enough to verify that there is no edge to the exit + block in CFG already. Calling make_edge in such case would + cause us to mark that edge as fake and remove it later. */ + +#ifdef ENABLE_CHECKING + if (split_at_insn == BB_END (bb)) + for (e = bb->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR) + abort (); +#endif + + /* Note that the following may create a new basic block + and renumber the existing basic blocks. */ + if (split_at_insn != BB_END (bb)) + { + e = split_block (bb, split_at_insn); + if (e) + blocks_split++; + } + + make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE); + } + + if (insn == BB_HEAD (bb)) + break; + } + } + + if (blocks_split) + verify_flow_info (); + + return blocks_split; +} + /* Implementation of CFG manipulation for linearized RTL. */ struct cfg_hooks rtl_cfg_hooks = { "rtl", @@ -2794,15 +2965,30 @@ struct cfg_hooks rtl_cfg_hooks = { rtl_move_block_after, rtl_can_merge_blocks, /* can_merge_blocks_p */ rtl_merge_blocks, + rtl_predict_edge, + rtl_predicted_by_p, + NULL, /* can_duplicate_block_p */ + NULL, /* duplicate_block */ rtl_split_edge, rtl_make_forwarder_block, - rtl_tidy_fallthru_edge + rtl_tidy_fallthru_edge, + rtl_block_ends_with_call_p, + rtl_block_ends_with_condjump_p, + rtl_flow_call_edges_add }; /* Implementation of CFG manipulation for cfg layout RTL, where basic block connected via fallthru edges does not have to be adjacent. This representation will hopefully become the default one in future version of the compiler. */ + +/* We do not want to declare these functions in a header file, since they + should only be used through the cfghooks interface, and we do not want to + move them here since it would require also moving quite a lot of related + code. */ +extern bool cfg_layout_can_duplicate_bb_p (basic_block); +extern basic_block cfg_layout_duplicate_bb (basic_block); + struct cfg_hooks cfg_layout_rtl_cfg_hooks = { "cfglayout mode", rtl_verify_flow_info_1, @@ -2815,7 +3001,15 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = { rtl_move_block_after, cfg_layout_can_merge_blocks_p, cfg_layout_merge_blocks, + rtl_predict_edge, + rtl_predicted_by_p, + cfg_layout_can_duplicate_bb_p, + cfg_layout_duplicate_bb, cfg_layout_split_edge, rtl_make_forwarder_block, - NULL + NULL, + rtl_block_ends_with_call_p, + rtl_block_ends_with_condjump_p, + rtl_flow_call_edges_add }; + diff --git a/gcc/cgraph.c b/gcc/cgraph.c index c1e66f933a6..5669edd8f08 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -407,16 +407,6 @@ cgraph_mark_reachable_node (struct cgraph_node *node) node->next_needed = cgraph_nodes_queue; cgraph_nodes_queue = node; - - /* At the moment frontend automatically emits all nested functions. */ - if (node->nested) - { - struct cgraph_node *node2; - - for (node2 = node->nested; node2; node2 = node2->next_nested) - if (!node2->reachable) - cgraph_mark_reachable_node (node2); - } } } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 617861be1ce..c76b5dc6caf 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -30,7 +30,6 @@ struct cgraph_local_info GTY(()) { /* Size of the function before inlining. */ int self_insns; - /* Set when function function is visible in current compilation unit only and it's address is never taken. */ bool local; @@ -66,9 +65,9 @@ struct cgraph_global_info GTY(()) struct cgraph_rtl_info GTY(()) { + int preferred_incoming_stack_boundary; bool const_function; bool pure_function; - int preferred_incoming_stack_boundary; }; diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index e9402dbfb6e..c079e404ee5 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -216,6 +216,8 @@ static htab_t visited_nodes; static bool decide_is_function_needed (struct cgraph_node *node, tree decl) { + struct cgraph_node *origin; + /* If we decided it was needed before, but at the time we didn't have the body of the function available, then it's still needed. We have to go back and re-check its dependencies now. */ @@ -252,6 +254,11 @@ decide_is_function_needed (struct cgraph_node *node, tree decl) /* "extern inline" functions are never output locally. */ if (DECL_EXTERNAL (decl)) return false; + /* Nested functions of extern inline function shall not be emit unless + we inlined the origin. */ + for (origin = node->origin; origin; origin = origin->origin) + if (DECL_EXTERNAL (origin->decl)) + return false; /* We want to emit COMDAT functions only when absolutely necessary. */ if (DECL_COMDAT (decl)) return false; @@ -283,7 +290,7 @@ cgraph_assemble_pending_functions (void) cgraph_nodes_queue = cgraph_nodes_queue->next_needed; n->next_needed = NULL; - if (!n->origin && !n->global.inlined_to && !DECL_EXTERNAL (n->decl)) + if (!n->global.inlined_to && !DECL_EXTERNAL (n->decl)) { cgraph_expand_function (n); output = true; @@ -374,11 +381,6 @@ cgraph_finalize_function (tree decl, bool nested) if (!TREE_ASM_WRITTEN (decl)) (*debug_hooks->deferred_inline_function) (decl); - /* We will never really output the function body, clear the STRUCT_FUNCTION array - early then. */ - if (DECL_EXTERNAL (decl)) - DECL_STRUCT_FUNCTION (decl) = NULL; - /* Possibly warn about unused parameters. */ if (warn_unused_parameter) do_warn_unused_parameter (decl); @@ -618,9 +620,7 @@ cgraph_analyze_function (struct cgraph_node *node) cgraph_create_edges (node, DECL_SAVED_TREE (decl)); node->local.inlinable = tree_inlinable_function_p (decl); - if (!node->local.self_insns) - node->local.self_insns - = lang_hooks.tree_inlining.estimate_num_insns (decl); + node->local.self_insns = estimate_num_insns (DECL_SAVED_TREE (decl)); if (node->local.inlinable) node->local.disregard_inline_limits = lang_hooks.tree_inlining.disregard_inline_limits (decl); @@ -737,7 +737,6 @@ cgraph_finalize_compilation_unit (void) ggc_collect (); timevar_pop (TV_CGRAPH); } - /* Figure out what functions we want to assemble. */ static void @@ -749,7 +748,6 @@ cgraph_mark_functions_to_output (void) { tree decl = node->decl; struct cgraph_edge *e; - if (node->output) abort (); @@ -764,12 +762,12 @@ cgraph_mark_functions_to_output (void) && !node->global.inlined_to && (node->needed || (e && node->reachable)) - && !TREE_ASM_WRITTEN (decl) && !node->origin + && !TREE_ASM_WRITTEN (decl) && !DECL_EXTERNAL (decl)) node->output = 1; /* We should've reclaimed all functions that are not needed. */ else if (!node->global.inlined_to && DECL_SAVED_TREE (decl) - && !node->origin && !DECL_EXTERNAL (decl)) + && !DECL_EXTERNAL (decl)) { dump_cgraph_node (stderr, node); abort (); @@ -794,15 +792,21 @@ cgraph_expand_function (struct cgraph_node *node) /* Generate RTL for the body of DECL. Nested functions are expanded via lang_expand_decl_stmt. */ lang_hooks.callgraph.expand_function (decl); - if (DECL_DEFER_OUTPUT (decl)) - abort (); - /* Make sure that BE didn't gave up on compiling. */ - if (!TREE_ASM_WRITTEN (node->decl) - && !(sorrycount || errorcount)) + /* Make sure that BE didn't give up on compiling. */ + /* ??? Can happen with nested function of extern inline. */ + if (!TREE_ASM_WRITTEN (node->decl)) abort (); current_function_decl = NULL; + if (DECL_SAVED_TREE (node->decl) + && !cgraph_preserve_function_body_p (node->decl)) + { + DECL_SAVED_TREE (node->decl) = NULL; + DECL_STRUCT_FUNCTION (node->decl) = NULL; + DECL_ARGUMENTS (node->decl) = NULL; + DECL_INITIAL (node->decl) = error_mark_node; + } } /* Fill array order with all nodes with output flag set in the reverse @@ -822,7 +826,7 @@ cgraph_postorder (struct cgraph_node **order) /* We have to deal with cycles nicely, so use a depth first traversal output algorithm. Ignore the fact that some functions won't need to be output and put them into order as well, so we get dependencies - right throughout inline functions. */ + right through intline functions. */ for (node = cgraph_nodes; node; node = node->next) node->aux = NULL; for (node = cgraph_nodes; node; node = node->next) @@ -921,7 +925,7 @@ cgraph_remove_unreachable_nodes (void) /* Remove unreachable nodes. Extern inline functions need special care; Unreachable extern inline functions shall be removed. Reachable extern inline functions we never inlined shall get their bodies - eliminated + eliminated. Reachable extern inline functions we sometimes inlined will be turned into unanalyzed nodes so they look like for true extern functions to the rest of code. Body of such functions is released via remove_node once the @@ -1008,7 +1012,7 @@ cgraph_estimate_growth (struct cgraph_node *node) /* ??? Wrong for self recursive functions or cases where we decide to not inline for different reasons, but it is not big deal as in that case we will keep the body around, but we will also avoid some inlining. */ - if (!node->needed && !node->origin && !DECL_EXTERNAL (node->decl)) + if (!node->needed && !DECL_EXTERNAL (node->decl)) growth -= node->global.insns; return growth; @@ -1028,7 +1032,6 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate) case just go ahead and re-use it. */ if (!e->callee->callers->next_caller && (!e->callee->needed || DECL_EXTERNAL (e->callee->decl)) - && !e->callee->origin && duplicate && flag_unit_at_a_time) { @@ -1191,28 +1194,17 @@ cgraph_recursive_inlining_p (struct cgraph_node *to, struct cgraph_node *what, const char **reason) { - struct cgraph_node *node; - - /* Walk TO and all functions TO is inlined in. */ - while (1) - { - /* We create recursive inlining either by inlining WHAT into something - already inlined in possibly different clone of WHAT. */ - if (what->decl == to->decl) - goto recursive; - /* Or by inlining WHAT into something that is already inlined in WHAT. */ - for (node = cgraph_node (to->decl); node; node = node->next_clone) - if (node->global.inlined_to == what) - goto recursive; - if (!to->callers || to->callers->inline_failed) - return false; - to = to->callers->caller; - } -recursive: - if (reason) + bool recursive; + if (to->global.inlined_to) + recursive = what->decl == to->global.inlined_to->decl; + else + recursive = what->decl == to->decl; + /* Marking recursive function inlinine has sane semantic and thus we should + not warn on it. */ + if (recursive && reason) *reason = (what->local.disregard_inline_limits ? N_("recursive inlining") : ""); - return true; + return recursive; } /* Recompute heap nodes for each of callees. */ @@ -1230,6 +1222,110 @@ update_callee_keys (fibheap_t heap, struct fibnode **heap_node, update_callee_keys (heap, heap_node, e->callee); } +/* Enqueue all recursive calls from NODE into queue linked via aux pointers + in between FIRST and LAST. WHERE is used for bookkeeping while looking + int calls inlined within NODE. */ +static void +lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where, + struct cgraph_edge **first, struct cgraph_edge **last) +{ + struct cgraph_edge *e; + for (e = where->callees; e; e = e->next_callee) + if (e->callee == node) + { + if (!*first) + *first = e; + else + (*last)->aux = e; + *last = e; + } + for (e = where->callees; e; e = e->next_callee) + if (!e->inline_failed) + lookup_recursive_calls (node, e->callee, first, last); +} + +/* Decide on recursive inlining: in the case function has recursive calls, + inline until body size reaches given argument. */ +static void +cgraph_decide_recursive_inlining (struct cgraph_node *node) +{ + int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO); + int max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO); + struct cgraph_edge *first_call = NULL, *last_call = NULL; + struct cgraph_edge *last_in_current_depth; + struct cgraph_edge *e; + struct cgraph_node *master_clone; + int depth = 0; + int n = 0; + + if (DECL_DECLARED_INLINE_P (node->decl)) + { + limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE); + max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH); + } + + /* Make sure that function is small enought to be considered for inlining. */ + if (!max_depth + || cgraph_estimate_size_after_inlining (1, node, node) >= limit) + return; + lookup_recursive_calls (node, node, &first_call, &last_call); + if (!first_call) + return; + + if (cgraph_dump_file) + fprintf (cgraph_dump_file, + "\nPerforming recursive inlining on %s\n", + cgraph_node_name (node)); + + /* We need original clone to copy around. */ + master_clone = cgraph_clone_node (node); + master_clone->needed = true; + for (e = master_clone->callees; e; e = e->next_callee) + if (!e->inline_failed) + cgraph_clone_inlined_nodes (e, true); + + /* Do the inlining and update list of recursive call during process. */ + last_in_current_depth = last_call; + while (first_call + && cgraph_estimate_size_after_inlining (1, node, master_clone) <= limit) + { + struct cgraph_edge *curr = first_call; + + first_call = first_call->aux; + curr->aux = NULL; + + cgraph_redirect_edge_callee (curr, master_clone); + cgraph_mark_inline_edge (curr); + lookup_recursive_calls (node, curr->callee, &first_call, &last_call); + + if (last_in_current_depth + && ++depth >= max_depth) + break; + n++; + } + + /* Cleanup queue pointers. */ + while (first_call) + { + struct cgraph_edge *next = first_call->aux; + first_call->aux = NULL; + first_call = next; + } + if (cgraph_dump_file) + fprintf (cgraph_dump_file, + "\n Inlined %i times, body grown from %i to %i insns\n", n, + master_clone->global.insns, node->global.insns); + + /* Remove master clone we used for inlining. We rely that clones inlined + into master clone gets queued just before master clone so we don't + need recursion. */ + for (node = cgraph_nodes; node != master_clone; + node = node->next) + if (node->global.inlined_to == master_clone) + cgraph_remove_node (node); + cgraph_remove_node (master_clone); +} + /* Set inline_failed for all callers of given function to REASON. */ static void @@ -1333,6 +1429,8 @@ cgraph_decide_inlining_of_small_functions (void) } } + cgraph_decide_recursive_inlining (node); + /* Similarly all functions called by the function we just inlined are now called more times; update keys. */ update_callee_keys (heap, heap_node, node); @@ -1383,38 +1481,36 @@ cgraph_decide_inlining (void) so none of our later choices will make this impossible. */ for (i = nnodes - 1; i >= 0; i--) { - struct cgraph_edge *e; + struct cgraph_edge *e, *next; node = order[i]; - for (e = node->callees; e; e = e->next_callee) - if (e->callee->local.disregard_inline_limits) - break; - if (!e) + if (!node->local.disregard_inline_limits) continue; if (cgraph_dump_file) fprintf (cgraph_dump_file, "\nConsidering %s %i insns (always inline)\n", cgraph_node_name (e->callee), e->callee->global.insns); - for (; e; e = e->next_callee) + old_insns = overall_insns; + for (e = node->callers; e; e = next) { - old_insns = overall_insns; - if (!e->inline_failed || !e->callee->local.disregard_inline_limits) + next = e->next_caller; + if (!e->inline_failed) continue; - if (cgraph_recursive_inlining_p (order[i], e->callee, + if (cgraph_recursive_inlining_p (e->caller, e->callee, &e->inline_failed)) continue; - cgraph_mark_inline (e); + cgraph_mark_inline_edge (e); if (cgraph_dump_file) fprintf (cgraph_dump_file, " Inlined into %s which now has %i insns.\n", cgraph_node_name (node->callees->caller), node->callees->caller->global.insns); } - if (cgraph_dump_file) - fprintf (cgraph_dump_file, - " Inlined for a net change of %+i insns.\n", - overall_insns - old_insns); + if (cgraph_dump_file) + fprintf (cgraph_dump_file, + " Inlined for a net change of %+i insns.\n", + overall_insns - old_insns); } if (!flag_really_no_inline) @@ -1675,5 +1771,25 @@ cgraph_optimize (void) } #ifdef ENABLE_CHECKING verify_cgraph (); + /* Double check that all inline clones are gone and that all + function bodies have been released from memory. */ + if (flag_unit_at_a_time + && !dump_enabled_p (TDI_all) + && !(sorrycount || errorcount)) + { + struct cgraph_node *node; + bool error_found = false; + + for (node = cgraph_nodes; node; node = node->next) + if (node->analyzed + && (node->global.inlined_to + || DECL_SAVED_TREE (node->decl))) + { + error_found = true; + dump_cgraph_node (stderr, node); + } + if (error_found) + internal_error ("Nodes with no released memory found."); + } #endif } diff --git a/gcc/combine.c b/gcc/combine.c index 77653744895..2abd3d86c5c 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -6661,17 +6661,15 @@ get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen) { /* Get the bit number of the first 1 bit from the right, -1 if none. */ int pos = exact_log2 (m & -m); - int len; - - if (pos < 0) - return -1; + int len = 0; - /* Now shift off the low-order zero bits and see if we have a power of - two minus 1. */ - len = exact_log2 ((m >> pos) + 1); + if (pos >= 0) + /* Now shift off the low-order zero bits and see if we have a + power of two minus 1. */ + len = exact_log2 ((m >> pos) + 1); if (len <= 0) - return -1; + pos = -1; *plen = len; return pos; diff --git a/gcc/common.opt b/gcc/common.opt index 92748d33062..5309365a0f5 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -310,6 +310,10 @@ fdiagnostics-show-location= Common Joined RejectNegative -fdiagnostics-show-location=[once|every-line] How often to emit source location at the beginning of line-wrapped diagnostics +fdump- +Common Joined RejectNegative +-fdump- Dump various compiler internals to a file + fdump-unnumbered Common Suppress output of instruction numbers and line number notes in debugging dumps @@ -466,6 +470,18 @@ fmove-all-movables Common Force all loop invariant computations out of loops +fmudflap +Common RejectNegative +Add mudflap bounds-checking instrumentation for single-threaded program. + +fmudflapth +Common RejectNegative +Add mudflap bounds-checking instrumentation for multi-threaded program. + +fmudflapir +Common RejectNegative +Ignore read operations when inserting mudflap instrumentation. + fnew-ra Common Use graph-coloring register allocation @@ -712,6 +728,61 @@ ftrapv Common Trap for signed overflow in addition, subtraction and multiplication +ftree-based-profiling +Common +Use tree-ssa based implementation of profiling + +ftree-ccp +Common +Enable SSA-CCP optimization on trees + +ftree-ch +Common +Enable loop header copying on trees + +ftree-combine-temps +Common +Coalesce memory temporaries in the SSA->normal pass + +ftree-copyrename +Common +Replace SSA temporaries with better names in copies. + +ftree-dce +Common +Enable SSA dead code elimination optimization on trees + +ftree-dominator-opts +Common +Enable dominator optimizations + +ftree-dse +Common +Enable dead store elimination + +ftree-loop-optimize +Common +Enable loop optimizations on trees + +ftree-points-to= +Common Joined RejectNegative + +ftree-pre +Common +Enable SSA-PRE optimization on trees + +ftree-sra +Common +Perform scalar replacement of aggregates + +ftree-ter +Common +Replace temporary expressions in the SSA->normal pass + +ftree-lrs +Common +Perform live range splitting during the SSA->normal pass. + funit-at-a-time Common Compile whole compilation unit at a time diff --git a/gcc/config.in b/gcc/config.in index 82b548f7ebd..6f0661fd6ee 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -568,6 +568,15 @@ /* Define to `int' if does not define. */ #undef ssize_t +/* Define if your linker supports -pie option. */ +#undef HAVE_LD_PIE + +/* Define if BANSHEE is available */ +#undef HAVE_BANSHEE + +/* Define to PREFIX/include if cpp should also search that directory. */ +#undef PREFIX_INCLUDE_DIR + /* Define to `int' if doesn't define. */ #undef uid_t diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index b1d1a54f20d..1f78205771c 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -801,9 +801,6 @@ input_operand (rtx op, enum machine_mode mode) case CONST_INT: return mode == QImode || mode == HImode || add_operand (op, mode); - case CONSTANT_P_RTX: - return 1; - default: break; } diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 371ffe8e1c0..ae9ff3a1b80 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -1116,7 +1116,7 @@ arm_compute_func_type (void) && TREE_THIS_VOLATILE (current_function_decl)) type |= ARM_FT_VOLATILE; - if (current_function_needs_context) + if (cfun->static_chain_decl != NULL) type |= ARM_FT_NESTED; attr = DECL_ATTRIBUTES (current_function_decl); @@ -10227,10 +10227,10 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) frame pointer and the arg pointer coincide. */ if (offsets->frame == offsets->saved_regs) return 0; - /* FIXME: Not sure about this. Maybe we should always return 0 ? */ - return (frame_pointer_needed - && current_function_needs_context - && ! cfun->machine->uses_anonymous_args) ? 4 : 0; + /* FIXME: Not sure about this. Maybe we should always return 0 ? */ + return (frame_pointer_needed + && cfun->static_chain_decl != NULL + && ! cfun->machine->uses_anonymous_args) ? 4 : 0; case STACK_POINTER_REGNUM: /* If nothing has been pushed on the stack at all diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 724a0d15646..518e387bba8 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -2046,7 +2046,6 @@ typedef struct #define THUMB_LEGITIMATE_CONSTANT_P(X) \ ( GET_CODE (X) == CONST_INT \ || GET_CODE (X) == CONST_DOUBLE \ - || GET_CODE (X) == CONSTANT_P_RTX \ || CONSTANT_ADDRESS_P (X) \ || flag_pic) diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index 79e3e585897..a78b42be449 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -765,9 +765,6 @@ extern int avr_case_values_threshold; #define FUNCTION_MODE HImode - /* 1 3 */ -#define INTEGRATE_THRESHOLD(DECL) (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2)) - #define DOLLARS_IN_IDENTIFIERS 0 #define NO_DOLLAR_IN_LABEL 1 diff --git a/gcc/config/c4x/c4x.c b/gcc/config/c4x/c4x.c index 0dad6a4c97c..850bcef44b9 100644 --- a/gcc/config/c4x/c4x.c +++ b/gcc/config/c4x/c4x.c @@ -2940,9 +2940,6 @@ const_operand (register rtx op, register enum machine_mode mode) case Pmode: #endif case QImode: - if (GET_CODE (op) == CONSTANT_P_RTX) - return 1; - if (GET_CODE (op) != CONST_INT || (GET_MODE (op) != VOIDmode && GET_MODE (op) != mode) || GET_MODE_CLASS (mode) != MODE_INT) diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c index a975f0b8509..9ca9d2d3551 100644 --- a/gcc/config/cris/cris.c +++ b/gcc/config/cris/cris.c @@ -2488,7 +2488,6 @@ cris_symbol (rtx x) case CONST_INT: case CONST_DOUBLE: - case CONSTANT_P_RTX: return 0; default: @@ -2550,7 +2549,6 @@ cris_gotless_symbol (rtx x) case CONST_INT: case CONST_DOUBLE: - case CONSTANT_P_RTX: return 0; default: @@ -2595,7 +2593,6 @@ cris_got_symbol (rtx x) case CONST_INT: case CONST_DOUBLE: - case CONSTANT_P_RTX: return 0; default: diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h index e6baec07973..9c62e36ed40 100644 --- a/gcc/config/frv/frv.h +++ b/gcc/config/frv/frv.h @@ -2639,8 +2639,7 @@ fixup_section (void) \ ( GET_CODE (X) == CONST_INT \ || GET_CODE (X) == CONST_DOUBLE \ || (GET_CODE (X) == HIGH && GET_CODE (XEXP (X, 0)) == CONST_INT) \ - || got12_operand (X, VOIDmode) \ - || GET_CODE (X) == CONSTANT_P_RTX) + || got12_operand (X, VOIDmode)) \ /* The Overall Framework of an Assembler File. */ diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index 789bb00c537..9efa140c23b 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -384,7 +384,7 @@ h8300_emit_stack_adjustment (int sign, unsigned int size) if (TARGET_H8300 && size > 4 && !h8300_current_function_interrupt_function_p () - && !(current_function_needs_context && sign < 0)) + && !(cfun->static_chain_decl != NULL && sign < 0)) { rtx r3 = gen_rtx_REG (Pmode, 3); emit_insn (gen_movhi (r3, GEN_INT (sign * size))); diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index e27ca031fb4..e15a8a7c8d5 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -715,7 +715,6 @@ int gr_reg_or_5bit_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 32) - || GET_CODE (op) == CONSTANT_P_RTX || gr_register_operand (op, mode)); } @@ -725,7 +724,6 @@ int gr_reg_or_6bit_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX || gr_register_operand (op, mode)); } @@ -735,7 +733,6 @@ int gr_reg_or_8bit_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX || gr_register_operand (op, mode)); } @@ -745,7 +742,6 @@ int grfr_reg_or_8bit_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX || grfr_register_operand (op, mode)); } @@ -756,7 +752,6 @@ int gr_reg_or_8bit_adjusted_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_L (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX || gr_register_operand (op, mode)); } @@ -770,7 +765,6 @@ gr_reg_or_8bit_and_adjusted_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op)) && CONST_OK_FOR_L (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX || gr_register_operand (op, mode)); } @@ -780,7 +774,6 @@ int gr_reg_or_14bit_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_I (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX || gr_register_operand (op, mode)); } @@ -790,7 +783,6 @@ int gr_reg_or_22bit_operand (rtx op, enum machine_mode mode) { return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_J (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX || gr_register_operand (op, mode)); } @@ -799,8 +791,7 @@ gr_reg_or_22bit_operand (rtx op, enum machine_mode mode) int shift_count_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { - return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op))) - || GET_CODE (op) == CONSTANT_P_RTX); + return (GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op))); } /* Return 1 if OP is a 5 bit immediate operand. */ @@ -808,9 +799,8 @@ shift_count_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) int shift_32bit_count_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { - return ((GET_CODE (op) == CONST_INT - && (INTVAL (op) >= 0 && INTVAL (op) < 32)) - || GET_CODE (op) == CONSTANT_P_RTX); + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) >= 0 && INTVAL (op) < 32)); } /* Return 1 if OP is a 2, 4, 8, or 16 immediate operand. */ diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index 29f78c43a0e..b0f4dc64bce 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -2178,7 +2178,7 @@ do { \ { "destination_operand", {SUBREG, REG, MEM}}, \ { "not_postinc_memory_operand", {MEM}}, \ { "move_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \ - CONSTANT_P_RTX, SYMBOL_REF, CONST, LABEL_REF}}, \ + SYMBOL_REF, CONST, LABEL_REF}}, \ { "gr_register_operand", {SUBREG, REG}}, \ { "fr_register_operand", {SUBREG, REG}}, \ { "grfr_register_operand", {SUBREG, REG}}, \ @@ -2186,19 +2186,16 @@ do { \ { "fr_nonimmediate_operand", {SUBREG, REG, MEM}}, \ { "grfr_nonimmediate_operand", {SUBREG, REG, MEM}}, \ { "gr_reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \ -{ "gr_reg_or_5bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{ "gr_reg_or_6bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{ "gr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{ "grfr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{ "gr_reg_or_8bit_adjusted_operand", {SUBREG, REG, CONST_INT, \ - CONSTANT_P_RTX}}, \ -{ "gr_reg_or_8bit_and_adjusted_operand", {SUBREG, REG, CONST_INT, \ - CONSTANT_P_RTX}}, \ -{ "gr_reg_or_14bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{ "gr_reg_or_22bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{ "shift_count_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \ -{ "shift_32bit_count_operand", {SUBREG, REG, CONST_INT, \ - CONSTANT_P_RTX}}, \ +{ "gr_reg_or_5bit_operand", {SUBREG, REG, CONST_INT}}, \ +{ "gr_reg_or_6bit_operand", {SUBREG, REG, CONST_INT}}, \ +{ "gr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT}}, \ +{ "grfr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT}}, \ +{ "gr_reg_or_8bit_adjusted_operand", {SUBREG, REG, CONST_INT}}, \ +{ "gr_reg_or_8bit_and_adjusted_operand", {SUBREG, REG, CONST_INT}}, \ +{ "gr_reg_or_14bit_operand", {SUBREG, REG, CONST_INT}}, \ +{ "gr_reg_or_22bit_operand", {SUBREG, REG, CONST_INT}}, \ +{ "shift_count_operand", {SUBREG, REG, CONST_INT}}, \ +{ "shift_32bit_count_operand", {SUBREG, REG, CONST_INT}}, \ { "shladd_operand", {CONST_INT}}, \ { "fetchadd_operand", {CONST_INT}}, \ { "fr_reg_or_fp01_operand", {SUBREG, REG, CONST_DOUBLE}}, \ diff --git a/gcc/config/ip2k/ip2k.h b/gcc/config/ip2k/ip2k.h index 4685d030c1c..a069bf21d18 100644 --- a/gcc/config/ip2k/ip2k.h +++ b/gcc/config/ip2k/ip2k.h @@ -767,9 +767,6 @@ do { \ #define FUNCTION_MODE HImode -#define INTEGRATE_THRESHOLD(DECL) \ - (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2)) - #define DOLLARS_IN_IDENTIFIERS 0 extern int ip2k_reorg_in_progress; diff --git a/gcc/config/m32r/m32r.c b/gcc/config/m32r/m32r.c index 734d75743c1..fa898bcd189 100644 --- a/gcc/config/m32r/m32r.c +++ b/gcc/config/m32r/m32r.c @@ -771,8 +771,6 @@ move_src_operand (rtx op, enum machine_mode mode) } else return 1; - case CONSTANT_P_RTX: - return 1; case CONST_DOUBLE : if (mode == SFmode) return 1; diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 2925ffd3d96..5bcdbd938bc 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -1277,9 +1277,6 @@ mips_const_insns (rtx x) switch (GET_CODE (x)) { - case CONSTANT_P_RTX: - return 1; - case HIGH: if (TARGET_MIPS16 || !mips_symbolic_constant_p (XEXP (x, 0), &symbol_type) diff --git a/gcc/config/mmix/mmix.c b/gcc/config/mmix/mmix.c index 8bf8e0eae5e..5c3014c4731 100644 --- a/gcc/config/mmix/mmix.c +++ b/gcc/config/mmix/mmix.c @@ -1008,7 +1008,6 @@ mmix_constant_address_p (rtx x) case SYMBOL_REF: return 1; - case CONSTANT_P_RTX: case HIGH: /* FIXME: Don't know how to dissect these. Avoid them for now, except we know they're constants. */ diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index d4a286d4d8f..0cc1ed7eb99 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -592,9 +592,6 @@ move_src_operand (rtx op, enum machine_mode mode) if (register_operand (op, mode)) return 1; - if (GET_CODE (op) == CONSTANT_P_RTX) - return 1; - if (GET_CODE (op) == CONST_INT) return cint_ok_for_move (INTVAL (op)); diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h index 200936e8e49..b08021dd472 100644 --- a/gcc/config/pa/pa.h +++ b/gcc/config/pa/pa.h @@ -1987,7 +1987,7 @@ do { \ #define PREDICATE_CODES \ {"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ {"call_operand_address", {LABEL_REF, SYMBOL_REF, CONST_INT, \ - CONST_DOUBLE, CONST, HIGH, CONSTANT_P_RTX}}, \ + CONST_DOUBLE, CONST, HIGH}}, \ {"indexed_memory_operand", {SUBREG, MEM}}, \ {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \ {"symbolic_memory_operand", {SUBREG, MEM}}, \ @@ -1995,7 +1995,7 @@ do { \ {"reg_or_0_or_nonsymb_mem_operand", {SUBREG, REG, MEM, CONST_INT, \ CONST_DOUBLE}}, \ {"move_dest_operand", {SUBREG, REG, MEM}}, \ - {"move_src_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, MEM}}, \ + {"move_src_operand", {SUBREG, REG, CONST_INT, MEM}}, \ {"reg_or_cint_move_operand", {SUBREG, REG, CONST_INT}}, \ {"pic_label_operand", {LABEL_REF, CONST}}, \ {"fp_reg_operand", {REG}}, \ diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h index c530f988e25..88752079772 100644 --- a/gcc/config/rs6000/aix.h +++ b/gcc/config/rs6000/aix.h @@ -51,12 +51,37 @@ #define REAL_NM_FILE_NAME "/usr/ucb/nm" #define USER_LABEL_PREFIX "" + /* Don't turn -B into -L if the argument specifies a relative file name. */ #define RELATIVE_PREFIX_NOT_LINKDIR /* Because of the above, we must have gcc search itself to find libgcc.a. */ #define LINK_LIBGCC_SPECIAL_1 +#define MFWRAP_SPEC " %{static: %{fmudflap|fmudflapth: \ + -brename:malloc,__wrap_malloc -brename:__real_malloc,malloc \ + -brename:free,__wrap_free -brename:__real_free,free \ + -brename:calloc,__wrap_calloc -brename:__real_calloc,calloc \ + -brename:realloc,__wrap_realloc -brename:__real_realloc,realloc \ + -brename:mmap,__wrap_mmap -brename:__real_mmap,mmap \ + -brename:munmap,__wrap_munmap -brename:__real_munmap,munmap \ + -brename:alloca,__wrap_alloca -brename:__real_alloca,alloca \ +} %{fmudflapth: \ + -brename:pthread_create,__wrap_pthread_create \ + -brename:__real_pthread_create,pthread_create \ + -brename:pthread_join,__wrap_pthread_join \ + -brename:__real_pthread_join,pthread_join \ + -brename:pthread_exit,__wrap_pthread_exit \ + -brename:__real_pthread_exit,pthread_exit \ +}} %{fmudflap|fmudflapth: \ + -brename:main,__wrap_main -brename:__real_main,main \ +}" + +#define MFLIB_SPEC " %{fmudflap: -lmudflap \ + %{static:%(link_gcc_c_sequence) -lmudflap}} \ + %{fmudflapth: -lmudflapth -lpthread \ + %{static:%(link_gcc_c_sequence) -lmudflapth}} " + /* Names to predefine in the preprocessor for this target machine. */ #define TARGET_OS_AIX_CPP_BUILTINS() \ do \ diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 235e704014a..9f6301b3910 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -2419,10 +2419,6 @@ input_operand (rtx op, enum machine_mode mode) if (memory_operand (op, mode)) return 1; - /* Only a tiny bit of handling for CONSTANT_P_RTX is necessary. */ - if (GET_CODE (op) == CONSTANT_P_RTX) - return 1; - /* For floating-point, easy constants are valid. */ if (GET_MODE_CLASS (mode) == MODE_FLOAT && CONSTANT_P (op) @@ -3753,10 +3749,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) || ! nonimmediate_operand (operands[0], mode))) goto emit_set; - /* Handle the case of CONSTANT_P_RTX. */ - if (GET_CODE (operands[1]) == CONSTANT_P_RTX) - goto emit_set; - /* 128-bit constant floating-point values on Darwin should really be loaded as two parts. */ if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN) @@ -13125,7 +13117,8 @@ rs6000_output_function_epilogue (FILE *file, Java is 13. Objective-C is 14. */ if (! strcmp (language_string, "GNU C")) i = 0; - else if (! strcmp (language_string, "GNU F77")) + else if (! strcmp (language_string, "GNU F77") + || ! strcmp (language_string, "GNU F95")) i = 1; else if (! strcmp (language_string, "GNU Pascal")) i = 2; @@ -14120,7 +14113,7 @@ output_function_profiler (FILE *file, int labelno) asm_fprintf (file, "\tmflr %s\n", reg_names[0]); asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]); - if (current_function_needs_context) + if (cfun->static_chain_decl != NULL) { asm_fprintf (file, "\tstd %s,24(%s)\n", reg_names[STATIC_CHAIN_REGNUM], reg_names[1]); diff --git a/gcc/config/rs6000/t-rs6000 b/gcc/config/rs6000/t-rs6000 index caa07153ad3..9546461e57d 100644 --- a/gcc/config/rs6000/t-rs6000 +++ b/gcc/config/rs6000/t-rs6000 @@ -18,3 +18,23 @@ rs6000-c.o: $(srcdir)/config/rs6000/rs6000-c.c \ # The rs6000 backend doesn't cause warnings in these files. insn-conditions.o-warn = +# The files below trigger warnings in tree-ssa because of the gimplifier +# emitting code that confuse the compiler into thinking that some variables +# are used uninitialized. +jump.o-warn = -Wno-error +regmove.o-warn = -Wno-error +c-typeck.o-warn = -Wno-error +cfgrtl.o-warn = -Wno-error +combine.o-warn = -Wno-error +fold-const.o-warn = -Wno-error +ifcvt.o-warn = -Wno-error +reload1.o-warn = -Wno-error +rtlanal.o-warn = -Wno-error +cp/decl2.o-warn = -Wno-error +cp/pt.o-warn = -Wno-error +f/where.o-warn = -Wno-error +java/expr.o-warn = -Wno-error +objc/objc-act.o-warn = -Wno-error +rs6000.o-warn = -Wno-error +insn-emit.o-warn = -Wno-error +simplify-rtx.o-warn = -Wno-error diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index e5850957bfe..9e786bfdf70 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -2956,18 +2956,14 @@ s390_expand_movstr (rtx dst, rtx src, rtx len) else { rtx dst_addr, src_addr, count, blocks, temp; + rtx loop_end_label = gen_label_rtx (); rtx end_label = gen_label_rtx (); enum machine_mode mode; - tree type; mode = GET_MODE (len); if (mode == VOIDmode) mode = Pmode; - type = lang_hooks.types.type_for_mode (mode, 1); - if (!type) - abort (); - dst_addr = gen_reg_rtx (Pmode); src_addr = gen_reg_rtx (Pmode); count = gen_reg_rtx (mode); @@ -2990,10 +2986,9 @@ s390_expand_movstr (rtx dst, rtx src, rtx len) if (temp != blocks) emit_move_insn (blocks, temp); + emit_cmp_and_jump_insns (blocks, const0_rtx, + EQ, NULL_RTX, mode, 1, loop_end_label); expand_start_loop (1); - expand_exit_loop_top_cond (0, build (NE_EXPR, type, - make_tree (type, blocks), - make_tree (type, const0_rtx))); emit_insn (gen_movstr_short (dst, src, GEN_INT (255))); s390_load_address (dst_addr, @@ -3005,7 +3000,10 @@ s390_expand_movstr (rtx dst, rtx src, rtx len) if (temp != blocks) emit_move_insn (blocks, temp); + emit_cmp_and_jump_insns (blocks, const0_rtx, + EQ, NULL_RTX, mode, 1, loop_end_label); expand_end_loop (); + emit_label (loop_end_label); emit_insn (gen_movstr_short (dst, src, convert_to_mode (Pmode, count, 1))); @@ -3032,18 +3030,14 @@ s390_expand_clrstr (rtx dst, rtx len) else { rtx dst_addr, src_addr, count, blocks, temp; + rtx loop_end_label = gen_label_rtx (); rtx end_label = gen_label_rtx (); enum machine_mode mode; - tree type; mode = GET_MODE (len); if (mode == VOIDmode) mode = Pmode; - type = lang_hooks.types.type_for_mode (mode, 1); - if (!type) - abort (); - dst_addr = gen_reg_rtx (Pmode); src_addr = gen_reg_rtx (Pmode); count = gen_reg_rtx (mode); @@ -3064,10 +3058,9 @@ s390_expand_clrstr (rtx dst, rtx len) if (temp != blocks) emit_move_insn (blocks, temp); + emit_cmp_and_jump_insns (blocks, const0_rtx, + EQ, NULL_RTX, mode, 1, loop_end_label); expand_start_loop (1); - expand_exit_loop_top_cond (0, build (NE_EXPR, type, - make_tree (type, blocks), - make_tree (type, const0_rtx))); emit_insn (gen_clrstr_short (dst, GEN_INT (255))); s390_load_address (dst_addr, @@ -3077,7 +3070,10 @@ s390_expand_clrstr (rtx dst, rtx len) if (temp != blocks) emit_move_insn (blocks, temp); + emit_cmp_and_jump_insns (blocks, const0_rtx, + EQ, NULL_RTX, mode, 1, loop_end_label); expand_end_loop (); + emit_label (loop_end_label); emit_insn (gen_clrstr_short (dst, convert_to_mode (Pmode, count, 1))); emit_label (end_label); @@ -3120,18 +3116,14 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len) else { rtx addr0, addr1, count, blocks, temp; + rtx loop_end_label = gen_label_rtx (); rtx end_label = gen_label_rtx (); enum machine_mode mode; - tree type; mode = GET_MODE (len); if (mode == VOIDmode) mode = Pmode; - type = lang_hooks.types.type_for_mode (mode, 1); - if (!type) - abort (); - addr0 = gen_reg_rtx (Pmode); addr1 = gen_reg_rtx (Pmode); count = gen_reg_rtx (mode); @@ -3154,10 +3146,9 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len) if (temp != blocks) emit_move_insn (blocks, temp); + emit_cmp_and_jump_insns (blocks, const0_rtx, + EQ, NULL_RTX, mode, 1, loop_end_label); expand_start_loop (1); - expand_exit_loop_top_cond (0, build (NE_EXPR, type, - make_tree (type, blocks), - make_tree (type, const0_rtx))); emit_insn (gen_cmpmem_short (op0, op1, GEN_INT (255))); temp = gen_rtx_NE (VOIDmode, gen_rtx_REG (CCSmode, 33), const0_rtx); @@ -3175,7 +3166,10 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len) if (temp != blocks) emit_move_insn (blocks, temp); + emit_cmp_and_jump_insns (blocks, const0_rtx, + EQ, NULL_RTX, mode, 1, loop_end_label); expand_end_loop (); + emit_label (loop_end_label); emit_insn (gen_cmpmem_short (op0, op1, convert_to_mode (Pmode, count, 1))); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 5b44f1be03c..30526c2e694 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -4704,7 +4704,7 @@ output_stack_adjust (int size, rtx reg, int epilogue_p, for (i = FIRST_PARM_REG; i < FIRST_PARM_REG + NPARM_REGS (SImode); i++) CLEAR_HARD_REG_BIT (temps, i); - if (current_function_needs_context) + if (cfun->static_chain_decl != NULL) CLEAR_HARD_REG_BIT (temps, STATIC_CHAIN_REGNUM); } temp = scavenge_reg (&temps); @@ -5161,7 +5161,7 @@ sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule, if (call_used_regs[i] && ! fixed_regs[i] && i != PR_MEDIA_REG && ! FUNCTION_ARG_REGNO_P (i) && i != FIRST_RET_REG - && ! (current_function_needs_context && i == STATIC_CHAIN_REGNUM) + && ! (cfun->static_chain_decl != NULL && i == STATIC_CHAIN_REGNUM) && ! (current_function_calls_eh_return && (i == EH_RETURN_STACKADJ_REGNO || ((unsigned) i <= EH_RETURN_DATA_REGNO (0) diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 2192d967224..278ca9a26b0 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -1280,10 +1280,6 @@ input_operand (rtx op, enum machine_mode mode) if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op)) return 0; - /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and result in 0/1. */ - if (GET_CODE (op) == CONSTANT_P_RTX) - return 1; - /* Allow any one instruction integer constant, and all CONST_INT variants when we are working in DImode and !arch64. */ if (GET_MODE_CLASS (mode) == MODE_INT diff --git a/gcc/config/v850/v850.c b/gcc/config/v850/v850.c index 83372624309..f9e54cc2df9 100644 --- a/gcc/config/v850/v850.c +++ b/gcc/config/v850/v850.c @@ -1136,7 +1136,6 @@ movsi_source_operand (rtx op, enum machine_mode mode) must be done with HIGH & LO_SUM patterns. */ if (CONSTANT_P (op) && GET_CODE (op) != HIGH - && GET_CODE (op) != CONSTANT_P_RTX && !(GET_CODE (op) == CONST_INT && (CONST_OK_FOR_J (INTVAL (op)) || CONST_OK_FOR_K (INTVAL (op)) diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c index d1103681345..89d8c9ddf3d 100644 --- a/gcc/config/xtensa/xtensa.c +++ b/gcc/config/xtensa/xtensa.c @@ -627,11 +627,6 @@ move_operand (rtx op, enum machine_mode mode) case HImode: case QImode: - /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and - result in 0/1. */ - if (GET_CODE (op) == CONSTANT_P_RTX) - return TRUE; - if (GET_CODE (op) == CONST_INT && xtensa_simm12b (INTVAL (op))) return TRUE; break; @@ -1252,7 +1247,6 @@ int xtensa_emit_move_sequence (rtx *operands, enum machine_mode mode) { if (CONSTANT_P (operands[1]) - && GET_CODE (operands[1]) != CONSTANT_P_RTX && (GET_CODE (operands[1]) != CONST_INT || !xtensa_simm12b (INTVAL (operands[1])))) { @@ -2229,7 +2223,7 @@ long compute_frame_size (int size) { /* Add space for the incoming static chain value. */ - if (current_function_needs_context) + if (cfun->static_chain_decl != NULL) size += (1 * UNITS_PER_WORD); xtensa_current_frame_size = diff --git a/gcc/configure b/gcc/configure index 38c2591d4db..92d222c4276 100755 --- a/gcc/configure +++ b/gcc/configure @@ -309,7 +309,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP strict1_warn warn_cflags WERROR nocommon_flag EGREP valgrind_path valgrind_path_defines valgrind_command coverage_flags enable_multilib enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep SET_MAKE AWK LN LN_S RANLIB ac_ct_RANLIB INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON stage1_cflags COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LIBICONV_DEP manext objext gthread_flags extra_modes_file FORBUILD PACKAGE VERSION USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS CROSS ALL SYSTEM_HEADER_DIR inhibit_libc BUILD_PREFIX BUILD_PREFIX_1 CC_FOR_BUILD BUILD_CFLAGS STMP_FIXINC STMP_FIXPROTO collect2 libgcc_visibility GGC zlibdir zlibinc MAINT gcc_tooldir dollar slibdir objdir subdirs srcdir all_boot_languages all_compilers all_gtfiles all_gtfiles_files_langs all_gtfiles_files_files all_lang_makefrags all_lang_makefiles all_languages all_stagestuff build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines check_languages cc_set_by_configure quoted_cc_set_by_configure cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir libstdcxx_incdir gcc_version gcc_version_full gcc_version_trigger host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file stage_prefix_set_by_configure quoted_stage_prefix_set_by_configure symbolic_link thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines target_noncanonical c_target_objs cxx_target_objs target_cpu_default LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os build_subdir host_subdir target_subdir GENINSRC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT NO_MINUS_C_MINUS_O OUTPUT_OPTION CPP strict1_warn warn_cflags WERROR nocommon_flag EGREP valgrind_path valgrind_path_defines valgrind_command coverage_flags TREEBROWSER enable_multilib enable_shared TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE CROSS_SYSTEM_HEADER_DIR onestep SET_MAKE AWK LN LN_S RANLIB ac_ct_RANLIB INSTALL INSTALL_PROGRAM INSTALL_DATA make_compare_target have_mktemp_command MAKEINFO BUILD_INFO GENERATED_MANPAGES FLEX BISON stage1_cflags COLLECT2_LIBS GNAT_LIBEXC LDEXP_LIB TARGET_GETGROUPS_T LIBICONV LIBICONV_DEP manext objext gthread_flags extra_modes_file FORBUILD PACKAGE VERSION USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS CROSS ALL SYSTEM_HEADER_DIR inhibit_libc BUILD_PREFIX BUILD_PREFIX_1 CC_FOR_BUILD BUILD_CFLAGS STMP_FIXINC STMP_FIXPROTO collect2 libgcc_visibility GGC zlibdir zlibinc MAINT ANDER BANSHEEINC BANSHEELIB gcc_tooldir dollar slibdir objdir subdirs srcdir all_boot_languages all_compilers all_gtfiles all_gtfiles_files_langs all_gtfiles_files_files all_lang_makefrags all_lang_makefiles all_languages all_stagestuff build_exeext build_install_headers_dir build_xm_file_list build_xm_include_list build_xm_defines check_languages cc_set_by_configure quoted_cc_set_by_configure cpp_install_dir xmake_file tmake_file extra_gcc_objs extra_headers_list extra_objs extra_parts extra_passes extra_programs float_h_file gcc_config_arguments gcc_gxx_include_dir libstdcxx_incdir gcc_version gcc_version_full gcc_version_trigger host_exeext host_xm_file_list host_xm_include_list host_xm_defines out_host_hook_obj install lang_opt_files lang_specs_files lang_tree_files local_prefix md_file objc_boehm_gc out_file out_object_file stage_prefix_set_by_configure quoted_stage_prefix_set_by_configure symbolic_link thread_file tm_file_list tm_include_list tm_defines tm_p_file_list tm_p_include_list xm_file_list xm_include_list xm_defines target_noncanonical c_target_objs cxx_target_objs target_cpu_default GMPLIBS GMPINC LIBOBJS LTLIBOBJS' ac_subst_files='language_hooks' # Initialize some variables set by options. @@ -770,6 +770,14 @@ ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP +ac_env_GMPLIBS_set=${GMPLIBS+set} +ac_env_GMPLIBS_value=$GMPLIBS +ac_cv_env_GMPLIBS_set=${GMPLIBS+set} +ac_cv_env_GMPLIBS_value=$GMPLIBS +ac_env_GMPINC_set=${GMPINC+set} +ac_env_GMPINC_value=$GMPINC +ac_cv_env_GMPINC_set=${GMPINC+set} +ac_cv_env_GMPINC_value=$GMPINC # # Report the --help message. @@ -868,6 +876,7 @@ Optional Features: optimization. Values are opt, noopt, default is noopt --enable-gather-detailed-mem-stats enable detailed memory allocation stats gathering + --enable-tree-browser enable the tree browsing routines for debugging --enable-multilib enable library support for multiple ABIs --enable-__cxa_atexit enable __cxa_atexit for C++ --enable-threads enable thread usage for target GCC @@ -915,6 +924,7 @@ Optional Packages: --with-gc={page,zone} choose the garbage collection mechanism to use with the compiler --with-system-zlib use installed libz + --with-libbanshee enable libbanshee --with-slibdir=DIR shared libraries in DIR LIBDIR Some influential environment variables: @@ -925,6 +935,8 @@ Some influential environment variables: CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor + GMPLIBS How to link GMP + GMPINC How to find GMP include files Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -4673,6 +4685,18 @@ _ACEOF fi +# Check whether --enable-tree-browser or --disable-tree-browser was given. +if test "${enable_tree_browser+set}" = set; then + enableval="$enable_tree_browser" + +else + enable_tree_browser=no +fi; +if test x$enable_tree_browser = xyes ; then + TREEBROWSER=tree-browser.o +fi + + # ------------------------------- # Miscenalleous configure options # ------------------------------- @@ -5283,7 +5307,7 @@ if test "${gcc_cv_prog_makeinfo_modern+set}" = set; then else ac_prog_version=`$MAKEINFO --version 2>&1 | sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'` - echo "configure:5286: version of makeinfo is $ac_prog_version" >&5 + echo "configure:5310: version of makeinfo is $ac_prog_version" >&5 case $ac_prog_version in '') gcc_cv_prog_makeinfo_modern=no;; 4.[2-9]*) @@ -12131,6 +12155,38 @@ else MAINT='#' fi +echo "$as_me:$LINENO: checking whether to use libbanshee for points-to alias analysis" >&5 +echo $ECHO_N "checking whether to use libbanshee for points-to alias analysis... $ECHO_C" >&6 + +# Check whether --with-libbanshee or --without-libbanshee was given. +if test "${with_libbanshee+set}" = set; then + withval="$with_libbanshee" + libbanshee="$with_libbanshee" +else + libbanshee=no +fi; + +if test x"$libbanshee" = xyes; then + BANSHEELIB="../libbanshee/points-to/libandersen.a ../libbanshee/engine/libbansheeengine.a ../libbanshee/libcompat/libbansheecompat.a " + BANSHEEINC="-I\$(srcdir)/../libbanshee/libcompat -I\$(srcdir)/../libbanshee -I\$(srcdir)/../libbanshee/points-to" + ANDER="tree-alias-ander.o" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_BANSHEE 1 +_ACEOF + +else + BANSHEELIB="" + BANSHEEINC="" + ANDER="" +fi +echo "$as_me:$LINENO: result: $with_libbanshee" >&5 +echo "${ECHO_T}$with_libbanshee" >&6 + + + + + # -------------- # Language hooks # -------------- @@ -12430,6 +12486,9 @@ else fi fi + + + # Configure the subdirectories # AC_CONFIG_SUBDIRS($subdirs) @@ -13099,6 +13158,7 @@ s,@valgrind_path@,$valgrind_path,;t t s,@valgrind_path_defines@,$valgrind_path_defines,;t t s,@valgrind_command@,$valgrind_command,;t t s,@coverage_flags@,$coverage_flags,;t t +s,@TREEBROWSER@,$TREEBROWSER,;t t s,@enable_multilib@,$enable_multilib,;t t s,@enable_shared@,$enable_shared,;t t s,@TARGET_SYSTEM_ROOT@,$TARGET_SYSTEM_ROOT,;t t @@ -13159,6 +13219,9 @@ s,@GGC@,$GGC,;t t s,@zlibdir@,$zlibdir,;t t s,@zlibinc@,$zlibinc,;t t s,@MAINT@,$MAINT,;t t +s,@ANDER@,$ANDER,;t t +s,@BANSHEEINC@,$BANSHEEINC,;t t +s,@BANSHEELIB@,$BANSHEELIB,;t t s,@gcc_tooldir@,$gcc_tooldir,;t t s,@dollar@,$dollar,;t t s,@slibdir@,$slibdir,;t t @@ -13228,6 +13291,8 @@ s,@target_noncanonical@,$target_noncanonical,;t t s,@c_target_objs@,$c_target_objs,;t t s,@cxx_target_objs@,$cxx_target_objs,;t t s,@target_cpu_default@,$target_cpu_default,;t t +s,@GMPLIBS@,$GMPLIBS,;t t +s,@GMPINC@,$GMPINC,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t /@language_hooks@/r $language_hooks diff --git a/gcc/configure.ac b/gcc/configure.ac index 799f3ef1400..33a9f0bc0a0 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -544,6 +544,14 @@ if test x$enable_gather_detailed_mem_stats = xyes ; then [Define to enable detailed memory allocation stats gathering.]) fi +AC_ARG_ENABLE(tree-browser, +[ --enable-tree-browser enable the tree browsing routines for debugging], [], +[enable_tree_browser=no]) +if test x$enable_tree_browser = xyes ; then + TREEBROWSER=tree-browser.o +fi +AC_SUBST(TREEBROWSER) + # ------------------------------- # Miscenalleous configure options # ------------------------------- @@ -2847,6 +2855,28 @@ else fi AC_SUBST(MAINT)dnl +AC_MSG_CHECKING([whether to use libbanshee for points-to alias analysis]) +AC_ARG_WITH(libbanshee, +[ --with-libbanshee enable libbanshee], +libbanshee="$with_libbanshee", +libbanshee=no) + +if test x"$libbanshee" = xyes; then + BANSHEELIB="../libbanshee/points-to/libandersen.a ../libbanshee/engine/libbansheeengine.a ../libbanshee/libcompat/libbansheecompat.a " + BANSHEEINC="-I\$(srcdir)/../libbanshee/libcompat -I\$(srcdir)/../libbanshee -I\$(srcdir)/../libbanshee/points-to" + ANDER="tree-alias-ander.o" + AC_DEFINE(HAVE_BANSHEE, 1, [Define if BANSHEE is available]) +else + BANSHEELIB="" + BANSHEEINC="" + ANDER="" +fi +AC_MSG_RESULT($with_libbanshee) + +AC_SUBST(ANDER) +AC_SUBST(BANSHEEINC) +AC_SUBST(BANSHEELIB) + # -------------- # Language hooks # -------------- @@ -3143,6 +3173,9 @@ else fi fi +AC_ARG_VAR(GMPLIBS,[How to link GMP]) +AC_ARG_VAR(GMPINC,[How to find GMP include files]) + # Configure the subdirectories # AC_CONFIG_SUBDIRS($subdirs) diff --git a/gcc/coverage.c b/gcc/coverage.c index 1912c347809..8e952831acb 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -96,7 +96,11 @@ static char *da_file_name; /* Hash table of count data. */ static htab_t counts_hash = NULL; -/* The names of the counter tables. */ +/* Trees representing the counter table arrays. */ +static GTY(()) tree tree_ctr_tables[GCOV_COUNTERS]; + +/* The names of the counter tables. Not used if we're + generating counters at tree level. */ static GTY(()) rtx ctr_labels[GCOV_COUNTERS]; /* The names of merge functions for counters. */ @@ -369,14 +373,22 @@ coverage_counter_alloc (unsigned counter, unsigned num) if (!num) return 1; - if (!ctr_labels[counter]) + if (!tree_ctr_tables[counter]) { /* Generate and save a copy of this so it can be shared. */ + /* We don't know the size yet; make it big enough that nobody + will make any clever transformation on it. */ char buf[20]; - + tree domain_tree + = build_index_type (build_int_2 (1000, 0)); /* replaced later */ + tree gcov_type_array_type + = build_array_type (GCOV_TYPE_NODE, domain_tree); + tree_ctr_tables[counter] + = build_decl (VAR_DECL, NULL_TREE, gcov_type_array_type); + TREE_STATIC (tree_ctr_tables[counter]) = 1; ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", counter + 1); - ctr_labels[counter] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); - SYMBOL_REF_FLAGS (ctr_labels[counter]) = SYMBOL_FLAG_LOCAL; + DECL_NAME (tree_ctr_tables[counter]) = get_identifier (buf); + DECL_ALIGN (tree_ctr_tables[counter]) = TYPE_ALIGN (GCOV_TYPE_NODE); } fn_b_ctrs[counter] = fn_n_ctrs[counter]; fn_n_ctrs[counter] += num; @@ -387,7 +399,7 @@ coverage_counter_alloc (unsigned counter, unsigned num) /* Generate a MEM rtl to access COUNTER NO. */ rtx -coverage_counter_ref (unsigned counter, unsigned no) +rtl_coverage_counter_ref (unsigned counter, unsigned no) { unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); @@ -396,6 +408,13 @@ coverage_counter_ref (unsigned counter, unsigned no) if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter]) abort (); no += prg_n_ctrs[counter] + fn_b_ctrs[counter]; + if (!ctr_labels[counter]) + { + ctr_labels[counter] = gen_rtx_SYMBOL_REF (Pmode, + ggc_strdup (IDENTIFIER_POINTER (DECL_NAME + (tree_ctr_tables[counter])))); + SYMBOL_REF_FLAGS (ctr_labels[counter]) = SYMBOL_FLAG_LOCAL; + } ref = plus_constant (ctr_labels[counter], gcov_size / BITS_PER_UNIT * no); ref = gen_rtx_MEM (mode, ref); set_mem_alias_set (ref, new_alias_set ()); @@ -403,6 +422,23 @@ coverage_counter_ref (unsigned counter, unsigned no) return ref; } + +/* Generate a tree to access COUNTER NO. */ + +tree +tree_coverage_counter_ref (unsigned counter, unsigned no) +{ + tree t; + + if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter]) + abort (); + no += prg_n_ctrs[counter] + fn_b_ctrs[counter]; + + /* "no" here is an array index, scaled to bytes later. */ + t = build (ARRAY_REF, GCOV_TYPE_NODE, tree_ctr_tables[counter], + build_int_2 (no, 0)); + return t; +} /* Generate a checksum for a string. CHKSUM is the current checksum. */ @@ -684,19 +720,20 @@ build_ctr_info_value (unsigned int counter, tree type) if (prg_n_ctrs[counter]) { - tree array_type, array; + tree array_type; array_type = build_index_type (build_int_2 (prg_n_ctrs[counter] - 1, 0)); array_type = build_array_type (TREE_TYPE (TREE_TYPE (fields)), array_type); - array = build_decl (VAR_DECL, NULL_TREE, array_type); - TREE_STATIC (array) = 1; - DECL_NAME (array) = get_identifier (XSTR (ctr_labels[counter], 0)); - assemble_variable (array, 0, 0, 0); + TREE_TYPE (tree_ctr_tables[counter]) = array_type; + DECL_SIZE (tree_ctr_tables[counter]) = TYPE_SIZE (array_type); + DECL_SIZE_UNIT (tree_ctr_tables[counter]) = TYPE_SIZE_UNIT (array_type); + assemble_variable (tree_ctr_tables[counter], 0, 0, 0); value = tree_cons (fields, - build1 (ADDR_EXPR, TREE_TYPE (fields), array), + build1 (ADDR_EXPR, TREE_TYPE (fields), + tree_ctr_tables[counter]), value); } else diff --git a/gcc/coverage.h b/gcc/coverage.h index 9756bbaafa8..ec8134f1fe6 100644 --- a/gcc/coverage.h +++ b/gcc/coverage.h @@ -38,7 +38,9 @@ extern int coverage_begin_output (void); /* Allocate some counters. Repeatable per function. */ extern int coverage_counter_alloc (unsigned /*counter*/, unsigned/*num*/); /* Use a counter from the most recent allocation. */ -extern rtx coverage_counter_ref (unsigned /*counter*/, unsigned/*num*/); +extern rtx rtl_coverage_counter_ref (unsigned /*counter*/, unsigned/*num*/); +/* Use a counter from the most recent allocation. */ +extern tree tree_coverage_counter_ref (unsigned /*counter*/, unsigned/*num*/); /* Get all the counters for the current function. */ extern gcov_type *get_coverage_counts (unsigned /*counter*/, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 27fc85f79ec..9d990ee3642 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. See + ChangeLog.tree-ssa for details. + + * Make-lang.in, call.c, class.c, cp-lang.c, cp-tree.def, + cp-tree.h, cvt.c, decl.c, decl2.c, error.c, except.c, + expr.c, init.c, name-lookup.h, optimize.c, parser.c, + pt.c, rtti.c, semantics.c, tree.c, typeck.c, typeck2.c: + Merged. + * cp-mudflap.c: New file. + * cp-simplify.c:: New file. + 2004-05-03 Giovanni Bajo PR c++/14389 diff --git a/gcc/cp/ChangeLog.tree-ssa b/gcc/cp/ChangeLog.tree-ssa new file mode 100644 index 00000000000..a52dea67450 --- /dev/null +++ b/gcc/cp/ChangeLog.tree-ssa @@ -0,0 +1,566 @@ +2004-04-19 Richard Henderson + + * except.c (check_handlers_1): Use locus stored in master for warning. + * tree.c (cp_walk_subtrees): Save and restore input_location. + +2004-04-12 Diego Novillo + + * cp-lang.c (LANG_HOOKS_RTL_EXPAND_START): Remove. + (LANG_HOOKS_RTL_EXPAND_STMT): Remove. + * semantics.c (cxx_expand_function_start): Remove. + +2004-04-12 Richard Henderson + + * except.c (check_handlers_1): Use EXPR_LOCUS instead of STMT_LINENO. + * semantics.c (finalize_nrv_r): Likewise. + * tree.c (cp_walk_subtrees): Likewise. + * parser.c (cp_parser_statement): Save and restore entire locus; + set EXPR_LOCUS. + * pt.c (tsubst_expr): Don't special-case LABEL_STMT. + +2004-04-01 Diego Novillo + + * name-lookup.c (innermost_nonclass_level): Check for + error_mark_node. + +2004-03-25 Diego Novillo + + * parser.c (cp_parser_class_specifier): Initialize + variable 'attributes'. + +2004-03-17 Richard Henderson + + * cp-lang.c (cxx_types_compatible_p): Use + same_type_ignoring_top_level_qualifiers_p. + +2004-03-16 Dale Johannesen + + * cp-lang.c (cxx_types_compatible_p): New. + LANG_HOOKS_TYPES_COMPATIBLE_P: New. + +2004-03-10 Jason Merrill + + PR c++/14452 + * tree.c (stabilize_init): Return whether or not it worked. + * init.c (build_new_1): If not, use a sentry. + * cp-tree.h: Adjust prototype. + +2004-03-01 Jeff Law + + * init.c (build_vec_delete_1): Convert 2nd argument to NE_EXPR to + the proper type. + +2004-02-24 Jason Merrill + + PR c++/13944 + * except.c (do_free_exception): Remove #if 0 wrapper. + (build_throw): Use it if we elide a copy into the exception object. + + * tree.c (stabilize_call): Fix thinko. + +2004-02-19 Steven Bosscher + + * decl.c (poplevel): Don't output nested inline functions. + +2004-02-16 Richard Henderson + + * call.c (build_call, build_over_call, build_new_method_call): Add + static chain operand to call_expr. + * decl.c (build_offset_ref_call_from_tree): Likewise. + * parser.c (cp_parser_postfix_expression): Likewise. + * semantics.c (finish_call_expr): Likewise. + * cp-lang.c (cp_expand_decl): Don't declare_nonlocal_label. + +2004-02-09 Richard Henderson + + * cp-lang.c (LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P): New. + * cp-tree.h (cp_missing_noreturn_ok_p): Declare. + * decl.c (cp_missing_noreturn_ok_p): Export. + (cxx_init_decl_processing): Don't set lang_missing_noreturn_ok_p. + +2004-02-06 Andrew Pinski + + PR c/13863 + * cp-lang.c (LANG_HOOKS_DECL_UNINIT): Remove. + +2004-02-03 Richard Henderson + + PR middle-end/13325 + * call.c, cvt.c, init.c, typeck.c: Use TREE_NO_WARNING instead + of TREE_NO_UNUSED_WARNING. + * cvt.c (convert_to_void): Also use it for "has no effect" warning. + +2004-01-30 Frank Ch. Eigler + + * cp-mudflap.c (mflang_flush_calls): Mark static ctor as TREE_USED. + +2004-01-12 Jason Merrill + + * cp-lang.c (ok_to_generate_alias_set_for_type): Remove. + (cxx_get_alias_set): Allow all types. + +2004-01-08 Frank Ch. Eigler + + * cp-mudflap.c (mflang_flush_calls): mf_mark synthetic function. + +2004-01-04 Richard Henderson + + * call.c (build_over_call): Don't create a save_expr of an + aggregate, but rather its address. + +2004-01-01 Richard Henderson + + * expr.c (cxx_expand_expr): Don't handle THROW_EXPR, or + MUST_NOT_THROW_EXPR. + * semantics.c (genrtl_try_block, genrtl_eh_spec_block, + genrtl_handler, cp_expand_stmt): Remove. + (init_cp_semantics): Don't set lang_expand_stmt. + +2003-12-31 Richard Henderson + + * cp-mudflap.c (mflang_register_call): Remove. + +2003-12-18 Jason Merrill + + PR c++/12453 + * cp-simplify.c (cp_gimplify_init_expr): Look inside STMT_EXPRs + and COMPOUND_EXPRs to find an AGGR_INIT_EXPR. + +2003-12-16 Jason Merrill + + PR middle-end/12920 + * decl.c (grokdeclarator): Immediately layout an + ARRAY_TYPE used in a pointer-to-array declarator. + +2003-12-16 Jan Hubicka + + Revert until initializers are made language independent: + * cp-lang.c (LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR): Kill. + * cp-tree.h (cxx_callgraph_analyze_expr): Kill. + * decl2.c (cxx_callgraph_analyze_expr): Kill. + +2003-12-14 Jan Hubicka + + * cp-lang.c (LANG_HOOKS_CALLGRAPH_ANALYZE_EXPR): Kill. + * cp-tree.h (cxx_callgraph_analyze_expr): Kill. + * decl2.c (cxx_callgraph_analyze_expr): Kill. + +2003-11-24 Richard Henderson + + * Make-lang.in (tree.o, typeck.o): Remove -Wno-error. + +2003-11-20 Richard Henderson + + * call.c (build_java_interface_fn_ref): Use build_address+convert. + * except.c (build_eh_type_type): Likewise. + * class.c (build_base_path): Use convert+build_indirect_ref. + * init.c (expand_virtual_init): Likewise. + * rtti.c (get_tinfo_decl_dynamic): Use convert. + +2003-11-20 Frank Ch. Eigler + + * cp-mudflap.c (mflang_flush_calls): Adapt to direct expansion of + synthetic function, bypassing callgraph code. + * cp-decl2.c (finish_file): Call mudflap after callgraph-based + expansion. + +2003-11-17 Jason Merrill + + * init.c (build_new_1): Preevaluate initializer. Simplify EH code. + (build_init): Call a constructor rather than call build_aggr_init + for classes. + * except.c (stabilize_throw_expr): Remove. + (build_throw): Use stabilize_init instead of stabilize_throw_expr. + * tree.c (stabilize_call, stabilize_init): New fns. + * call.c (build_over_call): A constructor no longer returns the + address of the object. + +2003-11-16 Richard Henderson + + * typeck.c (pointer_diff): Remove unused variable. + +2003-11-16 Jason Merrill + + PR optimization/11269 + * semantics.c (finalize_nrv_r): Rename from nullify_returns_r. + Also replace uses of the nrv with our RESULT_DECL. + (cxx_expand_function_start): Don't mess with the nrv. + (finalize_nrv): New fn. + * cp-tree.h: Declare it. + * decl.c (finish_function): Call it. + * tree.c (cp_copy_res_decl_for_inlining): Don't mess with the nrv. + +2003-11-10 Richard Henderson + + * cp-simplify.c (gimplify_must_not_throw_expr): Replace add_tree + with append_to_statement_list. + +2003-10-30 Richard Henderson + + * decl.c (pop_switch): Call c_do_switch_warnings. + +2003-10-23 Richard Henderson + + * cp-simplify.c (cp_gimplify_expr): Return gimplify_status. + +2003-10-16 Richard Henderson + + * decl.c (finish_function): Don't check flag_disable_gimple. + +2003-10-14 Richard Henderson + + * decl.c (finish_function): Always gimplify; call c_warn_unused_result. + +2003-10-13 Richard Henderson + + * pt.c (push_tinst_level): Use annotate_with_locus. + +2003-10-12 Richard Henderson + + * call.c (call_builtin_trap): Use implicit_built_in_decls. + * class.c (build_base_path): Set TREE_INVARIANT. + (build_vtbl_ref_1, build_vtbl_initializer): Likewise. + * decl.c (build_enumerator): Likewise. + * init.c (build_zero_init): Likewise. + * pt.c (push_inline_template_parms_recursive): Likewise. + (build_template_parm_index, reduce_template_parm_level): Likewise. + (process_template_parm): Likewise. + * rtti.c (tinfo_base_init, generic_initializer): Likewise. + (ptr_initializer, ptm_initializer, class_initializer): Likewise. + * typeck.c (build_ptrmemfunc1): Likewise. + * typeck2.c (process_init_constructor): Likewise. + + * calls.c (dfs_accumulate_vtbl_inits): Rely on build to set + TREE_CONSTANT. + (build_vtbl_initializer): Likewise. + * init.c (build_vtbl_address): Likewise. + * rtti.c (tinfo_base_init): Likewise. + * tree.c (make_ptrmem_cst): Likewise. + * typeck.c (decay_conversion): Likewise. + (get_member_function_from_ptrfunc, build_binary_op): Likewise. + (pointer_diff, build_address, build_nop, build_unary_op): Likewise. + +2003-09-30 Richard Henderson + + * decl.c (finish_function): Set cfun->function_end_locus. + +2003-09-24 Jason Merrill + + * class.c, decl.c, decl2.c, error.c, init.c, lex.c, method.c, + pt.c, semantics.c, tree.c: Revert from TREE_LOCUS to + DECL_SOURCE_LOCATION. + +2003-09-17 Richard Henderson + + * decl.c (cxx_init_decl_processing): Don't using_eh_for_cleanups + if exceptions are disabled. + +2003-09-03 Richard Henderson + + * cp-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): Use expand_stmt_toplev. + +2003-09-03 Richard Henderson + + * decl.c (finish_function): Fix misapplied patch. Don't + free_after_parsing or free_after_compilation. For real this time. + +2003-08-22 Jason Merrill + + * cp-simplify.c (cp_gimplify_init_expr): Update use of predicates. + +2003-08-21 Jason Merrill + + * cp-simplify.c (cp_gimplify_expr): Use simplify_aggr_init_expr. + (cp_gimplify_init_expr): Don't call it here. + (gimplify_aggr_init_expr): Remove. + +2003-08-19 Jason Merrill + + * typeck.c (build_array_ref): Also build ARRAY_REFs from + INDIRECT_REFs of ARRAY_TYPE. + + * semantics.c (finish_id_expression): Unshare aliases. + +2003-08-12 Diego Novillo + + * optimize.c (optimize_function): Do not call dump_function. + +2003-08-08 Jason Merrill + + * optimize.c (optimize_function): Restore support for + !keep_function_tree_in_gimple_form. + +2003-07-27 Andreas Jaeger + + * cp-lang.c: Convert K&R prototypes to ISO C90. + * cp-simplify.c: Likewise. + * cp-mudflap.c: Likewise. + +2003-06-13 Frank Ch. Eigler + + * semantics.c (expand_body): Call mudflap_c_function just before + rtl expansion of function body; don't interfere with inlining. + * optimize.c (optimize_function): Remove mudflap call. + +2003-06-13 Diego Novillo + + * cp-lang.c, cp-simplify.c, cp-tree.h, decl.c, optimize.c, + semantics.c, tree.c: Rename SIMPLE to GIMPLE everywhere. + +2003-06-05 Frank Ch. Eigler + + * cp-mudflap.c (mflang_register_call): Give the synthetic decl + undefined (not zero) size. + +2003-06-05 Frank Ch. Eigler + + * cp-mudflap.c (mx_flag): Remove. Update callers to use mf_mark. + +2003-05-24 Diego Novillo + + * Make-lang.in (optimize.o): Add dependency on tree-simple.h + * decl.c (grokdeclarator): Don't abort when the declarator is + ERROR_MARK_NODE. + * optimize.c (optimize_function): Unshare all trees after + optimizing inline calls. + +2003-05-12 Diego Novillo + + * class.c (dump_array): Call CONSTRUCTOR_ELTS to access + the operand of a CONSTRUCTOR node. + +2003-05-07 Diego Novillo + + * decl.c (grokdeclarator): Fix thinko in handling + ERROR_MARK declarators. + +2003-05-07 Diego Novillo + + * decl.c (grokdeclarator): Handle ERROR_MARK declarators. + +2003-05-07 Jason Merrill + + * semantics.c (expand_body): Call expand_stmt when + -fdisable-simple is given. + +2003-04-21 Jeff Law + + * optimize.c (optimize_function_tree): Do run the tree-ssa + optimizers. + +2003-04-16 Jeff Law + + * optimize.c (optimize_function): No longer check + flag_disable_simple. + +2003-04-15 Jeff Law + + * pt.c (instantiate_decl): If CFUN is null, then we will + need to push to the toplevel. + + * Makefile.in (decl.o): Depends on tree-flow.h. + * decl.c (finish_function): Call set_has_hidden_use when + nullifying returns for named value return optimization. + +2003-04-02 Jason Merrill + + * cp-simplify.c (cp_simplify_expr) : + Change type of constant to RECORD_TYPE. + +2003-03-10 Jeff Law + + * optimize.c (optimize_function): Avoid unnecessary + simplification of the function tree. + +2003-03-02 Diego Novillo + + * decl.c: Replace DECL_SOURCE_LOCATION with TREE_LOCUS + everywhere. + +2003-02-28 Frank Ch. Eigler + + * decl2.c (finish_file): Adjust timing of mudflap_finish_file call + to account for unit-at-a-time compilation. + +2003-02-07 Jason Merrill + + * cp-simplify.c (cp_simplify_expr): Handle BASELINK. + + * parser.c (cp_parser_primary_expression): Unshare a COMPONENT_REF + from an ALIAS_DECL. + +2003-02-05 Jason Merrill + + * cp-simplify.c (genericize_try_block): Do genericize catch blocks. + +2003-02-03 Diego Novillo + + * parser.c (cp_parser_asm_definition): Call finish_asm_stmt with + 'volatile_p' directly. + * typeck.c (build_binary_op): Initialize variable 'type'. + * Make-lang.in (cp/tree.o-warn): Add -Wno-error. + +2003-01-29 Frank Ch. Eigler + + * cp-mudflap.c (mflang_register_call): Adapt to mf-runtime.h API + change. + +2003-01-15 Jeff Law + + * class.c: Use TREE_FILENAME and TREE_LINENO to extract + file/line information from tree nodes. Remove EXPR_WITH_FILE_LOCATION + nodes. Use annotate_with_file_line to attach file/line information + to tree nodes. Use TREE_LOCUS to copy file/line information + from one node to another. + * decl2.c, error.c, init.c, lex.c, method.c: Likewise. + * optimize.c: Likewise. + * cp-tree.def (TINST_LEVEL): New tree node. + * cp-tree.h (TINST_DECL): Update now that we no longer use + EXPR_WITH_FILE_LOCATION to represent the TINST_DECL information. + (TINST_FILE, TINST_LINE): Kill. + * decl.c: Use TREE_FILENAME and TREE_LINENO to extract + file/line information from tree nodes. Use annotate_witH_file_line + to add file/line information to tree nodes. Use TREE_LOCUS + to copy file/line information from one node to another. + (duplicate_decls): Make sure to copy TREE_LOCUS information + from the old decl to the new decl. + (finish_function): Save and restore file/line information + around genericizing the function tree. + * pt.c (lookup_template_class): Use TREE_LOCUS to copy file/line + information from one node to another. + (push_tinst_level): Generate a TINST_LEVEL node rather than + using EXPR_WITH_FILE_LOCATION nodes. Use annotate_with_file_line + to annotate the new node with file/line information. + (pop_tinst_level): Use TREE_LINENO and TREE_FILENAME to extract + file/line information from nodes. + (tsubst_friend_function, instantiate_class_template): Likewise. + (tsubst_decl, instantiate_decl, tsubst_enum): Likewise. + * semantics.c: Use annotate_with_file_line to annotate tree + nodes with file/line information. Use TREE_FILENAME and TREE_LINENO + to extract file/line information from tree nodes. + (expand_body): Restore file/line information slightly earlier. + tree.c (cp_walk_subtrees): Set lineno appropriately. + (cp_copy_res_decl_for_inlining): Use TREE_LOCUS to copy file/line + information from one node to another. + +2003-01-13 Frank Ch. Eigler + + Prototype C++ mudflap support. + * Make-lang.in (CXX_OBJS): Add cp/cp-mudflap.o and dependencies. + * cp-mudflap.c: New file with C++ front-end mflang_* routines. + * decl2.c (finish_file): Divert to mudflap if appropriate. + * optimize.c (optimize_function): Ditto. + +2003-01-02 Jason Merrill + + * Make-lang.in (CXX_C_OBJS): Replace old-tree-inline.o with + tree-inline.o. + + * optimize.c (dump_function): Move to ../tree-dump.c. + + * cp-simplify.c (cp_simplify_expr): Handle PTRMEM_CST, INIT_EXPR, + MODIFY_EXPR and EMPTY_CLASS_EXPR. + (cp_simplify_stmt): Handle USING_STMT. + (cp_simplify_init_expr): New fn. + * cvt.c (build_up_reference): Don't push the decl. + * class.c (build_vtable_entry_ref, build_vtbl_ref_1): Unshare the + vtable address. + * init.c (build_vtbl_address): Likewise. + * cp-lang.c (LANG_HOOKS_UNSAVE_EXPR_NOW): Remove. + * decl.c (lookup_name_real): Unshare the expansion of an ALIAS_DECL. + (finish_function): Don't genericize templates. + * parse.y (parse_asm_stmt): Fix prototype. + * semantics.c (expand_body): Don't expand if we saw errors. + Drop support for expanding non-GENERIC code. + + * cp-simplify.c (cp_simplify_stmt): Handle HANDLER and EH_SPEC_BLOCK. + (genericize_try_block): Always build a TRY_CATCH_EXPR. + (genericize_catch_block): New fn. + (genericize_eh_spec_block): New fn. + (cp_simplify_expr): Handle THROW_EXPR and MUST_NOT_THROW_EXPR. + (simplify_must_not_throw_expr): New fn. + * except.c (wrap_cleanups_r): Make the MUST_NOT_THROW_EXPR void. + (build_throw): Likewise. + +2002-12-14 Jason Merrill + + * optimize.c (dump_function): Use pretty dumpers. + (optimize_function): Don't do .original dump here. + +2002-12-03 Diego Novillo + + * cp-simplify.c: Include coretypes.h and tm.h. + +2002-11-24 Jason Merrill + + Gimplify C++ cleanups. + * decl.c (finish_function): Call c_genericize. + * cp-simplify.c (cp_simplify_stmt): New fn. + (genericize_try_block): New fn. + (cp_simplify_expr): Move INIT_EXPR/TARGET_EXPR code + to ../gimplify.c. Handle AGGR_INIT_EXPR. + (simplify_target_expr): Move to ../gimplify.c. + (maybe_fixup_loop_cond): Remove. + (simplify_aggr_init_expr): Split out from... + * semantics.c (simplify_aggr_init_exprs_r): ...here. + (expand_body): Don't simplify AGGR_INIT_EXPRs here + if we're gimplifying. Handle expanding generic trees. + * tree.c (init_tree): Set lang_simplify_stmt. + * cp-tree.h: Declare the new fns. + + * optimize.c (optimize_function): Do pretty dumps. + +2002-10-04 Jason Merrill + + * Make-lang.in (CXX_C_OBJS): Add gimplify.o. + +2002-09-24 Jason Merrill + + * parse.y (parse_asm_stmt): New fn. + (simple_stmt): Use it. + * semantics.c (finish_asm_stmt): Change cv_qualifier parm to + volatile_p. + * cp-tree.h: Adjust prototype. + * pt.c (tsubst_expr): Adjust call. + +2002-08-23 Diego Novillo + + * Make-lang.in (CXX_C_OBJS): Add tree-dchain.o + +2002-08-11 Jason Merrill + + * cp-simplify.c (maybe_fixup_loop_cond): Move here. + (cp_simplify_expr): Call it. + (simplify_target_expr): Remove pre_p parm. + +2002-08-09 Jason Merrill + + * cp-simplify.c (cp_simplify_expr): New fn. + (simplify_target_expr): New fn. + (cp_simplify_function_tree): Remove. + * cp-lang.c (LANG_HOOKS_SIMPLIFY_FUNCTION_TREE): Don't define. + (LANG_HOOKS_SIMPLIFY_EXPR): Define. + * optimize.c (optimize_function): De-hook simplify_function_tree. + * cp-tree.h: Declare cp_simplify_expr. + +2002-07-17 Daniel Berlin + + * Make-lang.in (CXX_C_OBJS): Add tree-alias-ecr.c, + tree-alias-type.o, tree-alias-steen.o, disjoint-set.o. + +2002-06-21 Andreas Jaeger + + * Make-lang.in (cp-simplify.o): New. + +2002-06-18 Jason Merrill + + * cp-simplify.c: New file. + * Make-lang.in: Add it. + * cp-tree.h: Declare cp_simplify_function_tree. + * cp-lang.c (LANG_HOOKS_SIMPLIFY_FUNCTION_TREE): Define. + * optimize.c (optimize_function): Call tree optimizers (but not yet). + +Local Variables: +mode: change-log +change-log-default-name: "ChangeLog.tree-ssa" +End: diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 0f934f225a3..bf4b0fe850f 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -73,14 +73,16 @@ g++-cross$(exeext): g++$(exeext) # Shared with C front end: CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \ c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o c-pch.o \ - c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o + c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \ + c-simplify.o tree-inline.o # Language-specific object files. CXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ cp/class.o cp/decl2.o cp/error.o cp/lex.o cp/parser.o cp/ptree.o cp/rtti.o \ cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \ cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \ - cp/mangle.o cp/cp-lang.o cp/name-lookup.o cp/cxx-pretty-print.o + cp/mangle.o cp/cp-lang.o cp/name-lookup.o cp/cxx-pretty-print.o \ + cp/cp-simplify.o tree-mudflap.o cp/cp-mudflap.o # Use strict warnings for this front end. cp-warn = $(STRICT_WARN) $(WERROR) @@ -221,7 +223,7 @@ cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) $(TM_H) toplev.h langhooks.h \ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h stack.h \ output.h $(EXPR_H) except.h toplev.h $(HASHTAB_H) $(RTL_H) \ cp/operators.def $(TM_P_H) tree-inline.h diagnostic.h c-pragma.h \ - debug.h gt-cp-decl.h gtype-cp.h timevar.h + debug.h gt-cp-decl.h gtype-cp.h timevar.h $(TREE_FLOW_H) cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \ output.h except.h toplev.h $(RTL_H) c-common.h gt-cp-decl2.h cgraph.h cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h output.h $(TM_P_H) \ @@ -257,12 +259,16 @@ cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) cp/lex.h except.h toplev.h tree-inline.h cgraph.h cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) tree-dump.h cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h integrate.h insn-config.h \ - input.h $(PARAMS_H) debug.h tree-inline.h + input.h $(PARAMS_H) debug.h tree-inline.h tree-simple.h cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h real.h gt-cp-mangle.h \ $(TARGET_H) $(TM_P_H) cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) diagnostic.h gt-cp-parser.h \ output.h +cp/cp-simplify.o: cp/cp-simplify.c $(CXX_TREE_H) toplev.h c-common.h \ + $(TM_H) coretypes.h +cp/cp-mudflap.o: cp/cp-mudflap.c $(CXX_TREE_H) toplev.h c-common.h \ + $(TM_H) coretypes.h cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(CXX_TREE_H) timevar.h gt-cp-name-lookup.h toplev.h \ diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4f38c7ed622..c4892e949e4 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -346,7 +346,7 @@ build_call (tree function, tree parms) TREE_VALUE (tmp), t); } - function = build (CALL_EXPR, result_type, function, parms); + function = build (CALL_EXPR, result_type, function, parms, NULL_TREE); TREE_HAS_CONSTRUCTOR (function) = is_constructor; TREE_NOTHROW (function) = nothrow; @@ -4331,7 +4331,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, static tree call_builtin_trap (tree type) { - tree fn = IDENTIFIER_GLOBAL_VALUE (get_identifier ("__builtin_trap")); + tree fn = implicit_built_in_decls[BUILT_IN_TRAP]; my_friendly_assert (fn != NULL, 20030927); fn = build_call (fn, NULL_TREE); @@ -4560,7 +4560,7 @@ build_over_call (struct z_candidate *cand, int flags) tree expr; tree return_type; return_type = TREE_TYPE (TREE_TYPE (fn)); - expr = build (CALL_EXPR, return_type, fn, args); + expr = build (CALL_EXPR, return_type, fn, args, NULL_TREE); if (!VOID_TYPE_P (return_type)) require_complete_type (return_type); return convert_from_reference (expr); @@ -4768,16 +4768,11 @@ build_over_call (struct z_candidate *cand, int flags) else if (TREE_CODE (arg) == TARGET_EXPR || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn))) { - tree address; tree to = stabilize_reference (build_indirect_ref (TREE_VALUE (args), 0)); val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg); - address = build_unary_op (ADDR_EXPR, val, 0); - /* Avoid a warning about this expression, if the address is - never used. */ - TREE_USED (address) = 1; - return address; + return val; } } else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR @@ -4813,7 +4808,7 @@ build_over_call (struct z_candidate *cand, int flags) val = build (MODIFY_EXPR, as_base, to_as_base, arg_as_base); val = convert_to_void (val, NULL); val = build (COMPOUND_EXPR, type, val, save_to); - TREE_NO_UNUSED_WARNING (val) = 1; + TREE_NO_WARNING (val) = 1; } return val; @@ -4936,7 +4931,8 @@ build_java_interface_fn_ref (tree fn, tree instance) iface); return error_mark_node; } - iface_ref = build1 (ADDR_EXPR, build_pointer_type (iface), iface_ref); + iface_ref = build_address (iface_ref); + iface_ref = convert (build_pointer_type (iface), iface_ref); /* Determine the itable index of FN. */ i = 1; @@ -5360,7 +5356,7 @@ build_new_method_call (tree instance, tree fns, tree args, call = (build_min_non_dep (CALL_EXPR, call, build_min_nt (COMPONENT_REF, orig_instance, orig_fns), - orig_args)); + orig_args, NULL_TREE)); /* Free all the conversions we allocated. */ obstack_free (&conversion_obstack, p); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 13d6d03c9a5..6d2fef50205 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -335,14 +335,14 @@ build_base_path (enum tree_code code, /* In a base member initializer, we cannot rely on the vtable being set up. We have to use the vtt_parm. */ tree derived = BINFO_INHERITANCE_CHAIN (v_binfo); - - v_offset = build (PLUS_EXPR, TREE_TYPE (current_vtt_parm), - current_vtt_parm, BINFO_VPTR_INDEX (derived)); - - v_offset = build1 (INDIRECT_REF, - TREE_TYPE (TYPE_VFIELD (BINFO_TYPE (derived))), - v_offset); - + tree t; + + t = TREE_TYPE (TYPE_VFIELD (BINFO_TYPE (derived))); + t = build_pointer_type (t); + v_offset = convert (t, current_vtt_parm); + v_offset = build (PLUS_EXPR, t, v_offset, + BINFO_VPTR_INDEX (derived)); + v_offset = build_indirect_ref (v_offset, NULL); } else v_offset = build_vfield_ref (build_indirect_ref (expr, NULL), @@ -354,6 +354,8 @@ build_base_path (enum tree_code code, build_pointer_type (ptrdiff_type_node), v_offset); v_offset = build_indirect_ref (v_offset, NULL); + TREE_CONSTANT (v_offset) = 1; + TREE_INVARIANT (v_offset) = 1; offset = convert_to_integer (ptrdiff_type_node, size_diffop (offset, @@ -513,7 +515,7 @@ build_vtbl_ref_1 (tree instance, tree idx) tree binfo = lookup_base (fixed_type, basetype, ba_ignore|ba_quiet, NULL); if (binfo) - vtbl = BINFO_VTABLE (binfo); + vtbl = unshare_expr (BINFO_VTABLE (binfo)); } if (!vtbl) @@ -522,6 +524,8 @@ build_vtbl_ref_1 (tree instance, tree idx) assemble_external (vtbl); aref = build_array_ref (vtbl, idx); + TREE_CONSTANT (aref) |= TREE_CONSTANT (vtbl) && TREE_CONSTANT (idx); + TREE_INVARIANT (aref) = TREE_CONSTANT (aref); return aref; } @@ -7277,10 +7281,7 @@ dfs_accumulate_vtbl_inits (tree binfo, /* Figure out the position to which the VPTR should point. */ vtbl = TREE_PURPOSE (l); - vtbl = build1 (ADDR_EXPR, - vtbl_ptr_type_node, - vtbl); - TREE_CONSTANT (vtbl) = 1; + vtbl = build1 (ADDR_EXPR, vtbl_ptr_type_node, vtbl); index = size_binop (PLUS_EXPR, size_int (non_fn_entries), size_int (list_length (TREE_VALUE (l)))); @@ -7288,7 +7289,6 @@ dfs_accumulate_vtbl_inits (tree binfo, TYPE_SIZE_UNIT (vtable_entry_type), index); vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index); - TREE_CONSTANT (vtbl) = 1; } if (ctor_vtbl_p) @@ -7462,8 +7462,6 @@ build_vtbl_initializer (tree binfo, /* Take the address of the function, considering it to be of an appropriate generic type. */ init = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn); - /* The address of a function can't change. */ - TREE_CONSTANT (init) = 1; } /* And add it to the chain of initializers. */ @@ -7480,6 +7478,7 @@ build_vtbl_initializer (tree binfo, TREE_OPERAND (init, 0), build_int_2 (i, 0)); TREE_CONSTANT (fdesc) = 1; + TREE_INVARIANT (fdesc) = 1; vfun_inits = tree_cons (NULL_TREE, fdesc, vfun_inits); } diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index 3c2a311e9ca..3d737ad502a 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -35,11 +35,12 @@ Boston, MA 02111-1307, USA. */ enum c_language_kind c_language = clk_cxx; static HOST_WIDE_INT cxx_get_alias_set (tree); -static bool ok_to_generate_alias_set_for_type (tree); static bool cxx_warn_unused_global_decl (tree); static tree cp_expr_size (tree); static size_t cp_tree_size (enum tree_code); static bool cp_var_mod_type_p (tree); +static int cxx_types_compatible_p (tree, tree); +static int cp_expand_decl (tree); static void cxx_initialize_diagnostics (diagnostic_context *); #undef LANG_HOOKS_NAME @@ -70,14 +71,14 @@ static void cxx_initialize_diagnostics (diagnostic_context *); #define LANG_HOOKS_EXPAND_CONSTANT cplus_expand_constant #undef LANG_HOOKS_EXPAND_EXPR #define LANG_HOOKS_EXPAND_EXPR cxx_expand_expr +#undef LANG_HOOKS_EXPAND_DECL +#define LANG_HOOKS_EXPAND_DECL cp_expand_decl #undef LANG_HOOKS_SAFE_FROM_P #define LANG_HOOKS_SAFE_FROM_P c_safe_from_p #undef LANG_HOOKS_PARSE_FILE #define LANG_HOOKS_PARSE_FILE c_common_parse_file #undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL #define LANG_HOOKS_DUP_LANG_SPECIFIC_DECL cxx_dup_lang_specific_decl -#undef LANG_HOOKS_UNSAVE_EXPR_NOW -#define LANG_HOOKS_UNSAVE_EXPR_NOW cxx_unsave_expr_now #undef LANG_HOOKS_MAYBE_BUILD_CLEANUP #define LANG_HOOKS_MAYBE_BUILD_CLEANUP cxx_maybe_build_cleanup #undef LANG_HOOKS_TRUTHVALUE_CONVERSION @@ -110,8 +111,6 @@ static void cxx_initialize_diagnostics (diagnostic_context *); #define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL cxx_warn_unused_global_decl #undef LANG_HOOKS_WRITE_GLOBALS #define LANG_HOOKS_WRITE_GLOBALS lhd_do_nothing -#undef LANG_HOOKS_DECL_UNINIT -#define LANG_HOOKS_DECL_UNINIT c_decl_uninit #undef LANG_HOOKS_UPDATE_DECL_AFTER_SAVING #define LANG_HOOKS_UPDATE_DECL_AFTER_SAVING cp_update_decl_after_saving @@ -120,11 +119,8 @@ static void cxx_initialize_diagnostics (diagnostic_context *); #define LANG_HOOKS_FUNCTION_INIT cxx_push_function_context #undef LANG_HOOKS_FUNCTION_FINAL #define LANG_HOOKS_FUNCTION_FINAL cxx_pop_function_context - -#undef LANG_HOOKS_RTL_EXPAND_START -#define LANG_HOOKS_RTL_EXPAND_START cxx_expand_function_start -#undef LANG_HOOKS_RTL_EXPAND_STMT -#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt +#undef LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P +#define LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE @@ -145,7 +141,7 @@ static void cxx_initialize_diagnostics (diagnostic_context *); cp_add_pending_fn_decls #undef LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P #define LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P \ - cp_is_overload_p + cp_tree_chain_matters_p #undef LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P #define LANG_HOOKS_TREE_INLINING_AUTO_VAR_IN_FN_P \ cp_auto_var_in_fn_p @@ -156,8 +152,6 @@ static void cxx_initialize_diagnostics (diagnostic_context *); #define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P anon_aggr_type_p #undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P #define LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P cp_var_mod_type_p -#undef LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS -#define LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS c_estimate_num_insns #undef LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN #define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN cp_dump_tree #undef LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN @@ -186,8 +180,12 @@ static void cxx_initialize_diagnostics (diagnostic_context *); #define LANG_HOOKS_INCOMPLETE_TYPE_ERROR cxx_incomplete_type_error #undef LANG_HOOKS_TYPE_PROMOTES_TO #define LANG_HOOKS_TYPE_PROMOTES_TO cxx_type_promotes_to +#undef LANG_HOOKS_TYPES_COMPATIBLE_P +#define LANG_HOOKS_TYPES_COMPATIBLE_P cxx_types_compatible_p #undef LANG_HOOKS_REGISTER_BUILTIN_TYPE #define LANG_HOOKS_REGISTER_BUILTIN_TYPE c_register_builtin_type +#undef LANG_HOOKS_GIMPLIFY_EXPR +#define LANG_HOOKS_GIMPLIFY_EXPR cp_gimplify_expr /* Each front end provides its own hooks, for toplev.c. */ const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; @@ -233,60 +231,6 @@ const char *const tree_code_name[] = { }; #undef DEFTREECODE -/* Check if a C++ type is safe for aliasing. - Return TRUE if T safe for aliasing FALSE otherwise. */ - -static bool -ok_to_generate_alias_set_for_type (tree t) -{ - if (TYPE_PTRMEMFUNC_P (t)) - return true; - if (AGGREGATE_TYPE_P (t)) - { - if ((TREE_CODE (t) == RECORD_TYPE) || (TREE_CODE (t) == UNION_TYPE)) - { - tree fields; - /* Backend-created structs are safe. */ - if (! CLASS_TYPE_P (t)) - return true; - /* PODs are safe. */ - if (! CLASSTYPE_NON_POD_P(t)) - return true; - /* Classes with virtual baseclasses are not. */ - if (TYPE_USES_VIRTUAL_BASECLASSES (t)) - return false; - /* Recursively check the base classes. */ - if (TYPE_BINFO (t) != NULL && TYPE_BINFO_BASETYPES (t) != NULL) - { - int i; - for (i = 0; i < TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (t)); i++) - { - tree binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i); - if (!ok_to_generate_alias_set_for_type (BINFO_TYPE (binfo))) - return false; - } - } - /* Check all the fields. */ - for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields)) - { - if (TREE_CODE (fields) != FIELD_DECL) - continue; - if (! ok_to_generate_alias_set_for_type (TREE_TYPE (fields))) - return false; - } - return true; - } - else if (TREE_CODE (t) == ARRAY_TYPE) - return ok_to_generate_alias_set_for_type (TREE_TYPE (t)); - else - /* This should never happen, we dealt with all the aggregate - types that can appear in C++ above. */ - abort (); - } - else - return true; -} - /* Special routine to get the alias set for C++. */ static HOST_WIDE_INT @@ -297,13 +241,8 @@ cxx_get_alias_set (tree t) complete type. */ return get_alias_set (TYPE_CONTEXT (t)); - if (/* It's not yet safe to use alias sets for some classes in C++. */ - !ok_to_generate_alias_set_for_type (t) - /* Nor is it safe to use alias sets for pointers-to-member - functions, due to the fact that there may be more than one - RECORD_TYPE type corresponding to the same pointer-to-member - type. */ - || TYPE_PTRMEMFUNC_P (t)) + /* Punt on PMFs until we canonicalize functions properly. */ + if (TYPE_PTRMEMFUNC_P (t)) return 0; return c_common_get_alias_set (t); @@ -354,6 +293,35 @@ cp_expr_size (tree exp) return lhd_expr_size (exp); } +/* Expand DECL if it declares an entity not handled by the + common code. */ + +static int +cp_expand_decl (tree decl) +{ + if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl)) + { + /* Let the back-end know about this variable. */ + if (!anon_aggr_type_p (TREE_TYPE (decl))) + emit_local_var (decl); + else + expand_anon_union_decl (decl, NULL_TREE, + DECL_ANON_UNION_ELEMS (decl)); + } + else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) + make_rtl_for_local_static (decl); + else + return 0; + + return 1; +} + +int +cp_tree_chain_matters_p (tree t) +{ + return cp_is_overload_p (t) || c_tree_chain_matters_p (t); +} + /* Langhook for tree_size: determine size of our 'x' and 'c' nodes. */ static size_t cp_tree_size (enum tree_code code) @@ -388,6 +356,11 @@ cp_var_mod_type_p (tree type) return false; } +static int cxx_types_compatible_p (tree x, tree y) +{ + return same_type_ignoring_top_level_qualifiers_p (x, y); +} + /* Construct a C++-aware pretty-printer for CONTEXT. It is assumed that CONTEXT->printer is an already constructed basic pretty_printer. */ static void diff --git a/gcc/cp/cp-mudflap.c b/gcc/cp/cp-mudflap.c new file mode 100644 index 00000000000..878dc8a1c85 --- /dev/null +++ b/gcc/cp/cp-mudflap.c @@ -0,0 +1,108 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting: + C++ front-end interface. + + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" +#include "errors.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tree-inline.h" +#include "cp-tree.h" +#include "c-common.h" +#include "diagnostic.h" +#include "output.h" +#include "varray.h" +#include "tree-mudflap.h" +#include "target.h" +#include "flags.h" +#include "rtl.h" +#include "toplev.h" + + +/* Initialize the global tree nodes that correspond to mf-runtime.h + declarations. */ +tree +mflang_lookup_decl (const char* name) +{ + tree decl = lookup_name (get_identifier (name), 1); + if (decl == NULL_TREE) + internal_error ("mudflap: cannot find declaration of `%s' from mf-runtime.h", + name); + + return decl; +} + + +/* Emit a synthetic CTOR function for the current file. Populate it from + the enqueued __mf_register calls. Register it with the constructors. */ + +void +mflang_flush_calls (tree enqueued_call_stmt_chain) +{ + tree fnname, fndecl, body; + + /* Short-circuit! */ + if (enqueued_call_stmt_chain == NULL_TREE) + return; + + /* Create a ctor function declaration. */ + fnname = get_identifier ("__static_initialization_and_destruction_mudflap"); + + start_function (void_list_node, + make_call_declarator (fnname, void_list_node, NULL_TREE, + NULL_TREE), + NULL_TREE, SF_DEFAULT); + + TREE_PUBLIC (current_function_decl) = 0; + TREE_USED (current_function_decl) = 1; + DECL_ARTIFICIAL (current_function_decl) = 1; + mf_mark (current_function_decl); + + /* Generate the body, one statement at a time. */ + body = begin_compound_stmt (/*has_no_scope=*/false); + + while (enqueued_call_stmt_chain) + { + tree next = TREE_CHAIN (enqueued_call_stmt_chain); + finish_expr_stmt (enqueued_call_stmt_chain); + enqueued_call_stmt_chain = next; + } + + finish_compound_stmt (body); + fndecl = finish_function (0); + + /* NB: We cannot call expand_or_defer_fn here, since that goes through + the callgraph queue. This queue will have already been processed by the + time this function is running. */ + expand_body (fndecl); + if (targetm.have_ctors_dtors) + (* targetm.asm_out.constructor) (XEXP (DECL_RTL (fndecl), 0), + DEFAULT_INIT_PRIORITY); + else + /* By this time, it's too late to do this: + static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors); */ + abort (); +} diff --git a/gcc/cp/cp-simplify.c b/gcc/cp/cp-simplify.c new file mode 100644 index 00000000000..af302ee5476 --- /dev/null +++ b/gcc/cp/cp-simplify.c @@ -0,0 +1,236 @@ +/* C++-specific tree lowering bits; see also c-simplify.c and tree-simple.c. + + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Jason Merrill + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "cp-tree.h" +#include "c-common.h" +#include "toplev.h" +#include "tree-simple.h" + +static void genericize_try_block (tree *); +static void genericize_catch_block (tree *); +static void genericize_eh_spec_block (tree *); +static void gimplify_must_not_throw_expr (tree *, tree *); +static void cp_gimplify_init_expr (tree *, tree *, tree *); + +/* Genericize a C++ _STMT. Called from c_gimplify_stmt. */ + +int +cp_gimplify_stmt (tree *stmt_p, tree *next_p ATTRIBUTE_UNUSED) +{ + tree stmt = *stmt_p; + switch (TREE_CODE (stmt)) + { + case TRY_BLOCK: + genericize_try_block (stmt_p); + return 1; + + case HANDLER: + genericize_catch_block (stmt_p); + return 1; + + case EH_SPEC_BLOCK: + genericize_eh_spec_block (stmt_p); + return 1; + + case USING_STMT: + /* Just ignore for now. Eventually we will want to pass this on to + the debugger. */ + *stmt_p = build_empty_stmt (); + return 1; + + default: + break; + } + return 0; +} + +/* Genericize a TRY_BLOCK. */ + +static void +genericize_try_block (tree *stmt_p) +{ + tree body = TRY_STMTS (*stmt_p); + tree cleanup = TRY_HANDLERS (*stmt_p); + + c_gimplify_stmt (&body); + + if (CLEANUP_P (*stmt_p)) + /* A cleanup is an expression, so it doesn't need to be genericized. */; + else + c_gimplify_stmt (&cleanup); + + *stmt_p = build (TRY_CATCH_EXPR, void_type_node, body, cleanup); +} + +/* Genericize a HANDLER by converting to a CATCH_EXPR. */ + +static void +genericize_catch_block (tree *stmt_p) +{ + tree type = HANDLER_TYPE (*stmt_p); + tree body = HANDLER_BODY (*stmt_p); + + c_gimplify_stmt (&body); + + /* FIXME should the caught type go in TREE_TYPE? */ + *stmt_p = build (CATCH_EXPR, void_type_node, type, body); +} + +/* Genericize an EH_SPEC_BLOCK by converting it to a + TRY_CATCH_EXPR/EH_FILTER_EXPR pair. */ + +static void +genericize_eh_spec_block (tree *stmt_p) +{ + tree body = EH_SPEC_STMTS (*stmt_p); + tree allowed = EH_SPEC_RAISES (*stmt_p); + tree failure = build_call (call_unexpected_node, + tree_cons (NULL_TREE, build_exc_ptr (), + NULL_TREE)); + c_gimplify_stmt (&body); + + *stmt_p = gimple_build_eh_filter (body, allowed, failure); +} + +/* Do C++-specific gimplification. Args are as for gimplify_expr. */ + +int +cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + switch (TREE_CODE (*expr_p)) + { + case PTRMEM_CST: + *expr_p = cplus_expand_constant (*expr_p); + return GS_OK; + + case AGGR_INIT_EXPR: + simplify_aggr_init_expr (expr_p); + return GS_OK; + + case THROW_EXPR: + /* FIXME communicate throw type to backend, probably by moving + THROW_EXPR into ../tree.def. */ + *expr_p = TREE_OPERAND (*expr_p, 0); + return GS_OK; + + case MUST_NOT_THROW_EXPR: + gimplify_must_not_throw_expr (expr_p, pre_p); + return GS_OK; + + case INIT_EXPR: + case MODIFY_EXPR: + cp_gimplify_init_expr (expr_p, pre_p, post_p); + return GS_OK; + + case EMPTY_CLASS_EXPR: + { + /* Yes, an INTEGER_CST with RECORD_TYPE. */ + tree i = build_int_2 (0, 0); + TREE_TYPE (i) = TREE_TYPE (*expr_p); + *expr_p = i; + } + return GS_OK; + + case BASELINK: + *expr_p = BASELINK_FUNCTIONS (*expr_p); + return GS_OK; + + default: + return c_gimplify_expr (expr_p, pre_p, post_p); + } +} + +/* Gimplify initialization from an AGGR_INIT_EXPR. */ + +static void +cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree from = TREE_OPERAND (*expr_p, 1); + tree to = TREE_OPERAND (*expr_p, 0); + tree sub; + + /* If we are initializing something from a TARGET_EXPR, strip the + TARGET_EXPR and initialize it directly. */ + /* What about code that pulls out the temp and uses it elsewhere? I + think that such code never uses the TARGET_EXPR as an initializer. If + I'm wrong, we'll abort because the temp won't have any RTL. In that + case, I guess we'll need to replace references somehow. */ + if (TREE_CODE (from) == TARGET_EXPR) + from = TARGET_EXPR_INITIAL (from); + + sub = from; + + /* If we are initializing from a STMT_EXPR, extract the returned + expression. */ + if (TREE_CODE (from) == STMT_EXPR) + sub = EXPR_STMT_EXPR (stmt_expr_last_stmt (from)); + + /* Look through any COMPOUND_EXPRs. */ + while (TREE_CODE (sub) == COMPOUND_EXPR) + sub = TREE_OPERAND (sub, 1); + + /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and + replace the slot operand with our target. + + Should we add a target parm to gimplify_expr instead? No, as in this + case we want to replace the INIT_EXPR. */ + if (TREE_CODE (sub) == AGGR_INIT_EXPR) + { + gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); + TREE_OPERAND (sub, 2) = to; + *expr_p = from; + + /* The initialization is now a side-effect, so the container can + become void. This is important for a STMT_EXPR, so we don't try + to voidify it later by creating a temporary. */ + if (from != sub) + TREE_TYPE (from) = void_type_node; + } +} + +/* Gimplify a MUST_NOT_THROW_EXPR. */ + +static void +gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p) +{ + tree stmt = *expr_p; + tree temp = voidify_wrapper_expr (stmt); + tree body = TREE_OPERAND (stmt, 0); + + gimplify_stmt (&body); + + stmt = gimple_build_eh_filter (body, NULL_TREE, + build_call (terminate_node, NULL_TREE)); + + if (temp) + { + append_to_statement_list (stmt, pre_p); + *expr_p = temp; + } + else + *expr_p = stmt; +} diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index d64752068a3..63a18af378e 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -257,6 +257,15 @@ DEFTREECODE (MUST_NOT_THROW_EXPR, "must_not_throw_expr", 'e', 1) DEFTREECODE (TAG_DEFN, "tag_defn", 'e', 0) +/* Template instantiation level node. + + Operand 1 contains the original DECL node and can be accessed via TINST_DECL. + + A stack of template instantiation nodes is kept through the TREE_CHAIN + fields of these nodes. */ + +DEFTREECODE (TINST_LEVEL, "TINST_LEVEL", 'e', 1) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 37170e2ca71..7efe55d8061 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3137,12 +3137,9 @@ typedef enum unification_kind_t { DEDUCE_ORDER } unification_kind_t; -/* Macros for operating on a template instantiation level node, represented - by an EXPR_WITH_FILE_LOCATION. */ +/* Macros for operating on a template instantiation level node. */ -#define TINST_DECL(NODE) EXPR_WFL_NODE (NODE) -#define TINST_LINE(NODE) EXPR_WFL_LINENO (NODE) -#define TINST_FILE(NODE) EXPR_WFL_FILENAME (NODE) +#define TINST_DECL(NODE) TREE_OPERAND (NODE, 0) /* in class.c */ @@ -3709,6 +3706,7 @@ extern tmpl_spec_kind current_tmpl_spec_kind (int); extern tree cp_fname_init (const char *, tree *); extern tree check_elaborated_type_specifier (enum tag_types, tree, bool); extern void warn_extern_redeclared_static (tree, tree); +extern bool cp_missing_noreturn_ok_p (tree); extern bool have_extern_spec; @@ -4047,7 +4045,7 @@ extern void finish_handler (tree); extern void finish_cleanup (tree, tree); extern tree begin_compound_stmt (bool); extern tree finish_compound_stmt (tree); -extern tree finish_asm_stmt (tree, tree, tree, tree, tree); +extern tree finish_asm_stmt (int, tree, tree, tree, tree); extern tree finish_label_stmt (tree); extern void finish_label_decl (tree); extern void finish_subobject (tree); @@ -4087,7 +4085,6 @@ extern void finish_decl_cleanup (tree, tree); extern void finish_eh_cleanup (tree); extern void expand_body (tree); extern void cxx_expand_function_start (void); -extern tree nullify_returns_r (tree *, int *, void *); extern void do_pushlevel (scope_kind); extern tree do_poplevel (void); extern void finish_mem_initializers (tree); @@ -4098,11 +4095,14 @@ extern void expand_or_defer_fn (tree); extern void check_accessibility_of_qualified_id (tree, tree, tree); extern tree finish_qualified_id_expr (tree, tree, bool, bool); extern void simplify_aggr_init_expr (tree *); +extern void finalize_nrv (tree *, tree, tree); /* in tree.c */ extern void lang_check_failed (const char *, int, const char *); extern tree stabilize_expr (tree, tree *); +extern void stabilize_call (tree, tree *); +extern bool stabilize_init (tree, tree *); extern tree cxx_unsave_expr_now (tree); extern tree cxx_maybe_build_cleanup (tree); extern void init_tree (void); @@ -4166,6 +4166,7 @@ extern tree find_tree (tree, tree); extern linkage_kind decl_linkage (tree); extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn, void*, void*); +extern int cp_tree_chain_matters_p (tree); extern int cp_cannot_inline_tree_fn (tree*); extern tree cp_add_pending_fn_decls (void*,tree); extern int cp_is_overload_p (tree); @@ -4283,6 +4284,10 @@ extern tree mangle_ref_init_variable (tree); /* in dump.c */ extern bool cp_dump_tree (void *, tree); +/* in cp-simplify.c */ +extern int cp_gimplify_expr (tree *, tree *, tree *); +extern int cp_gimplify_stmt (tree *, tree *); + /* -- end of C++ */ /* In order for the format checking to accept the C++ frontend diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index bf906fd969e..b22948106b2 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -810,7 +810,7 @@ convert_to_void (tree expr, const char *implicit) /* The second part of a compound expr contains the value. */ tree op1 = TREE_OPERAND (expr,1); tree new_op1 = convert_to_void - (op1, (implicit && !TREE_NO_UNUSED_WARNING (expr) + (op1, (implicit && !TREE_NO_WARNING (expr) ? "right-hand operand of comma" : NULL)); if (new_op1 != op1) @@ -887,7 +887,8 @@ convert_to_void (tree expr, const char *implicit) if (expr != error_mark_node && !VOID_TYPE_P (TREE_TYPE (expr))) { - if (implicit && !TREE_SIDE_EFFECTS (expr) && warn_unused_value) + if (implicit && warn_unused_value + && !TREE_SIDE_EFFECTS (expr) && !TREE_NO_WARNING (expr)) warning ("%s has no effect", implicit); expr = build1 (CONVERT_EXPR, void_type_node, expr); } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 17b625f668c..21f82548eaa 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -51,6 +51,7 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "debug.h" #include "timevar.h" +#include "tree-flow.h" static tree grokparms (tree, tree *); static const char *redeclaration_error_message (tree, tree); @@ -114,7 +115,6 @@ static tree check_special_function_return_type static tree push_cp_library_fn (enum tree_code, tree); static tree build_cp_library_fn (tree, enum tree_code, tree); static void store_parm_decls (tree); -static int cp_missing_noreturn_ok_p (tree); static void initialize_local_var (tree, tree); static void expand_static_init (tree, tree); static tree next_initializable_field (tree); @@ -499,28 +499,6 @@ poplevel (int keep, int reverse, int functionbody) else decls = current_binding_level->names; - /* Output any nested inline functions within this block - if they weren't already output. */ - for (decl = decls; decl; decl = TREE_CHAIN (decl)) - if (TREE_CODE (decl) == FUNCTION_DECL - && ! TREE_ASM_WRITTEN (decl) - && DECL_INITIAL (decl) != NULL_TREE - && TREE_ADDRESSABLE (decl) - && decl_function_context (decl) == current_function_decl) - { - /* If this decl was copied from a file-scope decl - on account of a block-scope extern decl, - propagate TREE_ADDRESSABLE to the file-scope decl. */ - if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) - TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; - else - { - push_function_context (); - output_inline_function (decl); - pop_function_context (); - } - } - /* When not in function-at-a-time mode, expand_end_bindings will warn about unused variables. But, in function-at-a-time mode expand_end_bindings is not passed the list of variables in the @@ -2406,9 +2384,11 @@ push_switch (tree switch_stmt) void pop_switch (void) { - struct cp_switch *cs; + struct cp_switch *cs = switch_stack; + + /* Emit warnings as needed. */ + c_do_switch_warnings (cs->cases, cs->switch_stmt); - cs = switch_stack; splay_tree_delete (cs->cases); switch_stack = switch_stack->next; free (cs); @@ -2878,9 +2858,6 @@ cxx_init_decl_processing (void) /* Create all the identifiers we need. */ initialize_predefined_identifiers (); - /* Fill in back-end hooks. */ - lang_missing_noreturn_ok_p = &cp_missing_noreturn_ok_p; - /* Create the global variables. */ push_to_top_level (); @@ -3060,7 +3037,8 @@ cxx_init_decl_processing (void) start_fname_decls (); /* Show we use EH for cleanups. */ - using_eh_for_cleanups (); + if (flag_exceptions) + using_eh_for_cleanups (); } /* Generate an initializer for a function naming variable from @@ -4544,7 +4522,7 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) asm-specification, indicates that the variable should be placed in a particular register. */ if (DECL_REGISTER (decl)) - DECL_C_HARD_REGISTER (decl) = 1; + DECL_HARD_REGISTER (decl) = 1; } /* We don't create any RTL for local variables. */ @@ -7283,6 +7261,13 @@ grokdeclarator (tree declarator, type = create_array_type_for_decl (dname, type, size); + if (declarator + && (TREE_CODE (declarator) == INDIRECT_REF + || TREE_CODE (declarator) == ADDR_EXPR)) + /* We can never complete an array type which is the target of a + pointer, so go ahead and lay it out. */ + layout_type (type); + ctype = NULL_TREE; } break; @@ -7768,6 +7753,7 @@ grokdeclarator (tree declarator, } if (declarator == NULL_TREE + || TREE_CODE (declarator) == ERROR_MARK || TREE_CODE (declarator) == IDENTIFIER_NODE || (TREE_CODE (declarator) == TEMPLATE_ID_EXPR && (TREE_CODE (type) == FUNCTION_TYPE @@ -9935,7 +9921,9 @@ build_enumerator (tree name, tree value, tree enumtype) decl = build_decl (CONST_DECL, name, type); DECL_CONTEXT (decl) = FROB_CONTEXT (context); - TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1; + TREE_CONSTANT (decl) = 1; + TREE_INVARIANT (decl) = 1; + TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = value; if (context && context == current_class_type) @@ -10730,10 +10718,8 @@ finish_function (int flags) of curly braces for a function. */ my_friendly_assert (stmts_are_full_exprs_p (), 19990831); - /* Set up the named return value optimization, if we can. Here, we - eliminate the copy from the nrv into the RESULT_DECL and any cleanup - for the nrv. genrtl_start_function and declare_return_variable - handle making the nrv and RESULT_DECL share space. */ + /* Set up the named return value optimization, if we can. Candidate + variables are selected in check_return_value. */ if (current_function_return_value) { tree r = current_function_return_value; @@ -10750,16 +10736,9 @@ finish_function (int flags) /* Skip the artificial function body block. */ && (outer = BLOCK_SUBBLOCKS (BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl))), chain_member (r, BLOCK_VARS (outer)))) - { - - DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fndecl)); - walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), - nullify_returns_r, r); - } - else - /* Clear it so genrtl_start_function and declare_return_variable - know we're not optimizing. */ - current_function_return_value = NULL_TREE; + finalize_nrv (&DECL_SAVED_TREE (fndecl), r, DECL_RESULT (fndecl)); + + current_function_return_value = NULL_TREE; } /* Remember that we were in class scope. */ @@ -10802,9 +10781,21 @@ finish_function (int flags) && (DECL_INLINE (fndecl) || processing_template_decl)) warning ("no return statement in function returning non-void"); - /* We're leaving the context of this function, so zap cfun. - It's still in DECL_STRUCT_FUNCTION, and we'll restore it in - tree_rest_of_compilation. */ + /* Store the end of the function, so that we get good line number + info for the epilogue. */ + cfun->function_end_locus = input_location; + + /* Genericize before inlining. */ + if (!processing_template_decl) + { + c_genericize (fndecl); + + /* Handle attribute((warn_unused_result)). Relies on gimple input. */ + c_warn_unused_result (&DECL_SAVED_TREE (fndecl)); + } + + /* We're leaving the context of this function, so zap cfun. It's still in + DECL_STRUCT_FUNCTION, and we'll restore it in tree_rest_of_compilation. */ cfun = NULL; current_function_decl = NULL; @@ -11178,7 +11169,7 @@ build_void_list_node (void) return t; } -static int +bool cp_missing_noreturn_ok_p (tree decl) { /* A missing noreturn is ok for the `main' function. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 5730d369efc..4c36eb5549c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -46,8 +46,10 @@ Boston, MA 02111-1307, USA. */ #include "cpplib.h" #include "target.h" #include "c-common.h" +#include "tree-mudflap.h" #include "cgraph.h" #include "tree-inline.h" + extern cpp_reader *parse_in; /* This structure contains information about the initializations @@ -2587,7 +2589,7 @@ finish_file (void) timevar_push (TV_VARCONST); emit_support_tinfos (); - + do { tree t; @@ -2872,6 +2874,11 @@ finish_file (void) cgraph_optimize (); } + /* Emit mudflap static registration function. This must be done + after all the user functions have been expanded. */ + if (flag_mudflap) + mudflap_finish_file (); + /* Now, issue warnings about static, but not defined, functions, etc., and emit debugging information. */ walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider); @@ -2885,12 +2892,12 @@ finish_file (void) to a file. */ { int flags; - FILE *stream = dump_begin (TDI_all, &flags); + FILE *stream = dump_begin (TDI_tu, &flags); if (stream) { dump_node (global_namespace, flags & ~TDF_SLIM, stream); - dump_end (TDI_all, stream); + dump_end (TDI_tu, stream); } } @@ -2932,7 +2939,7 @@ build_offset_ref_call_from_tree (tree fn, tree args) 20030708); if (type_dependent_expression_p (fn) || any_type_dependent_arguments_p (args)) - return build_min_nt (CALL_EXPR, fn, args); + return build_min_nt (CALL_EXPR, fn, args, NULL_TREE); /* Transform the arguments and add the implicit "this" parameter. That must be done before the FN is transformed @@ -2962,7 +2969,7 @@ build_offset_ref_call_from_tree (tree fn, tree args) expr = build_function_call (fn, args); if (processing_template_decl && expr != error_mark_node) - return build_min_non_dep (CALL_EXPR, expr, orig_fn, orig_args); + return build_min_non_dep (CALL_EXPR, expr, orig_fn, orig_args, NULL_TREE); return expr; } diff --git a/gcc/cp/error.c b/gcc/cp/error.c index e313c16f39d..6e186503bad 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -47,7 +47,7 @@ static cxx_pretty_printer scratch_pretty_printer; # define NEXT_CODE(T) (TREE_CODE (TREE_TYPE (T))) #define reinit_global_formatting_buffer() \ - output_clear_message_text (scratch_buffer) + pp_clear_output_area (scratch_buffer) static const char *args_to_string (tree, int); static const char *assop_to_string (enum tree_code); @@ -1604,10 +1604,6 @@ dump_expr (tree t, int flags) break; } - case EXPR_WITH_FILE_LOCATION: - dump_expr (EXPR_WFL_NODE (t), flags); - break; - case CONSTRUCTOR: if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))) { @@ -2191,8 +2187,7 @@ print_instantiation_full_context (diagnostic_context *context) decl_as_string (TINST_DECL (p), TFF_DECL_SPECIFIERS | TFF_RETURN_TYPE)); - location.line = TINST_LINE (p); - location.file = TINST_FILE (p); + location = *EXPR_LOCUS (p); p = TREE_CHAIN (p); } } @@ -2211,8 +2206,7 @@ print_instantiation_partial_context (diagnostic_context *context, loc.file, loc.line, decl_as_string (TINST_DECL (t), TFF_DECL_SPECIFIERS | TFF_RETURN_TYPE)); - loc.line = TINST_LINE (t); - loc.file = TINST_FILE (t); + loc = *EXPR_LOCUS (t); } pp_verbatim (context->printer, "%s:%d: instantiated from here\n", loc.file, loc.line); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 7e172d62e6b..79f1dfac0d9 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -47,7 +47,6 @@ static tree do_end_catch (tree); static bool decl_is_java_type (tree decl, int err); static void initialize_handler_parm (tree, tree); static tree do_allocate_exception (tree); -static tree stabilize_throw_expr (tree, tree *); static tree wrap_cleanups_r (tree *, int *, void *); static int complete_ptr_ref_or_void_ptr_p (tree, tree); static bool is_admissible_throw_operand (tree); @@ -145,7 +144,7 @@ build_eh_type_type (tree type) mark_used (exp); - return build1 (ADDR_EXPR, ptr_type_node, exp); + return convert (ptr_type_node, build_address (exp)); } tree @@ -507,7 +506,6 @@ do_allocate_exception (tree type) NULL_TREE)); } -#if 0 /* Call __cxa_free_exception from a cleanup. This is never invoked directly, but see the comment for stabilize_throw_expr. */ @@ -526,7 +524,6 @@ do_free_exception (tree ptr) return build_function_call (fn, tree_cons (NULL_TREE, ptr, NULL_TREE)); } -#endif /* Wrap all cleanups for TARGET_EXPRs in MUST_NOT_THROW_EXPR. Called from build_throw via walk_tree_without_duplicates. */ @@ -558,58 +555,6 @@ wrap_cleanups_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, return NULL_TREE; } -/* Like stabilize_expr, but specifically for a thrown expression. When - throwing a temporary class object, we want to construct it directly into - the thrown exception, so we look past the TARGET_EXPR and stabilize the - arguments of the call instead. - - The case where EXP is a call to a function returning a class is a bit of - a grey area in the standard; it's unclear whether or not it should be - allowed to throw. I'm going to say no, as that allows us to optimize - this case without worrying about deallocating the exception object if it - does. The alternatives would be either not optimizing this case, or - wrapping the initialization in a TRY_CATCH_EXPR to call do_free_exception - rather than in a MUST_NOT_THROW_EXPR, for this case only. */ - -static tree -stabilize_throw_expr (tree exp, tree *initp) -{ - tree init_expr; - - if (TREE_CODE (exp) == TARGET_EXPR - && TREE_CODE (TARGET_EXPR_INITIAL (exp)) == AGGR_INIT_EXPR - && flag_elide_constructors) - { - tree aggr_init = AGGR_INIT_EXPR_CHECK (TARGET_EXPR_INITIAL (exp)); - tree args = TREE_OPERAND (aggr_init, 1); - tree newargs = NULL_TREE; - tree *p = &newargs; - - init_expr = void_zero_node; - for (; args; args = TREE_CHAIN (args)) - { - tree arg = TREE_VALUE (args); - tree arg_init_expr; - - arg = stabilize_expr (arg, &arg_init_expr); - - if (TREE_SIDE_EFFECTS (arg_init_expr)) - init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, - arg_init_expr); - *p = tree_cons (NULL_TREE, arg, NULL_TREE); - p = &TREE_CHAIN (*p); - } - TREE_OPERAND (aggr_init, 1) = newargs; - } - else - { - exp = stabilize_expr (exp, &init_expr); - } - - *initp = init_expr; - return exp; -} - /* Build a throw expression. */ tree @@ -663,6 +608,7 @@ build_throw (tree exp) tree object, ptr; tree tmp; tree temp_expr, allocate_expr; + bool elided; fn = get_identifier ("__cxa_throw"); if (!get_global_value_if_present (fn, &fn)) @@ -703,11 +649,6 @@ build_throw (tree exp) the call to __cxa_allocate_exception first (which doesn't matter, since it can't throw). */ - /* Pre-evaluate the thrown expression first, since if we allocated - the space first we would have to deal with cleaning it up if - evaluating this expression throws. */ - exp = stabilize_throw_expr (exp, &temp_expr); - /* Allocate the space for the exception. */ allocate_expr = do_allocate_exception (TREE_TYPE (exp)); allocate_expr = get_target_expr (allocate_expr); @@ -715,6 +656,8 @@ build_throw (tree exp) object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr); object = build_indirect_ref (object, NULL); + elided = (TREE_CODE (exp) == TARGET_EXPR); + /* And initialize the exception object. */ exp = build_init (object, exp, LOOKUP_ONLYCONVERTING); if (exp == error_mark_node) @@ -723,10 +666,35 @@ build_throw (tree exp) return error_mark_node; } - exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp); + /* Pre-evaluate the thrown expression first, since if we allocated + the space first we would have to deal with cleaning it up if + evaluating this expression throws. + + The case where EXP the initializer is a call to a constructor or a + function returning a class is a bit of a grey area in the + standard; it's unclear whether or not it should be allowed to + throw. We used to say no, as that allowed us to optimize this + case without worrying about deallocating the exception object if + it does. But that conflicted with expectations (PR 13944) and the + EDG compiler; now we wrap the initialization in a TRY_CATCH_EXPR + to call do_free_exception rather than in a MUST_NOT_THROW_EXPR, + for this case only. + + Note that we don't check the return value from stabilize_init + because it will only return false in cases where elided is true, + and therefore we don't need to work around the failure to + preevaluate. */ + stabilize_init (exp, &temp_expr); + + if (elided) + exp = build (TRY_CATCH_EXPR, void_type_node, exp, + do_free_exception (ptr)); + else + exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp); + /* Prepend the allocation. */ exp = build (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp); - if (temp_expr != void_zero_node) + if (temp_expr) { /* Prepend the calculation of the throw expression. Also, force any cleanups from the expression to be evaluated here so that @@ -921,11 +889,10 @@ check_handlers_1 (tree master, tree handlers) if (TREE_TYPE (handler) && can_convert_eh (type, TREE_TYPE (handler))) { - input_line = STMT_LINENO (handler); - warning ("exception of type `%T' will be caught", - TREE_TYPE (handler)); - input_line = STMT_LINENO (master); - warning (" by earlier handler for `%T'", type); + warning ("%Hexception of type `%T' will be caught", + EXPR_LOCUS (handler), TREE_TYPE (handler)); + warning ("%H by earlier handler for `%T'", + EXPR_LOCUS (master), type); break; } } @@ -943,11 +910,8 @@ check_handlers (tree handlers) if (TREE_CHAIN (handler) == NULL_TREE) /* No more handlers; nothing to shadow. */; else if (TREE_TYPE (handler) == NULL_TREE) - { - input_line = STMT_LINENO (handler); - pedwarn - ("`...' handler must be the last handler for its try block"); - } + pedwarn ("%H`...' handler must be the last handler for" + " its try block", EXPR_LOCUS (handler)); else check_handlers_1 (handler, TREE_CHAIN (handler)); } diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 00f8676e180..e12c6a4a64f 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -73,6 +73,9 @@ cplus_expand_constant (tree cst) } /* Hook used by expand_expr to expand language-specific tree codes. */ +/* ??? The only thing that should be here are things needed to expand + constant initializers; everything else should be handled by the + gimplification routines. Are EMPTY_CLASS_EXPR or BASELINK needed? */ rtx cxx_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier, @@ -81,7 +84,6 @@ cxx_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier, tree type = TREE_TYPE (exp); enum machine_mode mode = TYPE_MODE (type); enum tree_code code = TREE_CODE (exp); - rtx ret; /* No sense saving up arithmetic to be done if it's all in the wrong mode to form part of an address. @@ -99,17 +101,6 @@ cxx_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier, case OFFSET_REF: /* Offset refs should not make it through to here. */ abort (); - return const0_rtx; - - case THROW_EXPR: - expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0); - return const0_rtx; - - case MUST_NOT_THROW_EXPR: - expand_eh_region_start (); - ret = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier); - expand_eh_region_end_must_not_throw (build_call (terminate_node, 0)); - return ret; case EMPTY_CLASS_EXPR: /* We don't need to generate any code for an empty class. */ @@ -122,7 +113,4 @@ cxx_expand_expr (tree exp, rtx target, enum machine_mode tmode, int modifier, default: return c_expand_expr (exp, target, tmode, modifier, alt_rtl); } - abort (); - /* NOTREACHED */ - return NULL; } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 6811aaab58e..8cf0019cfab 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -248,7 +248,10 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) /* In all cases, the initializer is a constant. */ if (init) - TREE_CONSTANT (init) = 1; + { + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + } return init; } @@ -728,12 +731,9 @@ build_vtbl_address (tree binfo) TREE_USED (vtbl) = 1; /* Now compute the address to use when initializing the vptr. */ - vtbl = BINFO_VTABLE (binfo_for); + vtbl = unshare_expr (BINFO_VTABLE (binfo_for)); if (TREE_CODE (vtbl) == VAR_DECL) - { - vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); - TREE_CONSTANT (vtbl) = 1; - } + vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); return vtbl; } @@ -767,7 +767,8 @@ expand_virtual_init (tree binfo, tree decl) TREE_TYPE (vtt_parm), vtt_parm, vtt_index); - vtbl2 = build1 (INDIRECT_REF, TREE_TYPE (vtbl), vtbl2); + vtbl2 = build_indirect_ref (vtbl2, NULL); + vtbl2 = convert (TREE_TYPE (vtbl), vtbl2); /* The actual initializer is the VTT value only in the subobject constructor. In maybe_clone_body we'll substitute NULL for @@ -1143,9 +1144,13 @@ build_init (tree decl, tree init, int flags) { tree expr; - if (IS_AGGR_TYPE (TREE_TYPE (decl)) - || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) expr = build_aggr_init (decl, init, flags); + else if (CLASS_TYPE_P (TREE_TYPE (decl))) + expr = build_special_member_call (decl, complete_ctor_identifier, + build_tree_list (NULL_TREE, init), + TYPE_BINFO (TREE_TYPE (decl)), + LOOKUP_NORMAL|flags); else expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init); @@ -1825,7 +1830,7 @@ build_new (tree placement, tree decl, tree init, int use_global_new) /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */ rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval); - TREE_NO_UNUSED_WARNING (rval) = 1; + TREE_NO_WARNING (rval) = 1; return rval; } @@ -1908,7 +1913,7 @@ static tree build_new_1 (tree exp) { tree placement, init; - tree true_type, size, rval, t; + tree true_type, size, rval; /* The type of the new-expression. (This type is always a pointer type.) */ tree pointer_type; @@ -1949,6 +1954,7 @@ build_new_1 (tree exp) address of the first array element. This node is a VAR_DECL, and is therefore reusable. */ tree data_addr; + tree init_preeval_expr = NULL_TREE; placement = TREE_OPERAND (exp, 0); type = TREE_OPERAND (exp, 1); @@ -2009,7 +2015,9 @@ build_new_1 (tree exp) tree class_addr, alloc_decl; tree class_decl = build_java_class_ref (true_type); static const char alloc_name[] = "_Jv_AllocObject"; + use_java_new = 1; + alloc_decl = NULL; if (!get_global_value_if_present (get_identifier (alloc_name), &alloc_decl)) { @@ -2115,18 +2123,8 @@ build_new_1 (tree exp) placement delete. */ if (placement_allocation_fn_p) { - tree inits = NULL_TREE; - t = TREE_CHAIN (TREE_OPERAND (alloc_call, 1)); - for (; t; t = TREE_CHAIN (t)) - if (TREE_SIDE_EFFECTS (TREE_VALUE (t))) - { - tree init; - TREE_VALUE (t) = stabilize_expr (TREE_VALUE (t), &init); - if (inits) - inits = build (COMPOUND_EXPR, void_type_node, inits, init); - else - inits = init; - } + tree inits; + stabilize_call (alloc_call, &inits); if (inits) alloc_expr = build (COMPOUND_EXPR, TREE_TYPE (alloc_expr), inits, alloc_expr); @@ -2169,27 +2167,43 @@ build_new_1 (tree exp) data_addr = alloc_node; } - /* Now initialize the allocated object. */ + /* Now initialize the allocated object. Note that we preevaluate the + initialization expression, apart from the actual constructor call or + assignment--we do this because we want to delay the allocation as long + as possible in order to minimize the size of the exception region for + placement delete. */ if (is_initialized) { + bool stable; + init_expr = build_indirect_ref (data_addr, NULL); if (init == void_zero_node) init = build_default_init (full_type, nelts); - else if (init && pedantic && has_array) + else if (init && has_array) pedwarn ("ISO C++ forbids initialization in array new"); if (has_array) - init_expr - = build_vec_init (init_expr, - cp_build_binary_op (MINUS_EXPR, outer_nelts, - integer_one_node), - init, /*from_array=*/0); + { + init_expr + = build_vec_init (init_expr, + cp_build_binary_op (MINUS_EXPR, outer_nelts, + integer_one_node), + init, /*from_array=*/0); + + /* An array initialization is stable because the initialization + of each element is a full-expression, so the temporaries don't + leak out. */ + stable = true; + } else if (TYPE_NEEDS_CONSTRUCTING (type)) - init_expr = build_special_member_call (init_expr, - complete_ctor_identifier, - init, TYPE_BINFO (true_type), - LOOKUP_NORMAL); + { + init_expr = build_special_member_call (init_expr, + complete_ctor_identifier, + init, TYPE_BINFO (true_type), + LOOKUP_NORMAL); + stable = stabilize_init (init_expr, &init_preeval_expr); + } else { /* We are processing something like `new int (10)', which @@ -2197,15 +2211,13 @@ build_new_1 (tree exp) if (TREE_CODE (init) == TREE_LIST) init = build_x_compound_expr_from_list (init, "new initializer"); - + else if (TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == NULL_TREE) - { - pedwarn ("ISO C++ forbids aggregate initializer to new"); - init = digest_init (type, init, 0); - } + abort (); init_expr = build_modify_expr (init_expr, INIT_EXPR, init); + stable = stabilize_init (init_expr, &init_preeval_expr); } if (init_expr == error_mark_node) @@ -2232,31 +2244,24 @@ build_new_1 (tree exp) (placement_allocation_fn_p ? alloc_call : NULL_TREE)); - /* Ack! First we allocate the memory. Then we set our sentry - variable to true, and expand a cleanup that deletes the memory - if sentry is true. Then we run the constructor, and finally - clear the sentry. - - It would be nice to be able to handle this without the sentry - variable, perhaps with a TRY_CATCH_EXPR, but this doesn't - work. We allocate the space first, so if there are any - temporaries with cleanups in the constructor args we need this - EH region to extend until end of full-expression to preserve - nesting. - - If the backend had some mechanism so that we could force the - allocation to be expanded after all the other args to the - constructor, that would fix the nesting problem and we could - do away with this complexity. But that would complicate other - things; in particular, it would make it difficult to bail out - if the allocation function returns null. Er, no, it wouldn't; - we just don't run the constructor. The standard says it's - unspecified whether or not the args are evaluated. - - FIXME FIXME FIXME inline invisible refs as refs. That way we - can preevaluate value parameters. */ - - if (cleanup) + if (!cleanup) + /* We're done. */; + else if (stable) + /* This is much simpler if we were able to preevaluate all of + the arguments to the constructor call. */ + init_expr = build (TRY_CATCH_EXPR, void_type_node, + init_expr, cleanup); + else + /* Ack! First we allocate the memory. Then we set our sentry + variable to true, and expand a cleanup that deletes the + memory if sentry is true. Then we run the constructor, and + finally clear the sentry. + + We need to do this because we allocate the space first, so + if there are any temporaries with cleanups in the + constructor args and we weren't able to preevaluate them, we + need this EH region to extend until end of full-expression + to preserve nesting. */ { tree end, sentry, begin; @@ -2277,6 +2282,7 @@ build_new_1 (tree exp) build (COMPOUND_EXPR, void_type_node, init_expr, end)); } + } } else @@ -2309,6 +2315,9 @@ build_new_1 (tree exp) rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval); } + if (init_preeval_expr) + rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_preeval_expr, rval); + /* Convert to the final type. */ rval = build_nop (pointer_type, rval); diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 1ade1a91f3f..044f2895c0c 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -317,7 +317,6 @@ static inline bool get_global_value_if_present (tree id, tree *decl) { tree global_value = namespace_binding (id, global_namespace); - if (global_value) *decl = global_value; return global_value != NULL; diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 2fd10599151..1be4d8afdcc 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -36,6 +36,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "hashtab.h" #include "debug.h" #include "tree-inline.h" +#include "flags.h" +#include "langhooks.h" +#include "diagnostic.h" +#include "tree-dump.h" +#include "tree-simple.h" /* Prototypes. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6fb8da5d158..fdc171e041f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3842,7 +3842,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p) || any_type_dependent_arguments_p (args))) { postfix_expression - = build_min_nt (CALL_EXPR, postfix_expression, args); + = build_min_nt (CALL_EXPR, postfix_expression, + args, NULL_TREE); break; } @@ -5473,14 +5474,14 @@ cp_parser_statement (cp_parser* parser, bool in_statement_expr_p) { tree statement; cp_token *token; - int statement_line_number; + location_t statement_locus; /* There is no statement yet. */ statement = NULL_TREE; /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); - /* Remember the line number of the first token in the statement. */ - statement_line_number = token->location.line; + /* Remember the location of the first token in the statement. */ + statement_locus = token->location; /* If this is a keyword, then that will often determine what kind of statement we have. */ if (token->type == CPP_KEYWORD) @@ -5556,7 +5557,10 @@ cp_parser_statement (cp_parser* parser, bool in_statement_expr_p) /* Set the line number for the statement. */ if (statement && STATEMENT_CODE_P (TREE_CODE (statement))) - STMT_LINENO (statement) = statement_line_number; + { + SET_EXPR_LOCUS (statement, NULL); + annotate_with_locus (statement, statement_locus); + } } /* Parse a labeled-statement. @@ -9867,10 +9871,8 @@ cp_parser_asm_definition (cp_parser* parser) /* Create the ASM_STMT. */ if (at_function_scope_p ()) { - asm_stmt = - finish_asm_stmt (volatile_p - ? ridpointers[(int) RID_VOLATILE] : NULL_TREE, - string, outputs, inputs, clobbers); + asm_stmt = finish_asm_stmt (volatile_p, string, outputs, + inputs, clobbers); /* If the extended syntax was not used, mark the ASM_STMT. */ if (!extended_p) ASM_INPUT_P (asm_stmt) = 1; @@ -11787,7 +11789,7 @@ cp_parser_class_specifier (cp_parser* parser) { cp_token *token; tree type; - tree attributes; + tree attributes = NULL_TREE; int has_trailing_semicolon; bool nested_name_specifier_p; unsigned saved_num_template_parameter_lists; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 96ee6875a56..043e3e467c2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -375,7 +375,9 @@ push_inline_template_parms_recursive (tree parmlist, int levels) tree decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm)); DECL_ARTIFICIAL (decl) = 1; - TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1; + TREE_CONSTANT (decl) = 1; + TREE_INVARIANT (decl) = 1; + TREE_READONLY (decl) = 1; DECL_INITIAL (decl) = DECL_INITIAL (parm); SET_DECL_TEMPLATE_PARM_P (decl); pushdecl (decl); @@ -2115,6 +2117,7 @@ build_template_parm_index (int index, TEMPLATE_PARM_DECL (t) = decl; TREE_TYPE (t) = type; TREE_CONSTANT (t) = TREE_CONSTANT (decl); + TREE_INVARIANT (t) = TREE_INVARIANT (decl); TREE_READONLY (t) = TREE_READONLY (decl); return t; @@ -2137,6 +2140,7 @@ reduce_template_parm_level (tree index, tree type, int levels) decl = build_decl (TREE_CODE (orig_decl), DECL_NAME (orig_decl), type); TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl); + TREE_INVARIANT (decl) = TREE_INVARIANT (orig_decl); TREE_READONLY (decl) = TREE_READONLY (orig_decl); DECL_ARTIFICIAL (decl) = 1; SET_DECL_TEMPLATE_PARM_P (decl); @@ -2200,11 +2204,15 @@ process_template_parm (tree list, tree next) TREE_TYPE (parm) = TYPE_MAIN_VARIANT (TREE_TYPE (parm)); /* A template parameter is not modifiable. */ - TREE_READONLY (parm) = TREE_CONSTANT (parm) = 1; + TREE_CONSTANT (parm) = 1; + TREE_INVARIANT (parm) = 1; + TREE_READONLY (parm) = 1; if (invalid_nontype_parm_type_p (TREE_TYPE (parm), 1)) TREE_TYPE (parm) = void_type_node; decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm)); - TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1; + TREE_CONSTANT (decl) = 1; + TREE_INVARIANT (decl) = 1; + TREE_READONLY (decl) = 1; DECL_INITIAL (parm) = DECL_INITIAL (decl) = build_template_parm_index (idx, processing_template_decl, processing_template_decl, @@ -4865,7 +4873,9 @@ push_tinst_level (tree d) return 0; } - new = build_expr_wfl (d, input_filename, input_line, 0); + new = make_node (TINST_LEVEL); + annotate_with_locus (new, input_location); + TINST_DECL (new) = d; TREE_CHAIN (new) = current_tinst_level; current_tinst_level = new; @@ -4889,8 +4899,7 @@ pop_tinst_level (void) /* Restore the filename and line number stashed away when we started this instantiation. */ - input_line = TINST_LINE (old); - input_filename = TINST_FILE (old); + input_location = *EXPR_LOCUS (old); extract_interface_info (); current_tinst_level = TREE_CHAIN (old); @@ -5648,7 +5657,7 @@ instantiate_class_template (tree type) that would be used for non-template classes. */ typedecl = TYPE_MAIN_DECL (type); input_location = DECL_SOURCE_LOCATION (typedecl); - + unreverse_member_declarations (type); finish_struct_1 (type); @@ -7971,15 +7980,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) break; case LABEL_STMT: - input_line = STMT_LINENO (t); + prep_stmt (t); finish_label_stmt (DECL_NAME (LABEL_STMT_LABEL (t))); break; - case FILE_STMT: - input_filename = FILE_STMT_FILENAME (t); - add_stmt (build_nt (FILE_STMT, FILE_STMT_FILENAME_NODE (t))); - break; - case GOTO_STMT: prep_stmt (t); tmp = GOTO_DESTINATION (t); @@ -7996,7 +8000,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case ASM_STMT: prep_stmt (t); tmp = finish_asm_stmt - (ASM_CV_QUAL (t), + (ASM_VOLATILE_P (t), tsubst_expr (ASM_STRING (t), args, complain, in_decl), tsubst_expr (ASM_OUTPUTS (t), args, complain, in_decl), tsubst_expr (ASM_INPUTS (t), args, complain, in_decl), @@ -11151,7 +11155,7 @@ instantiate_decl (tree d, int defer_ok) goto out; } - need_push = !global_bindings_p (); + need_push = !cfun || !global_bindings_p (); if (need_push) push_to_top_level (); @@ -11164,8 +11168,7 @@ instantiate_decl (tree d, int defer_ok) regenerate_decl_from_template (d, td); /* We already set the file and line above. Reset them now in case - they changed as a result of calling - regenerate_decl_from_template. */ + they changed as a result of calling regenerate_decl_from_template. */ input_location = DECL_SOURCE_LOCATION (d); if (TREE_CODE (d) == VAR_DECL) diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 9e7805651ce..ac149c8c91b 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -231,7 +231,7 @@ get_tinfo_decl_dynamic (tree exp) /* The RTTI information is at index -1. */ index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1); t = build_vtbl_ref (exp, index); - TREE_TYPE (t) = type_info_ptr_type; + t = convert (type_info_ptr_type, t); } else /* Otherwise return the type_info for the static type of the expr. */ @@ -797,7 +797,6 @@ tinfo_base_init (tree desc, tree target) size_binop (MULT_EXPR, size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE), TYPE_SIZE_UNIT (vtable_entry_type))); - TREE_CONSTANT (vtable_ptr) = 1; TINFO_VTABLE_DECL (desc) = vtable_ptr; } @@ -807,7 +806,9 @@ tinfo_base_init (tree desc, tree target) init = tree_cons (NULL_TREE, decay_conversion (name_decl), init); init = build_constructor (NULL_TREE, nreverse (init)); - TREE_CONSTANT (init) = TREE_STATIC (init) = 1; + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + TREE_STATIC (init) = 1; init = tree_cons (NULL_TREE, init, NULL_TREE); return init; @@ -823,7 +824,9 @@ generic_initializer (tree desc, tree target) tree init = tinfo_base_init (desc, target); init = build_constructor (NULL_TREE, init); - TREE_CONSTANT (init) = TREE_STATIC (init) = 1; + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + TREE_STATIC (init) = 1; return init; } @@ -850,7 +853,9 @@ ptr_initializer (tree desc, tree target, bool *non_public_ptr) init); init = build_constructor (NULL_TREE, nreverse (init)); - TREE_CONSTANT (init) = TREE_STATIC (init) = 1; + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + TREE_STATIC (init) = 1; return init; } @@ -887,7 +892,9 @@ ptm_initializer (tree desc, tree target, bool *non_public_ptr) init); init = build_constructor (NULL_TREE, nreverse (init)); - TREE_CONSTANT (init) = TREE_STATIC (init) = 1; + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + TREE_STATIC (init) = 1; return init; } @@ -955,7 +962,9 @@ class_initializer (tree desc, tree target, tree trail) TREE_CHAIN (init) = trail; init = build_constructor (NULL_TREE, init); - TREE_CONSTANT (init) = TREE_STATIC (init) = 1; + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + TREE_STATIC (init) = 1; return init; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6e15e611317..2fea1c8b86c 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -32,6 +32,7 @@ #include "tree.h" #include "cp-tree.h" #include "tree-inline.h" +#include "tree-mudflap.h" #include "except.h" #include "lex.h" #include "toplev.h" @@ -41,6 +42,7 @@ #include "output.h" #include "timevar.h" #include "debug.h" +#include "diagnostic.h" #include "cgraph.h" /* There routines provide a modular interface to perform many parsing @@ -55,10 +57,7 @@ static tree maybe_convert_cond (tree); static tree simplify_aggr_init_exprs_r (tree *, int *, void *); static void emit_associated_thunks (tree); -static void genrtl_try_block (tree); -static void genrtl_eh_spec_block (tree); -static void genrtl_handler (tree); -static void cp_expand_stmt (tree); +static tree finalize_nrv_r (tree *, int *, void *); /* Finish processing the COND, the SUBSTMT condition for STMT. */ @@ -788,56 +787,6 @@ finish_switch_stmt (tree switch_stmt) do_poplevel (); } -/* Generate the RTL for T, which is a TRY_BLOCK. */ - -static void -genrtl_try_block (tree t) -{ - if (CLEANUP_P (t)) - { - expand_eh_region_start (); - expand_stmt (TRY_STMTS (t)); - expand_eh_region_end_cleanup (TRY_HANDLERS (t)); - } - else - { - if (!FN_TRY_BLOCK_P (t)) - emit_line_note (input_location); - - expand_eh_region_start (); - expand_stmt (TRY_STMTS (t)); - - if (FN_TRY_BLOCK_P (t)) - { - expand_start_all_catch (); - in_function_try_handler = 1; - expand_stmt (TRY_HANDLERS (t)); - in_function_try_handler = 0; - expand_end_all_catch (); - } - else - { - expand_start_all_catch (); - expand_stmt (TRY_HANDLERS (t)); - expand_end_all_catch (); - } - } -} - -/* Generate the RTL for T, which is an EH_SPEC_BLOCK. */ - -static void -genrtl_eh_spec_block (tree t) -{ - expand_eh_region_start (); - expand_stmt (EH_SPEC_STMTS (t)); - expand_eh_region_end_allowed (EH_SPEC_RAISES (t), - build_call (call_unexpected_node, - tree_cons (NULL_TREE, - build_exc_ptr (), - NULL_TREE))); -} - /* Begin a try-block. Returns a newly-created TRY_BLOCK if appropriate. */ @@ -925,19 +874,6 @@ finish_function_handler_sequence (tree try_block) check_handlers (TRY_HANDLERS (try_block)); } -/* Generate the RTL for T, which is a HANDLER. */ - -static void -genrtl_handler (tree t) -{ - genrtl_do_pushlevel (); - if (!processing_template_decl) - expand_start_catch (HANDLER_TYPE (t)); - expand_stmt (HANDLER_BODY (t)); - if (!processing_template_decl) - expand_end_catch (); -} - /* Begin a handler. Returns a HANDLER if appropriate. */ tree @@ -1050,28 +986,17 @@ finish_compound_stmt (tree compound_stmt) return r; } -/* Finish an asm-statement, whose components are a CV_QUALIFIER, a - STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, and some - CLOBBERS. */ +/* Finish an asm-statement, whose components are a STRING, some + OUTPUT_OPERANDS, some INPUT_OPERANDS, and some CLOBBERS. Also note + whether the asm-statement should be considered volatile. */ tree -finish_asm_stmt (tree cv_qualifier, - tree string, - tree output_operands, - tree input_operands, - tree clobbers) +finish_asm_stmt (int volatile_p, tree string, tree output_operands, + tree input_operands, tree clobbers) { tree r; tree t; - if (cv_qualifier != NULL_TREE - && cv_qualifier != ridpointers[(int) RID_VOLATILE]) - { - warning ("%s qualifier ignored on asm", - IDENTIFIER_POINTER (cv_qualifier)); - cv_qualifier = NULL_TREE; - } - if (!processing_template_decl) { int i; @@ -1133,9 +1058,10 @@ finish_asm_stmt (tree cv_qualifier, } } - r = build_stmt (ASM_STMT, cv_qualifier, string, + r = build_stmt (ASM_STMT, string, output_operands, input_operands, clobbers); + ASM_VOLATILE_P (r) = volatile_p; return add_stmt (r); } @@ -1629,7 +1555,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p) if (type_dependent_expression_p (fn) || any_type_dependent_arguments_p (args)) { - result = build_nt (CALL_EXPR, fn, args); + result = build_nt (CALL_EXPR, fn, args, NULL_TREE); KOENIG_LOOKUP_P (result) = koenig_p; return result; } @@ -1704,7 +1630,7 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p) if (processing_template_decl) { if (type_dependent_expression_p (object)) - return build_nt (CALL_EXPR, orig_fn, orig_args); + return build_nt (CALL_EXPR, orig_fn, orig_args, NULL_TREE); object = build_non_dependent_expr (object); } @@ -1737,7 +1663,8 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p) if (processing_template_decl) { - result = build (CALL_EXPR, TREE_TYPE (result), orig_fn, orig_args); + result = build (CALL_EXPR, TREE_TYPE (result), orig_fn, + orig_args, NULL_TREE); KOENIG_LOOKUP_P (result) = koenig_p; } return result; @@ -2686,7 +2613,7 @@ finish_id_expression (tree id_expression, /* Resolve references to variables of anonymous unions into COMPONENT_REFs. */ if (TREE_CODE (decl) == ALIAS_DECL) - decl = DECL_INITIAL (decl); + decl = unshare_expr (DECL_INITIAL (decl)); } if (TREE_DEPRECATED (decl)) @@ -2722,37 +2649,8 @@ finish_typeof (tree expr) return type; } -/* Generate RTL for the statement T, and its substatements, and any - other statements at its nesting level. */ - -static void -cp_expand_stmt (tree t) -{ - switch (TREE_CODE (t)) - { - case TRY_BLOCK: - genrtl_try_block (t); - break; - - case EH_SPEC_BLOCK: - genrtl_eh_spec_block (t); - break; - - case HANDLER: - genrtl_handler (t); - break; - - case USING_STMT: - break; - - default: - abort (); - break; - } -} - /* Called from expand_body via walk_tree. Replace all AGGR_INIT_EXPRs - will equivalent CALL_EXPRs. */ + with equivalent CALL_EXPRs. */ static tree simplify_aggr_init_exprs_r (tree* tp, @@ -2905,7 +2803,7 @@ void expand_body (tree fn) { tree saved_function; - + /* Compute the appropriate object-file linkage for inline functions. */ if (DECL_DECLARED_INLINE_P (fn)) @@ -3013,37 +2911,94 @@ expand_or_defer_fn (tree fn) function_depth--; } -/* Helper function for walk_tree, used by finish_function to override all - the RETURN_STMTs and pertinent CLEANUP_STMTs for the named return - value optimization. */ +struct nrv_data +{ + tree var; + tree result; + htab_t visited; +}; -tree -nullify_returns_r (tree* tp, int* walk_subtrees, void* data) +/* Helper function for walk_tree, used by finalize_nrv below. */ + +static tree +finalize_nrv_r (tree* tp, int* walk_subtrees, void* data) { - tree nrv = (tree) data; + struct nrv_data *dp = (struct nrv_data *)data; + void **slot; /* No need to walk into types. There wouldn't be any need to walk into non-statements, except that we have to consider STMT_EXPRs. */ if (TYPE_P (*tp)) *walk_subtrees = 0; + /* Change all returns to just refer to the RESULT_DECL; this is a nop, + but differs from using NULL_TREE in that it indicates that we care + about the value of the RESULT_DECL. */ else if (TREE_CODE (*tp) == RETURN_STMT) - RETURN_STMT_EXPR (*tp) = NULL_TREE; + RETURN_STMT_EXPR (*tp) = dp->result; + /* Change all cleanups for the NRV to only run when an exception is + thrown. */ else if (TREE_CODE (*tp) == CLEANUP_STMT - && CLEANUP_DECL (*tp) == nrv) + && CLEANUP_DECL (*tp) == dp->var) CLEANUP_EH_ONLY (*tp) = 1; + /* Replace the DECL_STMT for the NRV with an initialization of the + RESULT_DECL, if needed. */ + else if (TREE_CODE (*tp) == DECL_STMT + && DECL_STMT_DECL (*tp) == dp->var) + { + tree init; + if (DECL_INITIAL (dp->var) + && DECL_INITIAL (dp->var) != error_mark_node) + { + init = build (INIT_EXPR, void_type_node, dp->result, + DECL_INITIAL (dp->var)); + DECL_INITIAL (dp->var) = error_mark_node; + } + else + init = NULL_TREE; + init = build_stmt (EXPR_STMT, init); + SET_EXPR_LOCUS (init, EXPR_LOCUS (*tp)); + TREE_CHAIN (init) = TREE_CHAIN (*tp); + *tp = init; + } + /* And replace all uses of the NRV with the RESULT_DECL. */ + else if (*tp == dp->var) + *tp = dp->result; + + /* Avoid walking into the same tree more than once. Unfortunately, we + can't just use walk_tree_without duplicates because it would only call + us for the first occurrence of dp->var in the function body. */ + slot = htab_find_slot (dp->visited, *tp, INSERT); + if (*slot) + *walk_subtrees = 0; + else + *slot = *tp; /* Keep iterating. */ return NULL_TREE; } -/* Start generating the RTL for FN. */ +/* Called from finish_function to implement the named return value + optimization by overriding all the RETURN_STMTs and pertinent + CLEANUP_STMTs and replacing all occurrences of VAR with RESULT, the + RESULT_DECL for the function. */ void -cxx_expand_function_start (void) +finalize_nrv (tree *tp, tree var, tree result) { - /* Give our named return value the same RTL as our RESULT_DECL. */ - if (current_function_return_value) - COPY_DECL_RTL (DECL_RESULT (cfun->decl), current_function_return_value); + struct nrv_data data; + + /* Copy debugging information from VAR to RESULT. */ + DECL_NAME (result) = DECL_NAME (var); + DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (var); + DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (var); + /* Don't forget that we take its address. */ + TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (var); + + data.var = var; + data.result = result; + data.visited = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); + walk_tree (tp, finalize_nrv_r, &data, 0); + htab_delete (data.visited); } /* Perform initialization related to this module. */ @@ -3051,7 +3006,6 @@ cxx_expand_function_start (void) void init_cp_semantics (void) { - lang_expand_stmt = cp_expand_stmt; } #include "gt-cp-semantics.h" diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8dd85eae80d..1e470eb862d 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1933,9 +1933,6 @@ tree make_ptrmem_cst (tree type, tree member) { tree ptrmem_cst = make_node (PTRMEM_CST); - /* If would seem a great convenience if make_node would set - TREE_CONSTANT for things of class `c', but it does not. */ - TREE_CONSTANT (ptrmem_cst) = 1; TREE_TYPE (ptrmem_cst) = type; PTRMEM_CST_MEMBER (ptrmem_cst) = member; return ptrmem_cst; @@ -1969,19 +1966,26 @@ cp_walk_subtrees (tree* tp, void* htab) { enum tree_code code = TREE_CODE (*tp); + location_t save_locus; tree result; #define WALK_SUBTREE(NODE) \ do \ { \ result = walk_tree (&(NODE), func, data, htab); \ - if (result) \ - return result; \ + if (result) goto out; \ } \ while (0) + /* Set input_location here so we get the right instantiation context + if we call instantiate_decl from inlinable_function_p. */ + save_locus = input_location; + if (EXPR_LOCUS (*tp)) + input_location = *EXPR_LOCUS (*tp); + /* Not one of the easy cases. We must explicitly go through the children. */ + result = NULL_TREE; switch (code) { case DEFAULT_ARG: @@ -2019,11 +2023,14 @@ cp_walk_subtrees (tree* tp, break; default: - break; + input_location = save_locus; + return c_walk_subtrees (tp, walk_subtrees_p, func, data, htab); } /* We didn't find what we were looking for. */ - return NULL_TREE; + out: + input_location = save_locus; + return result; #undef WALK_SUBTREE } @@ -2132,11 +2139,10 @@ tree cp_copy_res_decl_for_inlining (tree result, tree fn, tree caller, - void* decl_map_, + void* decl_map_ ATTRIBUTE_UNUSED, int* need_decl, tree return_slot_addr) { - splay_tree decl_map = (splay_tree)decl_map_; tree var; /* If FN returns an aggregate then the caller will always pass the @@ -2147,7 +2153,7 @@ cp_copy_res_decl_for_inlining (tree result, references to the RESULT into references to the target. */ /* We should have an explicit return slot iff the return type is - TREE_ADDRESSABLE. See simplify_aggr_init_expr. */ + TREE_ADDRESSABLE. See gimplify_aggr_init_expr. */ if (TREE_ADDRESSABLE (TREE_TYPE (result)) != (return_slot_addr != NULL_TREE)) abort (); @@ -2164,34 +2170,6 @@ cp_copy_res_decl_for_inlining (tree result, else var = copy_decl_for_inlining (result, fn, caller); - if (DECL_SAVED_FUNCTION_DATA (fn)) - { - tree nrv = DECL_SAVED_FUNCTION_DATA (fn)->x_return_value; - if (nrv) - { - /* We have a named return value; copy the name and source - position so we can get reasonable debugging information, and - register the return variable as its equivalent. */ - if (TREE_CODE (var) == VAR_DECL - /* But not if we're initializing a variable from the - enclosing function which already has its own name. */ - && DECL_NAME (var) == NULL_TREE) - { - DECL_NAME (var) = DECL_NAME (nrv); - DECL_SOURCE_LOCATION (var) = DECL_SOURCE_LOCATION (nrv); - DECL_ABSTRACT_ORIGIN (var) = DECL_ORIGIN (nrv); - /* Don't lose initialization info. */ - DECL_INITIAL (var) = DECL_INITIAL (nrv); - /* Don't forget that it needs to go in the stack. */ - TREE_ADDRESSABLE (var) = TREE_ADDRESSABLE (nrv); - } - - splay_tree_insert (decl_map, - (splay_tree_key) nrv, - (splay_tree_value) var); - } - } - return var; } @@ -2214,6 +2192,7 @@ cp_update_decl_after_saving (tree fn, void init_tree (void) { + lang_gimplify_stmt = cp_gimplify_stmt; list_hash_table = htab_create_ggc (31, list_hash, list_hash_eq, NULL); } @@ -2431,7 +2410,7 @@ stabilize_expr (tree exp, tree* initp) if (!TREE_SIDE_EFFECTS (exp)) { - init_expr = void_zero_node; + init_expr = NULL_TREE; } else if (!real_lvalue_p (exp) || !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp))) @@ -2450,6 +2429,80 @@ stabilize_expr (tree exp, tree* initp) *initp = init_expr; return exp; } + +/* Like stabilize_expr, but for a call whose args we want to + pre-evaluate. */ + +void +stabilize_call (tree call, tree *initp) +{ + tree inits = NULL_TREE; + tree t; + + if (call == error_mark_node) + return; + + if (TREE_CODE (call) != CALL_EXPR + && TREE_CODE (call) != AGGR_INIT_EXPR) + abort (); + + for (t = TREE_OPERAND (call, 1); t; t = TREE_CHAIN (t)) + if (TREE_SIDE_EFFECTS (TREE_VALUE (t))) + { + tree init; + TREE_VALUE (t) = stabilize_expr (TREE_VALUE (t), &init); + if (!init) + /* Nothing. */; + else if (inits) + inits = build (COMPOUND_EXPR, void_type_node, inits, init); + else + inits = init; + } + + *initp = inits; +} + +/* Like stabilize_expr, but for an initialization. If we are initializing + an object of class type, we don't want to introduce an extra temporary, + so we look past the TARGET_EXPR and stabilize the arguments of the call + instead. */ + +bool +stabilize_init (tree init, tree *initp) +{ + tree t = init; + + if (t == error_mark_node) + return true; + + if (TREE_CODE (t) == INIT_EXPR + && TREE_CODE (TREE_OPERAND (t, 1)) != TARGET_EXPR) + TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp); + else + { + if (TREE_CODE (t) == INIT_EXPR) + t = TREE_OPERAND (t, 1); + if (TREE_CODE (t) == TARGET_EXPR) + t = TARGET_EXPR_INITIAL (t); + if (TREE_CODE (t) == CONSTRUCTOR + && CONSTRUCTOR_ELTS (t) == NULL_TREE) + { + /* Default-initialization. */ + *initp = NULL_TREE; + return true; + } + + /* If the initializer is a COND_EXPR, we can't preevaluate + anything. */ + if (TREE_CODE (t) == COND_EXPR) + return false; + + stabilize_call (t, initp); + } + + return true; +} + #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007) /* Complain that some language-specific thing hanging off a tree diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index dedf4956b7e..2bfd743e090 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1379,7 +1379,6 @@ decay_conversion (tree exp) if (!cxx_mark_addressable (exp)) return error_mark_node; adr = build_nop (ptrtype, build_address (exp)); - TREE_SIDE_EFFECTS (adr) = 0; /* Default would be, same as EXP. */ return adr; } /* This way is better for a COMPONENT_REF since it can @@ -2160,8 +2159,7 @@ build_array_ref (tree array, tree idx) break; } - if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE - && TREE_CODE (array) != INDIRECT_REF) + if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE) { tree rval, type; @@ -2363,6 +2361,7 @@ get_member_function_from_ptrfunc (tree *instance_ptrptr, tree function) e2 = fold (build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, idx)); e2 = build_indirect_ref (e2, NULL); TREE_CONSTANT (e2) = 1; + TREE_INVARIANT (e2) = 1; /* When using function descriptors, the address of the vtable entry is treated as a function pointer. */ @@ -3436,15 +3435,10 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, build_type = result_type; { - tree result = build (resultcode, build_type, op0, op1); - tree folded; - - folded = fold (result); - if (folded == result) - TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); + tree result = fold (build (resultcode, build_type, op0, op1)); if (final_type != 0) - return cp_convert (final_type, folded); - return folded; + result = cp_convert (final_type, result); + return result; } } @@ -3472,7 +3466,7 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop) static tree pointer_diff (tree op0, tree op1, tree ptrtype) { - tree result, folded; + tree result; tree restype = ptrdiff_type_node; tree target_type = TREE_TYPE (ptrtype); @@ -3507,11 +3501,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype) /* Do the division. */ result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1)); - - folded = fold (result); - if (folded == result) - TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); - return folded; + return fold (result); } /* Construct and perhaps optimize a tree representation @@ -3634,8 +3624,6 @@ build_address (tree t) return error_mark_node; addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (t)), t); - if (staticp (t)) - TREE_CONSTANT (addr) = 1; return addr; } @@ -3645,16 +3633,9 @@ build_address (tree t) tree build_nop (tree type, tree expr) { - tree nop; - if (type == error_mark_node || error_operand_p (expr)) return expr; - - nop = build1 (NOP_EXPR, type, expr); - if (TREE_CONSTANT (expr)) - TREE_CONSTANT (nop) = 1; - - return nop; + return build1 (NOP_EXPR, type, expr); } /* C++: Must handle pointers to members. @@ -3690,9 +3671,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) else { if (!noconvert) - arg = default_conversion (arg); + arg = default_conversion (arg); arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg); - TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0)); } break; @@ -3874,7 +3854,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value); /* Eliminate warning about unused result of + or -. */ - TREE_NO_UNUSED_WARNING (compound) = 1; + TREE_NO_WARNING (compound) = 1; return compound; } @@ -3916,10 +3896,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) if (TREE_CODE (argtype) == REFERENCE_TYPE) { - arg = build1 - (CONVERT_EXPR, - build_pointer_type (TREE_TYPE (argtype)), arg); - TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0)); + tree type = build_pointer_type (TREE_TYPE (argtype)); + arg = build1 (CONVERT_EXPR, type, arg); return arg; } else if (pedantic && DECL_MAIN_P (arg)) @@ -3937,10 +3915,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) arg = TREE_OPERAND (arg, 0); if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE) { - arg = build1 - (CONVERT_EXPR, - build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg); - TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0)); + tree type = build_pointer_type (TREE_TYPE (TREE_TYPE (arg))); + arg = build1 (CONVERT_EXPR, type, arg); } else if (lvalue_p (arg)) /* Don't let this be an lvalue. */ @@ -4170,7 +4146,7 @@ unary_complex_lvalue (enum tree_code code, tree arg) { tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0); arg = build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result); - TREE_NO_UNUSED_WARNING (arg) = 1; + TREE_NO_WARNING (arg) = 1; return arg; } @@ -5035,7 +5011,9 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) return cond; /* Make sure the code to compute the rhs comes out before the split. */ - return build (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond); + if (preeval) + cond = build (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond); + return cond; } default: @@ -5236,7 +5214,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) if (olhs) { result = build (COMPOUND_EXPR, olhstype, result, olhs); - TREE_NO_UNUSED_WARNING (result) = 1; + TREE_NO_WARNING (result) = 1; return result; } return convert_for_assignment (olhstype, result, "assignment", @@ -5348,7 +5326,8 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn) u = tree_cons (pfn_field, pfn, build_tree_list (delta_field, delta)); u = build_constructor (type, u); - TREE_CONSTANT (u) = TREE_CONSTANT (pfn) && TREE_CONSTANT (delta); + TREE_CONSTANT (u) = TREE_CONSTANT (pfn) & TREE_CONSTANT (delta); + TREE_INVARIANT (u) = TREE_INVARIANT (pfn) & TREE_INVARIANT (delta); TREE_STATIC (u) = (TREE_CONSTANT (u) && (initializer_constant_valid_p (pfn, TREE_TYPE (pfn)) != NULL_TREE) @@ -5998,9 +5977,7 @@ check_return_expr (tree retval) returned expression uses the chosen variable somehow. And people expect this restriction, anyway. (jason 2000-11-19) - See finish_function, cxx_expand_function_start, and - cp_copy_res_decl_for_inlining for other pieces of this - optimization. */ + See finish_function and finalize_nrv for the rest of this optimization. */ if (fn_returns_value_p && flag_elide_constructors) { diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index b49d4201c50..2c6b843a7f0 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -997,8 +997,13 @@ process_init_constructor (tree type, tree init, tree* elts) complete_array_type (type, result, /*do_default=*/0); if (init) TREE_HAS_CONSTRUCTOR (result) = TREE_HAS_CONSTRUCTOR (init); - if (allconstant) TREE_CONSTANT (result) = 1; - if (allconstant && allsimple) TREE_STATIC (result) = 1; + if (allconstant) + { + TREE_CONSTANT (result) = 1; + TREE_INVARIANT (result) = 1; + if (allsimple) + TREE_STATIC (result) = 1; + } return result; } diff --git a/gcc/cppexp.c b/gcc/cppexp.c index 6b47dd7b06c..22d34b69416 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -408,6 +408,7 @@ append_digit (cpp_num num, int digit, int base, size_t precision) result.high = num.high << shift; result.low = num.low << shift; result.high |= num.low >> (PART_PRECISION - shift); + result.unsignedp = num.unsignedp; if (base == 10) { @@ -428,6 +429,7 @@ append_digit (cpp_num num, int digit, int base, size_t precision) result.low += add_low; result.high += add_high; + result.overflow = overflow; /* The above code catches overflow of a cpp_num type. This catches overflow of the (possibly shorter) target precision. */ @@ -435,10 +437,8 @@ append_digit (cpp_num num, int digit, int base, size_t precision) num.high = result.high; result = num_trim (result, precision); if (!num_eq (result, num)) - overflow = true; + result.overflow = true; - result.unsignedp = num.unsignedp; - result.overflow = overflow; return result; } @@ -520,6 +520,9 @@ eval_token (cpp_reader *pfile, const cpp_token *token) unsigned int temp; int unsignedp = 0; + result.unsignedp = false; + result.overflow = false; + switch (token->type) { case CPP_NUMBER: @@ -591,7 +594,6 @@ eval_token (cpp_reader *pfile, const cpp_token *token) } result.unsignedp = !!unsignedp; - result.overflow = false; return result; } @@ -1166,8 +1168,9 @@ static cpp_num num_rshift (cpp_num num, size_t precision, size_t n) { cpp_num_part sign_mask; + bool x = num_positive (num, precision); - if (num.unsignedp || num_positive (num, precision)) + if (num.unsignedp || x) sign_mask = 0; else sign_mask = ~(cpp_num_part) 0; @@ -1332,12 +1335,11 @@ num_binary_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) result.high = lhs.high + rhs.high; if (result.low < lhs.low) result.high++; + result.unsignedp = lhs.unsignedp || rhs.unsignedp; + result.overflow = false; result = num_trim (result, precision); - result.unsignedp = lhs.unsignedp || rhs.unsignedp; - if (result.unsignedp) - result.overflow = false; - else + if (!result.unsignedp) { bool lhsp = num_positive (lhs, precision); result.overflow = (lhsp == num_positive (rhs, precision) @@ -1384,7 +1386,8 @@ num_part_mul (cpp_num_part lhs, cpp_num_part rhs) result.high += HIGH_PART (middle[0]); result.high += HIGH_PART (middle[1]); - result.unsignedp = 1; + result.unsignedp = true; + result.overflow = false; return result; } @@ -1516,9 +1519,8 @@ num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num rhs, enum cpp_ttype op) if (op == CPP_DIV) { result.unsignedp = unsignedp; - if (unsignedp) - result.overflow = false; - else + result.overflow = false; + if (!unsignedp) { if (negate) result = num_negate (result, precision); diff --git a/gcc/cse.c b/gcc/cse.c index e155db98fea..6d3c53f7635 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -593,7 +593,7 @@ struct cse_basic_block_data /* Whether it should be taken or not. AROUND is the same as taken except that it is used when the destination label is not preceded by a BARRIER. */ - enum taken {TAKEN, NOT_TAKEN, AROUND} status; + enum taken {PATH_TAKEN, PATH_NOT_TAKEN, PATH_AROUND} status; } *path; }; @@ -4153,17 +4153,6 @@ fold_rtx (rtx x, rtx insn) const_arg2 ? const_arg2 : XEXP (x, 2)); break; - case RTX_EXTRA: - /* Eliminate CONSTANT_P_RTX if its constant. */ - if (code == CONSTANT_P_RTX) - { - if (const_arg0) - return const1_rtx; - if (optimize == 0 || !flag_gcse) - return const0_rtx; - } - break; - default: break; } @@ -4256,7 +4245,7 @@ gen_lowpart_if_possible (enum machine_mode mode, rtx x) return 0; } -/* Given INSN, a jump insn, TAKEN indicates if we are following the "taken" +/* Given INSN, a jump insn, PATH_TAKEN indicates if we are following the "taken" branch. It will be zero if not. In certain cases, this can cause us to add an equivalence. For example, @@ -5644,8 +5633,6 @@ cse_insn (rtx insn, rtx libcall_insn) else INSN_CODE (insn) = -1; - never_reached_warning (insn, NULL); - /* Do not bother deleting any unreachable code, let jump/flow do that. */ @@ -6673,14 +6660,15 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data, int i; /* Update the previous branch path, if any. If the last branch was - previously TAKEN, mark it NOT_TAKEN. If it was previously NOT_TAKEN, + previously PATH_TAKEN, mark it PATH_NOT_TAKEN. + If it was previously PATH_NOT_TAKEN, shorten the path by one and look at the previous branch. We know that at least one branch must have been taken if PATH_SIZE is nonzero. */ while (path_size > 0) { - if (data->path[path_size - 1].status != NOT_TAKEN) + if (data->path[path_size - 1].status != PATH_NOT_TAKEN) { - data->path[path_size - 1].status = NOT_TAKEN; + data->path[path_size - 1].status = PATH_NOT_TAKEN; break; } else @@ -6742,7 +6730,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data, take it, do so. */ if (path_entry < path_size && data->path[path_entry].branch == p) { - if (data->path[path_entry].status != NOT_TAKEN) + if (data->path[path_entry].status != PATH_NOT_TAKEN) p = JUMP_LABEL (p); /* Point to next entry in path, if any. */ @@ -6796,7 +6784,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data, break; data->path[path_entry].branch = p; - data->path[path_entry++].status = TAKEN; + data->path[path_entry++].status = PATH_TAKEN; /* This branch now ends our path. It was possible that we didn't see this branch the last time around (when the @@ -6835,7 +6823,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data, if (tmp == q) { data->path[path_entry].branch = p; - data->path[path_entry++].status = AROUND; + data->path[path_entry++].status = PATH_AROUND; path_size = path_entry; @@ -6856,7 +6844,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data, /* If all jumps in the path are not taken, set our path length to zero so a rescan won't be done. */ for (i = path_size - 1; i >= 0; i--) - if (data->path[i].status != NOT_TAKEN) + if (data->path[i].status != PATH_NOT_TAKEN) break; if (i == -1) @@ -7072,9 +7060,9 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch, if (next_branch->branch == insn) { enum taken status = next_branch++->status; - if (status != NOT_TAKEN) + if (status != PATH_NOT_TAKEN) { - if (status == TAKEN) + if (status == PATH_TAKEN) record_jump_equiv (insn, 1); else invalidate_skipped_block (NEXT_INSN (insn)); diff --git a/gcc/dbxout.c b/gcc/dbxout.c index a93946d2ec7..9e3ffb4ea8b 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -2560,8 +2560,7 @@ dbxout_symbol_location (tree decl, tree type, const char *suffix, rtx home) 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 it's not a parameter, ignore it. */ { if (GET_CODE (XEXP (home, 0)) == REG) { diff --git a/gcc/defaults.h b/gcc/defaults.h index b2384090849..220559798c0 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -743,6 +743,11 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE! #define CASE_VECTOR_PC_RELATIVE 0 #endif +/* Assume that trampolines need function alignment. */ +#ifndef TRAMPOLINE_ALIGNMENT +#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY +#endif + /* Register mappings for target machines without register windows. */ #ifndef INCOMING_REGNO #define INCOMING_REGNO(N) (N) diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index daf24279d5e..782f5028025 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -182,4 +182,16 @@ extern char *diagnostic_build_prefix (diagnostic_info *); extern void verbatim (const char *, ...); extern char *file_name_as_prefix (const char *); +extern void debug_output_buffer (pretty_printer *); + +/* In tree-pretty-print.c */ +extern int dump_generic_node (pretty_printer *, tree, int, int, bool); +extern void print_generic_stmt (FILE *, tree, int); +extern void print_generic_stmt_indented (FILE *, tree, int, int); +extern void print_generic_expr (FILE *, tree, int); +extern void print_generic_decl (FILE *, tree, int); + +extern void debug_generic_expr (tree); +extern void debug_generic_stmt (tree); +extern void debug_c_tree (tree); #endif /* ! GCC_DIAGNOSTIC_H */ diff --git a/gcc/doc/c-tree.texi b/gcc/doc/c-tree.texi index 8cd059e3e5c..d99c568380d 100644 --- a/gcc/doc/c-tree.texi +++ b/gcc/doc/c-tree.texi @@ -438,7 +438,7 @@ suppose that there were a 24-bit integer type, but that alignment requirements for the ABI required 32-bit alignment. Then, @code{TYPE_SIZE} would be an @code{INTEGER_CST} for 32, while @code{TYPE_PRECISION} would be 24.) The integer type is unsigned if -@code{TREE_UNSIGNED} holds; otherwise, it is signed. +@code{TYPE_UNSIGNED} holds; otherwise, it is signed. The @code{TYPE_MIN_VALUE} is an @code{INTEGER_CST} for the smallest integer that may be represented by this type. Similarly, the @@ -457,7 +457,7 @@ Used to represent GCC built-in @code{__complex__} data types. The @item ENUMERAL_TYPE Used to represent an enumeration type. The @code{TYPE_PRECISION} gives (as an @code{int}), the number of bits used to represent the type. If -there are no negative enumeration constants, @code{TREE_UNSIGNED} will +there are no negative enumeration constants, @code{TYPE_UNSIGNED} will hold. The minimum and maximum enumeration constants may be obtained with @code{TYPE_MIN_VALUE} and @code{TYPE_MAX_VALUE}, respectively; each of these macros returns an @code{INTEGER_CST}. @@ -856,13 +856,13 @@ entity. @item TREE_TYPE This macro returns the type of the entity declared. -@item DECL_SOURCE_FILE +@item TREE_FILENAME This macro returns the name of the file in which the entity was declared, as a @code{char*}. For an entity declared implicitly by the compiler (like @code{__builtin_memcpy}), this will be the string @code{""}. -@item DECL_SOURCE_LINE +@item TREE_LINENO This macro returns the line number at which the entity was declared, as an @code{int}. @@ -1298,8 +1298,6 @@ This predicate holds if the function an overloaded @findex FOR_COND @findex FOR_EXPR @findex FOR_BODY -@tindex FILE_STMT -@findex FILE_STMT_FILENAME @tindex GOTO_STMT @findex GOTO_DESTINATION @findex GOTO_FAKE_P @@ -1343,24 +1341,13 @@ the outermost block of the function, but it may also be a @subsubsection Statements -There are tree nodes corresponding to all of the source-level statement -constructs. These are enumerated here, together with a list of the -various macros that can be used to obtain information about them. There -are a few macros that can be used with all statements: +There are tree nodes corresponding to all of the source-level +statement constructs, used within the C and C++ frontends. These are +enumerated here, together with a list of the various macros that can +be used to obtain information about them. There are a few macros that +can be used with all statements: @ftable @code -@item STMT_LINENO -This macro returns the line number for the statement. If the statement -spans multiple lines, this value will be the number of the first line on -which the statement occurs. Although we mention @code{CASE_LABEL} below -as if it were a statement, they do not allow the use of -@code{STMT_LINENO}. There is no way to obtain the line number for a -@code{CASE_LABEL}. - -Statements do not contain information about -the file from which they came; that information is implicit in the -@code{FUNCTION_DECL} from which the statements originate. - @item STMT_IS_FULL_EXPR_P In C++, statements normally constitute ``full expressions''; temporaries created during a statement are destroyed when the statement is complete. @@ -1523,11 +1510,6 @@ address is never taken. (All such objects are interchangeable.) The Used to represent an expression statement. Use @code{EXPR_STMT_EXPR} to obtain the expression. -@item FILE_STMT - -Used to record a change in filename within the body of a function. -Use @code{FILE_STMT_FILENAME} to obtain the new filename. - @item FOR_STMT Used to represent a @code{for} statement. The @code{FOR_INIT_STMT} is @@ -2213,9 +2195,9 @@ the @code{STMT_EXPR} does not yield a value, it's type will be @item BIND_EXPR These nodes represent local blocks. The first operand is a list of -temporary variables, connected via their @code{TREE_CHAIN} field. These -will never require cleanups. The scope of these variables is just the -body of the @code{BIND_EXPR}. The body of the @code{BIND_EXPR} is the +variables, connected via their @code{TREE_CHAIN} field. These will +never require cleanups. The scope of these variables is just the body +of the @code{BIND_EXPR}. The body of the @code{BIND_EXPR} is the second operand. @item LOOP_EXPR diff --git a/gcc/doc/cfg.texi b/gcc/doc/cfg.texi new file mode 100644 index 00000000000..58a890cc262 --- /dev/null +++ b/gcc/doc/cfg.texi @@ -0,0 +1,614 @@ +@c -*-texinfo-*- +@c Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. +@c This is part of the GCC manual. +@c For copying conditions, see the file gcc.texi. + +@c --------------------------------------------------------------------- +@c Control Flow Graph +@c --------------------------------------------------------------------- + +@node Control Flow +@chapter Control Flow Graph +@cindex CFG, Control Flow Graph +@findex basic-block.h + +A control flow graph (CFG) is a data structure built on top of the +intermediate code representation (the RTL or @code{tree} instruction +stream) abstracting the control flow behavior of a function that is +being compiled. The CFG is a directed graph where the vertices +represent basic blocks and edges represent possible transfer of +control flow from one basic block to another. The data structures +used to represent the control flow graph are defined in +@file{basic-block.h}. + +@menu +* Basic Blocks:: The definition and representation of basic blocks. +* Edges:: Types of edges and their representation. +* Profile information:: Representation of frequencies and probabilities. +* Maintaining the CFG:: Keeping the control flow graph and up to date. +* Liveness information:: Using and maintaining liveness information. +@end menu + + +@node Basic Blocks +@section Basic Blocks + +@cindex basic block +@findex basic_block +A basic block is a straight-line sequence of code with only one entry +point and only one exit. In GCC, basic blocks are represented using +the @code{basic_block} data type. + +@findex next_bb, prev_bb, FOR_EACH_BB +Two pointer members of the @code{basic_block} structure are the +pointers @code{next_bb} and @code{prev_bb}. These are used to keep +doubly linked chain of basic blocks in the same order as the +underlying instruction stream. The chain of basic blocks is updated +transparently by the provided API for manipulating the CFG. The macro +@code{FOR_EACH_BB} can be used to visit all the basic blocks in +lexicographical order. Dominator traversals are also possible using +@code{walk_dominator_tree}. + +@findex BASIC_BLOCK +The @code{BASIC_BLOCK} array contains all basic blocks in an +unspecified order. Each @code{basic_block} structure has a field +that holds a unique integer identifier @code{index} that is the +index of the block in the @code{BASIC_BLOCK} array. +The total number of basic blocks in the function is +@code{n_basic_blocks}. Both the basic block indices and +the total number of basic blocks may vary during the compilation +process, as passes reorder, create, duplicate, and destroy basic +blocks. The index for any block should never be greater than +@code{last_basic_block}. + +@findex ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR +Special basic blocks represent possible entry and exit points of a +function. These blocks are called @code{ENTRY_BLOCK_PTR} and +@code{EXIT_BLOCK_PTR}. These blocks do not contain any code, and are +not elements of the @code{BASIC_BLOCK} array. Therefore they have +been assigned unique, negative index numbers. + +Each @code{basic_block} also contains pointers to the first +instruction (the @dfn{head}) and the last instruction (the @dfn{tail}) +or @dfn{end} of the instruction stream contained in a basic block. In +fact, since the @code{basic_block} data type is used to represent +blocks in both major intermediate representations of GCC (@code{tree} +and RTL), there are pointers to the head and end of a basic block for +both representations. + +@findex NOTE_INSN_BASIC_BLOCK, CODE_LABEL, notes +For RTL, these pointers are @code{rtx head, end}. In the RTL function +representation, the head pointer always points either to a +@code{NOTE_INSN_BASIC_BLOCK} or to a @code{CODE_LABEL}, if present. +In the RTL representation of a function, the instruction stream +contains not only the ``real'' instructions, but also @dfn{notes}. +Any function that moves or duplicates the basic blocks needs +to take care of updating of these notes. Many of these notes expect +that the instruction stream consists of linear regions, making such +updates difficult. The @code{NOTE_INSN_BASIC_BLOCK} note is the only +kind of note that may appear in the instruction stream contained in a +basic block. The instruction stream of a basic block always follows a +@code{NOTE_INSN_BASIC_BLOCK}, but zero or more @code{CODE_LABEL} +nodes can precede the block note. A basic block ends by control flow +instruction or last instruction before following @code{CODE_LABEL} or +@code{NOTE_INSN_BASIC_BLOCK}. A @code{CODE_LABEL} cannot appear in +the instruction stream of a basic block. + +@findex can_fallthru +@cindex table jump +In addition to notes, the jump table vectors are also represented as +``pseudo-instructions'' inside the insn stream. These vectors never +appear in the basic block and should always be placed just after the +table jump instructions referencing them. After removing the +table-jump it is often difficult to eliminate the code computing the +address and referencing the vector, so cleaning up these vectors is +postponed until after liveness analysis. Thus the jump table vectors +may appear in the insn stream unreferenced and without any purpose. +Before any edge is made @dfn{fall-thru}, the existence of such +construct in the way needs to be checked by calling +@code{can_fallthru} function. + +@cindex block statement iterators +For the @code{tree} representation, the head and end of the basic block +are being pointed to by the @code{stmt_list} field, but this special +@code{tree} should never be referenced directly. Instead, at the tree +level abstract containers and iterators are used to access statements +and expressions in basic blocks. These iterators are called +@dfn{block statement iterators} (BSIs). Grep for @code{^bsi} +in the various @file{tree-*} files. +The following snippet will pretty-print all the statements of the +program in the GIMPLE representation. + +@example +FOR_EACH_BB (bb) + @{ + block_stmt_iterator si; + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + @{ + tree stmt = bsi_stmt (si); + print_generic_stmt (stderr, stmt, 0); + @} + @} +@end example + + +@node Edges +@section Edges + +@cindex edge in the flow graph +@findex edge +Edges represent possible control flow transfers from the end of some +basic block A to the head of another basic block B. We say that A is +a predecessor of B, and B is a successor of A. Edges are represented +in GCC with the @code{edge} data type. Each @code{edge} acts as a +link between two basic blocks: the @code{src} member of an edge +points to the predecessor basic block of the @code{dest} basic block. +The members @code{pred} and @code{succ} of the @code{basic_block} data +type point to single linked lists of edges to the predecessors and +successorts of the block. The edges are linked via the +@code{succ_next} and @code{pred_next} members of the @code{edge} data +type. + +@findex fall-thru +There are various reasons why control flow may transfer from one block +to another. One possibility is that some instruction, for example a +@code{CODE_LABEL}, in a linearized instruction stream just always +starts a new basic block. In this case a @dfn{fall-thru} edge links +the basic block to the first following basic block. But there are +several other reasons why edges may be created. The @code{flags} +field of the @code{edge} data type is used to store information +about the type of edge we are dealing with. Each edge is of one of +the following types: + +@table @emph +@item jump +No type flags are set for edges corresponding to jump instructions. +These edges are used for unconditional or conditional jumps and in +RTL also for table jumps. They are the easiest to manipulate as they +may be freely redirected when the flow graph is not in SSA form. + +@item fall-thru +@findex EDGE_FALLTHRU, force_nonfallthru +Fall-thru edges are present in case where the basic block may continue +execution to the following one without branching. These edges have +the @code{EDGE_FALLTHRU} flag set. Unlike other types of edges, these +edges must come into the basic block immediately following in the +instruction stream. The function @code{force_nonfallthru} is +available to insert an unconditional jump in the case that redirection +is needed. Note that this may require creation of a new basic block. + +@item exception handling +@cindex exception handling +@findex EDGE_ABNORMAL, EDGE_EH +Exception handling edges represent possible control transfers from a +trapping instruction to an exception handler. The definition of +``trapping'' varies. In C++, only function calls can throw, but for +Java, exceptions like division by zero or segmentation fault are +defined and thus each instruction possibly throwing this kind of +exception needs to be handled as control flow instruction. Exception +edges have the @code{EDGE_ABNORMAL} and @code{EDGE_EH} flags set. + +@findex purge_dead_edges +When updating the instruction stream it is easy to change possibly +trapping instruction to non-trapping, by simply removing the exception +edge. The opposite conversion is difficult, but should not happen +anyway. The edges can be eliminated via @code{purge_dead_edges} call. + +@findex REG_EH_REGION, EDGE_ABNORMAL_CALL +In the RTL representation, the destination of an exception edge is +specified by @code{REG_EH_REGION} note attached to the insn. +In case of a trapping call the @code{EDGE_ABNORMAL_CALL} flag is set +too. In the @code{tree} representation, this extra flag is not set. + +@findex may_trap_p, tree_could_trap_p +In the RTL representation, the predicate @code{may_trap_p} may be used +to check whether instruction still may trap or not. For the tree +representation, the @code{tree_could_trap_p} predicate is available, +but this predicate only checks for possible memory traps, as in +dereferencing an invalid pointer location. + + +@item sibling calls +@cindex sibling call +@findex EDGE_ABNORMAL, EDGE_SIBCALL +Sibling calls or tail calls terminate the function in a non-standard +way and thus an edge to the exit must be present. +@code{EDGE_SIBCALL} and @code{EDGE_ABNORMAL} are set in such case. +These edges only exist in the RTL representation. + +@item computed jumps +@cindex computed jump +@findex EDGE_ABNORMAL +Computed jumps contain edges to all labels in the function referenced +from the code. All those edges have @code{EDGE_ABNORMAL} flag set. +The edges used to represent computed jumps often cause compile time +performance problems, since functions consisting of many taken labels +and many computed jumps may have @emph{very} dense flow graphs, so +these edges need to be handled with special care. During the earlier +stages of the compilation process, GCC tries to avoid such dense flow +graphs by factoring computed jumps. For example, given the following +series of jumps, + +@example + goto *x; + [ ... ] + + goto *x; + [ ... ] + + goto *x; + [ ... ] +@end example + +@noindent +factoring the computed jumps results in the following code sequence +which has a much simpler flow graph: + +@example + goto y; + [ ... ] + + goto y; + [ ... ] + + goto y; + [ ... ] + +y: + goto *x; +@end example + +However, the classic problem with this transformation is that it has a +runtime cost in there resulting code: An extra jump. Therefore, the +computed jumps are un-factored in the later passes of the compiler. +Be aware of that when you work on passes in that area. There have +been numerous examples already where the compile time for code with +unfactored computed jumps caused some serious headaches. + +@item nonlocal goto handlers +@cindex nonlocal goto handler +@findex EDGE_ABNORMAL, EDGE_ABNORMAL_CALL +GCC allows nested functions to return into caller using a @code{goto} +to a label passed to as an argument to the callee. The labels passed +to nested functions contain special code to cleanup after function +call. Such sections of code are referred to as ``nonlocal goto +receivers''. If a function contains such nonlocal goto receivers, an +edge from the call to the label is created with the +@code{EDGE_ABNORMAL} and @code{EDGE_ABNORMAL_CALL} flags set. + +@item function entry points +@cindex function entry point, alternate function entry point +@findex LABEL_ALTERNATE_NAME +By definition, execution of function starts at basic block 0, so there +is always an edge from the @code{ENTRY_BLOCK_PTR} to basic block 0. +There is no @code{tree} representation for alternate entry points at +this moment. In RTL, alternate entry points are specified by +@code{CODE_LABEL} with @code{LABEL_ALTERNATE_NAME} defined. This +feature is currently used for multiple entry point prologues and is +limited to post-reload passes only. This can be used by back-ends to +emit alternate prologues for functions called from different contexts. +In future full support for multiple entry functions defined by Fortran +90 needs to be implemented. + +@item function exits +In the pre-reload representation a function terminates after the last +instruction in the insn chain and no explicit return instructions are +used. This corresponds to the fall-thru edge into exit block. After +reload, optimal RTL epilogues are used that use explicit (conditional) +return instructions that are represented by edges with no flags set. + +@end table + + +@node Profile information +@section Profile information + +@cindex profile representation +In many cases a compiler must make a choice whether to trade speed in +one part of code for speed in another, or to trade code size for code +speed. In such cases it is useful to know information about how often +some given block will be executed. That is the purpose for +maintaining profile within the flow graph. +GCC can handle profile information obtained through @dfn{profile +feedback}, but it can also estimate branch probabilities based on +statics and heuristics. + +@cindex profile feedback +The feedback based profile is produced by compiling the program with +instrumentation, executing it on a train run and reading the numbers +of executions of basic blocks and edges back to the compiler while +re-compiling the program to produce the final executable. This method +provides very accurate information about where a program spends most +of its time on the train run. Whether it matches the average run of +course depends on the choice of train data set, but several studies +have shown that the behavior of a program usually changes just +marginally over different data sets. + +@cindex Static profile estimation +@cindex branch prediction +@findex predict.def +When profile feedback is not available, the compiler may be asked to +attempt to predict the behavior of each branch in the program using a +set of heuristics (see @file{predict.def} for details) and compute +estimated frequencies of each basic block by propagating the +probabilities over the graph. + +@findex frequency, count, BB_FREQ_BASE +Each @code{basic_block} contains two integer fields to represent +profile information: @code{frequency} and @code{count}. The +@code{frequency} is an estimation how often is basic block executed +within a function. It is represented as an integer scaled in the +range from 0 to @code{BB_FREQ_BASE}. The most frequently executed +basic block in function is initially set to @code{BB_FREQ_BASE} and +the rest of frequencies are scaled accordingly. During optimization, +the frequency of the most frequent basic block can both decrease (for +instance by loop unrolling) or grow (for instance by cross-jumping +optimization), so scaling sometimes has to be performed multiple +times. + +@findex gcov_type +The @code{count} contains hard-counted numbers of execution measured +during training runs and is nonzero only when profile feedback is +available. This value is represented as the host's widest integer +(typically a 64 bit integer) of the special type @code{gcov_type}. + +Most optimization passes can use only the frequency information of a +basic block, but a few passes may want to know hard execution counts. +The frequencies should always match the counts after scaling, however +during updating of the profile information numerical error may +accumulate into quite large errors. + +@findex REG_BR_PROB_BASE, EDGE_FREQUENCY +Each edge also contains a branch probability field: an integer in the +range from 0 to @code{REG_BR_PROB_BASE}. It represents probability of +passing control from the end of the @code{src} basic block to the +@code{dest} basic block, i.e. the probability that control will flow +along this edge. The @code{EDGE_FREQUENCY} macro is available to +compute how frequently a given edge is taken. There is a @code{count} +field for each edge as well, representing same information as for a +basic block. + +The basic block frequencies are not represented in the instruction +stream, but in the RTL representation the edge frequencies are +represented for conditional jumps (via the @code{REG_BR_PROB} +macro) since they are used when instructions are output to the +assembly file and the flow graph is no longer maintained. + +@cindex reverse probability +The probability that control flow arrives via a given edge to its +destination basic block is called @dfn{reverse probability} and is not +directly represented, but it may be easily computed from frequencies +of basic blocks. + +@findex redirect_edge_and_branch +Updating profile information is a delicate task that can unfortunately +not be easily integrated with the CFG manipulation API. Many of the +functions and hooks to modify the CFG, such as +@code{redirect_edge_and_branch}, do not have enough information to +easily update the profile, so updating it is in the majority of cases +left up to the caller. It is difficult to uncover bugs in the profile +updating code, because they manifest themselves only by producing +worse code, and checking profile consistency is not possible because +of numeric error accumulation. Hence special attention needs to be +given to this issue in each pass that modifies the CFG. + +@findex REG_BR_PROB_BASE, BB_FREQ_BASE, count +It is important to point out that @code{REG_BR_PROB_BASE} and +@code{BB_FREQ_BASE} are both set low enough to be possible to compute +second power of any frequency or probability in the flow graph, it is +not possible to even square the @code{count} field, as modern CPUs are +fast enough to execute $2^32$ operations quickly. + + +@node Maintaining the CFG +@section Maintaining the CFG +@findex cfghooks.h + +An important task of each compiler pass is to keep both the control +flow graph and all profile information up-to-date. Reconstruction of +the control flow graph after each pass is not an option, since it may be +very expensive and lost profile information cannot be reconstructed at +all. + +GCC has two major intermediate representations, and both use the +@code{basic_block} and @code{edge} data types to represent control +flow. Both representations share as much of the CFG maintenance code +as possible. For each representation, a set of @dfn{hooks} is defined +so that each representation can provide its own implementation of CFG +manipulation routines when necessary. These hooks are defined in +@file{cfghooks.h}. There are hooks for almost all common CFG +manipulations, including block splitting and merging, edge redirection +and creating and deleting basic blocks. These hooks should provide +everything you need to maintain and manipulate the CFG in both the RTL +and @code{tree} representation. + +At the moment, the basic block boundaries are maintained transparently +when modifying instructions, so there rarely is a need to move them +manually (such as in case someone wants to output instruction outside +basic block explicitly). +Often the CFG may be better viewed as integral part of instruction +chain, than structure built on the top of it. However, in principle +the control flow graph for the @code{tree} representation is +@emph{not} an integral part of the representation, in that a function +tree may be expanded without first building a flow graph for the +@code{tree} representation at all. This happens when compiling +without any @code{tree} optimization enabled. When the @code{tree} +optimizations are enabled and the instruction stream is rewritten in +SSA form, the CFG is very tightly coupled with the instruction stream. +In particular, statement insertion and removal has to be done with +care. In fact, the whole @code{tree} representation can not be easily +used or maintained without proper maintenance of the CFG +simultaneously. + +@findex BLOCK_FOR_INSN, bb_for_stmt +In the RTL representation, each instruction has a +@code{BLOCK_FOR_INSN} value that represents pointer to the basic block +that contains the instruction. In the @code{tree} representation, the +function @code{bb_for_stmt} returns a pointer to the basic block +containing the queried statement. + +@cindex block statement iterators +When changes need to be applied to a function in its @code{tree} +representation, @dfn{block statement iterators} should be used. These +iterators provide an integrated abstraction of the flow graph and the +instruction stream. Block statement iterators iterators are +constructed using the @code{block_stmt_iterator} data structure and +several modifier are available, including the following: + +@table @code +@item bsi_start +@findex bsi_start +This function initializes a @code{block_stmt_iterator} that points to +the first non-empty statement in a basic block. + +@item bsi_last +@findex bsi_last +This function initializes a @code{block_stmt_iterator} that points to +the last statement in a basic block. + +@item bsi_end_p +@findex bsi_end_p +This predicate is @code{true} if a @code{block_stmt_iterator} +represents the end of a basic block. + +@item bsi_next +@findex bsi_next +This function takes a @code{block_stmt_iterator} and makes it point to +its successor. + +@item bsi_prev +@item bsi_prev +This function takes a @code{block_stmt_iterator} and makes it point to +its predecessor. + +@item bsi_insert_after +@findex bsi_insert_after +This function inserts a statement after the @code{block_stmt_iterator} +passed in. The final parameter determines whether the statement +iterator is updated to point to the newly inserted statement, or left +pointing to the original statement. + +@item bsi_insert_before +@findex bsi_insert_before +This function inserts a statement before the @code{block_stmt_iterator} +passed in. The final parameter determines whether the statement +iterator is updated to point to the newly inserted statement, or left +pointing to the original statement. + +@item bsi_remove +This function removes the @code{block_stmt_iterator} passed in and +rechains the remaining statements in a basic block, if any. + +@end table + +@findex BB_HEAD, BB_END +In the RTL representation, the macros @code{BB_HEAD} and @code{BB_END} +may be used to get the head and end @code{rtx} of a basic block. No +abstract iterators are defined for traversing the insn chain, but you +can just use @code{NEXT_INSN} and @code{PREV_INSN} instead. See +@xref{Insns}. + +@findex purge_dead_edges +Usually a code manipulating pass simplifies the instruction stream and +the flow of control, possibly eliminating some edges. This may for +example happen when a conditional jump is replaced with an +unconditional jump, but also when simplifying possibly trapping +instruction to non-trapping while compiling Java. Updating of edges +is not transparent and each optimization pass is required to do so +manually. However only few cases occur in practice. The pass may +call @code{purge_dead_edges} on a given basic block to remove +superfluous edges, if any. + +@findex redirect_edge_and_branch, redirect_jump +Another common scenario is redirection of branch instructions, but +this is best modeled as redirection of edges in the control flow graph +and thus use of @code{redirect_edge_and_branch} is preferred over more +low level functions, such as @code{redirect_jump} that operate on RTL +chain only. The CFG hooks defined in @file{cfghooks.h} should provide +the complete API required for manipulating and maintaining the CFG. + +@findex find_sub_basic_blocks, split_block +It is also possible that a pass has to insert control flow instruction +into the middle of a basic block, thus creating an entry point in the +middle of the basic block, which is impossible by definition: The +block must be split to make sure it only has one entry point, i.e. the +head of the basic block. In the RTL representation, the +@code{find_sub_basic_blocks} may be used to split existing basic block +and add necessary edges. The CFG hook @code{split_block} may be used +when an instruction in the middle of a basic block has to become the +target of a jump or branch instruction. + +@findex insert_insn_on_edge, commit_edge_insertions +@findex bsi_insert_on_edge, bsi_commit_edge_inserts +@cindex edge splitting +For a global optimizer, a common operation is to split edges in the +flow graph and insert instructions on them. In the RTL +representation, this can be easily done using the +@code{insert_insn_on_edge} function that emits an instruction +``on the edge'', caching it for a later @code{commit_edge_insertions} +call that will take care of moving the inserted instructions off the +edge into the instruction stream contained in a basic block. This +includes the creation of new basic blocks where needed. In the +@code{tree} representation, the equivalent functions are +@code{bsi_insert_on_edge} which inserts a block statement +iterator on an edge, and @code{bsi_commit_edge_inserts} which flushes +the instruction to actual instruction stream. + +While debugging the optimization pass, an @code{verify_flow_info} +function may be useful to find bugs in the control flow graph updating +code. + +Note that at present, the representation of control flow in the +@code{tree} representation is discarded before expanding to RTL. +Long term the CFG should be maintained and ``expanded'' to the +RTL representation along with the function @code{tree} itself. + + +@node Liveness information +@section Liveness information +@cindex Liveness representation +Liveness information is useful to determine whether some register is +``live'' at given point of program, i.e. that it contains a value that +may be used at a later point in the program. This information is +used, for instance, during register allocation, as the pseudo +registers only need to be assigned to a unique hard register or to a +stack slot if they are live. The hard registers and stack slots may +be freely reused for other values when a register is dead. + +@findex REG_DEAD, REG_UNUSED +The liveness information is stored partly in the RTL instruction +stream and partly in the flow graph. Local information is stored in +the instruction stream: +Each instruction may contain @code{REG_DEAD} notes representing that +the value of a given register is no longer needed, or +@code{REG_UNUSED} notes representing that the value computed by the +instruction is never used. The second is useful for instructions +computing multiple values at once. + +@findex global_live_at_start, global_live_at_end +Global liveness information is stored in the control flow graph. +Each basic block contains two bitmaps, @code{global_live_at_start} and +@code{global_live_at_end} representing liveness of each register at +the entry and exit of the basic block. The file @code{flow.c} +contains functions to compute liveness of each register at any given +place in the instruction stream using this information. + +@findex BB_DIRTY, clear_bb_flags, update_life_info_in_dirty_blocks +Liveness is expensive to compute and thus it is desirable to keep it +up to date during code modifying passes. This can be easily +accomplished using the @code{flags} field of a basic block. Functions +modifying the instruction stream automatically set the @code{BB_DIRTY} +flag of a modifies basic block, so the pass may simply +use@code{clear_bb_flags} before doing any modifications and then ask +the data flow module to have liveness updated via the +@code{update_life_info_in_dirty_blocks} function. + +This scheme works reliably as long as no control flow graph +transformations are done. The task of updating liveness after control +flow graph changes is more difficult as normal iterative data flow +analysis may produce invalid results or get into an infinite cycle +when the initial solution is not below the desired one. Only simple +transformations, like splitting basic blocks or inserting on edges, +are safe, as functions to implement them already know how to update +liveness information locally. diff --git a/gcc/doc/gccint.texi b/gcc/doc/gccint.texi index 7ce5dde73c6..5dbe1f79f43 100644 --- a/gcc/doc/gccint.texi +++ b/gcc/doc/gccint.texi @@ -140,6 +140,8 @@ Additional tutorial information is linked to from * Passes:: Order of passes, what they do, and what each file is for. * Trees:: The source representation used by the C and C++ front ends. * RTL:: The intermediate representation that most passes work on. +* Control Flow:: Maintaining and manipulating the control flow graph. +* Tree SSA:: Analysis and optimization of the tree representation. * Machine Desc:: How to write machine description instruction patterns. * Target Macros:: How to write the machine description C macros and functions. * Host Config:: Writing the @file{xm-@var{machine}.h} file. @@ -168,7 +170,9 @@ Additional tutorial information is linked to from @include sourcebuild.texi @include passes.texi @include c-tree.texi +@include tree-ssa.texi @include rtl.texi +@include cfg.texi @include md.texi @include tm.texi @include hostconfig.texi diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index a70b66b6f34..599b9172c77 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -429,11 +429,11 @@ components. Please refer to our @uref{http://gcc.gnu.org/releases.html,,releases web page} for information on how to obtain GCC@. -The full distribution includes the C, C++, Objective-C, Fortran, Java, -and Ada (in case of GCC 3.1 and later) compilers. The full distribution -also includes runtime libraries for C++, Objective-C, Fortran, and Java. -In GCC 3.0 and later versions, GNU compiler testsuites are also included -in the full distribution. +The full distribution includes the C, C++, Objective-C, Fortran 77, Fortran +(in case of GCC 3.5 and later), Java, and Ada (in case of GCC 3.1 and later) +compilers. The full distribution also includes runtime libraries for C++, +Objective-C, Fortran 77, Fortran, and Java. In GCC 3.0 and later versions, +GNU compiler testsuites are also included in the full distribution. If you choose to download specific components, you must download the core GCC distribution plus any language specific distributions you wish to @@ -1029,7 +1029,8 @@ their runtime libraries should be built. For a list of valid values for grep language= */config-lang.in @end smallexample Currently, you can use any of the following: -@code{ada}, @code{c}, @code{c++}, @code{f77}, @code{java}, @code{objc}. +@code{ada}, @code{c}, @code{c++}, @code{f77}, @code{f95}, @code{java}, +@code{objc}. Building the Ada compiler has special requirements, see below.@* If you do not pass this flag, all languages available in the @file{gcc} sub-tree will be configured. Re-defining @code{LANGUAGES} when calling diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ff1e34a3b34..3144fd1fcb4 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -245,11 +245,24 @@ in the following sections. @gccoptlist{-d@var{letters} -dumpspecs -dumpmachine -dumpversion @gol -fdump-unnumbered -fdump-translation-unit@r{[}-@var{n}@r{]} @gol -fdump-class-hierarchy@r{[}-@var{n}@r{]} @gol +-fdump-tree-all @gol -fdump-tree-original@r{[}-@var{n}@r{]} @gol -fdump-tree-optimized@r{[}-@var{n}@r{]} @gol -fdump-tree-inlined@r{[}-@var{n}@r{]} @gol +-fdump-tree-cfg -fdump-tree-vcg -fdump-tree-alias @gol +-fdump-tree-ch @gol +-fdump-tree-ssa@r{[}-@var{n}@r{]} -fdump-tree-pre@r{[}-@var{n}@r{]} @gol +-fdump-tree-ccp@r{[}-@var{n}@r{]} -fdump-tree-dce@r{[}-@var{n}@r{]} @gol +-fdump-tree-gimple@r{[}-raw@r{]} -fdump-tree-mudflap@r{[}-@var{n}@r{]} @gol +-fdump-tree-dom@r{[}-@var{n}@r{]} @gol +-fdump-tree-dse@r{[}-@var{n}@r{]} @gol +-fdump-tree-phiopt@r{[}-@var{n}@r{]} @gol +-fdump-tree-forwprop@r{[}-@var{n}@r{]} @gol +-fdump-tree-copyrename@r{[}-@var{n}@r{]} @gol +-fdump-tree-nrv @gol +-fdump-tree-sra@r{[}-@var{n}@r{]} @gol -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol --feliminate-unused-debug-symbols -fmem-report -fprofile-arcs @gol +-feliminate-unused-debug-symbols -fmem-report -fprofile-arcs -ftree-based-profiling @gol -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol -ftest-coverage -ftime-report -fvar-tracking @gol -g -g@var{level} -gcoff -gdwarf-2 @gol @@ -263,6 +276,7 @@ in the following sections. @xref{Optimize Options,,Options that Control Optimization}. @gccoptlist{-falign-functions=@var{n} -falign-jumps=@var{n} @gol -falign-labels=@var{n} -falign-loops=@var{n} @gol +-fbounds-check -fmudflap -fmudflapth -fmudflapir @gol -fbranch-probabilities -fprofile-values -fvpt -fbranch-target-load-optimize @gol -fbranch-target-load-optimize2 -fbtr-bb-exclusive @gol -fcaller-saves -fcprop-registers @gol @@ -296,6 +310,9 @@ in the following sections. -fstrength-reduce -fstrict-aliasing -ftracer -fthread-jumps @gol -funroll-all-loops -funroll-loops -fpeel-loops @gol -funswitch-loops -fold-unroll-loops -fold-unroll-all-loops @gol +-ftree-pre -ftree-ccp -ftree-dce @gol +-ftree-dominator-opts -ftree-dse -ftree-copyrename @gol +-ftree-ch -ftree-sra -ftree-ter -ftree-lrs @gol --param @var{name}=@var{value} -O -O0 -O1 -O2 -O3 -Os} @@ -754,6 +771,10 @@ preprocessor). Fortran source code which must be preprocessed with a RATFOR preprocessor (not included with GCC)@. +@item @var{file}.f90 +@itemx @var{file}.f95 +Fortran 90/95 source code which should not be preprocessed. + @xref{Overall Options,,Options Controlling the Kind of Output, g77, Using and Porting GNU Fortran}, for more details of the handling of Fortran input files. @@ -807,6 +828,7 @@ objective-c objective-c-header objc-cpp-output assembler assembler-with-cpp ada f77 f77-cpp-input ratfor +f95 java treelang @end smallexample @@ -3214,6 +3236,17 @@ executed. When an arc is the only exit or only entrance to a block, the instrumentation code can be added to the block; otherwise, a new basic block must be created to hold the instrumentation code. +@item -ftree-based-profiling +@opindex ftree-based-profiling +This option is used in addition to @option{-fprofile-arcs} or +@option{-fbranch-probabilities} to control whether those optimizations +are performed on a tree-based or rtl-based internal representation. +If you use this option when compiling with @option{-fprofile-arcs}, +you must also use it when compiling later with @option{-fbranch-probabilities}. +Currently the tree-based optimization is in an early stage of +development, and this option is recommended only for those people +working on improving it. + @need 2000 @item -ftest-coverage @opindex ftest-coverage @@ -3409,8 +3442,8 @@ to the source file name. If the @samp{-@var{options}} form is used, @var{options} controls the details of the dump as described for the @option{-fdump-tree} options. -@item -fdump-tree-@var{switch} @r{(C++ only)} -@itemx -fdump-tree-@var{switch}-@var{options} @r{(C++ only)} +@item -fdump-tree-@var{switch} @r{(C and C++ only)} +@itemx -fdump-tree-@var{switch}-@var{options} @r{(C and C++ only)} @opindex fdump-tree Control the dumping at various stages of processing the intermediate language tree to a file. The file name is generated by appending a switch @@ -3427,20 +3460,133 @@ changes according to the environment and source file. Its primary use is for tying up a dump file with a debug environment. @item slim Inhibit dumping of members of a scope or body of a function merely -because that scope has been reached. Only dump such items when they -are directly reachable by some other path. +because that scope has been reached. Only dump such items when they +are directly reachable by some other path. When dumping pretty-printed +trees, this option inhibits dumping the bodies of control structures. +@item raw +Print a raw representation of the tree. By default, trees are +pretty-printed into a C-like representation. +@item details +Enable more detailed dumps (not honored by every dump option). +@item stats +Enable dumping various statistics about the pass (not honored by every dump +option). +@item blocks +Enable showing basic block boundaries (disabled in raw dumps). +@item vops +Enable showing virtual operands for every statement. +@item lineno +Enable showing line numbers for statements. +@item uid +Enable showing the unique ID (@code{DECL_UID}) for each variable. @item all -Turn on all options. +Turn on all options, except @option{raw}, @option{slim} and @option{lineno}. @end table The following tree dumps are possible: @table @samp + @item original Dump before any tree based optimization, to @file{@var{file}.original}. + @item optimized Dump after all tree based optimization, to @file{@var{file}.optimized}. + @item inlined Dump after function inlining, to @file{@var{file}.inlined}. + +@item gimple +@opindex fdump-tree-gimple +Dump each function before and after the gimplification pass to a file. The +file name is made by appending @file{.gimple} to the source file name. + +@item cfg +@opindex fdump-tree-cfg +Dump the control flow graph of each function to a file. The file name is +made by appending @file{.cfg} to the source file name. + +@item vcg +@opindex fdump-tree-vcg +Dump the control flow graph of each function to a file in VCG format. The +file name is made by appending @file{.vcg} to the source file name. Note +that if the file contains more than one function, the generated file cannot +be used directly by VCG. You will need to cut and paste each function's +graph into its own separate file first. + +@item ch +@opindex fdump-tree-ch +Dump each function after copying loop headers. The file name is made by +appending @file{.ch} to the source file name. + +@item ssa +@opindex fdump-tree-ssa +Dump SSA related information to a file. The file name is made by appending +@file{.ssa} to the source file name. + +@item alias +@opindex fdump-tree-alias +Dump aliasing information for each function. The file name is made by +appending @file{.alias} to the source file name. + +@item ccp +@opindex fdump-tree-ccp +Dump each function after CCP. The file name is made by appending +@file{.ccp} to the source file name. + +@item pre +@opindex fdump-tree-pre +Dump trees after partial redundancy elimination. The file name is made +by appending @file{.pre} to the source file name. + +@item dce +@opindex fdump-tree-dce +Dump each function after dead code elimination. The file name is made by +appending @file{.dce} to the source file name. + +@item mudflap +@opindex fdump-tree-mudflap +Dump each function after adding mudflap instrumentation. The file name is +made by appending @file{.mudflap} to the source file name. + +@item sra +@opindex fdump-tree-sra +Dump each function after performing scalar replacement of aggregates. The +file name is made by appending @file{.sra} to the source file name. + +@item dom +@opindex fdump-tree-dom +Dump each function after applying dominator tree optimizations. The file +name is made by appending @file{.dom} to the source file name. + +@item dse +@opindex fdump-tree-dse +Dump each function after applying dead store elimination. The file +name is made by appending @file{.dse} to the source file name. + +@item phiopt +@opindex fdump-tree-phiopt +Dump each function after optimizing PHI nodes into straightline code. The file +name is made by appending @file{.phiopt} to the source file name. + +@item forwprop +@opindex fdump-tree-forwprop +Dump each function after forward propagating single use variables. The file +name is made by appending @file{.forwprop} to the source file name. + +@item copyrename +@opindex fdump-tree-copyrename +Dump each function after applying the copy rename optimization. The file +name is made by appending @file{.copyrename} to the source file name. + +@item nrv +@opindex fdump-tree-nrv +Dump each function after applying the named return value optimization on +generic trees. The file name is made by appending @file{.nrv} to the source +file name. + +@item all +@opindex fdump-tree-all +Enable all the available tree dumps with the flags provided in this option. @end table @item -frandom-seed=@var{string} @@ -3900,6 +4046,39 @@ assumptions based on that. The default is @option{-fzero-initialized-in-bss}. +@item -fbounds-check +@opindex fbounds-check +For front-ends that support it, generate additional code to check that +indices used to access arrays are within the declared range. This is +currently only supported by the Java and Fortran front-ends, where +this option defaults to true and false respectively. + +@item -fmudflap -fmudflapth -fmudflapir +@opindex fmudflap +@opindex fmudflapth +@opindex fmudflapir +@cindex bounds checking +@cindex mudflap +For front-ends that support it (C and C++), instrument all risky +pointer/array dereferencing operations, some standard library +string/heap functions, and some other associated constructs with +range/validity tests. Modules so instrumented should be immune to +buffer overflows, invalid heap use, and some other classes of C/C++ +programming errors. The instrumentation relies on a separate runtime +library (@file{libmudflap}), which will be linked into a program if +@option{-fmudflap} is given at link time. Run-time behavior of the +instrumented program is controlled by the @env{MUDFLAP_OPTIONS} +environment variable. See @code{env MUDFLAP_OPTIONS=-help a.out} +for its options. + +Use @option{-fmudflapth} instead of @option{-fmudflap} to compile and to +link if your program is multi-threaded. Use @option{-fmudflapir}, in +addition to @option{-fmudflap} or @option{-fmudflapth}, if +instrumentation should ignore pointer reads. This produces less +instrumentation (and therefore faster execution) and still provides +some protection against outright memory corrupting writes, but allows +erroneously read data to propagate within a program. + @item -fstrength-reduce @opindex fstrength-reduce Perform the optimizations of loop strength reduction and @@ -4159,6 +4338,76 @@ those which have no call-preserved registers to use instead. Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. +@item -ftree-pre +Perform Partial Redundancy Elimination (PRE) on trees. This flag is +enabled by default at -O and higher. + +@item -ftree-ccp +Perform sparse conditional constant propagation (CCP) on trees. This flag +is enabled by default at -O and higher. + +@item -ftree-dce +Perform dead code elimination (DCE) on trees. This flag is enabled by +default at -O and higher. + +@item -ftree-dominator-opts +Perform dead code elimination (DCE) on trees. This flag is enabled by +default at -O and higher. + +@item -ftree-ch +Perform loop header copying on trees. This is beneficial since it increases +effectivity of code motion optimizations. It also saves one jump. This flag +is enabled by default at -O and higher. It is not enabled for -Os, since it +usually increases code size. + +@item -ftree-sra +Perform scalar replacement of aggregates. This pass replaces structure +references with scalars to prevent committing structures to memory too +early. This flag is enabled by default at -O and higher. + +@item -ftree-copyrename +Perform copy renaming on trees. This pass attempts to rename compiler +temporaries to other variables at copy locations, usually resulting in +variable names which more closely resemble the original variables. This flag +is enabled by default at -O and higher. + +@item -ftree-ter +Perform temporary expression replacement during the SSA->normal phase. Single +use/single def temporaries are replaced at their use location with their +defining expression. This results in non-GIMPLE code, but gives the expanders +much more complex trees to work on resulting in better RTL generation. This is +enabled by default at -O and higher. + +@item -ftree-lrs +Perform live range splitting during the SSA->normal phase. Distinct live +ranges of a variable are split into unique variables, allowing for better +optimization later. This is enabled by default at -O and higher. + +@item -ftracer +@opindex ftracer +Perform tail duplication to enlarge superblock size. This transformation +simplifies the control flow of the function allowing other optimizations to do +better job. + +@item -funroll-loops +@opindex funroll-loops +Unroll loops whose number of iterations can be determined at compile +time or upon entry to the loop. @option{-funroll-loops} implies both +@option{-fstrength-reduce} and @option{-frerun-cse-after-loop}. This +option makes code larger, and may or may not make it run faster. + +@item -funroll-all-loops +@opindex funroll-all-loops +Unroll all loops, even if their number of iterations is uncertain when +the loop is entered. This usually makes programs run more slowly. +@option{-funroll-all-loops} implies the same options as +@option{-funroll-loops}, + +@item -fprefetch-loop-arrays +@opindex fprefetch-loop-arrays +If supported by the target machine, generate instructions to prefetch +memory to improve the performance of loops that access large arrays. + @item -fmove-all-movables @opindex fmove-all-movables Forces all invariant computations in loops to be moved @@ -4820,6 +5069,27 @@ Specifies maximal overall growth of the compilation unit caused by inlining. This parameter is ignored when @option{-funit-at-a-time} is not used. The default value is 150. +@item max-inline-insns-recursive +@itemx max-inline-insns-recursive-auto +Specifies maximum number of instructions out-of-line copy of self recursive inline +function can grow into by performing recursive inlining. + +For functions declared inline @option{--param max-inline-insns-recursive} is +taken into acount. For function not declared inline, recursive inlining +happens only when @option{-finline-functions} (included in @option{-O3}) is +enabled and @option{--param max-inline-insns-recursive-auto} is used. The +default value is 500. + +@item max-inline-recursive-depth +@itemx max-inline-recursive-depth-auto +Specifies maximum recursion depth used by the recursive inlining. + +For functions declared inline @option{--param max-inline-recursive-depth} is +taken into acount. For function not declared inline, recursive inlining +happens only when @option{-finline-functions} (included in @option{-O3}) is +enabled and @option{--param max-inline-recursive-depth-auto} is used. The +default value is 500. + @item max-inline-insns-rtl For languages that use the RTL inliner (this happens at a later stage than tree inlining), you can set the maximum allowable size (counted @@ -4904,6 +5174,22 @@ order to make tracer effective. Maximum number of basic blocks on path that cse considers. The default is 10. +@item global-var-threshold + +Counts the number of function calls (N) and the number of +call-clobbered variables (V). If NxV is larger than this limit, a +single artificial variable will be created to represent all the +call-clobbered variables at function call sites. This artificial +variable will then be made to alias every call-clobbered variable. +(done as int * size_t on the host machine; beware overflow). + +@item max-aliased-vops + +Maxiumum number of virtual operands allowed to represent aliases +before triggering the alias grouping heuristic. Alias grouping +reduces compile times and memory consumption needed for aliasing at +the expense of precision loss in alias information. + @item ggc-min-expand GCC uses a garbage collector to manage its own memory allocation. This diff --git a/gcc/doc/passes.texi b/gcc/doc/passes.texi index 5962c5378d5..b5a69d88633 100644 --- a/gcc/doc/passes.texi +++ b/gcc/doc/passes.texi @@ -1,3 +1,5 @@ +@c markers: CROSSREF BUG TODO + @c Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, @c 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. @c This is part of the GCC manual. @@ -9,131 +11,441 @@ @cindex files and passes of the compiler @cindex compiler passes and files -@cindex top level of 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. Routines for emitting -diagnostic messages are defined in @file{diagnostic.c}. The files -@file{pretty-print.h} and @file{pretty-print.c} provide basic support -for language-independent pretty-printing. - -@cindex parsing pass -The parsing pass is invoked only once, to parse the entire input. A -high level tree representation is then generated from the input, -one function at a time. This tree code is then transformed into RTL -intermediate code, and processed. The files involved in transforming -the trees into RTL are @file{expr.c}, @file{expmed.c}, and -@file{stmt.c}. -@c Note, the above files aren't strictly the only files involved. It's -@c all over the place (function.c, final.c,etc). However, those are -@c the files that are supposed to be directly involved, and have -@c their purpose listed as such, so i've only listed them. -The order of trees that are processed, is not -necessarily the same order they are generated from -the input, due to deferred inlining, and other considerations. - -@findex rest_of_compilation +This chapter is dedicated to giving an overview of the optimization and +code generation passes of the compiler. In the process, it describes +some of the language front end interface, though this description is no +where near complete. + +@menu +* Parsing pass:: The language front end turns text into bits. +* Gimplification pass:: The bits are turned into something we can optimize. +* Pass manager:: Sequencing the optimization passes. +* Tree-SSA passes:: Optimizations on a high-level representation. +* RTL passes:: Optimizations on a low-level representation. +@end menu + +@node Parsing pass +@section Parsing pass +@cindex GENERIC +@findex lang_hooks.parse_file +The language front end is invoked only once, via +@code{lang_hooks.parse_file}, to parse the entire input. The language +front end may use any intermediate language representation deemed +appropriate. The C front end uses GENERIC trees (CROSSREF), plus +a double handful of language specific tree codes defined in +@file{c-common.def}. The Fortran front end uses a completely different +private representation. + +@cindex GIMPLE +@cindex gimplification +@cindex gimplifier +@cindex language-independent intermediate representation +@cindex intermediate representation lowering +@cindex lowering, language-dependent intermediate representation +At some point the front end must translate the representation used in the +front end to a representation understood by the language-independent +portions of the compiler. Current practice takes one of two forms. +The C front end manually invokes the gimplifier (CROSSREF) on each function, +and uses the gimplifier callbacks to convert the language-specific tree +nodes directly to GIMPLE (CROSSREF) before passing the function off to +be compiled. +The Fortran front end converts from a private representation to GENERIC, +which is later lowered to GIMPLE when the function is compiled. Which +route to choose probably depends on how well GENERIC (plus extensions) +can be made to match up with the source language and necessary parsing +data structures. + +BUG: Gimplification must occur before nested function lowering, +and nested function lowering must be done by the front end before +passing the data off to cgraph. + +TODO: Cgraph should control nested function lowering. It would +only be invoked when it is certain that the outer-most function +is used. + +TODO: Cgraph needs a gimplify_function callback. It should be +invoked when (1) it is certain that the function is used, (2) +warning flags specified by the user require some amount of +compilation in order to honor, (3) the language indicates that +semantic analysis is not complete until gimplification occurs. +Hum... this sounds overly complicated. Perhaps we should just +have the front end gimplify always; in most cases it's only one +function call. + +The front end needs to pass all function definitions and top level +declarations off to the middle-end so that they can be compiled and +emitted to the object file. For a simple procedural language, it is +usually most convenient to do this as each top level declaration or +definition is seen. There is also a distinction to be made between +generating functional code and generating complete debug information. +The only thing that is absolutely required for functional code is that +function and data @emph{defintions} be passed to the middle-end. For +complete debug information, function, data and type declarations +should all be passed as well. + @findex rest_of_decl_compilation -Each time the parsing pass reads a complete function definition or -top-level declaration, it calls either the function -@code{rest_of_compilation}, or the function -@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, or was deferred for some reason (this can occur in -templates, for example). -(@pxref{Inline,,An Inline Function is As Fast As a Macro,gcc,Using the -GNU Compiler Collection (GCC)}). - -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 @option{-d} options. +@findex rest_of_type_compilation +@findex cgraph_finalize_function +In any case, the front end needs each complete top-level function or +data declaration, and each data definition should be passed to +@code{rest_of_decl_compilation}. Each complete type definition should +be passed to @code{rest_of_type_compilation}. Each function definition +should be passed to @code{cgraph_finalize_function}. + +TODO: I know rest_of_compilation currently has all sorts of +rtl-generation semantics. I plan to move all code generation +bits (both tree and rtl) to compile_function. Should we hide +cgraph from the front ends and move back to rest_of_compilation +as the official interface? Possibly we should rename all three +interfaces such that the names match in some meaningful way and +that is more descriptive than "rest_of". + +The middle-end will, at its option, emit the function and data +definitions immediately or queue them for later processing. + +@node Gimplification pass +@section Gimplification pass + +@cindex gimplification +@cindex GIMPLE +@dfn{Gimplification} is a whimsical term for the process of converting +the intermediate representation of a function into the GIMPLE language +(CROSSREF). The term stuck, and so words like ``gimplification,'' +``gimplify,'' ``gimplifier'' and the like are sprinkled throughout this +section of code. + +@cindex GENERIC +While a front end may certainly choose to generate GIMPLE directly if +it chooses, this can be a moderately complex process unless the +intermediate language used by the front end is already fairly simple. +Usually it is easier to generate GENERIC trees plus extensions +and let the language-independent gimplifier do most of the work. + +@findex gimplify_function_tree +@findex gimplify_expr +@findex lang_hooks.gimplify_expr +The main entry point to this pass is @code{gimplify_function_tree} +located in @file{gimplify.c}. From here we process the entire +function gimplifying each statement in turn. The main workhorse +for this pass is @code{gimplify_expr}. Approximately everything +passes through here at least once, and it is from here that we +invoke the @code{lang_hooks.gimplify_expr} callback. + +The callback should examine the expression in question and return +@code{GS_UNHANDLED} if the expression is not a language specific +construct that requires attention. Otherwise it should alter the +expression in some way to such that forward progress is made toward +producing valid GIMPLE. If the callback is certain that the +transformation is complete and the expression is valid GIMPLE, it +should return @code{GS_ALL_DONE}. Otherwise it should return +@code{GS_OK}, which will cause the expression to be processed again. +If the callback encounters an error during the transformation (because +the front end is relying on the gimplification process to finish +semantic checks), it should return @code{GS_ERROR}. + +@node Pass manager +@section Pass manager + +The pass manager is located in @file{passes.c} and @file{passes.h}. +Its job is to run all of the individual passes in the correct order, +and take care of standard bookkeeping that applies to every pass. + +The theory of operation is that each pass defines a structure that +represents everything we need to know about that pass --- when it +should be run, how it should be run, what intermediate language +form or on-the-side data structures it needs. We register the pass +to be run in some particular order, and the pass manager arranges +for everything to happen in the correct order. + +The actuality doesn't completely live up to the theory at present. +Command-line switches and @code{timevar_id_t} enumerations must still +be defined elsewhere. The pass manager validates constraints but does +not attempt to (re-)generate data structures or lower intermediate +language form based on the requirements of the next pass. Nevertheless, +what is present is useful, and a far sight better than nothing at all. + +TODO: describe the global variables set up by the pass manager, +and a brief description of how a new pass should use it. +I need to look at what info rtl passes use first... + +@node Tree-SSA passes +@section Tree-SSA passes + +The following briefly describes the tree optimization passes that are +run after gimplification and what source files they are located in. @itemize @bullet -@item -Parsing. This pass reads the entire text of a function definition, -constructing a high level tree representation. (Because of the semantic -analysis that takes place during this pass, it does more than is -formally considered to be parsing.) - -The tree representation does not entirely follow C syntax, because it is -intended to support other languages as well. - -Language-specific 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. - -The language-independent source files for parsing are -@file{tree.c}, @file{fold-const.c}, and @file{stor-layout.c}. -There are also header files @file{tree.h} and @file{tree.def} -which define the format of the tree representation. - -C preprocessing, for language front ends, that want or require it, is -performed by cpplib, which is covered in separate documentation. In -particular, the internals are covered in @xref{Top, ,Cpplib internals, -cppinternals, Cpplib Internals}. - -The source files to parse C are found in the toplevel directory, and -by convention are named @file{c-*}. Some of these are also used by -the other C-like languages: @file{c-common.c}, -@file{c-common.def}, -@file{c-format.c}, -@file{c-opts.c}, -@file{c-pragma.c}, -@file{c-semantics.c}, -@file{c-lex.c}, -@file{c-incpath.c}, -@file{c-ppoutput.c}, -@file{c-cppbuiltin.c}, -@file{c-common.h}, -@file{c-dump.h}, -@file{c.opt}, -@file{c-incpath.h} -and -@file{c-pragma.h}, - -Files specific to each language are in subdirectories named after the -language in question, like @file{ada}, @file{objc}, @file{cp} (for C++). - -@cindex Tree optimization -@item -Tree optimization. This is the optimization of the tree -representation, before converting into RTL code. - -@cindex inline on trees, automatic -Currently, the main optimization performed here is tree-based -inlining. -This is implemented in @file{tree-inline.c} and used by both C and C++. -Note that tree based inlining turns off rtx based inlining (since it's more -powerful, it would be a waste of time to do rtx based inlining in -addition). - -@cindex constant folding -@cindex arithmetic simplifications -@cindex simplifications, arithmetic -Constant folding and some arithmetic simplifications are also done -during this pass, on the tree representation. -The routines that perform these tasks are located in @file{fold-const.c}. - -@cindex RTL generation -@item -RTL generation. This is the conversion of syntax tree into RTL code. +@item Remove useless statements + +This pass is an extremely simple sweep across the gimple code in which +we identify obviously dead code and remove it. Here we do things like +simplify @code{if} statements with constant conditions, remove +exception handling constructs surrounding code that obviously cannot +throw, remove lexical bindings that contain no variables, and other +assorted simplistic cleanups. The idea is to get rid of the obvious +stuff quickly rather than wait until later when it's more work to get +rid of it. This pass is located in @file{tree-cfg.c} and described by +@code{pass_remove_useless_stmts}. + +@item Mudflap declaration registration + +If mudflap (@pxref{Optimize Options,,-fmudflap -fmudflapth +-fmudflapir,gcc.info,Using the GNU Compiler Collection (GCC)}) is +enabled, we generate code to register some variable declarations with +the mudflap runtime. Specifically, the runtime tracks the lifetimes of +those variable declarations that have their addresses taken, or whose +bounds are unknown at compile time (@code{extern}). This pass generates +new exception handling constructs (@code{try}/@code{finally}), and so +must run before those are lowered. In addition, the pass enqueues +declarations of static variables whose lifetimes extend to the entire +program. The pass is located in @file{tree-mudflap.c} and is described +by @code{pass_mudflap_1}. + +@item Lower control flow + +This pass flattens @code{if} statements (@code{COND_EXPR}) and +and moves lexical bindings (@code{BIND_EXPR}) out of line. After +this pass, all @code{if} statements will have exactly two @code{goto} +statements in its @code{then} and @code{else} arms. Lexical binding +information for each statement will be found in @code{TREE_BLOCK} rather +than being inferred from its position under a @code{BIND_EXPR}. This +pass is found in @file{gimple-low.c} and is described by +@code{pass_lower_cf}. + +@item Lower exception handling control flow + +This pass decomposes high-level exception handling constructs +(@code{TRY_FINALLY_EXPR} and @code{TRY_CATCH_EXPR}) into a form +that explicitly represents the control flow involved. After this +pass, @code{lookup_stmt_eh_region} will return a non-negative +number for any statement that may have EH control flow semantics; +examine @code{tree_can_throw_internal} or @code{tree_can_throw_external} +for exact semantics. Exact control flow may be extracted from +@code{foreach_reachable_handler}. The EH region nesting tree is defined +in @file{except.h} and built in @file{except.c}. The lowering pass +itself is in @file{tree-eh.c} and is described by @code{pass_lower_eh}. + +@item Build the control flow graph + +This pass decomposes a function into basic blocks and creates all of +the edges that connect them. It is located in @file{tree-cfg.c} and +is described by @code{pass_build_cfg}. + +@item Find all referenced variables + +This pass walks the entire function and collects an array of all +variables referenced in the function, @code{referenced_vars}. The +index at which a variable is found in the array is used as a UID +for the variable within this function. This data is needed by the +SSA rewriting routines. The pass is located in @file{tree-dfa.c} +and is described by @code{pass_referenced_vars}. + +@item Points-to analysis + +This pass constructs flow-insensitive alias analysis information. +The pass is located in @file{tree-alias-common.c} and described by +@code{pass_build_pta}. + +@item Enter static single assignment form + +This pass rewrites the function such that it is in SSA form. After +this pass, all @code{is_gimple_reg} variables will be referenced by +@code{SSA_NAME}, and all occurences of other variables will be +annotated with @code{VDEFS} and @code{VUSES}; phi nodes will have +been inserted as necessary for each basic block. This pass is +located in @file{tree-ssa.c} and is described by @code{pass_build_ssa}. + +@item Warn for uninitialized variables + +This pass scans the function for uses of @code{SSA_NAME}s that +are fed by default definition. For non-parameter variables, such +uses are uninitialized. The pass is run twice, before and after +optimization. In the first pass we only warn for uses that are +positively uninitialized; in the second pass we warn for uses that +are possibly uninitialized. The pass is located in @file{tree-ssa.c} +and is defined by @code{pass_early_warn_uninitialized} and +@code{pass_late_warn_uninitialized}. + +@item Dead code elimination + +This pass scans the function for statements without side effects whose +result is unused. It does not do memory life analysis, so any value +that is stored in memory is considered used. The pass is run multiple +times throughout the optimization process. It is located in +@file{tree-ssa-dce.c} and is described by @code{pass_dce}. + +@item Dominator optimizations + +This pass performs trivial dominator-based copy and constant propagation, +expression simplification, and jump threading. It is run multiple times +throughout the optimization process. It it located in @file{tree-ssa-dom.c} +and is described by @code{pass_dominator}. + +@item Redundant phi elimination + +This pass removes phi nodes for which all of the arguments are the same +value, excluding feedback. Such degenerate forms are typically created +by removing unreachable code. The pass is run multiple times throughout +the optimization process. It is located in @file{tree-ssa.c} and is +described by @code{pass_redundant_phi}.o + +@item Forward propagation of single-use variables + +This pass attempts to remove redundant computation by substituting +variables that are used once into the expression that uses them and +seeing if the result can be simplified. It is located in +@file{tree-ssa-forwprop.c} and is described by @code{pass_forwprop}. + +@item Copy Renaming + +This pass attempts to change the name of compiler temporaries involved in +copy operations such that SSA->normal can coalesce the copy away. When compiler +temporaries are copies of user variables, it also renames the compiler +temporary to the user variable resulting in better use of user symbols. It is +located in @file{tree-ssa-copyrename.c} and is described by +@code{pass_copyrename}. + +@item PHI node optimizations + +This pass recognizes forms of phi inputs that can be represented as +conditional expressions and rewrites them into straight line code. +It is located in @file{tree-ssa-phiopt.c} and is described by +@code{pass_phiopt}. + +@item May-alias optimization + +This pass performs a flow sensitive SSA-based points-to analysis. +The resulting may-alias, must-alias, and escape analysis information +is used to promote variables from in-memory addressable objects to +non-aliased variables that can be renamed into SSA form. We also +update the @code{VDEF}/@code{VUSE} memory tags for non-renamable +aggregates so that we get fewer false kills. The pass is located +in @file{tree-ssa-alias.c} and is described by @code{pass_may_alias}. + +@item Profiling + +This pass rewrites the function in order to collect runtime block +and value profiling data. Such data may be fed back into the compiler +on a subsequent run so as to allow optimization based on expected +execution frequencies. The pass is located in @file{predict.c} and +is described by @code{pass_profile}. + +@item Lower complex arithmetic + +This pass rewrites complex arithmetic operations into their component +scalar arithmetic operations. The pass is located in @file{tree-complex.c} +and is described by @code{pass_lower_complex}. + +@item Scalar replacement of aggregates + +This pass rewrites suitable non-aliased local aggregate variables into +a set of scalar variables. The resulting scalar variables are +rewritten into SSA form, which allows subsequent optimization passes +to do a significantly better job with them. The pass is located in +@file{tree-sra.c} and is described by @code{pass_sra}. + +@item Dead store elimination + +This pass eliminates stores to memory that are subsequently overwritten +by another store, without any intervening loads. The pass is located +in @file{tree-ssa-dse.c} and is described by @code{pass_dse}. + +@item Tail recursion elimination + +This pass transforms tail recursion into a loop. It is located in +@file{tree-tailcall.c} and is described by @code{pass_tail_recursion}. + +@item Partial redundancy elimination + +This pass eliminates partially redundant computations, as well as +performing load motion. The pass is located in @file{tree-ssa-pre.c} +and is described by @code{pass_pre}. + +@item Loop optimization + +TODO: Presumably we're going to do something with loops here. At +present we don't, and this is a placeholder. The pass is located +in @file{tree-ssa-loop.c} and is described by @code{pass_loop}. -@cindex target-parameter-dependent code -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. +@item Conditional constant propagation -@cindex tail recursion optimization -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. +This pass relaxes a lattice of values in order to identify those +that must be constant even in the presence of conditional branches. +The pass is located in @file{tree-ssa-ccp.c} and is described +by @code{pass_ccp}. + +@item Folding builtin functions + +This pass simplifies builtin functions, as applicable, with constant +arguments or with inferrable string lengths. It is located in +@file{tree-ssa-ccp.c} and is described by @code{pass_fold_builtins}. + +@item Split critical edges + +This pass identifies critical edges and inserts empty basic blocks +such that the edge is no longer critical. The pass is located in +@file{tree-cfg.c} and is described by @code{pass_split_crit_edges}. + +@item Partial redundancy elimination + +This pass answers the question ``given a hypothetical temporary +variable, what expressions could we eliminate?'' It is located +in @file{tree-ssa-pre.c} and is described by @code{pass_pre}. + +@item Control dependence dead code elimination + +This pass is a stronger form of dead code elimination that can +eliminate unnecessary control flow statements. It is located +in @file{tree-ssa-dce.c} and is described by @code{pass_cd_dce}. + +@item Tail call elimination + +This pass identifies function calls that may be rewritten into +jumps. No code transformation is actually applied here, but the +data and control flow problem is solved. The code transformation +requires target support, and so is delayed until RTL. In the +meantime @code{CALL_EXPR_TAILCALL} is set indicating the possibility. +The pass is located in @file{tree-tailcall.c} and is described by +@code{pass_tail_calls}. The RTL transformation is handled by +@code{fixup_tail_calls} in @file{calls.c}. + +@item Warn for function return without value + +For non-void functions, this pass locates return statements that do +not specify a value and issues a warning. Such a statement may have +been injected by falling off the end of the function. This pass is +run last so that we have as much time as possible to prove that the +statement is not reachable. It is located in @file{tree-cfg.c} and +is described by @code{pass_warn_function_return}. + +@item Mudflap statement annotation + +If mudflap is enabled, we rewrite some memory accesses with code to +validate that the memory access is correct. In particular, expressions +involving pointer dereferences (@code{INDIRECT_REF}, @code{ARRAY_REF}, +etc.) are replaced by code that checks the selected address range +against the mudflap runtime's database of valid regions. This check +includes an inline lookup into a direct-mapped cache, based on +shift/mask operations of the pointer value, with a fallback function +call into the runtime. The pass is located in @file{tree-mudflap.c} and +is described by @code{pass_mudflap_2}. + +@item Leave static single assignment form + +This pass rewrites the function such that it is in normal form. At +the same time, we eliminate as many single-use temporaries as possible, +so the intermediate language is no longer GIMPLE, but GENERIC. The +pass is located in @file{tree-ssa.c} and is described by @code{pass_del_ssa}. +@end itemize + +@node RTL passes +@section RTL passes + +The following briefly describes the rtl generation and optimization +passes that are run after tree optimization. + +@itemize @bullet +@item RTL generation @c Avoiding overfull is tricky here. The source files for RTL generation include @@ -157,105 +469,32 @@ 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. -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). - -@cindex inline on rtx, automatic -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 GCC@. The file @file{integrate.c} contains -the code to save a function's rtl for later inlining and to inline that -rtl when the function is called. The header file @file{integrate.h} -is also used for this purpose. - -@opindex dr -The option @option{-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. - -@c Should the exception handling pass be talked about here? - -@cindex sibling call optimization -@item -Sibling call optimization. This pass performs tail recursion -elimination, and tail and sibling call optimizations. The purpose of -these optimizations is to reduce the overhead of function calls, -whenever possible. +@item Generate exception handling landing pads -The source file of this pass is @file{sibcall.c} +This pass generates the glue that handles communication between the +exception handling library routines and the exception handlers within +the function. Entry points in the function that are invoked by the +exception handling library are called @dfn{landing pads}. The code +for this pass is located within @file{except.c}. -@opindex di -The option @option{-di} causes a debugging dump of the RTL code after -this pass is run. This dump file's name is made by appending -@samp{.sibling} to the input file name. +@item Cleanup control flow graph -@cindex jump optimization -@cindex unreachable code -@cindex dead code -@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.) It also -converts some code originally written with jumps into sequences of -instructions that directly set values from the results of comparisons, -if the machine has such instructions. - -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}. - -@opindex dj -The option @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 @samp{.jump} to the input file name. - - -@cindex register use analysis -@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}. +This pass removes unreachable code, simplifies jumps to next, jumps to +jump, jumps across jumps, etc. The pass is run multiple times. +For historical reasons, it is occasionally referred to as the ``jump +optimization pass''. The bulk of the code for this pass is in +@file{cfgcleanup.c}, and there are support routines in @file{cfgrtl.c} +and @file{jump.c}. -@cindex jump threading -@item -@opindex fthread-jumps -Jump threading. This pass detects a condition jump that branches to an -identical or inverse test. Such jumps can be @samp{threaded} through -the second conditional test. The source code for this pass is in -@file{jump.c}. This optimization is only performed if -@option{-fthread-jumps} is enabled. - -@cindex common subexpression elimination -@cindex constant propagation -@item -Common subexpression elimination. This pass also does constant -propagation. Its source files are @file{cse.c}, and @file{cselib.c}. -If constant propagation causes conditional jumps to become -unconditional or to become no-ops, jump optimization is run again when -CSE is finished. - -@opindex ds -The option @option{-ds} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.cse} to -the input file name. - -@cindex global common subexpression elimination -@cindex constant propagation -@cindex copy propagation -@item -Global common subexpression elimination. This pass performs two +@item Common subexpression elimination + +This pass removes redundant computation within basic blocks, and +optimizes addressing modes based on cost. The pass is run twice. +The source is located in @file{cse.c}. + +@item Global common subexpression elimination. + +This pass performs two different types of GCSE depending on whether you are optimizing for size or not (LCM based GCSE tends to increase code size for a gain in speed, while Morel-Renvoise based GCSE does not). @@ -270,193 +509,119 @@ based GCSE also does loop invariant code motion. We also perform load and store motion when optimizing for speed. Regardless of which type of GCSE is used, the GCSE pass also performs global constant and copy propagation. - The source file for this pass is @file{gcse.c}, and the LCM routines are in @file{lcm.c}. -@opindex dG -The option @option{-dG} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.gcse} to -the input file name. +@item Loop optimization -@cindex loop optimization -@cindex code motion -@cindex strength-reduction -@item -Loop optimization. This pass moves constant expressions out of loops, +This pass moves constant expressions out of loops, and optionally does strength-reduction and loop unrolling as well. Its source files are @file{loop.c} and @file{unroll.c}, plus the header @file{loop.h} used for communication between them. Loop unrolling uses some functions in @file{integrate.c} and the header @file{integrate.h}. Loop dependency analysis routines are contained in @file{dependence.c}. -Second loop optimization pass takes care of basic block level optimizations -- -unrolling, peeling and unswitching loops. The source files are -@file{cfgloopanal.c} and @file{cfgloopmanip.c} containing generic loop -analysis and manipulation code, @file{loop-init.c} with initialization and -finalization code, @file{loop-unswitch.c} for loop unswitching and -@file{loop-unroll.c} for loop unrolling and peeling. +A second loop optimization pass takes care of basic block level +optimizations---unrolling, peeling and unswitching loops. The source +files are @file{cfgloopanal.c} and @file{cfgloopmanip.c} containing +generic loop analysis and manipulation code, @file{loop-init.c} with +initialization and finalization code, @file{loop-unswitch.c} for loop +unswitching and @file{loop-unroll.c} for loop unrolling and peeling. -@opindex dL -The option @option{-dL} causes a debugging dump of the RTL code after -these passes. The dump file names are made by appending @samp{.loop} and -@samp{.loop2} to the input file name. +@item Jump bypassing -@cindex jump bypassing -@item -Jump bypassing. This pass is an aggressive form of GCSE that transforms -the control flow graph of a function by propagating constants into -conditional branch instructions. +This pass is an aggressive form of GCSE that transforms the control +flow graph of a function by propagating constants into conditional +branch instructions. The source file for this pass is @file{gcse.c}. -The source file for this pass is @file{gcse.c}. +@item If conversion -@opindex dG -The option @option{-dG} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.bypass} -to the input file name. +This pass attempts to replace conditional branches and surrounding +assignments with arithmetic, boolean value producing comparison +instructions, and conditional move instructions. In the very last +invocation after reload, it will generate predicated instructions +when supported by the target. The pass is located in @file{ifcvt.c}. -@cindex web construction -@item -Simple optimization pass that splits independent uses of each pseudo -increasing effect of other optimizations. This can improve effect of the -other transformation, such as CSE or register allocation. -Its source files are @file{web.c}. +@item Web construction -@opindex dZ -The option @option{-dZ} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.web} to -the input file name. +This pass splits independent uses of each pseudo-register. This can +improve effect of the other transformation, such as CSE or register +allocation. Its source files are @file{web.c}. -@item -@opindex frerun-cse-after-loop -If @option{-frerun-cse-after-loop} was enabled, a second common -subexpression elimination pass is performed after the loop optimization -pass. Jump threading is also done again at this time if it was specified. - -@opindex dt -The option @option{-dt} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.cse2} to -the input file name. - -@cindex data flow analysis -@cindex analysis, data flow -@cindex basic blocks -@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. - -@cindex autoincrement/decrement analysis -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. - -@opindex df -The option @option{-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. - -@cindex instruction combination -@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. - -@opindex dc -The option @option{-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. - -@cindex if conversion -@item -If-conversion is a transformation that transforms control dependencies -into data dependencies (IE it transforms conditional code into a -single control stream). -It is implemented in the file @file{ifcvt.c}. +@item Life analysis -@opindex dE -The option @option{-dE} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.ce} to -the input file name. +This pass 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. It then deletes +computations whose results are never used, and combines memory +references with add or subtract instructions to make autoincrement or +autodecrement addressing. The pass is located in @file{flow.c}. -@cindex register movement -@item -Register movement (@file{regmove.c}). This pass looks for cases where -matching constraints would force an instruction to need a reload, and -this reload would be a register-to-register move. It then attempts -to change the registers used by the instruction to avoid the move -instruction. - -@opindex dN -The option @option{-dN} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.regmove} -to the input file name. - -@cindex instruction scheduling -@cindex scheduling, instruction -@item -Instruction scheduling (@file{sched.c}). This pass looks for -instructions whose output will not be available by the time that it is -used in subsequent instructions. (Memory loads and floating point -instructions often have this behavior on RISC machines). It re-orders -instructions within a basic block to try to separate the definition and -use of items that otherwise would cause pipeline stalls. - -Instruction scheduling is performed twice. The first time is immediately -after instruction combination and the second is immediately after reload. - -@opindex dS -The option @option{-dS} causes a debugging dump of the RTL code after this -pass is run for the first time. The dump file's name is made by -appending @samp{.sched} to the input file name. - -@cindex register allocation -@item -Register allocation. These passes make sure that all occurrences of pseudo -registers are eliminated, either by allocating them to a hard register, -replacing them by an equivalent expression (e.g.@: a constant) or by placing +@item Instruction combination + +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 pass is located in @file{combine.c}. + +@item Register movement + +This pass looks for cases where matching constraints would force an +instruction to need a reload, and this reload would be a +register-to-register move. It then attempts to change the registers +used by the instruction to avoid the move instruction. +The pass is located in @file{regmove.c}. + +@item Optimize mode switching + +This pass looks for instructions that require the processor to be in a +specific ``mode'' and minimizes the number of mode changes required to +satisfy all users. What these modes are, and what they apply to are +completely target-specific. The source is located in @file{lcm.c}. + +@item Instruction scheduling + +This pass looks for instructions whose output will not be available by +the time that it is used in subsequent instructions. Memory loads and +floating point instructions often have this behavior on RISC machines. +It re-orders instructions within a basic block to try to separate the +definition and use of items that otherwise would cause pipeline +stalls. This pass is performed twice, before and after register +allocation. The pass is located in @file{haifa-sched.c}, +@file{sched-deps.c}, @file{sched-ebb.c}, @file{sched-rgn.c} and +@file{sched-vis.c}. + +@item Register allocation + +These passes make sure that all occurrences of pseudo registers are +eliminated, either by allocating them to a hard register, replacing +them by an equivalent expression (e.g.@: a constant) or by placing them on the stack. This is done in several subpasses: @itemize @bullet -@cindex register class preference pass @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}. -@cindex local register allocation @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. - -@opindex dl -The option @option{-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. +Local register allocation. 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 decent job. The source is located in @file{local-alloc.c}. -@cindex global register allocation @item -Global register allocation (@file{global.c}). This pass -allocates hard registers for the remaining pseudo registers (those -whose life spans are not contained in one basic block). +Global register allocation. This pass allocates hard registers for +the remaining pseudo registers (those whose life spans are not +contained in one basic block). The pass is located in @file{global.c}. -@cindex graph coloring register allocation -@opindex fnew-ra -@opindex dl @item Graph coloring register allocator. The files @file{ra.c}, @file{ra-build.c}, @file{ra-colorize.c}, @file{ra-debug.c}, @file{ra-rewrite.c} together with the header @file{ra.h} contain another register allocator, which is used when the option @option{-fnew-ra} is given. In that case it is run instead -of the above mentioned local and global register allocation passes, and the -option @option{-dl} causes a debugging dump of its work. +of the above mentioned local and global register allocation passes. @cindex reloading @item @@ -474,165 +639,65 @@ instructions to save and restore call-clobbered registers around calls. Source files are @file{reload.c} and @file{reload1.c}, plus the header @file{reload.h} used for communication between them. - -@opindex dg -The option @option{-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. @end itemize -@cindex instruction scheduling -@cindex scheduling, instruction -@item -Instruction scheduling is repeated here to try to avoid pipeline stalls -due to memory loads generated for spilled pseudo registers. +@item Basic block reordering -@opindex dR -The option @option{-dR} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.sched2} -to the input file name. +This pass implements profile guided code positioning. If profile +information is not available, various types of static analysis are +performed to make the predictions normally coming from the profile +feedback (IE execution frequency, branch probability, etc). It is +implemented in the file @file{bb-reorder.c}, and the various +prediction routines are in @file{predict.c}. -@cindex basic block reordering -@cindex reordering, block -@item -Basic block reordering. This pass implements profile guided code -positioning. If profile information is not available, various types of -static analysis are performed to make the predictions normally coming -from the profile feedback (IE execution frequency, branch probability, -etc). It is implemented in the file @file{bb-reorder.c}, and the -various prediction routines are in @file{predict.c}. - -@opindex dB -The option @option{-dB} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.bbro} to -the input file name. - -@cindex variable tracking -@item -Variable tracking. This pass computes where the variables are stored at each +@item Variable tracking + +This pass computes where the variables are stored at each position in code and generates notes describing the variable locations to RTL code. The location lists are then generated according to these notes to debug information if the debugging information format supports location lists. -@opindex dV -The option @option{-dV} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.vartrack} -to the input file name. +@item Delayed branch scheduling -@cindex delayed branch scheduling -@cindex scheduling, delayed branch -@item -Delayed branch scheduling. This optional pass attempts to find -instructions that can go into the delay slots of other instructions, -usually jumps and calls. The source file name is @file{reorg.c}. +This optional pass attempts to find instructions that can go into the +delay slots of other instructions, usually jumps and calls. The +source file name is @file{reorg.c}. -@opindex dd -The option @option{-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 Branch shortening + +On many RISC machines, branch instructions have a limited range. +Thus, longer sequences of instructions must be used for long branches. +In this pass, the compiler figures out what how far each instruction +will be from each other instruction, and therefore whether the usual +instructions, or the longer sequences, must be used for each branch. + +@item Register-to-stack conversion -@cindex branch shortening -@item -Branch shortening. On many RISC machines, branch instructions have a -limited range. Thus, longer sequences of instructions must be used for -long branches. In this pass, the compiler figures out what how far each -instruction will be from each other instruction, and therefore whether -the usual instructions, or the longer sequences, must be used for each -branch. - -@cindex register-to-stack conversion -@item Conversion from usage of some hard registers to usage of a register stack may be done at this point. Currently, this is supported only for the floating-point registers of the Intel 80387 coprocessor. The source file name is @file{reg-stack.c}. -@opindex dk -The options @option{-dk} causes a debugging dump of the RTL code after -this pass. This dump file's name is made by appending @samp{.stack} -to the input file name. +@item Final -@cindex final pass -@cindex peephole optimization -@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. - -@cindex debugging information generation -@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, @file{sdbout.c} for SDB symbol table format, @file{dwarfout.c} -for DWARF symbol table format, files @file{dwarf2out.c} and -@file{dwarf2asm.c} for DWARF2 symbol table format, and @file{vmsdbgout.c} -for VMS debug symbol table format. -@end itemize +This pass outputs the assembler code for the function. 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. If mudflap is enabled, the queue of deferred declarations +and any addressed constants (e.g., string literals) is processed by +@code{mudflap_finish_file} into a synthetic constructor function +containing calls into the mudflap runtime. -Some additional files are used by all or many passes: +@item Debugging information output -@itemize @bullet -@item -Every pass uses @file{machmode.def} and @file{machmode.h} which define -the machine modes. - -@item -Several passes use @file{real.h}, which defines the default -representation of floating point constants and how to operate on them. +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, @file{sdbout.c} for +SDB symbol table format, @file{dwarfout.c} for DWARF symbol table +format, files @file{dwarf2out.c} and @file{dwarf2asm.c} for DWARF2 +symbol table format, and @file{vmsdbgout.c} for VMS debug symbol table +format. -@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 -All the tools that read the machine description use support routines -found in @file{gensupport.c}, @file{errors.c}, and @file{read-rtl.c}. - -@findex genconfig -@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}. - -@cindex instruction recognizer -@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}. - -@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. - -@item -Several passes use instruction attributes. A definition of the -attributes defined for a particular machine is in file -@file{insn-attr.h}, which is generated from the machine description by -the program @file{genattr}. The file @file{insn-attrtab.c} contains -subroutines to obtain the attribute values for insns and information -about processor pipeline characteristics for the instruction -scheduler. It is generated from the machine description by the -program @file{genattrtab}. @end itemize diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index 746bca587bd..c5e8d33c15b 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -722,7 +722,6 @@ computation performed by this instruction, i.e., one that This flag is required for exception handling support on targets with RTL prologues. -@findex RTX_INTEGRATED_P @cindex @code{insn} and @samp{/i} @cindex @code{call_insn} and @samp{/i} @cindex @code{jump_insn} and @samp{/i} @@ -732,8 +731,6 @@ prologues. @cindex @code{const} and @samp{/i} @cindex @code{note} and @samp{/i} @cindex @code{integrated}, in @code{insn}, @code{call_insn}, @code{jump_insn}, @code{barrier}, @code{code_label}, @code{insn_list}, @code{const}, and @code{note} -@item RTX_INTEGRATED_P (@var{x}) -Nonzero in an @code{insn}, @code{call_insn}, @code{jump_insn}, @code{barrier}, @code{code_label}, @code{insn_list}, @code{const}, or @code{note} if it resulted from an in-line function call. Stored in the @code{integrated} field and printed as @samp{/i}. diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 8868d193b88..03a450a2b99 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -54,6 +54,9 @@ Headers for the @code{libiberty} library. The Ada runtime library. @item libf2c +The Fortran 77 runtime library. + +@item libgfortran The Fortran runtime library. @item libffi @@ -700,6 +703,10 @@ If defined, a space-separated list of files that should be scanned by gengtype.c to generate the garbage collection tables and routines for this language. This excludes the files that are common to all front ends. @xref{Type Information}. +@item need_gmp +If defined to @samp{yes}, this frontend requires the GMP library. +Enables configure tests for GMP, which set @code{GMPLIBS} and +@code{GMPINC} appropriately. @end table diff --git a/gcc/doc/standards.texi b/gcc/doc/standards.texi index b8a44d40e69..df14c0f143d 100644 --- a/gcc/doc/standards.texi +++ b/gcc/doc/standards.texi @@ -186,7 +186,10 @@ GNAT Reference Manual}, for information on standard conformance and compatibility of the Ada compiler. @xref{Language,,The GNU Fortran Language, g77, Using and Porting GNU -Fortran}, for details of the Fortran language supported by GCC@. +Fortran}, for details of the Fortran language supported by @command{g77}. + +@xref{Standards,,Standards, gfortran, The GNU Fortran 95 Compiler}, for details +of standards supported by @command{gfortran}. @xref{Compatibility,,Compatibility with the Java Platform, gcj, GNU gcj}, for details of compatibility between @command{gcj} and the Java Platform. diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 85515bf0b3c..339dc7ad1c4 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -8781,16 +8781,6 @@ being called, in @code{call} RTL expressions. On most machines this should be @code{QImode}. @end defmac -@defmac INTEGRATE_THRESHOLD (@var{decl}) -A C expression for the maximum number of instructions above which the -function @var{decl} should not be inlined. @var{decl} is a -@code{FUNCTION_DECL} node. - -The default definition of this macro is 64 plus 8 times the number of -arguments that the function accepts. Some people think a larger -threshold should be used on RISC machines. -@end defmac - @defmac STDC_0_IN_SYSTEM_HEADERS In normal operation, the preprocessor expands @code{__STDC__} to the constant 1, to signify that GCC conforms to ISO Standard C@. On some diff --git a/gcc/doc/tree-ssa.texi b/gcc/doc/tree-ssa.texi new file mode 100644 index 00000000000..56ccd6109c2 --- /dev/null +++ b/gcc/doc/tree-ssa.texi @@ -0,0 +1,1189 @@ +@c Copyright (c) 2004 Free Software Foundation, Inc. +@c Free Software Foundation, Inc. +@c This is part of the GCC manual. +@c For copying conditions, see the file gcc.texi. + +@c --------------------------------------------------------------------- +@c Tree SSA +@c --------------------------------------------------------------------- + +@node Tree SSA +@chapter Analysis and Optimization of GIMPLE Trees +@cindex Tree SSA +@cindex Optimization infrastructure for GIMPLE + +GCC uses three main intermediate languages to represent the program +during compilation: GENERIC, GIMPLE and RTL@. GENERIC is a +language-independent representation generated by each front end. It +is used to serve as an interface between the parser and optimizer. +GENERIC is a common representation that is able to represent programs +written in all the languages supported by GCC@. + +GIMPLE and RTL are used to optimize the program. GIMPLE is used for +target and language independent optimizations (e.g., inlining, +constant propagation, tail call elimination, redundancy elimination, +etc). Much like GENERIC, GIMPLE is a language independent, tree based +representation. However, it differs from GENERIC in that the GIMPLE +grammar is more restrictive: expressions contain no more than 3 +operands (except function calls), it has no control flow structures +and expressions with side-effects are only allowed on the right hand +side of assignments. See the chapter describing GENERIC and GIMPLE +for more details. + +This chapter describes the data structures and functions used in the +GIMPLE optimizers (also known as ``tree optimizers'' or ``middle +end''). In particular, it focuses on all the macros, data structures, +functions and programming constructs needed to implement optimization +passes for GIMPLE@. + +@menu +* GENERIC:: A high-level language-independent representation. +* GIMPLE:: A lower-level factored tree representation. +* Annotations:: Attributes for statements and variables. +* Statement Operands:: Variables referenced by GIMPLE statements. +* SSA:: Static Single Assignment representation. +* Alias analysis:: Representing aliased loads and stores. +@end menu + +@node GENERIC +@section GENERIC +@cindex GENERIC + +The purpose of GENERIC is simply to provide a language-independent way of +representing an entire function in trees. To this end, it was necessary to +add a few new tree codes to the back end, but most everything was already +there. If you can express it with the codes in @code{gcc/tree.def}, it's +GENERIC. + +Early on, there was a great deal of debate about how to think about +statements in a tree IL. In GENERIC, a statement is defined as any +expression whose value, if any, is ignored. A statement will always +have @code{TREE_SIDE_EFFECTS} set (or it will be discarded), but a +non-statement expression may also have side effects. A +@code{CALL_EXPR}, for instance. + +It would be possible for some local optimizations to work on the +GENERIC form of a function; indeed, the adapted tree inliner works +fine on GENERIC, but the current compiler performs inlining after +lowering to GIMPLE (a restricted form described in the next section). +Indeed, currently the frontends perform this lowering before handing +off to @code{tree_rest_of_compilation}, but this seems inelegant. + +If necessary, a front end can use some language-dependent tree codes +in its GENERIC representation, so long as it provides a hook for +converting them to GIMPLE and doesn't expect them to work with any +(hypothetical) optimizers that run before the conversion to GIMPLE. +The intermediate representation used while parsing C and C++ looks +very little like GENERIC, but the C and C++ gimplifier hooks are +perfectly happy to take it as input and spit out GIMPLE. + +@node GIMPLE +@section GIMPLE +@cindex GIMPLE + +GIMPLE is a simplified subset of GENERIC for use in optimization. The +particular subset chosen (and the name) was heavily influenced by the +SIMPLE IL used by the McCAT compiler project at McGill University, +though we have made some different choices. For one thing, SIMPLE +doesn't support @code{goto}; a production compiler can't afford that +kind of restriction. + +GIMPLE retains much of the structure of the parse trees: lexical +scopes are represented as containers, rather than markers. However, +expressions are broken down into a 3-address form, using temporary +variables to hold intermediate values. Also, control structures are +lowered to gotos. + +In GIMPLE no container node is ever used for its value; if a +@code{COND_EXPR} or @code{BIND_EXPR} has a value, it is stored into a +temporary within the controlled blocks, and that temporary is used in +place of the container. + +The compiler pass which lowers GENERIC to GIMPLE is referred to as the +@samp{gimplifier}. The gimplifier works recursively, replacing complex +statements with sequences of simple statements. + +@c Currently, the only way to +@c tell whether or not an expression is in GIMPLE form is by recursively +@c examining it; in the future there will probably be a flag to help avoid +@c redundant work. FIXME FIXME + +@menu +* Interfaces:: +* Temporaries:: +* GIMPLE Expressions:: +* Statements:: +* GIMPLE Example:: +* Rough GIMPLE Grammar:: +@end menu + +@node Interfaces +@subsection Interfaces +@cindex gimplification + +The tree representation of a function is stored in +@code{DECL_SAVED_TREE}. It is lowered to GIMPLE by a call to +@code{gimplify_function_tree}. + +If a front end wants to include language-specific tree codes in the tree +representation which it provides to the back end, it must provide a +definition of @code{LANG_HOOKS_GIMPLIFY_EXPR} which knows how to +convert the front end trees to GIMPLE. Usually such a hook will involve +much of the same code for expanding front end trees to RTL. This function +can return fully lowered GIMPLE, or it can return GENERIC trees and let the +main gimplifier lower them the rest of the way; this is often simpler. + +The C and C++ front ends currently convert directly from front end +trees to GIMPLE, and hand that off to the back end rather than first +converting to GENERIC. Their gimplifier hooks know about all the +@code{_STMT} nodes and how to convert them to GENERIC forms. There +was some work done on a genericization pass which would run first, but +the existence of @code{STMT_EXPR} meant that in order to convert all +of the C statements into GENERIC equivalents would involve walking the +entire tree anyway, so it was simpler to lower all the way. This +might change in the future if someone writes an optimization pass +which would work better with higher-level trees, but currently the +optimizers all expect GIMPLE. + +A front end which wants to use the tree optimizers (and already has +some sort of whole-function tree representation) only needs to provide +a definition of @code{LANG_HOOKS_GIMPLIFY_EXPR}, call +@code{gimplify_function_tree} to lower to GIMPLE, and then hand off to +@code{tree_rest_of_compilation} to compile and output the function. + +You can tell the compiler to dump a C-like representation of the GIMPLE +form with the flag @code{-fdump-tree-gimple}. + +@node Temporaries +@subsection Temporaries +@cindex Temporaries + +When gimplification encounters a subexpression which is too complex, it +creates a new temporary variable to hold the value of the subexpression, +and adds a new statement to initialize it before the current statement. +These special temporaries are known as @samp{expression temporaries}, and are +allocated using @code{get_formal_tmp_var}. The compiler tries to +always evaluate identical expressions into the same temporary, to simplify +elimination of redundant calculations. + +We can only use expression temporaries when we know that it will not be +reevaluated before its value is used, and that it will not be otherwise +modified@footnote{These restrictions are derived from those in Morgan 4.8.}. +Other temporaries can be allocated using +@code{get_initialized_tmp_var} or @code{create_tmp_var}. + +Currently, an expression like @code{a = b + 5} is not reduced any +further. We tried converting it to something like +@smallexample + T1 = b + 5; + a = T1; +@end smallexample +but this bloated the representation for minimal benefit. However, a +variable which must live in memory cannot appear in an expression; its +value is explicitly loaded into a temporary first. Similarly, storing +the value of an expression to a memory variable goes through a +temporary. + +@node GIMPLE Expressions +@subsection Expressions +@cindex GIMPLE Expressions + +In general, expressions in GIMPLE consist of an operation and the +appropriate number of simple operands; these operands must either be a +GIMPLE rvalue (@code{is_gimple_val}), i.e. a constant or a register +variable. More complex operands are factored out into temporaries, so +that +@smallexample + a = b + c + d +@end smallexample +becomes +@smallexample + T1 = b + c; + a = T1 + d; +@end smallexample + +The same rule holds for arguments to a @code{CALL_EXPR}. + +The target of an assignment is usually a variable, but can also be an +@code{INDIRECT_REF} or a compound lvalue as described below. + +@menu +* Compound Expressions:: +* Compound Lvalues:: +* Conditional Expressions:: +* Logical Operators:: +@end menu + +@node Compound Expressions +@subsubsection Compound Expressions +@cindex Compound Expressions + +The left-hand side of a C comma expression is simply moved into a separate +statement. + +@node Compound Lvalues +@subsubsection Compound Lvalues +@cindex Compound Lvalues + +Currently compound lvalues involving array and structure field references +are not broken down; an expression like @code{a.b[2] = 42} is not reduced +any further (though complex array subscripts are). This restriction is a +workaround for limitations in later optimizers; if we were to convert this +to + +@smallexample + T1 = &a.b; + T1[2] = 42; +@end smallexample + +alias analysis would not remember that the reference to @code{T1[2]} came +by way of @code{a.b}, so it would think that the assignment could alias +another member of @code{a}; this broke @code{struct-alias-1.c}. Future +optimizer improvements may make this limitation unnecessary. + +@node Conditional Expressions +@subsubsection Conditional Expressions +@cindex Conditional Expressions + +A C @code{?:} expression is converted into an @code{if} statement with +each branch assigning to the same temporary. So, + +@smallexample + a = b ? c : d; +@end smallexample +becomes +@smallexample + if (b) + T1 = c; + else + T1 = d; + a = T1; +@end smallexample + +Note that in GIMPLE, @code{if} statements are also represented using +@code{COND_EXPR}, as described below. + +@node Logical Operators +@subsubsection Logical Operators +@cindex Logical Operators + +Except when they appear in the condition operand of a @code{COND_EXPR}, +logical `and' and `or' operators are simplified as follows: +@code{a = b && c} becomes + +@smallexample + T1 = (bool)b; + if (T1) + T1 = (bool)c; + a = T1; +@end smallexample + +Note that @code{T1} in this example cannot be an expression temporary, +because it has two different assignments. + +@node Statements +@subsection Statements +@cindex Statements + +Most statements will be assignment statements, represented by +@code{MODIFY_EXPR}. A @code{CALL_EXPR} whose value is ignored can +also be a statement. No other C expressions can appear at statement level; +a reference to a volatile object is converted into a @code{MODIFY_EXPR}. + +There are also several varieties of complex statements. + +@menu +* Blocks:: +* Statement Sequences:: +* Empty Statements:: +* Loops:: +* Selection Statements:: +* Jumps:: +* Cleanups:: +* GIMPLE Exception Handling:: +@end menu + +@node Blocks +@subsubsection Blocks +@cindex Blocks + +Block scopes and the variables they declare in GENERIC and GIMPLE are +expressed using the @code{BIND_EXPR} code, which in previous versions of +GCC was primarily used for the C statement-expression extension. + +Variables in a block are collected into @code{BIND_EXPR_VARS} in +declaration order. Any runtime initialization is moved out of +@code{DECL_INITIAL} and into a statement in the controlled block. When +gimplifying from C or C++, this initialization replaces the +@code{DECL_STMT}. + +Variable-length arrays (VLAs) complicate this process, as their size often +refers to variables initialized earlier in the block. To handle this, we +currently split the block at that point, and move the VLA into a new, inner +@code{BIND_EXPR}. This strategy may change in the future. + +@code{DECL_SAVED_TREE} for a GIMPLE function will always be a +@code{BIND_EXPR} which contains declarations for the temporary variables +used in the function. + +A C++ program will usually contain more @code{BIND_EXPR}s than there are +syntactic blocks in the source code, since several C++ constructs have +implicit scopes associated with them. On the other hand, although the C++ +front end uses pseudo-scopes to handle cleanups for objects with +destructors, these don't translate into the GIMPLE form; multiple +declarations at the same level use the same BIND_EXPR. + +@node Statement Sequences +@subsubsection Statement Sequences +@cindex Statement Sequences + +Multiple statements at the same nesting level are collected into a +@code{STATEMENT_LIST}. Statement lists are modified and traversed +using the interface in @samp{tree-iterator.h}. + +@node Empty Statements +@subsubsection Empty Statements +@cindex Empty Statements + +Whenever possible, statements with no effect are discarded. But if they +are nested within another construct which cannot be discarded for some +reason, they are instead replaced with an empty statement, generated by +@code{build_empty_stmt}. Initially, all empty statements were shared, +after the pattern of the Java front end, but this caused a lot of trouble in +practice. + +An empty statement is represented as @code{(void)0}. + +@node Loops +@subsubsection Loops +@cindex Loops + +At one time loops were expressed in GIMPLE using @code{LOOP_EXPR}, but +now they are lowered to explicit gotos. + +@node Selection Statements +@subsubsection Selection Statements +@cindex Selection Statements + +A simple selection statement, such as the C @code{if} statement, is +expressed in GIMPLE using a void @code{COND_EXPR}. If only one branch is +used, the other is filled with an empty statement. + +Normally, the condition expression is reduced to a simple comparison. If +it is a shortcut (@code{&&} or @code{||}) expression, however, we try to +break up the @code{if} into multiple @code{if}s so that the implied shortcut +is taken directly, much like the transformation done by @code{do_jump} in +the RTL expander. + +A @code{SWITCH_EXPR} in GIMPLE contains the condition and a +@code{TREE_VEC} of @code{CASE_LABEL_EXPR}s describing the case values +and corresponding @code{LABEL_DECL}s to jump to. The body of the +@code{switch} is moved after the @code{SWITCH_EXPR}. + +@node Jumps +@subsubsection Jumps +@cindex Jumps + +Other jumps are expressed by either @code{GOTO_EXPR} or @code{RETURN_EXPR}. + +The operand of a @code{GOTO_EXPR} must be either a label or a variable +containing the address to jump to. + +The operand of a @code{RETURN_EXPR} is either @code{NULL_TREE} or a +@code{MODIFY_EXPR} which sets the return value. It would be nice to +move the @code{MODIFY_EXPR} into a separate statement, but the special +return semantics in @code{expand_return} make that difficult. It may +still happen in the future, perhaps by moving most of that logic into +@code{expand_assignment}. + +@node Cleanups +@subsubsection Cleanups +@cindex Cleanups + +Destructors for local C++ objects and similar dynamic cleanups are +represented in GIMPLE by a @code{TRY_FINALLY_EXPR}. When the controlled +block exits, the cleanup is run. + +@code{TRY_FINALLY_EXPR} complicates the flow graph, since the cleanup +needs to appear on every edge out of the controlled block; this +reduces our freedom to move code across these edges. Therefore, the +EH lowering pass which runs before most of the optimization passes +eliminates these expressions by explicitly adding the cleanup to each +edge. + +@node GIMPLE Exception Handling +@subsubsection Exception Handling +@cindex GIMPLE Exception Handling + +Other exception handling constructs are represented using +@code{TRY_CATCH_EXPR}. The handler operand of a @code{TRY_CATCH_EXPR} +can be a normal statement to be executed if the controlled block throws an +exception, or it can have one of two special forms: + +@enumerate +@item A @code{CATCH_EXPR} executes its handler if the thrown exception + matches one of the allowed types. Multiple handlers can be + expressed by a sequence of @code{CATCH_EXPR} statements. +@item An @code{EH_FILTER_EXPR} executes its handler if the thrown + exception does not match one of the allowed types. +@end enumerate + +Currently throwing an exception is not directly represented in GIMPLE, +since it is implemented by calling a function. At some point in the future +we will want to add some way to express that the call will throw an +exception of a known type. + +Just before running the optimizers, the compiler lowers the high-level +EH constructs above into a set of @samp{goto}s, magic labels, and EH +regions. Continuing to unwind at the end of a cleanup is represented +with a @code{RESX_EXPR}. + +@node GIMPLE Example +@subsection GIMPLE Example +@cindex GIMPLE Example + +@smallexample +struct A @{ A(); ~A(); @}; + +int i; +int g(); +void f() +@{ + A a; + int j = (--i, i ? 0 : 1); + + for (int x = 42; x > 0; --x) + @{ + i += g()*4 + 32; + @} +@} +@end smallexample + +becomes + +@smallexample +void f() +@{ + int i.0; + int T.1; + int iftmp.2; + int T.3; + int T.4; + int T.5; + int T.6; + + @{ + struct A a; + int j; + + __comp_ctor (&a); + try + @{ + i.0 = i; + T.1 = i.0 - 1; + i = T.1; + i.0 = i; + if (i.0 == 0) + iftmp.2 = 1; + else + iftmp.2 = 0; + j = iftmp.2; + @{ + int x; + + x = 42; + goto test; + loop:; + + T.3 = g (); + T.4 = T.3 * 4; + i.0 = i; + T.5 = T.4 + i.0; + T.6 = T.5 + 32; + i = T.6; + x = x - 1; + + test:; + if (x > 0) + goto loop; + else + goto break_; + break_:; + @} + @} + finally + @{ + __comp_dtor (&a); + @} + @} +@} +@end smallexample + +@node Rough GIMPLE Grammar +@subsection Rough GIMPLE Grammar +@cindex Rough GIMPLE Grammar + +@smallexample +function: + FUNCTION_DECL + DECL_SAVED_TREE -> block +block: + BIND_EXPR + BIND_EXPR_VARS -> DECL chain + BIND_EXPR_BLOCK -> BLOCK + BIND_EXPR_BODY + -> compound-stmt +compound-stmt: + COMPOUND_EXPR + op0 -> non-compound-stmt + op1 -> stmt +stmt: compound-stmt + | non-compound-stmt +non-compound-stmt: + block + | if-stmt + | switch-stmt + | jump-stmt + | label-stmt + | try-stmt + | modify-stmt + | call-stmt +if-stmt: + COND_EXPR + op0 -> condition + op1 -> stmt + op2 -> stmt +switch-stmt: + SWITCH_EXPR + op0 -> val + op1 -> NULL_TREE + op2 -> TREE_VEC of CASE_LABEL_EXPRs +jump-stmt: + GOTO_EXPR + op0 -> LABEL_DECL | '*' ID + | RETURN_EXPR + op0 -> modify-stmt + | NULL_TREE +label-stmt: + LABEL_EXPR + op0 -> LABEL_DECL +try-stmt: + TRY_CATCH_EXPR + op0 -> stmt + op1 -> handler + | TRY_FINALLY_EXPR + op0 -> stmt + op1 -> stmt +handler: + catch-seq + | EH_FILTER_EXPR + | stmt +catch-seq: + CATCH_EXPR + | COMPOUND_EXPR + op0 -> CATCH_EXPR + op1 -> catch-seq +modify-stmt: + MODIFY_EXPR + op0 -> lhs + op1 -> rhs +call-stmt: CALL_EXPR + op0 -> _DECL | '&' _DECL + op1 -> arglist +arglist: + NULL_TREE + | TREE_LIST + op0 -> val + op1 -> arglist + +varname : compref | _DECL +lhs: varname | '*' _DECL +pseudo-lval: _DECL | '*' _DECL +compref : + COMPONENT_REF + op0 -> compref | pseudo-lval + | ARRAY_REF + op0 -> compref | pseudo-lval + op1 -> val + +condition : val | val relop val +val : _DECL | CONST + +rhs: varname | CONST + | '*' _DECL + | '&' varname + | call_expr + | unop val + | val binop val + | '(' cast ')' val + +unop: '+' | '-' | '!' | '~' + +binop: relop | '-' | '+' | '/' | '*' + | '%' | '&' | '|' | '<<' | '>>' | '^' + +relop: All tree codes of class '<' +@end smallexample + +@node Annotations +@section Annotations +@cindex annotations + +The optimizers need to associate attributes with statements and +variables during the optimization process. For instance, we need to +know what basic block does a statement belong to or whether a variable +has aliases. All these attributes are stored in data structures +called annotations which are then linked to the field @code{ann} in +@code{struct tree_common}. + +Presently, we define annotations for statements (@code{stmt_ann_t}), +variables (@code{var_ann_t}) and SSA names (@code{ssa_name_ann_t}). +Annotations are defined and documented in @file{tree-flow.h}. + + +@node Statement Operands +@section Statement Operands +@cindex operands +@cindex virtual operands +@cindex real operands +@findex get_stmt_operands +@findex modify_stmt + +Almost every GIMPLE statement will contain a reference to a variable +or memory location. Since statements come in different shapes and +sizes, their operands are going to be located at various spots inside +the statement's tree. To facilitate access to the statement's +operands, they are organized into arrays associated inside each +statement's annotation. Each element in an operand array is a pointer +to a @code{VAR_DECL}, @code{PARM_DECL} or @code{SSA_NAME} tree node. +This provides a very convenient way of examining and replacing +operands. + +Data flow analysis and optimization is done on all tree nodes +representing variables. Any node for which @code{SSA_VAR_P} returns +nonzero is considered when scanning statement operands. However, not +all @code{SSA_VAR_P} variables are processed in the same way. For the +purposes of optimization, we need to distinguish between references to +local scalar variables and references to globals, statics, structures, +arrays, aliased variables, etc. The reason is simple, the compiler +can gather complete data flow information for a local scalar. On the +other hand, a global variable may be modified by a function call, it +may not be possible to keep track of all the elements of an array or +the fields of a structure, etc. + +The operand scanner gathers two kinds of operands: @dfn{real} and +@dfn{virtual}. An operand for which @code{is_gimple_reg} returns true +is considered real, otherwise it is a virtual operand. We also +distinguish between uses and definitions. An operand is used if its +value is loaded by the statement (e.g., the operand at the RHS of an +assignment). If the statement assigns a new value to the operand, the +operand is considered a definition (e.g., the operand at the LHS of +an assignment). + +Virtual and real operands also have very different data flow +properties. Real operands are unambiguous references to the +full object that they represent. For instance, given + +@smallexample +@{ + int a, b; + a = b +@} +@end smallexample + +Since @code{a} and @code{b} are non-aliased locals, the statement +@code{a = b} will have one real definition and one real use because +variable @code{b} is completely modified with the contents of +variable @code{a}. Real definition are also known as @dfn{killing +definitions}. Similarly, the use of @code{a} reads all its bits. + +In contrast, virtual operands represent partial or ambiguous +references to a variable. For instance, given + +@smallexample +@{ + int a, b, *p; + + if (...) + p = &a; + else + p = &b; + *p = 5; + return *p; +@} +@end smallexample + +The assignment @code{*p = 5} may be a definition of @code{a} or +@code{b}. If we cannot determine statically where @code{p} is +pointing to at the time of the store operation, we create virtual +definitions to mark that statement as a potential definition site for +@code{a} and @code{b}. Memory loads are similarly marked with virtual +use operands. Virtual operands are shown in tree dumps right before +the statement that contains them. To request a tree dump with virtual +operands, use the @option{-vops} option to @option{-fdump-tree}: + +@smallexample +@{ + int a, b, *p; + + if (...) + p = &a; + else + p = &b; + # a = VDEF + # b = VDEF + *p = 5; + + # VUSE + # VUSE + return *p; +@} +@end smallexample + +Notice that @code{VDEF} operands have two copies of the referenced +variable. This indicates that this is not a killing definition of +that variable. In this case we refer to it as a @dfn{may definition} +or @dfn{aliased store}. The presence of the second copy of the +variable in the @code{VDEF} operand will become important when the +function is converted into SSA form. This will be used to link all +the non-killing definitions to prevent optimizations from making +incorrect assumptions about them. + +Operands are collected by @file{tree-ssa-operands.c}. They are stored +inside each statement's annotation and can be accessed with +@code{DEF_OPS}, @code{USE_OPS}, @code{VDEF_OPS} and @code{VUSE_OPS}. +The following are all the accessor macros available to access USE +operands. To access all the other operand arrays, just change the +name accordingly: + +@defmac USE_OPS (@var{ann}) +Returns the array of operands used by the statement with annotation +@var{ann}. +@end defmac + +@defmac STMT_USE_OPS (@var{stmt}) +Alternate version of USE_OPS that takes the statement @var{stmt} as +input. +@end defmac + +@defmac NUM_USES (@var{ops}) +Return the number of USE operands in array @var{ops}. +@end defmac + +@defmac USE_OP_PTR (@var{ops}, @var{i}) +Return a pointer to the @var{i}th operand in array @var{ops}. +@end defmac + +@defmac USE_OP (@var{ops}, @var{i}) +Return the @var{i}th operand in array @var{ops}. +@end defmac + +The following function shows how to print all the operands of a given +statement: + +@smallexample +void +print_ops (tree stmt) +@{ + vuse_optype vuses; + vdef_optype vdefs; + def_optype defs; + use_optype uses; + stmt_ann_t ann; + size_t i; + + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + print_generic_expr (stderr, DEF_OP (defs, i), 0); + + uses = USE_OPS (ann); + for (i = 0; i < NUM_USES (uses); i++) + print_generic_expr (stderr, USE_OP (uses, i), 0); + + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + print_generic_expr (stderr, VDEF_OP (vdefs, i), 0); + + vuses = VUSE_OPS (ann); + for (i = 0; i < NUM_VUSES (vuses); i++) + print_generic_expr (stderr, VUSE_OP (vuses, i), 0); +@} +@end smallexample + +To collect the operands, you first need to call +@code{get_stmt_operands}. Since that is a potentially expensive +operation, statements are only scanned if they have been marked +modified by a call to @code{modify_stmt}. So, if your pass replaces +operands in a statement, make sure to call @code{modify_stmt}. + + +@node SSA +@section Static Single Assignment +@cindex SSA +@cindex static single assignment + +Most of the tree optimizers rely on the data flow information provided +by the Static Single Assignment (SSA) form. We implement the SSA form +as described in @cite{R. Cytron, J. Ferrante, B. Rosen, M. Wegman, and +K. Zadeck. Efficiently Computing Static Single Assignment Form and the +Control Dependence Graph. ACM Transactions on Programming Languages +and Systems, 13(4):451-490, October 1991}. + +The SSA form is based on the premise that program variables are +assigned in exactly one location in the program. Multiple assignments +to the same variable create new versions of that variable. Naturally, +actual programs are seldom in SSA form initially because variables +tend to be assigned multiple times. The compiler modifies the program +representation so that every time a variable is assigned in the code, +a new version of the variable is created. Different versions of the +same variable are distinguished by subscripting the variable name with +its version number. Variables used in the right-hand side of +expressions are renamed so that their version number matches that of +the most recent assignment. + +We represent variable versions using @code{SSA_NAME} nodes. The +renaming process in @file{tree-ssa.c} wraps every real and +virtual operand with an @code{SSA_NAME} node which contains +the version number and the statement that created the +@code{SSA_NAME}. Only definitions and virtual definitions may +create new @code{SSA_NAME} nodes. + +Sometimes, flow of control makes it impossible to determine what is the +most recent version of a variable. In these cases, the compiler +inserts an artificial definition for that variable called +@dfn{PHI function} or @dfn{PHI node}. This new definition merges +all the incoming versions of the variable to create a new name +for it. For instance, + +@smallexample +if (...) + a_1 = 5; +else if (...) + a_2 = 2; +else + a_3 = 13; + +# a_4 = PHI +return a_4; +@end smallexample + +Since it is not possible to determine which of the three branches +will be taken at runtime, we don't know which of @code{a_1}, +@code{a_2} or @code{a_3} to use at the return statement. So, the +SSA renamer creates a new version @code{a_4} which is assigned +the result of ``merging'' @code{a_1}, @code{a_2} and @code{a_3}. +Hence, PHI nodes mean ``one of these operands. I don't know +which''. + +The following macros can be used to examine PHI nodes + +@defmac PHI_RESULT (@var{phi}) +Returns the @code{SSA_NAME} created by PHI node @var{phi} (i.e., +@var{phi}'s LHS). +@end defmac + +@defmac PHI_NUM_ARGS (@var{phi}) +Returns the number of arguments in @var{phi}. This number is exactly +the number of incoming edges to the basic block holding @var{phi}@. +@end defmac + +@defmac PHI_ARG_ELT (@var{phi}, @var{i}) +Returns a tuple representing the @var{i}th argument of @var{phi}@. +Each element of this tuple contains an @code{SSA_NAME} @var{var} and +the incoming edge through which @var{var} flows. +@end defmac + +@defmac PHI_ARG_EDGE (@var{phi}, @var{i}) +Returns the incoming edge for the @var{i}th argument of @var{phi}. +@end defmac + +@defmac PHI_ARG_DEF (@var{phi}, @var{i}) +Returns the @code{SSA_NAME} for the @var{i}th argument of @var{phi}. +@end defmac + + +@subsection Preserving the SSA form +@findex vars_to_rename +@cindex preserving SSA form +Some optimization passes make changes to the function that +invalidate the SSA property. This can happen when a pass has +added new variables or changed the program so that variables that +were previously aliased aren't anymore. + +Whenever something like this happens, the affected variables must +be renamed into SSA form again. To do this, you should mark the +new variables in the global bitmap @code{vars_to_rename}. Once +your pass has finished, the pass manager will invoke the SSA +renamer to put the program into SSA once more. + +@subsection Examining @code{SSA_NAME} nodes +@cindex examining SSA_NAMEs + +The following macros can be used to examine @code{SSA_NAME} nodes + +@defmac SSA_NAME_DEF_STMT (@var{var}) +Returns the statement @var{s} that creates the @code{SSA_NAME} +@var{var}. If @var{s} is an empty statement (i.e., @code{IS_EMPTY_STMT +(@var{s})} returns @code{true}), it means that the first reference to +this variable is a USE or a VUSE@. +@end defmac + +@defmac SSA_NAME_VERSION (@var{var}) +Returns the version number of the @code{SSA_NAME} object @var{var}. +@end defmac + + +@subsection Walking use-def chains + +@deftypefn {Tree SSA function} void walk_use_def_chains (@var{var}, @var{fn}, @var{data}) + +Walks use-def chains starting at the @code{SSA_NAME} node @var{var}. +Calls function @var{fn} at each reaching definition found. Function +@var{FN} takes three arguments: @var{var}, its defining statement +(@var{def_stmt}) and a generic pointer to whatever state information +that @var{fn} may want to maintain (@var{data}). Function @var{fn} is +able to stop the walk by returning @code{true}, otherwise in order to +continue the walk, @var{fn} should return @code{false}. + +Note, that if @var{def_stmt} is a @code{PHI} node, the semantics are +slightly different. For each argument @var{arg} of the PHI node, this +function will: + +@enumerate +@item Walk the use-def chains for @var{arg}. +@item Call @code{FN (@var{arg}, @var{phi}, @var{data})}. +@end enumerate + +Note how the first argument to @var{fn} is no longer the original +variable @var{var}, but the PHI argument currently being examined. +If @var{fn} wants to get at @var{var}, it should call +@code{PHI_RESULT} (@var{phi}). +@end deftypefn + +@subsection Walking the dominator tree + +@deftypefn {Tree SSA function} void walk_dominator_tree (@var{walk_data}, @var{bb}) + +This function walks the dominator tree for the current CFG calling a +set of callback functions defined in @var{struct dom_walk_data} in +@file{domwalk.h}. The call back functions you need to define give you +hooks to execute custom code at various points during traversal: + +@enumerate +@item Once to initialize any local data needed while processing + @var{bb} and its children. This local data is pushed into an + internal stack which is automatically pushed and popped as the + walker traverses the dominator tree. + +@item Once before traversing all the statements in the @var{bb}. + +@item Once for every statement inside @var{bb}. + +@item Once after traversing all the statements and before recursing + into @var{bb}'s dominator children. + +@item It then recurses into all the dominator children of @var{bb}. + +@item After recursing into all the dominator children of @var{bb} it + can, optionally, traverse every statement in @var{bb} again + (i.e., repeating steps 2 and 3). + +@item Once after walking the statements in @var{bb} and @var{bb}'s + dominator children. At this stage, the block local data stack + is popped. +@end enumerate +@end deftypefn + +@node Alias analysis +@section Alias analysis +@cindex alias +@cindex flow-sensitive alias analysis +@cindex flow-insensitive alias analysis + +Alias analysis proceeds in 3 main phases: + +@enumerate +@item Points-to and escape analysis. + +This phase walks the use-def chains in the SSA web looking for +three things: + + @itemize @bullet + @item Assignments of the form @code{P_i = &VAR} + @item Assignments of the form P_i = malloc() + @item Pointers and ADDR_EXPR that escape the current function. + @end itemize + +The concept of `escaping' is the same one used in the Java world. +When a pointer or an ADDR_EXPR escapes, it means that it has been +exposed outside of the current function. So, assignment to +global variables, function arguments and returning a pointer are +all escape sites. + +This is where we are currently limited. Since not everything is +renamed into SSA, we lose track of escape properties when a +pointer is stashed inside a field in a structure, for instance. +In those cases, we are assuming that the pointer does escape. + +We use escape analysis to determine whether a variable is +call-clobbered. Simply put, if an ADDR_EXPR escapes, then the +variable is call-clobbered. If a pointer P_i escapes, then all +the variables pointed-to by P_i (and its memory tag) also escape. + +@item Compute flow-sensitive aliases + +We have two classes of memory tags. Memory tags associated with +the pointed-to data type of the pointers in the program. These +tags are called ``type memory tag'' (TMT). The other class are +those associated with SSA_NAMEs, called ``name memory tag'' (NMT). +The basic idea is that when adding operands for an INDIRECT_REF +*P_i, we will first check whether P_i has a name tag, if it does +we use it, because that will have more precise aliasing +information. Otherwise, we use the standard type tag. + +In this phase, we go through all the pointers we found in +points-to analysis and create alias sets for the name memory tags +associated with each pointer P_i. If P_i escapes, we mark +call-clobbered the variables it points to and its tag. + + +@item Compute flow-insensitive aliases + +This pass will compare the alias set of every type memory tag and +every addressable variable found in the program. Given a type +memory tag TMT and an addressable variable V@. If the alias sets +of TMT and V conflict (as computed by may_alias_p), then V is +marked as an alias tag and added to the alias set of TMT@. +@end enumerate + +For instance, consider the following function: + +@example +foo (int i) +@{ + int *p, *q, a, b; + + if (i > 10) + p = &a; + else + q = &b; + + *p = 3; + *q = 5; + a = b + 2; + return *p; +@} +@end example + +After aliasing analysis has finished, the type memory tag for +pointer @code{p} will have two aliases, namely variables @code{a} and +@code{b}. +Every time pointer @code{p} is dereferenced, we want to mark the +operation as a potential reference to @code{a} and @code{b}. + +@example +foo (int i) +@{ + int *p, a, b; + + if (i_2 > 10) + p_4 = &a; + else + p_6 = &b; + # p_1 = PHI ; + + # a_7 = VDEF ; + # b_8 = VDEF ; + *p_1 = 3; + + # a_9 = VDEF + # VUSE + a_9 = b_8 + 2; + + # VUSE ; + # VUSE ; + return *p_1; +@} +@end example + +In certain cases, the list of may aliases for a pointer may grow +too large. This may cause an explosion in the number of virtual +operands inserted in the code. Resulting in increased memory +consumption and compilation time. + +When the number of virtual operands needed to represent aliased +loads and stores grows too large (configurable with @option{--param +max-aliased-vops}), alias sets are grouped to avoid severe +compile-time slow downs and memory consumption. The alias +grouping heuristic proceeds as follows: + +@enumerate +@item Sort the list of pointers in decreasing number of contributed +virtual operands. + +@item Take the first pointer from the list and reverse the role +of the memory tag and its aliases. Usually, whenever an +aliased variable Vi is found to alias with a memory tag +T, we add Vi to the may-aliases set for T@. Meaning that +after alias analysis, we will have: + +@smallexample +may-aliases(T) = @{ V1, V2, V3, ..., Vn @} +@end smallexample + +This means that every statement that references T, will get +@code{n} virtual operands for each of the Vi tags. But, when +alias grouping is enabled, we make T an alias tag and add it +to the alias set of all the Vi variables: + +@smallexample +may-aliases(V1) = @{ T @} +may-aliases(V2) = @{ T @} +... +may-aliases(Vn) = @{ T @} +@end smallexample + +This has two effects: (a) statements referencing T will only get +a single virtual operand, and, (b) all the variables Vi will now +appear to alias each other. So, we lose alias precision to +improve compile time. But, in theory, a program with such a high +level of aliasing should not be very optimizable in the first +place. + +@item Since variables may be in the alias set of more than one +memory tag, the grouping done in step (2) needs to be extended +to all the memory tags that have a non-empty intersection with +the may-aliases set of tag T@. For instance, if we originally +had these may-aliases sets: + +@smallexample +may-aliases(T) = @{ V1, V2, V3 @} +may-aliases(R) = @{ V2, V4 @} +@end smallexample + +In step (2) we would have reverted the aliases for T as: + +@smallexample +may-aliases(V1) = @{ T @} +may-aliases(V2) = @{ T @} +may-aliases(V3) = @{ T @} +@end smallexample + +But note that now V2 is no longer aliased with R@. We could +add R to may-aliases(V2), but we are in the process of +grouping aliases to reduce virtual operands so what we do is +add V4 to the grouping to obtain: + +@smallexample +may-aliases(V1) = @{ T @} +may-aliases(V2) = @{ T @} +may-aliases(V3) = @{ T @} +may-aliases(V4) = @{ T @} +@end smallexample + +@item If the total number of virtual operands due to aliasing is +still above the threshold set by max-alias-vops, go back to (2). +@end enumerate diff --git a/gcc/dominance.c b/gcc/dominance.c index 793820557fe..86f0191eb4f 100644 --- a/gcc/dominance.c +++ b/gcc/dominance.c @@ -118,6 +118,9 @@ static void link_roots (struct dom_info *, TBB, TBB); static void calc_idoms (struct dom_info *, enum cdi_direction); void debug_dominance_info (enum cdi_direction); +/* Keeps track of the*/ +static unsigned n_bbs_in_dom_tree[2]; + /* Helper macro for allocating and initializing an array, for aesthetic reasons. */ #define init_ar(var, type, num, content) \ @@ -531,7 +534,7 @@ assign_dfs_numbers (struct et_node *node, int *num) { assign_dfs_numbers (node->son, num); for (son = node->son->right; son != node->son; son = son->right) - assign_dfs_numbers (son, num); + assign_dfs_numbers (son, num); } node->dfs_num_out = (*num)++; @@ -555,7 +558,7 @@ compute_dom_fast_query (enum cdi_direction dir) FOR_ALL_BB (bb) { if (!bb->dom[dir]->father) - assign_dfs_numbers (bb->dom[dir], &num); + assign_dfs_numbers (bb->dom[dir], &num); } dom_computed[dir] = DOM_OK; @@ -576,12 +579,16 @@ calculate_dominance_info (enum cdi_direction dir) if (dom_computed[dir] != DOM_NO_FAST_QUERY) { if (dom_computed[dir] != DOM_NONE) - free_dominance_info (dir); + free_dominance_info (dir); + + if (n_bbs_in_dom_tree[dir]) + abort (); FOR_ALL_BB (b) { b->dom[dir] = et_new_tree (b); } + n_bbs_in_dom_tree[dir] = n_basic_blocks + 2; init_dom_info (&di); calc_dfs_tree (&di, dir); @@ -616,6 +623,10 @@ free_dominance_info (enum cdi_direction dir) delete_from_dominance_info (dir, bb); } + /* If there are any nodes left, something is wrong. */ + if (n_bbs_in_dom_tree[dir]) + abort (); + dom_computed[dir] = DOM_NONE; } @@ -631,7 +642,7 @@ get_immediate_dominator (enum cdi_direction dir, basic_block bb) if (!node->father) return NULL; - return node->father->data; + return node->father->data; } /* Set the immediate dominator of the block possibly removing @@ -648,7 +659,7 @@ set_immediate_dominator (enum cdi_direction dir, basic_block bb, if (node->father) { if (node->father->data == dominated_by) - return; + return; et_split (node); } @@ -730,7 +741,7 @@ nearest_common_dominator (enum cdi_direction dir, basic_block bb1, basic_block b /* Return TRUE in case BB1 is dominated by BB2. */ bool dominated_by_p (enum cdi_direction dir, basic_block bb1, basic_block bb2) -{ +{ struct et_node *n1 = bb1->dom[dir], *n2 = bb2->dom[dir]; if (!dom_computed[dir]) @@ -738,7 +749,7 @@ dominated_by_p (enum cdi_direction dir, basic_block bb1, basic_block bb2) if (dom_computed[dir] == DOM_OK) return (n1->dfs_num_in >= n2->dfs_num_in - && n1->dfs_num_out <= n2->dfs_num_out); + && n1->dfs_num_out <= n2->dfs_num_out); return et_below (n1, n2); } @@ -839,6 +850,8 @@ add_to_dominance_info (enum cdi_direction dir, basic_block bb) if (bb->dom[dir]) abort (); + n_bbs_in_dom_tree[dir]++; + bb->dom[dir] = et_new_tree (bb); if (dom_computed[dir] == DOM_OK) @@ -853,6 +866,7 @@ delete_from_dominance_info (enum cdi_direction dir, basic_block bb) et_free_tree (bb->dom[dir]); bb->dom[dir] = NULL; + n_bbs_in_dom_tree[dir]--; if (dom_computed[dir] == DOM_OK) dom_computed[dir] = DOM_NO_FAST_QUERY; diff --git a/gcc/domwalk.c b/gcc/domwalk.c new file mode 100644 index 00000000000..ce0ccd113e4 --- /dev/null +++ b/gcc/domwalk.c @@ -0,0 +1,265 @@ +/* Generic dominator tree walker + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "domwalk.h" +#include "ggc.h" + +/* This file implements a generic walker for dominator trees. + + To understand the dominator walker one must first have a grasp of dominators, + immediate dominators and the dominator tree. + + Dominators + A block B1 is said to dominate B2 if every path from the entry to B2 must + pass through B1. Given the dominance relationship, we can proceed to + compute immediate dominators. Note it is not important whether or not + our definition allows a block to dominate itself. + + Immediate Dominators: + Every block in the CFG has no more than one immediate dominator. The + immediate dominator of block BB must dominate BB and must not dominate + any other dominator of BB and must not be BB itself. + + Dominator tree: + If we then construct a tree where each node is a basic block and there + is an edge from each block's immediate dominator to the block itself, then + we have a dominator tree. + + + [ Note this walker can also walk the post-dominator tree, which is + defined in a similar manner. ie, block B1 is said to post-dominate + block B2 if all paths from B2 to the exit block must pass through + B1. ] + + For example, given the CFG + + 1 + | + 2 + / \ + 3 4 + / \ + +---------->5 6 + | / \ / + | +--->8 7 + | | / | + | +--9 11 + | / | + +--- 10 ---> 12 + + + We have a dominator tree which looks like + + 1 + | + 2 + / \ + / \ + 3 4 + / / \ \ + | | | | + 5 6 7 12 + | | + 8 11 + | + 9 + | + 10 + + + + The dominator tree is the basis for a number of analysis, transformation + and optimization algorithms that operate on a semi-global basis. + + The dominator walker is a generic routine which visits blocks in the CFG + via a depth first search of the dominator tree. In the example above + the dominator walker might visit blocks in the following order + 1, 2, 3, 4, 5, 8, 9, 10, 6, 7, 11, 12. + + The dominator walker has a number of callbacks to perform actions + during the walk of the dominator tree. There are two callbacks + which walk statements, one before visiting the dominator children, + one after visiting the dominator children. There is a callback + before and after each statement walk callback. In addition, the + dominator walker manages allocation/deallocation of data structures + which are local to each block visited. + + The dominator walker is meant to provide a generic means to build a pass + which can analyze or transform/optimize a function based on walking + the dominator tree. One simply fills in the dominator walker data + structure with the appropriate callbacks and calls the walker. + + We currently use the dominator walker to prune the set of variables + which might need PHI nodes (which can greatly improve compile-time + performance in some cases). + + We also use the dominator walker to rewrite the function into SSA form + which reduces code duplication since the rewriting phase is inherently + a walk of the dominator tree. + + And (of course), we use the dominator walker to drive a our dominator + optimizer, which is a semi-global optimizer. + + TODO: + + Walking statements is based on the block statement iterator abstraction, + which is currently an abstraction over walking tree statements. Thus + the dominator walker is currently only useful for trees. */ + +/* Recursively walk the dominator tree. + + WALK_DATA contains a set of callbacks to perform pass-specific + actions during the dominator walk as well as a stack of block local + data maintained during the dominator walk. + + BB is the basic block we are currently visiting. */ + +void +walk_dominator_tree (struct dom_walk_data *walk_data, basic_block bb) +{ + void *bd = NULL; + basic_block dest; + block_stmt_iterator bsi; + + /* Callback to initialize the local data structure. */ + if (walk_data->initialize_block_local_data) + { + bool recycled; + + /* First get some local data, reusing any local data pointer we may + have saved. */ + if (VARRAY_ACTIVE_SIZE (walk_data->free_block_data) > 0) + { + bd = VARRAY_TOP_GENERIC_PTR (walk_data->free_block_data); + VARRAY_POP (walk_data->free_block_data); + recycled = 1; + } + else + { + bd = xcalloc (1, walk_data->block_local_data_size); + recycled = 0; + } + + /* Push the local data into the local data stack. */ + VARRAY_PUSH_GENERIC_PTR (walk_data->block_data_stack, bd); + + /* Call the initializer. */ + walk_data->initialize_block_local_data (walk_data, bb, recycled); + + } + + /* Callback for operations to execute before we have walked the + dominator children, but before we walk statements. */ + if (walk_data->before_dom_children_before_stmts) + (*walk_data->before_dom_children_before_stmts) (walk_data, bb); + + /* Statement walk before walking dominator children. */ + if (walk_data->before_dom_children_walk_stmts) + { + if (walk_data->walk_stmts_backward) + for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi)) + (*walk_data->before_dom_children_walk_stmts) (walk_data, bb, bsi); + else + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + (*walk_data->before_dom_children_walk_stmts) (walk_data, bb, bsi); + } + + /* Callback for operations to execute before we have walked the + dominator children, and after we walk statements. */ + if (walk_data->before_dom_children_after_stmts) + (*walk_data->before_dom_children_after_stmts) (walk_data, bb); + + /* Recursively call ourselves on the dominator children of BB. */ + for (dest = first_dom_son (walk_data->dom_direction, bb); + dest; + dest = next_dom_son (walk_data->dom_direction, dest)) + { + /* The destination block may have become unreachable, in + which case there's no point in optimizing it. */ + if (dest->pred) + walk_dominator_tree (walk_data, dest); + } + + /* Callback for operations to execute after we have walked the + dominator children, but before we walk statements. */ + if (walk_data->after_dom_children_before_stmts) + (*walk_data->after_dom_children_before_stmts) (walk_data, bb); + + /* Statement walk after walking dominator children. */ + if (walk_data->after_dom_children_walk_stmts) + { + if (walk_data->walk_stmts_backward) + for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi)) + (*walk_data->after_dom_children_walk_stmts) (walk_data, bb, bsi); + else + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + (*walk_data->after_dom_children_walk_stmts) (walk_data, bb, bsi); + } + + /* Callback for operations to execute after we have walked the + dominator children and after we have walked statements. */ + if (walk_data->after_dom_children_after_stmts) + (*walk_data->after_dom_children_after_stmts) (walk_data, bb); + + if (walk_data->initialize_block_local_data) + { + /* And save the block data so that we can re-use it. */ + VARRAY_PUSH_GENERIC_PTR (walk_data->free_block_data, bd); + + /* And finally pop the record off the block local data stack. */ + VARRAY_POP (walk_data->block_data_stack); + } +} + +void +init_walk_dominator_tree (struct dom_walk_data *walk_data) +{ + if (walk_data->initialize_block_local_data) + { + VARRAY_GENERIC_PTR_INIT (walk_data->free_block_data, 2, "freelist "); + VARRAY_GENERIC_PTR_INIT (walk_data->block_data_stack, 2, "block_data"); + } + else + { + walk_data->free_block_data = NULL; + walk_data->block_data_stack = NULL; + } +} + +void +fini_walk_dominator_tree (struct dom_walk_data *walk_data) +{ + if (walk_data->initialize_block_local_data) + { + while (VARRAY_ACTIVE_SIZE (walk_data->free_block_data) > 0) + { + free (VARRAY_TOP_GENERIC_PTR (walk_data->free_block_data)); + VARRAY_POP (walk_data->free_block_data); + } + } +} diff --git a/gcc/domwalk.h b/gcc/domwalk.h new file mode 100644 index 00000000000..2c2138a9199 --- /dev/null +++ b/gcc/domwalk.h @@ -0,0 +1,112 @@ +/* Generic dominator tree walker + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This is the main data structure for the dominator walker. It provides + the callback hooks as well as a convenient place to hang block local + data and pass-global data. */ + +struct dom_walk_data +{ + /* This is the direction of the dominator tree we want to walk. ie, + if it is set to CDI_DOMINATORS, then we walk the dominator tree, + if it is set to CDI_POST_DOMINATORS, then we walk the post + dominator tree. */ + ENUM_BITFIELD (cdi_direction) dom_direction : 2; + + /* Nonzero if the statement walker should walk the statements from + last to first within a basic block instead of first to last. + + Note this affects both statement walkers. We haven't yet needed + to use the second statement walker for anything, so it's hard to + predict if we really need the ability to select their direction + independently. */ + bool walk_stmts_backward : 1; + + /* Function to initialize block local data. + + Note that the dominator walker infrastructure may provide a new + fresh, and zero'd block local data structure, or it may re-use an + existing block local data structure. + + If the block local structure has items such as virtual arrays, then + that allows your optimizer to re-use those arrays rather than + creating new ones. */ + void (*initialize_block_local_data) (struct dom_walk_data *, + basic_block, bool); + + /* Function to call before the statement walk occurring before the + recursive walk of the dominator children. + + This typically initializes an block local data and pushes that + data onto BLOCK_DATA_STACK. */ + void (*before_dom_children_before_stmts) (struct dom_walk_data *, + basic_block); + + /* Function to call to walk statements before the recursive walk + of the dominator children. */ + void (*before_dom_children_walk_stmts) (struct dom_walk_data *, + basic_block, block_stmt_iterator); + + /* Function to call after the statement walk occurring before the + recursive walk of the dominator children. */ + void (*before_dom_children_after_stmts) (struct dom_walk_data *, + basic_block); + + /* Function to call before the statement walk occurring after the + recursive walk of the dominator children. */ + void (*after_dom_children_before_stmts) (struct dom_walk_data *, + basic_block); + + /* Function to call to walk statements after the recursive walk + of the dominator children. */ + void (*after_dom_children_walk_stmts) (struct dom_walk_data *, + basic_block, block_stmt_iterator); + + /* Function to call after the statement walk occurring after the + recursive walk of the dominator children. + + This typically finalizes any block local data and pops + that data from BLOCK_DATA_STACK. */ + void (*after_dom_children_after_stmts) (struct dom_walk_data *, + basic_block); + + /* Global data for a walk through the dominator tree. */ + void *global_data; + + /* Stack of any data we need to keep on a per-block basis. + + If you have no local data, then BLOCK_DATA_STACK will be NULL. */ + varray_type block_data_stack; + + /* Size of the block local data. If this is zero, then it is assumed + you have no local data and thus no BLOCK_DATA_STACK as well. */ + size_t block_local_data_size; + + /* From here below are private data. Please do not use this + information/data outside domwalk.c. */ + + /* Stack of available block local structures. */ + varray_type free_block_data; +}; + +void walk_dominator_tree (struct dom_walk_data *, basic_block); +void init_walk_dominator_tree (struct dom_walk_data *); +void fini_walk_dominator_tree (struct dom_walk_data *); diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 7af0eb34853..cfedd13bd28 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -5070,7 +5070,9 @@ is_fortran (void) { unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language); - return lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90; + return (lang == DW_LANG_Fortran77 + || lang == DW_LANG_Fortran90 + || lang == DW_LANG_Fortran95); } /* Return TRUE if the language is Java. */ @@ -8829,6 +8831,7 @@ loc_descriptor_from_tree (tree loc, int addressp) /* Fall through. */ case PARM_DECL: + case RESULT_DECL: { rtx rtl = rtl_for_decl_location (loc); @@ -9117,9 +9120,6 @@ loc_descriptor_from_tree (tree loc, int addressp) } break; - case EXPR_WITH_FILE_LOCATION: - return loc_descriptor_from_tree (EXPR_WFL_NODE (loc), addressp); - default: /* Leave front-end specific codes as simply unknown. This comes up, for instance, with the C STMT_EXPR. */ @@ -9696,10 +9696,7 @@ rtl_for_decl_location (tree decl) This happens (for example) for inlined-instances of inline function formal parameters which are never referenced. This really shouldn't be happening. All PARM_DECL nodes should get valid non-NULL - DECL_INCOMING_RTL values, but integrate.c doesn't currently generate these - values for inlined instances of inline function parameters, so when we see - such cases, we are just out-of-luck for the time being (until integrate.c - gets fixed). */ + DECL_INCOMING_RTL values. FIXME. */ /* Use DECL_RTL as the "location" unless we find something better. */ rtl = DECL_RTL_IF_SET (decl); @@ -9875,7 +9872,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, if (TREE_CODE (decl) == ERROR_MARK) return; - else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL) + else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL + && TREE_CODE (decl) != RESULT_DECL) abort (); /* See if we possibly have multiple locations for this variable. */ @@ -10183,6 +10181,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b case VAR_DECL: case PARM_DECL: + case RESULT_DECL: { dw_die_ref decl_die = lookup_decl_die (bound); @@ -11343,13 +11342,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg)); } -#if 0 - /* ??? This fails for nested inline functions, because context_display - is not part of the state saved/restored for inline functions. */ - if (current_function_needs_context) + if (cfun->static_chain_decl) add_AT_location_description (subr_die, DW_AT_static_link, - loc_descriptor (lookup_static_chain (decl))); -#endif + loc_descriptor_from_tree (cfun->static_chain_decl, 0)); } /* Now output descriptions of the arguments for this function. This gets @@ -11425,6 +11420,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) constructor function. */ if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK) { + /* Emit a DW_TAG_variable DIE for a named return value. */ + if (DECL_NAME (DECL_RESULT (decl))) + gen_decl_die (DECL_RESULT (decl), subr_die); + current_function_has_inlines = 0; decls_for_scope (outer_scope, subr_die, 0); @@ -11769,6 +11768,8 @@ gen_compile_unit_die (const char *filename) language = DW_LANG_Ada95; else if (strcmp (language_string, "GNU F77") == 0) language = DW_LANG_Fortran77; + else if (strcmp (language_string, "GNU F95") == 0) + language = DW_LANG_Fortran95; else if (strcmp (language_string, "GNU Pascal") == 0) language = DW_LANG_Pascal83; else if (strcmp (language_string, "GNU Java") == 0) @@ -12578,6 +12579,14 @@ gen_decl_die (tree decl, dw_die_ref context_die) && (current_function_decl == NULL_TREE || DECL_ARTIFICIAL (decl))) break; +#if 0 + /* FIXME */ + /* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN + on local redeclarations of global functions. That seems broken. */ + if (current_function_decl != decl) + /* This is only a declaration. */; +#endif + /* If we're emitting a clone, emit info for the abstract instance. */ if (DECL_ORIGIN (decl) != decl) dwarf2out_abstract_function (DECL_ABSTRACT_ORIGIN (decl)); @@ -12651,6 +12660,7 @@ gen_decl_die (tree decl, dw_die_ref context_die) break; case VAR_DECL: + case RESULT_DECL: /* If we are in terse mode, don't generate any DIEs to represent any variable declarations or definitions. */ if (debug_info_level <= DINFO_LEVEL_TERSE) diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index d7633e5a816..ba8a3d6cf24 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -929,6 +929,17 @@ get_first_label_num (void) { return first_label_num; } + +/* If the rtx for label was created during the expansion of a nested + function, then first_label_num won't include this label number. + Fix this now so that array indicies work later. */ + +void +maybe_set_first_label_num (rtx x) +{ + if (CODE_LABEL_NUMBER (x) < first_label_num) + first_label_num = CODE_LABEL_NUMBER (x); +} /* Return the final regno of X, which is a SUBREG of a hard register. */ @@ -2387,8 +2398,8 @@ copy_most_rtx (rtx orig, rtx may_share) RTX_FLAG (copy, in_struct) = RTX_FLAG (orig, in_struct); RTX_FLAG (copy, volatil) = RTX_FLAG (orig, volatil); RTX_FLAG (copy, unchanging) = RTX_FLAG (orig, unchanging); - RTX_FLAG (copy, integrated) = RTX_FLAG (orig, integrated); RTX_FLAG (copy, frame_related) = RTX_FLAG (orig, frame_related); + RTX_FLAG (copy, return_val) = RTX_FLAG (orig, return_val); format_ptr = GET_RTX_FORMAT (GET_CODE (copy)); diff --git a/gcc/et-forest.c b/gcc/et-forest.c index e65ccda6005..9b0997188bd 100644 --- a/gcc/et-forest.c +++ b/gcc/et-forest.c @@ -206,9 +206,13 @@ et_check_tree_sanity (struct et_occ *occ) /* For recording the paths. */ +/* An ad-hoc constant; if the function has more blocks, this won't work, + but since it is used for debugging only, it does not matter. */ +#define MAX_NODES 100000 + static int len; -static void *datas[100000]; -static int depths[100000]; +static void *datas[MAX_NODES]; +static int depths[MAX_NODES]; /* Records the path represented by OCC, with depth incremented by DEPTH. */ @@ -228,6 +232,10 @@ record_path_before_1 (struct et_occ *occ, int depth) } fprintf (stderr, "%d (%d); ", ((basic_block) occ->of->data)->index, depth); + + if (len >= MAX_NODES) + abort (); + depths[len] = depth; datas[len] = occ->of; len++; diff --git a/gcc/except.c b/gcc/except.c index d7daec3e602..2dfd073e70a 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -134,7 +134,7 @@ struct eh_region GTY(()) /* Each region does exactly one thing. */ enum eh_region_type - { + { ERT_UNKNOWN = 0, ERT_CLEANUP, ERT_TRY, @@ -195,6 +195,7 @@ struct eh_region GTY(()) /* Entry point for this region's handler before landing pads are built. */ rtx label; + tree tree_label; /* Entry point for this region's handler from the runtime eh library. */ rtx landing_pad; @@ -264,9 +265,6 @@ static tree lookup_type_for_runtime (tree); static struct eh_region *expand_eh_region_end (void); -static rtx get_exception_filter (struct function *); - -static void collect_eh_region_array (void); static void resolve_fixup_regions (void); static void remove_fixup_regions (void); static void remove_unreachable_regions (rtx); @@ -302,8 +300,6 @@ static void remove_exception_handler_label (rtx); static void remove_eh_handler (struct eh_region *); static int for_each_eh_label_1 (void **, void *); -struct reachable_info; - /* The return value of reachable_next_level. */ enum reachable_code { @@ -317,9 +313,7 @@ enum reachable_code RNL_BLOCKED }; -static int check_handled (tree, tree); -static void add_reachable_handler (struct reachable_info *, - struct eh_region *, struct eh_region *); +struct reachable_info; static enum reachable_code reachable_next_level (struct eh_region *, tree, struct reachable_info *); @@ -461,6 +455,128 @@ init_eh_for_function (void) cfun->eh = ggc_alloc_cleared (sizeof (struct eh_status)); } +/* Routines to generate the exception tree somewhat directly. + These are used from tree-eh.c when processing exception related + nodes during tree optimization. */ + +static struct eh_region * +gen_eh_region (enum eh_region_type type, struct eh_region *outer) +{ + struct eh_region *new; + +#ifdef ENABLE_CHECKING + if (! doing_eh (0)) + abort (); +#endif + + /* Insert a new blank region as a leaf in the tree. */ + new = ggc_alloc_cleared (sizeof (*new)); + new->type = type; + new->outer = outer; + if (outer) + { + new->next_peer = outer->inner; + outer->inner = new; + } + else + { + new->next_peer = cfun->eh->region_tree; + cfun->eh->region_tree = new; + } + + new->region_number = ++cfun->eh->last_region_number; + + return new; +} + +struct eh_region * +gen_eh_region_cleanup (struct eh_region *outer, struct eh_region *prev_try) +{ + struct eh_region *cleanup = gen_eh_region (ERT_CLEANUP, outer); + cleanup->u.cleanup.prev_try = prev_try; + return cleanup; +} + +struct eh_region * +gen_eh_region_try (struct eh_region *outer) +{ + return gen_eh_region (ERT_TRY, outer); +} + +struct eh_region * +gen_eh_region_catch (struct eh_region *t, tree type_or_list) +{ + struct eh_region *c, *l; + tree type_list, type_node; + + /* Ensure to always end up with a type list to normalize further + processing, then register each type against the runtime types map. */ + type_list = type_or_list; + if (type_or_list) + { + if (TREE_CODE (type_or_list) != TREE_LIST) + type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE); + + type_node = type_list; + for (; type_node; type_node = TREE_CHAIN (type_node)) + add_type_for_runtime (TREE_VALUE (type_node)); + } + + c = gen_eh_region (ERT_CATCH, t->outer); + c->u.catch.type_list = type_list; + l = t->u.try.last_catch; + c->u.catch.prev_catch = l; + if (l) + l->u.catch.next_catch = c; + else + t->u.try.catch = c; + t->u.try.last_catch = c; + + return c; +} + +struct eh_region * +gen_eh_region_allowed (struct eh_region *outer, tree allowed) +{ + struct eh_region *region = gen_eh_region (ERT_ALLOWED_EXCEPTIONS, outer); + region->u.allowed.type_list = allowed; + + for (; allowed ; allowed = TREE_CHAIN (allowed)) + add_type_for_runtime (TREE_VALUE (allowed)); + + return region; +} + +struct eh_region * +gen_eh_region_must_not_throw (struct eh_region *outer) +{ + return gen_eh_region (ERT_MUST_NOT_THROW, outer); +} + +int +get_eh_region_number (struct eh_region *region) +{ + return region->region_number; +} + +bool +get_eh_region_may_contain_throw (struct eh_region *region) +{ + return region->may_contain_throw; +} + +tree +get_eh_region_tree_label (struct eh_region *region) +{ + return region->tree_label; +} + +void +set_eh_region_tree_label (struct eh_region *region, tree lab) +{ + region->tree_label = lab; +} + /* Start an exception handling region. All instructions emitted after this point are considered to be part of the region until expand_eh_region_end is invoked. */ @@ -468,33 +584,18 @@ init_eh_for_function (void) void expand_eh_region_start (void) { - struct eh_region *new_region; - struct eh_region *cur_region; + struct eh_region *new; rtx note; if (! doing_eh (0)) return; - /* Insert a new blank region as a leaf in the tree. */ - new_region = ggc_alloc_cleared (sizeof (*new_region)); - cur_region = cfun->eh->cur_region; - new_region->outer = cur_region; - if (cur_region) - { - new_region->next_peer = cur_region->inner; - cur_region->inner = new_region; - } - else - { - new_region->next_peer = cfun->eh->region_tree; - cfun->eh->region_tree = new_region; - } - cfun->eh->cur_region = new_region; + new = gen_eh_region (ERT_UNKNOWN, cfun->eh->cur_region); + cfun->eh->cur_region = new; /* Create a note marking the start of this region. */ - new_region->region_number = ++cfun->eh->last_region_number; note = emit_note (NOTE_INSN_EH_REGION_BEG); - NOTE_EH_HANDLER (note) = new_region->region_number; + NOTE_EH_HANDLER (note) = new->region_number; } /* Common code to end a region. Returns the region just ended. */ @@ -515,6 +616,36 @@ expand_eh_region_end (void) return cur_region; } +/* Expand HANDLER, which is the operand 1 of a TRY_CATCH_EXPR. Catch + blocks and C++ exception-specifications are handled specially. */ + +void +expand_eh_handler (tree handler) +{ + tree inner = expr_first (handler); + + switch (TREE_CODE (inner)) + { + case CATCH_EXPR: + expand_start_all_catch (); + expand_expr (handler, const0_rtx, VOIDmode, 0); + expand_end_all_catch (); + break; + + case EH_FILTER_EXPR: + if (EH_FILTER_MUST_NOT_THROW (handler)) + expand_eh_region_end_must_not_throw (EH_FILTER_FAILURE (handler)); + else + expand_eh_region_end_allowed (EH_FILTER_TYPES (handler), + EH_FILTER_FAILURE (handler)); + break; + + default: + expand_eh_region_end_cleanup (handler); + break; + } +} + /* End an exception handling region for a cleanup. HANDLER is an expression to expand for the cleanup. */ @@ -581,6 +712,16 @@ expand_eh_region_end_cleanup (tree handler) emit_label (around_label); } +void +expand_resx_expr (tree exp) +{ + int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)); + struct eh_region *reg = cfun->eh->region_array[region_nr]; + + reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr)); + emit_barrier (); +} + /* End an exception handling region for a try block, and prepares for subsequent calls to expand_start_catch. */ @@ -612,46 +753,20 @@ expand_start_all_catch (void) void expand_start_catch (tree type_or_list) { - struct eh_region *t, *c, *l; - tree type_list; + struct eh_region *c; + rtx note; if (! doing_eh (0)) return; - type_list = type_or_list; + c = gen_eh_region_catch (cfun->eh->try_region, type_or_list); + cfun->eh->cur_region = c; - if (type_or_list) - { - /* Ensure to always end up with a type list to normalize further - processing, then register each type against the runtime types - map. */ - tree type_node; - - if (TREE_CODE (type_or_list) != TREE_LIST) - type_list = tree_cons (NULL_TREE, type_or_list, NULL_TREE); - - type_node = type_list; - for (; type_node; type_node = TREE_CHAIN (type_node)) - add_type_for_runtime (TREE_VALUE (type_node)); - } - - expand_eh_region_start (); - - t = cfun->eh->try_region; - c = cfun->eh->cur_region; - c->type = ERT_CATCH; - c->u.catch.type_list = type_list; c->label = gen_label_rtx (); - - l = t->u.try.last_catch; - c->u.catch.prev_catch = l; - if (l) - l->u.catch.next_catch = c; - else - t->u.try.catch = c; - t->u.try.last_catch = c; - emit_label (c->label); + + note = emit_note (NOTE_INSN_EH_REGION_BEG); + NOTE_EH_HANDLER (note) = c->region_number; } /* End a catch clause. Control will resume after the try/catch block. */ @@ -659,15 +774,11 @@ expand_start_catch (tree type_or_list) void expand_end_catch (void) { - struct eh_region *try_region; - if (! doing_eh (0)) return; expand_eh_region_end (); - try_region = cfun->eh->try_region; - - emit_jump (try_region->u.try.continue_label); + emit_jump (cfun->eh->try_region->u.try.continue_label); } /* End a sequence of catch handlers for a try block. */ @@ -806,11 +917,8 @@ expand_eh_region_end_fixup (tree handler) call to a function which itself may contain a throw. */ void -note_eh_region_may_contain_throw (void) +note_eh_region_may_contain_throw (struct eh_region *region) { - struct eh_region *region; - - region = cfun->eh->cur_region; while (region && !region->may_contain_throw) { region->may_contain_throw = 1; @@ -818,6 +926,13 @@ note_eh_region_may_contain_throw (void) } } +void +note_current_region_may_contain_throw (void) +{ + note_eh_region_may_contain_throw (cfun->eh->cur_region); +} + + /* Return an rtl expression for a pointer to the exception object within a handler. */ @@ -836,7 +951,7 @@ get_exception_pointer (struct function *fun) /* Return an rtl expression for the exception dispatch filter within a handler. */ -static rtx +rtx get_exception_filter (struct function *fun) { rtx filter = fun->eh->filter; @@ -854,7 +969,7 @@ get_exception_filter (struct function *fun) collect the regions this way as in expand_eh_region_start, but without having to realloc memory. */ -static void +void collect_eh_region_array (void) { struct eh_region **array, *i; @@ -1039,12 +1154,6 @@ remove_unreachable_regions (rtx insns) abort (); uid_region_num[INSN_UID (r->label)] = i; } - if (r->type == ERT_TRY && r->u.try.continue_label) - { - if (uid_region_num[INSN_UID (r->u.try.continue_label)]) - abort (); - uid_region_num[INSN_UID (r->u.try.continue_label)] = i; - } } for (insn = insns; insn; insn = NEXT_INSN (insn)) @@ -1066,14 +1175,43 @@ remove_unreachable_regions (rtx insns) r = cfun->eh->region_array[i]; if (r && r->region_number == i && !reachable[i]) { - /* Don't remove ERT_THROW regions if their outer region - is reachable. */ - if (r->type == ERT_THROW - && r->outer - && reachable[r->outer->region_number]) - continue; + bool kill_it = true; + switch (r->type) + { + case ERT_THROW: + /* Don't remove ERT_THROW regions if their outer region + is reachable. */ + if (r->outer && reachable[r->outer->region_number]) + kill_it = false; + break; + + case ERT_MUST_NOT_THROW: + /* MUST_NOT_THROW regions are implementable solely in the + runtime, but their existance continues to affect calls + within that region. Never delete them here. */ + kill_it = false; + break; + + case ERT_TRY: + { + /* TRY regions are reachable if any of its CATCH regions + are reachable. */ + struct eh_region *c; + for (c = r->u.try.catch; c ; c = c->u.catch.next_catch) + if (reachable[c->region_number]) + { + kill_it = false; + break; + } + break; + } - remove_eh_handler (r); + default: + break; + } + + if (kill_it) + remove_eh_handler (r); } } @@ -1165,21 +1303,45 @@ convert_from_eh_region_ranges_1 (rtx *pinsns, int *orig_sp, int cur) abort (); } +static void +collect_rtl_labels_from_trees (void) +{ + int i, n = cfun->eh->last_region_number; + for (i = 1; i <= n; ++i) + { + struct eh_region *reg = cfun->eh->region_array[i]; + if (reg && reg->tree_label) + reg->label = DECL_RTL_IF_SET (reg->tree_label); + } +} + void convert_from_eh_region_ranges (void) { - int *stack; - rtx insns; + rtx insns = get_insns (); + + if (cfun->eh->region_array) + { + /* If the region array already exists, assume we're coming from + optimize_function_tree. In this case all we need to do is + collect the rtl labels that correspond to the tree labels + that we allocated earlier. */ + collect_rtl_labels_from_trees (); + } + else + { + int *stack; - collect_eh_region_array (); - resolve_fixup_regions (); + collect_eh_region_array (); + resolve_fixup_regions (); - stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1)); - insns = get_insns (); - convert_from_eh_region_ranges_1 (&insns, stack, 0); - free (stack); + stack = xmalloc (sizeof (int) * (cfun->eh->last_region_number + 1)); + convert_from_eh_region_ranges_1 (&insns, stack, 0); + free (stack); + + remove_fixup_regions (); + } - remove_fixup_regions (); remove_unreachable_regions (insns); } @@ -1854,6 +2016,12 @@ connect_post_landing_pads (void) abort (); delete_insn (barrier); delete_insn (region->resume); + + /* ??? From tree-ssa we can wind up with catch regions whose + label is not instantiated, but whose resx is present. Now + that we've dealt with the resx, kill the region. */ + if (region->label == NULL && region->type == ERT_CLEANUP) + remove_eh_handler (region); } } @@ -1980,7 +2148,7 @@ sjlj_find_directly_reachable_regions (struct sjlj_lp_info *lp_info) rc = RNL_NOT_CAUGHT; for (; region; region = region->outer) { - rc = reachable_next_level (region, type_thrown, 0); + rc = reachable_next_level (region, type_thrown, NULL); if (rc != RNL_NOT_CAUGHT) break; } @@ -2406,7 +2574,7 @@ finish_eh_generation (void) } } if (eh) - make_eh_edge (NULL, bb, BB_END (bb)); + rtl_make_eh_edge (NULL, bb, BB_END (bb)); } cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL); } @@ -2602,17 +2770,19 @@ for_each_eh_label_1 (void **pentry, void *data) /* This section describes CFG exception edges for flow. */ /* For communicating between calls to reachable_next_level. */ -struct reachable_info GTY(()) +struct reachable_info { tree types_caught; tree types_allowed; - rtx handlers; + void (*callback) (struct eh_region *, void *); + void *callback_data; + bool saw_any_handlers; }; /* A subroutine of reachable_next_level. Return true if TYPE, or a base class of TYPE, is in HANDLED. */ -static int +int check_handled (tree handled, tree type) { tree t; @@ -2643,18 +2813,18 @@ check_handled (tree handled, tree type) LP_REGION contains the landing pad; REGION is the handler. */ static void -add_reachable_handler (struct reachable_info *info, struct eh_region *lp_region, struct eh_region *region) +add_reachable_handler (struct reachable_info *info, + struct eh_region *lp_region, struct eh_region *region) { if (! info) return; + info->saw_any_handlers = true; + if (cfun->eh->built_landing_pads) - { - if (! info->handlers) - info->handlers = alloc_INSN_LIST (lp_region->landing_pad, NULL_RTX); - } + info->callback (lp_region, info->callback_data); else - info->handlers = alloc_INSN_LIST (region->label, info->handlers); + info->callback (region, info->callback_data); } /* Process one level of exception regions for reachability. @@ -2803,7 +2973,7 @@ reachable_next_level (struct eh_region *region, tree type_thrown, If we've touched down at some landing pad previous, then the explicit function call we generated may be used. Otherwise the call is made by the runtime. */ - if (info && info->handlers) + if (info && info->saw_any_handlers) { add_reachable_handler (info, region, region); return RNL_CAUGHT; @@ -2821,40 +2991,30 @@ reachable_next_level (struct eh_region *region, tree type_thrown, abort (); } -/* Retrieve a list of labels of exception handlers which can be - reached by a given insn. */ +/* Invoke CALLBACK on each region reachable from REGION_NUMBER. */ -rtx -reachable_handlers (rtx insn) +void +foreach_reachable_handler (int region_number, bool is_resx, + void (*callback) (struct eh_region *, void *), + void *callback_data) { struct reachable_info info; struct eh_region *region; tree type_thrown; - int region_number; - - if (GET_CODE (insn) == JUMP_INSN - && GET_CODE (PATTERN (insn)) == RESX) - region_number = XINT (PATTERN (insn), 0); - else - { - rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); - if (!note || INTVAL (XEXP (note, 0)) <= 0) - return NULL; - region_number = INTVAL (XEXP (note, 0)); - } memset (&info, 0, sizeof (info)); + info.callback = callback; + info.callback_data = callback_data; region = cfun->eh->region_array[region_number]; type_thrown = NULL_TREE; - if (GET_CODE (insn) == JUMP_INSN - && GET_CODE (PATTERN (insn)) == RESX) + if (is_resx) { /* A RESX leaves a region instead of entering it. Thus the region itself may have been deleted out from under us. */ if (region == NULL) - return NULL; + return; region = region->outer; } else if (region->type == ERT_THROW) @@ -2876,18 +3036,92 @@ reachable_handlers (rtx insn) else region = region->outer; } +} + +/* Retrieve a list of labels of exception handlers which can be + reached by a given insn. */ + +static void +arh_to_landing_pad (struct eh_region *region, void *data) +{ + rtx *p_handlers = data; + if (! *p_handlers) + *p_handlers = alloc_INSN_LIST (region->landing_pad, NULL_RTX); +} + +static void +arh_to_label (struct eh_region *region, void *data) +{ + rtx *p_handlers = data; + *p_handlers = alloc_INSN_LIST (region->label, *p_handlers); +} + +rtx +reachable_handlers (rtx insn) +{ + bool is_resx = false; + rtx handlers = NULL; + int region_number; + + if (GET_CODE (insn) == JUMP_INSN + && GET_CODE (PATTERN (insn)) == RESX) + { + region_number = XINT (PATTERN (insn), 0); + is_resx = true; + } + else + { + rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); + if (!note || INTVAL (XEXP (note, 0)) <= 0) + return NULL; + region_number = INTVAL (XEXP (note, 0)); + } - return info.handlers; + foreach_reachable_handler (region_number, is_resx, + (cfun->eh->built_landing_pads + ? arh_to_landing_pad + : arh_to_label), + &handlers); + + return handlers; } /* Determine if the given INSN can throw an exception that is caught within the function. */ bool -can_throw_internal (rtx insn) +can_throw_internal_1 (int region_number) { struct eh_region *region; tree type_thrown; + + region = cfun->eh->region_array[region_number]; + + type_thrown = NULL_TREE; + if (region->type == ERT_THROW) + { + type_thrown = region->u.throw.type; + region = region->outer; + } + + /* If this exception is ignored by each and every containing region, + then control passes straight out. The runtime may handle some + regions, which also do not require processing internally. */ + for (; region; region = region->outer) + { + enum reachable_code how = reachable_next_level (region, type_thrown, 0); + if (how == RNL_BLOCKED) + return false; + if (how != RNL_NOT_CAUGHT) + return true; + } + + return false; +} + +bool +can_throw_internal (rtx insn) +{ rtx note; if (! INSN_P (insn)) @@ -2916,7 +3150,19 @@ can_throw_internal (rtx insn) if (!note || INTVAL (XEXP (note, 0)) <= 0) return false; - region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; + return can_throw_internal_1 (INTVAL (XEXP (note, 0))); +} + +/* Determine if the given INSN can throw an exception that is + visible outside the function. */ + +bool +can_throw_external_1 (int region_number) +{ + struct eh_region *region; + tree type_thrown; + + region = cfun->eh->region_array[region_number]; type_thrown = NULL_TREE; if (region->type == ERT_THROW) @@ -2925,29 +3171,18 @@ can_throw_internal (rtx insn) region = region->outer; } - /* If this exception is ignored by each and every containing region, - then control passes straight out. The runtime may handle some - regions, which also do not require processing internally. */ - for (; region; region = region->outer) - { - enum reachable_code how = reachable_next_level (region, type_thrown, 0); - if (how == RNL_BLOCKED) - return false; - if (how != RNL_NOT_CAUGHT) - return true; - } + /* If the exception is caught or blocked by any containing region, + then it is not seen by any calling function. */ + for (; region ; region = region->outer) + if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT) + return false; - return false; + return true; } -/* Determine if the given INSN can throw an exception that is - visible outside the function. */ - bool can_throw_external (rtx insn) { - struct eh_region *region; - tree type_thrown; rtx note; if (! INSN_P (insn)) @@ -2986,22 +3221,7 @@ can_throw_external (rtx insn) if (INTVAL (XEXP (note, 0)) <= 0) return false; - region = cfun->eh->region_array[INTVAL (XEXP (note, 0))]; - - type_thrown = NULL_TREE; - if (region->type == ERT_THROW) - { - type_thrown = region->u.throw.type; - region = region->outer; - } - - /* If the exception is caught or blocked by any containing region, - then it is not seen by any calling function. */ - for (; region ; region = region->outer) - if (reachable_next_level (region, type_thrown, NULL) >= RNL_CAUGHT) - return false; - - return true; + return can_throw_external_1 (INTVAL (XEXP (note, 0))); } /* Set current_function_nothrow and cfun->all_throwers_are_sibcalls. */ @@ -3897,6 +4117,7 @@ output_function_exception_table (void) /* Let cgraph know that the rtti decl is used. Not all of the paths below go through assemble_integer, which would take care of this for us. */ + STRIP_NOPS (type); if (TREE_CODE (type) == ADDR_EXPR) { type = TREE_OPERAND (type, 0); diff --git a/gcc/except.h b/gcc/except.h index a75b3d46d80..2fed79f30fb 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -78,16 +78,22 @@ extern void expand_eh_region_end_throw (tree); destroying an object twice. */ extern void expand_eh_region_end_fixup (tree); +/* End some sort of EH region, depending on the argument. */ +extern void expand_eh_handler (tree); + /* Note that the current EH region (if any) may contain a throw, or a call to a function which itself may contain a throw. */ -extern void note_eh_region_may_contain_throw (void); +extern void note_eh_region_may_contain_throw (struct eh_region *); +extern void note_current_region_may_contain_throw (void); /* Invokes CALLBACK for every exception handler label. Only used by old loop hackery; should not be used by new code. */ extern void for_each_eh_label (void (*) (rtx)); /* Determine if the given INSN can throw an exception. */ +extern bool can_throw_internal_1 (int); extern bool can_throw_internal (rtx); +extern bool can_throw_external_1 (int); extern bool can_throw_external (rtx); /* Set current_function_nothrow and cfun->all_throwers_are_sibcalls. */ @@ -119,10 +125,32 @@ extern void expand_builtin_eh_return (tree, tree); extern void expand_eh_return (void); extern rtx expand_builtin_extend_pointer (tree); extern rtx get_exception_pointer (struct function *); +extern rtx get_exception_filter (struct function *); extern int duplicate_eh_regions (struct function *, struct inline_remap *); +extern int check_handled (tree, tree); extern void sjlj_emit_function_exit_after (rtx); +extern struct eh_region *gen_eh_region_cleanup (struct eh_region *, + struct eh_region *); +extern struct eh_region *gen_eh_region_try (struct eh_region *); +extern struct eh_region *gen_eh_region_catch (struct eh_region *, tree); +extern struct eh_region *gen_eh_region_allowed (struct eh_region *, tree); +extern struct eh_region *gen_eh_region_must_not_throw (struct eh_region *); +extern int get_eh_region_number (struct eh_region *); +extern bool get_eh_region_may_contain_throw (struct eh_region *); +extern tree get_eh_region_tree_label (struct eh_region *); +extern void set_eh_region_tree_label (struct eh_region *, tree); + +extern void foreach_reachable_handler (int, bool, + void (*) (struct eh_region *, void *), + void *); + +extern void collect_eh_region_array (void); +extern void expand_resx_expr (tree); + +/* tree-eh.c */ +extern int lookup_stmt_eh_region (tree); /* If non-NULL, this is a function that returns an expression to be executed if an unhandled exception is propagated out of a cleanup diff --git a/gcc/explow.c b/gcc/explow.c index e6eacdcf0bf..155404dc0cf 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -998,11 +998,6 @@ emit_stack_save (enum save_level save_level, rtx *psave, rtx after) *psave = sa = gen_reg_rtx (mode); } } - else - { - if (mode == VOIDmode || GET_MODE (sa) != mode) - abort (); - } if (after) { @@ -1089,6 +1084,27 @@ emit_stack_restore (enum save_level save_level, rtx sa, rtx after) else emit_insn (fcn (stack_pointer_rtx, sa)); } + +/* Invoke emit_stack_save on the nonlocal_goto_save_area for the current + function. This function should be called whenever we allocate or + deallocate dynamic stack space. */ + +void +update_nonlocal_goto_save_area (void) +{ + tree t_save; + rtx r_save; + + /* The nonlocal_goto_save_area object is an array of N pointers. The + first one is used for the frame pointer save; the rest are sized by + STACK_SAVEAREA_MODE. Create a reference to array index 1, the first + of the stack save area slots. */ + t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area, + integer_one_node); + r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE); + + emit_stack_save (SAVE_NONLOCAL, &r_save, NULL_RTX); +} #ifdef SETJMP_VIA_SAVE_AREA /* Optimize RTL generated by allocate_dynamic_stack_space for targets @@ -1413,8 +1429,8 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align) } /* Record the new stack level for nonlocal gotos. */ - if (nonlocal_goto_handler_slots != 0) - emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX); + if (cfun->nonlocal_goto_save_area != 0) + update_nonlocal_goto_save_area (); return target; } @@ -1545,14 +1561,11 @@ probe_stack_range (HOST_WIDE_INT first, rtx size) || REGNO (test_addr) < FIRST_PSEUDO_REGISTER) test_addr = force_reg (Pmode, test_addr); - emit_note (NOTE_INSN_LOOP_BEG); emit_jump (test_lab); emit_label (loop_lab); emit_stack_probe (test_addr); - emit_note (NOTE_INSN_LOOP_CONT); - #ifdef STACK_GROWS_DOWNWARD #define CMP_OPCODE GTU temp = expand_binop (Pmode, sub_optab, test_addr, incr, test_addr, @@ -1570,7 +1583,6 @@ probe_stack_range (HOST_WIDE_INT first, rtx size) emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE, NULL_RTX, Pmode, 1, loop_lab); emit_jump (end_lab); - emit_note (NOTE_INSN_LOOP_END); emit_label (end_lab); emit_stack_probe (last_addr); diff --git a/gcc/expmed.c b/gcc/expmed.c index 54959799411..a8cd617f859 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -1718,9 +1718,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0, 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); + rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); if (tmode != mode) subtarget = 0; op0 = expand_shift (RSHIFT_EXPR, mode, op0, amount, subtarget, 1); } @@ -1759,10 +1757,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0, 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); + rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0); op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1); } diff --git a/gcc/expr.c b/gcc/expr.c index 9239c4a0415..23e128d4704 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -47,6 +47,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "intl.h" #include "tm_p.h" +#include "tree-iterator.h" #include "target.h" /* Decide whether a function's arguments should be processed @@ -143,7 +144,6 @@ static rtx clear_storage_via_libcall (rtx, rtx); static tree clear_storage_libcall_fn (int); static rtx compress_float_constant (rtx, rtx); static rtx get_subtarget (rtx); -static int is_zeros_p (tree); static void store_constructor_field (rtx, unsigned HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode, tree, tree, int, int); @@ -209,9 +209,6 @@ enum insn_code clrstr_optab[NUM_MACHINE_MODES]; enum insn_code cmpstr_optab[NUM_MACHINE_MODES]; enum insn_code cmpmem_optab[NUM_MACHINE_MODES]; -/* Stack of EXPR_WITH_FILE_LOCATION nested expressions. */ -struct file_stack *expr_wfl_stack; - /* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow. */ #ifndef SLOW_UNALIGNED_ACCESS @@ -554,6 +551,11 @@ convert_move (rtx to, rtx from, int unsignedp) if (to_real != from_real) abort (); + /* If the source and destination are already the same, then there's + nothing to do. */ + if (to == from) + return; + /* If FROM is a SUBREG that indicates that we have already done at least the required extension, strip it. We don't handle such SUBREGs as TO here. */ @@ -1688,8 +1690,6 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, y_addr = force_operand (XEXP (y, 0), NULL_RTX); do_pending_stack_adjust (); - emit_note (NOTE_INSN_LOOP_BEG); - emit_jump (cmp_label); emit_label (top_label); @@ -1706,13 +1706,10 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, if (tmp != iter) emit_move_insn (iter, tmp); - emit_note (NOTE_INSN_LOOP_CONT); emit_label (cmp_label); emit_cmp_and_jump_insns (iter, size, LT, NULL_RTX, iter_mode, true, top_label); - - emit_note (NOTE_INSN_LOOP_END); } /* Copy all or part of a value X into registers starting at REGNO. @@ -2801,10 +2798,7 @@ emit_move_insn (rtx x, rtx y) if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode)) abort (); - /* Never force constant_p_rtx to memory. */ - if (GET_CODE (y) == CONSTANT_P_RTX) - ; - else if (CONSTANT_P (y)) + if (CONSTANT_P (y)) { if (optimize && SCALAR_FLOAT_MODE_P (GET_MODE (x)) @@ -2987,9 +2981,6 @@ emit_move_insn_1 (rtx x, rtx y) GET_MODE_SIZE (mode), 0); rtx cmem = adjust_address (mem, mode, 0); - cfun->cannot_inline - = N_("function using short complex types cannot be inline"); - if (packed_dest_p) { rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0); @@ -4396,50 +4387,166 @@ store_expr (tree exp, rtx target, int want_value) return target; } -/* Return 1 if EXP just contains zeros. FIXME merge with initializer_zerop. */ +/* Examine CTOR. Discover how many scalar fields are set to non-zero + values and place it in *P_NZ_ELTS. Discover how many scalar fields + are set to non-constant values and place it in *P_NC_ELTS. */ -static int -is_zeros_p (tree exp) +static void +categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts, + HOST_WIDE_INT *p_nc_elts) { - tree elt; + HOST_WIDE_INT nz_elts, nc_elts; + tree list; - switch (TREE_CODE (exp)) + nz_elts = 0; + nc_elts = 0; + + for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list)) { - case CONVERT_EXPR: - case NOP_EXPR: - case NON_LVALUE_EXPR: - case VIEW_CONVERT_EXPR: - return is_zeros_p (TREE_OPERAND (exp, 0)); + tree value = TREE_VALUE (list); + tree purpose = TREE_PURPOSE (list); + HOST_WIDE_INT mult; - case INTEGER_CST: - return integer_zerop (exp); + mult = 1; + if (TREE_CODE (purpose) == RANGE_EXPR) + { + tree lo_index = TREE_OPERAND (purpose, 0); + tree hi_index = TREE_OPERAND (purpose, 1); - case COMPLEX_CST: - return - is_zeros_p (TREE_REALPART (exp)) && is_zeros_p (TREE_IMAGPART (exp)); + if (host_integerp (lo_index, 1) && host_integerp (hi_index, 1)) + mult = (tree_low_cst (hi_index, 1) + - tree_low_cst (lo_index, 1) + 1); + } - case REAL_CST: - return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0); + switch (TREE_CODE (value)) + { + case CONSTRUCTOR: + { + HOST_WIDE_INT nz = 0, nc = 0; + categorize_ctor_elements_1 (value, &nz, &nc); + nz_elts += mult * nz; + nc_elts += mult * nc; + } + break; - case VECTOR_CST: - for (elt = TREE_VECTOR_CST_ELTS (exp); elt; - elt = TREE_CHAIN (elt)) - if (!is_zeros_p (TREE_VALUE (elt))) - return 0; + case INTEGER_CST: + case REAL_CST: + if (!initializer_zerop (value)) + nz_elts += mult; + break; + case COMPLEX_CST: + if (!initializer_zerop (TREE_REALPART (value))) + nz_elts += mult; + if (!initializer_zerop (TREE_IMAGPART (value))) + nz_elts += mult; + break; + case VECTOR_CST: + { + tree v; + for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v)) + if (!initializer_zerop (TREE_VALUE (v))) + nz_elts += mult; + } + break; - return 1; + default: + nz_elts += mult; + if (!initializer_constant_valid_p (value, TREE_TYPE (value))) + nc_elts += mult; + break; + } + } - case CONSTRUCTOR: - if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE) - return CONSTRUCTOR_ELTS (exp) == NULL_TREE; - for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt)) - if (! is_zeros_p (TREE_VALUE (elt))) - return 0; + *p_nz_elts += nz_elts; + *p_nc_elts += nc_elts; +} + +void +categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts, + HOST_WIDE_INT *p_nc_elts) +{ + *p_nz_elts = 0; + *p_nc_elts = 0; + categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts); +} + +/* Count the number of scalars in TYPE. Return -1 on overflow or + variable-sized. */ + +HOST_WIDE_INT +count_type_elements (tree type) +{ + const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1)); + switch (TREE_CODE (type)) + { + case ARRAY_TYPE: + { + tree telts = array_type_nelts (type); + if (telts && host_integerp (telts, 1)) + { + HOST_WIDE_INT n = tree_low_cst (telts, 1); + HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type)); + if (n == 0) + return 0; + if (max / n < m) + return n * m; + } + return -1; + } + + case RECORD_TYPE: + { + HOST_WIDE_INT n = 0, t; + tree f; + + for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL) + { + t = count_type_elements (TREE_TYPE (f)); + if (t < 0) + return -1; + n += t; + } + + return n; + } + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + /* Ho hum. How in the world do we guess here? Clearly it isn't + right to count the fields. Guess based on the number of words. */ + HOST_WIDE_INT n = int_size_in_bytes (type); + if (n < 0) + return -1; + return n / UNITS_PER_WORD; + } + + case COMPLEX_TYPE: + return 2; + + case VECTOR_TYPE: + /* ??? This is broke. We should encode the vector width in the tree. */ + return GET_MODE_NUNITS (TYPE_MODE (type)); + + case INTEGER_TYPE: + case REAL_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + case POINTER_TYPE: + case OFFSET_TYPE: + case REFERENCE_TYPE: return 1; + case VOID_TYPE: + case METHOD_TYPE: + case FILE_TYPE: + case SET_TYPE: + case FUNCTION_TYPE: + case LANG_TYPE: default: - return 0; + abort (); } } @@ -4449,30 +4556,21 @@ int mostly_zeros_p (tree exp) { if (TREE_CODE (exp) == CONSTRUCTOR) + { - int elts = 0, zeros = 0; - tree elt = CONSTRUCTOR_ELTS (exp); + HOST_WIDE_INT nz_elts, nc_elts, elts; + + /* If there are no ranges of true bits, it is all zero. */ if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE) - { - /* If there are no ranges of true bits, it is all zero. */ - return elt == NULL_TREE; - } - for (; elt; elt = TREE_CHAIN (elt)) - { - /* We do not handle the case where the index is a RANGE_EXPR, - so the statistic will be somewhat inaccurate. - We do make a more accurate count in store_constructor itself, - so since this function is only used for nested array elements, - this should be close enough. */ - if (mostly_zeros_p (TREE_VALUE (elt))) - zeros++; - elts++; - } + return CONSTRUCTOR_ELTS (exp) == NULL_TREE; + + categorize_ctor_elements (exp, &nz_elts, &nc_elts); + elts = count_type_elements (TREE_TYPE (exp)); - return 4 * zeros >= 3 * elts; + return nz_elts < elts / 4; } - return is_zeros_p (exp); + return initializer_zerop (exp); } /* Helper function for store_constructor. @@ -4615,7 +4713,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (field == 0) continue; - if (cleared && is_zeros_p (value)) + if (cleared && initializer_zerop (value)) continue; if (host_integerp (DECL_SIZE (field), 1)) @@ -4849,7 +4947,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) tree index = TREE_PURPOSE (elt); rtx xtarget = target; - if (cleared && is_zeros_p (value)) + if (cleared && initializer_zerop (value)) continue; unsignedp = TYPE_UNSIGNED (elttype); @@ -5271,7 +5369,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, if (bitpos != 0) abort (); - return store_expr (exp, target, 0); + return store_expr (exp, target, value_mode != VOIDmode); } /* If the structure is in a register or if the component @@ -6082,6 +6180,70 @@ highest_pow2_factor_for_target (tree target, tree exp) return MAX (factor, target_align); } +/* Expands variable VAR. */ + +void +expand_var (tree var) +{ + if (DECL_EXTERNAL (var)) + return; + + if (TREE_STATIC (var)) + /* If this is an inlined copy of a static local variable, + look up the original decl. */ + var = DECL_ORIGIN (var); + + if (TREE_STATIC (var) + ? !TREE_ASM_WRITTEN (var) + : !DECL_RTL_SET_P (var)) + { + if (TREE_CODE (var) == VAR_DECL && DECL_DEFER_OUTPUT (var)) + { + /* Prepare a mem & address for the decl. */ + rtx x; + + if (TREE_STATIC (var)) + abort (); + + x = gen_rtx_MEM (DECL_MODE (var), + gen_reg_rtx (Pmode)); + + set_mem_attributes (x, var, 1); + SET_DECL_RTL (var, x); + } + else if ((*lang_hooks.expand_decl) (var)) + /* OK. */; + else if (TREE_CODE (var) == VAR_DECL && !TREE_STATIC (var)) + expand_decl (var); + else if (TREE_CODE (var) == VAR_DECL && TREE_STATIC (var)) + rest_of_decl_compilation (var, NULL, 0, 0); + else if (TREE_CODE (var) == TYPE_DECL + || TREE_CODE (var) == CONST_DECL + || TREE_CODE (var) == FUNCTION_DECL + || TREE_CODE (var) == LABEL_DECL) + /* No expansion needed. */; + else + abort (); + } +} + +/* Expands declarations of variables in list VARS. */ + +static void +expand_vars (tree vars) +{ + for (; vars; vars = TREE_CHAIN (vars)) + { + tree var = vars; + + if (DECL_EXTERNAL (var)) + continue; + + expand_var (var); + expand_decl_init (var); + } +} + /* Subroutine of expand_expr. Expand the two operands of a binary expression EXP0 and EXP1 placing the results in OP0 and OP1. The value may be stored in TARGET if TARGET is nonzero. The @@ -6158,9 +6320,87 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1, COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on recursively. */ +static rtx expand_expr_real_1 (tree, rtx, enum machine_mode, + enum expand_modifier, rtx *); + rtx expand_expr_real (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier, rtx *alt_rtl) +{ + int rn = -1; + rtx ret, last = NULL; + + /* Handle ERROR_MARK before anybody tries to access its type. */ + if (TREE_CODE (exp) == ERROR_MARK + || TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK) + { + ret = CONST0_RTX (tmode); + return ret ? ret : const0_rtx; + } + + if (flag_non_call_exceptions) + { + rn = lookup_stmt_eh_region (exp); + /* If rn < 0, then either (1) tree-ssa not used or (2) doesn't throw. */ + if (rn >= 0) + last = get_last_insn (); + } + + /* If this is an expression of some kind and it has an associated line + number, then emit the line number before expanding the expression. + + We need to save and restore the file and line information so that + errors discovered during expansion are emitted with the right + information. It would be better of the diagnostic routines + used the file/line information embedded in the tree nodes rather + than globals. */ + if (cfun && EXPR_HAS_LOCATION (exp)) + { + location_t saved_location = input_location; + input_location = EXPR_LOCATION (exp); + emit_line_note (input_location); + + /* Record where the insns produced belong. */ + if (cfun->dont_emit_block_notes) + record_block_change (TREE_BLOCK (exp)); + + ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl); + + input_location = saved_location; + } + else + { + ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl); + } + + /* If using non-call exceptions, mark all insns that may trap. + expand_call() will mark CALL_INSNs before we get to this code, + but it doesn't handle libcalls, and these may trap. */ + if (rn >= 0) + { + rtx insn; + for (insn = next_real_insn (last); insn; + insn = next_real_insn (insn)) + { + if (! find_reg_note (insn, REG_EH_REGION, NULL_RTX) + /* If we want exceptions for non-call insns, any + may_trap_p instruction may throw. */ + && GET_CODE (PATTERN (insn)) != CLOBBER + && GET_CODE (PATTERN (insn)) != USE + && (GET_CODE (insn) == CALL_INSN || may_trap_p (PATTERN (insn)))) + { + REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (rn), + REG_NOTES (insn)); + } + } + } + + return ret; +} + +static rtx +expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, + enum expand_modifier modifier, rtx *alt_rtl) { rtx op0, op1, temp; tree type = TREE_TYPE (exp); @@ -6172,15 +6412,6 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, int ignore; tree context; - /* Handle ERROR_MARK before anybody tries to access its type. */ - if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK) - { - op0 = CONST0_RTX (tmode); - if (op0 != 0) - return op0; - return const0_rtx; - } - mode = TYPE_MODE (type); unsignedp = TYPE_UNSIGNED (type); @@ -6264,20 +6495,15 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, case LABEL_DECL: { tree function = decl_function_context (exp); - /* Labels in containing functions, or labels used from initializers, - must be forced. */ - if (modifier == EXPAND_INITIALIZER - || (function != current_function_decl - && function != inline_function_decl - && function != 0)) - temp = force_label_rtx (exp); - else - temp = label_rtx (exp); - temp = gen_rtx_MEM (FUNCTION_MODE, gen_rtx_LABEL_REF (Pmode, temp)); + temp = label_rtx (exp); + temp = gen_rtx_LABEL_REF (Pmode, temp); + if (function != current_function_decl - && function != inline_function_decl && function != 0) - LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1; + && function != 0) + LABEL_REF_NONLOCAL_P (temp) = 1; + + temp = gen_rtx_MEM (FUNCTION_MODE, temp); return temp; } @@ -6320,13 +6546,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, /* Handle variables inherited from containing functions. */ context = decl_function_context (exp); - /* We treat inline_function_decl as an alias for the current function - because that is the inline function whose vars, types, etc. - are being merged into the current function. - See expand_inline_function. */ - if (context != 0 && context != current_function_decl - && context != inline_function_decl /* If var is static, we don't need a static chain to access it. */ && ! (GET_CODE (DECL_RTL (exp)) == MEM && CONSTANT_P (XEXP (DECL_RTL (exp), 0)))) @@ -6484,29 +6704,6 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, copy_rtx (XEXP (temp, 0))); return temp; - case EXPR_WITH_FILE_LOCATION: - { - rtx to_return; - struct file_stack fs; - - fs.location = input_location; - fs.next = expr_wfl_stack; - input_filename = EXPR_WFL_FILENAME (exp); - input_line = EXPR_WFL_LINENO (exp); - expr_wfl_stack = &fs; - if (EXPR_WFL_EMIT_LINE_NOTE (exp)) - emit_line_note (input_location); - /* Possibly avoid switching back and forth here. */ - to_return = expand_expr (EXPR_WFL_NODE (exp), - (ignore ? const0_rtx : target), - tmode, modifier); - if (expr_wfl_stack != &fs) - abort (); - input_location = fs.location; - expr_wfl_stack = fs.next; - return to_return; - } - case SAVE_EXPR: context = decl_function_context (exp); @@ -6515,11 +6712,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, if (context == 0) SAVE_EXPR_CONTEXT (exp) = current_function_decl; - /* We treat inline_function_decl as an alias for the current function - because that is the inline function whose vars, types, etc. - are being merged into the current function. - See expand_inline_function. */ - if (context == current_function_decl || context == inline_function_decl) + if (context == current_function_decl) context = 0; /* If this is non-local, handle it. */ @@ -6641,29 +6834,47 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, case BIND_EXPR: { - tree vars = TREE_OPERAND (exp, 0); + tree block = BIND_EXPR_BLOCK (exp); + int mark_ends; - /* Need to open a binding contour here because - if there are any cleanups they must be contained here. */ - expand_start_bindings (2); + if (TREE_CODE (BIND_EXPR_BODY (exp)) != RTL_EXPR) + { + /* If we're in functions-as-trees mode, this BIND_EXPR represents + the block, so we need to emit NOTE_INSN_BLOCK_* notes. */ + mark_ends = (block != NULL_TREE); + expand_start_bindings_and_block (mark_ends ? 0 : 2, block); + } + else + { + /* If we're not in functions-as-trees mode, we've already emitted + those notes into our RTL_EXPR, so we just want to splice our BLOCK + into the enclosing one. */ + mark_ends = 0; - /* Mark the corresponding BLOCK for output in its proper place. */ - if (TREE_OPERAND (exp, 2) != 0 - && ! TREE_USED (TREE_OPERAND (exp, 2))) - lang_hooks.decls.insert_block (TREE_OPERAND (exp, 2)); + /* Need to open a binding contour here because + if there are any cleanups they must be contained here. */ + expand_start_bindings_and_block (2, NULL_TREE); - /* If VARS have not yet been expanded, expand them now. */ - while (vars) - { - if (!DECL_RTL_SET_P (vars)) - expand_decl (vars); - expand_decl_init (vars); - vars = TREE_CHAIN (vars); + /* Mark the corresponding BLOCK for output in its proper place. */ + if (block) + { + if (TREE_USED (block)) + abort (); + (*lang_hooks.decls.insert_block) (block); + } } - temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier); + /* If VARS have not yet been expanded, expand them now. */ + expand_vars (BIND_EXPR_VARS (exp)); + + /* TARGET was clobbered early in this function. The correct + indicator or whether or not we need the value of this + expression is the IGNORE variable. */ + temp = expand_expr (BIND_EXPR_BODY (exp), + ignore ? const0_rtx : target, + tmode, modifier); - expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0); + expand_end_bindings (BIND_EXPR_VARS (exp), mark_ends, 0); return temp; } @@ -6716,9 +6927,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, && (! MOVE_BY_PIECES_P (tree_low_cst (TYPE_SIZE_UNIT (type), 1), TYPE_ALIGN (type))) - && ((TREE_CODE (type) == VECTOR_TYPE - && !is_zeros_p (exp)) - || ! mostly_zeros_p (exp))))) + && ! mostly_zeros_p (exp)))) || ((modifier == EXPAND_INITIALIZER || modifier == EXPAND_CONST_ADDRESS) && TREE_CONSTANT (exp))) @@ -6753,19 +6962,15 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, case INDIRECT_REF: { tree exp1 = TREE_OPERAND (exp, 0); - tree index; - tree string = string_constant (exp1, &index); - /* Try to optimize reads from const strings. */ - if (string - && TREE_CODE (string) == STRING_CST - && TREE_CODE (index) == INTEGER_CST - && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0 - && GET_MODE_CLASS (mode) == MODE_INT - && GET_MODE_SIZE (mode) == 1 - && modifier != EXPAND_WRITE) - return gen_int_mode (TREE_STRING_POINTER (string) - [TREE_INT_CST_LOW (index)], mode); + if (modifier != EXPAND_WRITE) + { + tree t; + + t = fold_read_from_constant_string (exp); + if (t) + return expand_expr (t, target, tmode, modifier); + } op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM); op0 = memory_address (mode, op0); @@ -6782,8 +6987,11 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, } case ARRAY_REF: + +#ifdef ENABLE_CHECKING if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE) abort (); +#endif { tree array = TREE_OPERAND (exp, 0); @@ -6810,14 +7018,13 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER - && modifier != EXPAND_MEMORY - && TREE_CODE (array) == STRING_CST - && TREE_CODE (index) == INTEGER_CST - && compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0 - && GET_MODE_CLASS (mode) == MODE_INT - && GET_MODE_SIZE (mode) == 1) - return gen_int_mode (TREE_STRING_POINTER (array) - [TREE_INT_CST_LOW (index)], mode); + && modifier != EXPAND_MEMORY) + { + tree t = fold_read_from_constant_string (exp); + + if (t) + return expand_expr (t, target, tmode, modifier); + } /* If this is a constant index into a constant array, just get the value from the array. Handle both the cases when @@ -8187,7 +8394,77 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, (ignore ? const0_rtx : target), VOIDmode, modifier, alt_rtl); + case STATEMENT_LIST: + { + tree_stmt_iterator iter; + + if (!ignore) + abort (); + + for (iter = tsi_start (exp); !tsi_end_p (iter); tsi_next (&iter)) + expand_expr (tsi_stmt (iter), const0_rtx, VOIDmode, modifier); + } + return const0_rtx; + case COND_EXPR: + /* If it's void, we don't need to worry about computing a value. */ + if (VOID_TYPE_P (TREE_TYPE (exp))) + { + tree pred = TREE_OPERAND (exp, 0); + tree then_ = TREE_OPERAND (exp, 1); + tree else_ = TREE_OPERAND (exp, 2); + + /* If we do not have any pending cleanups or stack_levels + to restore, and at least one arm of the COND_EXPR is a + GOTO_EXPR to a local label, then we can emit more efficient + code by using jumpif/jumpifnot instead of the 'if' machinery. */ + if (! optimize + || containing_blocks_have_cleanups_or_stack_level ()) + ; + else if (TREE_CODE (then_) == GOTO_EXPR + && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL) + { + jumpif (pred, label_rtx (GOTO_DESTINATION (then_))); + return expand_expr (else_, const0_rtx, VOIDmode, 0); + } + else if (TREE_CODE (else_) == GOTO_EXPR + && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL) + { + jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_))); + return expand_expr (then_, const0_rtx, VOIDmode, 0); + } + + /* Just use the 'if' machinery. */ + expand_start_cond (pred, 0); + start_cleanup_deferral (); + expand_expr (then_, const0_rtx, VOIDmode, 0); + + exp = else_; + + /* Iterate over 'else if's instead of recursing. */ + for (; TREE_CODE (exp) == COND_EXPR; exp = TREE_OPERAND (exp, 2)) + { + expand_start_else (); + if (EXPR_HAS_LOCATION (exp)) + { + emit_line_note (EXPR_LOCATION (exp)); + if (cfun->dont_emit_block_notes) + record_block_change (TREE_BLOCK (exp)); + } + expand_elseif (TREE_OPERAND (exp, 0)); + expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, 0); + } + /* Don't emit the jump and label if there's no 'else' clause. */ + if (TREE_SIDE_EFFECTS (exp)) + { + expand_start_else (); + expand_expr (exp, const0_rtx, VOIDmode, 0); + } + end_cleanup_deferral (); + expand_end_cond (); + return const0_rtx; + } + /* If we would have a "singleton" (see below) were it not for a conversion in each arm, bring that conversion back out. */ if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR @@ -8665,18 +8942,9 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, case ADDR_EXPR: if (modifier == EXPAND_STACK_PARM) target = 0; - /* Are we taking the address of a nested function? */ - if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL - && decl_function_context (TREE_OPERAND (exp, 0)) != 0 - && ! DECL_NO_STATIC_CHAIN (TREE_OPERAND (exp, 0)) - && ! TREE_STATIC (exp)) - { - op0 = trampoline_address (TREE_OPERAND (exp, 0)); - op0 = force_operand (op0, target); - } /* If we are taking the address of something erroneous, just return a zero. */ - else if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK) + if (TREE_CODE (TREE_OPERAND (exp, 0)) == ERROR_MARK) return const0_rtx; /* If we are taking the address of a constant and are at the top level, we have to use output_constant_def since we can't @@ -8903,25 +9171,38 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, return target; } + case RESX_EXPR: + expand_resx_expr (exp); + return const0_rtx; + case TRY_CATCH_EXPR: { tree handler = TREE_OPERAND (exp, 1); expand_eh_region_start (); - op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0); - - expand_eh_region_end_cleanup (handler); + expand_eh_handler (handler); return op0; } + case CATCH_EXPR: + expand_start_catch (CATCH_TYPES (exp)); + expand_expr (CATCH_BODY (exp), const0_rtx, VOIDmode, 0); + expand_end_catch (); + return const0_rtx; + + case EH_FILTER_EXPR: + /* Should have been handled in expand_eh_handler. */ + abort (); + case TRY_FINALLY_EXPR: { tree try_block = TREE_OPERAND (exp, 0); tree finally_block = TREE_OPERAND (exp, 1); - if (!optimize || unsafe_for_reeval (finally_block) > 1) + if ((!optimize && lang_protect_cleanup_actions == NULL) + || unsafe_for_reeval (finally_block) > 1) { /* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR is not sufficient, so we cannot expand the block twice. @@ -8990,11 +9271,99 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode, case EXC_PTR_EXPR: return get_exception_pointer (cfun); + case FILTER_EXPR: + return get_exception_filter (cfun); + case FDESC_EXPR: /* Function descriptors are not valid except for as initialization constants, and should not be expanded. */ abort (); + case SWITCH_EXPR: + expand_start_case (0, SWITCH_COND (exp), integer_type_node, + "switch"); + if (SWITCH_BODY (exp)) + expand_expr_stmt (SWITCH_BODY (exp)); + if (SWITCH_LABELS (exp)) + { + tree duplicate = 0; + tree vec = SWITCH_LABELS (exp); + size_t i, n = TREE_VEC_LENGTH (vec); + + for (i = 0; i < n; ++i) + { + tree elt = TREE_VEC_ELT (vec, i); + tree controlling_expr_type = TREE_TYPE (SWITCH_COND (exp)); + tree min_value = TYPE_MIN_VALUE (controlling_expr_type); + tree max_value = TYPE_MAX_VALUE (controlling_expr_type); + + tree case_low = CASE_LOW (elt); + tree case_high = CASE_HIGH (elt) ? CASE_HIGH (elt) : case_low; + if (case_low && case_high) + { + /* Case label is less than minimum for type. */ + if ((tree_int_cst_compare (case_low, min_value) < 0) + && (tree_int_cst_compare (case_high, min_value) < 0)) + { + warning ("case label value %d is less than minimum value for type", + TREE_INT_CST (case_low)); + continue; + } + + /* Case value is greater than maximum for type. */ + if ((tree_int_cst_compare (case_low, max_value) > 0) + && (tree_int_cst_compare (case_high, max_value) > 0)) + { + warning ("case label value %d exceeds maximum value for type", + TREE_INT_CST (case_high)); + continue; + } + + /* Saturate lower case label value to minimum. */ + if ((tree_int_cst_compare (case_high, min_value) >= 0) + && (tree_int_cst_compare (case_low, min_value) < 0)) + { + warning ("lower value %d in case label range less than minimum value for type", + TREE_INT_CST (case_low)); + case_low = min_value; + } + + /* Saturate upper case label value to maximum. */ + if ((tree_int_cst_compare (case_low, max_value) <= 0) + && (tree_int_cst_compare (case_high, max_value) > 0)) + { + warning ("upper value %d in case label range exceeds maximum value for type", + TREE_INT_CST (case_high)); + case_high = max_value; + } + } + + add_case_node (case_low, case_high, CASE_LABEL (elt), &duplicate, true); + if (duplicate) + abort (); + } + } + expand_end_case_type (SWITCH_COND (exp), TREE_TYPE (exp)); + return const0_rtx; + + case LABEL_EXPR: + expand_label (TREE_OPERAND (exp, 0)); + return const0_rtx; + + case CASE_LABEL_EXPR: + { + tree duplicate = 0; + add_case_node (CASE_LOW (exp), CASE_HIGH (exp), CASE_LABEL (exp), + &duplicate, false); + if (duplicate) + abort (); + return const0_rtx; + } + + case ASM_EXPR: + expand_asm_expr (exp); + return const0_rtx; + default: /* ??? Use (*fun) form because expand_expr is a macro. */ return (*lang_hooks.expand_expr) (exp, original_target, tmode, @@ -9075,6 +9444,13 @@ string_constant (tree arg, tree *ptr_offset) *ptr_offset = size_zero_node; return TREE_OPERAND (arg, 0); } + if (TREE_CODE (arg) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)) == STRING_CST) + { + *ptr_offset = convert (sizetype, TREE_OPERAND (TREE_OPERAND (arg, 0), 1)); + return TREE_OPERAND (TREE_OPERAND (arg, 0), 0); + } else if (TREE_CODE (arg) == PLUS_EXPR) { tree arg0 = TREE_OPERAND (arg, 0); @@ -9795,7 +10171,7 @@ const_vector_from_tree (tree exp) mode = TYPE_MODE (TREE_TYPE (exp)); - if (is_zeros_p (exp)) + if (initializer_zerop (exp)) return CONST0_RTX (mode); units = GET_MODE_NUNITS (mode); diff --git a/gcc/expr.h b/gcc/expr.h index 5c7bbbe6c51..002bcfc892d 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -366,6 +366,9 @@ extern void record_base_value (unsigned int, rtx, int); extern void record_alias_subset (HOST_WIDE_INT, HOST_WIDE_INT); extern HOST_WIDE_INT new_alias_set (void); extern int can_address_p (tree); +extern tree simplify_builtin_fputs (tree, int, int, tree); +extern tree simplify_builtin_strcpy (tree, tree); +extern tree simplify_builtin_strncpy (tree, tree); /* Functions from expr.c: */ @@ -513,6 +516,8 @@ extern rtx force_operand (rtx, rtx); extern rtx expand_expr_real (tree, rtx, enum machine_mode, enum expand_modifier, rtx *); +extern void expand_var (tree); + /* At the start of a function, record that we have no previously-pushed arguments waiting to be popped. */ extern void init_pending_stack_adjust (void); @@ -561,8 +566,6 @@ extern rtx expr_size (tree); if the size can vary or is larger than an integer. */ extern HOST_WIDE_INT int_expr_size (tree); -extern rtx lookup_static_chain (tree); - /* Convert a stack slot address ADDR valid in function FNDECL into an address valid in this function (using a static chain). */ extern rtx fix_lexical_addr (rtx, tree); @@ -574,10 +577,12 @@ extern rtx trampoline_address (tree); in its original home. This becomes invalid if any more code is emitted. */ extern rtx hard_function_value (tree, tree, int); -extern rtx prepare_call_address (rtx, tree, rtx *, int, int); +extern rtx prepare_call_address (rtx, rtx, rtx *, int, int); extern rtx expand_call (tree, rtx, int); +extern void fixup_tail_calls (void); + #ifdef TREE_CODE extern rtx expand_shift (enum tree_code, enum machine_mode, rtx, tree, rtx, int); @@ -588,7 +593,6 @@ extern rtx expand_divmod (int, enum tree_code, enum machine_mode, rtx, rtx, extern void locate_and_pad_parm (enum machine_mode, tree, int, int, tree, struct args_size *, struct locate_and_pad_arg_data *); -extern rtx expand_inline_function (tree, tree, rtx, int, tree, rtx); /* Return the CODE_LABEL rtx for a LABEL_DECL, creating it if necessary. */ extern rtx label_rtx (tree); @@ -742,6 +746,9 @@ extern void emit_stack_save (enum save_level, rtx *, rtx); /* Restore the stack pointer from a save area of the specified level. */ extern void emit_stack_restore (enum save_level, rtx, rtx); +/* Invoke emit_stack_save for the nonlocal_goto_save_area. */ +extern void update_nonlocal_goto_save_area (void); + /* Allocate some space on the stack dynamically and return its address. An rtx says how many bytes. */ extern rtx allocate_dynamic_stack_space (rtx, rtx, int); @@ -796,6 +803,4 @@ extern void do_jump_by_parts_equality_rtx (rtx, rtx, rtx); extern void do_jump_by_parts_greater_rtx (enum machine_mode, int, rtx, rtx, rtx, rtx); -extern void mark_seen_cases (tree, unsigned char *, HOST_WIDE_INT, int); - extern int vector_mode_valid_p (enum machine_mode); diff --git a/gcc/f/ChangeLog b/gcc/f/ChangeLog index edbff11016d..0d3532e5da6 100644 --- a/gcc/f/ChangeLog +++ b/gcc/f/ChangeLog @@ -1,3 +1,9 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. + + * config-lang.in (build_by_default): Set to no. + 2004-04-18 Gerald Pfeifer * g77.texi (Floating-point Errors): Avoid referencing diff --git a/gcc/f/ChangeLog.tree-ssa b/gcc/f/ChangeLog.tree-ssa new file mode 100644 index 00000000000..783ebaa998b --- /dev/null +++ b/gcc/f/ChangeLog.tree-ssa @@ -0,0 +1,21 @@ +2003-11-16 Toon Moene + + * config-lang.in: Re-add. + +2003-10-26 Richard Henderson + + * config-lang.in: Remove. + +2003-09-24 Jason Merrill + + * com.c, ste.c: Revert earlier change. + +2003-01-15 Jeff Law + + * com.c (duplicate_decls): Use TREE_FILENAME and TREE_LINENO + to extract file/line information from nodes. Use TREE_LOCUS + to copy file/line information from one node to another. + Make sure to copy TREE_LOCUS from the old decl to the new decl. + (pushdecl): Similarly. + * ste.c: Likewise. + diff --git a/gcc/f/config-lang.in b/gcc/f/config-lang.in index 92ba5cca73e..8ec70f7af8c 100644 --- a/gcc/f/config-lang.in +++ b/gcc/f/config-lang.in @@ -34,3 +34,5 @@ stagestuff="g77\$(exeext) g77-cross\$(exeext) f771\$(exeext)" target_libs=target-libf2c gtfiles="\$(srcdir)/f/com.c \$(srcdir)/f/com.h \$(srcdir)/f/ste.c \$(srcdir)/f/where.h \$(srcdir)/f/where.c \$(srcdir)/f/lex.c" + +build_by_default=no diff --git a/gcc/final.c b/gcc/final.c index 500f4062e2d..96a7a5bfcdb 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -1409,7 +1409,7 @@ profile_function (FILE *file ATTRIBUTE_UNUSED) int sval = current_function_returns_struct; rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1); #if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM) - int cxt = current_function_needs_context; + int cxt = cfun->static_chain_decl != NULL; #endif #endif /* ASM_OUTPUT_REG_PUSH */ @@ -1516,11 +1516,9 @@ final (rtx first, FILE *file, int optimize, int prescan) for (insn = first; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0) { - if ((RTX_INTEGRATED_P (insn) - && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0) - || (last != 0 - && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) - && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last))) + if (last != 0 + && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last) + && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)) { delete_insn (insn); /* Use delete_note. */ continue; diff --git a/gcc/flags.h b/gcc/flags.h index 458b2e9432f..8778b635392 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -720,6 +720,53 @@ extern int flag_detailed_statistics; /* Nonzero means enable synchronous exceptions for non-call instructions. */ extern int flag_non_call_exceptions; +/* Nonzero means enable mudflap bounds-checking transforms; + >1 means also to include multithreading locks. */ +extern int flag_mudflap; +extern int flag_mudflap_threads; +extern int flag_mudflap_ignore_reads; + +/* Enable SSA-PRE on trees. */ +extern int flag_tree_pre; + +/* Enable SSA-CCP on trees. */ +extern int flag_tree_ccp; + +/* Enable SSA-DCE on trees. */ +extern int flag_tree_dce; + +/* Enable SSA->normal pass memory location coalescing. */ +extern int flag_tree_combine_temps; + +/* Enable SSA->normal pass expression replacement. */ +extern int flag_tree_ter; + +/* Enable SSA_>normal live range splitting. */ +extern int flag_tree_live_range_split; + +/* Enable dominator optimizations. */ +extern int flag_tree_dom; + +/* Enable loop header copying on tree-ssa. */ +extern int flag_tree_ch; + +/* Enable dead store and redundant load elimination */ +extern int flag_tree_dse; + +/* Enable scalar replacement of aggregates. */ +extern int flag_tree_sra; + +/* Enable copy rename optimization. */ +extern int flag_tree_copyrename; + +/* Enable points-to analysis on trees. */ +enum pta_type + { + PTA_NONE, + PTA_ANDERSEN + }; +extern enum pta_type flag_tree_points_to; + /* Nonzero means put zero initialized data in the bss section. */ extern int flag_zero_initialized_in_bss; diff --git a/gcc/flow.c b/gcc/flow.c index 49729bb538e..fa47f2d24a0 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -192,10 +192,6 @@ regset regs_live_at_setjmp; are another pair, etc. */ rtx regs_may_share; -/* Callback that determines if it's ok for a function to have no - noreturn attribute. */ -int (*lang_missing_noreturn_ok_p) (tree); - /* Set of registers that may be eliminable. These are handled specially in updating regs_ever_live. */ @@ -334,48 +330,6 @@ static void invalidate_mems_from_set (struct propagate_block_info *, rtx); static void clear_log_links (sbitmap); static int count_or_remove_death_notes_bb (basic_block, int); - -void -check_function_return_warnings (void) -{ - if (warn_missing_noreturn - && !TREE_THIS_VOLATILE (cfun->decl) - && EXIT_BLOCK_PTR->pred == NULL - && (lang_missing_noreturn_ok_p - && !lang_missing_noreturn_ok_p (cfun->decl))) - warning ("function might be possible candidate for attribute `noreturn'"); - - /* If we have a path to EXIT, then we do return. */ - if (TREE_THIS_VOLATILE (cfun->decl) - && EXIT_BLOCK_PTR->pred != NULL) - warning ("`noreturn' function does return"); - - /* If the clobber_return_insn appears in some basic block, then we - do reach the end without returning a value. */ - else if (warn_return_type - && cfun->x_clobber_return_insn != NULL - && EXIT_BLOCK_PTR->pred != NULL) - { - int max_uid = get_max_uid (); - - /* If clobber_return_insn was excised by jump1, then renumber_insns - can make max_uid smaller than the number still recorded in our rtx. - That's fine, since this is a quick way of verifying that the insn - is no longer in the chain. */ - if (INSN_UID (cfun->x_clobber_return_insn) < max_uid) - { - rtx insn; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (insn == cfun->x_clobber_return_insn) - { - warning ("control reaches end of non-void function"); - break; - } - } - } -} - /* Return the INSN immediately following the NOTE_INSN_BASIC_BLOCK note associated with the BLOCK. */ @@ -683,8 +637,7 @@ update_life_info (sbitmap blocks, enum update_life_extent extent, int prop_flags /* Zap the life information from the last round. If we don't do this, we can wind up with registers that no longer appear - in the code being marked live at entry, which twiggs bogus - warnings from regno_uninitialized. */ + in the code being marked live at entry. */ FOR_EACH_BB (bb) { CLEAR_REG_SET (bb->global_live_at_start); @@ -815,7 +768,7 @@ free_basic_block_vars (void) if (basic_block_info) { clear_edges (); - VARRAY_FREE (basic_block_info); + basic_block_info = NULL; } n_basic_blocks = 0; last_basic_block = 0; @@ -2350,24 +2303,6 @@ libcall_dead_p (struct propagate_block_info *pbi, rtx note, rtx insn) return 1; } -/* Return 1 if register REGNO was used before it was set, i.e. if it is - live at function entry. Don't count global register variables, variables - in registers that can be used for function arg passing, or variables in - fixed hard registers. */ - -int -regno_uninitialized (unsigned int regno) -{ - if (n_basic_blocks == 0 - || (regno < FIRST_PSEUDO_REGISTER - && (global_regs[regno] - || fixed_regs[regno] - || FUNCTION_ARG_REGNO_P (regno)))) - return 0; - - return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->global_live_at_end, regno); -} - /* 1 if register REGNO was alive at a place where `setjmp' was called and was set more than once or is an argument. Such regs may be clobbered by `longjmp'. */ @@ -4285,7 +4220,6 @@ count_or_remove_death_notes (sbitmap blocks, int kill) int i; basic_block bb; - /* This used to be a loop over all the blocks with a membership test inside the loop. That can be amazingly expensive on a large CFG when only a small number of bits are set in BLOCKs (for example, diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7d04db61307..ed54ee93bb6 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -65,7 +65,6 @@ static bool negate_expr_p (tree); static tree negate_expr (tree); static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int); static tree associate_trees (tree, tree, enum tree_code, tree); -static tree int_const_binop (enum tree_code, tree, tree, int); static tree const_binop (enum tree_code, tree, tree, int); static hashval_t size_htab_hash (const void *); static int size_htab_eq (const void *, const void *); @@ -116,6 +115,7 @@ static bool tree_swap_operands_p (tree, tree, bool); static tree fold_negate_const (tree, tree); static tree fold_abs_const (tree, tree); static tree fold_relational_const (enum tree_code, tree, tree, tree); +static tree fold_relational_hi_lo (enum tree_code *, const tree, tree *, tree *); /* The following constants represent a bit based encoding of GCC's comparison operators. This encoding simplifies transformations @@ -1230,7 +1230,7 @@ associate_trees (tree t1, tree t2, enum tree_code code, tree type) If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ -static tree +tree int_const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) { unsigned HOST_WIDE_INT int1l, int2l; @@ -1990,8 +1990,6 @@ fold_convert (tree type, tree arg) tree non_lvalue (tree x) { - tree result; - /* These things are certainly not lvalues. */ if (TREE_CODE (x) == NON_LVALUE_EXPR || TREE_CODE (x) == INTEGER_CST @@ -2000,9 +1998,7 @@ non_lvalue (tree x) || TREE_CODE (x) == ADDR_EXPR) return x; - result = build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x); - TREE_CONSTANT (result) = TREE_CONSTANT (x); - return result; + return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x); } /* Nonzero means lvalues are limited to those valid in pedantic ANSI C. @@ -2138,16 +2134,16 @@ truth_value_p (enum tree_code code) /* Return nonzero if two operands (typically of the same tree node) are necessarily equal. If either argument has side-effects this - function returns zero. + function returns zero. FLAGS modifies behaviour as follows: - If ONLY_CONST is nonzero, only return nonzero for constants. + If OEP_ONLY_CONST is set, only return nonzero for constants. This function tests whether the operands are indistinguishable; it does not test whether they are equal using C's == operation. The distinction is important for IEEE floating point, because (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and (2) two NaNs may be indistinguishable, but NaN!=NaN. - If ONLY_CONST is zero, a VAR_DECL is considered equal to itself + If OEP_ONLY_CONST is unset, a VAR_DECL is considered equal to itself even though it may hold multiple values during a function. This is because a GCC tree node guarantees that nothing else is executed between the evaluation of its "operands" (which may often @@ -2156,13 +2152,15 @@ truth_value_p (enum tree_code code) same value in each operand/subexpression. Hence a zero value for ONLY_CONST assumes isochronic (or instantaneous) tree equivalence. If comparing arbitrary expression trees, such as from different - statements, ONLY_CONST must usually be nonzero. */ + statements, ONLY_CONST must usually be nonzero. + + If OEP_PURE_SAME is set, then pure functions with identical arguments + are considered the same. It is used when the caller has other ways + to ensure that global memory is unchanged in between. */ int -operand_equal_p (tree arg0, tree arg1, int only_const) +operand_equal_p (tree arg0, tree arg1, unsigned int flags) { - tree fndecl; - /* If either is ERROR_MARK, they aren't equal. */ if (TREE_CODE (arg0) == ERROR_MARK || TREE_CODE (arg1) == ERROR_MARK) return 0; @@ -2191,7 +2189,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) expressions with side effects that should be treated the same due to the only side effects being identical SAVE_EXPR's, that will be detected in the recursive calls below. */ - if (arg0 == arg1 && ! only_const + if (arg0 == arg1 && ! (flags & OEP_ONLY_CONST) && (TREE_CODE (arg0) == SAVE_EXPR || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1)))) return 1; @@ -2225,7 +2223,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) while (v1 && v2) { if (!operand_equal_p (TREE_VALUE (v1), TREE_VALUE (v2), - only_const)) + flags)) return 0; v1 = TREE_CHAIN (v1); v2 = TREE_CHAIN (v2); @@ -2236,9 +2234,9 @@ operand_equal_p (tree arg0, tree arg1, int only_const) case COMPLEX_CST: return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1), - only_const) + flags) && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1), - only_const)); + flags)); case STRING_CST: return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1) @@ -2253,7 +2251,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) break; } - if (only_const) + if (flags & OEP_ONLY_CONST) return 0; switch (TREE_CODE_CLASS (TREE_CODE (arg0))) @@ -2266,7 +2264,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) return 0; return operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0); + TREE_OPERAND (arg1, 0), flags); case '<': case '2': @@ -2278,9 +2276,9 @@ operand_equal_p (tree arg0, tree arg1, int only_const) /* For commutative ops, allow the other order. */ return (commutative_tree_code (TREE_CODE (arg0)) && operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 1), 0) + TREE_OPERAND (arg1, 1), flags) && operand_equal_p (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 0), 0)); + TREE_OPERAND (arg1, 0), flags)); case 'r': /* If either of the pointer (or reference) expressions we are @@ -2293,23 +2291,23 @@ operand_equal_p (tree arg0, tree arg1, int only_const) { case INDIRECT_REF: return operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0); + TREE_OPERAND (arg1, 0), flags); case COMPONENT_REF: case ARRAY_REF: case ARRAY_RANGE_REF: return (operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0) + TREE_OPERAND (arg1, 0), flags) && operand_equal_p (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 1), 0)); + TREE_OPERAND (arg1, 1), flags)); case BIT_FIELD_REF: return (operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0) + TREE_OPERAND (arg1, 0), flags) && operand_equal_p (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 1), 0) + TREE_OPERAND (arg1, 1), flags) && operand_equal_p (TREE_OPERAND (arg0, 2), - TREE_OPERAND (arg1, 2), 0)); + TREE_OPERAND (arg1, 2), flags)); default: return 0; } @@ -2320,7 +2318,7 @@ operand_equal_p (tree arg0, tree arg1, int only_const) case ADDR_EXPR: case TRUTH_NOT_EXPR: return operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0); + TREE_OPERAND (arg1, 0), flags); case RTL_EXPR: return rtx_equal_p (RTL_EXPR_RTL (arg0), RTL_EXPR_RTL (arg1)); @@ -2329,14 +2327,18 @@ operand_equal_p (tree arg0, tree arg1, int only_const) /* If the CALL_EXPRs call different functions, then they clearly can not be equal. */ if (! operand_equal_p (TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg1, 0), 0)) + TREE_OPERAND (arg1, 0), flags)) return 0; - /* Only consider const functions equivalent. */ - fndecl = get_callee_fndecl (arg0); - if (fndecl == NULL_TREE - || ! (flags_from_decl_or_type (fndecl) & ECF_CONST)) - return 0; + { + unsigned int cef = call_expr_flags (arg0); + if (flags & OEP_PURE_SAME) + cef &= ECF_CONST | ECF_PURE; + else + cef &= ECF_CONST; + if (!cef) + return 0; + } /* Now see if all the arguments are the same. operand_equal_p does not handle TREE_LIST, so we walk the operands here @@ -2345,7 +2347,8 @@ operand_equal_p (tree arg0, tree arg1, int only_const) arg1 = TREE_OPERAND (arg1, 1); while (arg0 && arg1) { - if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1), 0)) + if (! operand_equal_p (TREE_VALUE (arg0), TREE_VALUE (arg1), + flags)) return 0; arg0 = TREE_CHAIN (arg0); @@ -2361,11 +2364,11 @@ operand_equal_p (tree arg0, tree arg1, int only_const) } case 'd': - /* Consider __builtin_sqrt equal to sqrt. */ - return TREE_CODE (arg0) == FUNCTION_DECL - && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1) - && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1) - && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1); + /* Consider __builtin_sqrt equal to sqrt. */ + return (TREE_CODE (arg0) == FUNCTION_DECL + && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1) + && DECL_BUILT_IN_CLASS (arg0) == DECL_BUILT_IN_CLASS (arg1) + && DECL_FUNCTION_CODE (arg0) == DECL_FUNCTION_CODE (arg1)); default: return 0; @@ -2730,6 +2733,9 @@ invert_truthvalue (tree arg) return invert_truthvalue (TREE_OPERAND (arg, 0)); case NOP_EXPR: + if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + break; + case CONVERT_EXPR: case FLOAT_EXPR: return build1 (TREE_CODE (arg), type, @@ -5527,6 +5533,15 @@ tree_swap_operands_p (tree arg0, tree arg1, bool reorder) if (DECL_P (arg0)) return 1; + if (reorder && flag_evaluation_order + && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1))) + return 0; + + if (DECL_P (arg1)) + return 0; + if (DECL_P (arg0)) + return 1; + return 0; } @@ -5553,6 +5568,7 @@ fold (tree expr) tree arg0 = NULL_TREE, arg1 = NULL_TREE; enum tree_code code = TREE_CODE (t); int kind = TREE_CODE_CLASS (code); + /* WINS will be nonzero when the switch is done if all operands are constant. */ int wins = 1; @@ -5673,9 +5689,10 @@ fold (tree expr) && integer_onep (TREE_OPERAND (arg0, 1))))))) { tem = fold (build (code == BIT_AND_EXPR ? TRUTH_AND_EXPR - : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR - : TRUTH_XOR_EXPR, - type, arg0, arg1)); + : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR + : TRUTH_XOR_EXPR, + type, fold_convert (boolean_type_node, arg0), + fold_convert (boolean_type_node, arg1))); if (code == EQ_EXPR) tem = invert_truthvalue (tem); @@ -5731,9 +5748,18 @@ fold (tree expr) return tem; } else if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<') - return fold (build (COND_EXPR, type, arg0, - fold (build1 (code, type, integer_one_node)), - fold (build1 (code, type, integer_zero_node)))); + { + if (TREE_CODE (type) == BOOLEAN_TYPE) + { + arg0 = copy_node (arg0); + TREE_TYPE (arg0) = type; + return arg0; + } + else if (TREE_CODE (type) != INTEGER_TYPE) + return fold (build (COND_EXPR, type, arg0, + fold (build1 (code, type, integer_one_node)), + fold (build1 (code, type, integer_zero_node)))); + } } else if (TREE_CODE_CLASS (code) == '<' && TREE_CODE (arg0) == COMPOUND_EXPR) @@ -5884,7 +5910,7 @@ fold (tree expr) TREE_OPERAND (tem, 0) = TREE_OPERAND (prev, 1); /* First do the assignment, then return converted constant. */ tem = build (COMPOUND_EXPR, TREE_TYPE (tem), prev, fold (tem)); - TREE_NO_UNUSED_WARNING (tem) = 1; + TREE_NO_WARNING (tem) = 1; TREE_USED (tem) = 1; return tem; } @@ -5932,6 +5958,26 @@ fold (tree expr) fold_convert (type, and1))); } + /* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and + T2 being pointers to types of the same size. */ + if (POINTER_TYPE_P (TREE_TYPE (t)) + && TREE_CODE_CLASS (TREE_CODE (arg0)) == '2' + && TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0)))) + { + tree arg00 = TREE_OPERAND (arg0, 0); + tree t0 = TREE_TYPE (t); + tree t1 = TREE_TYPE (arg00); + tree tt0 = TREE_TYPE (t0); + tree tt1 = TREE_TYPE (t1); + tree s0 = TYPE_SIZE (tt0); + tree s1 = TYPE_SIZE (tt1); + + if (s0 && s1 && operand_equal_p (s0, s1, OEP_ONLY_CONST)) + return build (TREE_CODE (arg0), t0, convert (t0, arg00), + TREE_OPERAND (arg0, 1)); + } + tem = fold_convert_const (code, type, arg0); return tem ? tem : t; @@ -5956,6 +6002,7 @@ fold (tree expr) { tem = copy_node (t); TREE_CONSTANT (tem) = wins; + TREE_INVARIANT (tem) = wins; return tem; } return t; @@ -7131,7 +7178,7 @@ fold (tree expr) if (operand_equal_p (arg0, arg1, 0)) return omit_one_operand (type, arg0, arg1); if (INTEGRAL_TYPE_P (type) - && operand_equal_p (arg1, TYPE_MIN_VALUE (type), 1)) + && operand_equal_p (arg1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST)) return omit_one_operand (type, arg1, arg0); goto associate; @@ -7140,7 +7187,7 @@ fold (tree expr) return omit_one_operand (type, arg0, arg1); if (INTEGRAL_TYPE_P (type) && TYPE_MAX_VALUE (type) - && operand_equal_p (arg1, TYPE_MAX_VALUE (type), 1)) + && operand_equal_p (arg1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST)) return omit_one_operand (type, arg1, arg0); goto associate; @@ -7284,6 +7331,9 @@ fold (tree expr) return non_lvalue (fold_convert (type, invert_truthvalue (arg1))); if (integer_onep (arg1)) return non_lvalue (fold_convert (type, invert_truthvalue (arg0))); + /* Identical arguments cancel to zero. */ + if (operand_equal_p (arg0, arg1, 0)) + return omit_one_operand (type, integer_zero_node, arg0); return t; case EQ_EXPR: @@ -7520,7 +7570,11 @@ fold (tree expr) } /* Comparisons with the highest or lowest possible integer of - the specified size will have known values. */ + the specified size will have known values. + + This is quite similar to fold_relational_hi_lo; however, my + attempts to share the code have been nothing but trouble. + I give up for now. */ { int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg1))); @@ -7622,7 +7676,8 @@ fold (tree expr) break; } - else if (TREE_INT_CST_HIGH (arg1) == 0 + else if (!in_gimple_form + && TREE_INT_CST_HIGH (arg1) == 0 && TREE_INT_CST_LOW (arg1) == signed_max && TYPE_UNSIGNED (TREE_TYPE (arg1)) /* signed_type does not work on pointer types. */ @@ -8262,40 +8317,48 @@ fold (tree expr) case LT_EXPR: /* If C1 is C2 + 1, this is min(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (PLUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MIN_EXPR, type, arg1, arg2))); break; case LE_EXPR: /* If C1 is C2 - 1, this is min(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (MINUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MIN_EXPR, type, arg1, arg2))); break; case GT_EXPR: /* If C1 is C2 - 1, this is max(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (MINUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MAX_EXPR, type, arg1, arg2))); break; case GE_EXPR: /* If C1 is C2 + 1, this is max(A, C2). */ - if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), 1) + if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type), + OEP_ONLY_CONST) && operand_equal_p (TREE_OPERAND (arg0, 1), const_binop (PLUS_EXPR, arg2, - integer_one_node, 0), 1)) + integer_one_node, 0), + OEP_ONLY_CONST)) return pedantic_non_lvalue (fold (build (MAX_EXPR, type, arg1, arg2))); break; @@ -8348,7 +8411,7 @@ fold (tree expr) && integer_pow2p (arg1) && TREE_CODE (TREE_OPERAND (arg0, 0)) == BIT_AND_EXPR && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg0, 0), 1), - arg1, 1)) + arg1, OEP_ONLY_CONST)) return pedantic_non_lvalue (fold_convert (type, TREE_OPERAND (arg0, 0))); @@ -9183,6 +9246,598 @@ rtl_expr_nonnegative_p (rtx r) } } + +/* See if we are applying CODE, a relational to the highest or lowest + possible integer of TYPE. If so, then the result is a compile + time constant. */ + +static tree +fold_relational_hi_lo (enum tree_code *code_p, const tree type, tree *op0_p, + tree *op1_p) +{ + tree op0 = *op0_p; + tree op1 = *op1_p; + enum tree_code code = *code_p; + int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (op1))); + + if (TREE_CODE (op1) == INTEGER_CST + && ! TREE_CONSTANT_OVERFLOW (op1) + && width <= HOST_BITS_PER_WIDE_INT + && (INTEGRAL_TYPE_P (TREE_TYPE (op1)) + || POINTER_TYPE_P (TREE_TYPE (op1)))) + { + unsigned HOST_WIDE_INT signed_max; + unsigned HOST_WIDE_INT max, min; + + signed_max = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1; + + if (TYPE_UNSIGNED (TREE_TYPE (op1))) + { + max = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1; + min = 0; + } + else + { + max = signed_max; + min = ((unsigned HOST_WIDE_INT) -1 << (width - 1)); + } + + if (TREE_INT_CST_HIGH (op1) == 0 + && TREE_INT_CST_LOW (op1) == max) + switch (code) + { + case GT_EXPR: + return omit_one_operand (type, + convert (type, integer_zero_node), + op0); + case GE_EXPR: + *code_p = EQ_EXPR; + break; + case LE_EXPR: + return omit_one_operand (type, + convert (type, integer_one_node), + op0); + case LT_EXPR: + *code_p = NE_EXPR; + break; + + /* The GE_EXPR and LT_EXPR cases above are not normally + reached because of previous transformations. */ + + default: + break; + } + else if (TREE_INT_CST_HIGH (op1) == 0 + && TREE_INT_CST_LOW (op1) == max - 1) + switch (code) + { + case GT_EXPR: + *code_p = EQ_EXPR; + *op1_p = const_binop (PLUS_EXPR, op1, integer_one_node, 0); + break; + case LE_EXPR: + *code_p = NE_EXPR; + *op1_p = const_binop (PLUS_EXPR, op1, integer_one_node, 0); + break; + default: + break; + } + else if (TREE_INT_CST_HIGH (op1) == (min ? -1 : 0) + && TREE_INT_CST_LOW (op1) == min) + switch (code) + { + case LT_EXPR: + return omit_one_operand (type, + convert (type, integer_zero_node), + op0); + case LE_EXPR: + *code_p = EQ_EXPR; + break; + + case GE_EXPR: + return omit_one_operand (type, + convert (type, integer_one_node), + op0); + case GT_EXPR: + *code_p = NE_EXPR; + break; + + default: + break; + } + else if (TREE_INT_CST_HIGH (op1) == (min ? -1 : 0) + && TREE_INT_CST_LOW (op1) == min + 1) + switch (code) + { + case GE_EXPR: + *code_p = NE_EXPR; + *op1_p = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + case LT_EXPR: + *code_p = EQ_EXPR; + *op1_p = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + default: + break; + } + + else if (TREE_INT_CST_HIGH (op1) == 0 + && TREE_INT_CST_LOW (op1) == signed_max + && TYPE_UNSIGNED (TREE_TYPE (op1)) + /* signed_type does not work on pointer types. */ + && INTEGRAL_TYPE_P (TREE_TYPE (op1))) + { + /* The following case also applies to X < signed_max+1 + and X >= signed_max+1 because previous transformations. */ + if (code == LE_EXPR || code == GT_EXPR) + { + tree st0, st1, exp, retval; + st0 = (*lang_hooks.types.signed_type) (TREE_TYPE (op0)); + st1 = (*lang_hooks.types.signed_type) (TREE_TYPE (op1)); + + exp = build (code == LE_EXPR ? GE_EXPR: LT_EXPR, + type, + convert (st0, op0), + convert (st1, integer_zero_node)); + + retval + = nondestructive_fold_binary_to_constant (TREE_CODE (exp), + TREE_TYPE (exp), + TREE_OPERAND (exp, 0), + TREE_OPERAND (exp, 1)); + + /* If we are in gimple form, then returning EXP would create + non-gimple expressions. Clearing it is safe and insures + we do not allow a non-gimple expression to escape. */ + if (in_gimple_form) + exp = NULL; + + return (retval ? retval : exp); + } + } + } + + return NULL_TREE; +} + + +/* Given the components of a binary expression CODE, TYPE, OP0 and OP1, + attempt to fold the expression to a constant without modifying TYPE, + OP0 or OP1. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. + + Note this is primarily designed to be called after gimplification + of the tree structures and when at least one operand is a constant. + As a result of those simplifying assumptions this routine is far + simpler than the generic fold routine. */ + +tree +nondestructive_fold_binary_to_constant (enum tree_code code, tree type, + tree op0, tree op1) +{ + int wins = 1; + tree subop0; + tree subop1; + tree tem; + + /* If this is a commutative operation, and ARG0 is a constant, move it + to ARG1 to reduce the number of tests below. */ + if (commutative_tree_code (code) + && (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)) + { + tem = op0; + op0 = op1; + op1 = tem; + } + + /* If either operand is a complex type, extract its real component. */ + if (TREE_CODE (op0) == COMPLEX_CST) + subop0 = TREE_REALPART (op0); + else + subop0 = op0; + + if (TREE_CODE (op1) == COMPLEX_CST) + subop1 = TREE_REALPART (op1); + else + subop1 = op1; + + /* Note if either argument is not a real or integer constant. + With a few exceptions, simplification is limited to cases + where both arguments are constants. */ + if ((TREE_CODE (subop0) != INTEGER_CST + && TREE_CODE (subop0) != REAL_CST) + || (TREE_CODE (subop1) != INTEGER_CST + && TREE_CODE (subop1) != REAL_CST)) + wins = 0; + + switch (code) + { + case PLUS_EXPR: + /* (plus (address) (const_int)) is a constant. */ + if (TREE_CODE (op0) == PLUS_EXPR + && TREE_CODE (op1) == INTEGER_CST + && (TREE_CODE (TREE_OPERAND (op0, 0)) == ADDR_EXPR + || (TREE_CODE (TREE_OPERAND (op0, 0)) == NOP_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (op0, 0), 0)) + == ADDR_EXPR))) + && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST) + { + return build (PLUS_EXPR, type, TREE_OPERAND (op0, 0), + const_binop (PLUS_EXPR, op1, TREE_OPERAND (op0, 1), 0)); + } + case BIT_XOR_EXPR: + + binary: + if (!wins) + return NULL_TREE; + + /* Both arguments are constants. Simplify. */ + tem = const_binop (code, op0, op1, 0); + if (tem != NULL_TREE) + { + /* The return value should always have the same type as + the original expression. */ + if (TREE_TYPE (tem) != type) + tem = convert (type, tem); + + return tem; + } + return NULL_TREE; + + case MINUS_EXPR: + /* Fold &x - &x. This can happen from &x.foo - &x. + This is unsafe for certain floats even in non-IEEE formats. + In IEEE, it is unsafe because it does wrong for NaNs. + Also note that operand_equal_p is always false if an + operand is volatile. */ + if (! FLOAT_TYPE_P (type) && operand_equal_p (op0, op1, 0)) + return convert (type, integer_zero_node); + + goto binary; + + case MULT_EXPR: + case BIT_AND_EXPR: + /* Special case multiplication or bitwise AND where one argument + is zero. */ + if (! FLOAT_TYPE_P (type) && integer_zerop (op1)) + return omit_one_operand (type, op1, op0); + else + if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (op0))) + && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op0))) + && real_zerop (op1)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case BIT_IOR_EXPR: + /* Special case when we know the result will be all ones. */ + if (integer_all_onesp (op1)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case TRUNC_DIV_EXPR: + case ROUND_DIV_EXPR: + case FLOOR_DIV_EXPR: + case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + case TRUNC_MOD_EXPR: + case ROUND_MOD_EXPR: + case FLOOR_MOD_EXPR: + case CEIL_MOD_EXPR: + case RDIV_EXPR: + /* Division by zero is undefined. */ + if (integer_zerop (op1)) + return NULL_TREE; + + if (TREE_CODE (op1) == REAL_CST + && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (op1))) + && real_zerop (op1)) + return NULL_TREE; + + goto binary; + + case MIN_EXPR: + if (INTEGRAL_TYPE_P (type) + && operand_equal_p (op1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case MAX_EXPR: + if (INTEGRAL_TYPE_P (type) + && TYPE_MAX_VALUE (type) + && operand_equal_p (op1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST)) + return omit_one_operand (type, op1, op0); + + goto binary; + + case RSHIFT_EXPR: + /* Optimize -1 >> x for arithmetic right shifts. */ + if (integer_all_onesp (op0) && ! TYPE_UNSIGNED (type)) + return omit_one_operand (type, op0, op1); + /* ... fall through ... */ + + case LSHIFT_EXPR: + if (integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + + /* Since negative shift count is not well-defined, don't + try to compute it in the compiler. */ + if (TREE_CODE (op1) == INTEGER_CST && tree_int_cst_sgn (op1) < 0) + return NULL_TREE; + + goto binary; + + case LROTATE_EXPR: + case RROTATE_EXPR: + /* -1 rotated either direction by any amount is still -1. */ + if (integer_all_onesp (op0)) + return omit_one_operand (type, op0, op1); + + /* 0 rotated either direction by any amount is still zero. */ + if (integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + + goto binary; + + case COMPLEX_EXPR: + if (wins) + return build_complex (type, op0, op1); + return NULL_TREE; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + /* If one arg is a real or integer constant, put it last. */ + if ((TREE_CODE (op0) == INTEGER_CST + && TREE_CODE (op1) != INTEGER_CST) + || (TREE_CODE (op0) == REAL_CST + && TREE_CODE (op0) != REAL_CST)) + { + tree temp; + + temp = op0; + op0 = op1; + op1 = temp; + code = swap_tree_comparison (code); + } + + /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0. + This transformation affects the cases which are handled in later + optimizations involving comparisons with non-negative constants. */ + if (TREE_CODE (op1) == INTEGER_CST + && TREE_CODE (op0) != INTEGER_CST + && tree_int_cst_sgn (op1) > 0) + { + switch (code) + { + case GE_EXPR: + code = GT_EXPR; + op1 = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + + case LT_EXPR: + code = LE_EXPR; + op1 = const_binop (MINUS_EXPR, op1, integer_one_node, 0); + break; + + default: + break; + } + } + + tem = fold_relational_hi_lo (&code, type, &op0, &op1); + if (tem) + return tem; + + if (!wins) + return NULL_TREE; + + return fold_relational_const (code, type, op0, op1); + + case RANGE_EXPR: + /* This could probably be handled. */ + return NULL_TREE; + + case TRUTH_AND_EXPR: + /* If second arg is constant zero, result is zero, but first arg + must be evaluated. */ + if (integer_zerop (op1)) + return omit_one_operand (type, op1, op0); + /* Likewise for first arg, but note that only the TRUTH_AND_EXPR + case will be handled here. */ + if (integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + int x1 = ! integer_zerop (op0); + int x2 = ! integer_zerop (op1); + + return ((x1 & x2) ? integer_one_node : integer_zero_node); + } + return NULL_TREE; + + case TRUTH_OR_EXPR: + /* If second arg is constant true, result is true, but we must + evaluate first arg. */ + if (TREE_CODE (op1) == INTEGER_CST && ! integer_zerop (op1)) + return omit_one_operand (type, op1, op0); + /* Likewise for first arg, but note this only occurs here for + TRUTH_OR_EXPR. */ + if (TREE_CODE (op0) == INTEGER_CST && ! integer_zerop (op0)) + return omit_one_operand (type, op0, op1); + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + int x1 = ! integer_zerop (op0); + int x2 = ! integer_zerop (op1); + + return ((x1 | x2) ? integer_one_node : integer_zero_node); + } + return NULL_TREE; + + case TRUTH_XOR_EXPR: + if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST) + { + int x1 = ! integer_zerop (op0); + int x2 = ! integer_zerop (op1); + + return ((x1 ^ x2) ? integer_one_node : integer_zero_node); + } + return NULL_TREE; + + default: + return NULL_TREE; + } +} + +/* Given the components of a unary expression CODE, TYPE and OP0, + attempt to fold the expression to a constant without modifying + TYPE or OP0. + + If the expression could be simplified to a constant, then return + the constant. If the expression would not be simplified to a + constant, then return NULL_TREE. + + Note this is primarily designed to be called after gimplification + of the tree structures and when op0 is a constant. As a result + of those simplifying assumptions this routine is far simpler than + the generic fold routine. */ + +tree +nondestructive_fold_unary_to_constant (enum tree_code code, tree type, + tree op0) +{ + tree t; + + /* Make sure we have a suitable constant argument. */ + if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR) + { + tree subop; + + if (TREE_CODE (op0) == COMPLEX_CST) + subop = TREE_REALPART (op0); + else + subop = op0; + + if (TREE_CODE (subop) != INTEGER_CST && TREE_CODE (subop) != REAL_CST) + return NULL_TREE; + } + + switch (code) + { + case NOP_EXPR: + case FLOAT_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_FLOOR_EXPR: + case FIX_CEIL_EXPR: + return fold_convert_const (code, type, op0); + + case NEGATE_EXPR: + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + return fold_negate_const (op0, type); + else + return NULL_TREE; + + case ABS_EXPR: + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + return fold_abs_const (op0, type); + else + return NULL_TREE; + + case BIT_NOT_EXPR: + if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST) + { + t = build_int_2 (~ TREE_INT_CST_LOW (op0), ~ TREE_INT_CST_HIGH (op0)); + TREE_TYPE (t) = type; + force_fit_type (t, 0); + TREE_OVERFLOW (t) = TREE_OVERFLOW (op0); + TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (op0); + return t; + } + else + return NULL_TREE; + + case REALPART_EXPR: + if (TREE_CODE (op0) == COMPLEX_CST) + return TREE_REALPART (op0); + else + return NULL_TREE; + + case IMAGPART_EXPR: + if (TREE_CODE (op0) == COMPLEX_CST) + return TREE_IMAGPART (op0); + else + return NULL_TREE; + + case CONJ_EXPR: + if (TREE_CODE (op0) == COMPLEX_CST + && TREE_CODE (TREE_TYPE (op0)) == COMPLEX_TYPE) + return build_complex (type, TREE_REALPART (op0), + negate_expr (TREE_IMAGPART (op0))); + return NULL_TREE; + + default: + return NULL_TREE; + } +} + +/* If EXP represents referencing an element in a constant string + (either via pointer arithmetic or array indexing), return the + tree representing the value accessed, otherwise return NULL. */ + +tree +fold_read_from_constant_string (tree exp) +{ + if (TREE_CODE (exp) == INDIRECT_REF || TREE_CODE (exp) == ARRAY_REF) + { + tree exp1 = TREE_OPERAND (exp, 0); + tree index; + tree string; + + if (TREE_CODE (exp) == INDIRECT_REF) + { + string = string_constant (exp1, &index); + } + else + { + tree domain = TYPE_DOMAIN (TREE_TYPE (exp1)); + tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node; + index = convert (sizetype, TREE_OPERAND (exp, 1)); + + /* Optimize the special-case of a zero lower bound. + + We convert the low_bound to sizetype to avoid some problems + with constant folding. (E.g. suppose the lower bound is 1, + and its mode is QI. Without the conversion,l (ARRAY + +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1)) + +INDEX), which becomes (ARRAY+255+INDEX). Opps!) */ + if (! integer_zerop (low_bound)) + index = size_diffop (index, convert (sizetype, low_bound)); + + string = exp1; + } + + if (string + && TREE_CODE (string) == STRING_CST + && TREE_CODE (index) == INTEGER_CST + && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0 + && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) + == MODE_INT) + && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) == 1)) + return build_int_2 ((TREE_STRING_POINTER (string) + [TREE_INT_CST_LOW (index)]), 0); + } + return NULL; +} + /* Return the tree for neg (ARG0) when ARG0 is known to be either an integer constant or real constant. diff --git a/gcc/fortran/.cvsignore b/gcc/fortran/.cvsignore new file mode 100644 index 00000000000..da7ce896169 --- /dev/null +++ b/gcc/fortran/.cvsignore @@ -0,0 +1 @@ +gfortran.info* diff --git a/gcc/fortran/CONTRIB b/gcc/fortran/CONTRIB new file mode 100644 index 00000000000..765dfe62e3b --- /dev/null +++ b/gcc/fortran/CONTRIB @@ -0,0 +1,33 @@ +Contributors to G95 + +If we have left anyone out, please let us know: + + + +Major code contributors +---------------------------------- +Andy Vaught +Katherine Holcomb +Steven Bosscher +Paul Brook +Arnaud Desitter +Canqun Yang +Xiaoqiang Zhang + + +Small patches (no copyright assignment) +---------------------------------- +Niels Kristian Bech Jensen +Steven G. Johnson +Tobias Schlüter + + +Helpful comments +---------------------------------- +Erik Schnetter +Steven G. Kargl +W. Clodius +Claus Fischer +Toon Moene +Richard T. Henderson + diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog new file mode 100644 index 00000000000..4e927638fee --- /dev/null +++ b/gcc/fortran/ChangeLog @@ -0,0 +1,3068 @@ +2004-05-09 Tobias Schlüter + + * array.c (match_subscript, match_array_ref): Add comments + explaining argument 'init'. + * decl.c, f95-lang.c, match.c, resolve.c, trans-array.c, + trans-expr.c, trans.c: Fix some typos in comments. + * dump-parse-tree.c (gfc_show_expr): Remove wrong comment. + * primary.c (match_digits, match_integer_constant): Add comment + explaining signflag. + +2004-05-01 Tobias Schlüter + + PR fortran/13940 + * primary.c: Include system.h and flags.h, needed for pedantic. + (match_boz_constant): Allow "x" for hexadecimal constants, warn if + pedantic is set. + +2004-05-01 Tobias Schlüter + + PR fortran/13940 + * match.c (match_data_constant): Handle case where + gfc_find_symbol sets sym to NULL + +2004-04-28 Tobias Schlüter + + * Make-lang.in (f95-lang.o, trans-intrinsic.o): Add missing + dependency on mathbuiltins.def + +2004-04-24 Victor Leikehman + + * trans-io.c (transfer_expr): Implemented recursive printing + of derived types. + +2004-04-24 Andrew Pinski + + * gfortranspec.c: Do not include multilib.h. + +2004-04-24 Tobias Schlüter + + * trans-intrinsic.c: Fix comment, this is not trans-expr.c. Add + 2004 to copyright years. + * trans-expr.c, trans-decl.c: Comment update, we now generate + GENERIC, not SIMPLE. Add 2004 to copyright years. + +2004-04-24 Paul Brook + + * Make-lang.in (gfortranspec.o): Add dependency on $(TM_H). + +2004-04-24 Feng Wang + + PR 14817 + * arith.c (gfc_arith_divide): Fix complex divide. + +2004-04-23 Andrew Pinski + + * gfortranspec.c: Include the target headers. + +2004-04-18 Feng Wang + + PR fortran/14921 + PR fortran/14540 + * arith.c (arctangent2): New function. + * arith.h (arctangent2): Add function prototype. + * simplify.c (gfc_simplify_atan2): Use it. + (gfc_simplify_log): Use it. + +2004-04-12 Diego Novillo + + * fortran/f95-lang.c (gfc_expand_stmt): Remove. + (LANG_HOOKS_RTL_EXPAND_STMT): Remove. + +2004-04-11 Bud Davis + + PR fortran/14872 + * trans-io.c (build_dt): Change REC to value. + +2004-04-11 Feng Wang + + PR 14394 + * trans-const.c (gfc_conv_mpf_to_tree): Loosen the maximum digits of + the real value when converting mpf to string. + +2004-04-11 Feng Wang + + PR 14395 + * trans-intrinsic.c (gfc_conv_intrinsic_cmplx): Fix the imag part of + the result. + +2004-04-11 Feng Wang + + PR fortran/14377 + * simplify.c (simplify_min_max): Convert the type of the result. + +2004-04-11 Paul Brook + + * gfortran.texi: Use full target triplet. + +2004-04-11 Paul Brook + + * Make-lang.in (GFORTRAN_TEXI): Set it. + (fortran/dfortran.dvi): Use it. Add fortran to include paths. + (fortran/gfortran.info): Ditto. + * gfortran.texi: Major update. + * invoke.texi: New file. + +2004-04-10 Paul Brook + + * trans-array.c (gfc_trans_allocate_temp_array, + gfc_conv_tmp_array_ref): Don't use GFC_DECL_STRING. + * trans-decl.c (gfc_build_dummy_array_decl, + gfc_get_symbol_decl, gfc_build_function_decl, + gfc_create_module_variable): Ditto. + * trans-expr.c (gfc_conv_variable): Ditto. + * trans-intrinsic.c (gfc_conv_intrinsic_len): Ditto. + * trans.h (GFC_DECL_STRING): Remove. + (GFC_DECL_PACKED_ARRAY, GFC_DECL_PARTIAL_PACKED_ARRAY, + GFC_DECL_ASSIGN): Renumber flags. + +2004-04-05 Paul Brook + + PR 13252 + PR 14081 + * f95-lang.c (gfc_init_builtin_functions): Add stack_alloc, stack_save + and stack_restore. + * gfortran.h (struct gfc_charlen): Add backend_decl. + * trans-array.c (gfc_trans_allocate_temp_array, + gfc_conv_temp_array_ref, gfc_conv_resolve_dependencies, + (gfc_conv_loop_setup, gfc_array_allocate, gfc_conv_array_init_size): + Remove old, broken string handling. + (gfc_trans_auto_array_allocation, gfc_trans_g77_array, + gfc_trans_dummy_array_bias, gfc_conv_expr_descriptor, + gfc_trans_deferred_array): Handle character arrays. + * trans-const.c (gfc_conv_const_charlen): New function. + * trans-const.h (gfc_conv_const_charlen): Add prototype. + * trans-decl.c (gfc_finish_var_decl): Don't mark automatic variables + as static. + (gfc_build_dummy_array_decl): Handle arrays with unknown element size. + (gfc_create_string_length): New function. + (gfc_get_symbol_decl): Create lengths for character variables. + (gfc_get_fake_result_decl): Ditto. + (gfc_build_function_decl): Only set length for assumed length + character arguments. + (gfc_trans_dummy_character): New function. + (gfc_trans_auto_character_variable): Rewrite. + (gfc_trans_deferred_vars): Handle more types of character variable. + (gfc_create_module_variable): String lengths have moved. + (gfc_generate_function_code): Initialize deferred var chain earlier. + * trans-expr.c (gfc_conv_init_string_length): Rename ... + (gfc_trans_init_string_length): ... to this. + (gfc_conv_component_ref, gfc_conv_variable, gfc_conv_concat_op, + gfc_conv_function_call): Update to new format for character variables. + (gfc_conv_string_length): Remove. + (gfc_conv_string_parameter): Update assertion. + * trans-intrinsic.c (gfc_conv_intrinsic_len): Use new location. + * trans-io.c (set_string): Use new macro names. + * trans-stmt.c (gfc_trans_label_assign. gfc_trans_goto): Ditto. + * trans-types.c (gfc_get_character_type): Use existing length expr. + (gfc_is_nodesc_array): Make public. + (gfc_get_dtype_cst): Rename ... + (gfc_get_dtype): ... to this. Handle unknown size arrays. + (gfc_get_nodesc_array_type): Use new name. + (gfc_sym_type): New character variable code. + (gfc_get_derived_type): Ditto. + (gfc_get_function_type): Evaluate character variable lengths. + * trans-types.h (gfc_strlen_kind): Define. + (gfc_is_nodesc_array): Add prototype. + * trans.h: Update prototypes. + (struct lang_type): Update comments. + (GFC_DECL_STRING_LEN): New name for GFC_DECL_STRING_LENGTH. + (GFC_KNOWN_SIZE_STRING_TYPE): Remove. + +2004-04-04 Paul Brook + + * gfortran.h (struct gfc_option_t): Remove flag_g77_calls. + * options.c (gfc_init.options, gfc_handle_option): Ditto. + * trans-expr.c (gfc_conv_function_call): Ditto. + * trans-types.c (gfc_is_nodesc_array): Ditto + * lang.opt (fg77-calls): Remove. + +2004-04-04 Paul Brook + + * trans-array.c (OFFSET_FIELD): Rename from BASE_FIELD. + (gfc_conv_descriptor_base): Rename ... + (gfc_conv_descriptor_offset): ... to this. + (gfc_trans_allocate_array_storage): Set offset to zero. + (gfc_conv_array_base): Rename ... + (gfc_conv_array_offset): ... to this. + (gfc_conv_array_index_ref): Add offset parameter. + (gfc_conv_array_ref): Include offset. + (gfc_trans_preloop_setup): Use existing offset. + (gfc_trans_allocate_temp_array, gfc_array_allocate, + gfc_trans_auto_array_allocation, gfc_trans_g77_array, + gfc_trans_dummy_array_bias, gfc_conv_expr_descriptor, + gfc_conf_ss_descriptor): Set offset. + * trans-array.h: Rename prototypes. + * trans-const.h (gfc_index_zero_node): Define. + * trans-decl.c (gfc_build_qualified_array): Change base to offset. + * trans-types.c (gfc_get_array_type_bounds): Ditto. + (gfc_get_nodesc_array_type): Calculate offset before upper bound. + +2004-03-25 Diego Novillo + + * convert.c (convert): Don't handle WITH_RECORD_EXPR. + +2004-03-24 Bud Davis + + PR 14055 + * arith.c (gfc_convert_integer,gfc_convert_real): Removed leading '+' + before conversion by gmp library call. + +2004-03-24 Bud Davis + + PR 12921 + * trans-io.c (gfc_trans_open): Change RECL= to a value parameter. + +2004-02-24 Richard Henderson + + * trans-array.c (gfc_trans_dummy_array_bias): Fix typo. + +2004-02-19 Loren J. Rittle + + * Make-lang.in ($(srcdir)/fortran/gfortran.info): Move... + (fortran/gfortran.info): ... to here. + (f95.srcinfo): New. + +2004-02-16 Richard Henderson + + * Make-lang.in (f95-lang.o, trans-decl.o): Depend on cgraph.h. + * f95-lang.c (LANG_HOOKS_EXPAND_DECL): Remove. + (LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION): New. + (gfc_expand_function): Rename from expand_function_body, make static, + don't do anything except invoke tree_rest_of_compilation. + (gfc_be_parse_file): Invoke cgraph. + (gfc_expand_decl): Remove. + (gfc_init_builtin_functions): Add __builtin_init_trampoline and + __builtin_adjust_trampoline. + * trans-decl.c (gfc_get_extern_function_decl): Don't set DECL_CONTEXT. + (gfc_finalize): New. + (gfc_generate_function_code): Use it. Lower nested functions. + * trans-expr.c (gfc_conv_function_call): Add static chain operand + to call_expr. + * trans.c (gfc_build_function_call): Likewise. + * trans.h (expand_function_body): Remove. + +2004-02-15 Victor Leikehman + + PR gfortran/13433 + * trans-decl.c (gfc_build_function_decl) For functions + returning CHARACTER pass an extra length argument, + following g77 calling conventions. + * trans-types.c (gfc_get_function_type) Ditto. + * trans-expr.c (gfc_conv_function_call) Ditto. + +2004-02-14 Paul Brook + + * f95-lang.c (gfc_init_builtin_functions): Build chain properly. + +2004-02-12 Paul Brook + + * BUGS: Remove. + +2004-02-08 Steve Kargl + + * gfortran.texi: Fix typos. + +2004-02-07 Bud Davis + + PR gfortran/13909 + * intrinsic.c (add_conversions) Use logical conversion instead + of real. + * trans-types.c (gfc_get_logical_type) implemented logical*1 + and logical*2. + +2004-01-17 Paul Brook + + * lang-specs.h: Remove % + + * lang-specs.h: Enable preprocessing of source files + ending in .F, .fpp, .FPP, .F90 and .F95. + +2004-01-13 Toon Moene + + PR fortran/12912 + * lang-specs.h: Enable compilation of files ending + in .f, .for and .FOR. + +2004-01-11 Paul Brook + + * trans-stmt.c (gfc_trans_if_1): New function. + (gfc_trans_if): Use it. + +2004-01-11 Erik Schnetter + + * gfortran.h (GFC_MAX_SYMBOL_LEN): Increase. + (gfc_option_t): Add max_identifier_length. + * lang.opt: Add fmax-identifier-length. + * match.c (parse_name): Use limit. + * options.c (gfc_init_options): Set max_identifier_length. + (gfc_handle_option): Ditto. + +2004-01-11 Feng Wang + + * intrinsic.c (add_functions): Add resolve function to dcmplx. + * intrinsic.h (gfc_resolve_dcmplx): Add prototype. + * iresolve.c (gfc_resolve_dcmplx): New function. + +2004-01-10 Paul Brook + + * trans-decl.c (gfc_get_symbol_decl): Don't set subroutine attr. + * trans-types.c (gfc_sym_type): Handle external dummy procedures. + (gfc_return_by_reference): Correct condition. + (gfc_get_function_type): Ditto. + +2004-01-10 Paul Brook + + * trans-intrinsic.c (gfc_conv_intrinsic_minmax): Convert mismatched + types. + +2004-01-10 Huang Chun + + * iresolve.c: Use correct kind. + +2004-01-10 Huang Chun + + PR fortran/13467 + * trans-decl.c (gfc_create_module_variable): Output array valued + parameters. + +2004-01-10 Paul Brook + + * resolve.c (resolve_branch): Get error message right way round. + +2004-01-10 Canqun Yang + + * trans-array (gfc_conv_loop_setup): Adjust comment to track + reality. + (gfc_array_allocate): Don't count size of element twice. + +2004-01-04 Paul Brook + + * lang.opt (i8, r8, std=*): Remove RejectNegative. + +2004-01-04 Paul Brook + + * error.c (gfc_notify_std): New function. + * gfortran.h (gfc_notify_std): Declare. + (GFC_STD_*): Define. + (gfc_option_t): Add warn_std and allow_std. + * intrinsic.c (gfc_init_expr_extensions): Fix logic. + (gfc_intrinsic_func_interface): Use gfc_notify_std. + * check.c (check_rest): Use gfc_notify_std. + * match.c (gfc_match_pause): Ditto. + (gfc_match_assign): Ditto. + (gfc_match_goto): Ditto. + * resolve.c (resolve_branch): Ditto. + * lang.opt: Add std= and w. + * options.c (gfc_init_options): Set allow_std and warn_std. + (gfc_handle_option): Handle OPT_std_* and OPT_w. + +2004-01-01 Paul Brook + + * array.c (gfc_append_constructor): Take constructor, not expression. + * data.c (struct gfc_expr_stack): Remove. + (expr_stack): Remove. + (find_con_by_offset): Rename from find_expr_in_con. + (find_con_by_component): Rename from find_component_in_con. + (gfc_get_expr_stack): Remove. + (gfc_assign_data_value): Rewrite. + (gfc_expr_push): Remove. + (gfc_expr_pop): Remove. + (gfc_advance_section): Rename from + gfc_modify_index_and_calculate_offset. Handle unbounded sections. + (gfc_get_section_index): Handle unbounded sections. + * gfortran.h: Update prototypes. + * resolve.c (check_data_variable): Array section maight not be the + last ref. + +2004-01-01 Paul Brook + + PR fortran/13432 + * resolve.c (resolve_symbol): Allow assumed length function results. + +2004-01-01 Steve Kargl + + * match.c (gfc_match_pause): Fix spelling. + +2004-01-01 Steven Bosscher + + PR fortran/13251 + * trans-expr.c (gfc_conv_variable): Take the type kind of a substring + reference from the expression. + +2003-12-26 Feng Wang + + * dump-parse-tree.c (gfc_show_code_node): Add ASSIGN and ASSIGNED GOTO + dumping. + * gfortran.h (gfc_statement): New ST_LABEL_ASSIGNMENT. + (gfc_exec_op): New EXEC_LABEL_ASSIGN. + (symbol_attribute):New variable attribute: assign. + * io.c (resolve_tag):Integer variable is allowed. + (match_dt_format): Add ASSIGN statement. Set assign flag. + * match.c (gfc_match_if): Change ST_NONE to ST_LABEL_ASSIGNMENT. + (gfc_match_assign): Add ASSIGN statement. Set assign flag. + (gfc_match_goto): Add ASSIGNED GOTO statement. Set assign flag. + * parse.c (decode_statement): Add ST_LABEL_ASSIGNMENT. + (next_statement): Add ST_LABEL_ASSIGNMENT. + (gfc_ascii_statement): Add ST_LABEL_ASSIGNMENT. + * resolve.c (resolve_code): Resolve ASSIGN and ASSIGNED GOTO statement. + (resolve_blocks): Resolve ASSIGNED GOTO statement label list. + * st.c (gfc_free_statement): Add EXEC_LABEL_ASSIGN. + * trans-decl.c (gfc_get_symbol_decl): Create the shadow variable for + assign. Put them into the stuct lang_decl. + * trans-io.c (set_string): Add the assign statement. + * trans-stmt.c (gfc_trans_label_assign): New function. + (gfc_trans_goto): Translate ASSIGNED GOTO statement. + * trans-stmt.h (gfc_trans_label_assign): Added function prototype. + * trans.c (gfc_trans_code): Add EXEC_LABEL_ASSIGN. + * trans.h (lang_decl):Add shadow variable decl tree needed by assign. + (GFC_DECL_ASSIGN_ADDR(node)): New macro to access this. + (GFC_DECL_ASSIGN(node)): New macro to access flag. + +2003-12-31 Huang Chun + + PR fortran/13434 + * trans-intrinsic.c (gfc_conv_intrinsic_minmaxval): Fixed bug in + minval/maxval. + +2003-12-22 Toon Moene + + * options.c (gfc_init_options): Set flag_argument_noalias to 2, to indicate + that arguments to subroutines/functions can't alias themselves, nor global + memory. + +2003-12-20 Steven Bosscher + + * trans-expr.c (gfc_conv_expr_op): Fold the result expression. + * trans.c (gfc_add_modify_expr, gfc_add_expr_to_block): Likewise. + +2003-12-12 Huang Chun + + * primary.c (match_substring): Fix substring bug for start point + or end point is NULL. + * trans-expr.c (gfc_conv_substring): Ditto + * trans-types.c (gfc_sym_type): Get correct type of scalar + character variables. + * trans-intrinsic.c (gfc_conv_intrinsic_len): Handle character in + derived type. + +2003-12-10 Richard Henderson + + * options.c (gfc_post_options): Don't ever use rtl inlining. + +2003-12-05 Canqun Yang + + * trans-common.c: Re-implement COMMON blocks and EQUIVALENCE lists. + * trans-equivalence.c: Remove. + * trans-decl.c (gfc_get_symbol_decl): Update to match. + (gfc_generate_function_code): Ditto. + * trans-array.c (gfc_conv_array_parameter): Ditto. + * Make-lang.in (F95_OBJS): Remove fortran/trans-equivalence.o + (F95_ADDITIONAL_OBJS): Add stor-layout.o + * trans.h (gfc_trans_equivalence): Remove. + * gfortran.h (struct gfc_equiv): Add used field. + (struct gfc_symbol): Remove addr_base, addr_offset, equiv_ring, + equiv_offset fields. + +2003-12-05 Richard Henderson + + * trans.c (gfc_build_addr_expr): New. + (gfc_build_indirect_ref, gfc_build_array_ref): New. + * trans.h: Declare them. + * trans-array.c, trans-expr.c, trans-intrinsic.c, trans-io.c, + trans-stmt.c, trans.c (*): Use them. + + * f95-lang.c (gfc_post_options): Remove dead prototype. + * trans-array.c (gfc_trans_deferred_vars): Remove unused variable. + * trans-stmt.c (gfc_evaluate_where_mask): Fix temporary_list + allocation size. + +2003-12-01 Feng Wang + + * io.c (gfc_match_format): Check for missing format label. + +2003-11-30 Huang Chun + + PR fortran/13155 + * trans-decl.c (gfc_sym_mangled_function_id): Don't mangle symbols + from interfaces in modules. + +2003-11-30 Paul Brook + + * trans-array.c (gfc_trans_g77_array): Make non-static. + (gfc_trans_assumed_size): Remove. + (gfc_trans_dummy_array_bias): Explicitly free temporary. + * trans-array.h (gfc_trans_g77_array): Add prototype. + (gfc_trans_assumed_size): Remove. + * trans-decls.c (gfor_fndecl_push_context): Remove. + (gfor_fndecl_pop_context): Remove. + (gfc_build_function)decls): Don't create them. + (gfc_trans_deferred_vars): Update to match. Remove dead code. + * trans-stmt.c (gfc_trans_pointer_assign_need_temp): Free temp. + +2003-11-30 Kejia Zhao + + * trans-array.c (gfc_conv_array_parameter): Simplify + array argument passing for array name actual argument. + * trans-expr.c (gfc_conv_function_call): Ditto + * trans-types.c (gfc_is_nodesc_array):Ditto. + +2003-11-30 Paul Brook + + * f95-lang.c (gfc_post_options): Move ... + * options.c (gfc_post_options): .. to here. Handle inlining options. + * gfortran.h (gfc_post_options): Add prototype. + +2003-11-28 Richard Henderson + + * trans.c (gfc_create_var_np): Use create_tmp_var_raw. + +2003-11-28 Huang Chun + + * trans.h (has_alternate_specifier): New global variable. + * match.c (gfc_match_call): Handle actual arguments associated with + alternate return indicators. + * trans-expr.c (gfc_conv_function_call): Ditto + * trans-stmt.c (gfc_trans_call): Ditto + (gfc_trans_return): Handle return statement with value. + * trans-decl.c (gfc_generate_function_code): Handle functions with + asterisk dummy. + (gfc_get_fake_result_decl): Ditto + * trans-types.c (gfc_get_function_type): Ditto + * resolve.c (resolve_actual_arglist): Check alternate return indicators. + (resolve_formal_arglist): Check asterisk dummy. + +2003-11-27 Paul Brook + + * trans-array.c (gfc_tran_allocate_array_storage): Use new memory + allocation interface. + (gfc_conv_ array_parameter): Ditto. + (gfc_trans_auto_array_allocation): Ditto. Also free the memory. + * trans-array.c: Update prototype. + * trans-decl.c (gfc_build_builtin_function_decls): Update prototypes. + (gfc_trans_auto_character_variable): Use new memory alloc interface. + * trans-expr.c (gfc_conv_string_tmp): Ditto. + (gfc_conv_function_call): Use gfc_conv_string_tmp. + * trans-stmt.c (gfc_do_allocate): Use new memory alloc interface. + * trans-intrinsic.c (gfc_conv_intrinsic_trim): Ditto. + * trans.h (gfc_ss_info): Remove unused pdata field. + * trans.c (gfc_create_var_np): Change T to V. + +2003-11-26 Richard Henderson + + * mathbuiltins.def: Move acos, asin, cosh, log10, sinh, tanh from ... + * trans-intrinsic.c (gfc_intrinsic_map): ... here. Add SCALE, + FRACTION, NEAREST, SET_EXPONENT. + (gfc_intrinsic_map_t): Add libm_name, complex_available, is_constant. + Fix GTY marking. Remove unnecessary const's. + (LIBM_FUNCTION): Rename from I_LIB. + (LIBF_FUNCTION): New. + (gfc_get_intrinsic_lib_fndecl): Handle libm and libgfortran naming + conventions. Assume the expr signature is correct. Mark const. + (gfc_conv_intrinsic_exponent): Use library functions. + (gfc_conv_intrinsic_set_exponent): Remove. + (gfc_conv_intrinsic_scale): Remove. + (gfc_conv_intrinsic_nearest): Remove. + (gfc_conv_intrinsic_fraction): Remove. + (gfc_conv_intrinsic_function): Update. + * trans-decl.c (gfor_fndecl_math_exponent4): New. + (gfor_fndecl_math_exponent8): New. + (gfc_build_intrinsic_function_decls): Set them. + * trans.h: Declare them. + +2003-11-25 Canqun Yang + + * trans-common.c (gfc_layout_global_equiv): Locate the error for + underflow COMMON block. + (gfc_trans_one_common): Fix bug for size of COMMON block containing + EQUIVALENCE object. Also fix typo in an error message. + +2003-11-25 Diego Novillo + + * Make-lang.in: Add check-gfortran to lang_checks. + (check-f95): Alias for check-gfortran. + +2003-11-25 Jason Merrill + + * Make-lang.in (f95.tags): Create TAGS.sub files in each + directory and TAGS files that include them for each front end. + +2003-11-24 Paul Brook + + PR fortran/13154 + * trans-decl.c (gfc_greate_module_variable): Skip COMMON blocks. + +2003-11-24 Paul Brook + + * expr.c (simplify_const_ref): Return SUCCESS for things we don't + handle. + * resolve.c (gfc_resolve_expr): Resolve contents before rank/shape. + +2003-11-24 Paul Brook + + PR fortran/13105 + * array.c (gfc_array_ref_shape): Handle elemental dimensions. + * trans-array.c (gfc_trans_preloop_setup): Use correct dim lookup. + +2003-11-20 Richard Henderson + + * trans-array.c (gfc_trans_allocate_array_storage): Use convert. + (gfc_conv_array_base): Likewise. + * trans-decl.c (gfc_trans_auto_character_variable): Likewise. + * trans-expr.c (gfc_conv_string_tmp): Likewise. + * trans-intrinsic.c (gfc_conv_intrinsic_trim): Likewise. + * trans-stmt.c (gfc_trans_character_select): Likewise. + +2003-11-13 Paul Brook + + * trans-decl.c (gfc_sym_mangled_function_id): Dont mangle externals. + +2003-11-13 Canqun Yang + + * resolve.c (gfc_resolve): Also resolve EQUIVALENCE objects. + (resolve_equivalence): New function. + (resolve_equivalence_derived): New function. + +2003-11-12 Richard Henderson + + * trans.c (gfc_trans_code): Use annotate_with_locus instead of + annotate_all_with_locus. + +2003-11-11 Canqun Yang + + * options.c (gfc_init_options): Set flag_max_stack_var_size as 32768. + * trans-decl.c (gfc_finish_var_decl): Modified. + +2003-11-08 Paul Brook + + PR fortran/12704 + * trans-intrinsic.c (gfc_conv_intrinsics_minmaxloc): Handle zero-size + arrays. + +2003-11-06 Paul Brook + + * trans-intrinsic.c (gfc_conv_intrinsics_minmaxloc): Initialize pos. + +2003-11-02 Canqun Yang + + * match.c (gfc_match_stopcode): Assign '0' to stop_code. + +2003-10-27 Anthony Green + + * Make-lang.in (f95.stageprofile): Use tabs, not spaces. + (f95.stagefeedback): Ditto. + +2003-10-27 Andrew Pinski + + PR fortran/12682 + * Make-lang.in (f95.stageprofile): Add. + (f95.stagefeedback): Add. + +2003-10-23 Richard Henderson + + * f96-lang.c (gfc_gimplify_expr): Remove. + (LANG_HOOKS_GIMPLIFY_EXPR): Remove. + (LANG_HOOKS_GIMPLE_BEFORE_INLINING): New. + +2003-10-23 Richard Henderson + + * f95-lang.c (gfc_gimplify_expr): Return gimplify_status. + +2003-10-20 Paul Brook + + * trans-expr.c (gfc_conv_integer_power): Use boolean_type_node. + * trans-stmt.c (gfc_trans_do_while): Ditto. + +2003-10-17 Paul Brook + + * simplify.c (gfc_simplify_shape): Use gfc_array_dimen_size. + +2003-10-17 Paul Brook + + * trans-io.c (gfc_build_io_library_fndecls): Set TREE_PUBLIC. + +2003-10-17 Feng Wang + + * iresolve.c (gfc_resolve_maxloc): Change the result's kind and type. + (gfc_resolve_minloc): Ditto. + * trans-intrinsic.c (gfc_conv_intrinsic_minmaxloc): Use correct types. + Return the value after subtracting the lower bound. + +2003-10-16 Richard Henderson + + * f95-lang.c (expand_function_body): Don't check flag_disable_gimple. + +2003-10-16 Steven Bosscher + + * lang.c: Remove -M option for now, it's in the way for C. + +2003-10-14 Jason Merrill + + * Make-lang.in (f95.tags): New rule. + +2003-10-13 Richard Henderson + + * trans.c (gfc_trans_code): Use annotate_all_with_locus. + +2003-10-13 Paul Brook + + * trans-decl.c (generate_local_decl): Don't create junk variables. + +2003-10-13 Paul Brook + + * resolve.c (resolve_formal_arglist): Use function result decl in + preference to function decl. + +2003-10-12 Richard Henderson + + * f95-lang.c (gfc_define_builtin): New const_p argument. Set + TREE_READONLY. Update all callers. + +2003-10-12 Feng Wang + + * iresolve.c (gfc_resolve_cshift): Change to match implementation. + * trans-intrinsic.c (gfc_conv_intrinsic_function): Remove CSHIFT. + (gfc_is_intrinsic_libcall): Add CSHIFT. + +2003-10-12 Richard Henderson + + * trans-array.c (gfc_trans_static_array_pointer): Set TREE_INVARIANT. + (gfc_trans_array_constructor_value): Likewise. + (gfc_conv_array_initializer): Likewise. + * trans-stmt.c (gfc_trans_character_select): Likewise. + +2003-11-12 Kejia Zhao + + * trans-intrinsic.c (integer_kind_info, real_kind_info): Remove. + +2003-10-11 Huang Chun + + * check.c (gfc_check_repeat): Check arguments are scalar. + (gfc_check_trim): New function. + * intrinsic.h (gfc_check_trim): Add prototype. + * intrinsic.c (add_functions): Use it. + * trans.h (gfor_fndecl_string_trim, gfor_fndecl_string_repeat): + Decalare. + * trans-decl.c: Ditto. + (gfc_build_intrinsic_fucntion_decls): Set them. + * trans-intrinsic.c (gfc_conv_intrinsic_len): Handle result vars. + (gfc_conv_intrinsic_trim): New function. + (gfc_conv_intrinsic_repeat): New function. + (gfc_conv_intrinsic_function): Use them. + +2003-10-11 Huang Chun + + * trans-types.c (gfc_sym_type): Handle result variables. + +2003-10-11 Huang Chun + + * trans-intrinsic.c (gfc_conv_intrinsic_char): Don't use + gfc_get_character_type. + +2003-10-11 Feng Wang + + * trans-expr.c (gfc_conv_variable): Check sym->ts, not the decl. + +2003-10-11 Paul Brook + + * iresolve.c (gfc_resolve_dint, gfc_resolve_dnint): New functions. + (gfc_resolve_dprod): New function. + (gfc_resolve_aint, gfc_resolve_anint): Only base name on arg type. + * intrinsic.h (gfc_resolve_dint, gfc_resolve_dnint): Declare. + (gfc_resolve_dprod): Declare. + * intrinsic.c (add_functions): Use them. + * trans-decl.c (gfc_get_extern_function_decl): Only pass one arg. + +2003-10-06 Richard Henderson + + * f95-lang.c (gfc_init_builtin_functions): Add clzll. + * trans-intrinsic.c (call_builtin_clz): Use it. + +2003-10-05 Paul Brook + + * f95-lang.c (expand_function_body): Call (push|pop)_function_context. + * trans-decl.c (gfc_generate_function_code): Set + cfun->function_end_locus. + +2003-09-24 Jason Merrill + + * f95-lang.c, trans-decl.c: Use DECL_SOURCE_LOCATION instead of + TREE_LOCUS. + +2003-09-21 Lifang Zeng + Paul Brook + + * Make-lang.in (F95_OBJS): Add fortran/data.o. + * array.c (gfc_inser_constructor): New function. + (gfc_get_constructor): New function. + (gfc_free_constructor): Initialize offset and repeat. + (iterator_stack): Remove. + (expand_info): Add offset, component and repeat fields. + (expand_constructor): Set them. + (expand): Set new fields. + (gfc_copy_constructor): Ditto. Avoid recursion. + * gfortran.h: Add prototypes for new functions. + (gfc_constructor): Add offset, component and repeat. + (iteratio_stack): Move to here. + * resolve.c (check_data_variable): Convert data values into variable + initializers. + (traverse_data_list): Build implicit loop chain. + (gfc_resolve): Ditto. + * trans-array.c (gfc_conv_array_intializer): Handle repeat count. + * trans-decl.c (gfc_get_symbol_decl): Use gfc_conv_structure. + * trans-expr.c (gfc_conv_structure): Handle array initializers. + (gfc_conv_expr): Update to match. + * trans.h (gfc_conv_structure): Declare. + * data.c: New file. + +2003-09-20 Kejia Zhao + + * trans.h: Add declarations for gfor_fndecl_si_kind and + gfor_fndecl_sr_kind. + * trans-decl.c (g95_build_intrinsic_function_decls): Build them. + * trans-intrinsic.c (g95_conv_intrinsic_si_kind): New function. + (g95_conv_intrinsic_sr_kind): New function. + (g95_conv_intrinsic_function): Add SELECTED_INT_KIND and + SELECTED_REAL_KIND. + +2003-09-17 Lars Segerlund + + * iresolve.c (gfc_resolve_random_number): Generate _r4 & _r8 + instead of _4 and _8 as postfix for libgfortran calls. + +2003-09-16 Paul Brook + + * array.c (compare_bounds): New function. + (gfc_compare_array_spec): Use it. + +2003-09-14 Paul Brook + + * primary.c (gfc_match_rvalue): Make sure sym->result is set. + * trans-expr.c (gfc_conv_string_parameter): Also allow PRAM_DECLs. + +2003-09-14 Paul Brook + + * check.c (dim_rank_check): Allow assumed bounds if requested. + (gfc_check_lbound): Call it. + (gfc_check_ubound): Ditto. + (gfc_check_size): Change to match. + * simplify.c (gfc_simplify_bound): New function. + (gfc_simplify_lbound): New function. + (gfc_simplify_ubound): New function. + * intrinsic.h: Declare them. + * intrinsic.c (add_functions): Use them. + +2003-09-14 Paul Brook + + * io.c (format_lex): Initialize negative_flag. + (check_format): Intialize repeat. + * trans-io.c (gfc_new_nml_name_expr): Declare static. + (gfc_new_var_expr): Ditto. + +2003-09-14 Paul Brook + + * trans-array.c (gfc_conv_array_initializer): Handle derived types. + * trans-decl.c (gfc_get_symbol_decl): Only do local scalar values. + +2003-09-12 Paul Brook + + * trans-intrinsic.c (gfc_conv_intrinsic_sign): Call fold. + +2003-09-12 Zdenek Dvorak + + * fortran/trans.c (gfc_finish_block): Call rationalize_compound_expr + for a correct expression. + +2003-09-10 Kejia Zhao + + * trans-intrinsic.c (real_compnt_info): New struct. + (prepare_arg_info): New function. + (gfc_conv_intrinsic_set_exponent): New function. + (gfc_conv_intrinsic_scale): New function. + (gfc_conv_intrinsic_nearest): New function. + (gfc_conv_intrinsic_fraction): New function. + (gfc_conv_intrinsic_exponent): New function. + (gfc_conv_intrinsic_spacing): New function. + (gfc_conv_intrinsic_rrspacing): New function. + (gfc_conv_intrinsic_function): Use them. + +2003-08-24 XiaoQiang Zhang (zhangapache@yahoo.com> + + * trans-const.c (gfc_conv_mpz_to_tree): Fix bug, parameter for + build_int_2 changed from (high, low) to (low, high). + * trans-io.c (ioparm_namelist_name, ioparm_namelist_name_len, + ioparm_namelist_read_mode, iocall_set_nml_val_int, + iocall_set_nml_val_float, iocall_set_nml_val_char, + iocall_set_nml_val_complex, iocall_set_nml_val_log): New declaration. + (gfc_build_io_library_fndecls): Add variable initialization. + (gfc_new_nml_name_expr, get_new_var_expr): New function. + (build_dt): Add namelist support. + * io.c (value): New variable. + (check_format): Support FMT_H now. + +2003-09-07 Paul Brook + + * io.c (gfc_resolve_dt): Error if format label is not defined. + +2003-09-07 Kejia Zhao + + * trans-intrinsic.c (gfc_conv_intrinsic_aint): Fix two bugs. One is + about case_switch's break. The other is about building the condition + statement tree, which judges the argument in the range of the + corresponding integer type. + * trans-intrinsic.c (gfc_conv_intrinsic_mod): MOD and MODULO can work + for the large values. + +2003-09-05 Paul Brook + + * f95-lang.c (expand_function_body): Gimplify the function. + +2003-09-04 Jeff Law + + * f95-lang.c (DEFINE_MATH_BUILTIN): C arrays start at + index zero! + +2003-09-04 Paul Brook + + * f95-lang.c (gfc_define_builtin): Also set implicit_built_in_decls. + (gfc_expand_stmt): New function. + (LANG_HOOKS_RTL_EXPAND_STMT): Define. + (expand_function_body): Use tree_rest_of_compilation. + * trans-decl.c (gfc_generate_function_code): Don't free cfun. + +2003-09-03 Jeff Law + + * f95-lang.c (gfc_init_builtin_functions): C arrays start at + index zero! + +2003-08-30 Paul Brook + + * f95-lang.c (builtin_function): Remove #if 0 code. + (gfc_define_builtin): New function. + (gfc_init_builtin_functions): Use mathbuiltins.def not ../builtins.def. + * mathbuiltins.def: New file. + * trans-intrinsic.c (gfc_intrinsic_map_t): Add builtin code fields. + (gfc_intrinsic_map): Use mathbuiltins.def. + (gfc_intrinsic_builtin_t): Remove. + (gfc_build_intrinsic_lib_fndecls): Update. + * trans-types.c (gfc_init_types): Remove redundant initilaization of + signed_size_type_node. + +2003-08-29 Paul Brook + + * arith.c (gfc_real_kinds): Use correct minimum exponents. + +2003-08-22 Kejia Zhao + + * trans-instinsic.c (gfc_conv_intrinsic_mod): Also do MODULO. + (gfc_conv_intrinsic_function): Add MODULO. + +2003-08-22 Jason Merrill + + * trans-array.c (gfc_conv_expr_descriptor): Update use of predicates. + +2003-08-22 Andreas Jaeger + + * Make-lang.in (f95.install-common): Add DESTDIR support. + * (f95.install-info): Likewise. + (f95.uninstall): Likewise. + +2003-08-19 Diego Novillo + + * trans-types.c (gfc_init_types): Initialize + signed_size_type_node with size_type_node. + +2003-08-18 Paul Brook + + * dependency.c (gfc_dependency): New enum. + (check_another_array_ref): Remove. + (gfc_get_array_from_component): Remove. + (get_x): Remove. + (get_range): Remove. + (get_no_of_elements): Use mpz_t, not mpf_t. + (transform_sections): New function. + (gfc_check_range_range): Rename ... + (gfc_check_section_vs_section): ... to this. Use new function. + (gfc_is_inside_range): Rewrite to match. + (gfc_check_element_vs_section): Ditto. + (gfc_check_element_vs_element): Ditto. + (get_deps): Ditto. + (gfc_dep_resolver): Ditto. Remove unused parameter. + * Dependency.h (gfc_check_range_range, gfc_check_element_vs_section, + gfc_check_element_vs_element, gfc_is_inside_range, + gfc_get_array_from_component): Remove prototypes for static functions. + (gfc_dep_resolver): Update prototype. + * trans-array.c (gfc_conv_resolve_dependencies): Change to match. + +2003-08-15 Paul Brook + + * trans-decl.c (gfc_build_qualified_array): Don't add symbols for + return values to parent scope. + (gfc_build_dummy_array_decl): Ditto. + +2003-08-14 Paul Brook + + * trans-stmt.c (gfc_trans_allocate): Handle NULL refs. Allocate the + size of the type, not the pointer. + * resolve.c (resolve_symbol): Give more accurate error message. + +2003-08-10 Paul Brook + + * trans-decl.c (gfc_build_function_decl): Only mangle global symbols. + +2003-08-10 Paul Brook + + * trans-stmt.c (gfc_trans_allocate): Correctly handle non-array derived + type components. + +2003-08-10 Chun Huang + + * resolve.c (resolve_formal_arglist): Resolve STATEMENT function. + (resolve_symbol): Ditto. + * trans-expr.c (gfc_conv_statement_function): New function. + (gfc_conv_function_expr): Use it. + +2003-08-10 Paul Brook + + * trans-array.c (gfc_conv_ss_startstride): Handle functions. + (walk_function_expr): Set section rank. + * trans-intrinsic.c (gfc_walk_intrinsic_libfunc): Ditto. + +2003-08-10 Paul Brook + + * intrinsic.c (add_sym): Prefix names with correct string. + (add_sym_0s): New function. + (add_subroutines): Register abort. + +2003-08-10 Erik Schnetter + + * gfortran.h: Introduce options to control the mangling. + * lang.opt: Likewise. + * options.c (gfc_init_options): Handle the options. + * trans-common.c (gfc_sym_mangled_common_id): New function. + (gfc_build_common_decl): Call it. + * trans-decl.c (gfc_sym_mangled_function_id): New function. + (gfc_get_extern_function_decl, gfc_build_function_decl): Call it. + +2003-08-09 Paul Brook + + * module.c (mio_symbol): Always ouput a namespace for formal args. + (load_needed): Namespace now belong to their proper symbol. + (gfc_dump_module): Change G95=>GFORTRAN. + +2003-08-05 Paul Brook + + * options.c: Force -fg77-calls. + +2003-08-02 Paul Brook + + * Makelang.in: Rename G95_* to GFORTRAN_*. + * All sources: Rename G95_* to GFC_*. + +2003-08-01 Paul Brook + + * fortran/Make-lang.in: Use GMPLIBS. + * fortran/config-lang.in: Set need_gmp. + * trans-expr.c (gfc_conv_variable): Remove incorrect assertion. + +2003-07-27 Andreas Jaeger + + * trans-decl.c (gfc_generate_constructors): Convert prototype to + ISO C90. + * trans-const.c (gfc_init_constants): Likewise. + * trans-intrinsic.c (gfc_build_intrinsic_lib_fndecls): Likewise. + + * gfortranspec.c: Convert to ISO C90. + (lang_specific_driver): Correct copyright, remove ALT_LIBM usage. + +2003-07-26 Paul Brook + + * lang.opt: Add -fdump-parse-tree. + * options.c (gfc_handle_option): Ditto. + * resolve.c (resolve_forall_iterators): Convert to proper type. + * trans-stmt.c (gfc_trans_forall_1): Create temp var with correct type. + +2003-07-26 Paul Brook + + * Makefile.in: Add build dependencies on files common with rest of gcc. + +2003-07-26 Lifang Zeng + + * trans.h: Declare g95_trans_pointer_assignment. + * trans-expr.c (g95_trans_pointer_assignment): New function. + (g95_trans_pointer_assign): Use it. + * trans-stmt.c (g95_trans_forall_1): Handle pointer assignment. + (g95_trans_pointer_assign_need_temp): New function. + +2003-07-26 Paul Brook + + * gfortran.texi: Replace references to g95. + +2003-07-26 Paul Brook + + Rename g95_* to gfc_*. + +2003-07-25 Paul Brook + + * gfortran.h: Rename from g95.h. + * trans-types.c (boolean_type_node, booelan_true_node, + boolean_false_node): Remove. + * trans-types.h: Ditto. + +2003-07-25 Chun Huang + + * parse.c (accept_statement): Implement BLOCK DATA statement. + * trans-expr.c (g95_conv_variable): Fix bug for dereference pointer + variables. + +2003-07-24 Lifang Zeng + + * trans-stmt.c (temporary_list): Define. + (g95_trans_assign_need_temp): New function. + (g95_trans_forall_1): Modified for WHERE. + (g95_trans_where_assign): Modified. + (g95_trans_where_2): Modified. + (g95_evaluate_where_mask): Modified. + (g95_trans_where): Modified. + (g95_get_temp_expr): Removed. + (g95_add_to_where_stmt_list): Removed. + (compute_overall_iter_number): Modified for WHERE. + * trans.h: Remove where_stmt_list. + +2003-07-24 Arnaud Desitter + + * lang.opt: Correct description of options -J and -M. + +2003-07-23 Steven Bosscher + + * lang.opt: Move help text to here. + * lang-options.h: Remove. + +2003-07-23 Arnaud Desitter + * iresolve.c (g95_resolve_transpose): Proper variable in switch. + * simplify.c (g95_simplify_nearest): Fix typo and use a correct test + on kind. + +2003-07-22 Steven Bosscher + Paul Brook + + * check.c (check_rest): Use global pedantic flag. + * io.c (data_desc): Ditto. + * error.c (g95_warning, g95_warning_now): Use global flag. + * f95-lang.c (LANG_HOOKS_HANDLE_OPTION): Rename from DECODE. + (expand_function_body): Update to new prototypes. + (g95_init): Use new option names. + * g95.h (g95_option_t): Standardize names. + (g95_init_options, g95_handle_option): Update prototypes. + * interface.c: Use new option names. + * match.c: Ditto. + * module.c: Ditto. + * parse.c: Ditto. + * primary.c: Ditto. + * resolve.c: Ditto. + * scanner.c: Ditto. + * simplify.c: Ditto. + * symbol.c: Ditto. + * trans-array.c: Ditto. + * trans-expr.c: Ditto. + * trans-types.c: Ditto. + * trans-decl.c: Ditto. + (g95_build_library_function_decl): Remove obsolete VPARAMS. + * trans.h: Ditto. + * options.c (g95_display_help): Remove. + (g95_init_options): Convert to new scheme. + (set_Wall): Ditto + (g95module_option): Ditto, rename from g95_parse_arg. + (g95_handle_module_path_options): New function. + * trans-equivalence.c: Fix error message. + * lang.opt: Corrections. + +2003-07-21 Steven Bosscher + + * lang.opt: New file. + +2003-07-21 Arnaud Desitter + + * decl.c (match_attr_spec): Set colon_seen. + +2003-07-14 Paul Brook + + * trans-array.c: Update comment. + (g95_trans_array_constructor_subarray): Cleanup loopinfo data. + * trans-intrinsic.c (g95_conv_intrinsic_anyall,count,arith, + minmaxloc,minmaxval): Ditto. + * trans-io.c (g95_trans_transfer): Ditto. + * trans-stmt.c: Remove unneeded prototypes. + (generate_loop_for_lhs_to_rhs): Rename vars. Add loop post chain. + (generate_loop_for_rhs_to_temp): Rename vars. Don't share loopinfo. + (compute_inner_temp_size): Remove bits of dead code. Add comments. + Don't share loopinfo. + (compute_overall_iter_number): Declare as static. + (allocate_temp_for_forall_nest): Ditto. + (g95_trans_forall_1): Don't pass shared loopinfo. + * trans.c (g95_start_block): Expand comment. + +2003-07-12 Paul Brook + + * arith.c (g95_index_integer_kind): Remove unused initializer. + * trans-stmt.c (generate_loop_for_temp_to_lhs): Don't multiply array + index by size of element. + (generate_loop_for_rhs_to_temp): Ditto. + (allocate_temp_for_forall_nest): Use element size, not index size. + +2003-07-11 Arnaud Desitter + + * arith.c (g95_index_integer_kind): Add a TODO. + * simplify.c (g95_simplify_nearest): Add a TODO. + +2003-07-09 Chun Huang + + * trans.h: Add declarations for gfor_fndecl_string_scan and + gfor_fndecl_string_verify. + * trans-decl.c (g95_build_intrinsic_function_decls): Build them. + * trans-intrinsic.c (g95_conv_intrinsic_scan): New function. + (g95_conv_intrinsic_verify): New function. + (g95_conv_intrinsic_function): Add SCAN and VERIFY. + * simplify.c (g95_simplify_scan, g95_simplify_verify): Fix bug in case + of parameter 'BACK=.TRUE.' + +2003-07-05 Lifang Zeng + + * trans-stmt.c (iter_info, forall_info): Define. + (g95_trans_forall_block): Remove. + (g95_trans_forall_loop): Use forall info blocks. + (g95_trans_nested_forall_loop): New function. + (g95_do_allocate): Handle things other than logical masks. + (generate_loop_for_temp_to_lhs): New function. + (generate_loop_for_rsh_to_temp): New function. + (compute_inner_temp_size): New function. + (compute_overall_iter_number): New function. + (allocate_temp_for_forall_nest): New function. + (g95_trans_forall): Move body ... + (g95_trans_forall_1): ... to here. Handle loops with temporaries. + +2003-07-02 Paul Brook + + * trans-decl.c (create_index_var, g95_build_qualified_array): Put vars + in correct scope. Change callers to match. + * trans-types.c (g95_get_dtype_cst): Allow rank 7 arrays. + * iresolve.c (g95_resolve_reshape): Only use constant shapes. + +2003-07-02 Paul Brook + + * trans-array.c (g95_conv_loop_setup): Remove dead var. Use + expression shape for all expressions. + * trans-decl.c (g95_symbol_init): Allow adding at very end of list. + +2003-07-03 Arnaud Desitter + + * g95.h (g95_option_t), lang-options.h, options.c (g95_init_options, + g95_parse_arg), intrinsic.c (g95_convert_type): support of + -Wconversion. + * intrinsic.c, g95.h: Add g95_convert_type_warn, + * resolve.c (g95_resolve_index): Call it. + +2003-07-02 Paul Brook + + * iresolve.c (g95_resolve_reshape): Set expression shape. + (g95_resolve_shape): Ditto. + * simplify.c (g95_simplify_shape): Move common code outside condition. + * trans-array.c (g95_conv_array_initializer): Teach it how to count. + +2003-07-01 Arnaud Desitter + + * array.c (g95_array_dimen_size): Deal with EXPR_ARRAY to improve + conformance checks. + +2003-06-29 Paul Brook + + * array.c (g95_simplify_iterator_var): Don't bother with return value. + * expr.c (find_array_element, find_component_ref): New functions. + (remove_subobject_ref): New function. + (simplify_const_ref): Use them. Rename from simplify_component_ref. + (simplify_ref_chain): New function. + (g95_simplify_expr): Use it. Simplify parameter variable subobjects. + (g95_specification_expr): Simplify the expression. + * resolve.c (resolve_operator): Check simplifications return code. + (g95_resolve_expr): Ditto. + +2003-06-26 Paul Brook + + * expr.c (simplify_component_ref): New function. + (g95_simplify_expr): Use it. + * resolve.c (resolve_structure_cons): Handle references. + +2003-06-25 Paul Brook + + * trans-io.c (build_dt): Handle internal units. + +2003-06-25 Canqun Yang + + * trans-common.c (g95_build_common_decl): Array index range starts at 0. + (g95_build_common_decl, g95_layout_global_equiv, g95_trans_one_common): + Use g95_array_index_type instead of integer_type_node. + (g95_build_common_decl, g95_set_common_master_type): Use + g95_character1_type_node instead of char_type_node. + * trans-equivalence.c (g95_layout_local_equiv): As above. + +2003-06-24 Steven G. Kargl + + * g95.h (g95_option_t), options.c (g95_init_options, g95_parse_arg): + remove last remains of -fquiet. + +2003-06-22 Paul Brook + + * resolve.c (resolve_operator): Don't fail if we can't simplify. + (g95_resolve_expr): Ditto. + (resolce_code): Mark as static. + * trans-stmt.c (g95_trans_chaaracter_select): Mark labels because the + gimplifer doesn't (yet). + +2003-06-20 Paul Brook + + * g95.h: Add ST_PAUSE and EXEC_PAUSE. + * match.c (g95_match_if): Add ST_PAUSE. + (g95_match_stopcode): New function. + (g95_match_pause, g95_match_stop): Use it. + * parse.c (g95_ascii_statement): Handle ST_PAUSE. + (decode_stmt, next_statement, parse_executable): Ditto. + * resolve.c (resolve_code): Ditto. + * st.c (g95_free_statement): Ditto. + * trans-stmt.c (g95_trans_pause): New function. + * trans-stmt.h: Declare it. + * trans.c (g95_trans_code): Use it. + * trans-decl.c (gfor_fndecl_pause_numeric, gfor_fndecl_pause_string): + Declare. + (g95_build_builtin_function_decls): Initialize them. + * trans.h: Ditto. + * dump-parse-tree.c (g95_show_code_node): Handle EXEC_PAUSE. + +2003-06-18 Arnaud Desitter + + * io.c (g95_match_open , g95_match_close, g95_match_inquire, + match_filepos): Fix error handling. + +2003-06-18 Arnaud Desitter + + * array.c (spec_dimen_size, ref_dimen_size, g95_array_dimen_size): + Add assertions on arguments. + * resolve.c (expression_shape): Remove useless &. + * simplify.c (get_kind, g95_simplify_bit_size, g95_simplify_digits, + g95_simplify_ibclr, g95_simplify_ibits, g95_simplify_ibset, + g95_simplify_ishft,g95_simplify_ishftc, g95_simplify_maxexponent, + g95_simplify_minexponent, g95_simplify_radix, g95_simplify_range + g95_simplify_rrspacing, g95_simplify_scale, g95_simplify_spacing, + g95_simplify_tan, g95_simplify_tiny): Clean predicates and assertions. + (g95_simplify_not, g95_simplify_scale): Add assertions. + +2003-06-15 Paul Brook + + Clean up stuff to work with the ssa optimizers. + * convert.c (convert): Handle BOOLEAN_TYPEs. + * f95-lang.c (g95_truthvalue_conversion): Implement. + * trans-array.c (g95_trans_array_constructor_value): Group multiple + scalar values. + * trans.h (g95_truthvalue_conversion): Declare. + * trans-intrinsic.c (g95_conv_intrinsic_anyall): Use bool constants. + * trans-stmt.c (g95_trans_character_select): Don't create array + assignments. Mark labels as indirect jump targets. + * trans-types.h (g95_init_types): Use BOOLEAN_TYPE nodes. + (g95_get_dtype_cst): Handle LOGICAL types. + +2003-06-14 Paul Brook + + * f95-lang.c (g95_gimplify_expr): New function. + * trans-array.c (g95_trans_array_constructor_value): Don't create + array assignments. + (g95_conv_expr_descriptor): Rename simple->gimple. + * trans-expr.c (conv_expr_op): Use proper logical operators. + * trans-intrinsic.c (build_fixbound_expr): New function. + (build_fix_expr): Ditto. + (g95_conv_intinsic_aint): Use them. Use builtin functions. + (g95_conv_intrinsic_function): Add FLOOR and CEILING. + +2003-06-10 Arnaud Desitter + + * array.c (g95_compare_array_spec): Remove unreachable code. + * expr.c (g95_copy_expr): Likewise. + * intrinsic.c (g95_convert_type): Likewise. + * misc.c (g95_code2string): Likewise. + * simplify.c (g95_simplify_ishft, g95_simplify_real, + g95_simplify_reshape, g95_simplify_sign, g95_simplify_sqrt): Likewise. + * trans-stmt.c (g95_trans_select): Likewise. + * primary.c (extend_ref): Add an assertion. + * simplify.c (g95_convert_constant): Add const. + * intrinsic.h: Remove g95_check_x_ni. + * f95-lang.c (g95_finish): Call g95_release_include_path. + +2003-06-10 Arnaud Desitter + + * resolve.c (resolve_contained_functions): Fix typo introduced on + 2003-01-13. + +2003-06-09 Paul Brook + + * g95.h: Include system.h not hwint.h. + * many: use safe-ctype.h not ctype.h. Change isalpha -> ISALPHA, etc. + * misc.c (g95_getmem): Use xmalloc/memset instead of calloc. + +2003-06-09 Paul Brook + + * g95.h (g95_symbol): Add fields for COMMON and EQUIVALENCE variables. + * Make-lang.in (F95_OBJS): Add files for COMMON and EQUIVALENCE. + * trans-decl.c (g95_add_decl_to_functions): Make non-static. + (g95_get_symbol_decl): Handle COMMON and EQUIVALENCE objects. + (g95_generate_function_code): Translate COMMON and EQUIVALENCE + objects. + * trans.h (g95_trans_equivalence, g95_trans_common, + g95_add_decl_to_function): Declare. + * trans-common.c, trans-equivalence.c: New files. + +2003-06-08 Steven Bosscher + + * intrinsic.c (g95_intrinsic_extension): Remove. + (add_functions): Substitute g95_check_x for g95_check_x_ni + everywhere. + (g95_init_expr_extensions): New function. + (g95_intrinsic_func_interface): Use it. + * intrinsic.h: Remove extern decl for g95_intrinsic_extension. + * check.c (g95_check_digit, g95_check_huge, g95_check_kind, + g95_check_precision, g95_check_present, g95_check_radix, + g95_check_range, g95_check_selected_real_kind): Do not set + g95_intrinsic_extension. + (g95_check_x_ni): Remove now duplicate of g95_check_x. + + * expr.c (check_inquiry): Add FIXME, fixup some code style. + +2003-06-06 Arnaud Desitter + + * g95.h (ref_type): Name this type explicitly. + * module.c (MIO_NAME): Add specialisations of mio_name. + (mio_symbol_attribute, mio_typespec, mio_array_ref, + mio_array_spec, mio_ref, mio_expr, mio_symbol): Use them. + (ab_attribute): Name this type explicitly. + (mio_symbol_attribute, mio_expr): Add cast to call to find_enum. + +2003-06-05 Kejia Zhao + + * trans-intrinsic.c (g95_conv_allocated): New function. + (g95_conv_intrinsic_function): Make G95_ISYM_ALLOCATED work. + +2003-06-05 Steven Bosscher + + * f95-lang.c: Don't include g95-support.h + (g95_mark_addressable): Add prototype. + (g95_init_decl_processing): Remove C front end hack. + * f95-tree.c: Remove file. + * support.c: Remove file. + * g95-support.h: Remove file. + * trans-types.c (g95_init_types): Set up boolean + type related tree nodes. + * Make-lang.in: Remove rules for dead files and + dependencies on them. + +2003-06-05 Steven Bosscher + + * Make-lang.in (F95_ADDITIONAL_OBJS): Remove the final + C front end dependency. Also, convert.c does not depend on + g95-support.h anymore. + * convert.c: Don't include c-common.h and g95-support.h + * f95-lang.c: Don't inlude c-common.h and c-common.def (3x). + (g95_stmt_tree, g95_scope_stmt_stack, anon_aggr_type_p, + stmts_are_full_exprs_p, current_stmt_tree, + current_scope_stmt_stack): Remove. + * g95-support.h (unsigned_conversion_warning): Kill proto. + (boolean_type_node, boolean_true_node, boolean_false_node): + Don't define here. Instead, make then true tree nodes in + trans-types. + * support.c (c_global_trees): Die, C front end, die!!! + (g95_init_c_decl_hacks): Don't touch intmax_type_node, + uintmax_type_node, string_type_node and const_string_type_node. + (decl_constant_value, overflow_warning): Make static functions. + They are in death row too, though. + (default_conversion, c_expand_asm_operands): Remove. + * trans-array.c, trans-expr.c, trans-intrinsic.c, trans-stmt.c, + trans.c: Don't include c-common.h. + * trans-types.c (boolean_type_node, boolean_true_node, + boolean_false_node): Make them real tree nodes. + * trans-types.h (intmax_type_node, string_type_node, + const_string_type_node): Hack to work around C dependencies + in builtin-types.def. + +2003-06-04 Arnaud Desitter + + * decl.c (decl_types): Add some iterators-like sentinels. + * decl.c (match_attr_spec): Use them. + Use "decl_types" instead of "int". + Add cast in call to g95_match_strings. + * dump-parse-tree.c (g95_show_namespace): Use "g95_intrinsic_op" + instead of "int". + * g95.h (g95_intrinsic_op): Add some iterators-like sentinels. + (g95_interface_info): Use "g95_intrinsic_op". + * dump-parse-tree.c (g95_show_namespace): Use them. + * interface.c (g95_check_interfaces): Use them. + * module.c (read_module, write_module): Use them. + * symbol.c (g95_get_namespace, g95_free_namespace): Use them. + Use "g95_intrinsic_op". + * interface.c (check_operator_interface): Use "g95_intrinsic_op". + Add a default case in switch statement. + * intrinsic.h (g95_generic_isym_id): Moved to... + * g95.h (g95_generic_isym_id): here. + (g95_intrinsic_sym): Use "g95_generic_isym_id". + * intrinsic.c (make_generic): Use "g95_generice_isym_id". + * trans-intrinsic.c (g95_intrinsic_map_t, + g95_conv_intrinsic_lib_funtion): Use "g95_generice_isym_id". + * match.c (g95_match_intrinsic_op): Add cast in call to + g95_match_strings. + +2003-06-03 Steven Bosscher + + * support.c (skip_evaluation, warn_conversion, lvalue_p, + lvalue_or_else, pedantic_lvalue_warning, warn_for_assignment, + constant_fits_type_p, convert_and_check, + unsigned_conversion_warning): Remove these ugly remnants + we inherited from the C front end. + (function_types_compatible): Remove '#if 0'-edcode. + (build_modify_expr): Likewise. + (convert_for_assignment): Don't use the deceased functions. + The parameter fundecl is now unused. + (decl_constant_value): Always just return decl. In fact + this function is not used at present, but it might be in + the future, when we start using the tree inliner. + (overflow_warning, default_conversion, c_expand_asm_operands): + Abort when these are called, they are part of the C type + checking implementation and therefore poison to Fortran. + +2003-06-04 Steven Bosscher + + * Make-lang.in (F95_ADDITIONAL_OBJS): Don't depend on + c-pretty-print.o and c-dump.o. Add a comment on why we + depend on c-semantics.c. + * f95-lang.c (LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN): + Don't use the C front end tree dumper hook to dump the + language specific tree representation -- we don't have + one. So instead, inherit the default langhook. + +2003-06-02 Paul Brook + + * trans-expr.c (g95_conv_variable): Remove incorrent assertion. + +2003-06-02 Arnaud Desitter + + * check.c (g95_check_associated): Use proper types. Remove + extraneous argument in call to g95_error(). + +2003-06-02 Kejia Zhao + + * resolve.c (resolve_operator): Make logical operands convert to the + type with higher kind. + +2003-06-02 Kejia Zhao + + * check.c (g95_check_associated): Make sure both pointer and target has + the same type and rank. Null pointer or array section with vector + subscript as target are not allowed. + * trans.h: Declare gfor_fndecl_associated. + * trans-decl.c: (g95_build_builtin_function_decls): Initialize + gfor_fndecl_associated. + * trans-intrinsic.c (g95_conv_associated): New function. + (g95_conv_intrinsic_function): Make G95_ISYM_ASSOCIATED work. + +2003-06-02 Kejia Zhao + + * trans-array.c (g95_conv_expr_descriptor): Set the base of POINTER + according to POINTER itself rather than TARGET. + (g95_conv_expr_descriptor): Make lbound start at 1. + * trans-expr.c (g95_trans_pointer_assign): Fix a bug for Nullify. + +2003-06-01 Paul Brook + + * expr.c (g95_type_convert_binary): Make it match the standard. + * g95.texi: Remove dead link. + +2003-06-01 Steven Bosscher + + * g95.texi: Cleanup somewhat in preparation for inclusion + in GCC CVS. + +2003-05-23 Arnaud Desitter + Canqun Yang + + * resolve.c (compare_bound_int, resolve_where_shape): Proper return + type. + (g95_find_forall_index): Return proper value. + (g95_resolve_assign_in_forall, g95_resolve_forall): Use proper type to + compare the return value from g95_find_forall_index. + +2003-05-23 Arnaud Desitter + * g95.h, io.c (g95_st_label): Remove "length". + (g95_symtree): Remove "link". + (g95_case): Remove "code". + * arith.c, arith.h (g95_compare_string, g95_convert_integer, + g95_convert_real): Make an argument pointer to const. + * decl.c (colon_seen): Add a TODO. + * interface.c (g95_compare_types): Fix typo. + * interface.c (compare_interfaces): Preserve value of "p". + * intrinsic.c (sort_actual): Remove "i". + * match.c (g95_match_assign): Proper type in call to g95_match(). + * parse.c (next_free): Avoid duplicate call due to macro. + * parse.c (check_statement_label): wrong type in call to g95_error. + * primary.c (match_real_constant): Add a TODO. + * resolve.c (resolve_select): Remove useless conditional. + * simplify.c (g95_simplify_repeat): Proper assignment to + "value.character.string". + * simplify.c (g95_simplify_reshape): Wrong variable in call to + g95_error. + +2003-05-20 Canqun Yang + + * trans-stmt.c: Remove unnecessary include file defaults.h. + +2003-05-19 Lifang Zeng + + * trans-stmt.c (g95_trans_forall_loop): Handle FORALL with negative + stride. + (g95_trans_forall): Allow arbitrary number of FORALL indexes and + actual variables used as FORALL indexes. + +2003-05-15 Paul Brook + + * trans-array.c (g95_trans_static_array_pointer): Use + null_pointer_node. + (g95_trans_deferred_array): Initialize static array pointers. + * trans-expr.c (g95_conv_function_call): Use formal arglist to + correctly pass POINTER and absent CHARACTER arguments. + +2003-05-14 Lifang Zeng + + * resolve.c (g95_resolve_forall): Resolve FORALL construct/statement. + (g95_resolve_forall_body): Resolve FORALL body. + (g95_resolve_where_code_in_forall): Resolve WHERE inside FORALL. + (g95_resolve_assign_in_forall): Resolve assignment inside FORALL. + (g95_find_forall_index): Check whether the FORALL index appears in + the expression or not. + (resolve_code): Modified. + +2003-05-14 Paul Brook + + * iresolve.c (g95_resolve_spread): Convert ncopies to index_type. + +2003-05-13 Paul Brook + + * trans-types.c (g95_max_array_element_size): Now a tree node. + (g95_init_types): Work out max size properly. + (g95_get_dtype_cst): Modify to match. + +2003-05-11 Paul Brook + + * trans-io.c (add_case): Create a label decl for case labels. + +2003-05-11 Paul Brook + + * arith.c (g95_integer_index_kind): New variable. + * f95-lang.c (g95_init): Move frontend initialization here ... + (g95_post_options): ... from here. + * g95.h (g95_index_integer_kind, g95_resolve_index): Declare. + * intrinsic.c (add_functions): Use index kinds. + * iresolve.c: Convert to index_kind where needed. + * resolve.c (g95_resolve_index): Make public, use index_kind. + (resolve_array_ref): Adjust to match. + * trans-array.c: Rename g95_array_index_kind to g95_index_integer_kind. + * trans-stmt.c: Ditto. + * trans-types.c: Ditto. + * trans-types.h (g95_array_index_kind): Remove declaration. + * trans-expr.c (g95_conv_expr_present): Use null_pointer_node. + +2003-05-07 Paul Brook + + * trans-const.c (g95_conv_mpz_to_tree): Typecast constant. + * trans-intrinsic.c (g95_conv_intrinsic_bound): Convert type + of bound indices. + +2003-05-07 Paul Brook + + * trans-array.c (trans_static_array_pointer, + g95_trans_array_constructor_value, g95_conv_array_initializer, + g95_conv_structure): CONSTRUCTOR nodes only have one operand. + (g95_add_loop_ss_code): Convert subscripts to the correct type. + * trans-stmt.c (g95_trans_character_select): Ditto. + * trans-types.c (g95_init_types): Ditto. + +2003-05-07 Steven Bosscher + + * f95-lang.c (expand_function_body): Use input_line, not lineno. + * trans-decl.c (g95_generate_function_code, + g95_generate_constructors): Likewise. + * trans.c (g95_trans_runtime_check, g95_add_block_to_block, + g95_get_backend_locus, g95_set_backend_locus, g95_trans_code): + Likewise. + +2003-05-07 Kejia Zhao + * trans-types.c (g95_get_derived_type): Fix bug for DERIVED type + with components point to the DERIVED type itself, and two DERIVED + type with components point to each other. + * trans-expr.c (g95_conv_componet_ref): Modified + +2003-05-07 Kejia Zhao + * trans-expr.c (g95_conv_expr): Translate EXPR_NULL into + null_pointer_node. + (g95_trans_pointer_assign): Implement Nullify. + +2003-05-01 Paul Brook + + * trans-array.c (g95_walk_function_expr): Cope with NULL esym. + * trans-decl.c (g95_get_symbol_decl): Don't mangle dummy functions. + +2003-05-01 Paul Brook + + * trans-array.c, trans.c, trans-expr.c, trans-intrinsic.c, + trans-stmt.c: Replace empty_stmt_node with build_empty_stmt () and + IS_EMPTY_STMT. + +2003-05-01 Canqun Yang + + * trans-stmt.c (g95_trans_integer_select): Add a parameter to build + CASE_LABEL_EXPR. + +2003-04-28 Paul Brook + + * iresolve.c (g95_resolve_transpose): COMPLEX types are twice as big + as their kind suggests. + (g95_resolve_reshape): Ditto. + +2003-04-28 Chun Huang + + * trans-expr.c (g95_conv_substring_expr): New function. + (g95_conv_expr): Use it. + +2003-04-28 Paul Brook + + * iresolve.c (g95_resolve_transpose): Make it match the + implementation. + * trans-intrinsic.c (g95_is_intrinsic_libcall): Add TRANSPOSE. + +2003-04-18 Steven Bosscher + + * trans-types.c (g95_add_field_to_struct): New function to + add a field to a UNION_TYPE or RECORD_TYPE. + * trans-types.h (g95_add_field_to_struct): Prototype. + (g95_get_derived_type): Use g95_add_field_to_struct to add + components. + * trans-io.c (g95_add_field): Remove. + (ADD_FIELD): Use new g95_add_field_to_struct function. + (ADD_STRING): Likewise. + * trans-stmt.c (g95_trans_select): Likewise. + (g95_add_field): Remove duplicated function. + +2003-04-18 Canqun Yang + + Port implementation for CHARACTER SELECT from Andy's tree. + * trans-stmt.c (g95_trans_character_select): Implement character + select. (g95_add_field): New function. + * trans-decl.c: Declare 'gfor_gndecl_select_string'. + (g95_build_builtin_function_decls): Add 'gfor_fndecl_select_string'. + * g95.h (struct g95_case): Add field 'int n'. + * trans.h: Declare 'gfor_fndecl_select_string'. + +2003-04-18 Steven Bosscher + + * bbt.c (duplicate_key, g95_insert_bbt_with_overlap): Remove. + (g95_insert_bbd): Die on duplicates. + * g95.h (g95_insert_bbt_with_overlap): Delete prototype. + +2003-04-14 Steven Bosscher + + * g95.texi: Require GMP 4.0 -- like we actually + do. Explain the testsuite and what-goes-where. + Don't use undefined texinfo symbol. Break very + long line. Remove finished item from the list + of open projects. + +2003-04-11 Canqun Yang + + * trans-stmt.c (g95_evaluate_where_mask): Give mask temporaries + LOGICAL type. + +2003-04-10 Canqun Yang + + * trans-stmt.c (g95_trans_forall): Implement WHERE inside FORALL. + (g95_trans_forall_body): New function. + +2003-04-10 Canqun Yang + + * resolve.c (resove_where): New function. + (resolve_where_shape): New function. + (resolve_code): Add call to 'resolve_where' + * trans-stmt.c (g95_trans_where): Modified. + (g95_trans_where_2): New function. + (g95_trans_where_assign): New function. + (g95_evaluate_where_mask): New function. + (g95_add_to_stmt_list): New function. + (g95_get_temp_expr): New function. + * trans.h (where_stmt_list): New structure. + +2003-04-10 Paul Brook + + * g95spec.c (DEFAULT_SWITCH_TAKES_ARG): Remove. + (DEFAULT_WORD_SWITCH_TAKES_ARG): Ditto. + +2003-04-10 Steven Bosscher + + Update after mainline -> tree-ssa-branch merge. + * f95-lang.c (g95_mark_addressable): Update put_var_into_stack + call. + (g95_init): Update for new lang_hooks definition. + (g95_post_options): New langhook. + (LANG_HOOK_POST_OPTIONS): Clear, then define to g95_post_options. + * scanner.c (g95_new_file): Comment update. + +2003-04-09 Arnaud Desitter + + * g95.h, lang-options.h: Add -Wimplicit-interface. + * options.c (g95_init_options, g95_parse_arg): Set it. + * interface.c (check_intents): Warn about call with implicit + interface. + * resolve.c (resolve_unknown_f, resolve_unknown_s): Call + g95_procedure_use. + +2003-04-05 Paul Brook + + * iresolve.c (g95_resolve_spread): Don't resole based on type. + * trans-intrinsic.c (g95_is_intrinsic_libcall): Add G95_ISYM_SPREAD. + +2003-03-29 Paul Brook + + * iresolve.c (g95_resolve_pack): Don't bother resolving based on type. + (g95_resolve_unpack): Ditto. + * trans-intrinsic.c (g95_conv_intrinsic_merge): New Function. + (g95_conv_intrinsic_function): Use it. Remove PACK and UNPACK. + (g95_is_intrinsic_libcall): Add PACK and UNPACK. + +2003-03-25 Paul Brook + + * arith.c (g95_unary_user, g95_user): Remove dead functions. + * arith.h: Ditto. + * array.c (g95_free_array_ref): Ditto. + * g95.h: Ditto. + * symbol.c (g95_use_derived_tree): Ditto. + * intrinsic.c (add_functions): Use simplification for SCALE. + * primary.c (g95_match_rvalue): Test sym, not symtree. + +2003-03-25 Paul Brook + + * trans-decl.c (build_function_decl): Add parameter before it gets + turned into a constant. + * iresolve.c (g95_resolve_eoshift): Resolve to a useful name. + * trans-intrinsic.c (g95_is_intrinsic_libcall): Add G95_ISYM_EOSHIFT. + * trans-decl.c (g95_create_module_variable): Don't pushdecl constants. + +2003-03-22 Paul Brook + + * trans-array.c (g95_conv_array_initializer): Allow scalar + expressions. + * trans-decl.c (g95_finish_var_decl): Result variables are not + module variables. + * trans-intrinsic.c (g95_conv_intrinsic_transfer): New function. + (g95_conv_intrinsic_function): Use it. + * trans-types.h (g95_type_spec): Remove dead declaration. + +2003-03-21 Paul Brook + + * trans-decl.c (g95_build_function_decl): Mark string parameters. + +2003-03-20 Paul Brook + + * trans-decl.c (g95_build_function_decl): Put character length + parameters at the end of the function declaration. + * trans-expr.c (g95_conv_function_call): Ditto. + * trans-types.c (g95_get_function_type): Ditto. + +2003-03-20 Arnaud Desitter + + * resolve.c (resolve_formal_arglist): Don't impose intent for + procedure arguments of pure functions. + (resolve_select): Remove redundant assignment. + +2003-03-19 Arnaud Desitter + + * arith.c (validate_logical), g95.h, options.c (g95_init_options): + Remove option l1. + * g95.h, intrinsic.c(g95_get_intrinsic_sub_symbol): Add const. + * iresolve.c(g95_resolve_cpu_time, g95_resolve_random_number): Add + const. + * lang-options.h: Remove -finline-repack-arrays. Add -fg77-calls. + Order list. + * symbol.c (g95_add_type): Fix typo in comment. + + +2003-03-16 Paul Brook + + * dump-parse-tree.c (g95_show_code_node): Print resolved sym name. + * expr.c (g95_build_call): Remove. + * f95-lang.c (puchdecl_top_level): New function. + * g95.h (g95_code): Store resolved symbol, not just the name. + * intrinsic.c (g95_intrinsic_namespace): New global namespace. + (g95_intirinsic_init_1, g95_intrinsic_done_1): Use it. + (g95_get_intrinsic_sub_symbol): New function. + * iresolve.c (g95_resolve_cpu_time): Use it. + (g95_resolve_random_number): Ditto. + * resolve.c: Set code->resolved_sym instead of code->sub_name. + * trans-decl.c (g95_get_extern_function_decl): Give external decls + the correct DECL_CONTEXT. Add global symbold to the global scope. + * trans-stmt.c (g95_trans_code): Remove hacks now the fronted is + fixed. + +2003-03-16 Paul Brook + + * g95.h (g95_option_t): Add g77_calls. Remove inline_repack_arrays. + * options.c (g95_parse_arg): Ditto. + * module.c (mio_symbol_attribute): Handle the always_explicit bit. + * resolve.c (resolve_formal_arglist): The always_explicit sould be set + for the procedure, not the parameter. + * trans-array.c (g95_trans_g77_array): New function. + (g95_trans_assumed_size): Use it. + (g95_trans_dummy_array_bias): Ditto. + (g95_conv_array_parameter): Handle g77 arrays. Move existing body ... + (g95_conv_expr_descriptor): ... to here. Update callers. + * trans-decl.c (g95_build_dummy_array_decl): Handle g77 arrays. + (g95_get_symbol_decl): Avoid processing g77 arrays multiple times. + * trans-expr.c (g95_conv_function_call): Handle g77 arrays. + * trans-intrinsic.c (g95_get_symbol_for_expr): Never use g77 arrays. + * trans-types.c (g95_is_nodesc_array): Handle g77 arrays. + (g95_sym_type): Ditto. + +2003-03-15 Paul Brook + + * trans-array.c (g95_walk_elemental_function_args): Don't amputate the + first chain. + * trans-expr.c (g95_conv_function_call): Use the resolved symbol. + +2003-03-14 Paul Brook + + * trans-array.c (g95_array_is_packed): Remove. + (g95_conv_array_base): Correctly handle all descriptorless cases. + (g95_conv_array_stride): Use descriptorless strides. + (g95_trans_dummy_array_bias): Don't always repack the array. + (g95_build_dummy_array_decl): Automatic dummy arrays are only partial + packed. + * trans-types.c (g95_get_nodesc_array_type): Differentiate between + dummy and non-dummy arrays... + (g95_sym_type, g95_get_derived_type): ... like these. + (g95_get_array_type_bounds): Allow discontiguous arrays. + +2003-03-12 Paul Brook + + * array.c (g95_resolve_array_spec): Fix comment. + * g95.h (symbol_attributes): New flag always_explicit. + * resolve.c (resolve_formal_arglist): Set it always_explicit. + * iresolve.c (g95_resolve_lbound, g95_resolve_ubound): Simplify. + * trans-array.c (g95_conv_descriptor_dimension): Remove dead assert. + (g95_trans_array_bounds): Allow assumed shape arrays. + (g95_trans_repack_array): Remove. + (g95_trans_dummy_array_bias): Rewite to use descriptorless arrays. + * trans-decl.c (g95_build_qualified_array): Only ignore absent + bounds for assumed size arrays. + (g95_build_dummy_array_decl): Use descriptorless arrays. + * trans-expr.c (g95_conv_expr_present): Allow descriptorless arrays. + (g95_trans_pointer_assign): Fix typo. + * trans-intrinsic.c (g95_conv_intrinsic_function_args): Remove dead + code. + (g95_conv_intrinsic_bound): Rewrite to handle descriptorless arrays. + * trans-types.c (g95_get_nodesc_array_type): Allow non-packed arrays. + Also modify callers. + * trans-types.h (g95_get_nodesc_array_type): Modify prototype. + +2003-03-08 Paul Brook + + * trans-array.c (g95_walk_elemental_functions): Don't reverse the SS. + (g95_conv_array_ubound): Provide dummy value for assumed size arrays. + * resolve.c (compare_spec_to_ref): Allow full array sections. + +2003-03-08 Paul Brook + + * expr.c (g95_simplify_expr): Also simplify array index and + substring expressions. + * resolve.c (compare_spec_to_ref): Check for assumed size bounds. + * trans-array.c (g95_trans_array_bounds): New function. + (g95_trans_auto_array_allocation): Use it. + (g95_trans_assumed_size): Rewrite. + * trans-decl.c (gfor_fndecl_in_pack, gfor_fndecl_in_unpack): Declare. + (gfor_fndecl_repack): Remove. + (g95_build_qualified_array): Handle absent upper bounds. + (g95_build_dummy_array_decl): Assumed shape arrays are descriptorless. + (g95_get_symbol_decl): Update. + (g95_build_intrinsic_function_decls): Initialize new decls. + * trans.h (gfor_fndecl_in_pack, gfor_fndecl_in_unpack): Declare. + (gfor_fndecl_repack): Remove. + * trans-io.c (g95_build_io_library_fndecls): Correct prototypes. + * trans-types.c: (g95_build_array_type): Merge duplicated code.. + (g95_get_nodesc_array_type): Handle absent bounds. + * trans-types.h (g95_get_nodesc_array_type): Declare. + +2003-03-04 Paul Brook + + * f95-lang.c (DEF_FUNCTION_TYPE_VAR_3): Define before including + builtin-types.def. + +2003-03-02 Paul Brook + + * options.c (g95_init_options): Drfault to 1. + (g95_pasrse_arg): Add -frepack-arrays, use strcmp. + * trans-array.c (g95_conv_array_data, g95_conv_array_base, + g95_conv_array_stride,g95_conv_array_lbound, g95_conv_array_ubound): + Handle non-constant size automatic arrays. + (g95_conv_section_upper_bound, g95_conv_section_startstride): Use + generic bound functions. + (g95_trans_auto_array_allocation): Don't create a descriptor. + (g95_trans_assumed_size): New function (broken). + (g95_trans_dummy_array_bias): Remove unused var. + * trans-array.h (g95_trans_assumed_size): Declare. + * trans-decl.c (create_index_var): New fuction. + (g95_build_qualified_array): New function. + (g95_get_symbol_decl): Use it. + (g95_trans_deferred_vars): Handle assumed shape seperately. + * trans-types.c (get_element_type): Handle heap allocated arrays. + (g95_is_nodesc_array): Include non-const size arrays. + (g95_get_nodesc_array_type): Ditto. + +2003-02-23 Paul Brook + + * trans-array.c (g95_array_init_size): Should use stride, not size of + last dimension. + +2003-02-18 Paul Brook + + * trans-expr.c (g95_trans_arrayfunc_assign): Nove elemental check + after intrinsic function check. + +2003-02-18 Arnaud Desitter + + * io.c (match_io): Fix missing return value and remove useless + assignment. + * match.c (g95_match): Remove useless assignment. + * module.c (parse_string): Remove useless post increment. + * simplify.c (g95_simplify_verify): Remove useless assignment. + +2003-02-15 Paul Brook + + * expr.c (restricted_intrinsic): Handle bad values gracefully. + * g95.h (symbol_attribute): Add referenced member. + (g95_symbol): Add dummy_order member. + (g95_set_sym_referenced): Declare. + * match.c (g95_match_assignment, g95_match_call): Use it + * primary.c (match_actual_arg, g95_match_rvalue, + g95_match_variable): Ditto. + * symbol.c (next_dummy_order): New variable. + (g95_set_sym_referenced): New function. + (check_done): New function. + (g95_add_*): Use it. + * trans-decl.c: Make formatting conform to GCC standards. + (g95_defer_symbol_init): Add dummy variables in the right order. + (g95_get_symbol_decl): Only accept referenced variables. + (g95_create_module_variable): Module variables are always required. + (generatr_local_decls): New function. + (generate_local_vars): New function. + (g95_generate_function_code): Use it. + +2003-02-13 Paul Brook + + * trans-decl.c (g95_conv_struct_cons): Remove. + (g95_get_symbol_decl): Use g95_conv_expr for structure initializers. + * trans-expr.c (g95_conv_structure): New function. + (g95_conv_expr): Use it. + +2003-02-09 Paul Brook + + * trans-array.c (g95_array_init_size): Don't evaluate the linit + expressions multiple times. + (g95_trans_auto_arry_allocation): Use pointer not tmp. + +2003-02-08 Paul Brook + + * module.c (mio_symtree_ref): Declare as static. + (mio_expr): Remove dead code. + (read_module): Set the symtree link for fixups. + * trans-intrinsic.c (g95_conv_intrinsic_round): Rename... + (build_round_expr): ... to this. + (g95_conv_intrinsic_aint): New function. + (g95_conv_intrinsic_function): Use it. + +2003-02-08 Paul Brook + + * trans-array.c (g95_trans_array_constructor_value): Use the acutal + offset after modificaton, not the increment expression. + * dependency.c: Kill excess whitespace. + +2003-02-07 Sanjiv Gupta + + * dependency.h: Remove some function declarations. + * dependency.c (get_no_of_elements): Change this function not to + return int. + * other: Add comments for all modified functions. + +2003-02-06 Paul Brook + + * g95spec.c (lang_specific_functions): Fix initializer warning. + * dump-parse-tree.c (g95_show_expr): Use typespec instead of symtree + for structure type names. + * trans-decl.c (g95_cons_structure_cons): New function. + (g95_get_symbol_decl): Use it. + * trans-expr.c (g95_conv_component_ref): Remove duplicate pointer + referencing code. + +2003-02-06 Arnaud Desitter + + * resolve.c (compare_cases): Add const to casts. + +2003-01-30 Arnaud Desitter + + * g95.h (g95_check_f): Change a1 to f1m. + * intrinsic.c (add_sym_1m, check_specific, + g95_intrinsic_func_interface): Use it. + + * module.c (init_pi_tree): Remove useless cast. + (fp2): Fix argument type. + + * parse.c (parse_select_block): Add comment. + +2003-02-05 Toon Moene + + * lang-options.h: Fix warning involving C90 concatenated + strings. + +2003-02-06 Steven Bosscher + Arnaud Desitter + + * io.c (format_asterisk): Complete initializer to kill warning. + * arith.c (DEF_G95_INTEGER_KIND, DEF_G95_LOGICAL_KIND, + DEF_G95_REAL_KIND, MPZ_NULL, MPF_NULL): New #defines. + (g95_integer_kinds, g95_logical_kinds, g95_real_kinds): Use the + new defines to complete initializers. Kills all warnings. + + * Make-lang.in: Comment cleanup. + +2003-02-05 Paul Brook + + * array.c (g95_free_constructor): Handle NULL expressions. + * resolve.c (resolve_structure_cons): Ditto. + * decl.c (g95_match_null): New Function. + (variable_decl): Use it. + * module.c (mio_expr): Don't bother saving symtree for EXPR_STRUCTURE. + * primary.c (g95_match_runtime): Don't use symtree for EXPR_STRUCTURE. + * trans-types.c (g95_set_decl_attributes): Remove empty function. + +2003-02-05 Paul Brook + + * trans.h (build1_v): New macro. + (build_v): Remove pointless and incorrect prototype. + * various: Use build1_v for GOTO_EXPR and LABEL_EXPRs. + * f95-lang.c (g95_init_builtin_decls): DEF_BUILTIN takes 10 args. + +2003-02-01 Steven Bosscher + + * Make-lang.in (F95_OBJS): Remove one more dead file. + +2003-02-01 Paul Brook + + * lang-specs.h: Don't pass -ffixed-form to the linker. + * trans-decl.c (g95_generate_function_code): Clear saved decl chain. + +2003-02-01 Paul Brook + + * Make-lang.in (F95_OBJS): Remove dead files. + * trans-array.c (g95_array_init_size): Do the right thing when + ubound=NULL. + * trans-decl.c (g95_generate_function_code): Initialize deffered + symbol list before translating contained subroutines. + * trans-expr.c (g95_conv_expr, g95_conv_expr_reference): Substitute + scalar invariant values here... + (g95_conv_variable, g95_conv_function_call): ... instead of here ... + * trans-intrinsic.c (g95_conv_intrinsic_function_args): .. and here. + +2003-01-29 Paul Brook + + * trans-array.c (g95_add_loop_code): Put pre code in the right block. + (g95_walk_elemental_function_args): Reverse chains before adding. + (g95_reverse_ss): Move about a bit. + * trans-expr.c (g95_conv_function_call): Handle scalar intrinsic + function arguments. + +2003-01-28 Paul Brook + + * intrinsic.c (resolve_intrinsic): Use correct union member. + * trans-array.c (g95_trans_dummy_array_bias): Don't touch absent + parameters. + * trans-decl.c (g95_get_symbol_decl): Don't translate initializers for + use associated variables. + * trans-intrinsic.c (g95_conv_intrinsic_present): Move body ... + * trans-expr.c (g95_conv_expr_present): ... to here. + * trans.h: Declare it. + * trans-types.c (g95_sym_type): Assume subroutine if not specified. + +2003-01-28 Arnaud Desitter + + * array.c (expand_iterator): Suppress useless assignment. + * decl.c (match_char_spec): Ditto. + * io.c (match_io_iterator): Ditto. + * primary.c (match_real_constant): Ditto. + * interface.c (fold_unary, g95_free_interface, g95_extend_expr): + Ditto. Also, use g95_intrinsic_op not int for intrinsic operators. + * matchexp.c (match_add_operand, match_level_5): Likewise. + * module.c (parse_atom, find_enum): Likewise. + * resolve.c: move #include + (resolve_select): Fix serious typo. + +2003-01-28 Steven Bosscher + + * Make-lang.in: Don't build with broken tree-ssa-pre. + +2003-01-28 Steven Bosscher + + * resolve.c (resolve_index): Add a TODO. + * symbol.c: Remove useless "#include ". + +2003-01-27 Paul Brook + + * check.c (check_rest): Allow different type kinds as an extension. + * g95.h (g95_resolve_f): Add f1m. + * intrinsic.c (add_sym_1m, resolve_intrinsic): Use it. + * intrinsic.h: Chenge prototypes for MIN and MAX. + * iresolve.c (g95_resolve_minmax): New function. + (g95_resolve_min, g95_resolve_max): Use it. + * trans-intrinsic.c (g95_trans_intrinsic_minmax): Only evaluate + arguments once. + (g95_conv_intrinsic_present): Fix logic. + +2003-01-27 Steven Bossche + + * g95.h (g95_case): Don't be a tree, be a double linked list. + * match.c (match_case_selector): Remove redundant semantics check. + Clean up a few goto's to make it a tiny little bit faster. + * resolve.c (case_tree): Die. + (compare_cases): Accept and compare unbounded cases too. + (check_case_overlap): Don't build a tree. Instead, merge-sort the + whole list of g95_cases passed from resolve_select. + (sane_logical_select): Die. + (check_case_expr): Return FAILURE if a CASE label is of the wrong + type kind. + (resolve_select): Fixup case expression for computed GOTOs, put it + in expr, not expr2, for easier handing in the parse tree dumper and + the code generator. Rewrite the rest of the function: Kill + unreachable case labels and unreachable case blocks. + * dump-parse-tree.c (g95_show_code_node): Always dump expr for + an EXEC_SELECT, not case2 anymore. + * trans-const.c (g95_conv_constant_to_tree): New function. + (g95_conv_constant): Use it. + * trans-const.h: Declare prototype for the new function. + * trans-stmt.c (g95_trans_integer_select, g95_trans_logical_select, + g95_trans_character_select): New static functions. + (g95_trans_select): Rewrite. + +2003-01-26 Paul Brook + + * intrinsic.c (add_fnctions): Properly add dreal. + * trans-intrinsic.c (g95_conv_intrinsic_present): New function. + (g95_conv_intrinsic_function): Use it. + * trans-io.c (build_dt): Abort on internal files (unimplemented). + +2003-01-26 Paul Brook + + Widespread changes to the handling of symbols in expressions. These + are now linked via g95_symtree nodes. + * parse.c (g95_fixup_sibling symbols): New function. + (parse_contained): Use it. + * g95.h (symbol_attribute): Add contained. Indicates a symbol is a + contained procedure that has bee correctly fixed up. + (g95_code, g95_expr): Point to a g95_symtree, not a g95_symbol. + +2003-01-24 Paul Brook + + * trans-array.c (g95_walk_expr): Function result attributes are in + sym->result. + * trans-expr.c (g95_conv_function_call, + g95_trans_arrayfunc_assign): Ditto. + * trans-decl.c (g95_get_symbol_for_expr): Set sym->result. + +2003-01-23 Steven Bosscher + + * expr.c (check_restricted): Fix error message. + * symbol.c (free_st_labels): Plug memleak. + +2003-01-22 Steven Bosscher + + * arith.c (reduce_unary, reduce_binary_ac, reduce_binary_ca, + reduce_binary_aa, reduce_binary, eval_intrinsic, + eval_intrinsic_f2): Use typesafe prototypes for eval functions. + * g95.h (g95_check_f, g95_simplify_f, g95_resolve_f): New unions + for typesafe intrinsics helper functions. + (g95_intrinsic_sym): Use them. + * intrinsic.c (do_check, add_sym, add_sym_0, add_sym_1, + add_sym_1s, add_sym_1m, add_sym_2, add_sym_3, add_sym_4, + add_sym_5, add_conv, resolve_intrinsic, do_simplify, + check_specific, g95_intrinsic_func_interface, + g95_intrinsic_sub_interface): Adjust all calls to intrinsics + helper functions. + * trans-decl.c (g95_get_extern_function_decl): Likewise. + * Make-lang.in: Don't disable warnings for strict prototypes + any longer, everything is typesafe now. + +2003-01-22 Steven Bosscher + + * bbt.c (duplicate_node): Make static. + * module.c (module_name): Make static. + * scanner.c (include_dirs): Make static. + +2003-01-20 Steven Bosscher + + Hard coded _gfor_'s should not show up anymore. + * g95.h (PREFIX): New macro. + * iresolve.c (g95_resolve_cpu_time): Use PREFIX, not + hard-coded "_gfor". + (g95_resolve_random_number): Likewise. + * trans-decl.c (g95_build_intrinsic_function_decls): Likewise. + * trans-io.c: Remove 'prefix' macro. Replace all uses with + the new PREFIX macro from g95.h. + +2003-01-20 Steven Bosscher + + The troubles of forking... Andy implemented this just now too. + Let's stick to that and keep the trees close. + * g95.h (g95_st_label): 'format' member is now a g95_expr. + * io.c: Revert previous changes. + (g95_match_format): Match the format string as a character + literal expression. + * match.h (g95_statement_label): Declare external. + * parse.c: Revert previous changes. + * symbol.c (g95_free_st_label): Free a g95_expr instead + if a 'char *'. + * trans-io.c: Revert previous changes. + (build_dt): Use set_string to set the format string. + +2003-01-20 Steven Bosscher + + * io.c (format_string): Make non-static. + (g95_match_format): Remember the format string. + (terminate_io): Add I/O termination for empty I/O lists. + * match.h: Declare external format_string. + * parse.c (check_statement_label): Attack the format string + to a format label for FORMAT statements. + * trans-io.c (g95_add_field): Define prefix macro. Replace + all uses of PREFIX define with a use of this macro. + (build_dt): Implement formatted I/O for format labels. + +2003-01-20 Steven Bosscher + + * lang-options.h: Kill "-std=F". + * options.c: Remove unimplemented "-std=F". Modify + web address. + * misc.c (g95_terminal_width): New function. + * error.c (g95_error_init_1): Use g95_terminal_width. + * g95.h: Add prototype for g95_terminal_width, remove + fmode flag. + +2003-01-19 Steven Bosscher + + * Make-lang.in: Fix typo. + +2003-01-18 Steven Bosscher + + * g95.h (struct g95_case): Remove unused cruft, new member + 'where' to keep track of the locus of the default case. + * match.c (g95_match_case): Add locus to the current case. + (match_case_selector): Likewise. + * parse.c (parse_select_block): Move semantics check for + multiple DEFAULT cases out of here to... + * resolve.c (check_case_overlap): ...here. Return sooner + when possible. + (check_case_expr): Take two g95_cases now, use to sure the + expression kinds are the same. + (resolve_select): Cleanup. + +2003-01-18 Paul Brook + + * trans-io.c: Fix typos in ported IO work (set_fla[tg]). + * trans-decl.c (g95_set_symbol_decl): Handle non-array result + variables. + (g95_get_extern_function_decl): Put decls in the correct context. + +2003-01-18 Steven Bosscher + + * trans-io.c: Port changes from Andy to set ERR flag. + +2003-01-17 Paul Brook + + * trans-array.c: Add various comments. + (g95_ss_terminator): Declare as const. + (g95_walk_expr): Remove first parameter and update all callers. + (g95_walk_op_expr): Initialize scalar SS properly. + * trans-array.h (g95_walk_expr): Update prototype. + * trans-expr.c: Update for new g95_walk_expr. + * trans-intrinsic.c: Ditto. + * trans-io.c: Ditto. + * trans.h: Various comments for SS chains. + +2003-01-17 Paul Brook + + * intrinsic.h (g95_generic_isym_id): Add G95_ISYM_S?_KIND, SPACING + and RRSPACING. + * intrinsic.c (add_functions): Use them. + * trans-intrinsic.c (g95_conv_intrinsic_function): Ditto. + * trans-expr.c (g95_conv_expr_lhs): Abort on impossible error. + +2003-01-17 Steven Bosscher + + Fallout of a small merge conflict: + * intrinsic.c: Un-revert lost patch (G95_ISYM_SCALE). + +2003-01-17 Steven Bosscher + + * initrinsic.c: New add_sym_* functions for strong typing. + (add_conv): Make prototype strict. + * dump-parse-tree.c, dependency.c: Include config.h + * resolve.c, trans-io.c: Fix typos. + +2003-01-17 Steven Bosscher + + * dump-parse-tree.c (g95_show_code_node): Show the + condition for a computed GOTO that was transformed + to a SELECT CASE construct. + * resolve.c (check_case_overlap): Revert previous switch + to treaps, it was too slow and didn't catch all trouble. + (resolve_symbol): Be more flexible about module procedures. + * symbol.c (check_conflict): Point to relevant section in + the standard for dubious conflict. Allow procedure + dummy arguments to be optional again. + * trans-io (add_field): Rename to g95_add_field. Change + all callers. + * trans-stmt (trans_select): Handle unbounded cases for + integer SELECT CASE constructs. Fix/add more comment. + +2003-01-17 Steven Bosscher + + * g95.h: Uses GCC's function attribute macros. + * error.c, module.c, parse.c, g95.h: More function attributes. + +2003-01-16 Steven Bosscher + Forgot a file... + * trans-decl.c (get_label_decl): Use TREE_LINENO instead + of DECL_SOURCE_LINE, and TREE_FILENAME instead of + DECL_SOURCE_FILE. + +2003-01-16 Steven Bosscher + + * f95-lang.c (pushdecl): Use TREE_LINENO instead of + DECL_SOURCE_LINE. + * trans.c (g95_trans_code): Use annotate_all_with_file_line + instead of nowdead wrap_all_with_wfl. + +2003-01-14 Steven Bosscher + + * parse.c (g95_parse_file): In verbose mode, dump the parse tree + before generating code, so we can still see it even if the code + generation phase dies. + +2003-01-14 Steven Bosscher + + * decl.c (build_sym): Split out initialization expression parts... + (add_init_expr_to_sym): ...to here. + (variable_decl): Add the symbol following an attribute list to the + symbol tree before parsing the optional initialization expression + if the symbol is not of a derived type. + * primary.c (g95_match_rvalue): Don't assume a symbol always has + a value if it is a PARAMETER. + +2003-01-14 Steven Bosscher + + * misc.c: Don't #include + * module.c: Ditto. Kill uses of mtrace, muntrace. If there + ever was a glibc bug, then either this was never reported to + glibc people, or it has been fixed for so long that there's + no information you can find about it, anywhere. + +2003-01-14 Steven Bosscher + + Fix warnings: + * module.c (attr_bits, bt_types, array_spec_types): + Switch 'const' and 'static'. + * iresolve.c (g95_resolve_reshape): Make __resolve0 non-'const'. + + GNU'ify source code: + * trans-io.c: Numerous fixes, one fixed warning and a few + TODO markers so that we don't forget about them. + +2003-01-13 Paul Brook + + * intrinsic.c (add_functions): Add G95_ISYM_SCALE. + * intrinsic.h (g95_generic_isym_id): Remove bogus G95_ISYM_ANINIT. + Add G95_ISYM_SCALE. + * trans-intrinsic.c (g95_conv_intrinsic_function): Ditto + * match.c (g95_match_stop): Fix dumb == -> != error. + +2003-01-13 Steven Bosscher + + * dump-parse-tree.c (show_indent): Add line breaks. This + whole dumping process needs cleanups. + * f95-lang.c (g95_mark_addressable): Fix prototype to match + the langhook. Fix 'return's accordingly. + * g95-support.h: Adjust prototype. + * g95.h: Add 'no_backend' member to 'g95_option_t' struct. + * lang-options.h: Add '-fsyntax-only'. + * options.c (g95_init_options): Init 'no_backend'. + (g95_parse_arg): Deal with '-fsyntax-only'. + * parse.c (g95_parse_file): Do not generate code if 'no_backend' + is set. + +2003-01-13 Steven Bosscher + Patch from Arnaud + * resolve.c (resolve_symbol): Assumed shape arrays must be dummy + arguments. Also make sure that if a symbol is marked INTRINSIC, + an intrinsic with the symbol's name actually exists. + (check_conflict): Make EXTERNAL and DIMENSION attributes conflict. + Do not allow PROCEDURES to have the SAVE, POINTER, TARGET, + ALLOCATABLE, RESULT, IN_NAMESPACE, OPTIONAL or FUNCTION attribute. + +2003-01-13 Steven Bosscher + + * resolve.c (resolve_contained_functions): Fix condition, don't + throw internal_error if a child namespace has no name. Apparently + this can be the case? + +2003-01-11 Paul Brook + + Port changes from Andy's tree: + * g95.h (g95_code): Add stop_code. + * match.c (g95_match_stop): Detter syntax checking. + * resolve.c (resolve_generic_f0): Return match type. + (resolve_generic_f): Remove dead/duplicated code. + (resolve_specific_f): Ditto. + * dump-parse-tree.c (g95_show_code_node): Handle new STOP format. + * trans-decl.c (gfor_fndel_stop_*): New fndecl nodes. + * trans-stmt.c (g95_trans_stop): Handle new STOP format. + +2003-01-11 Paul Brook + + * trans-array.c: Various documentation/comment changes. + * trans-stmt.c: Ditto. + + +2003-01-10 Paul Brook + + * options.c/h: Add -fdump-parse-tree as alias of -v. + +2003-01-10 Steven Bosscher + + * dump-parse-tree.c (g95_show_namespace): Fixed another + typo. Sorry, it's Friday... + +2003-01-10 Steven Bosscher + + Spotted by Tobi: + * trans-array.c, trans-array.h, trans.c, trans-const.c, + trans-const.h, trans-decl.c, trans-expr.c, trans.h + trans-intrinsic.c, trans-io.c, trans-stmt.c, trans-stmt.h + trans-types.c: Fix bogus copyright years, add 2003. + * trans-types.h: Give copyright header. + +2003-01-10 Steven Bosscher + + * dump-parse-tree.c (g95_show_namespace): Fixed typo. + * expr.c, options.c, scanner.c: Add some more 'const' markers. + * intrinsic.c: Some constant strings moved to read-only memory. + * io.c (format_asterisk): Move to... + * g95.h: ...here. + +2003-01-10 Steven Bosscher + + * dump-parse-tree.c (g95_show_namespace): Dump implicit + types for ranges instead of per-letter. Indent the + 'CONTAINS' just like everything else. + * resolve.c (resolve_contained_functions): Clarify comment. + Explain non-obvious conditional expression. Improve + diagnostics if tyoe cannot be resolved. + Port semi-fix from Andy's tree: + (was_declared): Move up before first use. + (generic_sym, specific_sym): New functions. Code moved + out if procedure_kind. + (procedure_kind): Simplify using new functions. + (resolve_generic_f): Make sure the functions we find in + a parent namespace is generic. + (resolve_specific_f): Ditto for specific functions. + +2003-01-10 Steven Bosscher + + * trans-stmt.c, trans.c: Fix some code style issues. Add + some more comment (but still not enough!). + +2003-01-10 Steven Bosscher + + * symbol.c (flavors, procedures, intents, acces_types, + access_types, ifsrc_types): Make const. + * misc.c (g95_string2code): Make 'm' param 'const'. + * module.c (find_enum, write_atom, mio_name): Make + 'm' param 'const'. + (attr_bits, bt_types, array_spec_types, array_ref_types, + ref_types, expr_types): Make const. + * g95.h: Adjust external decls. + +2003-01-09 Paul Brook + + * Testsuite: Add a load of new cases. + +2003-01-08 Steven Bosscher + + * Make-file.in: Add dependency on back end header files; + a parallel build should work now. + * f95-lang-c (lang_identifier): Remove bogus comment. + (g95_be_parse_file): Fix prototype. + (g95_init): Make static. + (g95_finish): Make static. + * error.c (g95_syntax_error): Kill. Make define in... + * g95.h (g95_syntax_error): Define. + (g95.options): Make 'source' member 'const'. + * interface.c (g95_match_interface): Explain + hard-to-read condition. + (g95_match_end_interface): Ditto. + * trans_const.c (g95_build_string_const): Make 's' parameter + 'const'. + * trans_const.h: Adjust protoype accordingly. + * trans-decl.c: Include tree-dump.h + (g95_generate_function_code): Build fixes for recent changes + in the tree-ssa branch. + +2003-01-08 Steven Bosscher + + * format.c: Kill, move code from here... + * io.c: ...to here. + * Make-lang.in: Adjust. + * MANIFEST: Ditto. + * match.h: Ditto. + * BUGS: Mention where to submit bugs. Move old content... + * TODO: ...to here. New file. + +2003-01-08 Steven Bosscher + Fix most warnings, and suppress the ones we can't fix for now. + * Make-lang.in: Suppress warnings about bad proto's in g95.h, + these warnings just clutter the screen and there's not much + we can do about them for now anyway. + * check.c, iresolve.c: Mark unused function parameters. + * dump-parse-tree.c (g95_show_array_spec): Punt on AS_UNKNOWN, + they should be resolved before they get here. + * error.c: Remove unused FILE *status_out. + * f95-lang.c (g95_init): Remove bogus cast. + * Many files: Make things 'const' where required. + * g95.h: Fix prototypes for all modified functions above. + (g95_options): Remove 'object' member. + +2003-01-07 Steven Bosscher + + * Make-file.in: Cleanup bogus targets. Add more comment. + * lang-options.h: New option '-w'. + * g95.h: add no_options field to struct g95_options. + * options.c (g95_init_options): Default no_warnings to off. + (g95_parse_arg): Recognise the '-w' switch and its alias, + '-fno-warnings'. + * error.c (g95_warning, g95_warning_now): Don't emit warning if + no_warning option is set. + * iresolve.c (g95_resolve_shape): Fix warning. + +2003-01-07 Steven Bosscher + + * primary.c (g95_next_string_char): Rename next_string_char, and + make static. Adjust callers accordingly. + * resolve.c (resolve_generic_f0): Return try, not match. Adjust + callers accordingly. + * g95.h: Split out all g95_match* functions to... + * match.h: ...here. New file. + * array.c, decl.c, expr.c, format.c, interface.c, io.c, match.c, + matchexp.c, module.c, parse.c, primary.c: Inlcude match.h + +2003-01-07 Steven Bosscher + + * symbol.c (g95_clear_new_implicit, g95_add_new_implicit_range, + g95_merge_new_implicit): New functions. + (g95_match_implicit_none, g95_match_implicit): Move from here... + * match.c (g95_match_implicit_none, g95_match_implicit): ... to here. + Modify to use the new functions in symbol.c. + * g95.h: Add and move prototypes. + +2003-01-06 Steven Bosscher + + * bbt.c (insert): Use a typedef'ed compare_fn prototype for the + node compare function. + (g95_insert_bbt): Likewise. + (g95_insert_bbt_with_overlap): Likewise. + (g95_delete_bbt): Likewise. + (delete_treap): Likewise. Also fix a potential bug when calling it. + * module.c (compare_pointers): Change proto to compare_fn. + (compare_integers): Likewise. + (compare_true_names): Likewise. + (find_true_name): Adjust call to compare_true_names to match proto. + (require_atom, write_atom, mio_name): Fix 'const' warnings. + (init_pi_tree): Make compare a compare_fn instead of (int *). + * resolve.c (compare_cases): Change proto to compare_fn. + * symbol.c (g95_compare_symtree): Change proto to compare_fn, make + it static, and rename to compare_symtree. + (delete_symtree, g95_undo_symbols, g95_new_symtree): Use renamed + function. + * g95.h: Kill g95_compare_symtree prototype. Adjust prototypes + of g95_insert_bbt, g95_insert_bbt_with_overlap, and g95_delete_bbt. + +2003-01-06 Steven Bosscher + * Make-lang.in: Fix spaces/tabs issues from previous patch. + * patch.options: Blow away Paul's checkin mistake :-) + * io.c (terminate_io): Fix memory leak (Arnaud). + +2003-01-06 Steven Bosscher + + * Make-lang.in: Teach about building DVI, info manual. + * g95.texi: New file. + +2003-01-02 Paul Brook + + * trans-array.c (g95_reverse_ss): Make static and don't use. + (g95_conv_ss_descriptor): Don't use g95_loopinfo + (g95_conv_array_parameters): Modify for pointer assignments. + (g95_walk_subexpr): New function. + (g95_walk_expr*): Use it. + * trans-array.h (g95_reverse_ss): Remove prototype. + * trans-expr.c (g95_trans_pointer_assign): Implement. + (Many): Set se.want_pointer before calling g95_conv_array_parameter. + * trans-intrinsic.c: Sync with scalarizer changes. + * trans-io.c: Ditto. + +2002-12-29 Paul Brook + + * trans-array.c: Document calling convention for arrays. + +2002-12-19 Paul Brook + + * trans-intrinsic.c (g95_conv_intrsinsic_function): Remove incorrect + assertion. Remove intrinsic subroutine G95_ISYM_* cases. Always pass + optional parameters for some intrinsics. + (g95_is_intrinsic_libcall): Add G95_ISYM_RESHAPE. + * trans-expr.c (g95_conv_function_call): Pass NULL for absent + optional parameters. + * trans.h (g95_se): Add ignore_optional flag. + +2002-12-15 Paul Brook + + * trans-array.c (g95_conv_array_parameter): Fix partial rank sections. + * trans-decl.c (g95_generate_function_code): Use TDI_original. + +2002-12-14 Paul Brook + + * trans-stmt.c (g95_trans_call): Use resolved symbol name. + +2002-12-12 Paul Brook + + * trans-array.c (g95_trans_array_constructor_subarray): Fully + initialize the scalarizer. + (various): Update to new format of g95_expr->value.constructor. + +2002-12-08 Paul Brook + + * trans-array.c (g95_put_offset_into_var): New function. + (g95_trans_array_constructor_subarray): New function. + (g95_trans_array_constructor_value): Use it. + (g95_array_cons_size): Don't abort() on array components. + +2002-12-08 Paul Brook + + * Make-lang.in (F95_ADDITIONAL_OBJS): Remove tree-dchain.o. + * support.c: Update #includes. + (statement_code_p, c_size_in_bytes, s_size_type_node): Remove. + * trans-array.c: Update #includes. + * trans.c: Ditto. + * trans-const.c: Ditto. + * trans-io.c: Ditto. + * trans-types.c: Ditto. + (g95_init_types): Set size_type_node. + * trans-decl.c: Update #includes. + (gfor_fndecl_adjust{l,r}): Declare and initialize. + * trans-stmt.c: Update #includes. + (g95_trans_do_while): Generate LABEL_EXPR, not GOTO_EXPR. + (g95_trans_select): Fix check for unbounded ranges. + * trans-expr.c: Update #includes. + (g95_conv_string_tmp): New function. + (g95_conv_concat_op): Use it. + * trans.h (g95_conv_string_tmp, gfor_fndecl_adjust{l,r}): Declare. + * Trans-intrisic.c: Update #includes. + (g95_conv_intrinsic_strcmp): New function. + (g95_conv_intrinsic_adjust): Ditto. + (g95_conv_intrinsic_function: Use them. + +2002-11-30 Paul Brook + + * trans-array.c (g95_walk_function_expr): Handle non-array return by + reference. + * trans-dec.c (g95_build_function_decl): Handle character return + parammeters. + (g95_get_fake_result_decl): Ditto. + (g95_trans_deferred_vars): Ditto. + * trans-expr.c (g95_conv_function_call): Ditto. + (g95_trans_arrayfunc_assign) Limit to array valued functions. + * trans-intrinsic.c (g95_conv_intrinsic_char): New function. + (g95_conv_intrinsic_function): Use it. + * trans-types.c (g95_sym_type): Handle functions returning strings. + (g95_return_by_reference): Ditto. + (g95_get_function_type): Ditto. + +2002-11-18 Paul Brook + + * trans-stmt.c (g95_trans_if): Fix IF statements when the condition + requires a temporary. + (g95_trans_select): Handle computed gotos. + * trans-types.c (g95_build_array_type): Warn about non-functional + assumed shape arrays. + * trans-expr.c (g95_trans_scalar_assign): Correctly handle post + blocks. + * trans-intrinsic.c (g95_conv_intrinsic_round): New function. + (g95_conv_intrinsic_int): New function. + (g95_conv_intrinsic_mod): New function. + (g95_conv_intrinsic_ichar): New function. + (g95_conv_intrinsic_function): Use them. + (g95_conv_intrinsic_dim): Use g95_evaluate_now. + +2002-11-17 Toon Moene + + * trans-types.c (g95_build_array_type): Assumed + sized arrays can have rank > 1. + * trans.c (g95_trans_code): Remove erroneous + warning about CONTINUE. + * trans-expr.c (g95_conv_variable): Remove + erroneous assert. + +2002-11-15 Paul Brook + + * trans-array.c (g95_conv_array_parameter): Check for NULL stride. + +2002-10-31 Paul Brook + + * f95-tree.c: Remove tree copying stuff that's now in gimple.c + * trans-expr.c (g95_conv_component_ref): Handle character string + components. + (g95_conv_string_parameter): Ditto. + * trans-types.c (g95_get_derived_type): Add length decl to caracter + string components. + +2002-10-10 Paul Brook + + * trans-decl.c (gfor_fndecl_size?): Declare and initialize. + * trans-expr.c (g95_conv_function_call): Remove unreliable return value + check. + * trans-intrinsic.c (g95_conv_intrinsic_size): New function. + (g95_conv_intrinsic_function): Handle size and shape intrinsics. + (g95_is_intrinsic_libcall): Add G95_ISYM_SHAPE. + * trans-types.c (pvoid_type_node): Declare and initialize. + * trans-array.c: Fix typo COMPONENT_REF->REF_COMPONENT + (g95_array_allocate): Fix when base==data. + (g95_conv_array_parameter): Correctly handle reduced rank sections. + * trans-io.c (g95_trans_write): Correctly handle string modifiers. + +2002-10-09 Paul Brook + + * (g95_conv_expr_reference): Handle character strings correctly. + +2002-10-07 Paul Brook + + (g95_expand_decl): Rename from f95_expand_decl_stmt and use as + langhook. + * trans-array.c (g95_build_array_initializer): Remove. + (g95_conv_array_initializer): New Function. + (g95_trans_auto_arry_allocation): Cleanup. + (g95_trans_init_character_array): Remove. + * g95spec.c: Link in libgforbegin. + * trans.c (g95_generate_code): Rename main function to MAIN__. + (g95_create_var): New function. + (g95_create_var_np): New function. + (g95_evaluate_now): New function. + (g95_start_block): New function. + (g95_finish_block): New function. + (g95_add_expr_to_block): New function. + (g95_add_block_to_block): New function. + * trans-expr.c (g95_conv_componen_ref): New function. + * Make-lang.in (F95_ADDITIONAL_OBJS): Add gimplify.o. + (F95_OBJS): Add dependency.o. + * f95-lang.c (g95_is_simple_stmt): Remove. + * f95-tree.c (mark_not_simple): New function. + (unshare_all_trees): New function. + (create_tmp_var, create_tmp_alias_var): Remove. + * support.c (declare_tmp_vars, tree_last_decl): Remove. + * trans*: Convert to new IR using GENERIC trees. Don't bother about + SIMPLE/GIMPLE rules, this is now done by Lang-independant code. + +2002-10-01 Paul Brook + + * trans-array.c: Add support for descriptorless arrays. + (g95_conv_array_data): New function. + (g95_conv_array_base): New function. + * trans-array.h: Declare these here. + * trans-decl.c(g95_create_mopdule_variable): Perform variable + initialization and creation here. + (g95_create_module_vars): Instead of here. + * trans.h (G95_TYPE_ARRAY_*: Rename from G95_TYPE_DESCRIPTOR_*. + * trans-intrinsic.c: Ditto. + * trans-types.c (g95_is_nodesc_array): New function. + (g95_get_nodesc_array_type): New function. + (g95_sym_type, g95_get_derived_type): Use them. + * trans-const.c (g95_conv_mpf_to_tree): Remove workaround. + +2002-09-28 Paul Brook + + * trans-const.c (g95_conv_mpf_to_tree): Work around backend bug. + * trans-intrinsic.c (g95_conv_intrinsic_abs): Correctly detect complex + parameters. + +2002-09-24 Paul Brook + + * f95-lang.c (listify): Remove declaration. + (expand_function_body): Use optimize >=1 instead of flag_tree_saa. + (listify) + * f95-tree.c (get_name): New function. + * trans.c (module_namespace): Remove. + * trans-decl.c: Use g95_chainon_list rather than chainon(listify()). + * trans-types.c: Ditto. + +2002-09-19 Paul Brook + + * trans-array.c (g95_get_array_cons_size): New Function. + (g95_con_ss_startstride): Handle Array constructors. + (g95_conv_loop_setup): Ditto. + (g95_conv_array_parameter): Ditto. + * tras-decl.c (g95_finish_var_decl): Make initializes variables + static. + +2002-09-19 Paul Brook + + * trans.c (g95_simple_fold_tmp): Detect variables inside + NON_LVALUE_EXPR. + * trans-stmt.c (g95_trans_arithmetic_if): Implement this. + +2002-09-18 Steven Bosscher + + * Make-lang.in (F95_ADDITIONAL_OBJS): Add tree-ssa-dce.o + +2002-09-14 Paul Brook + + * trans.c (g95_create_module_variable): Move to trans-decl.c. + * trans-const.c (g95_conv_string_init): New Function. + * trans-const.h: Declare it. + * trans-decl.c (g95_get_symbol_decl): Handle initializers for static + variables. Don't bail on intrinsic symbols. + (get_extern_function_decl): Handle specific intrinsic functions. + * trans-types.c (g95_sym_type): Dummy functions don't return + reference types. + * trans-array.c (g95_build_array_initializer): New Function. + (g95_trans_auto_array_allocation): Build initializer for static decls. + Don't use mpz_addmul, it's GMP4 only. + +2002-09-12 Paul Brook + + * trans-decl.c (g95_generate_code): Fix thinko with return variable. + (g95_get_extern_function_decl, g95_build_function_decl): Mangle + assembler names for module procedures. + +2002-09-11 Tobias Schlueter + + * trans-array.c,h trans-expr.c, trans-stmt.c: Correct spelling of + dependency/ + +2002-09-10 Paul Brook + + * trans-array.c: Change format of G95_SS_TEMP strictures. + (g95_check_fncall_dependancy): New function. + (trans_dummy_array_bias): stride[n], not stride[n-1]. for calculating + offsets. + * trans-decl.c (g95_get_symbol_decl): move assertion after handling of + result variables. + (g95_build_function_decl): Don't assume result arrays are packed. + (g95_trans-deferred-vars): Handle array result variables. + (g95_generate_fuction_code): Clear saved_function_decls. + * trans-expr.c (g95_conv_fnction_call): Handle direct array return by + reference. + (g95_trans_arrayfunc_assign): New function. + (g95_trans_assignment): Use it. + * trans.h (g95_ss): Add temp struct for G95_SS_TEMP. + (g95_se): Add direct_byref. + * trans-types.c: Use sym->result rather than sym where appropriate. + * trans-intrinsic.c (g95_conv_intrinsic_funcall): New function. + Update other functions to use this. + (g95_is_intrinsic_libcall): New function. + (g95_conv_intrinsic_function): Add MATMUL and PRODUCT intrinsics. + (g95_walk_intrinsic_function): Ditto. + +2002-09-08 Paul Brook + + * trans-types.c: Change rank field to dtype field in array descriptor. + * trans-array.c: Implement filling of dtype array descriptor field. + * trans-intrinsic.c: Fix broken LEN intrinsic. + +2002-09-07 Paul Brook + + * trans-intrinsic.c: Remove outdated todo intrinsic list. + (g95_get_symbol_for_expr): Remove hack for fortran based intrinsics. + (g95_walk_intrinsic_function): Add MINLOC and MAXLOC. + +2002-09-06 Paul Brook + + * Make-lang.in (F95_ADDITIONAL_OBJS): Add tree_alias_comon.o. + (gt-f95-trans-types.h): Add dependancy information. + * config-lang.in (gtfiles): Add trans-types.c + * f95-lang.c (g95_be_parse_file): Pass error and warning counts + back to top-level code. + * trans-array.c, trans-types.c: Change format of array descriptor. + (g95_conv_descriptor_dimension): New function. + * trans-types.h (g95_conv_descriptor_rank): define. + * trans-intrinsic.c: Implement PRODUCT, COUNT. MINLOC and MAXLOC + intrinsics. + +2002-09-02 Steven Bosscher + + * trans-array.c, trans-types.c: Add rank information to descriptor. + +2002-09-06 Tobias Schlueter + + * trans-stmt.c (g95_trans_allocate): Fix when ref==NULL. + +2002-09-04 Paul Brook + + * f95-lang.c (g95_create_decls): New function. + (g95_init): Move initialization of external decls to above, and call + from g95_be_parse_file. + * trans.c (g95_finish_stmt): Don't amputate the decl chain. + * trans-types.c (g95_init_types): Always name integer and char types. + (g95_get_array_type_bounds): TYPE_NAME may be a TYPE_DECL. + +2002-09-02 Steven Bosscher + + * Make-lang.in: Add options.c to F95_PARSER_OBJS + +2002-09-02 Paul Brook + + * g95_generate_code: Clear the attr for __fortran_main. + * trans-types.c (g95_finish_type): New function. + * g95_init_io_state_type: Use g95_finish_type. + * g95_conv_intrinsic_anyall: Fix thinko in result initialization. + +2002-09-01 Paul Brook + + * README.backend: Warn about the dangers of extra config.h files. + Remove obsolete libgfor stuff. + * config-lang.in: Add target-libgfor dependancy. + * g95_conv_mpf_to_tree: Use & free allocated buffer p rather than buff. + +2002-09-01 Toon Moene + + * g95_conv_mpz_to_tree: Free storage pointed to by q, + not by buff. + +2002-08-30 Paul Brook + + * trans-intrinsic.c (g95_conv_intrinsic_function, + g95_walk_intrinsic_function): Added ANY and ALL. + (g95_conv_intrinsic_anyall): New function. + * iresolve.c (g95_resolve_any, g95_resolve_all): Include rank in + mangled name + diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in new file mode 100644 index 00000000000..a38834b4713 --- /dev/null +++ b/gcc/fortran/Make-lang.in @@ -0,0 +1,300 @@ +# -*- makefile -*- +# Top level makefile fragment for GNU gfortran, the GNU Fortran 95 compiler. +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. +# Contributed by Paul Brook + +#This file is part of G95. + +#G95 is free software; you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation; either version 2, or (at your option) +#any later version. + +#G95 is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with G95; see the file COPYING. If not, write to +#the Free Software Foundation, 59 Temple Place - Suite 330, +#Boston, MA 02111-1307, USA. + +# This file provides the language dependent support in the main Makefile. +# Each language makefile fragment must provide the following targets: +# +# foo.all.build, foo.all.cross, foo.start.encap, foo.rest.encap, +# foo.info, foo.dvi, +# foo.install-normal, foo.install-common, foo.install-info, foo.install-man, +# foo.uninstall, foo.distdir, +# foo.mostlyclean, foo.clean, foo.distclean, foo.extraclean, +# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4 +# +# where `foo' is the name of the language. +# +# It should also provide rules for: +# +# - making any compiler driver (eg: gfortran) +# - the compiler proper (eg: f951) +# - define the names for selecting the language in LANGUAGES. +# $(srcdir) must be set to the gcc/ source directory (*not* gcc/fortran/). + +# Actual name to use when installing a native compiler. +GFORTRAN_INSTALL_NAME = `echo gfortran|sed '$(program_transform_name)'` + +# Actual name to use when installing a cross-compiler. +GFORTRAN_CROSS_NAME = `echo gfortran|sed '$(program_transform_cross_name)'` + +#^L + +# This is in addition to the warning flags defined by default. +# You can use it to enable/disable warnings globally or for specific +# files, e.g. +# fortran-warn = -Wno-strict-prototypes +# fortran/arith.o-warn = -Wno-error +# +# We don't need these cheats, everything builds fine with all warnings +# enabled and -Werror. + +# These are the groups of object files we have. The F95_PARSER_OBJS are +# all the front end files, the F95_OBJS are the files for the translation +# from the parse tree to GENERIC, and F95_ADDITIONAL_OBJS are the files +# from the middle end we depend on. + +F95_PARSER_OBJS = fortran/arith.o fortran/array.o fortran/bbt.o fortran/check.o\ + fortran/decl.o fortran/error.o fortran/expr.o fortran/interface.o \ + fortran/intrinsic.o fortran/io.o fortran/iresolve.o fortran/match.o \ + fortran/matchexp.o fortran/misc.o fortran/module.o fortran/parse.o \ + fortran/primary.o fortran/options.o fortran/resolve.o \ + fortran/scanner.o fortran/simplify.o fortran/st.o fortran/symbol.o \ + fortran/dump-parse-tree.o + +F95_OBJS = $(F95_PARSER_OBJS) \ + fortran/f95-lang.o fortran/convert.o fortran/trans.o fortran/trans-decl.o \ + fortran/trans-types.o fortran/trans-const.o fortran/trans-expr.o \ + fortran/trans-stmt.o fortran/trans-io.o fortran/trans-array.o \ + fortran/trans-intrinsic.o fortran/dependency.o fortran/trans-common.o \ + fortran/data.o + +# FIXME: +# We rely on c-semantics to expand from GIMPLE to RTL. +# This should go away once a real GIMPLE expander is available. +F95_ADDITIONAL_OBJS = \ + tree-cfg.o tree-dfa.o tree-optimize.o tree-simple.o \ + tree-ssa.o tree-ssa-ccp.o tree-ssa-dce.o \ + tree-alias-common.o tree-alias-type.o gimplify.o stor-layout.o + +# GFORTRAN uses GMP for its internal arithmetics. +F95_LIBS = $(GMPLIBS) $(LIBS) + +# +# Define the names for selecting gfortran in LANGUAGES. +F95 f95: f951$(exeext) + +# Tell GNU make to ignore files by these names if they exist. +.PHONY: F95 f95 + +gfortranspec.o: $(srcdir)/fortran/gfortranspec.c $(SYSTEM_H) $(TM_H) $(GCC_H) $(CONFIG_H) + (SHLIB_LINK='$(SHLIB_LINK)' \ + SHLIB_MULTILIB='$(SHLIB_MULTILIB)'; \ + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(DRIVER_DEFINES) \ + $(INCLUDES) $(srcdir)/fortran/gfortranspec.c) + +# Create the compiler driver gfortran. +GFORTRAN_D_OBJS = gcc.o gfortranspec.o version.o prefix.o intl.o +gfortran$(exeext): $(GFORTRAN_D_OBJS) $(EXTRA_GCC_OBJS) $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \ + $(GFORTRAN_D_OBJS) $(EXTRA_GCC_OBJS) $(LIBS) + +# Create a version of the gfortran driver which calls the cross-compiler. +gfortran-cross$(exeext): gfortran$(exeext) + -rm -f gfortran-cross$(exeext) + cp gfortran$(exeext) gfortran-cross$(exeext) + +# The compiler itself is called f951. +f951$(exeext): $(F95_OBJS) $(F95_ADDITIONAL_OBJS) \ + $(BACKEND) $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \ + $(F95_OBJS) $(F95_ADDITIONAL_OBJS) $(BACKEND) $(F95_LIBS) + +gt-fortran-f95-lang.h gtype-fortran.h : s-gtype; @true +gt-fortran-trans-decl.h gt-fortran-trans.h : s-gtype; @true +gt-fortran-trans-io.h gt-fortran-trans-types.h: s-gtype; @true +gt-fortran-trans-intrinsic.h : s-gtype; @true + +# +# Build hooks: + +f95.all.build: gfortran$(exeext) +f95.all.cross: gfortran-cross$(exeext) + +f95.start.encap: gfortran$(exeext) +f95.rest.encap: + +f95.srcinfo: fortran/gfortran.info + -cp -p $^ $(srcdir)/fortran + +f95.tags: force + cd $(srcdir)/fortran; etags -o TAGS.sub *.c *.h; \ + etags --include TAGS.sub --include ../TAGS.sub + +f95.info: fortran/gfortran.info +f95.dvi: fortran/gfortran.dvi +f95.generated-manpages: + +f95.man: +f95.srcman: + +check-f95 : check-gfortran +lang_checks += check-gfortran + +# GFORTRAN documentation. +GFORTRAN_TEXI = \ + $(srcdir)/fortran/gfortran.texi \ + $(srcdir)/fortran/invoke.texi \ + $(srcdir)/doc/include/fdl.texi \ + $(srcdir)/doc/include/gpl.texi \ + $(srcdir)/doc/include/funding.texi \ + $(srcdir)/doc/include/gcc-common.texi + +fortran/gfortran.info: $(GFORTRAN_TEXI) + if [ x$(BUILD_INFO) = xinfo ]; then \ + rm -f fortran/gfortran.info-*; \ + $(MAKEINFO) -I$(srcdir)/doc/include -I$(srcdir)/fortran \ + -o fortran/gfortran.info $(srcdir)/fortran/gfortran.texi; \ + else true; fi + +fortran/gfortran.dvi: $(GFORTRAN_TEXI) + s=`cd $(srcdir); ${PWD}`; export s; \ + cd fortran && $(TEXI2DVI) -I $$s/doc/include -I $$s/fortran \ + $$s/fortran/gfortran.texi + +# +# Install hooks: +# f951 is installed elsewhere as part of $(COMPILERS). + +# Nothing to do here. +f95.install-normal: + +# Install the driver program as $(target)-gfortran +# and also as either gfortran (if native) or $(tooldir)/bin/gfortran. +f95.install-common: installdirs + -if [ -f f951$(exeext) ] ; then \ + if [ -f gfortran-cross$(exeext) ] ; then \ + rm -f $(DESTDIR)$(bindir)/$(GFORTRAN_CROSS_NAME)$(exeext); \ + $(INSTALL_PROGRAM) gfortran-cross$(exeext) $(DESTDIR)$(bindir)/$(GFORTRAN_CROSS_NAME)$(exeext); \ + chmod a+x $(DESTDIR)$(bindir)/$(GFORTRAN_CROSS_NAME)$(exeext); \ + if [ -d $(DESTDIR)$(gcc_tooldir)/bin/. ] ; then \ + rm -f $(DESTDIR)$(gcc_tooldir)/bin/gfortran$(exeext); \ + $(INSTALL_PROGRAM) gfortran-cross$(exeext) $(DESTDIR)$(gcc_tooldir)/bin/gfortran$(exeext); \ + else true; fi; \ + else \ + rm -f $(DESTDIR)$(bindir)/$(GFORTRAN_INSTALL_NAME)$(exeext); \ + $(INSTALL_PROGRAM) gfortran$(exeext) $(DESTDIR)$(bindir)/$(GFORTRAN_INSTALL_NAME)$(exeext); \ + chmod a+x $(DESTDIR)$(bindir)/$(GFORTRAN_INSTALL_NAME)$(exeext); \ + rm -f $(DESTDIR)$(bindir)/$(GFORTRAN_TARGET_INSTALL_NAME)$(exeext); \ + $(LN) $(DESTDIR)$(bindir)/$(GFORTRAN_INSTALL_NAME)$(exeext) $(DESTDIR)$(bindir)/$(GFORTRAN_TARGET_INSTALL_NAME)$(exeext); \ + fi ; \ + fi + +# Install the info documentation in $(infodir). +# Taken from G77 (but then, what is not...) +f95.install-info: f95.info installdirs + if [ -f fortran/gfortran.info ] ; then \ + rm -f $(DESTDIR)$(infodir)/gfortran.info*; \ + for f in fortran/gfortran.info*; do \ + realfile=`echo $$f | sed -e 's|.*/\([^/]*\)$$|\1|'`; \ + $(INSTALL_DATA) $$f $(DESTDIR)$(infodir)/$$realfile; \ + done; \ + chmod a-x $(DESTDIR)$(infodir)/gfortran.info*; \ + else true; fi + @if [ -f fortran/gfortran.info ] ; then \ + if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/gfortran.info"; \ + install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/gfortran.info || : ; \ + else : ; fi; \ + else : ; fi + +f95.install-man: installdirs +#TODO: write the gfortran man pages + +f95.uninstall: + if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + echo " install-info --delete --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/gfortran.info"; \ + install-info --delete --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/gfortran.info || : ; \ + else : ; fi; \ + rm -rf $(DESTDIR)$(bindir)/$(GFORTRAN_INSTALL_NAME)$(exeext); \ + rm -rf $(DESTDIR)$(bindir)/$(GFORTRAN_CROSS_NAME)$(exeext); \ + rm -rf $(DESTDIR)$(infodir)/gfortran.info* + +# +# Clean hooks: +# A lot of the ancillary files are deleted by the main makefile. +# We just have to delete files specific to us. + +f95.mostlyclean: + -rm -f f951$(exeext) + -rm -f fortran/*.o + +f95.clean: +f95.distclean: + -rm -f fortran/config.status fortran/Makefile + +f95.extraclean: +f95.maintainer-clean: + -rm -f fortran/gfortran.info* fortran/gfortran.*aux + +# +# Stage hooks: +# The toplevel makefile has already created stage?/fortran at this point. + +f95.stage1: stage1-start + -mv fortran/*$(objext) stage1/fortran +f95.stage2: stage2-start + -mv fortran/*$(objext) stage2/fortran +f95.stage3: stage3-start + -mv fortran/*$(objext) stage3/fortran +f95.stage4: stage4-start + -mv fortran/*$(objext) stage4/fortran +f95.stageprofile: stageprofile-start + -mv fortran/*$(objext) stageprofile/fortran +f95.stagefeedback: stageprofile-start + -mv fortran/*$(objext) stagefeedback/fortran + +# +# .o: .h dependencies. + +# Everything depends on gfortran.h, but only a few files depend on +# the other headers. So at some point we'll have to split out +# which objects depend on what. FIXME +# TODO: Add dependencies on the backend/tree header files + +$(F95_PARSER_OBJS): fortran/gfortran.h fortran/intrinsic.h fortran/match.h \ + fortran/parse.h \ + $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TM_P_H) coretypes.h \ + $(RTL_H) $(TREE_H) $(TREE_DUMP_H) $(GGC_H) $(EXPR_H) \ + flags.h output.h diagnostic.h errors.h function.h + +GFORTRAN_TRANS_DEPS = fortran/gfortran.h fortran/intrinsic.h fortran/trans-array.h \ + fortran/trans-const.h fortran/trans-const.h fortran/trans.h \ + fortran/trans-stmt.h fortran/trans-types.h \ + $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TM_H) coretypes.h + +fortran/f95-lang.o: $(GFORTRAN_TRANS_DEPS) fortran/mathbuiltins.def \ + gt-fortran-f95-lang.h gtype-fortran.h cgraph.h +fortran/convert.o: $(GFORTRAN_TRANS_DEPS) +fortran/trans.o: $(GFORTRAN_TRANS_DEPS) +fortran/trans-decl.o: $(GFORTRAN_TRANS_DEPS) gt-fortran-trans-decl.h cgraph.h +fortran/trans-types.o: $(GFORTRAN_TRANS_DEPS) gt-fortran-trans-types.h +fortran/trans-const.o: $(GFORTRAN_TRANS_DEPS) +fortran/trans-expr.o: $(GFORTRAN_TRANS_DEPS) +fortran/trans-stmt.o: $(GFORTRAN_TRANS_DEPS) +fortran/trans-io.o: $(GFORTRAN_TRANS_DEPS) gt-fortran-trans-io.h +fortran/trans-array.o: $(GFORTRAN_TRANS_DEPS) +fortran/trans-intrinsic.o: $(GFORTRAN_TRANS_DEPS) fortran/mathbuiltins.def \ + gt-fortran-trans-intrinsic.h +fortran/dependency.o: fortran/gfortran.h fortran/dependency.h +fortran/trans-common.o: $(GFORTRAN_TRANS_DEPS) fortran/gfortran.h +fortran/data.c: $(GFORTRAN_TRANS_DEPS) + diff --git a/gcc/fortran/NEWS b/gcc/fortran/NEWS new file mode 100644 index 00000000000..ce466feef81 --- /dev/null +++ b/gcc/fortran/NEWS @@ -0,0 +1,7 @@ +2003-01-06 +This project is a fork of the original G95 project. The fork has the +support of the GCC community. We still persue mostly the same goals +as the original project, but we hope we can attrack more developers +through better cooperation and communication, and we target quicker +inclusion in GCC. + diff --git a/gcc/fortran/README b/gcc/fortran/README new file mode 100644 index 00000000000..fc28c995200 --- /dev/null +++ b/gcc/fortran/README @@ -0,0 +1,18 @@ +The goal of the gcc-g95 project is to create a Free (as +in speech) Fortran 95 compiler. The code has been donated +to the Free Software Foundation for inclusion in GCC, thE +GNU Compiler Collection. + +WARNING: + +G95 is still under development. Perusing the g77 source, we estimate +that about 200,000 lines of code will be necessary to fully implement +g95. Currently, G95 is about 70,000 lines long, making it about +version 0.3. + +The current g95 can generate code for most legal Fortran 77 programs, +and we're getting close to being able to compile most Fortran 95 +programs as well. The generated code may still be quite poor, however. +Part of this is a back-end issue, since we're using the Work-In-Progress +tree-ssa infrastructure. + diff --git a/gcc/fortran/TODO b/gcc/fortran/TODO new file mode 100644 index 00000000000..023ac34b0a0 --- /dev/null +++ b/gcc/fortran/TODO @@ -0,0 +1,56 @@ +TODO + +Parser fixes: +------------ + +In a constant format string given to a data transfer statement, the +locus of any problems in the string isn't guaranteed to come out +right, because there is not a 1:1 correspondence between source +characters and characters in the string. This scheme totally doesn't +work for format strings that are longer than a physical line. + +Fix IMPLICIT to allow forward references of derived types. + +Array issues in expressions and intrinsics. + +Resolve scoping issues. Create symbols in correct namespaces. + +Finish resolution phase. + +Finish compiler side of intrinsic functions. + +Allow init exprs to be numbers raised to integer powers (negative too). + +See about making emacs-parsable error messages. + + +Biggies: +-------- + +Interface to code generator. + +Complete runtime library. + + +Known bugs: +----------- + +Failure to set the expr_locus field in g95_expr structures. + + +And for the really pedantic +--------------------------- + +Fix INCLUDE such that it only appears on a single line. The current +code allows things like: + + 0I + 1NCLUDE "filename" + +or its free form equivalent: + +I& +NCLUDE "filename" + +This is explicitly forbidden by the F95 standard (ref. section 3.4). + diff --git a/gcc/fortran/arith.c b/gcc/fortran/arith.c new file mode 100644 index 00000000000..bd03fba4046 --- /dev/null +++ b/gcc/fortran/arith.c @@ -0,0 +1,2763 @@ +/* Compiler arithmetic + Copyright (C) 2000, 2001. 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Since target arithmetic must be done on the host, there has to + be some way of evaluating arithmetic expressions as the host + would evaluate them. We use the GNU MP library to do arithmetic, + and this file provides the interface. */ + +#include "config.h" + +#include + +#include "gfortran.h" +#include "arith.h" + +mpf_t pi, half_pi, two_pi, e; + +/* The gfc_(integer|real)_kinds[] structures have everything the front + end needs to know about integers and real numbers on the target. + Other entries of the structure are calculated from these values. + The first entry is the default kind, the second entry of the real + structure is the default double kind. */ + +#define MPZ_NULL {{0,0,0}} +#define MPF_NULL {{0,0,0,0}} + +#define DEF_GFC_INTEGER_KIND(KIND,RADIX,DIGITS,BIT_SIZE) \ + {KIND, RADIX, DIGITS, BIT_SIZE, 0, MPZ_NULL, MPZ_NULL, MPZ_NULL} + +#define DEF_GFC_LOGICAL_KIND(KIND,BIT_SIZE) \ + {KIND, BIT_SIZE} + +#define DEF_GFC_REAL_KIND(KIND,RADIX,DIGITS,MIN_EXP, MAX_EXP) \ + {KIND, RADIX, DIGITS, MIN_EXP, MAX_EXP, \ + 0, 0, MPF_NULL, MPF_NULL, MPF_NULL} + +gfc_integer_info gfc_integer_kinds[] = { + DEF_GFC_INTEGER_KIND (4, 2, 31, 32), + DEF_GFC_INTEGER_KIND (8, 2, 63, 64), + DEF_GFC_INTEGER_KIND (2, 2, 15, 16), + DEF_GFC_INTEGER_KIND (1, 2, 7, 8), + DEF_GFC_INTEGER_KIND (0, 0, 0, 0) +}; + +gfc_logical_info gfc_logical_kinds[] = { + DEF_GFC_LOGICAL_KIND (4, 32), + DEF_GFC_LOGICAL_KIND (8, 64), + DEF_GFC_LOGICAL_KIND (2, 16), + DEF_GFC_LOGICAL_KIND (1, 8), + DEF_GFC_LOGICAL_KIND (0, 0) +}; + +gfc_real_info gfc_real_kinds[] = { + DEF_GFC_REAL_KIND (4, 2, 24, -125, 128), + DEF_GFC_REAL_KIND (8, 2, 53, -1021, 1024), + DEF_GFC_REAL_KIND (0, 0, 0, 0, 0) +}; + + +/* The integer kind to use for array indices. This will be set to the + proper value based on target information from the backend. */ + +int gfc_index_integer_kind; + + +/* Compute the natural log of arg. + + We first get the argument into the range 0.5 to 1.5 by successive + multiplications or divisions by e. Then we use the series: + + ln(x) = (x-1) - (x-1)^/2 + (x-1)^3/3 - (x-1)^4/4 + ... + + Because we are expanding in powers of (x-1), and 0.5 < x < 1.5, we + have -0.5 < (x-1) < 0.5. Ignoring the harmonic term, this means + that each term is at most 1/(2^i), meaning one bit is gained per + iteration. + + Not very efficient, but it doesn't have to be. */ + +void +natural_logarithm (mpf_t * arg, mpf_t * result) +{ + mpf_t x, xp, t, log; + int i, p; + + mpf_init_set (x, *arg); + mpf_init (t); + + p = 0; + + mpf_set_str (t, "0.5", 10); + while (mpf_cmp (x, t) < 0) + { + mpf_mul (x, x, e); + p--; + } + + mpf_set_str (t, "1.5", 10); + while (mpf_cmp (x, t) > 0) + { + mpf_div (x, x, e); + p++; + } + + mpf_sub_ui (x, x, 1); + mpf_init_set_ui (log, 0); + mpf_init_set_ui (xp, 1); + + for (i = 1; i < GFC_REAL_BITS; i++) + { + mpf_mul (xp, xp, x); + mpf_div_ui (t, xp, i); + + if (i % 2 == 0) + mpf_sub (log, log, t); + else + mpf_add (log, log, t); + } + + /* Add in the log (e^p) = p */ + + if (p < 0) + mpf_sub_ui (log, log, -p); + else + mpf_add_ui (log, log, p); + + mpf_clear (x); + mpf_clear (xp); + mpf_clear (t); + + mpf_set (*result, log); + mpf_clear (log); +} + + +/* Calculate the common logarithm of arg. We use the natural + logaritm of arg and of 10: + + log10(arg) = log(arg)/log(10) */ + +void +common_logarithm (mpf_t * arg, mpf_t * result) +{ + mpf_t i10, log10; + + natural_logarithm (arg, result); + + mpf_init_set_ui (i10, 10); + mpf_init (log10); + natural_logarithm (&i10, &log10); + + mpf_div (*result, *result, log10); + mpf_clear (i10); + mpf_clear (log10); +} + +/* Calculate exp(arg). + + We use a reduction of the form + + x = Nln2 + r + + Then we obtain exp(r) from the McLaurin series. + exp(x) is then recovered from the identity + + exp(x) = 2^N*exp(r). */ + +void +exponential (mpf_t * arg, mpf_t * result) +{ + mpf_t two, ln2, power, q, r, num, denom, term, x, xp; + int i; + long n; + unsigned long p, mp; + + + mpf_init_set (x, *arg); + + if (mpf_cmp_ui (x, 0) == 0) + { + mpf_set_ui (*result, 1); + } + else if (mpf_cmp_ui (x, 1) == 0) + { + mpf_set (*result, e); + } + else + { + mpf_init_set_ui (two, 2); + mpf_init (ln2); + mpf_init (q); + mpf_init (r); + mpf_init (power); + mpf_init (term); + + natural_logarithm (&two, &ln2); + + mpf_div (q, x, ln2); + mpf_floor (power, q); + mpf_mul (q, power, ln2); + mpf_sub (r, x, q); + + mpf_init_set_ui (xp, 1); + mpf_init_set_ui (num, 1); + mpf_init_set_ui (denom, 1); + + for (i = 1; i <= GFC_REAL_BITS + 10; i++) + { + mpf_mul (num, num, r); + mpf_mul_ui (denom, denom, i); + mpf_div (term, num, denom); + mpf_add (xp, xp, term); + } + + /* Reconstruction step */ + n = (long) mpf_get_d (power); + + if (n > 0) + { + p = (unsigned int) n; + mpf_mul_2exp (*result, xp, p); + } + else + { + mp = (unsigned int) (-n); + mpf_div_2exp (*result, xp, mp); + } + + mpf_clear (two); + mpf_clear (ln2); + mpf_clear (q); + mpf_clear (r); + mpf_clear (power); + mpf_clear (num); + mpf_clear (denom); + mpf_clear (term); + mpf_clear (xp); + } + + mpf_clear (x); +} + + +/* Calculate sin(arg). + + We use a reduction of the form + + x= N*2pi + r + + Then we obtain sin(r) from the McLaurin series. */ + +void +sine (mpf_t * arg, mpf_t * result) +{ + mpf_t factor, q, r, num, denom, term, x, xp; + int i, sign; + + mpf_init_set (x, *arg); + + /* Special case (we do not treat multiples of pi due to roundoff issues) */ + if (mpf_cmp_ui (x, 0) == 0) + { + mpf_set_ui (*result, 0); + } + else + { + mpf_init (q); + mpf_init (r); + mpf_init (factor); + mpf_init (term); + + mpf_div (q, x, two_pi); + mpf_floor (factor, q); + mpf_mul (q, factor, two_pi); + mpf_sub (r, x, q); + + mpf_init_set_ui (xp, 0); + mpf_init_set_ui (num, 1); + mpf_init_set_ui (denom, 1); + + sign = -1; + for (i = 1; i < GFC_REAL_BITS + 10; i++) + { + mpf_mul (num, num, r); + mpf_mul_ui (denom, denom, i); + if (i % 2 == 0) + continue; + + sign = -sign; + mpf_div (term, num, denom); + if (sign > 0) + mpf_add (xp, xp, term); + else + mpf_sub (xp, xp, term); + } + + mpf_set (*result, xp); + + mpf_clear (q); + mpf_clear (r); + mpf_clear (factor); + mpf_clear (num); + mpf_clear (denom); + mpf_clear (term); + mpf_clear (xp); + } + + mpf_clear (x); +} + + +/* Calculate cos(arg). + + Similar to sine. */ + +void +cosine (mpf_t * arg, mpf_t * result) +{ + mpf_t factor, q, r, num, denom, term, x, xp; + int i, sign; + + mpf_init_set (x, *arg); + + /* Special case (we do not treat multiples of pi due to roundoff issues) */ + if (mpf_cmp_ui (x, 0) == 0) + { + mpf_set_ui (*result, 1); + } + else + { + mpf_init (q); + mpf_init (r); + mpf_init (factor); + mpf_init (term); + + mpf_div (q, x, two_pi); + mpf_floor (factor, q); + mpf_mul (q, factor, two_pi); + mpf_sub (r, x, q); + + mpf_init_set_ui (xp, 1); + mpf_init_set_ui (num, 1); + mpf_init_set_ui (denom, 1); + + sign = 1; + for (i = 1; i < GFC_REAL_BITS + 10; i++) + { + mpf_mul (num, num, r); + mpf_mul_ui (denom, denom, i); + if (i % 2 != 0) + continue; + + sign = -sign; + mpf_div (term, num, denom); + if (sign > 0) + mpf_add (xp, xp, term); + else + mpf_sub (xp, xp, term); + } + mpf_set (*result, xp); + + mpf_clear (q); + mpf_clear (r); + mpf_clear (factor); + mpf_clear (num); + mpf_clear (denom); + mpf_clear (term); + mpf_clear (xp); + } + + mpf_clear (x); +} + + +/* Calculate atan(arg). + + Similar to sine but requires special handling for x near 1. */ + +void +arctangent (mpf_t * arg, mpf_t * result) +{ + mpf_t absval, convgu, convgl, num, term, x, xp; + int i, sign; + + mpf_init_set (x, *arg); + + /* Special cases */ + if (mpf_cmp_ui (x, 0) == 0) + { + mpf_set_ui (*result, 0); + } + else if (mpf_cmp_ui (x, 1) == 0) + { + mpf_init (num); + mpf_div_ui (num, half_pi, 2); + mpf_set (*result, num); + mpf_clear (num); + } + else if (mpf_cmp_si (x, -1) == 0) + { + mpf_init (num); + mpf_div_ui (num, half_pi, 2); + mpf_neg (*result, num); + mpf_clear (num); + } + else + { /* General cases */ + + mpf_init (absval); + mpf_abs (absval, x); + + mpf_init_set_d (convgu, 1.5); + mpf_init_set_d (convgl, 0.5); + mpf_init_set_ui (num, 1); + mpf_init (term); + + if (mpf_cmp (absval, convgl) < 0) + { + mpf_init_set_ui (xp, 0); + sign = -1; + for (i = 1; i < GFC_REAL_BITS + 10; i++) + { + mpf_mul (num, num, absval); + if (i % 2 == 0) + continue; + + sign = -sign; + mpf_div_ui (term, num, i); + if (sign > 0) + mpf_add (xp, xp, term); + else + mpf_sub (xp, xp, term); + } + } + else if (mpf_cmp (absval, convgu) >= 0) + { + mpf_init_set (xp, half_pi); + sign = 1; + for (i = 1; i < GFC_REAL_BITS + 10; i++) + { + mpf_div (num, num, absval); + if (i % 2 == 0) + continue; + + sign = -sign; + mpf_div_ui (term, num, i); + if (sign > 0) + mpf_add (xp, xp, term); + else + mpf_sub (xp, xp, term); + } + } + else + { + mpf_init_set_ui (xp, 0); + + mpf_sub_ui (num, absval, 1); + mpf_add_ui (term, absval, 1); + mpf_div (absval, num, term); + + mpf_set_ui (num, 1); + + sign = -1; + for (i = 1; i < GFC_REAL_BITS + 10; i++) + { + mpf_mul (num, num, absval); + if (i % 2 == 0) + continue; + sign = -sign; + mpf_div_ui (term, num, i); + if (sign > 0) + mpf_add (xp, xp, term); + else + mpf_sub (xp, xp, term); + } + + mpf_div_ui (term, half_pi, 2); + mpf_add (xp, term, xp); + } + + /* This makes sure to preserve the identity arctan(-x) = -arctan(x) + and improves accuracy to boot. */ + + if (mpf_cmp_ui (x, 0) > 0) + mpf_set (*result, xp); + else + mpf_neg (*result, xp); + + mpf_clear (absval); + mpf_clear (convgl); + mpf_clear (convgu); + mpf_clear (num); + mpf_clear (term); + mpf_clear (xp); + } + mpf_clear (x); +} + + +/* Calculate atan2 (y, x) + +atan2(y, x) = atan(y/x) if x > 0, + sign(y)*(pi - atan(|y/x|)) if x < 0, + 0 if x = 0 && y == 0, + sign(y)*pi/2 if x = 0 && y != 0. +*/ + +void +arctangent2 (mpf_t * y, mpf_t * x, mpf_t * result) +{ + mpf_t t; + + mpf_init (t); + + switch (mpf_sgn (*x)) + { + case 1: + mpf_div (t, *y, *x); + arctangent (&t, result); + break; + case -1: + mpf_div (t, *y, *x); + mpf_abs (t, t); + arctangent (&t, &t); + mpf_sub (*result, pi, t); + if (mpf_sgn (*y) == -1) + mpf_neg (*result, *result); + break; + case 0: + if (mpf_sgn (*y) == 0) + mpf_set_ui (*result, 0); + else + { + mpf_set (*result, half_pi); + if (mpf_sgn (*y) == -1) + mpf_neg (*result, *result); + } + break; + } + mpf_clear (t); +} + +/* Calculate cosh(arg). */ + +void +hypercos (mpf_t * arg, mpf_t * result) +{ + mpf_t neg, term1, term2, x, xp; + + mpf_init_set (x, *arg); + + mpf_init (neg); + mpf_init (term1); + mpf_init (term2); + mpf_init (xp); + + mpf_neg (neg, x); + + exponential (&x, &term1); + exponential (&neg, &term2); + + mpf_add (xp, term1, term2); + mpf_div_ui (*result, xp, 2); + + mpf_clear (neg); + mpf_clear (term1); + mpf_clear (term2); + mpf_clear (x); + mpf_clear (xp); +} + + +/* Calculate sinh(arg). */ + +void +hypersine (mpf_t * arg, mpf_t * result) +{ + mpf_t neg, term1, term2, x, xp; + + mpf_init_set (x, *arg); + + mpf_init (neg); + mpf_init (term1); + mpf_init (term2); + mpf_init (xp); + + mpf_neg (neg, x); + + exponential (&x, &term1); + exponential (&neg, &term2); + + mpf_sub (xp, term1, term2); + mpf_div_ui (*result, xp, 2); + + mpf_clear (neg); + mpf_clear (term1); + mpf_clear (term2); + mpf_clear (x); + mpf_clear (xp); +} + + +/* Given an arithmetic error code, return a pointer to a string that + explains the error. */ + +static const char * +gfc_arith_error (arith code) +{ + const char *p; + + switch (code) + { + case ARITH_OK: + p = "Arithmetic OK"; + break; + case ARITH_OVERFLOW: + p = "Arithmetic overflow"; + break; + case ARITH_UNDERFLOW: + p = "Arithmetic underflow"; + break; + case ARITH_DIV0: + p = "Division by zero"; + break; + case ARITH_0TO0: + p = "Indeterminate form 0 ** 0"; + break; + case ARITH_INCOMMENSURATE: + p = "Array operands are incommensurate"; + break; + default: + gfc_internal_error ("gfc_arith_error(): Bad error code"); + } + + return p; +} + + +/* Get things ready to do math. */ + +void +gfc_arith_init_1 (void) +{ + gfc_integer_info *int_info; + gfc_real_info *real_info; + mpf_t a, b; + mpz_t r; + int i, n, limit; + + /* Set the default precision for GMP computations. */ + mpf_set_default_prec (GFC_REAL_BITS + 30); + + /* Calculate e, needed by the natural_logarithm() subroutine. */ + mpf_init (b); + mpf_init_set_ui (e, 0); + mpf_init_set_ui (a, 1); + + for (i = 1; i < 100; i++) + { + mpf_add (e, e, a); + mpf_div_ui (a, a, i); /* 1/(i!) */ + } + + /* Calculate pi, 2pi, pi/2, and -pi/2, needed for trigonometric + functions. + + We use the Bailey, Borwein and Plouffe formula: + + pi = \sum{n=0}^\infty (1/16)^n [4/(8n+1) - 2/(8n+4) - 1/(8n+5) - 1/(8n+6)] + + which gives about four bits per iteration. */ + + mpf_init_set_ui (pi, 0); + + mpf_init (two_pi); + mpf_init (half_pi); + + limit = (GFC_REAL_BITS / 4) + 10; /* (1/16)^n gives 4 bits per iteration */ + + for (n = 0; n < limit; n++) + { + mpf_set_ui (b, 4); + mpf_div_ui (b, b, 8 * n + 1); /* 4/(8n+1) */ + + mpf_set_ui (a, 2); + mpf_div_ui (a, a, 8 * n + 4); /* 2/(8n+4) */ + mpf_sub (b, b, a); + + mpf_set_ui (a, 1); + mpf_div_ui (a, a, 8 * n + 5); /* 1/(8n+5) */ + mpf_sub (b, b, a); + + mpf_set_ui (a, 1); + mpf_div_ui (a, a, 8 * n + 6); /* 1/(8n+6) */ + mpf_sub (b, b, a); + + mpf_set_ui (a, 16); + mpf_pow_ui (a, a, n); /* 16^n */ + + mpf_div (b, b, a); + + mpf_add (pi, pi, b); + } + + mpf_mul_ui (two_pi, pi, 2); + mpf_div_ui (half_pi, pi, 2); + + /* Convert the minimum/maximum values for each kind into their + GNU MP representation. */ + mpz_init (r); + + for (int_info = gfc_integer_kinds; int_info->kind != 0; int_info++) + { + /* Huge */ + mpz_set_ui (r, int_info->radix); + mpz_pow_ui (r, r, int_info->digits); + + mpz_init (int_info->huge); + mpz_sub_ui (int_info->huge, r, 1); + + /* These are the numbers that are actually representable by the + target. For bases other than two, this needs to be changed. */ + if (int_info->radix != 2) + gfc_internal_error ("Fix min_int, max_int calculation"); + + mpz_init (int_info->min_int); + mpz_neg (int_info->min_int, int_info->huge); + /* No -1 here, because the representation is symmetric. */ + + mpz_init (int_info->max_int); + mpz_add (int_info->max_int, int_info->huge, int_info->huge); + mpz_add_ui (int_info->max_int, int_info->max_int, 1); + + /* Range */ + mpf_set_z (a, int_info->huge); + common_logarithm (&a, &a); + mpf_trunc (a, a); + mpz_set_f (r, a); + int_info->range = mpz_get_si (r); + } + + /* mpf_set_default_prec(GFC_REAL_BITS); */ + for (real_info = gfc_real_kinds; real_info->kind != 0; real_info++) + { + /* Huge */ + mpf_set_ui (a, real_info->radix); + mpf_set_ui (b, real_info->radix); + + mpf_pow_ui (a, a, real_info->max_exponent); + mpf_pow_ui (b, b, real_info->max_exponent - real_info->digits); + + mpf_init (real_info->huge); + mpf_sub (real_info->huge, a, b); + + /* Tiny */ + mpf_set_ui (b, real_info->radix); + mpf_pow_ui (b, b, 1 - real_info->min_exponent); + + mpf_init (real_info->tiny); + mpf_ui_div (real_info->tiny, 1, b); + + /* Epsilon */ + mpf_set_ui (b, real_info->radix); + mpf_pow_ui (b, b, real_info->digits - 1); + + mpf_init (real_info->epsilon); + mpf_ui_div (real_info->epsilon, 1, b); + + /* Range */ + common_logarithm (&real_info->huge, &a); + common_logarithm (&real_info->tiny, &b); + mpf_neg (b, b); + + if (mpf_cmp (a, b) > 0) + mpf_set (a, b); /* a = min(a, b) */ + + mpf_trunc (a, a); + mpz_set_f (r, a); + real_info->range = mpz_get_si (r); + + /* Precision */ + mpf_set_ui (a, real_info->radix); + common_logarithm (&a, &a); + + mpf_mul_ui (a, a, real_info->digits - 1); + mpf_trunc (a, a); + mpz_set_f (r, a); + real_info->precision = mpz_get_si (r); + + /* If the radix is an integral power of 10, add one to the + precision. */ + for (i = 10; i <= real_info->radix; i *= 10) + if (i == real_info->radix) + real_info->precision++; + } + + mpz_clear (r); + mpf_clear (a); + mpf_clear (b); +} + + +/* Clean up, get rid of numeric constants. */ + +void +gfc_arith_done_1 (void) +{ + gfc_integer_info *ip; + gfc_real_info *rp; + + mpf_clear (e); + + mpf_clear (pi); + mpf_clear (half_pi); + mpf_clear (two_pi); + + for (ip = gfc_integer_kinds; ip->kind; ip++) + { + mpz_clear (ip->min_int); + mpz_clear (ip->max_int); + mpz_clear (ip->huge); + } + + for (rp = gfc_real_kinds; rp->kind; rp++) + { + mpf_clear (rp->epsilon); + mpf_clear (rp->huge); + mpf_clear (rp->tiny); + } +} + + +/* Return default kinds. */ + +int +gfc_default_integer_kind (void) +{ + return gfc_integer_kinds[gfc_option.i8 ? 1 : 0].kind; +} + +int +gfc_default_real_kind (void) +{ + return gfc_real_kinds[gfc_option.r8 ? 1 : 0].kind; +} + +int +gfc_default_double_kind (void) +{ + return gfc_real_kinds[1].kind; +} + +int +gfc_default_character_kind (void) +{ + return 1; +} + +int +gfc_default_logical_kind (void) +{ + return gfc_logical_kinds[gfc_option.i8 ? 1 : 0].kind; +} + +int +gfc_default_complex_kind (void) +{ + return gfc_default_real_kind (); +} + + +/* Make sure that a valid kind is present. Returns an index into the + gfc_integer_kinds array, -1 if the kind is not present. */ + +static int +validate_integer (int kind) +{ + int i; + + for (i = 0;; i++) + { + if (gfc_integer_kinds[i].kind == 0) + { + i = -1; + break; + } + if (gfc_integer_kinds[i].kind == kind) + break; + } + + return i; +} + + +static int +validate_real (int kind) +{ + int i; + + for (i = 0;; i++) + { + if (gfc_real_kinds[i].kind == 0) + { + i = -1; + break; + } + if (gfc_real_kinds[i].kind == kind) + break; + } + + return i; +} + + +static int +validate_logical (int kind) +{ + int i; + + for (i = 0;; i++) + { + if (gfc_logical_kinds[i].kind == 0) + { + i = -1; + break; + } + if (gfc_logical_kinds[i].kind == kind) + break; + } + + return i; +} + + +static int +validate_character (int kind) +{ + + if (kind == gfc_default_character_kind ()) + return 0; + return -1; +} + + +/* Validate a kind given a basic type. The return value is the same + for the child functions, with -1 indicating nonexistence of the + type. */ + +int +gfc_validate_kind (bt type, int kind) +{ + int rc; + + switch (type) + { + case BT_REAL: /* Fall through */ + case BT_COMPLEX: + rc = validate_real (kind); + break; + case BT_INTEGER: + rc = validate_integer (kind); + break; + case BT_LOGICAL: + rc = validate_logical (kind); + break; + case BT_CHARACTER: + rc = validate_character (kind); + break; + + default: + gfc_internal_error ("gfc_validate_kind(): Got bad type"); + } + + return rc; +} + + +/* Given an integer and a kind, make sure that the integer lies within + the range of the kind. Returns ARITH_OK or ARITH_OVERFLOW. */ + +static arith +gfc_check_integer_range (mpz_t p, int kind) +{ + arith result; + int i; + + i = validate_integer (kind); + if (i == -1) + gfc_internal_error ("gfc_check_integer_range(): Bad kind"); + + result = ARITH_OK; + + if (mpz_cmp (p, gfc_integer_kinds[i].min_int) < 0 + || mpz_cmp (p, gfc_integer_kinds[i].max_int) > 0) + result = ARITH_OVERFLOW; + + return result; +} + + +/* Given a real and a kind, make sure that the real lies within the + range of the kind. Returns ARITH_OK, ARITH_OVERFLOW or + ARITH_UNDERFLOW. */ + +static arith +gfc_check_real_range (mpf_t p, int kind) +{ + arith retval; + mpf_t q; + int i; + + mpf_init (q); + mpf_abs (q, p); + + i = validate_real (kind); + if (i == -1) + gfc_internal_error ("gfc_check_real_range(): Bad kind"); + + retval = ARITH_OK; + if (mpf_sgn (q) == 0) + goto done; + + if (mpf_cmp (q, gfc_real_kinds[i].huge) == 1) + { + retval = ARITH_OVERFLOW; + goto done; + } + + if (mpf_cmp (q, gfc_real_kinds[i].tiny) == -1) + retval = ARITH_UNDERFLOW; + +done: + mpf_clear (q); + + return retval; +} + + +/* Function to return a constant expression node of a given type and + kind. */ + +gfc_expr * +gfc_constant_result (bt type, int kind, locus * where) +{ + gfc_expr *result; + + if (!where) + gfc_internal_error + ("gfc_constant_result(): locus 'where' cannot be NULL"); + + result = gfc_get_expr (); + + result->expr_type = EXPR_CONSTANT; + result->ts.type = type; + result->ts.kind = kind; + result->where = *where; + + switch (type) + { + case BT_INTEGER: + mpz_init (result->value.integer); + break; + + case BT_REAL: + mpf_init (result->value.real); + break; + + case BT_COMPLEX: + mpf_init (result->value.complex.r); + mpf_init (result->value.complex.i); + break; + + default: + break; + } + + return result; +} + + +/* Low-level arithmetic functions. All of these subroutines assume + that all operands are of the same type and return an operand of the + same type. The other thing about these subroutines is that they + can fail in various ways -- overflow, underflow, division by zero, + zero raised to the zero, etc. */ + +static arith +gfc_arith_not (gfc_expr * op1, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, op1->ts.kind, &op1->where); + result->value.logical = !op1->value.logical; + *resultp = result; + + return ARITH_OK; +} + + +static arith +gfc_arith_and (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2), + &op1->where); + result->value.logical = op1->value.logical && op2->value.logical; + *resultp = result; + + return ARITH_OK; +} + + +static arith +gfc_arith_or (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2), + &op1->where); + result->value.logical = op1->value.logical || op2->value.logical; + *resultp = result; + + return ARITH_OK; +} + + +static arith +gfc_arith_eqv (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2), + &op1->where); + result->value.logical = op1->value.logical == op2->value.logical; + *resultp = result; + + return ARITH_OK; +} + + +static arith +gfc_arith_neqv (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_kind_max (op1, op2), + &op1->where); + result->value.logical = op1->value.logical != op2->value.logical; + *resultp = result; + + return ARITH_OK; +} + + +/* Make sure a constant numeric expression is within the range for + it's type and kind. Note that there's also a gfc_check_range(), + but that one deals with the intrinsic RANGE function. */ + +arith +gfc_range_check (gfc_expr * e) +{ + arith rc; + + switch (e->ts.type) + { + case BT_INTEGER: + rc = gfc_check_integer_range (e->value.integer, e->ts.kind); + break; + + case BT_REAL: + rc = gfc_check_real_range (e->value.real, e->ts.kind); + break; + + case BT_COMPLEX: + rc = gfc_check_real_range (e->value.complex.r, e->ts.kind); + if (rc != ARITH_OK) + rc = gfc_check_real_range (e->value.complex.i, e->ts.kind); + + break; + + default: + gfc_internal_error ("gfc_range_check(): Bad type"); + } + + return rc; +} + + +/* It may seem silly to have a subroutine that actually computes the + unary plus of a constant, but it prevents us from making exceptions + in the code elsewhere. */ + +static arith +gfc_arith_uplus (gfc_expr * op1, gfc_expr ** resultp) +{ + + *resultp = gfc_copy_expr (op1); + return ARITH_OK; +} + + +static arith +gfc_arith_uminus (gfc_expr * op1, gfc_expr ** resultp) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where); + + switch (op1->ts.type) + { + case BT_INTEGER: + mpz_neg (result->value.integer, op1->value.integer); + break; + + case BT_REAL: + mpf_neg (result->value.real, op1->value.real); + break; + + case BT_COMPLEX: + mpf_neg (result->value.complex.r, op1->value.complex.r); + mpf_neg (result->value.complex.i, op1->value.complex.i); + break; + + default: + gfc_internal_error ("gfc_arith_uminus(): Bad basic type"); + } + + rc = gfc_range_check (result); + + if (rc != ARITH_OK) + gfc_free_expr (result); + else + *resultp = result; + + return rc; +} + + +static arith +gfc_arith_plus (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where); + + switch (op1->ts.type) + { + case BT_INTEGER: + mpz_add (result->value.integer, op1->value.integer, op2->value.integer); + break; + + case BT_REAL: + mpf_add (result->value.real, op1->value.real, op2->value.real); + break; + + case BT_COMPLEX: + mpf_add (result->value.complex.r, op1->value.complex.r, + op2->value.complex.r); + + mpf_add (result->value.complex.i, op1->value.complex.i, + op2->value.complex.i); + break; + + default: + gfc_internal_error ("gfc_arith_plus(): Bad basic type"); + } + + rc = gfc_range_check (result); + + if (rc != ARITH_OK) + gfc_free_expr (result); + else + *resultp = result; + + return rc; +} + + +static arith +gfc_arith_minus (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where); + + switch (op1->ts.type) + { + case BT_INTEGER: + mpz_sub (result->value.integer, op1->value.integer, op2->value.integer); + break; + + case BT_REAL: + mpf_sub (result->value.real, op1->value.real, op2->value.real); + break; + + case BT_COMPLEX: + mpf_sub (result->value.complex.r, op1->value.complex.r, + op2->value.complex.r); + + mpf_sub (result->value.complex.i, op1->value.complex.i, + op2->value.complex.i); + + break; + + default: + gfc_internal_error ("gfc_arith_minus(): Bad basic type"); + } + + rc = gfc_range_check (result); + + if (rc != ARITH_OK) + gfc_free_expr (result); + else + *resultp = result; + + return rc; +} + + +static arith +gfc_arith_times (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + mpf_t x, y; + arith rc; + + result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where); + + switch (op1->ts.type) + { + case BT_INTEGER: + mpz_mul (result->value.integer, op1->value.integer, op2->value.integer); + break; + + case BT_REAL: + mpf_mul (result->value.real, op1->value.real, op2->value.real); + break; + + case BT_COMPLEX: + mpf_init (x); + mpf_init (y); + + mpf_mul (x, op1->value.complex.r, op2->value.complex.r); + mpf_mul (y, op1->value.complex.i, op2->value.complex.i); + mpf_sub (result->value.complex.r, x, y); + + mpf_mul (x, op1->value.complex.r, op2->value.complex.i); + mpf_mul (y, op1->value.complex.i, op2->value.complex.r); + mpf_add (result->value.complex.i, x, y); + + mpf_clear (x); + mpf_clear (y); + + break; + + default: + gfc_internal_error ("gfc_arith_times(): Bad basic type"); + } + + rc = gfc_range_check (result); + + if (rc != ARITH_OK) + gfc_free_expr (result); + else + *resultp = result; + + return rc; +} + + +static arith +gfc_arith_divide (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + mpf_t x, y, div; + arith rc; + + rc = ARITH_OK; + + result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where); + + switch (op1->ts.type) + { + case BT_INTEGER: + if (mpz_sgn (op2->value.integer) == 0) + { + rc = ARITH_DIV0; + break; + } + + mpz_tdiv_q (result->value.integer, op1->value.integer, + op2->value.integer); + break; + + case BT_REAL: + if (mpf_sgn (op2->value.real) == 0) + { + rc = ARITH_DIV0; + break; + } + + mpf_div (result->value.real, op1->value.real, op2->value.real); + break; + + case BT_COMPLEX: + if (mpf_sgn (op2->value.complex.r) == 0 + && mpf_sgn (op2->value.complex.i) == 0) + { + rc = ARITH_DIV0; + break; + } + + mpf_init (x); + mpf_init (y); + mpf_init (div); + + mpf_mul (x, op2->value.complex.r, op2->value.complex.r); + mpf_mul (y, op2->value.complex.i, op2->value.complex.i); + mpf_add (div, x, y); + + mpf_mul (x, op1->value.complex.r, op2->value.complex.r); + mpf_mul (y, op1->value.complex.i, op2->value.complex.i); + mpf_add (result->value.complex.r, x, y); + mpf_div (result->value.complex.r, result->value.complex.r, div); + + mpf_mul (x, op1->value.complex.i, op2->value.complex.r); + mpf_mul (y, op1->value.complex.r, op2->value.complex.i); + mpf_sub (result->value.complex.i, x, y); + mpf_div (result->value.complex.i, result->value.complex.i, div); + + mpf_clear (x); + mpf_clear (y); + mpf_clear (div); + + break; + + default: + gfc_internal_error ("gfc_arith_divide(): Bad basic type"); + } + + if (rc == ARITH_OK) + rc = gfc_range_check (result); + + if (rc != ARITH_OK) + gfc_free_expr (result); + else + *resultp = result; + + return rc; +} + + +/* Compute the reciprocal of a complex number (guaranteed nonzero). */ + +static void +complex_reciprocal (gfc_expr * op) +{ + mpf_t mod, a, result_r, result_i; + + mpf_init (mod); + mpf_init (a); + + mpf_mul (mod, op->value.complex.r, op->value.complex.r); + mpf_mul (a, op->value.complex.i, op->value.complex.i); + mpf_add (mod, mod, a); + + mpf_init (result_r); + mpf_div (result_r, op->value.complex.r, mod); + + mpf_init (result_i); + mpf_neg (result_i, op->value.complex.i); + mpf_div (result_i, result_i, mod); + + mpf_set (op->value.complex.r, result_r); + mpf_set (op->value.complex.i, result_i); + + mpf_clear (result_r); + mpf_clear (result_i); + + mpf_clear (mod); + mpf_clear (a); +} + + +/* Raise a complex number to positive power. */ + +static void +complex_pow_ui (gfc_expr * base, int power, gfc_expr * result) +{ + mpf_t temp_r, temp_i, a; + + mpf_set_ui (result->value.complex.r, 1); + mpf_set_ui (result->value.complex.i, 0); + + mpf_init (temp_r); + mpf_init (temp_i); + mpf_init (a); + + for (; power > 0; power--) + { + mpf_mul (temp_r, base->value.complex.r, result->value.complex.r); + mpf_mul (a, base->value.complex.i, result->value.complex.i); + mpf_sub (temp_r, temp_r, a); + + mpf_mul (temp_i, base->value.complex.r, result->value.complex.i); + mpf_mul (a, base->value.complex.i, result->value.complex.r); + mpf_add (temp_i, temp_i, a); + + mpf_set (result->value.complex.r, temp_r); + mpf_set (result->value.complex.i, temp_i); + } + + mpf_clear (temp_r); + mpf_clear (temp_i); + mpf_clear (a); +} + + +/* Raise a number to an integer power. */ + +static arith +gfc_arith_power (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + int power, apower; + gfc_expr *result; + mpz_t unity_z; + mpf_t unity_f; + arith rc; + + rc = ARITH_OK; + + if (gfc_extract_int (op2, &power) != NULL) + gfc_internal_error ("gfc_arith_power(): Bad exponent"); + + result = gfc_constant_result (op1->ts.type, op1->ts.kind, &op1->where); + + if (power == 0) + { /* Handle something to the zeroth power */ + switch (op1->ts.type) + { + case BT_INTEGER: + if (mpz_sgn (op1->value.integer) == 0) + rc = ARITH_0TO0; + else + mpz_set_ui (result->value.integer, 1); + + break; + + case BT_REAL: + if (mpf_sgn (op1->value.real) == 0) + rc = ARITH_0TO0; + else + mpf_set_ui (result->value.real, 1); + + break; + + case BT_COMPLEX: + if (mpf_sgn (op1->value.complex.r) == 0 + && mpf_sgn (op1->value.complex.i) == 0) + rc = ARITH_0TO0; + else + { + mpf_set_ui (result->value.complex.r, 1); + mpf_set_ui (result->value.complex.r, 0); + } + + break; + + default: + gfc_internal_error ("gfc_arith_power(): Bad base"); + } + } + + if (power != 0) + { + apower = power; + if (power < 0) + apower = -power; + + switch (op1->ts.type) + { + case BT_INTEGER: + mpz_pow_ui (result->value.integer, op1->value.integer, apower); + + if (power < 0) + { + mpz_init_set_ui (unity_z, 1); + mpz_tdiv_q (result->value.integer, unity_z, + result->value.integer); + mpz_clear (unity_z); + } + + break; + + case BT_REAL: + mpf_pow_ui (result->value.real, op1->value.real, apower); + + if (power < 0) + { + mpf_init_set_ui (unity_f, 1); + mpf_div (result->value.real, unity_f, result->value.real); + mpf_clear (unity_f); + } + + break; + + case BT_COMPLEX: + complex_pow_ui (op1, apower, result); + if (power < 0) + complex_reciprocal (result); + + break; + + default: + break; + } + } + + if (rc == ARITH_OK) + rc = gfc_range_check (result); + + if (rc != ARITH_OK) + gfc_free_expr (result); + else + *resultp = result; + + return rc; +} + + +/* Concatenate two string constants. */ + +static arith +gfc_arith_concat (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + int len; + + result = gfc_constant_result (BT_CHARACTER, gfc_default_character_kind (), + &op1->where); + + len = op1->value.character.length + op2->value.character.length; + + result->value.character.string = gfc_getmem (len + 1); + result->value.character.length = len; + + memcpy (result->value.character.string, op1->value.character.string, + op1->value.character.length); + + memcpy (result->value.character.string + op1->value.character.length, + op2->value.character.string, op2->value.character.length); + + result->value.character.string[len] = '\0'; + + *resultp = result; + + return ARITH_OK; +} + + +/* Comparison operators. Assumes that the two expression nodes + contain two constants of the same type. */ + +int +gfc_compare_expr (gfc_expr * op1, gfc_expr * op2) +{ + int rc; + + switch (op1->ts.type) + { + case BT_INTEGER: + rc = mpz_cmp (op1->value.integer, op2->value.integer); + break; + + case BT_REAL: + rc = mpf_cmp (op1->value.real, op2->value.real); + break; + + case BT_CHARACTER: + rc = gfc_compare_string (op1, op2, NULL); + break; + + case BT_LOGICAL: + rc = ((!op1->value.logical && op2->value.logical) + || (op1->value.logical && !op2->value.logical)); + break; + + default: + gfc_internal_error ("gfc_compare_expr(): Bad basic type"); + } + + return rc; +} + + +/* Compare a pair of complex numbers. Naturally, this is only for + equality/nonequality. */ + +static int +compare_complex (gfc_expr * op1, gfc_expr * op2) +{ + + return (mpf_cmp (op1->value.complex.r, op2->value.complex.r) == 0 + && mpf_cmp (op1->value.complex.i, op2->value.complex.i) == 0); +} + + +/* Given two constant strings and the inverse collating sequence, + compare the strings. We return -1 for ab. If the xcoll_table is NULL, we use the processor's default + collating sequence. */ + +int +gfc_compare_string (gfc_expr * a, gfc_expr * b, const int *xcoll_table) +{ + int len, alen, blen, i, ac, bc; + + alen = a->value.character.length; + blen = b->value.character.length; + + len = (alen > blen) ? alen : blen; + + for (i = 0; i < len; i++) + { + ac = (i < alen) ? a->value.character.string[i] : ' '; + bc = (i < blen) ? b->value.character.string[i] : ' '; + + if (xcoll_table != NULL) + { + ac = xcoll_table[ac]; + bc = xcoll_table[bc]; + } + + if (ac < bc) + return -1; + if (ac > bc) + return 1; + } + + /* Strings are equal */ + + return 0; +} + + +/* Specific comparison subroutines. */ + +static arith +gfc_arith_eq (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (), + &op1->where); + result->value.logical = (op1->ts.type == BT_COMPLEX) ? + compare_complex (op1, op2) : (gfc_compare_expr (op1, op2) == 0); + + *resultp = result; + return ARITH_OK; +} + + +static arith +gfc_arith_ne (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (), + &op1->where); + result->value.logical = (op1->ts.type == BT_COMPLEX) ? + !compare_complex (op1, op2) : (gfc_compare_expr (op1, op2) != 0); + + *resultp = result; + return ARITH_OK; +} + + +static arith +gfc_arith_gt (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (), + &op1->where); + result->value.logical = (gfc_compare_expr (op1, op2) > 0); + *resultp = result; + + return ARITH_OK; +} + + +static arith +gfc_arith_ge (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (), + &op1->where); + result->value.logical = (gfc_compare_expr (op1, op2) >= 0); + *resultp = result; + + return ARITH_OK; +} + + +static arith +gfc_arith_lt (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (), + &op1->where); + result->value.logical = (gfc_compare_expr (op1, op2) < 0); + *resultp = result; + + return ARITH_OK; +} + + +static arith +gfc_arith_le (gfc_expr * op1, gfc_expr * op2, gfc_expr ** resultp) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, gfc_default_logical_kind (), + &op1->where); + result->value.logical = (gfc_compare_expr (op1, op2) <= 0); + *resultp = result; + + return ARITH_OK; +} + + +static arith +reduce_unary (arith (*eval) (gfc_expr *, gfc_expr **), gfc_expr * op, + gfc_expr ** result) +{ + gfc_constructor *c, *head; + gfc_expr *r; + arith rc; + + if (op->expr_type == EXPR_CONSTANT) + return eval (op, result); + + rc = ARITH_OK; + head = gfc_copy_constructor (op->value.constructor); + + for (c = head; c; c = c->next) + { + rc = eval (c->expr, &r); + if (rc != ARITH_OK) + break; + + gfc_replace_expr (c->expr, r); + } + + if (rc != ARITH_OK) + gfc_free_constructor (head); + else + { + r = gfc_get_expr (); + r->expr_type = EXPR_ARRAY; + r->value.constructor = head; + r->shape = gfc_copy_shape (op->shape, op->rank); + + r->ts = head->expr->ts; + r->where = op->where; + r->rank = op->rank; + + *result = r; + } + + return rc; +} + + +static arith +reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), + gfc_expr * op1, gfc_expr * op2, + gfc_expr ** result) +{ + gfc_constructor *c, *head; + gfc_expr *r; + arith rc; + + head = gfc_copy_constructor (op1->value.constructor); + rc = ARITH_OK; + + for (c = head; c; c = c->next) + { + rc = eval (c->expr, op2, &r); + if (rc != ARITH_OK) + break; + + gfc_replace_expr (c->expr, r); + } + + if (rc != ARITH_OK) + gfc_free_constructor (head); + else + { + r = gfc_get_expr (); + r->expr_type = EXPR_ARRAY; + r->value.constructor = head; + r->shape = gfc_copy_shape (op1->shape, op1->rank); + + r->ts = head->expr->ts; + r->where = op1->where; + r->rank = op1->rank; + + *result = r; + } + + return rc; +} + + +static arith +reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), + gfc_expr * op1, gfc_expr * op2, + gfc_expr ** result) +{ + gfc_constructor *c, *head; + gfc_expr *r; + arith rc; + + head = gfc_copy_constructor (op2->value.constructor); + rc = ARITH_OK; + + for (c = head; c; c = c->next) + { + rc = eval (op1, c->expr, &r); + if (rc != ARITH_OK) + break; + + gfc_replace_expr (c->expr, r); + } + + if (rc != ARITH_OK) + gfc_free_constructor (head); + else + { + r = gfc_get_expr (); + r->expr_type = EXPR_ARRAY; + r->value.constructor = head; + r->shape = gfc_copy_shape (op2->shape, op2->rank); + + r->ts = head->expr->ts; + r->where = op2->where; + r->rank = op2->rank; + + *result = r; + } + + return rc; +} + + +static arith +reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), + gfc_expr * op1, gfc_expr * op2, + gfc_expr ** result) +{ + gfc_constructor *c, *d, *head; + gfc_expr *r; + arith rc; + + head = gfc_copy_constructor (op1->value.constructor); + + rc = ARITH_OK; + d = op2->value.constructor; + + if (gfc_check_conformance ("Elemental binary operation", op1, op2) + != SUCCESS) + rc = ARITH_INCOMMENSURATE; + else + { + + for (c = head; c; c = c->next, d = d->next) + { + if (d == NULL) + { + rc = ARITH_INCOMMENSURATE; + break; + } + + rc = eval (c->expr, d->expr, &r); + if (rc != ARITH_OK) + break; + + gfc_replace_expr (c->expr, r); + } + + if (d != NULL) + rc = ARITH_INCOMMENSURATE; + } + + if (rc != ARITH_OK) + gfc_free_constructor (head); + else + { + r = gfc_get_expr (); + r->expr_type = EXPR_ARRAY; + r->value.constructor = head; + r->shape = gfc_copy_shape (op1->shape, op1->rank); + + r->ts = head->expr->ts; + r->where = op1->where; + r->rank = op1->rank; + + *result = r; + } + + return rc; +} + + +static arith +reduce_binary (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), + gfc_expr * op1, gfc_expr * op2, + gfc_expr ** result) +{ + + if (op1->expr_type == EXPR_CONSTANT && op2->expr_type == EXPR_CONSTANT) + return eval (op1, op2, result); + + if (op1->expr_type == EXPR_CONSTANT && op2->expr_type == EXPR_ARRAY) + return reduce_binary_ca (eval, op1, op2, result); + + if (op1->expr_type == EXPR_ARRAY && op2->expr_type == EXPR_CONSTANT) + return reduce_binary_ac (eval, op1, op2, result); + + return reduce_binary_aa (eval, op1, op2, result); +} + + +typedef union +{ + arith (*f2)(gfc_expr *, gfc_expr **); + arith (*f3)(gfc_expr *, gfc_expr *, gfc_expr **); +} +eval_f; + +/* High level arithmetic subroutines. These subroutines go into + eval_intrinsic(), which can do one of several things to its + operands. If the operands are incompatible with the intrinsic + operation, we return a node pointing to the operands and hope that + an operator interface is found during resolution. + + If the operands are compatible and are constants, then we try doing + the arithmetic. We also handle the cases where either or both + operands are array constructors. */ + +static gfc_expr * +eval_intrinsic (gfc_intrinsic_op operator, + eval_f eval, gfc_expr * op1, gfc_expr * op2) +{ + gfc_expr temp, *result; + int unary; + arith rc; + + gfc_clear_ts (&temp.ts); + + switch (operator) + { + case INTRINSIC_NOT: /* Logical unary */ + if (op1->ts.type != BT_LOGICAL) + goto runtime; + + temp.ts.type = BT_LOGICAL; + temp.ts.kind = gfc_default_logical_kind (); + + unary = 1; + break; + + /* Logical binary operators */ + case INTRINSIC_OR: + case INTRINSIC_AND: + case INTRINSIC_NEQV: + case INTRINSIC_EQV: + if (op1->ts.type != BT_LOGICAL || op2->ts.type != BT_LOGICAL) + goto runtime; + + temp.ts.type = BT_LOGICAL; + temp.ts.kind = gfc_default_logical_kind (); + + unary = 0; + break; + + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: /* Numeric unary */ + if (!gfc_numeric_ts (&op1->ts)) + goto runtime; + + temp.ts = op1->ts; + + unary = 1; + break; + + case INTRINSIC_GE: + case INTRINSIC_LT: /* Additional restrictions */ + case INTRINSIC_LE: /* for ordering relations. */ + case INTRINSIC_GT: + if (op1->ts.type == BT_COMPLEX || op2->ts.type == BT_COMPLEX) + { + temp.ts.type = BT_LOGICAL; + temp.ts.kind = gfc_default_logical_kind(); + goto runtime; + } + + /* else fall through */ + + case INTRINSIC_EQ: + case INTRINSIC_NE: + if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER) + { + unary = 0; + temp.ts.type = BT_LOGICAL; + temp.ts.kind = gfc_default_logical_kind(); + break; + } + + /* else fall through */ + + case INTRINSIC_PLUS: + case INTRINSIC_MINUS: + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + case INTRINSIC_POWER: /* Numeric binary */ + if (!gfc_numeric_ts (&op1->ts) || !gfc_numeric_ts (&op2->ts)) + goto runtime; + + /* Insert any necessary type conversions to make the operands compatible. */ + + temp.expr_type = EXPR_OP; + gfc_clear_ts (&temp.ts); + temp.operator = operator; + + temp.op1 = op1; + temp.op2 = op2; + + gfc_type_convert_binary (&temp); + + if (operator == INTRINSIC_EQ || operator == INTRINSIC_NE + || operator == INTRINSIC_GE || operator == INTRINSIC_GT + || operator == INTRINSIC_LE || operator == INTRINSIC_LT) + { + temp.ts.type = BT_LOGICAL; + temp.ts.kind = gfc_default_logical_kind (); + } + + unary = 0; + break; + + case INTRINSIC_CONCAT: /* Character binary */ + if (op1->ts.type != BT_CHARACTER || op2->ts.type != BT_CHARACTER) + goto runtime; + + temp.ts.type = BT_CHARACTER; + temp.ts.kind = gfc_default_character_kind (); + + unary = 0; + break; + + case INTRINSIC_USER: + goto runtime; + + default: + gfc_internal_error ("eval_intrinsic(): Bad operator"); + } + + /* Try to combine the operators. */ + if (operator == INTRINSIC_POWER && op2->ts.type != BT_INTEGER) + goto runtime; + + if (op1->expr_type != EXPR_CONSTANT + && (op1->expr_type != EXPR_ARRAY + || !gfc_is_constant_expr (op1) + || !gfc_expanded_ac (op1))) + goto runtime; + + if (op2 != NULL + && op2->expr_type != EXPR_CONSTANT + && (op2->expr_type != EXPR_ARRAY + || !gfc_is_constant_expr (op2) + || !gfc_expanded_ac (op2))) + goto runtime; + + if (unary) + rc = reduce_unary (eval.f2, op1, &result); + else + rc = reduce_binary (eval.f3, op1, op2, &result); + + if (rc != ARITH_OK) + { /* Something went wrong */ + gfc_error ("%s at %L", gfc_arith_error (rc), &op1->where); + return NULL; + } + + gfc_free_expr (op1); + gfc_free_expr (op2); + return result; + +runtime: + /* Create a run-time expression */ + result = gfc_get_expr (); + result->ts = temp.ts; + + result->expr_type = EXPR_OP; + result->operator = operator; + + result->op1 = op1; + result->op2 = op2; + + result->where = op1->where; + + return result; +} + + +/* Modify type of expression for zero size array. */ +static gfc_expr * +eval_type_intrinsic0 (gfc_intrinsic_op operator, gfc_expr *op) +{ + if (op == NULL) + gfc_internal_error("eval_type_intrinsic0(): op NULL"); + + switch(operator) + { + case INTRINSIC_GE: + case INTRINSIC_LT: + case INTRINSIC_LE: + case INTRINSIC_GT: + case INTRINSIC_EQ: + case INTRINSIC_NE: + op->ts.type = BT_LOGICAL; + op->ts.kind = gfc_default_logical_kind(); + break; + + default: + break; + } + + return op; +} + + +/* Return nonzero if the expression is a zero size array. */ + +static int +gfc_zero_size_array (gfc_expr * e) +{ + + if (e->expr_type != EXPR_ARRAY) + return 0; + + return e->value.constructor == NULL; +} + + +/* Reduce a binary expression where at least one of the operands + involves a zero-length array. Returns NULL if neither of the + operands is a zero-length array. */ + +static gfc_expr * +reduce_binary0 (gfc_expr * op1, gfc_expr * op2) +{ + + if (gfc_zero_size_array (op1)) + { + gfc_free_expr (op2); + return op1; + } + + if (gfc_zero_size_array (op2)) + { + gfc_free_expr (op1); + return op2; + } + + return NULL; +} + + +static gfc_expr * +eval_intrinsic_f2 (gfc_intrinsic_op operator, + arith (*eval) (gfc_expr *, gfc_expr **), + gfc_expr * op1, gfc_expr * op2) +{ + gfc_expr *result; + eval_f f; + + if (op2 == NULL) + { + if (gfc_zero_size_array (op1)) + return eval_type_intrinsic0(operator, op1); + } + else + { + result = reduce_binary0 (op1, op2); + if (result != NULL) + return eval_type_intrinsic0(operator, result); + } + + f.f2 = eval; + return eval_intrinsic (operator, f, op1, op2); +} + + +static gfc_expr * +eval_intrinsic_f3 (gfc_intrinsic_op operator, + arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), + gfc_expr * op1, gfc_expr * op2) +{ + gfc_expr *result; + eval_f f; + + result = reduce_binary0 (op1, op2); + if (result != NULL) + return eval_type_intrinsic0(operator, result); + + f.f3 = eval; + return eval_intrinsic (operator, f, op1, op2); +} + + + +gfc_expr * +gfc_uplus (gfc_expr * op) +{ + return eval_intrinsic_f2 (INTRINSIC_UPLUS, gfc_arith_uplus, op, NULL); +} + +gfc_expr * +gfc_uminus (gfc_expr * op) +{ + return eval_intrinsic_f2 (INTRINSIC_UMINUS, gfc_arith_uminus, op, NULL); +} + +gfc_expr * +gfc_add (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_PLUS, gfc_arith_plus, op1, op2); +} + +gfc_expr * +gfc_subtract (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_MINUS, gfc_arith_minus, op1, op2); +} + +gfc_expr * +gfc_multiply (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_TIMES, gfc_arith_times, op1, op2); +} + +gfc_expr * +gfc_divide (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_DIVIDE, gfc_arith_divide, op1, op2); +} + +gfc_expr * +gfc_power (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_POWER, gfc_arith_power, op1, op2); +} + +gfc_expr * +gfc_concat (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_CONCAT, gfc_arith_concat, op1, op2); +} + +gfc_expr * +gfc_and (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_AND, gfc_arith_and, op1, op2); +} + +gfc_expr * +gfc_or (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_OR, gfc_arith_or, op1, op2); +} + +gfc_expr * +gfc_not (gfc_expr * op1) +{ + return eval_intrinsic_f2 (INTRINSIC_NOT, gfc_arith_not, op1, NULL); +} + +gfc_expr * +gfc_eqv (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_EQV, gfc_arith_eqv, op1, op2); +} + +gfc_expr * +gfc_neqv (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_NEQV, gfc_arith_neqv, op1, op2); +} + +gfc_expr * +gfc_eq (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_EQ, gfc_arith_eq, op1, op2); +} + +gfc_expr * +gfc_ne (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_NE, gfc_arith_ne, op1, op2); +} + +gfc_expr * +gfc_gt (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_GT, gfc_arith_gt, op1, op2); +} + +gfc_expr * +gfc_ge (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_GE, gfc_arith_ge, op1, op2); +} + +gfc_expr * +gfc_lt (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_LT, gfc_arith_lt, op1, op2); +} + +gfc_expr * +gfc_le (gfc_expr * op1, gfc_expr * op2) +{ + return eval_intrinsic_f3 (INTRINSIC_LE, gfc_arith_le, op1, op2); +} + + +/* Convert an integer string to an expression node. */ + +gfc_expr * +gfc_convert_integer (const char *buffer, int kind, int radix, locus * where) +{ + gfc_expr *e; + const char *t; + + e = gfc_constant_result (BT_INTEGER, kind, where); + /* a leading plus is allowed, but not by mpz_set_str */ + if (buffer[0] == '+') + t = buffer + 1; + else + t = buffer; + mpz_set_str (e->value.integer, t, radix); + + return e; +} + + +/* Convert a real string to an expression node. */ + +gfc_expr * +gfc_convert_real (const char *buffer, int kind, locus * where) +{ + gfc_expr *e; + const char *t; + + e = gfc_constant_result (BT_REAL, kind, where); + /* a leading plus is allowed, but not by mpf_set_str */ + if (buffer[0] == '+') + t = buffer + 1; + else + t = buffer; + mpf_set_str (e->value.real, t, 10); + + return e; +} + + +/* Convert a pair of real, constant expression nodes to a single + complex expression node. */ + +gfc_expr * +gfc_convert_complex (gfc_expr * real, gfc_expr * imag, int kind) +{ + gfc_expr *e; + + e = gfc_constant_result (BT_COMPLEX, kind, &real->where); + mpf_set (e->value.complex.r, real->value.real); + mpf_set (e->value.complex.i, imag->value.real); + + return e; +} + + +/******* Simplification of intrinsic functions with constant arguments *****/ + + +/* Deal with an arithmetic error. */ + +static void +arith_error (arith rc, gfc_typespec * from, gfc_typespec * to, locus * where) +{ + + gfc_error ("%s converting %s to %s at %L", gfc_arith_error (rc), + gfc_typename (from), gfc_typename (to), where); + + /* TODO: Do something about the error, ie underflow rounds to 0, + throw exception, return NaN, etc. */ +} + +/* Convert integers to integers. */ + +gfc_expr * +gfc_int2int (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_INTEGER, kind, &src->where); + + mpz_set (result->value.integer, src->value.integer); + + if ((rc = gfc_check_integer_range (result->value.integer, kind)) + != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert integers to reals. */ + +gfc_expr * +gfc_int2real (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_REAL, kind, &src->where); + + mpf_set_z (result->value.real, src->value.integer); + + if ((rc = gfc_check_real_range (result->value.real, kind)) != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert default integer to default complex. */ + +gfc_expr * +gfc_int2complex (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_COMPLEX, kind, &src->where); + + mpf_set_z (result->value.complex.r, src->value.integer); + mpf_set_ui (result->value.complex.i, 0); + + if ((rc = gfc_check_real_range (result->value.complex.i, kind)) != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert default real to default integer. */ + +gfc_expr * +gfc_real2int (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_INTEGER, kind, &src->where); + + mpz_set_f (result->value.integer, src->value.real); + + if ((rc = gfc_check_integer_range (result->value.integer, kind)) + != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert real to real. */ + +gfc_expr * +gfc_real2real (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_REAL, kind, &src->where); + + mpf_set (result->value.real, src->value.real); + + if ((rc = gfc_check_real_range (result->value.real, kind)) != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert real to complex. */ + +gfc_expr * +gfc_real2complex (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_COMPLEX, kind, &src->where); + + mpf_set (result->value.complex.r, src->value.real); + mpf_set_ui (result->value.complex.i, 0); + + if ((rc = gfc_check_real_range (result->value.complex.i, kind)) != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert complex to integer. */ + +gfc_expr * +gfc_complex2int (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_INTEGER, kind, &src->where); + + mpz_set_f (result->value.integer, src->value.complex.r); + + if ((rc = gfc_check_integer_range (result->value.integer, kind)) + != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert complex to real. */ + +gfc_expr * +gfc_complex2real (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_REAL, kind, &src->where); + + mpf_set (result->value.real, src->value.complex.r); + + if ((rc = gfc_check_real_range (result->value.real, kind)) != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Convert complex to complex. */ + +gfc_expr * +gfc_complex2complex (gfc_expr * src, int kind) +{ + gfc_expr *result; + arith rc; + + result = gfc_constant_result (BT_COMPLEX, kind, &src->where); + + mpf_set (result->value.complex.r, src->value.complex.r); + mpf_set (result->value.complex.i, src->value.complex.i); + + if ((rc = gfc_check_real_range (result->value.complex.r, kind)) != ARITH_OK + || (rc = + gfc_check_real_range (result->value.complex.i, kind)) != ARITH_OK) + { + arith_error (rc, &src->ts, &result->ts, &src->where); + gfc_free_expr (result); + return NULL; + } + + return result; +} + + +/* Logical kind conversion. */ + +gfc_expr * +gfc_log2log (gfc_expr * src, int kind) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_LOGICAL, kind, &src->where); + result->value.logical = src->value.logical; + + return result; +} diff --git a/gcc/fortran/arith.h b/gcc/fortran/arith.h new file mode 100644 index 00000000000..3e629eee57f --- /dev/null +++ b/gcc/fortran/arith.h @@ -0,0 +1,91 @@ +/* Compiler arithmetic header. + Copyright (C) 2000, 2001. 2002 Free Software Foundation, Inc. + Contributed by Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef GFC_ARITH_H +#define GFC_ARITH_H + +#include "gfortran.h" + +/* Constants calculated during initialization. */ +extern mpf_t pi, half_pi, two_pi, e; + +/* Calculate mathematically interesting functions. */ +void natural_logarithm (mpf_t *, mpf_t *); +void common_logarithm (mpf_t *, mpf_t *); +void exponential (mpf_t *, mpf_t *); +void sine (mpf_t *, mpf_t *); +void cosine (mpf_t *, mpf_t *); +void arctangent (mpf_t *, mpf_t *); +void arctangent2 (mpf_t *, mpf_t *, mpf_t *); +void hypercos (mpf_t *, mpf_t *); +void hypersine (mpf_t *, mpf_t *); + +/* Return a constant result of a given type and kind, with locus. */ +gfc_expr *gfc_constant_result (bt, int, locus *); + +/* Make sure a gfc_expr expression is within its allowed range. Checks + for overflow and underflow. */ +arith gfc_range_check (gfc_expr *); + +int gfc_compare_expr (gfc_expr *, gfc_expr *); +int gfc_compare_string (gfc_expr *, gfc_expr *, const int *); + +/* Constant folding for gfc_expr trees. */ +gfc_expr *gfc_uplus (gfc_expr * op); +gfc_expr *gfc_uminus (gfc_expr * op); +gfc_expr *gfc_add (gfc_expr *, gfc_expr *); +gfc_expr *gfc_subtract (gfc_expr *, gfc_expr *); +gfc_expr *gfc_multiply (gfc_expr *, gfc_expr *); +gfc_expr *gfc_divide (gfc_expr *, gfc_expr *); +gfc_expr *gfc_power (gfc_expr *, gfc_expr *); +gfc_expr *gfc_concat (gfc_expr *, gfc_expr *); +gfc_expr *gfc_and (gfc_expr *, gfc_expr *); +gfc_expr *gfc_or (gfc_expr *, gfc_expr *); +gfc_expr *gfc_not (gfc_expr *); +gfc_expr *gfc_eqv (gfc_expr *, gfc_expr *); +gfc_expr *gfc_neqv (gfc_expr *, gfc_expr *); +gfc_expr *gfc_eq (gfc_expr *, gfc_expr *); +gfc_expr *gfc_ne (gfc_expr *, gfc_expr *); +gfc_expr *gfc_gt (gfc_expr *, gfc_expr *); +gfc_expr *gfc_ge (gfc_expr *, gfc_expr *); +gfc_expr *gfc_lt (gfc_expr *, gfc_expr *); +gfc_expr *gfc_le (gfc_expr *, gfc_expr *); + +/* Convert strings to literal constants. */ +gfc_expr *gfc_convert_integer (const char *, int, int, locus *); +gfc_expr *gfc_convert_real (const char *, int, locus *); +gfc_expr *gfc_convert_complex (gfc_expr *, gfc_expr *, int); + +/* Convert a constant of one kind to another kind. */ +gfc_expr *gfc_int2int (gfc_expr *, int); +gfc_expr *gfc_int2real (gfc_expr *, int); +gfc_expr *gfc_int2complex (gfc_expr *, int); +gfc_expr *gfc_real2int (gfc_expr *, int); +gfc_expr *gfc_real2real (gfc_expr *, int); +gfc_expr *gfc_real2complex (gfc_expr *, int); +gfc_expr *gfc_complex2int (gfc_expr *, int); +gfc_expr *gfc_complex2real (gfc_expr *, int); +gfc_expr *gfc_complex2complex (gfc_expr *, int); +gfc_expr *gfc_log2log (gfc_expr *, int); + +#endif /* GFC_ARITH_H */ + diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c new file mode 100644 index 00000000000..6ab5f83b9a3 --- /dev/null +++ b/gcc/fortran/array.c @@ -0,0 +1,1973 @@ +/* Array things + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "gfortran.h" +#include "match.h" + +#include +#include + +/* This parameter is the size of the largest array constructor that we + will expand to an array constructor without iterators. + Constructors larger than this will remain in the iterator form. */ + +#define GFC_MAX_AC_EXPAND 100 + + +/**************** Array reference matching subroutines *****************/ + +/* Copy an array reference structure. */ + +gfc_array_ref * +gfc_copy_array_ref (gfc_array_ref * src) +{ + gfc_array_ref *dest; + int i; + + if (src == NULL) + return NULL; + + dest = gfc_get_array_ref (); + + *dest = *src; + + for (i = 0; i < GFC_MAX_DIMENSIONS; i++) + { + dest->start[i] = gfc_copy_expr (src->start[i]); + dest->end[i] = gfc_copy_expr (src->end[i]); + dest->stride[i] = gfc_copy_expr (src->stride[i]); + } + + dest->offset = gfc_copy_expr (src->offset); + + return dest; +} + + +/* Match a single dimension of an array reference. This can be a + single element or an array section. Any modifications we've made + to the ar structure are cleaned up by the caller. If the init + is set, we require the subscript to be a valid initialization + expression. */ + +static match +match_subscript (gfc_array_ref * ar, int init) +{ + match m; + int i; + + i = ar->dimen; + + ar->c_where[i] = *gfc_current_locus (); + ar->start[i] = ar->end[i] = ar->stride[i] = NULL; + + /* We can't be sure of the difference between DIMEN_ELEMENT and + DIMEN_VECTOR until we know the type of the element itself at + resolution time. */ + + ar->dimen_type[i] = DIMEN_UNKNOWN; + + if (gfc_match_char (':') == MATCH_YES) + goto end_element; + + /* Get start element. */ + if (init) + m = gfc_match_init_expr (&ar->start[i]); + else + m = gfc_match_expr (&ar->start[i]); + + if (m == MATCH_NO) + gfc_error ("Expected array subscript at %C"); + if (m != MATCH_YES) + return MATCH_ERROR; + + if (gfc_match_char (':') == MATCH_NO) + return MATCH_YES; + + /* Get an optional end element. Because we've seen the colon, we + definitely have a range along this dimension. */ +end_element: + ar->dimen_type[i] = DIMEN_RANGE; + + if (init) + m = gfc_match_init_expr (&ar->end[i]); + else + m = gfc_match_expr (&ar->end[i]); + + if (m == MATCH_ERROR) + return MATCH_ERROR; + + /* See if we have an optional stride. */ + if (gfc_match_char (':') == MATCH_YES) + { + m = init ? gfc_match_init_expr (&ar->stride[i]) + : gfc_match_expr (&ar->stride[i]); + + if (m == MATCH_NO) + gfc_error ("Expected array subscript stride at %C"); + if (m != MATCH_YES) + return MATCH_ERROR; + } + + return MATCH_YES; +} + + +/* Match an array reference, whether it is the whole array or a + particular elements or a section. If init is set, the reference has + to consist of init expressions. */ + +match +gfc_match_array_ref (gfc_array_ref * ar, gfc_array_spec * as, int init) +{ + match m; + + memset (ar, '\0', sizeof (ar)); + + ar->where = *gfc_current_locus (); + ar->as = as; + + if (gfc_match_char ('(') != MATCH_YES) + { + ar->type = AR_FULL; + ar->dimen = 0; + return MATCH_YES; + } + + ar->type = AR_UNKNOWN; + + for (ar->dimen = 0; ar->dimen < GFC_MAX_DIMENSIONS; ar->dimen++) + { + m = match_subscript (ar, init); + if (m == MATCH_ERROR) + goto error; + + if (gfc_match_char (')') == MATCH_YES) + goto matched; + + if (gfc_match_char (',') != MATCH_YES) + { + gfc_error ("Invalid form of array reference at %C"); + goto error; + } + } + + gfc_error ("Array reference at %C cannot have more than " + stringize (GFC_MAX_DIMENSIONS) " dimensions"); + +error: + return MATCH_ERROR; + +matched: + ar->dimen++; + + return MATCH_YES; +} + + +/************** Array specification matching subroutines ***************/ + +/* Free all of the expressions associated with array bounds + specifications. */ + +void +gfc_free_array_spec (gfc_array_spec * as) +{ + int i; + + if (as == NULL) + return; + + for (i = 0; i < as->rank; i++) + { + gfc_free_expr (as->lower[i]); + gfc_free_expr (as->upper[i]); + } + + gfc_free (as); +} + + +/* Take an array bound, resolves the expression, that make up the + shape and check associated constraints. */ + +static try +resolve_array_bound (gfc_expr * e, int check_constant) +{ + + if (e == NULL) + return SUCCESS; + + if (gfc_resolve_expr (e) == FAILURE + || gfc_specification_expr (e) == FAILURE) + return FAILURE; + + if (check_constant && gfc_is_constant_expr (e) == 0) + { + gfc_error ("Variable '%s' at %L in this context must be constant", + e->symtree->n.sym->name, &e->where); + return FAILURE; + } + + return SUCCESS; +} + + +/* Takes an array specification, resolves the expressions that make up + the shape and make sure everything is integral. */ + +try +gfc_resolve_array_spec (gfc_array_spec * as, int check_constant) +{ + gfc_expr *e; + int i; + + if (as == NULL) + return SUCCESS; + + for (i = 0; i < as->rank; i++) + { + e = as->lower[i]; + if (resolve_array_bound (e, check_constant) == FAILURE) + return FAILURE; + + e = as->upper[i]; + if (resolve_array_bound (e, check_constant) == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +/* Match a single array element specification. The return values as + well as the upper and lower bounds of the array spec are filled + in according to what we see on the input. The caller makes sure + individual specifications make sense as a whole. + + + Parsed Lower Upper Returned + ------------------------------------ + : NULL NULL AS_DEFERRED (*) + x 1 x AS_EXPLICIT + x: x NULL AS_ASSUMED_SHAPE + x:y x y AS_EXPLICIT + x:* x NULL AS_ASSUMED_SIZE + * 1 NULL AS_ASSUMED_SIZE + + (*) For non-pointer dummy arrays this is AS_ASSUMED_SHAPE. This + is fixed during the resolution of formal interfaces. + + Anything else AS_UNKNOWN. */ + +static array_type +match_array_element_spec (gfc_array_spec * as) +{ + gfc_expr **upper, **lower; + match m; + + lower = &as->lower[as->rank - 1]; + upper = &as->upper[as->rank - 1]; + + if (gfc_match_char ('*') == MATCH_YES) + { + *lower = gfc_int_expr (1); + return AS_ASSUMED_SIZE; + } + + if (gfc_match_char (':') == MATCH_YES) + return AS_DEFERRED; + + m = gfc_match_expr (upper); + if (m == MATCH_NO) + gfc_error ("Expected expression in array specification at %C"); + if (m != MATCH_YES) + return AS_UNKNOWN; + + if (gfc_match_char (':') == MATCH_NO) + { + *lower = gfc_int_expr (1); + return AS_EXPLICIT; + } + + *lower = *upper; + *upper = NULL; + + if (gfc_match_char ('*') == MATCH_YES) + return AS_ASSUMED_SIZE; + + m = gfc_match_expr (upper); + if (m == MATCH_ERROR) + return AS_UNKNOWN; + if (m == MATCH_NO) + return AS_ASSUMED_SHAPE; + + return AS_EXPLICIT; +} + + +/* Matches an array specification, incidentally figuring out what sort + it is. */ + +match +gfc_match_array_spec (gfc_array_spec ** asp) +{ + array_type current_type; + gfc_array_spec *as; + int i; + + if (gfc_match_char ('(') != MATCH_YES) + { + *asp = NULL; + return MATCH_NO; + } + + as = gfc_get_array_spec (); + + for (i = 0; i < GFC_MAX_DIMENSIONS; i++) + { + as->lower[i] = NULL; + as->upper[i] = NULL; + } + + as->rank = 1; + + for (;;) + { + current_type = match_array_element_spec (as); + + if (as->rank == 1) + { + if (current_type == AS_UNKNOWN) + goto cleanup; + as->type = current_type; + } + else + switch (as->type) + { /* See how current spec meshes with the existing */ + case AS_UNKNOWN: + goto cleanup; + + case AS_EXPLICIT: + if (current_type == AS_ASSUMED_SIZE) + { + as->type = AS_ASSUMED_SIZE; + break; + } + + if (current_type == AS_EXPLICIT) + break; + + gfc_error + ("Bad array specification for an explicitly shaped array" + " at %C"); + + goto cleanup; + + case AS_ASSUMED_SHAPE: + if ((current_type == AS_ASSUMED_SHAPE) + || (current_type == AS_DEFERRED)) + break; + + gfc_error + ("Bad array specification for assumed shape array at %C"); + goto cleanup; + + case AS_DEFERRED: + if (current_type == AS_DEFERRED) + break; + + if (current_type == AS_ASSUMED_SHAPE) + { + as->type = AS_ASSUMED_SHAPE; + break; + } + + gfc_error ("Bad specification for deferred shape array at %C"); + goto cleanup; + + case AS_ASSUMED_SIZE: + gfc_error ("Bad specification for assumed size array at %C"); + goto cleanup; + } + + if (gfc_match_char (')') == MATCH_YES) + break; + + if (gfc_match_char (',') != MATCH_YES) + { + gfc_error ("Expected another dimension in array declaration at %C"); + goto cleanup; + } + + if (as->rank >= GFC_MAX_DIMENSIONS) + { + gfc_error ("Array specification at %C has more than " + stringize (GFC_MAX_DIMENSIONS) " dimensions"); + goto cleanup; + } + + as->rank++; + } + + /* If a lower bounds of an assumed shape array is blank, put in one. */ + if (as->type == AS_ASSUMED_SHAPE) + { + for (i = 0; i < as->rank; i++) + { + if (as->lower[i] == NULL) + as->lower[i] = gfc_int_expr (1); + } + } + *asp = as; + return MATCH_YES; + +cleanup: + /* Something went wrong. */ + gfc_free_array_spec (as); + return MATCH_ERROR; +} + + +/* Given a symbol and an array specification, modify the symbol to + have that array specification. The error locus is needed in case + something goes wrong. On failure, the caller must free the spec. */ + +try +gfc_set_array_spec (gfc_symbol * sym, gfc_array_spec * as, locus * error_loc) +{ + + if (as == NULL) + return SUCCESS; + + if (gfc_add_dimension (&sym->attr, error_loc) == FAILURE) + return FAILURE; + + sym->as = as; + + return SUCCESS; +} + + +/* Copy an array specification. */ + +gfc_array_spec * +gfc_copy_array_spec (gfc_array_spec * src) +{ + gfc_array_spec *dest; + int i; + + if (src == NULL) + return NULL; + + dest = gfc_get_array_spec (); + + *dest = *src; + + for (i = 0; i < dest->rank; i++) + { + dest->lower[i] = gfc_copy_expr (dest->lower[i]); + dest->upper[i] = gfc_copy_expr (dest->upper[i]); + } + + return dest; +} + +/* Returns nonzero if the two expressions are equal. Only handles integer + constants. */ + +static int +compare_bounds (gfc_expr * bound1, gfc_expr * bound2) +{ + if (bound1 == NULL || bound2 == NULL + || bound1->expr_type != EXPR_CONSTANT + || bound2->expr_type != EXPR_CONSTANT + || bound1->ts.type != BT_INTEGER + || bound2->ts.type != BT_INTEGER) + gfc_internal_error ("gfc_compare_array_spec(): Array spec clobbered"); + + if (mpz_cmp (bound1->value.integer, bound2->value.integer) == 0) + return 1; + else + return 0; +} + +/* Compares two array specifications. They must be constant or deferred + shape. */ + +int +gfc_compare_array_spec (gfc_array_spec * as1, gfc_array_spec * as2) +{ + int i; + + if (as1 == NULL && as2 == NULL) + return 1; + + if (as1 == NULL || as2 == NULL) + return 0; + + if (as1->rank != as2->rank) + return 0; + + if (as1->rank == 0) + return 1; + + if (as1->type != as2->type) + return 0; + + if (as1->type == AS_EXPLICIT) + for (i = 0; i < as1->rank; i++) + { + if (compare_bounds (as1->lower[i], as2->lower[i]) == 0) + return 0; + + if (compare_bounds (as1->upper[i], as2->upper[i]) == 0) + return 0; + } + + return 1; +} + + +/****************** Array constructor functions ******************/ + +/* Start an array constructor. The constructor starts with zero + elements and should be appended to by gfc_append_constructor(). */ + +gfc_expr * +gfc_start_constructor (bt type, int kind, locus * where) +{ + gfc_expr *result; + + result = gfc_get_expr (); + + result->expr_type = EXPR_ARRAY; + result->rank = 1; + + result->ts.type = type; + result->ts.kind = kind; + result->where = *where; + return result; +} + + +/* Given an array constructor expression, append the new expression + node onto the constructor. */ + +void +gfc_append_constructor (gfc_expr * base, gfc_expr * new) +{ + gfc_constructor *c; + + if (base->value.constructor == NULL) + base->value.constructor = c = gfc_get_constructor (); + else + { + c = base->value.constructor; + while (c->next) + c = c->next; + + c->next = gfc_get_constructor (); + c = c->next; + } + + c->expr = new; + + if (new->ts.type != base->ts.type || new->ts.kind != base->ts.kind) + gfc_internal_error ("gfc_append_constructor(): New node has wrong kind"); +} + + +/* Given an array constructor expression, insert the new expression's + constructor onto the base's one according to the offset. */ + +void +gfc_insert_constructor (gfc_expr * base, gfc_constructor * c1) +{ + gfc_constructor *c, *pre; + expr_t type; + + type = base->expr_type; + + if (base->value.constructor == NULL) + base->value.constructor = c1; + else + { + c = pre = base->value.constructor; + while (c) + { + if (type == EXPR_ARRAY) + { + if (mpz_cmp (c->n.offset, c1->n.offset) < 0) + { + pre = c; + c = c->next; + } + else if (mpz_cmp (c->n.offset, c1->n.offset) == 0) + { + gfc_error ("duplicated initializer"); + break; + } + else + break; + } + else + { + pre = c; + c = c->next; + } + } + + if (pre != c) + { + pre->next = c1; + c1->next = c; + } + else + { + c1->next = c; + base->value.constructor = c1; + } + } +} + + +/* Get a new constructor. */ + +gfc_constructor * +gfc_get_constructor (void) +{ + gfc_constructor *c; + + c = gfc_getmem (sizeof(gfc_constructor)); + c->expr = NULL; + c->iterator = NULL; + c->next = NULL; + mpz_init_set_si (c->n.offset, 0); + mpz_init_set_si (c->repeat, 0); + return c; +} + + +/* Free chains of gfc_constructor structures. */ + +void +gfc_free_constructor (gfc_constructor * p) +{ + gfc_constructor *next; + + if (p == NULL) + return; + + for (; p; p = next) + { + next = p->next; + + if (p->expr) + gfc_free_expr (p->expr); + if (p->iterator != NULL) + gfc_free_iterator (p->iterator, 1); + mpz_clear (p->n.offset); + mpz_clear (p->repeat); + gfc_free (p); + } +} + + +/* Given an expression node that might be an array constructor and a + symbol, make sure that no iterators in this or child constructors + use the symbol as an implied-DO iterator. Returns nonzero if a + duplicate was found. */ + +static int +check_duplicate_iterator (gfc_constructor * c, gfc_symbol * master) +{ + gfc_expr *e; + + for (; c; c = c->next) + { + e = c->expr; + + if (e->expr_type == EXPR_ARRAY + && check_duplicate_iterator (e->value.constructor, master)) + return 1; + + if (c->iterator == NULL) + continue; + + if (c->iterator->var->symtree->n.sym == master) + { + gfc_error + ("DO-iterator '%s' at %L is inside iterator of the same name", + master->name, &c->where); + + return 1; + } + } + + return 0; +} + + +/* Forward declaration because these functions are mutually recursive. */ +static match match_array_cons_element (gfc_constructor **); + +/* Match a list of array elements. */ + +static match +match_array_list (gfc_constructor ** result) +{ + gfc_constructor *p, *head, *tail, *new; + gfc_iterator iter; + locus old_loc; + gfc_expr *e; + match m; + int n; + + old_loc = *gfc_current_locus (); + + if (gfc_match_char ('(') == MATCH_NO) + return MATCH_NO; + + memset (&iter, '\0', sizeof (gfc_iterator)); + head = NULL; + + m = match_array_cons_element (&head); + if (m != MATCH_YES) + goto cleanup; + + tail = head; + + if (gfc_match_char (',') != MATCH_YES) + { + m = MATCH_NO; + goto cleanup; + } + + for (n = 1;; n++) + { + m = gfc_match_iterator (&iter, 0); + if (m == MATCH_YES) + break; + if (m == MATCH_ERROR) + goto cleanup; + + m = match_array_cons_element (&new); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + if (n > 2) + goto syntax; + m = MATCH_NO; + goto cleanup; /* Could be a complex constant */ + } + + tail->next = new; + tail = new; + + if (gfc_match_char (',') != MATCH_YES) + { + if (n > 2) + goto syntax; + m = MATCH_NO; + goto cleanup; + } + } + + if (gfc_match_char (')') != MATCH_YES) + goto syntax; + + if (check_duplicate_iterator (head, iter.var->symtree->n.sym)) + { + m = MATCH_ERROR; + goto cleanup; + } + + e = gfc_get_expr (); + e->expr_type = EXPR_ARRAY; + e->where = old_loc; + e->value.constructor = head; + + p = gfc_get_constructor (); + p->where = *gfc_current_locus (); + p->iterator = gfc_get_iterator (); + *p->iterator = iter; + + p->expr = e; + *result = p; + + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in array constructor at %C"); + m = MATCH_ERROR; + +cleanup: + gfc_free_constructor (head); + gfc_free_iterator (&iter, 0); + gfc_set_locus (&old_loc); + return m; +} + + +/* Match a single element of an array constructor, which can be a + single expression or a list of elements. */ + +static match +match_array_cons_element (gfc_constructor ** result) +{ + gfc_constructor *p; + gfc_expr *expr; + match m; + + m = match_array_list (result); + if (m != MATCH_NO) + return m; + + m = gfc_match_expr (&expr); + if (m != MATCH_YES) + return m; + + p = gfc_get_constructor (); + p->where = *gfc_current_locus (); + p->expr = expr; + + *result = p; + return MATCH_YES; +} + + +/* Match an array constructor. */ + +match +gfc_match_array_constructor (gfc_expr ** result) +{ + gfc_constructor *head, *tail, *new; + gfc_expr *expr; + locus where; + match m; + + if (gfc_match (" (/") == MATCH_NO) + return MATCH_NO; + + where = *gfc_current_locus (); + head = tail = NULL; + + if (gfc_match (" /)") == MATCH_YES) + goto empty; /* Special case */ + + for (;;) + { + m = match_array_cons_element (&new); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + if (head == NULL) + head = new; + else + tail->next = new; + + tail = new; + + if (gfc_match_char (',') == MATCH_NO) + break; + } + + if (gfc_match (" /)") == MATCH_NO) + goto syntax; + +empty: + expr = gfc_get_expr (); + + expr->expr_type = EXPR_ARRAY; + + expr->value.constructor = head; + /* Size must be calculated at resolution time. */ + + expr->where = where; + expr->rank = 1; + + *result = expr; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in array constructor at %C"); + +cleanup: + gfc_free_constructor (head); + return MATCH_ERROR; +} + + + +/************** Check array constructors for correctness **************/ + +/* Given an expression, compare it's type with the type of the current + constructor. Returns nonzero if an error was issued. The + cons_state variable keeps track of whether the type of the + constructor being read or resolved is known to be good, bad or just + starting out. */ + +static gfc_typespec constructor_ts; +static enum +{ CONS_START, CONS_GOOD, CONS_BAD } +cons_state; + +static int +check_element_type (gfc_expr * expr) +{ + + if (cons_state == CONS_BAD) + return 0; /* Supress further errors */ + + if (cons_state == CONS_START) + { + if (expr->ts.type == BT_UNKNOWN) + cons_state = CONS_BAD; + else + { + cons_state = CONS_GOOD; + constructor_ts = expr->ts; + } + + return 0; + } + + if (gfc_compare_types (&constructor_ts, &expr->ts)) + return 0; + + gfc_error ("Element in %s array constructor at %L is %s", + gfc_typename (&constructor_ts), &expr->where, + gfc_typename (&expr->ts)); + + cons_state = CONS_BAD; + return 1; +} + + +/* Recursive work function for gfc_check_constructor_type(). */ + +static try +check_constructor_type (gfc_constructor * c) +{ + gfc_expr *e; + + for (; c; c = c->next) + { + e = c->expr; + + if (e->expr_type == EXPR_ARRAY) + { + if (check_constructor_type (e->value.constructor) == FAILURE) + return FAILURE; + + continue; + } + + if (check_element_type (e)) + return FAILURE; + } + + return SUCCESS; +} + + +/* Check that all elements of an array constructor are the same type. + On FAILURE, an error has been generated. */ + +try +gfc_check_constructor_type (gfc_expr * e) +{ + try t; + + cons_state = CONS_START; + gfc_clear_ts (&constructor_ts); + + t = check_constructor_type (e->value.constructor); + if (t == SUCCESS && e->ts.type == BT_UNKNOWN) + e->ts = constructor_ts; + + return t; +} + + + +typedef struct cons_stack +{ + gfc_iterator *iterator; + struct cons_stack *previous; +} +cons_stack; + +static cons_stack *base; + +static try check_constructor (gfc_constructor *, try (*)(gfc_expr *)); + +/* Check an EXPR_VARIABLE expression in a constructor to make sure + that that variable is an iteration variables. */ + +try +gfc_check_iter_variable (gfc_expr * expr) +{ + + gfc_symbol *sym; + cons_stack *c; + + sym = expr->symtree->n.sym; + + for (c = base; c; c = c->previous) + if (sym == c->iterator->var->symtree->n.sym) + return SUCCESS; + + return FAILURE; +} + + +/* Recursive work function for gfc_check_constructor(). This amounts + to calling the check function for each expression in the + constructor, giving variables with the names of iterators a pass. */ + +static try +check_constructor (gfc_constructor * c, try (*check_function) (gfc_expr *)) +{ + cons_stack element; + gfc_expr *e; + try t; + + for (; c; c = c->next) + { + e = c->expr; + + if (e->expr_type != EXPR_ARRAY) + { + if ((*check_function) (e) == FAILURE) + return FAILURE; + continue; + } + + element.previous = base; + element.iterator = c->iterator; + + base = &element; + t = check_constructor (e->value.constructor, check_function); + base = element.previous; + + if (t == FAILURE) + return FAILURE; + } + + /* Nothing went wrong, so all OK. */ + return SUCCESS; +} + + +/* Checks a constructor to see if it is a particular kind of + expression -- specification, restricted, or initialization as + determined by the check_function. */ + +try +gfc_check_constructor (gfc_expr * expr, try (*check_function) (gfc_expr *)) +{ + cons_stack *base_save; + try t; + + base_save = base; + base = NULL; + + t = check_constructor (expr->value.constructor, check_function); + base = base_save; + + return t; +} + + + +/**************** Simplification of array constructors ****************/ + +iterator_stack *iter_stack; + +typedef struct +{ + gfc_constructor *new_head, *new_tail; + int extract_count, extract_n; + gfc_expr *extracted; + mpz_t *count; + + mpz_t *offset; + gfc_component *component; + mpz_t *repeat; + + try (*expand_work_function) (gfc_expr *); +} +expand_info; + +static expand_info current_expand; + +static try expand_constructor (gfc_constructor *); + + +/* Work function that counts the number of elements present in a + constructor. */ + +static try +count_elements (gfc_expr * e) +{ + mpz_t result; + + if (e->rank == 0) + mpz_add_ui (*current_expand.count, *current_expand.count, 1); + else + { + if (gfc_array_size (e, &result) == FAILURE) + { + gfc_free_expr (e); + return FAILURE; + } + + mpz_add (*current_expand.count, *current_expand.count, result); + mpz_clear (result); + } + + gfc_free_expr (e); + return SUCCESS; +} + + +/* Work function that extracts a particular element from an array + constructor, freeing the rest. */ + +static try +extract_element (gfc_expr * e) +{ + + if (e->rank != 0) + { /* Something unextractable */ + gfc_free_expr (e); + return FAILURE; + } + + if (current_expand.extract_count == current_expand.extract_n) + current_expand.extracted = e; + else + gfc_free_expr (e); + + current_expand.extract_count++; + return SUCCESS; +} + + +/* Work function that constructs a new constructor out of the old one, + stringing new elements together. */ + +static try +expand (gfc_expr * e) +{ + + if (current_expand.new_head == NULL) + current_expand.new_head = current_expand.new_tail = + gfc_get_constructor (); + else + { + current_expand.new_tail->next = gfc_get_constructor (); + current_expand.new_tail = current_expand.new_tail->next; + } + + current_expand.new_tail->where = e->where; + current_expand.new_tail->expr = e; + + mpz_set (current_expand.new_tail->n.offset, *current_expand.offset); + current_expand.new_tail->n.component = current_expand.component; + mpz_set (current_expand.new_tail->repeat, *current_expand.repeat); + return SUCCESS; +} + + +/* Given an initialization expression that is a variable reference, + substitute the current value of the iteration variable. */ + +void +gfc_simplify_iterator_var (gfc_expr * e) +{ + iterator_stack *p; + + for (p = iter_stack; p; p = p->prev) + if (e->symtree == p->variable) + break; + + if (p == NULL) + return; /* Variable not found */ + + gfc_replace_expr (e, gfc_int_expr (0)); + + mpz_set (e->value.integer, p->value); + + return; +} + + +/* Expand an expression with that is inside of a constructor, + recursing into other constructors if present. */ + +static try +expand_expr (gfc_expr * e) +{ + + if (e->expr_type == EXPR_ARRAY) + return expand_constructor (e->value.constructor); + + e = gfc_copy_expr (e); + + if (gfc_simplify_expr (e, 1) == FAILURE) + { + gfc_free_expr (e); + return FAILURE; + } + + return current_expand.expand_work_function (e); +} + + +static try +expand_iterator (gfc_constructor * c) +{ + gfc_expr *start, *end, *step; + iterator_stack frame; + mpz_t trip; + try t; + + end = step = NULL; + + t = FAILURE; + + mpz_init (trip); + mpz_init (frame.value); + + start = gfc_copy_expr (c->iterator->start); + if (gfc_simplify_expr (start, 1) == FAILURE) + goto cleanup; + + if (start->expr_type != EXPR_CONSTANT || start->ts.type != BT_INTEGER) + goto cleanup; + + end = gfc_copy_expr (c->iterator->end); + if (gfc_simplify_expr (end, 1) == FAILURE) + goto cleanup; + + if (end->expr_type != EXPR_CONSTANT || end->ts.type != BT_INTEGER) + goto cleanup; + + step = gfc_copy_expr (c->iterator->step); + if (gfc_simplify_expr (step, 1) == FAILURE) + goto cleanup; + + if (step->expr_type != EXPR_CONSTANT || step->ts.type != BT_INTEGER) + goto cleanup; + + if (mpz_sgn (step->value.integer) == 0) + { + gfc_error ("Iterator step at %L cannot be zero", &step->where); + goto cleanup; + } + + /* Calculate the trip count of the loop. */ + mpz_sub (trip, end->value.integer, start->value.integer); + mpz_add (trip, trip, step->value.integer); + mpz_tdiv_q (trip, trip, step->value.integer); + + mpz_set (frame.value, start->value.integer); + + frame.prev = iter_stack; + frame.variable = c->iterator->var->symtree; + iter_stack = &frame; + + while (mpz_sgn (trip) > 0) + { + if (expand_expr (c->expr) == FAILURE) + goto cleanup; + + mpz_add (frame.value, frame.value, step->value.integer); + mpz_sub_ui (trip, trip, 1); + } + + t = SUCCESS; + +cleanup: + gfc_free_expr (start); + gfc_free_expr (end); + gfc_free_expr (step); + + mpz_clear (trip); + mpz_clear (frame.value); + + iter_stack = frame.prev; + + return t; +} + + +/* Expand a constructor into constant constructors without any + iterators, calling the work function for each of the expanded + expressions. The work function needs to either save or free the + passed expression. */ + +static try +expand_constructor (gfc_constructor * c) +{ + gfc_expr *e; + + for (; c; c = c->next) + { + if (c->iterator != NULL) + { + if (expand_iterator (c) == FAILURE) + return FAILURE; + continue; + } + + e = c->expr; + + if (e->expr_type == EXPR_ARRAY) + { + if (expand_constructor (e->value.constructor) == FAILURE) + return FAILURE; + + continue; + } + + e = gfc_copy_expr (e); + if (gfc_simplify_expr (e, 1) == FAILURE) + { + gfc_free_expr (e); + return FAILURE; + } + current_expand.offset = &c->n.offset; + current_expand.component = c->n.component; + current_expand.repeat = &c->repeat; + if (current_expand.expand_work_function (e) == FAILURE) + return FAILURE; + } + return SUCCESS; +} + + +/* Top level subroutine for expanding constructors. We only expand + constructor if they are small enough. */ + +try +gfc_expand_constructor (gfc_expr * e) +{ + expand_info expand_save; + gfc_expr *f; + try rc; + + f = gfc_get_array_element (e, GFC_MAX_AC_EXPAND); + if (f != NULL) + { + gfc_free_expr (f); + return SUCCESS; + } + + expand_save = current_expand; + current_expand.new_head = current_expand.new_tail = NULL; + + iter_stack = NULL; + + current_expand.expand_work_function = expand; + + if (expand_constructor (e->value.constructor) == FAILURE) + { + gfc_free_constructor (current_expand.new_head); + rc = FAILURE; + goto done; + } + + gfc_free_constructor (e->value.constructor); + e->value.constructor = current_expand.new_head; + + rc = SUCCESS; + +done: + current_expand = expand_save; + + return rc; +} + + +/* Work function for checking that an element of a constructor is a + constant, after removal of any iteration variables. We return + FAILURE if not so. */ + +static try +constant_element (gfc_expr * e) +{ + int rv; + + rv = gfc_is_constant_expr (e); + gfc_free_expr (e); + + return rv ? SUCCESS : FAILURE; +} + + +/* Given an array constructor, determine if the constructor is + constant or not by expanding it and making sure that all elements + are constants. This is a bit of a hack since something like (/ (i, + i=1,100000000) /) will take a while as* opposed to a more clever + function that traverses the expression tree. FIXME. */ + +int +gfc_constant_ac (gfc_expr * e) +{ + expand_info expand_save; + try rc; + + iter_stack = NULL; + expand_save = current_expand; + current_expand.expand_work_function = constant_element; + + rc = expand_constructor (e->value.constructor); + + current_expand = expand_save; + if (rc == FAILURE) + return 0; + + return 1; +} + + +/* Returns nonzero if an array constructor has been completely + expanded (no iterators) and zero if iterators are present. */ + +int +gfc_expanded_ac (gfc_expr * e) +{ + gfc_constructor *p; + + if (e->expr_type == EXPR_ARRAY) + for (p = e->value.constructor; p; p = p->next) + if (p->iterator != NULL || !gfc_expanded_ac (p->expr)) + return 0; + + return 1; +} + + +/*************** Type resolution of array constructors ***************/ + +/* Recursive array list resolution function. All of the elements must + be of the same type. */ + +static try +resolve_array_list (gfc_constructor * p) +{ + try t; + + t = SUCCESS; + + for (; p; p = p->next) + { + if (p->iterator != NULL + && gfc_resolve_iterator (p->iterator) == FAILURE) + t = FAILURE; + + if (gfc_resolve_expr (p->expr) == FAILURE) + t = FAILURE; + } + + return t; +} + + +/* Resolve all of the expressions in an array list. + TODO: String lengths. */ + +try +gfc_resolve_array_constructor (gfc_expr * expr) +{ + try t; + + t = resolve_array_list (expr->value.constructor); + if (t == SUCCESS) + t = gfc_check_constructor_type (expr); + + return t; +} + + +/* Copy an iterator structure. */ + +static gfc_iterator * +copy_iterator (gfc_iterator * src) +{ + gfc_iterator *dest; + + if (src == NULL) + return NULL; + + dest = gfc_get_iterator (); + + dest->var = gfc_copy_expr (src->var); + dest->start = gfc_copy_expr (src->start); + dest->end = gfc_copy_expr (src->end); + dest->step = gfc_copy_expr (src->step); + + return dest; +} + + +/* Copy a constructor structure. */ + +gfc_constructor * +gfc_copy_constructor (gfc_constructor * src) +{ + gfc_constructor *dest; + gfc_constructor *tail; + + if (src == NULL) + return NULL; + + dest = tail = NULL; + while (src) + { + if (dest == NULL) + dest = tail = gfc_get_constructor (); + else + { + tail->next = gfc_get_constructor (); + tail = tail->next; + } + tail->where = src->where; + tail->expr = gfc_copy_expr (src->expr); + tail->iterator = copy_iterator (src->iterator); + mpz_set (tail->n.offset, src->n.offset); + tail->n.component = src->n.component; + mpz_set (tail->repeat, src->repeat); + src = src->next; + } + + return dest; +} + + +/* Given an array expression and an element number (starting at zero), + return a pointer to the array element. NULL is returned if the + size of the array has been exceeded. The expression node returned + remains a part of the array and should not be freed. Access is not + efficient at all, but this is another place where things do not + have to be particularly fast. */ + +gfc_expr * +gfc_get_array_element (gfc_expr * array, int element) +{ + expand_info expand_save; + gfc_expr *e; + try rc; + + expand_save = current_expand; + current_expand.extract_n = element; + current_expand.expand_work_function = extract_element; + current_expand.extracted = NULL; + current_expand.extract_count = 0; + + iter_stack = NULL; + + rc = expand_constructor (array->value.constructor); + e = current_expand.extracted; + current_expand = expand_save; + + if (rc == FAILURE) + return NULL; + + return e; +} + + +/********* Subroutines for determining the size of an array *********/ + +/* These are needed just to accomodate RESHAPE(). There are no + diagnostics here, we just return a negative number if something + goes wrong. */ + + +/* Get the size of single dimension of an array specification. The + array is guaranteed to be one dimensional. */ + +static try +spec_dimen_size (gfc_array_spec * as, int dimen, mpz_t * result) +{ + + if (as == NULL) + return FAILURE; + + if (dimen < 0 || dimen > as->rank - 1) + gfc_internal_error ("spec_dimen_size(): Bad dimension"); + + if (as->type != AS_EXPLICIT + || as->lower[dimen]->expr_type != EXPR_CONSTANT + || as->upper[dimen]->expr_type != EXPR_CONSTANT) + return FAILURE; + + mpz_init (*result); + + mpz_sub (*result, as->upper[dimen]->value.integer, + as->lower[dimen]->value.integer); + + mpz_add_ui (*result, *result, 1); + + return SUCCESS; +} + + +try +spec_size (gfc_array_spec * as, mpz_t * result) +{ + mpz_t size; + int d; + + mpz_init_set_ui (*result, 1); + + for (d = 0; d < as->rank; d++) + { + if (spec_dimen_size (as, d, &size) == FAILURE) + { + mpz_clear (*result); + return FAILURE; + } + + mpz_mul (*result, *result, size); + mpz_clear (size); + } + + return SUCCESS; +} + + +/* Get the number of elements in an array section. */ + +static try +ref_dimen_size (gfc_array_ref * ar, int dimen, mpz_t * result) +{ + mpz_t upper, lower, stride; + try t; + + if (dimen < 0 || ar == NULL || dimen > ar->dimen - 1) + gfc_internal_error ("ref_dimen_size(): Bad dimension"); + + switch (ar->dimen_type[dimen]) + { + case DIMEN_ELEMENT: + mpz_init (*result); + mpz_set_ui (*result, 1); + t = SUCCESS; + break; + + case DIMEN_VECTOR: + t = gfc_array_size (ar->start[dimen], result); /* Recurse! */ + break; + + case DIMEN_RANGE: + mpz_init (upper); + mpz_init (lower); + mpz_init (stride); + t = FAILURE; + + if (ar->start[dimen] == NULL) + { + if (ar->as->lower[dimen] == NULL + || ar->as->lower[dimen]->expr_type != EXPR_CONSTANT) + goto cleanup; + mpz_set (lower, ar->as->lower[dimen]->value.integer); + } + else + { + if (ar->start[dimen]->expr_type != EXPR_CONSTANT) + goto cleanup; + mpz_set (lower, ar->start[dimen]->value.integer); + } + + if (ar->end[dimen] == NULL) + { + if (ar->as->upper[dimen] == NULL + || ar->as->upper[dimen]->expr_type != EXPR_CONSTANT) + goto cleanup; + mpz_set (upper, ar->as->upper[dimen]->value.integer); + } + else + { + if (ar->end[dimen]->expr_type != EXPR_CONSTANT) + goto cleanup; + mpz_set (upper, ar->end[dimen]->value.integer); + } + + if (ar->stride[dimen] == NULL) + mpz_set_ui (stride, 1); + else + { + if (ar->stride[dimen]->expr_type != EXPR_CONSTANT) + goto cleanup; + mpz_set (stride, ar->stride[dimen]->value.integer); + } + + mpz_init (*result); + mpz_sub (*result, upper, lower); + mpz_add (*result, *result, stride); + mpz_div (*result, *result, stride); + + /* Zero stride caught earlier. */ + if (mpz_cmp_ui (*result, 0) < 0) + mpz_set_ui (*result, 0); + t = SUCCESS; + + cleanup: + mpz_clear (upper); + mpz_clear (lower); + mpz_clear (stride); + return t; + + default: + gfc_internal_error ("ref_dimen_size(): Bad dimen_type"); + } + + return t; +} + + +static try +ref_size (gfc_array_ref * ar, mpz_t * result) +{ + mpz_t size; + int d; + + mpz_init_set_ui (*result, 1); + + for (d = 0; d < ar->dimen; d++) + { + if (ref_dimen_size (ar, d, &size) == FAILURE) + { + mpz_clear (*result); + return FAILURE; + } + + mpz_mul (*result, *result, size); + mpz_clear (size); + } + + return SUCCESS; +} + + +/* Given an array expression and a dimension, figure out how many + elements it has along that dimension. Returns SUCCESS if we were + able to return a result in the 'result' variable, FAILURE + otherwise. */ + +try +gfc_array_dimen_size (gfc_expr * array, int dimen, mpz_t * result) +{ + gfc_ref *ref; + int i; + + if (dimen < 0 || array == NULL || dimen > array->rank - 1) + gfc_internal_error ("gfc_array_dimen_size(): Bad dimension"); + + switch (array->expr_type) + { + case EXPR_VARIABLE: + case EXPR_FUNCTION: + for (ref = array->ref; ref; ref = ref->next) + { + if (ref->type != REF_ARRAY) + continue; + + if (ref->u.ar.type == AR_FULL) + return spec_dimen_size (ref->u.ar.as, dimen, result); + + if (ref->u.ar.type == AR_SECTION) + { + for (i = 0; dimen >= 0; i++) + if (ref->u.ar.dimen_type[i] != DIMEN_ELEMENT) + dimen--; + + return ref_dimen_size (&ref->u.ar, i - 1, result); + } + } + + if (spec_dimen_size (array->symtree->n.sym->as, dimen, result) == FAILURE) + return FAILURE; + + break; + + case EXPR_ARRAY: + if (array->shape == NULL) { + /* Expressions with rank > 1 should have "shape" properly set */ + if ( array->rank != 1 ) + gfc_internal_error ("gfc_array_dimen_size(): Bad EXPR_ARRAY expr"); + return gfc_array_size(array, result); + } + + /* Fall through */ + default: + if (array->shape == NULL) + return FAILURE; + + mpz_init_set (*result, array->shape[dimen]); + + break; + } + + return SUCCESS; +} + + +/* Given an array expression, figure out how many elements are in the + array. Returns SUCCESS if this is possible, and sets the 'result' + variable. Otherwise returns FAILURE. */ + +try +gfc_array_size (gfc_expr * array, mpz_t * result) +{ + expand_info expand_save; + gfc_ref *ref; + int i, flag; + try t; + + switch (array->expr_type) + { + case EXPR_ARRAY: + flag = gfc_suppress_error; + gfc_suppress_error = 1; + + expand_save = current_expand; + + current_expand.count = result; + mpz_init_set_ui (*result, 0); + + current_expand.expand_work_function = count_elements; + iter_stack = NULL; + + t = expand_constructor (array->value.constructor); + gfc_suppress_error = flag; + + if (t == FAILURE) + mpz_clear (*result); + current_expand = expand_save; + return t; + + case EXPR_VARIABLE: + for (ref = array->ref; ref; ref = ref->next) + { + if (ref->type != REF_ARRAY) + continue; + + if (ref->u.ar.type == AR_FULL) + return spec_size (ref->u.ar.as, result); + + if (ref->u.ar.type == AR_SECTION) + return ref_size (&ref->u.ar, result); + } + + return spec_size (array->symtree->n.sym->as, result); + + + default: + if (array->rank == 0 || array->shape == NULL) + return FAILURE; + + mpz_init_set_ui (*result, 1); + + for (i = 0; i < array->rank; i++) + mpz_mul (*result, *result, array->shape[i]); + + break; + } + + return SUCCESS; +} + + +/* Given an array reference, return the shape of the reference in an + array of mpz_t integers. */ + +try +gfc_array_ref_shape (gfc_array_ref * ar, mpz_t * shape) +{ + int d; + int i; + + d = 0; + + switch (ar->type) + { + case AR_FULL: + for (; d < ar->as->rank; d++) + if (spec_dimen_size (ar->as, d, &shape[d]) == FAILURE) + goto cleanup; + + return SUCCESS; + + case AR_SECTION: + for (i = 0; i < ar->dimen; i++) + { + if (ar->dimen_type[i] != DIMEN_ELEMENT) + { + if (ref_dimen_size (ar, i, &shape[d]) == FAILURE) + goto cleanup; + d++; + } + } + + return SUCCESS; + + default: + break; + } + +cleanup: + for (d--; d >= 0; d--) + mpz_clear (shape[d]); + + return FAILURE; +} + + +/* Given an array expression, find the array reference structure that + characterizes the reference. */ + +gfc_array_ref * +gfc_find_array_ref (gfc_expr * e) +{ + gfc_ref *ref; + + for (ref = e->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY + && (ref->u.ar.type == AR_FULL + || ref->u.ar.type == AR_SECTION)) + break; + + if (ref == NULL) + gfc_internal_error ("gfc_find_array_ref(): No ref found"); + + return &ref->u.ar; +} diff --git a/gcc/fortran/bbt.c b/gcc/fortran/bbt.c new file mode 100644 index 00000000000..5846ccd4d39 --- /dev/null +++ b/gcc/fortran/bbt.c @@ -0,0 +1,201 @@ +/* Balanced binary trees using treaps. + Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* The idea is to balance the tree using pseudorandom numbers. The + main constraint on this implementation is that we have several + distinct structures that have to be arranged in a binary tree. + These structures all contain a BBT_HEADER() in front that gives the + treap-related information. The key and value are assumed to reside + in the rest of the structure. + + When calling, we are also passed a comparison function that + compares two nodes. We don't implement a separate 'find' function + here, but rather use separate functions for each variety of tree. + We are also restricted to not copy treap structures, which most + implementations find convenient, because we otherwise would need to + know how long the structure is. + + This implementation is based on Stefan Nilsson's article in the + July 1997 Doctor Dobb's Journal, "Treaps in Java". */ + +#include "config.h" +#include "gfortran.h" + +typedef struct gfc_treap +{ + BBT_HEADER (gfc_treap); +} +gfc_bbt; + +/* Simple linear congruential pseudorandom number generator. The + period of this generator is 44071, which is plenty for our + purposes. */ + +static int +pseudo_random (void) +{ + static int x0 = 5341; + + x0 = (22611 * x0 + 10) % 44071; + return x0; +} + + +/* Rotate the treap left. */ + +static gfc_bbt * +rotate_left (gfc_bbt * t) +{ + gfc_bbt *temp; + + temp = t->right; + t->right = t->right->left; + temp->left = t; + + return temp; +} + + +/* Rotate the treap right. */ + +static gfc_bbt * +rotate_right (gfc_bbt * t) +{ + gfc_bbt *temp; + + temp = t->left; + t->left = t->left->right; + temp->right = t; + + return temp; +} + + +/* Recursive insertion function. Returns the updated treap, or + aborts if we find a duplicate key. */ + +static gfc_bbt * +insert (gfc_bbt * new, gfc_bbt * t, compare_fn compare) +{ + int c; + + if (t == NULL) + return new; + + c = (*compare) (new, t); + + if (c < 0) + { + t->left = insert (new, t->left, compare); + if (t->priority < t->left->priority) + t = rotate_right (t); + } + + else if (c > 0) + { + t->right = insert (new, t->right, compare); + if (t->priority < t->right->priority) + t = rotate_left (t); + } + + else /* if (c == 0) */ + gfc_internal_error("insert_bbt(): Duplicate key found!"); + + return t; +} + + +/* Given root pointer, a new node and a comparison function, insert + the new node into the treap. It is an error to insert a key that + already exists. */ + +void +gfc_insert_bbt (void *root, void *new, compare_fn compare) +{ + gfc_bbt **r, *n; + + r = (gfc_bbt **) root; + n = (gfc_bbt *) new; + + n->priority = pseudo_random (); + *r = insert (n, *r, compare); +} + +static gfc_bbt * +delete_root (gfc_bbt * t) +{ + gfc_bbt *temp; + + if (t->left == NULL) + return t->right; + if (t->right == NULL) + return t->left; + + if (t->left->priority > t->right->priority) + { + temp = rotate_right (t); + temp->right = delete_root (t); + } + else + { + temp = rotate_left (t); + temp->left = delete_root (t); + } + + return temp; +} + + +/* Delete an element from a tree. The 'old' value does not + necessarily have to point to the element to be deleted, it must + just point to a treap structure with the key to be deleted. + Returns the new root node of the tree. */ + +static gfc_bbt * +delete_treap (gfc_bbt * old, gfc_bbt * t, compare_fn compare) +{ + int c; + + if (t == NULL) + return NULL; + + c = (*compare) (old, t); + + if (c < 0) + t->left = delete_treap (old, t->left, compare); + if (c > 0) + t->right = delete_treap (old, t->right, compare); + if (c == 0) + t = delete_root (t); + + return t; +} + + +void +gfc_delete_bbt (void *root, void *old, compare_fn compare) +{ + gfc_bbt **t; + + t = (gfc_bbt **) root; + + *t = delete_treap ((gfc_bbt *) old, *t, compare); +} diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c new file mode 100644 index 00000000000..e37964df85d --- /dev/null +++ b/gcc/fortran/check.c @@ -0,0 +1,1866 @@ +/* Check functions + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught & Katherine Holcomb + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* These functions check to see if an argument list is compatible with + a particular intrinsic function or subroutine. Presence of + required arguments has already been established, the argument list + has been sorted into the right order and has NULL arguments in the + correct places for missing optional arguments. */ + + +#include +#include + +#include "config.h" +#include "system.h" +#include "flags.h" +#include "gfortran.h" +#include "intrinsic.h" + + +/* The fundamental complaint function of this source file. This + function can be called in all kinds of ways. */ + +static void +must_be (gfc_expr * e, int n, const char *thing) +{ + + gfc_error ("'%s' argument of '%s' intrinsic at %L must be %s", + gfc_current_intrinsic_arg[n], gfc_current_intrinsic, &e->where, + thing); +} + + +/* Check the type of an expression. */ + +static try +type_check (gfc_expr * e, int n, bt type) +{ + + if (e->ts.type == type) + return SUCCESS; + + must_be (e, n, gfc_basic_typename (type)); + + return FAILURE; +} + + +/* Check that the expression is a numeric type. */ + +static try +numeric_check (gfc_expr * e, int n) +{ + + if (gfc_numeric_ts (&e->ts)) + return SUCCESS; + + must_be (e, n, "a numeric type"); + + return FAILURE; +} + + +/* Check that an expression is integer or real. */ + +static try +int_or_real_check (gfc_expr * e, int n) +{ + + if (e->ts.type != BT_INTEGER && e->ts.type != BT_REAL) + { + must_be (e, n, "INTEGER or REAL"); + return FAILURE; + } + + return SUCCESS; +} + + +/* Check that the expression is an optional constant integer + and that it specifies a valid kind for that type. */ + +static try +kind_check (gfc_expr * k, int n, bt type) +{ + int kind; + + if (k == NULL) + return SUCCESS; + + if (type_check (k, n, BT_INTEGER) == FAILURE) + return FAILURE; + + if (k->expr_type != EXPR_CONSTANT) + { + must_be (k, n, "a constant"); + return FAILURE; + } + + if (gfc_extract_int (k, &kind) != NULL + || gfc_validate_kind (type, kind) == -1) + { + gfc_error ("Invalid kind for %s at %L", gfc_basic_typename (type), + &k->where); + return FAILURE; + } + + return SUCCESS; +} + + +/* Make sure the expression is a double precision real. */ + +static try +double_check (gfc_expr * d, int n) +{ + + if (type_check (d, n, BT_REAL) == FAILURE) + return FAILURE; + + if (d->ts.kind != gfc_default_double_kind ()) + { + must_be (d, n, "double precision"); + return FAILURE; + } + + return SUCCESS; +} + + +/* Make sure the expression is a logical array. */ + +static try +logical_array_check (gfc_expr * array, int n) +{ + + if (array->ts.type != BT_LOGICAL || array->rank == 0) + { + must_be (array, n, "a logical array"); + return FAILURE; + } + + return SUCCESS; +} + + +/* Make sure an expression is an array. */ + +static try +array_check (gfc_expr * e, int n) +{ + + if (e->rank != 0) + return SUCCESS; + + must_be (e, n, "an array"); + + return FAILURE; +} + + +/* Make sure an expression is a scalar. */ + +static try +scalar_check (gfc_expr * e, int n) +{ + + if (e->rank == 0) + return SUCCESS; + + must_be (e, n, "a scalar"); + + return FAILURE; +} + + +/* Make sure two expression have the same type. */ + +static try +same_type_check (gfc_expr * e, int n, gfc_expr * f, int m) +{ + char message[100]; + + if (gfc_compare_types (&e->ts, &f->ts)) + return SUCCESS; + + sprintf (message, "the same type and kind as '%s'", + gfc_current_intrinsic_arg[n]); + + must_be (f, m, message); + + return FAILURE; +} + + +/* Make sure that an expression has a certain (nonzero) rank. */ + +static try +rank_check (gfc_expr * e, int n, int rank) +{ + char message[100]; + + if (e->rank == rank) + return SUCCESS; + + sprintf (message, "of rank %d", rank); + + must_be (e, n, message); + + return FAILURE; +} + + +/* Make sure a variable expression is not an optional dummy argument. */ + +static try +nonoptional_check (gfc_expr * e, int n) +{ + + if (e->expr_type == EXPR_VARIABLE && e->symtree->n.sym->attr.optional) + { + gfc_error ("'%s' argument of '%s' intrinsic at %L must not be OPTIONAL", + gfc_current_intrinsic_arg[n], gfc_current_intrinsic, + &e->where); + + } + + /* TODO: Recursive check on nonoptional variables? */ + + return SUCCESS; +} + + +/* Check that an expression has a particular kind. */ + +static try +kind_value_check (gfc_expr * e, int n, int k) +{ + char message[100]; + + if (e->ts.kind == k) + return SUCCESS; + + sprintf (message, "of kind %d", k); + + must_be (e, n, message); + return FAILURE; +} + + +/* Make sure an expression is a variable. */ + +static try +variable_check (gfc_expr * e, int n) +{ + + if ((e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.flavor != FL_PARAMETER) + || (e->expr_type == EXPR_FUNCTION + && e->symtree->n.sym->result == e->symtree->n.sym)) + return SUCCESS; + + if (e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error ("'%s' argument of '%s' intrinsic at %L cannot be INTENT(IN)", + gfc_current_intrinsic_arg[n], gfc_current_intrinsic, + &e->where); + return FAILURE; + } + + must_be (e, n, "a variable"); + + return FAILURE; +} + + +/* Check the common DIM parameter for correctness. */ + +static try +dim_check (gfc_expr * dim, int n, int optional) +{ + + if (optional) + { + if (dim == NULL) + return SUCCESS; + + if (nonoptional_check (dim, n) == FAILURE) + return FAILURE; + + return SUCCESS; + } + + if (dim == NULL) + { + gfc_error ("Missing DIM parameter in intrinsic '%s' at %L", + gfc_current_intrinsic, gfc_current_intrinsic_where); + return FAILURE; + } + + if (type_check (dim, n, BT_INTEGER) == FAILURE) + return FAILURE; + + if (scalar_check (dim, n) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* If a DIM parameter is a constant, make sure that it is greater than + zero and less than or equal to the rank of the given array. If + allow_assumed is zero then dim must be less than the rank of the array + for assumed size arrays. */ + +static try +dim_rank_check (gfc_expr * dim, gfc_expr * array, int allow_assumed) +{ + gfc_array_ref *ar; + int rank; + + if (dim->expr_type != EXPR_CONSTANT || array->expr_type != EXPR_VARIABLE) + return SUCCESS; + + ar = gfc_find_array_ref (array); + rank = array->rank; + if (ar->as->type == AS_ASSUMED_SIZE && !allow_assumed) + rank--; + + if (mpz_cmp_ui (dim->value.integer, 1) < 0 + || mpz_cmp_ui (dim->value.integer, rank) > 0) + { + gfc_error ("'dim' argument of '%s' intrinsic at %L is not a valid " + "dimension index", gfc_current_intrinsic, &dim->where); + + return FAILURE; + } + + return SUCCESS; +} + + +/***** Check functions *****/ + +/* Check subroutine suitable for intrinsics taking a real argument and + a kind argument for the result. */ + +static try +check_a_kind (gfc_expr * a, gfc_expr * kind, bt type) +{ + + if (type_check (a, 0, BT_REAL) == FAILURE) + return FAILURE; + if (kind_check (kind, 1, type) == FAILURE) + return FAILURE; + + return SUCCESS; +} + +/* Check subroutine suitable for ceiling, floor and nint. */ + +try +gfc_check_a_ikind (gfc_expr * a, gfc_expr * kind) +{ + + return check_a_kind (a, kind, BT_INTEGER); +} + +/* Check subroutine suitable for aint, anint. */ + +try +gfc_check_a_xkind (gfc_expr * a, gfc_expr * kind) +{ + + return check_a_kind (a, kind, BT_REAL); +} + +try +gfc_check_abs (gfc_expr * a) +{ + + if (numeric_check (a, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_all_any (gfc_expr * mask, gfc_expr * dim) +{ + + if (logical_array_check (mask, 0) == FAILURE) + return FAILURE; + + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_allocated (gfc_expr * array) +{ + + if (variable_check (array, 0) == FAILURE) + return FAILURE; + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (!array->symtree->n.sym->attr.allocatable) + { + must_be (array, 0, "ALLOCATABLE"); + return FAILURE; + } + + return SUCCESS; +} + + +/* Common check function where the first argument must be real or + integer and the second argument must be the same as the first. */ + +try +gfc_check_a_p (gfc_expr * a, gfc_expr * p) +{ + + if (int_or_real_check (a, 0) == FAILURE) + return FAILURE; + + if (same_type_check (a, 0, p, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_associated (gfc_expr * pointer, gfc_expr * target) +{ + symbol_attribute attr; + int i; + try t; + + if (variable_check (pointer, 0) == FAILURE) + return FAILURE; + + attr = gfc_variable_attr (pointer, NULL); + if (!attr.pointer) + { + must_be (pointer, 0, "a POINTER"); + return FAILURE; + } + + if (target == NULL) + return SUCCESS; + + /* Target argument is optional. */ + if (target->expr_type == EXPR_NULL) + { + gfc_error ("NULL pointer at %L is not permitted as actual argument " + "of '%s' intrinsic function", + &target->where, gfc_current_intrinsic); + return FAILURE; + } + + attr = gfc_variable_attr (target, NULL); + if (!attr.pointer && !attr.target) + { + must_be (target, 1, "a POINTER or a TARGET"); + return FAILURE; + } + + t = SUCCESS; + if (same_type_check (pointer, 0, target, 1) == FAILURE) + t = FAILURE; + if (rank_check (target, 0, pointer->rank) == FAILURE) + t = FAILURE; + if (target->rank > 0) + { + for (i = 0; i < target->rank; i++) + if (target->ref->u.ar.dimen_type[i] == DIMEN_VECTOR) + { + gfc_error ("Array section with a vector subscript at %L shall not " + "be the target of an pointer", + &target->where); + t = FAILURE; + break; + } + } + return t; +} + + +try +gfc_check_btest (gfc_expr * i, gfc_expr * pos) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE) + return FAILURE; + if (type_check (pos, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_char (gfc_expr * i, gfc_expr * kind) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE) + return FAILURE; + if (kind_check (kind, 1, BT_CHARACTER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_cmplx (gfc_expr * x, gfc_expr * y, gfc_expr * kind) +{ + + if (numeric_check (x, 0) == FAILURE) + return FAILURE; + + if (y != NULL) + { + if (numeric_check (y, 1) == FAILURE) + return FAILURE; + + if (x->ts.type == BT_COMPLEX) + { + must_be (y, 1, "not be present if 'x' is COMPLEX"); + return FAILURE; + } + } + + if (kind_check (kind, 2, BT_COMPLEX) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_count (gfc_expr * mask, gfc_expr * dim) +{ + + if (logical_array_check (mask, 0) == FAILURE) + return FAILURE; + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_cshift (gfc_expr * array, gfc_expr * shift, gfc_expr * dim) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (array->rank == 1) + { + if (scalar_check (shift, 1) == FAILURE) + return FAILURE; + } + else + { + /* TODO: more requirements on shift parameter. */ + } + + if (dim_check (dim, 2, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_dcmplx (gfc_expr * x, gfc_expr * y) +{ + + if (numeric_check (x, 0) == FAILURE) + return FAILURE; + + if (y != NULL) + { + if (numeric_check (y, 1) == FAILURE) + return FAILURE; + + if (x->ts.type == BT_COMPLEX) + { + must_be (y, 1, "not be present if 'x' is COMPLEX"); + return FAILURE; + } + } + + return SUCCESS; +} + + +try +gfc_check_dble (gfc_expr * x) +{ + + if (numeric_check (x, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_digits (gfc_expr * x) +{ + + if (int_or_real_check (x, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_dot_product (gfc_expr * vector_a, gfc_expr * vector_b) +{ + + switch (vector_a->ts.type) + { + case BT_LOGICAL: + if (type_check (vector_b, 1, BT_LOGICAL) == FAILURE) + return FAILURE; + break; + + case BT_INTEGER: + case BT_REAL: + case BT_COMPLEX: + if (numeric_check (vector_b, 1) == FAILURE) + return FAILURE; + break; + + default: + must_be (vector_a, 0, "numeric or LOGICAL"); + return FAILURE; + } + + if (rank_check (vector_a, 0, 1) == FAILURE) + return FAILURE; + + if (rank_check (vector_b, 1, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_eoshift (gfc_expr * array, gfc_expr * shift, gfc_expr * boundary, + gfc_expr * dim) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (type_check (shift, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (array->rank == 1) + { + if (scalar_check (shift, 2) == FAILURE) + return FAILURE; + } + else + { + /* TODO: more weird restrictions on shift. */ + } + + if (boundary != NULL) + { + if (same_type_check (array, 0, boundary, 2) == FAILURE) + return FAILURE; + + /* TODO: more restrictions on boundary. */ + } + + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + + +try +gfc_check_huge (gfc_expr * x) +{ + + if (int_or_real_check (x, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Check that the single argument is an integer. */ + +try +gfc_check_i (gfc_expr * i) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_iand (gfc_expr * i, gfc_expr * j) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (j, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (same_type_check (i, 0, j, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ibclr (gfc_expr * i, gfc_expr * pos) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (pos, 1, BT_INTEGER) == FAILURE + || kind_value_check (pos, 1, gfc_default_integer_kind ()) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ibits (gfc_expr * i, gfc_expr * pos, gfc_expr * len) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (pos, 1, BT_INTEGER) == FAILURE + || kind_value_check (pos, 1, gfc_default_integer_kind ()) == FAILURE + || type_check (len, 2, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ibset (gfc_expr * i, gfc_expr * pos) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (pos, 1, BT_INTEGER) == FAILURE + || kind_value_check (pos, 1, gfc_default_integer_kind ()) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_idnint (gfc_expr * a) +{ + + if (double_check (a, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ieor (gfc_expr * i, gfc_expr * j) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (j, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (same_type_check (i, 0, j, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_index (gfc_expr * string, gfc_expr * substring, gfc_expr * back) +{ + + if (type_check (string, 0, BT_CHARACTER) == FAILURE + || type_check (substring, 1, BT_CHARACTER) == FAILURE) + return FAILURE; + + + if (back != NULL && type_check (back, 2, BT_LOGICAL) == FAILURE) + return FAILURE; + + if (string->ts.kind != substring->ts.kind) + { + must_be (substring, 1, "the same kind as 'string'"); + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_int (gfc_expr * x, gfc_expr * kind) +{ + + if (numeric_check (x, 0) == FAILURE + || kind_check (kind, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ior (gfc_expr * i, gfc_expr * j) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (j, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (same_type_check (i, 0, j, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ishft (gfc_expr * i, gfc_expr * shift) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (shift, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ishftc (gfc_expr * i, gfc_expr * shift, gfc_expr * size) +{ + + if (type_check (i, 0, BT_INTEGER) == FAILURE + || type_check (shift, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (size != NULL && type_check (size, 2, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_kind (gfc_expr * x) +{ + + if (x->ts.type == BT_DERIVED) + { + must_be (x, 0, "a non-derived type"); + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_lbound (gfc_expr * array, gfc_expr * dim) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (dim != NULL) + { + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + if (dim_rank_check (dim, array, 1) == FAILURE) + return FAILURE; + } + return SUCCESS; +} + + +try +gfc_check_logical (gfc_expr * a, gfc_expr * kind) +{ + + if (type_check (a, 0, BT_LOGICAL) == FAILURE) + return FAILURE; + if (kind_check (kind, 1, BT_LOGICAL) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Min/max family. */ + +static try +min_max_args (gfc_actual_arglist * arg) +{ + + if (arg == NULL || arg->next == NULL) + { + gfc_error ("Intrinsic '%s' at %L must have at least two arguments", + gfc_current_intrinsic, gfc_current_intrinsic_where); + return FAILURE; + } + + return SUCCESS; +} + + +static try +check_rest (bt type, int kind, gfc_actual_arglist * arg) +{ + gfc_expr *x; + int n; + + if (min_max_args (arg) == FAILURE) + return FAILURE; + + n = 1; + + for (; arg; arg = arg->next, n++) + { + x = arg->expr; + if (x->ts.type != type || x->ts.kind != kind) + { + if (x->ts.type == type) + { + if (gfc_notify_std (GFC_STD_GNU, + "Extension: Different type kinds at %L", &x->where) + == FAILURE) + return FAILURE; + } + else + { + gfc_error ("'a%d' argument of '%s' intrinsic at %L must be %s(%d)", + n, gfc_current_intrinsic, &x->where, + gfc_basic_typename (type), kind); + return FAILURE; + } + } + } + + return SUCCESS; +} + + +try +gfc_check_min_max (gfc_actual_arglist * arg) +{ + gfc_expr *x; + + if (min_max_args (arg) == FAILURE) + return FAILURE; + + x = arg->expr; + + if (x->ts.type != BT_INTEGER && x->ts.type != BT_REAL) + { + gfc_error + ("'a1' argument of '%s' intrinsic at %L must be INTEGER or REAL", + gfc_current_intrinsic, &x->where); + return FAILURE; + } + + return check_rest (x->ts.type, x->ts.kind, arg); +} + + +try +gfc_check_min_max_integer (gfc_actual_arglist * arg) +{ + + return check_rest (BT_INTEGER, gfc_default_integer_kind (), arg); +} + + +try +gfc_check_min_max_real (gfc_actual_arglist * arg) +{ + + return check_rest (BT_REAL, gfc_default_real_kind (), arg); +} + + +try +gfc_check_min_max_double (gfc_actual_arglist * arg) +{ + + return check_rest (BT_REAL, gfc_default_double_kind (), arg); +} + +/* End of min/max family. */ + + +try +gfc_check_matmul (gfc_expr * matrix_a, gfc_expr * matrix_b) +{ + + if ((matrix_a->ts.type != BT_LOGICAL) && !gfc_numeric_ts (&matrix_b->ts)) + { + must_be (matrix_a, 0, "numeric or LOGICAL"); + return FAILURE; + } + + if ((matrix_b->ts.type != BT_LOGICAL) && !gfc_numeric_ts (&matrix_a->ts)) + { + must_be (matrix_b, 0, "numeric or LOGICAL"); + return FAILURE; + } + + switch (matrix_a->rank) + { + case 1: + if (rank_check (matrix_b, 1, 2) == FAILURE) + return FAILURE; + break; + + case 2: + if (matrix_b->rank == 2) + break; + if (rank_check (matrix_b, 1, 1) == FAILURE) + return FAILURE; + break; + + default: + must_be (matrix_a, 0, "of rank 1 or 2"); + return FAILURE; + } + + return SUCCESS; +} + + +/* Whoever came up with this interface was probably on something. + The possibilities for the occupation of the second and third + parameters are: + + Arg #2 Arg #3 + NULL NULL + DIM NULL + MASK NULL + NULL MASK minloc(array, mask=m) + DIM MASK +*/ + +try +gfc_check_minloc_maxloc (gfc_expr * array, gfc_expr * a2, gfc_expr * a3) +{ + + if (int_or_real_check (array, 0) == FAILURE) + return FAILURE; + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (a3 != NULL) + { + if (logical_array_check (a3, 2) == FAILURE) + return FAILURE; + + if (a2 != NULL) + { + if (scalar_check (a2, 1) == FAILURE) + return FAILURE; + if (type_check (a2, 1, BT_INTEGER) == FAILURE) + return FAILURE; + } + } + else + { + if (a2 != NULL) + { + switch (a2->ts.type) + { + case BT_INTEGER: + if (scalar_check (a2, 1) == FAILURE) + return FAILURE; + break; + + case BT_LOGICAL: /* The '2' makes the error message correct */ + if (logical_array_check (a2, 2) == FAILURE) + return FAILURE; + break; + + default: + type_check (a2, 1, BT_INTEGER); /* Guaranteed to fail */ + return FAILURE; + } + } + } + + return SUCCESS; +} + + +try +gfc_check_minval_maxval (gfc_expr * array, gfc_expr * dim, gfc_expr * mask) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (int_or_real_check (array, 0) == FAILURE) + return FAILURE; + + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + if (mask != NULL && logical_array_check (mask, 2) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_merge (gfc_expr * tsource, gfc_expr * fsource, gfc_expr * mask) +{ + + if (same_type_check (tsource, 0, fsource, 1) == FAILURE) + return FAILURE; + + if (type_check (mask, 2, BT_LOGICAL) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_nearest (gfc_expr * x, gfc_expr * s) +{ + + if (type_check (x, 0, BT_REAL) == FAILURE) + return FAILURE; + + if (type_check (s, 1, BT_REAL) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_null (gfc_expr * mold) +{ + symbol_attribute attr; + + if (mold == NULL) + return SUCCESS; + + if (variable_check (mold, 0) == FAILURE) + return FAILURE; + + attr = gfc_variable_attr (mold, NULL); + + if (!attr.pointer) + { + must_be (mold, 0, "a POINTER"); + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_pack (gfc_expr * array, gfc_expr * mask, gfc_expr * vector) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (type_check (mask, 1, BT_LOGICAL) == FAILURE) + return FAILURE; + + if (mask->rank != 0 && mask->rank != array->rank) + { + must_be (array, 0, "conformable with 'mask' argument"); + return FAILURE; + } + + if (vector != NULL) + { + if (same_type_check (array, 0, vector, 2) == FAILURE) + return FAILURE; + + if (rank_check (vector, 2, 1) == FAILURE) + return FAILURE; + + /* TODO: More constraints here. */ + } + + return SUCCESS; +} + + +try +gfc_check_precision (gfc_expr * x) +{ + + if (x->ts.type != BT_REAL && x->ts.type != BT_COMPLEX) + { + must_be (x, 0, "of type REAL or COMPLEX"); + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_present (gfc_expr * a) +{ + gfc_symbol *sym; + + if (variable_check (a, 0) == FAILURE) + return FAILURE; + + sym = a->symtree->n.sym; + if (!sym->attr.dummy) + { + must_be (a, 0, "a dummy variable"); + return FAILURE; + } + + if (!sym->attr.optional) + { + must_be (a, 0, "an OPTIONAL dummy variable"); + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_product (gfc_expr * array, gfc_expr * dim, gfc_expr * mask) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (numeric_check (array, 0) == FAILURE) + return FAILURE; + + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + if (mask != NULL && logical_array_check (mask, 2) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_radix (gfc_expr * x) +{ + + if (int_or_real_check (x, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_range (gfc_expr * x) +{ + + if (numeric_check (x, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* real, float, sngl. */ +try +gfc_check_real (gfc_expr * a, gfc_expr * kind) +{ + + if (numeric_check (a, 0) == FAILURE) + return FAILURE; + + if (kind_check (kind, 1, BT_REAL) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_repeat (gfc_expr * x, gfc_expr * y) +{ + + if (type_check (x, 0, BT_CHARACTER) == FAILURE) + return FAILURE; + + if (scalar_check (x, 0) == FAILURE) + return FAILURE; + + if (type_check (y, 0, BT_INTEGER) == FAILURE) + return FAILURE; + + if (scalar_check (y, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_reshape (gfc_expr * source, gfc_expr * shape, + gfc_expr * pad, gfc_expr * order) +{ + mpz_t size; + int m; + + if (array_check (source, 0) == FAILURE) + return FAILURE; + + if (rank_check (shape, 1, 1) == FAILURE) + return FAILURE; + + if (type_check (shape, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (gfc_array_size (shape, &size) != SUCCESS) + { + gfc_error ("'shape' argument of 'reshape' intrinsic at %L must be an " + "array of constant size", &shape->where); + return FAILURE; + } + + m = mpz_cmp_ui (size, GFC_MAX_DIMENSIONS); + mpz_clear (size); + + if (m > 0) + { + gfc_error + ("'shape' argument of 'reshape' intrinsic at %L has more than " + stringize (GFC_MAX_DIMENSIONS) " elements", &shape->where); + return FAILURE; + } + + if (pad != NULL) + { + if (same_type_check (source, 0, pad, 2) == FAILURE) + return FAILURE; + if (array_check (pad, 2) == FAILURE) + return FAILURE; + } + + if (order != NULL && array_check (order, 3) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_scale (gfc_expr * x, gfc_expr * i) +{ + + if (type_check (x, 0, BT_REAL) == FAILURE) + return FAILURE; + + if (type_check (i, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_scan (gfc_expr * x, gfc_expr * y, gfc_expr * z) +{ + + if (type_check (x, 0, BT_CHARACTER) == FAILURE) + return FAILURE; + + if (type_check (y, 1, BT_CHARACTER) == FAILURE) + return FAILURE; + + if (z != NULL && type_check (z, 2, BT_LOGICAL) == FAILURE) + return FAILURE; + + if (same_type_check (x, 0, y, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_selected_real_kind (gfc_expr * p, gfc_expr * r) +{ + + if (p == NULL && r == NULL) + { + gfc_error ("Missing arguments to %s intrinsic at %L", + gfc_current_intrinsic, gfc_current_intrinsic_where); + + return FAILURE; + } + + if (p != NULL && type_check (p, 0, BT_INTEGER) == FAILURE) + return FAILURE; + + if (r != NULL && type_check (r, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_set_exponent (gfc_expr * x, gfc_expr * i) +{ + + if (type_check (x, 0, BT_REAL) == FAILURE) + return FAILURE; + + if (type_check (i, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_shape (gfc_expr * source) +{ + gfc_array_ref *ar; + + if (source->rank == 0 || source->expr_type != EXPR_VARIABLE) + return SUCCESS; + + ar = gfc_find_array_ref (source); + + if (ar->as && ar->as->type == AS_ASSUMED_SIZE) + { + gfc_error ("'source' argument of 'shape' intrinsic at %L must not be " + "an assumed size array", &source->where); + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_size (gfc_expr * array, gfc_expr * dim) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (dim != NULL) + { + if (type_check (dim, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (kind_value_check (dim, 1, gfc_default_integer_kind ()) == FAILURE) + return FAILURE; + + if (dim_rank_check (dim, array, 0) == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_sign (gfc_expr * a, gfc_expr * b) +{ + + if (int_or_real_check (a, 0) == FAILURE) + return FAILURE; + + if (same_type_check (a, 0, b, 1) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_spread (gfc_expr * source, gfc_expr * dim, gfc_expr * ncopies) +{ + + if (source->rank >= GFC_MAX_DIMENSIONS) + { + must_be (source, 0, "less than rank " stringize (GFC_MAX_DIMENSIONS)); + return FAILURE; + } + + if (dim_check (dim, 1, 0) == FAILURE) + return FAILURE; + + if (type_check (ncopies, 2, BT_INTEGER) == FAILURE) + return FAILURE; + if (scalar_check (ncopies, 2) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_sum (gfc_expr * array, gfc_expr * dim, gfc_expr * mask) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (numeric_check (array, 0) == FAILURE) + return FAILURE; + + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + if (mask != NULL && logical_array_check (mask, 2) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_transfer (gfc_expr * source ATTRIBUTE_UNUSED, + gfc_expr * mold ATTRIBUTE_UNUSED, + gfc_expr * size) +{ + + if (size != NULL) + { + if (type_check (size, 2, BT_INTEGER) == FAILURE) + return FAILURE; + + if (scalar_check (size, 2) == FAILURE) + return FAILURE; + + if (nonoptional_check (size, 2) == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_transpose (gfc_expr * matrix) +{ + + if (rank_check (matrix, 0, 2) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_ubound (gfc_expr * array, gfc_expr * dim) +{ + + if (array_check (array, 0) == FAILURE) + return FAILURE; + + if (dim != NULL) + { + if (dim_check (dim, 1, 1) == FAILURE) + return FAILURE; + + if (dim_rank_check (dim, array, 0) == FAILURE) + return FAILURE; + } + return SUCCESS; +} + + +try +gfc_check_unpack (gfc_expr * vector, gfc_expr * mask, gfc_expr * field) +{ + + if (rank_check (vector, 0, 1) == FAILURE) + return FAILURE; + + if (array_check (mask, 1) == FAILURE) + return FAILURE; + + if (type_check (mask, 1, BT_LOGICAL) == FAILURE) + return FAILURE; + + if (same_type_check (vector, 0, field, 2) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_verify (gfc_expr * x, gfc_expr * y, gfc_expr * z) +{ + + if (type_check (x, 0, BT_CHARACTER) == FAILURE) + return FAILURE; + + if (same_type_check (x, 0, y, 1) == FAILURE) + return FAILURE; + + if (z != NULL && type_check (z, 2, BT_LOGICAL) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_trim (gfc_expr * x) +{ + if (type_check (x, 0, BT_CHARACTER) == FAILURE) + return FAILURE; + + if (scalar_check (x, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Common check function for the half a dozen intrinsics that have a + single real argument. */ + +try +gfc_check_x (gfc_expr * x) +{ + + if (type_check (x, 0, BT_REAL) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/************* Check functions for intrinsic subroutines *************/ + +try +gfc_check_cpu_time (gfc_expr * time) +{ + + if (scalar_check (time, 0) == FAILURE) + return FAILURE; + + if (type_check (time, 0, BT_REAL) == FAILURE) + return FAILURE; + + if (variable_check (time, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_date_and_time (gfc_expr * date, gfc_expr * time, + gfc_expr * zone, gfc_expr * values) +{ + + if (date != NULL) + { + if (type_check (date, 0, BT_CHARACTER) == FAILURE) + return FAILURE; + if (scalar_check (date, 0) == FAILURE) + return FAILURE; + if (variable_check (date, 0) == FAILURE) + return FAILURE; + } + + if (time != NULL) + { + if (type_check (time, 1, BT_CHARACTER) == FAILURE) + return FAILURE; + if (scalar_check (time, 1) == FAILURE) + return FAILURE; + if (variable_check (time, 1) == FAILURE) + return FAILURE; + } + + if (zone != NULL) + { + if (type_check (zone, 2, BT_CHARACTER) == FAILURE) + return FAILURE; + if (scalar_check (zone, 2) == FAILURE) + return FAILURE; + if (variable_check (zone, 2) == FAILURE) + return FAILURE; + } + + if (values != NULL) + { + if (type_check (values, 3, BT_INTEGER) == FAILURE) + return FAILURE; + if (array_check (values, 3) == FAILURE) + return FAILURE; + if (rank_check (values, 3, 1) == FAILURE) + return FAILURE; + if (variable_check (values, 3) == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +try +gfc_check_mvbits (gfc_expr * from, gfc_expr * frompos, gfc_expr * len, + gfc_expr * to, gfc_expr * topos) +{ + + if (type_check (from, 0, BT_INTEGER) == FAILURE) + return FAILURE; + + if (type_check (frompos, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (type_check (len, 2, BT_INTEGER) == FAILURE) + return FAILURE; + + if (same_type_check (from, 0, to, 3) == FAILURE) + return FAILURE; + + if (variable_check (to, 3) == FAILURE) + return FAILURE; + + if (type_check (topos, 4, BT_INTEGER) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_random_number (gfc_expr * harvest) +{ + + if (type_check (harvest, 0, BT_REAL) == FAILURE) + return FAILURE; + + if (variable_check (harvest, 0) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +try +gfc_check_random_seed (gfc_expr * size, gfc_expr * put, gfc_expr * get) +{ + + if (size != NULL) + { + if (scalar_check (size, 0) == FAILURE) + return FAILURE; + + if (type_check (size, 0, BT_INTEGER) == FAILURE) + return FAILURE; + + if (variable_check (size, 0) == FAILURE) + return FAILURE; + + if (kind_value_check (size, 0, gfc_default_integer_kind ()) == FAILURE) + return FAILURE; + } + + if (put != NULL) + { + if (array_check (put, 1) == FAILURE) + return FAILURE; + if (rank_check (put, 1, 1) == FAILURE) + return FAILURE; + + if (type_check (put, 1, BT_INTEGER) == FAILURE) + return FAILURE; + + if (kind_value_check (put, 1, gfc_default_integer_kind ()) == FAILURE) + return FAILURE; + } + + if (get != NULL) + { + if (array_check (get, 2) == FAILURE) + return FAILURE; + if (rank_check (get, 2, 1) == FAILURE) + return FAILURE; + + if (type_check (get, 2, BT_INTEGER) == FAILURE) + return FAILURE; + + if (variable_check (get, 2) == FAILURE) + return FAILURE; + + if (kind_value_check (get, 2, gfc_default_integer_kind ()) == FAILURE) + return FAILURE; + } + + return SUCCESS; +} diff --git a/gcc/fortran/config-lang.in b/gcc/fortran/config-lang.in new file mode 100644 index 00000000000..c638dcbaf48 --- /dev/null +++ b/gcc/fortran/config-lang.in @@ -0,0 +1,22 @@ +# Configure looks for the existence of this file to auto-config each language. +# We define several parameters used by configure: +# +# language - name of language as it would appear in $(LANGUAGES) +# compilers - value to add to $(COMPILERS) +# stagestuff - files to add to $(STAGESTUFF) +# diff_excludes - files to ignore when building diffs between two versions. + +language="f95" + +compilers="f951\$(exeext)" + +stagestuff="gfortran\$(exeext) f951\$(exeext)" + +target_libs=target-libgfortran + +gtfiles="\$(srcdir)/fortran/f95-lang.c \$(srcdir)/fortran/trans-decl.c \$(srcdir)/fortran/trans-intrinsic.c \$(srcdir)/fortran/trans-io.c \$(srcdir)/fortran/trans-types.c \$(srcdir)/fortran/trans-types.h \$(srcdir)/fortran/trans.h \$(srcdir)/fortran/trans-const.h" + +need_gmp="yes" + +#outputs=g95/Makefile + diff --git a/gcc/fortran/convert.c b/gcc/fortran/convert.c new file mode 100644 index 00000000000..9759f057f50 --- /dev/null +++ b/gcc/fortran/convert.c @@ -0,0 +1,124 @@ +/* Language-level data type conversion for GNU C. + Copyright (C) 1987, 1988, 1991, 1998, 2002 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +/* This file contains 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. */ + +/* copied from the f77 frontend I think */ + +/* copied from c-convert.c without significant modification*/ +/* 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. +*/ + +/* I've added support for WITH_RECORD_EXPR. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "flags.h" +#include "convert.h" +#include "toplev.h" +#include "gfortran.h" +#include "trans.h" + +/* + 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 convert.c, convert_to_integer. + In c-typeck.c, build_binary_op (boolean ops), and + c_common_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'. */ + + + +/* 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. */ +/* We are assuming that given a SIMPLE val, the result will be a SIMPLE rhs. + If this is not the case, we will abort with an internal error. */ +tree +convert (tree type, tree expr) +{ + tree e = expr; + enum tree_code code = TREE_CODE (type); + + if (type == TREE_TYPE (expr) + || TREE_CODE (expr) == ERROR_MARK + || code == ERROR_MARK || TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) + return expr; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) + return fold (build1 (NOP_EXPR, type, 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 build1 (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 == BOOLEAN_TYPE) + { + e = gfc_truthvalue_conversion (e); + + /* If we have a NOP_EXPR, we must fold it here to avoid + infinite recursion between fold () and convert (). */ + if (TREE_CODE (e) == NOP_EXPR) + return fold (build1 (NOP_EXPR, type, TREE_OPERAND (e, 0))); + else + return fold (build1 (NOP_EXPR, type, e)); + } + if (code == POINTER_TYPE || code == REFERENCE_TYPE) + return fold (convert_to_pointer (type, e)); + if (code == REAL_TYPE) + return fold (convert_to_real (type, e)); + if (code == COMPLEX_TYPE) + return fold (convert_to_complex (type, e)); + if (code == VECTOR_TYPE) + return fold (convert_to_vector (type, e)); + + error ("conversion to non-scalar type requested"); + return error_mark_node; +} diff --git a/gcc/fortran/data.c b/gcc/fortran/data.c new file mode 100644 index 00000000000..7977b335836 --- /dev/null +++ b/gcc/fortran/data.c @@ -0,0 +1,457 @@ +/* Supporting functions for resolving DATA statement. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Lifang Zeng + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Notes for DATA statement implementation: + + We first assign initial value to each symbol by gfc_assign_data_value + during resolveing DATA statement. Refer to check_data_variable and + traverse_data_list in resolve.c. + + The complexity exists in the handleing of array section, implied do + and array of struct appeared in DATA statement. + + We call gfc_conv_structure, gfc_con_array_array_initializer, + etc., to convert the initial value. Refer to trans-expr.c and + trans-array.c. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "toplev.h" +#include "gfortran.h" +#include "assert.h" +#include "trans.h" + +static void formalize_init_expr (gfc_expr *); + +/* Calculate the array element offset. */ + +static void +get_array_index (gfc_array_ref * ar, mpz_t * offset) +{ + gfc_expr *e; + int i; + try re; + mpz_t delta; + mpz_t tmp; + + mpz_init (tmp); + mpz_set_si (*offset, 0); + mpz_init_set_si (delta, 1); + for (i = 0; i < ar->dimen; i++) + { + e = gfc_copy_expr (ar->start[i]); + re = gfc_simplify_expr (e, 1); + + if ((gfc_is_constant_expr (ar->as->lower[i]) == 0) + || (gfc_is_constant_expr (ar->as->upper[i]) == 0) + || (gfc_is_constant_expr (e) == 0)) + gfc_error ("non-constant array in DATA statement %L.", &ar->where); + mpz_set (tmp, e->value.integer); + mpz_sub (tmp, tmp, ar->as->lower[i]->value.integer); + mpz_mul (tmp, tmp, delta); + mpz_add (*offset, tmp, *offset); + + mpz_sub (tmp, ar->as->upper[i]->value.integer, + ar->as->lower[i]->value.integer); + mpz_add_ui (tmp, tmp, 1); + mpz_mul (delta, tmp, delta); + } + mpz_clear (delta); + mpz_clear (tmp); +} + + +/* Find if there is a constructor which offset is equal to OFFSET. */ + +static gfc_constructor * +find_con_by_offset (mpz_t offset, gfc_constructor *con) +{ + for (; con; con = con->next) + { + if (mpz_cmp (offset, con->n.offset) == 0) + return con; + } + return NULL; +} + + +/* Find if there is a constructor which component is equal to COM. */ + +static gfc_constructor * +find_con_by_component (gfc_component *com, gfc_constructor *con) +{ + for (; con; con = con->next) + { + if (com == con->n.component) + return con; + } + return NULL; +} + + +/* Assign the initial value RVALUE to LVALUE's symbol->value. */ +void +gfc_assign_data_value (gfc_expr * lvalue, gfc_expr * rvalue, mpz_t index) +{ + gfc_ref *ref; + gfc_expr *init; + gfc_expr *expr; + gfc_constructor *con; + gfc_constructor *last_con; + gfc_symbol *symbol; + mpz_t offset; + + ref = lvalue->ref; + symbol = lvalue->symtree->n.sym; + init = symbol->value; + last_con = NULL; + mpz_init_set_si (offset, 0); + + for (ref = lvalue->ref; ref; ref = ref->next) + { + /* Use the existing initializer expression if it exists. Otherwise + create a new one. */ + if (init == NULL) + expr = gfc_get_expr (); + else + expr = init; + + /* Find or create this element. */ + switch (ref->type) + { + case REF_ARRAY: + if (init == NULL) + { + /* Setup the expression to hold the constructor. */ + expr->expr_type = EXPR_ARRAY; + if (ref->next) + { + assert (ref->next->type == REF_COMPONENT); + expr->ts.type = BT_DERIVED; + } + else + expr->ts = rvalue->ts; + expr->rank = ref->u.ar.as->rank; + } + else + assert (expr->expr_type == EXPR_ARRAY); + + if (ref->u.ar.type == AR_ELEMENT) + get_array_index (&ref->u.ar, &offset); + else + mpz_set (offset, index); + + /* Find the same element in the existing constructor. */ + con = expr->value.constructor; + con = find_con_by_offset (offset, con); + + if (con == NULL) + { + /* Create a new constructor. */ + con = gfc_get_constructor(); + mpz_set (con->n.offset, offset); + gfc_insert_constructor (expr, con); + } + break; + + case REF_COMPONENT: + if (init == NULL) + { + /* Setup the expression to hold the constructor. */ + expr->expr_type = EXPR_STRUCTURE; + expr->ts.type = BT_DERIVED; + expr->ts.derived = ref->u.c.sym; + } + else + assert (expr->expr_type == EXPR_STRUCTURE); + + /* Find the same element in the existing constructor. */ + con = expr->value.constructor; + con = find_con_by_component (ref->u.c.component, con); + + if (con == NULL) + { + /* Create a new constructor. */ + con = gfc_get_constructor (); + con->n.component = ref->u.c.component; + con->next = expr->value.constructor; + expr->value.constructor = con; + } + break; + + case REF_SUBSTRING: + gfc_todo_error ("Substring reference in DATA statement"); + + default: + abort (); + } + + if (init == NULL) + { + /* Point the container at the new expression. */ + if (last_con == NULL) + symbol->value = expr; + else + last_con->expr = expr; + } + init = con->expr; + last_con = con; + } + + expr = gfc_copy_expr (rvalue); + if (!gfc_compare_types (&lvalue->ts, &expr->ts)) + gfc_convert_type (expr, &lvalue->ts, 0); + + if (last_con == NULL) + symbol->value = expr; + else + { + assert (!last_con->expr); + last_con->expr = expr; + } +} + + +/* Modify the index of array section and re-calculate the array offset. */ + +void +gfc_advance_section (mpz_t *section_index, gfc_array_ref *ar, + mpz_t *offset_ret) +{ + int i; + mpz_t delta; + mpz_t tmp; + bool forwards; + int cmp; + + for (i = 0; i < ar->dimen; i++) + { + if (ar->dimen_type[i] != DIMEN_RANGE) + continue; + + if (ar->stride[i]) + { + mpz_add (section_index[i], section_index[i], + ar->stride[i]->value.integer); + if (mpz_cmp_si (ar->stride[i]->value.integer, 0) >= 0) + forwards = true; + else + forwards = false; + } + else + { + mpz_add_ui (section_index[i], section_index[i], 1); + forwards = true; + } + + if (ar->end[i]) + cmp = mpz_cmp (section_index[i], ar->end[i]->value.integer); + else + cmp = mpz_cmp (section_index[i], ar->as->upper[i]->value.integer); + + if ((cmp > 0 && forwards) + || (cmp < 0 && ! forwards)) + { + /* Reset index to start, then loop to advance the next index. */ + if (ar->start[i]) + mpz_set (section_index[i], ar->start[i]->value.integer); + else + mpz_set (section_index[i], ar->as->lower[i]->value.integer); + } + else + break; + } + + mpz_set_si (*offset_ret, 0); + mpz_init_set_si (delta, 1); + mpz_init (tmp); + for (i = 0; i < ar->dimen; i++) + { + mpz_sub (tmp, section_index[i], ar->as->lower[i]->value.integer); + mpz_mul (tmp, tmp, delta); + mpz_add (*offset_ret, tmp, *offset_ret); + + mpz_sub (tmp, ar->as->upper[i]->value.integer, + ar->as->lower[i]->value.integer); + mpz_add_ui (tmp, tmp, 1); + mpz_mul (delta, tmp, delta); + } + mpz_clear (tmp); + mpz_clear (delta); +} + + +/* Rearrange a structure constructor so the elements are in the specified + order. Also insert NULL entries if neccessary. */ + +static void +formalize_structure_cons (gfc_expr * expr) +{ + gfc_constructor *head; + gfc_constructor *tail; + gfc_constructor *cur; + gfc_constructor *last; + gfc_constructor *c; + gfc_component *order; + + c = expr->value.constructor; + + /* Constructor is already fomalized. */ + if (c->n.component == NULL) + return; + + head = tail = NULL; + for (order = expr->ts.derived->components; order; order = order->next) + { + /* Find the next component. */ + last = NULL; + cur = c; + while (cur != NULL && cur->n.component != order) + { + last = cur; + cur = cur->next; + } + + if (cur == NULL) + { + /* Create a new one. */ + cur = gfc_get_constructor (); + } + else + { + /* Remove it from the chain. */ + if (last == NULL) + c = cur->next; + else + last->next = cur->next; + cur->next = NULL; + + formalize_init_expr (cur->expr); + } + + /* Add it to the new constructor. */ + if (head == NULL) + head = tail = cur; + else + { + tail->next = cur; + tail = tail->next; + } + } + assert (c == NULL); + expr->value.constructor = head; +} + + +/* Make sure an initialization expression is in normalized form. Ie. all + elements of the constructors are in the correct order. */ + +static void +formalize_init_expr (gfc_expr * expr) +{ + expr_t type; + gfc_constructor *c; + + if (expr == NULL) + return; + + type = expr->expr_type; + switch (type) + { + case EXPR_ARRAY: + c = expr->value.constructor; + while (c) + { + formalize_init_expr (c->expr); + c = c->next; + } + break; + + case EXPR_STRUCTURE: + formalize_structure_cons (expr); + break; + + default: + break; + } +} + + +/* Resolve symbol's initial value after all data statement. */ + +void +gfc_formalize_init_value (gfc_symbol *sym) +{ + formalize_init_expr (sym->value); +} + + +/* Get the integer value into RET_AS and SECTION from AS and AR, and return + offset. */ + +void +gfc_get_section_index (gfc_array_ref *ar, mpz_t *section_index, mpz_t *offset) +{ + int i; + mpz_t delta; + mpz_t tmp; + + mpz_set_si (*offset, 0); + mpz_init (tmp); + mpz_init_set_si (delta, 1); + for (i = 0; i < ar->dimen; i++) + { + mpz_init (section_index[i]); + switch (ar->dimen_type[i]) + { + case DIMEN_ELEMENT: + case DIMEN_RANGE: + if (ar->start[i]) + { + mpz_sub (tmp, ar->start[i]->value.integer, + ar->as->lower[i]->value.integer); + mpz_mul (tmp, tmp, delta); + mpz_add (*offset, tmp, *offset); + mpz_set (section_index[i], ar->start[i]->value.integer); + } + else + mpz_set (section_index[i], ar->as->lower[i]->value.integer); + break; + + case DIMEN_VECTOR: + gfc_todo_error ("Vectors sections in data statements"); + + default: + abort (); + } + + mpz_sub (tmp, ar->as->upper[i]->value.integer, + ar->as->lower[i]->value.integer); + mpz_add_ui (tmp, tmp, 1); + mpz_mul (delta, tmp, delta); + } + + mpz_clear (tmp); + mpz_clear (delta); +} + diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c new file mode 100644 index 00000000000..1bc91c18393 --- /dev/null +++ b/gcc/fortran/decl.c @@ -0,0 +1,2649 @@ +/* Declaration statement matcher + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include "gfortran.h" +#include "match.h" +#include "parse.h" +#include + + +/* This flag is set if a an old-style length selector is matched + during a type-declaration statement. */ + +static int old_char_selector; + +/* When variables aquire types and attributes from a declaration + statement, they get them from the following static variables. The + first part of a declaration sets these variables and the second + part copies these into symbol structures. */ + +static gfc_typespec current_ts; + +static symbol_attribute current_attr; +static gfc_array_spec *current_as; +static int colon_seen; + +/* gfc_new_block points to the symbol of a newly matched block. */ + +gfc_symbol *gfc_new_block; + + +/* Match an intent specification. Since this can only happen after an + INTENT word, a legal intent-spec must follow. */ + +static sym_intent +match_intent_spec (void) +{ + + if (gfc_match (" ( in out )") == MATCH_YES) + return INTENT_INOUT; + if (gfc_match (" ( in )") == MATCH_YES) + return INTENT_IN; + if (gfc_match (" ( out )") == MATCH_YES) + return INTENT_OUT; + + gfc_error ("Bad INTENT specification at %C"); + return INTENT_UNKNOWN; +} + + +/* Matches a character length specification, which is either a + specification expression or a '*'. */ + +static match +char_len_param_value (gfc_expr ** expr) +{ + + if (gfc_match_char ('*') == MATCH_YES) + { + *expr = NULL; + return MATCH_YES; + } + + return gfc_match_expr (expr); +} + + +/* A character length is a '*' followed by a literal integer or a + char_len_param_value in parenthesis. */ + +static match +match_char_length (gfc_expr ** expr) +{ + int length; + match m; + + m = gfc_match_char ('*'); + if (m != MATCH_YES) + return m; + + m = gfc_match_small_literal_int (&length); + if (m == MATCH_ERROR) + return m; + + if (m == MATCH_YES) + { + *expr = gfc_int_expr (length); + return m; + } + + if (gfc_match_char ('(') == MATCH_NO) + goto syntax; + + m = char_len_param_value (expr); + if (m == MATCH_ERROR) + return m; + if (m == MATCH_NO) + goto syntax; + + if (gfc_match_char (')') == MATCH_NO) + { + gfc_free_expr (*expr); + *expr = NULL; + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in character length specification at %C"); + return MATCH_ERROR; +} + + +/* Special subroutine for finding a symbol. If we're compiling a + function or subroutine and the parent compilation unit is an + interface, then check to see if the name we've been given is the + name of the interface (located in another namespace). If so, + return that symbol. If not, use gfc_get_symbol(). */ + +static int +find_special (const char *name, gfc_symbol ** result) +{ + gfc_state_data *s; + + if (gfc_current_state () != COMP_SUBROUTINE + && gfc_current_state () != COMP_FUNCTION) + goto normal; + + s = gfc_state_stack->previous; + if (s == NULL) + goto normal; + + if (s->state != COMP_INTERFACE) + goto normal; + if (s->sym == NULL) + goto normal; /* Nameless interface */ + + if (strcmp (name, s->sym->name) == 0) + { + *result = s->sym; + return 0; + } + +normal: + return gfc_get_symbol (name, NULL, result); +} + + +/* Special subroutine for getting a symbol node associated with a + procedure name, used in SUBROUTINE and FUNCTION statements. The + symbol is created in the parent using with symtree node in the + child unit pointing to the symbol. If the current namespace has no + parent, then the symbol is just created in the current unit. */ + +static int +get_proc_name (const char *name, gfc_symbol ** result) +{ + gfc_symtree *st; + gfc_symbol *sym; + int rc; + + if (gfc_current_ns->parent == NULL) + return gfc_get_symbol (name, NULL, result); + + rc = gfc_get_symbol (name, gfc_current_ns->parent, result); + if (*result == NULL) + return rc; + + /* Deal with ENTRY problem */ + + st = gfc_new_symtree (&gfc_current_ns->sym_root, name); + + sym = *result; + st->n.sym = sym; + sym->refs++; + + /* See if the procedure should be a module procedure */ + + if (sym->ns->proc_name != NULL + && sym->ns->proc_name->attr.flavor == FL_MODULE + && sym->attr.proc != PROC_MODULE + && gfc_add_procedure (&sym->attr, PROC_MODULE, NULL) == FAILURE) + rc = 2; + + return rc; +} + + +/* Function called by variable_decl() that adds a name to the symbol + table. */ + +static try +build_sym (const char *name, gfc_charlen * cl, + gfc_array_spec ** as, locus * var_locus) +{ + symbol_attribute attr; + gfc_symbol *sym; + + if (find_special (name, &sym)) + return FAILURE; + + /* Start updating the symbol table. Add basic type attribute + if present. */ + if (current_ts.type != BT_UNKNOWN + &&(sym->attr.implicit_type == 0 + || !gfc_compare_types (&sym->ts, ¤t_ts)) + && gfc_add_type (sym, ¤t_ts, var_locus) == FAILURE) + return FAILURE; + + if (sym->ts.type == BT_CHARACTER) + sym->ts.cl = cl; + + /* Add dimension attribute if present. */ + if (gfc_set_array_spec (sym, *as, var_locus) == FAILURE) + return FAILURE; + *as = NULL; + + /* Add attribute to symbol. The copy is so that we can reset the + dimension attribute. */ + attr = current_attr; + attr.dimension = 0; + + if (gfc_copy_attr (&sym->attr, &attr, var_locus) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Function called by variable_decl() that adds an initialization + expression to a symbol. */ + +static try +add_init_expr_to_sym (const char *name, gfc_expr ** initp, + locus * var_locus) +{ + symbol_attribute attr; + gfc_symbol *sym; + gfc_expr *init; + + init = *initp; + if (find_special (name, &sym)) + return FAILURE; + + attr = sym->attr; + + /* If this symbol is confirming an implicit parameter type, + then an initialization expression is not allowed. */ + if (attr.flavor == FL_PARAMETER + && sym->value != NULL + && *initp != NULL) + { + gfc_error ("Initializer not allowed for PARAMETER '%s' at %C", + sym->name); + return FAILURE; + } + + if (init == NULL) + { + /* An initializer is required for PARAMETER declarations. */ + if (attr.flavor == FL_PARAMETER) + { + gfc_error ("PARAMETER at %L is missing an initializer", var_locus); + return FAILURE; + } + } + else + { + /* If a variable appears in a DATA block, it cannot have an + initializer. */ + if (sym->attr.data) + { + gfc_error + ("Variable '%s' at %C with an initializer already appears " + "in a DATA statement", sym->name); + return FAILURE; + } + + /* Checking a derived type parameter has to be put off until later. */ + if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED + && gfc_check_assign_symbol (sym, init) == FAILURE) + return FAILURE; + + /* Add initializer. Make sure we keep the ranks sane. */ + if (sym->attr.dimension && init->rank == 0) + init->rank = sym->as->rank; + + sym->value = init; + *initp = NULL; + } + + return SUCCESS; +} + + +/* Function called by variable_decl() that adds a name to a structure + being built. */ + +static try +build_struct (const char *name, gfc_charlen * cl, gfc_expr ** init, + gfc_array_spec ** as) +{ + gfc_component *c; + + /* If the current symbol is of the same derived type that we're + constructing, it must have the pointer attribute. */ + if (current_ts.type == BT_DERIVED + && current_ts.derived == gfc_current_block () + && current_attr.pointer == 0) + { + gfc_error ("Component at %C must have the POINTER attribute"); + return FAILURE; + } + + if (gfc_current_block ()->attr.pointer + && (*as)->rank != 0) + { + if ((*as)->type != AS_DEFERRED && (*as)->type != AS_EXPLICIT) + { + gfc_error ("Array component of structure at %C must have explicit " + "or deferred shape"); + return FAILURE; + } + } + + if (gfc_add_component (gfc_current_block (), name, &c) == FAILURE) + return FAILURE; + + c->ts = current_ts; + c->ts.cl = cl; + gfc_set_component_attr (c, ¤t_attr); + + c->initializer = *init; + *init = NULL; + + c->as = *as; + if (c->as != NULL) + c->dimension = 1; + *as = NULL; + + /* Check array components. */ + if (!c->dimension) + return SUCCESS; + + if (c->pointer) + { + if (c->as->type != AS_DEFERRED) + { + gfc_error ("Pointer array component of structure at %C " + "must have a deferred shape"); + return FAILURE; + } + } + else + { + if (c->as->type != AS_EXPLICIT) + { + gfc_error + ("Array component of structure at %C must have an explicit " + "shape"); + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Match a 'NULL()', and possibly take care of some side effects. */ + +match +gfc_match_null (gfc_expr ** result) +{ + gfc_symbol *sym; + gfc_expr *e; + match m; + + m = gfc_match (" null ( )"); + if (m != MATCH_YES) + return m; + + /* The NULL symbol now has to be/become an intrinsic function. */ + if (gfc_get_symbol ("null", NULL, &sym)) + { + gfc_error ("NULL() initialization at %C is ambiguous"); + return MATCH_ERROR; + } + + gfc_intrinsic_symbol (sym); + + if (sym->attr.proc != PROC_INTRINSIC + && (gfc_add_procedure (&sym->attr, PROC_INTRINSIC, NULL) == FAILURE + || gfc_add_function (&sym->attr, NULL) == FAILURE)) + return MATCH_ERROR; + + e = gfc_get_expr (); + e->where = *gfc_current_locus (); + e->expr_type = EXPR_NULL; + e->ts.type = BT_UNKNOWN; + + *result = e; + + return MATCH_YES; +} + + +/* Get an expression for a default initializer. */ +static gfc_expr * +default_initializer (void) +{ + gfc_constructor *tail; + gfc_expr *init; + gfc_component *c; + + init = NULL; + + /* First see if we have a default initializer. */ + for (c = current_ts.derived->components; c; c = c->next) + { + if (c->initializer && init == NULL) + init = gfc_get_expr (); + } + + if (init == NULL) + return NULL; + + init->expr_type = EXPR_STRUCTURE; + init->ts = current_ts; + init->where = current_ts.derived->declared_at; + tail = NULL; + for (c = current_ts.derived->components; c; c = c->next) + { + if (tail == NULL) + init->value.constructor = tail = gfc_get_constructor (); + else + { + tail->next = gfc_get_constructor (); + tail = tail->next; + } + + if (c->initializer) + tail->expr = gfc_copy_expr (c->initializer); + } + return init; +} + + +/* Match a variable name with an optional initializer. When this + subroutine is called, a variable is expected to be parsed next. + Depending on what is happening at the moment, updates either the + symbol table or the current interface. */ + +static match +variable_decl (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_expr *initializer, *char_len; + gfc_array_spec *as; + gfc_charlen *cl; + locus var_locus; + match m; + try t; + + initializer = NULL; + as = NULL; + + /* When we get here, we've just matched a list of attributes and + maybe a type and a double colon. The next thing we expect to see + is the name of the symbol. */ + m = gfc_match_name (name); + if (m != MATCH_YES) + goto cleanup; + + var_locus = *gfc_current_locus (); + + /* Now we could see the optional array spec. or character length. */ + m = gfc_match_array_spec (&as); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + as = gfc_copy_array_spec (current_as); + + char_len = NULL; + cl = NULL; + + if (current_ts.type == BT_CHARACTER) + { + switch (match_char_length (&char_len)) + { + case MATCH_YES: + cl = gfc_get_charlen (); + cl->next = gfc_current_ns->cl_list; + gfc_current_ns->cl_list = cl; + + cl->length = char_len; + break; + + case MATCH_NO: + cl = current_ts.cl; + break; + + case MATCH_ERROR: + goto cleanup; + } + } + + /* OK, we've successfully matched the declaration. Now put the + symbol in the current namespace, because it might be used in the + optional intialization expression for this symbol, e.g. this is + perfectly legal: + + integer, parameter :: i = huge(i) + + This is only true for parameters or variables of a basic type. + For components of derived types, it is not true, so we don't + create a symbol for those yet. If we fail to create the symbol, + bail out. */ + if (gfc_current_state () != COMP_DERIVED + && build_sym (name, cl, &as, &var_locus) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + /* In functions that have a RESULT variable defined, the function + name always refers to function calls. Therefore, the name is + not allowed to appear in specification statements. */ + if (gfc_current_state () == COMP_FUNCTION + && gfc_current_block () != NULL + && gfc_current_block ()->result != NULL + && gfc_current_block ()->result != gfc_current_block () + && strcmp (gfc_current_block ()->name, name) == 0) + { + gfc_error ("Function name '%s' not allowed at %C", name); + m = MATCH_ERROR; + goto cleanup; + } + + /* The double colon must be present in order to have initializers. + Otherwise the statement is ambiguous with an assignment statement. */ + if (colon_seen) + { + if (gfc_match (" =>") == MATCH_YES) + { + + if (!current_attr.pointer) + { + gfc_error ("Initialization at %C isn't for a pointer variable"); + m = MATCH_ERROR; + goto cleanup; + } + + m = gfc_match_null (&initializer); + if (m == MATCH_NO) + { + gfc_error ("Pointer initialization requires a NULL at %C"); + m = MATCH_ERROR; + } + + if (gfc_pure (NULL)) + { + gfc_error + ("Initialization of pointer at %C is not allowed in a " + "PURE procedure"); + m = MATCH_ERROR; + } + + if (m != MATCH_YES) + goto cleanup; + + initializer->ts = current_ts; + + } + else if (gfc_match_char ('=') == MATCH_YES) + { + if (current_attr.pointer) + { + gfc_error + ("Pointer initialization at %C requires '=>', not '='"); + m = MATCH_ERROR; + goto cleanup; + } + + m = gfc_match_init_expr (&initializer); + if (m == MATCH_NO) + { + gfc_error ("Expected an initialization expression at %C"); + m = MATCH_ERROR; + } + + if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL)) + { + gfc_error + ("Initialization of variable at %C is not allowed in a " + "PURE procedure"); + m = MATCH_ERROR; + } + + if (m != MATCH_YES) + goto cleanup; + } + else if (current_ts.type == BT_DERIVED) + { + initializer = default_initializer (); + } + } + + /* Add the initializer. Note that it is fine if &initializer is + NULL here, because we sometimes also need to check if a + declaration *must* have an initialization expression. */ + if (gfc_current_state () != COMP_DERIVED) + t = add_init_expr_to_sym (name, &initializer, &var_locus); + else + t = build_struct (name, cl, &initializer, &as); + + m = (t == SUCCESS) ? MATCH_YES : MATCH_ERROR; + +cleanup: + /* Free stuff up and return. */ + gfc_free_expr (initializer); + gfc_free_array_spec (as); + + return m; +} + + +/* Match an extended-f77 kind specification. */ + +match +gfc_match_old_kind_spec (gfc_typespec * ts) +{ + match m; + + if (gfc_match_char ('*') != MATCH_YES) + return MATCH_NO; + + m = gfc_match_small_literal_int (&ts->kind); + if (m != MATCH_YES) + return MATCH_ERROR; + + /* Massage the kind numbers for complex types. */ + if (ts->type == BT_COMPLEX && ts->kind == 8) + ts->kind = 4; + if (ts->type == BT_COMPLEX && ts->kind == 16) + ts->kind = 8; + + if (gfc_validate_kind (ts->type, ts->kind) == -1) + { + gfc_error ("Old-style kind %d not supported for type %s at %C", + ts->kind, gfc_basic_typename (ts->type)); + + return MATCH_ERROR; + } + + return MATCH_YES; +} + + +/* Match a kind specification. Since kinds are generally optional, we + usually return MATCH_NO if something goes wrong. If a "kind=" + string is found, then we know we have an error. */ + +match +gfc_match_kind_spec (gfc_typespec * ts) +{ + locus where; + gfc_expr *e; + match m, n; + const char *msg; + + m = MATCH_NO; + e = NULL; + + where = *gfc_current_locus (); + + if (gfc_match_char ('(') == MATCH_NO) + return MATCH_NO; + + /* Also gobbles optional text. */ + if (gfc_match (" kind = ") == MATCH_YES) + m = MATCH_ERROR; + + n = gfc_match_init_expr (&e); + if (n == MATCH_NO) + gfc_error ("Expected initialization expression at %C"); + if (n != MATCH_YES) + return MATCH_ERROR; + + if (e->rank != 0) + { + gfc_error ("Expected scalar initialization expression at %C"); + m = MATCH_ERROR; + goto no_match; + } + + msg = gfc_extract_int (e, &ts->kind); + if (msg != NULL) + { + gfc_error (msg); + m = MATCH_ERROR; + goto no_match; + } + + gfc_free_expr (e); + e = NULL; + + if (gfc_validate_kind (ts->type, ts->kind) == -1) + { + gfc_error ("Kind %d not supported for type %s at %C", ts->kind, + gfc_basic_typename (ts->type)); + + m = MATCH_ERROR; + goto no_match; + } + + if (gfc_match_char (')') != MATCH_YES) + { + gfc_error ("Missing right paren at %C"); + goto no_match; + } + + return MATCH_YES; + +no_match: + gfc_free_expr (e); + gfc_set_locus (&where); + return m; +} + + +/* Match the various kind/length specifications in a CHARACTER + declaration. We don't return MATCH_NO. */ + +static match +match_char_spec (gfc_typespec * ts) +{ + int i, kind, seen_length; + gfc_charlen *cl; + gfc_expr *len; + match m; + + kind = gfc_default_character_kind (); + len = NULL; + seen_length = 0; + + /* Try the old-style specification first. */ + old_char_selector = 0; + + m = match_char_length (&len); + if (m != MATCH_NO) + { + if (m == MATCH_YES) + old_char_selector = 1; + seen_length = 1; + goto done; + } + + m = gfc_match_char ('('); + if (m != MATCH_YES) + { + m = MATCH_YES; /* character without length is a single char */ + goto done; + } + + /* Try the weird case: ( KIND = [ , LEN = ] ) */ + if (gfc_match (" kind =") == MATCH_YES) + { + m = gfc_match_small_int (&kind); + if (m == MATCH_ERROR) + goto done; + if (m == MATCH_NO) + goto syntax; + + if (gfc_match (" , len =") == MATCH_NO) + goto rparen; + + m = char_len_param_value (&len); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto done; + seen_length = 1; + + goto rparen; + } + + /* Try to match ( LEN = ) or ( LEN = , KIND = ) */ + if (gfc_match (" len =") == MATCH_YES) + { + m = char_len_param_value (&len); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto done; + seen_length = 1; + + if (gfc_match_char (')') == MATCH_YES) + goto done; + + if (gfc_match (" , kind =") != MATCH_YES) + goto syntax; + + gfc_match_small_int (&kind); + + if (gfc_validate_kind (BT_CHARACTER, kind) == -1) + { + gfc_error ("Kind %d is not a CHARACTER kind at %C", kind); + return MATCH_YES; + } + + goto rparen; + } + + /* Try to match ( ) or ( , [ KIND = ] ) */ + m = char_len_param_value (&len); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto done; + seen_length = 1; + + m = gfc_match_char (')'); + if (m == MATCH_YES) + goto done; + + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + gfc_match (" kind ="); /* Gobble optional text */ + + m = gfc_match_small_int (&kind); + if (m == MATCH_ERROR) + goto done; + if (m == MATCH_NO) + goto syntax; + +rparen: + /* Require a right-paren at this point. */ + m = gfc_match_char (')'); + if (m == MATCH_YES) + goto done; + +syntax: + gfc_error ("Syntax error in CHARACTER declaration at %C"); + m = MATCH_ERROR; + +done: + if (m == MATCH_YES && gfc_validate_kind (BT_CHARACTER, kind) == -1) + { + gfc_error ("Kind %d is not a CHARACTER kind at %C", kind); + m = MATCH_ERROR; + } + + if (m != MATCH_YES) + { + gfc_free_expr (len); + return m; + } + + /* Do some final massaging of the length values. */ + cl = gfc_get_charlen (); + cl->next = gfc_current_ns->cl_list; + gfc_current_ns->cl_list = cl; + + if (seen_length == 0) + cl->length = gfc_int_expr (1); + else + { + if (len == NULL || gfc_extract_int (len, &i) != NULL || i >= 0) + cl->length = len; + else + { + gfc_free_expr (len); + cl->length = gfc_int_expr (0); + } + } + + ts->cl = cl; + ts->kind = kind; + + return MATCH_YES; +} + + +/* Matches a type specification. If successful, sets the ts structure + to the matched specification. This is necessary for FUNCTION and + IMPLICIT statements. + + If kind_flag is nonzero, then we check for the optional kind + specification. Not doing so is needed for matching an IMPLICIT + statement correctly. */ + +match +gfc_match_type_spec (gfc_typespec * ts, int kind_flag) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + match m; + + gfc_clear_ts (ts); + + if (gfc_match (" integer") == MATCH_YES) + { + ts->type = BT_INTEGER; + ts->kind = gfc_default_integer_kind (); + goto get_kind; + } + + if (gfc_match (" character") == MATCH_YES) + { + ts->type = BT_CHARACTER; + return match_char_spec (ts); + } + + if (gfc_match (" real") == MATCH_YES) + { + ts->type = BT_REAL; + ts->kind = gfc_default_real_kind (); + goto get_kind; + } + + if (gfc_match (" double precision") == MATCH_YES) + { + ts->type = BT_REAL; + ts->kind = gfc_default_double_kind (); + return MATCH_YES; + } + + if (gfc_match (" complex") == MATCH_YES) + { + ts->type = BT_COMPLEX; + ts->kind = gfc_default_complex_kind (); + goto get_kind; + } + + if (gfc_match (" double complex") == MATCH_YES) + { + ts->type = BT_COMPLEX; + ts->kind = gfc_default_double_kind (); + return MATCH_YES; + } + + if (gfc_match (" logical") == MATCH_YES) + { + ts->type = BT_LOGICAL; + ts->kind = gfc_default_logical_kind (); + goto get_kind; + } + + m = gfc_match (" type ( %n )", name); + if (m != MATCH_YES) + return m; + + /* Search for the name but allow the components to be defined later. */ + if (gfc_get_ha_symbol (name, &sym)) + { + gfc_error ("Type name '%s' at %C is ambiguous", name); + return MATCH_ERROR; + } + + if (sym->attr.flavor != FL_DERIVED + && gfc_add_flavor (&sym->attr, FL_DERIVED, NULL) == FAILURE) + return MATCH_ERROR; + + ts->type = BT_DERIVED; + ts->kind = 0; + ts->derived = sym; + + return MATCH_YES; + +get_kind: + /* For all types except double, derived and character, look for an + optional kind specifier. MATCH_NO is actually OK at this point. */ + if (kind_flag == 0) + return MATCH_YES; + + m = gfc_match_kind_spec (ts); + if (m == MATCH_NO && ts->type != BT_CHARACTER) + m = gfc_match_old_kind_spec (ts); + + if (m == MATCH_NO) + m = MATCH_YES; /* No kind specifier found. */ + + return m; +} + + +/* Matches an attribute specification including array specs. If + successful, leaves the variables current_attr and current_as + holding the specification. Also sets the colon_seen variable for + later use by matchers associated with initializations. + + This subroutine is a little tricky in the sense that we don't know + if we really have an attr-spec until we hit the double colon. + Until that time, we can only return MATCH_NO. This forces us to + check for duplicate specification at this level. */ + +static match +match_attr_spec (void) +{ + + /* Modifiers that can exist in a type statement. */ + typedef enum + { GFC_DECL_BEGIN = 0, + DECL_ALLOCATABLE = GFC_DECL_BEGIN, DECL_DIMENSION, DECL_EXTERNAL, + DECL_IN, DECL_OUT, DECL_INOUT, DECL_INTRINSIC, DECL_OPTIONAL, + DECL_PARAMETER, DECL_POINTER, DECL_PRIVATE, DECL_PUBLIC, DECL_SAVE, + DECL_TARGET, DECL_COLON, DECL_NONE, + GFC_DECL_END /* Sentinel */ + } + decl_types; + +/* GFC_DECL_END is the sentinel, index starts at 0. */ +#define NUM_DECL GFC_DECL_END + + static mstring decls[] = { + minit (", allocatable", DECL_ALLOCATABLE), + minit (", dimension", DECL_DIMENSION), + minit (", external", DECL_EXTERNAL), + minit (", intent ( in )", DECL_IN), + minit (", intent ( out )", DECL_OUT), + minit (", intent ( in out )", DECL_INOUT), + minit (", intrinsic", DECL_INTRINSIC), + minit (", optional", DECL_OPTIONAL), + minit (", parameter", DECL_PARAMETER), + minit (", pointer", DECL_POINTER), + minit (", private", DECL_PRIVATE), + minit (", public", DECL_PUBLIC), + minit (", save", DECL_SAVE), + minit (", target", DECL_TARGET), + minit ("::", DECL_COLON), + minit (NULL, DECL_NONE) + }; + + locus start, seen_at[NUM_DECL]; + int seen[NUM_DECL]; + decl_types d; + const char *attr; + match m; + try t; + + gfc_clear_attr (¤t_attr); + start = *gfc_current_locus (); + + current_as = NULL; + colon_seen = 0; + + /* See if we get all of the keywords up to the final double colon. */ + for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++) + seen[d] = 0; + + for (;;) + { + d = (decl_types) gfc_match_strings (decls); + if (d == DECL_NONE || d == DECL_COLON) + break; + + seen[d]++; + seen_at[d] = *gfc_current_locus (); + + if (d == DECL_DIMENSION) + { + m = gfc_match_array_spec (¤t_as); + + if (m == MATCH_NO) + { + gfc_error ("Missing dimension specification at %C"); + m = MATCH_ERROR; + } + + if (m == MATCH_ERROR) + goto cleanup; + } + } + + /* No double colon, so assume that we've been looking at something + else the whole time. */ + if (d == DECL_NONE) + { + m = MATCH_NO; + goto cleanup; + } + + /* Since we've seen a double colon, we have to be looking at an + attr-spec. This means that we can now issue errors. */ + for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++) + if (seen[d] > 1) + { + switch (d) + { + case DECL_ALLOCATABLE: + attr = "ALLOCATABLE"; + break; + case DECL_DIMENSION: + attr = "DIMENSION"; + break; + case DECL_EXTERNAL: + attr = "EXTERNAL"; + break; + case DECL_IN: + attr = "INTENT (IN)"; + break; + case DECL_OUT: + attr = "INTENT (OUT)"; + break; + case DECL_INOUT: + attr = "INTENT (IN OUT)"; + break; + case DECL_INTRINSIC: + attr = "INTRINSIC"; + break; + case DECL_OPTIONAL: + attr = "OPTIONAL"; + break; + case DECL_PARAMETER: + attr = "PARAMETER"; + break; + case DECL_POINTER: + attr = "POINTER"; + break; + case DECL_PRIVATE: + attr = "PRIVATE"; + break; + case DECL_PUBLIC: + attr = "PUBLIC"; + break; + case DECL_SAVE: + attr = "SAVE"; + break; + case DECL_TARGET: + attr = "TARGET"; + break; + default: + attr = NULL; /* This shouldn't happen */ + } + + gfc_error ("Duplicate %s attribute at %L", attr, &seen_at[d]); + m = MATCH_ERROR; + goto cleanup; + } + + /* Now that we've dealt with duplicate attributes, add the attributes + to the current attribute. */ + for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++) + { + if (seen[d] == 0) + continue; + + if (gfc_current_state () == COMP_DERIVED + && d != DECL_DIMENSION && d != DECL_POINTER + && d != DECL_COLON && d != DECL_NONE) + { + + gfc_error ("Attribute at %L is not allowed in a TYPE definition", + &seen_at[d]); + m = MATCH_ERROR; + goto cleanup; + } + + switch (d) + { + case DECL_ALLOCATABLE: + t = gfc_add_allocatable (¤t_attr, &seen_at[d]); + break; + + case DECL_DIMENSION: + t = gfc_add_dimension (¤t_attr, &seen_at[d]); + break; + + case DECL_EXTERNAL: + t = gfc_add_external (¤t_attr, &seen_at[d]); + break; + + case DECL_IN: + t = gfc_add_intent (¤t_attr, INTENT_IN, &seen_at[d]); + break; + + case DECL_OUT: + t = gfc_add_intent (¤t_attr, INTENT_OUT, &seen_at[d]); + break; + + case DECL_INOUT: + t = gfc_add_intent (¤t_attr, INTENT_INOUT, &seen_at[d]); + break; + + case DECL_INTRINSIC: + t = gfc_add_intrinsic (¤t_attr, &seen_at[d]); + break; + + case DECL_OPTIONAL: + t = gfc_add_optional (¤t_attr, &seen_at[d]); + break; + + case DECL_PARAMETER: + t = gfc_add_flavor (¤t_attr, FL_PARAMETER, &seen_at[d]); + break; + + case DECL_POINTER: + t = gfc_add_pointer (¤t_attr, &seen_at[d]); + break; + + case DECL_PRIVATE: + t = gfc_add_access (¤t_attr, ACCESS_PRIVATE, &seen_at[d]); + break; + + case DECL_PUBLIC: + t = gfc_add_access (¤t_attr, ACCESS_PUBLIC, &seen_at[d]); + break; + + case DECL_SAVE: + t = gfc_add_save (¤t_attr, &seen_at[d]); + break; + + case DECL_TARGET: + t = gfc_add_target (¤t_attr, &seen_at[d]); + break; + + default: + gfc_internal_error ("match_attr_spec(): Bad attribute"); + } + + if (t == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + } + + colon_seen = 1; + return MATCH_YES; + +cleanup: + gfc_set_locus (&start); + gfc_free_array_spec (current_as); + current_as = NULL; + return m; +} + + +/* Match a data declaration statement. */ + +match +gfc_match_data_decl (void) +{ + gfc_symbol *sym; + match m; + + m = gfc_match_type_spec (¤t_ts, 1); + if (m != MATCH_YES) + return m; + + if (current_ts.type == BT_DERIVED && gfc_current_state () != COMP_DERIVED) + { + sym = gfc_use_derived (current_ts.derived); + + if (sym == NULL) + { + m = MATCH_ERROR; + goto cleanup; + } + + current_ts.derived = sym; + } + + m = match_attr_spec (); + if (m == MATCH_ERROR) + { + m = MATCH_NO; + goto cleanup; + } + + if (current_ts.type == BT_DERIVED && current_ts.derived->components == NULL) + { + + if (current_attr.pointer && gfc_current_state () == COMP_DERIVED) + goto ok; + + if (gfc_find_symbol (current_ts.derived->name, + current_ts.derived->ns->parent, 1, &sym) == 0) + goto ok; + + /* Hope that an ambiguous symbol is itself masked by a type definition. */ + if (sym != NULL && sym->attr.flavor == FL_DERIVED) + goto ok; + + gfc_error ("Derived type at %C has not been previously defined"); + m = MATCH_ERROR; + goto cleanup; + } + +ok: + /* If we have an old-style character declaration, and no new-style + attribute specifications, then there a comma is optional between + the type specification and the variable list. */ + if (m == MATCH_NO && current_ts.type == BT_CHARACTER && old_char_selector) + gfc_match_char (','); + + /* Give the types/attributes to symbols that follow. */ + for (;;) + { + m = variable_decl (); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + break; + + if (gfc_match_eos () == MATCH_YES) + goto cleanup; + if (gfc_match_char (',') != MATCH_YES) + break; + } + + gfc_error ("Syntax error in data declaration at %C"); + m = MATCH_ERROR; + +cleanup: + gfc_free_array_spec (current_as); + current_as = NULL; + return m; +} + + +/* Match a prefix associated with a function or subroutine + declaration. If the typespec pointer is nonnull, then a typespec + can be matched. Note that if nothing matches, MATCH_YES is + returned (the null string was matched). */ + +static match +match_prefix (gfc_typespec * ts) +{ + int seen_type; + + gfc_clear_attr (¤t_attr); + seen_type = 0; + +loop: + if (!seen_type && ts != NULL + && gfc_match_type_spec (ts, 1) == MATCH_YES + && gfc_match_space () == MATCH_YES) + { + + seen_type = 1; + goto loop; + } + + if (gfc_match ("elemental% ") == MATCH_YES) + { + if (gfc_add_elemental (¤t_attr, NULL) == FAILURE) + return MATCH_ERROR; + + goto loop; + } + + if (gfc_match ("pure% ") == MATCH_YES) + { + if (gfc_add_pure (¤t_attr, NULL) == FAILURE) + return MATCH_ERROR; + + goto loop; + } + + if (gfc_match ("recursive% ") == MATCH_YES) + { + if (gfc_add_recursive (¤t_attr, NULL) == FAILURE) + return MATCH_ERROR; + + goto loop; + } + + /* At this point, the next item is not a prefix. */ + return MATCH_YES; +} + + +/* Copy attributes matched by match_prefix() to attributes on a symbol. */ + +static try +copy_prefix (symbol_attribute * dest, locus * where) +{ + + if (current_attr.pure && gfc_add_pure (dest, where) == FAILURE) + return FAILURE; + + if (current_attr.elemental && gfc_add_elemental (dest, where) == FAILURE) + return FAILURE; + + if (current_attr.recursive && gfc_add_recursive (dest, where) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Match a formal argument list. */ + +match +gfc_match_formal_arglist (gfc_symbol * progname, int st_flag, int null_flag) +{ + gfc_formal_arglist *head, *tail, *p, *q; + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + match m; + + head = tail = NULL; + + if (gfc_match_char ('(') != MATCH_YES) + { + if (null_flag) + goto ok; + return MATCH_NO; + } + + if (gfc_match_char (')') == MATCH_YES) + goto ok; + + for (;;) + { + if (gfc_match_char ('*') == MATCH_YES) + sym = NULL; + else + { + m = gfc_match_name (name); + if (m != MATCH_YES) + goto cleanup; + + if (gfc_get_symbol (name, NULL, &sym)) + goto cleanup; + } + + p = gfc_get_formal_arglist (); + + if (head == NULL) + head = tail = p; + else + { + tail->next = p; + tail = p; + } + + tail->sym = sym; + + /* We don't add the VARIABLE flavor because the name could be a + dummy procedure. We don't apply these attributes to formal + arguments of statement functions. */ + if (sym != NULL && !st_flag + && (gfc_add_dummy (&sym->attr, NULL) == FAILURE + || gfc_missing_attr (&sym->attr, NULL) == FAILURE)) + { + m = MATCH_ERROR; + goto cleanup; + } + + /* The name of a program unit can be in a different namespace, + so check for it explicitly. After the statement is accepted, + the name is checked for especially in gfc_get_symbol(). */ + if (gfc_new_block != NULL && sym != NULL + && strcmp (sym->name, gfc_new_block->name) == 0) + { + gfc_error ("Name '%s' at %C is the name of the procedure", + sym->name); + m = MATCH_ERROR; + goto cleanup; + } + + if (gfc_match_char (')') == MATCH_YES) + goto ok; + + m = gfc_match_char (','); + if (m != MATCH_YES) + { + gfc_error ("Unexpected junk in formal argument list at %C"); + goto cleanup; + } + } + +ok: + /* Check for duplicate symbols in the formal argument list. */ + if (head != NULL) + { + for (p = head; p->next; p = p->next) + { + if (p->sym == NULL) + continue; + + for (q = p->next; q; q = q->next) + if (p->sym == q->sym) + { + gfc_error + ("Duplicate symbol '%s' in formal argument list at %C", + p->sym->name); + + m = MATCH_ERROR; + goto cleanup; + } + } + } + + if (gfc_add_explicit_interface (progname, IFSRC_DECL, head, NULL) == + FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + return MATCH_YES; + +cleanup: + gfc_free_formal_arglist (head); + return m; +} + + +/* Match a RESULT specification following a function declaration or + ENTRY statement. Also matches the end-of-statement. */ + +static match +match_result (gfc_symbol * function, gfc_symbol ** result) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *r; + match m; + + if (gfc_match (" result (") != MATCH_YES) + return MATCH_NO; + + m = gfc_match_name (name); + if (m != MATCH_YES) + return m; + + if (gfc_match (" )%t") != MATCH_YES) + { + gfc_error ("Unexpected junk following RESULT variable at %C"); + return MATCH_ERROR; + } + + if (strcmp (function->name, name) == 0) + { + gfc_error + ("RESULT variable at %C must be different than function name"); + return MATCH_ERROR; + } + + if (gfc_get_symbol (name, NULL, &r)) + return MATCH_ERROR; + + if (gfc_add_flavor (&r->attr, FL_VARIABLE, NULL) == FAILURE + || gfc_add_result (&r->attr, NULL) == FAILURE) + return MATCH_ERROR; + + *result = r; + + return MATCH_YES; +} + + +/* Match a function declaration. */ + +match +gfc_match_function_decl (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym, *result; + locus old_loc; + match m; + + if (gfc_current_state () != COMP_NONE + && gfc_current_state () != COMP_INTERFACE + && gfc_current_state () != COMP_CONTAINS) + return MATCH_NO; + + gfc_clear_ts (¤t_ts); + + old_loc = *gfc_current_locus (); + + m = match_prefix (¤t_ts); + if (m != MATCH_YES) + { + gfc_set_locus (&old_loc); + return m; + } + + if (gfc_match ("function% %n", name) != MATCH_YES) + { + gfc_set_locus (&old_loc); + return MATCH_NO; + } + + if (get_proc_name (name, &sym)) + return MATCH_ERROR; + gfc_new_block = sym; + + m = gfc_match_formal_arglist (sym, 0, 0); + if (m == MATCH_NO) + gfc_error ("Expected formal argument list in function definition at %C"); + else if (m == MATCH_ERROR) + goto cleanup; + + result = NULL; + + if (gfc_match_eos () != MATCH_YES) + { + /* See if a result variable is present. */ + m = match_result (sym, &result); + if (m == MATCH_NO) + gfc_error ("Unexpected junk after function declaration at %C"); + + if (m != MATCH_YES) + { + m = MATCH_ERROR; + goto cleanup; + } + } + + /* Make changes to the symbol. */ + m = MATCH_ERROR; + + if (gfc_add_function (&sym->attr, NULL) == FAILURE) + goto cleanup; + + if (gfc_missing_attr (&sym->attr, NULL) == FAILURE + || copy_prefix (&sym->attr, &sym->declared_at) == FAILURE) + goto cleanup; + + if (current_ts.type != BT_UNKNOWN && sym->ts.type != BT_UNKNOWN) + { + gfc_error ("Function '%s' at %C already has a type of %s", name, + gfc_basic_typename (sym->ts.type)); + goto cleanup; + } + + if (result == NULL) + { + sym->ts = current_ts; + sym->result = sym; + } + else + { + result->ts = current_ts; + sym->result = result; + } + + return MATCH_YES; + +cleanup: + gfc_set_locus (&old_loc); + return m; +} + + +/* Match an ENTRY statement. */ + +match +gfc_match_entry (void) +{ + gfc_symbol *function, *result, *entry; + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_compile_state state; + match m; + + m = gfc_match_name (name); + if (m != MATCH_YES) + return m; + + if (get_proc_name (name, &entry)) + return MATCH_ERROR; + + gfc_enclosing_unit (&state); + switch (state) + { + case COMP_SUBROUTINE: + m = gfc_match_formal_arglist (entry, 0, 1); + if (m != MATCH_YES) + return MATCH_ERROR; + + if (gfc_current_state () != COMP_SUBROUTINE) + goto exec_construct; + + if (gfc_add_entry (&entry->attr, NULL) == FAILURE + || gfc_add_subroutine (&entry->attr, NULL) == FAILURE) + return MATCH_ERROR; + + break; + + case COMP_FUNCTION: + m = gfc_match_formal_arglist (entry, 0, 0); + if (m != MATCH_YES) + return MATCH_ERROR; + + if (gfc_current_state () != COMP_FUNCTION) + goto exec_construct; + function = gfc_state_stack->sym; + + result = NULL; + + if (gfc_match_eos () == MATCH_YES) + { + if (gfc_add_entry (&entry->attr, NULL) == FAILURE + || gfc_add_function (&entry->attr, NULL) == FAILURE) + return MATCH_ERROR; + + entry->result = function->result; + + } + else + { + m = match_result (function, &result); + if (m == MATCH_NO) + gfc_syntax_error (ST_ENTRY); + if (m != MATCH_YES) + return MATCH_ERROR; + + if (gfc_add_result (&result->attr, NULL) == FAILURE + || gfc_add_entry (&entry->attr, NULL) == FAILURE + || gfc_add_function (&entry->attr, NULL) == FAILURE) + return MATCH_ERROR; + } + + if (function->attr.recursive && result == NULL) + { + gfc_error ("RESULT attribute required in ENTRY statement at %C"); + return MATCH_ERROR; + } + + break; + + default: + goto exec_construct; + } + + if (gfc_match_eos () != MATCH_YES) + { + gfc_syntax_error (ST_ENTRY); + return MATCH_ERROR; + } + + return MATCH_YES; + +exec_construct: + gfc_error ("ENTRY statement at %C cannot appear within %s", + gfc_state_name (gfc_current_state ())); + + return MATCH_ERROR; +} + + +/* Match a subroutine statement, including optional prefixes. */ + +match +gfc_match_subroutine (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + match m; + + if (gfc_current_state () != COMP_NONE + && gfc_current_state () != COMP_INTERFACE + && gfc_current_state () != COMP_CONTAINS) + return MATCH_NO; + + m = match_prefix (NULL); + if (m != MATCH_YES) + return m; + + m = gfc_match ("subroutine% %n", name); + if (m != MATCH_YES) + return m; + + if (get_proc_name (name, &sym)) + return MATCH_ERROR; + gfc_new_block = sym; + + if (gfc_add_subroutine (&sym->attr, NULL) == FAILURE) + return MATCH_ERROR; + + if (gfc_match_formal_arglist (sym, 0, 1) != MATCH_YES) + return MATCH_ERROR; + + if (gfc_match_eos () != MATCH_YES) + { + gfc_syntax_error (ST_SUBROUTINE); + return MATCH_ERROR; + } + + if (copy_prefix (&sym->attr, &sym->declared_at) == FAILURE) + return MATCH_ERROR; + + return MATCH_YES; +} + + +/* Match any of the various end-block statements. Returns the type of + END to the caller. The END INTERFACE, END IF, END DO and END + SELECT statements cannot be replaced by a single END statement. */ + +match +gfc_match_end (gfc_statement * st) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_compile_state state; + locus old_loc; + const char *block_name; + const char *target; + match m; + + old_loc = *gfc_current_locus (); + if (gfc_match ("end") != MATCH_YES) + return MATCH_NO; + + state = gfc_current_state (); + block_name = + gfc_current_block () == NULL ? NULL : gfc_current_block ()->name; + + if (state == COMP_CONTAINS) + { + state = gfc_state_stack->previous->state; + block_name = gfc_state_stack->previous->sym == NULL ? NULL + : gfc_state_stack->previous->sym->name; + } + + switch (state) + { + case COMP_NONE: + case COMP_PROGRAM: + *st = ST_END_PROGRAM; + target = " program"; + break; + + case COMP_SUBROUTINE: + *st = ST_END_SUBROUTINE; + target = " subroutine"; + break; + + case COMP_FUNCTION: + *st = ST_END_FUNCTION; + target = " function"; + break; + + case COMP_BLOCK_DATA: + *st = ST_END_BLOCK_DATA; + target = " block data"; + break; + + case COMP_MODULE: + *st = ST_END_MODULE; + target = " module"; + break; + + case COMP_INTERFACE: + *st = ST_END_INTERFACE; + target = " interface"; + break; + + case COMP_DERIVED: + *st = ST_END_TYPE; + target = " type"; + break; + + case COMP_IF: + *st = ST_ENDIF; + target = " if"; + break; + + case COMP_DO: + *st = ST_ENDDO; + target = " do"; + break; + + case COMP_SELECT: + *st = ST_END_SELECT; + target = " select"; + break; + + case COMP_FORALL: + *st = ST_END_FORALL; + target = " forall"; + break; + + case COMP_WHERE: + *st = ST_END_WHERE; + target = " where"; + break; + + default: + gfc_error ("Unexpected END statement at %C"); + goto cleanup; + } + + if (gfc_match_eos () == MATCH_YES) + { + + if (*st == ST_ENDIF || *st == ST_ENDDO || *st == ST_END_SELECT + || *st == ST_END_INTERFACE || *st == ST_END_FORALL + || *st == ST_END_WHERE) + { + + gfc_error ("%s statement expected at %C", + gfc_ascii_statement (*st)); + goto cleanup; + } + + return MATCH_YES; + } + + /* Verify that we've got the sort of end-block that we're expecting. */ + if (gfc_match (target) != MATCH_YES) + { + gfc_error ("Expecting %s statement at %C", gfc_ascii_statement (*st)); + goto cleanup; + } + + /* If we're at the end, make sure a block name wasn't required. */ + if (gfc_match_eos () == MATCH_YES) + { + + if (*st != ST_ENDDO && *st != ST_ENDIF && *st != ST_END_SELECT) + return MATCH_YES; + + if (gfc_current_block () == NULL) + return MATCH_YES; + + gfc_error ("Expected block name of '%s' in %s statement at %C", + block_name, gfc_ascii_statement (*st)); + + return MATCH_ERROR; + } + + /* END INTERFACE has a special handler for its several possible endings. */ + if (*st == ST_END_INTERFACE) + return gfc_match_end_interface (); + + /* We haven't hit the end of statement, so what is left must be an end-name. */ + m = gfc_match_space (); + if (m == MATCH_YES) + m = gfc_match_name (name); + + if (m == MATCH_NO) + gfc_error ("Expected terminating name at %C"); + if (m != MATCH_YES) + goto cleanup; + + if (block_name == NULL) + goto syntax; + + if (strcmp (name, block_name) != 0) + { + gfc_error ("Expected label '%s' for %s statement at %C", block_name, + gfc_ascii_statement (*st)); + goto cleanup; + } + + if (gfc_match_eos () == MATCH_YES) + return MATCH_YES; + +syntax: + gfc_syntax_error (*st); + +cleanup: + gfc_set_locus (&old_loc); + return MATCH_ERROR; +} + + + +/***************** Attribute declaration statements ****************/ + +/* Set the attribute of a single variable. */ + +static match +attr_decl1 (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_array_spec *as; + gfc_symbol *sym; + locus var_locus; + match m; + + as = NULL; + + m = gfc_match_name (name); + if (m != MATCH_YES) + goto cleanup; + + if (find_special (name, &sym)) + return MATCH_ERROR; + + var_locus = *gfc_current_locus (); + + /* Deal with possible array specification for certain attributes. */ + if (current_attr.dimension + || current_attr.allocatable + || current_attr.pointer + || current_attr.target) + { + m = gfc_match_array_spec (&as); + if (m == MATCH_ERROR) + goto cleanup; + + if (current_attr.dimension && m == MATCH_NO) + { + gfc_error + ("Missing array specification at %L in DIMENSION statement", + &var_locus); + m = MATCH_ERROR; + goto cleanup; + } + + if ((current_attr.allocatable || current_attr.pointer) + && (m == MATCH_YES) && (as->type != AS_DEFERRED)) + { + gfc_error ("Array specification must be deferred at %L", + &var_locus); + m = MATCH_ERROR; + goto cleanup; + } + } + + /* Update symbol table. DIMENSION attribute is set in gfc_set_array_spec(). */ + if (current_attr.dimension == 0 + && gfc_copy_attr (&sym->attr, ¤t_attr, NULL) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + if (gfc_set_array_spec (sym, as, &var_locus) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + if ((current_attr.external || current_attr.intrinsic) + && sym->attr.flavor != FL_PROCEDURE + && gfc_add_flavor (&sym->attr, FL_PROCEDURE, NULL) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + return MATCH_YES; + +cleanup: + gfc_free_array_spec (as); + return m; +} + + +/* Generic attribute declaration subroutine. Used for attributes that + just have a list of names. */ + +static match +attr_decl (void) +{ + match m; + + /* Gobble the optional double colon, by simply ignoring the result + of gfc_match(). */ + gfc_match (" ::"); + + for (;;) + { + m = attr_decl1 (); + if (m != MATCH_YES) + break; + + if (gfc_match_eos () == MATCH_YES) + { + m = MATCH_YES; + break; + } + + if (gfc_match_char (',') != MATCH_YES) + { + gfc_error ("Unexpected character in variable list at %C"); + m = MATCH_ERROR; + break; + } + } + + return m; +} + + +match +gfc_match_external (void) +{ + + gfc_clear_attr (¤t_attr); + gfc_add_external (¤t_attr, NULL); + + return attr_decl (); +} + + + +match +gfc_match_intent (void) +{ + sym_intent intent; + + intent = match_intent_spec (); + if (intent == INTENT_UNKNOWN) + return MATCH_ERROR; + + gfc_clear_attr (¤t_attr); + gfc_add_intent (¤t_attr, intent, NULL); /* Can't fail */ + + return attr_decl (); +} + + +match +gfc_match_intrinsic (void) +{ + + gfc_clear_attr (¤t_attr); + gfc_add_intrinsic (¤t_attr, NULL); + + return attr_decl (); +} + + +match +gfc_match_optional (void) +{ + + gfc_clear_attr (¤t_attr); + gfc_add_optional (¤t_attr, NULL); + + return attr_decl (); +} + + +match +gfc_match_pointer (void) +{ + + gfc_clear_attr (¤t_attr); + gfc_add_pointer (¤t_attr, NULL); + + return attr_decl (); +} + + +match +gfc_match_allocatable (void) +{ + + gfc_clear_attr (¤t_attr); + gfc_add_allocatable (¤t_attr, NULL); + + return attr_decl (); +} + + +match +gfc_match_dimension (void) +{ + + gfc_clear_attr (¤t_attr); + gfc_add_dimension (¤t_attr, NULL); + + return attr_decl (); +} + + +match +gfc_match_target (void) +{ + + gfc_clear_attr (¤t_attr); + gfc_add_target (¤t_attr, NULL); + + return attr_decl (); +} + + +/* Match the list of entities being specified in a PUBLIC or PRIVATE + statement. */ + +static match +access_attr_decl (gfc_statement st) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + interface_type type; + gfc_user_op *uop; + gfc_symbol *sym; + gfc_intrinsic_op operator; + match m; + + if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO) + goto done; + + for (;;) + { + m = gfc_match_generic_spec (&type, name, &operator); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + return MATCH_ERROR; + + switch (type) + { + case INTERFACE_NAMELESS: + goto syntax; + + case INTERFACE_GENERIC: + if (gfc_get_symbol (name, NULL, &sym)) + goto done; + + if (gfc_add_access (&sym->attr, + (st == + ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE, + NULL) == FAILURE) + return MATCH_ERROR; + + break; + + case INTERFACE_INTRINSIC_OP: + if (gfc_current_ns->operator_access[operator] == ACCESS_UNKNOWN) + { + gfc_current_ns->operator_access[operator] = + (st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE; + } + else + { + gfc_error ("Access specification of the %s operator at %C has " + "already been specified", gfc_op2string (operator)); + goto done; + } + + break; + + case INTERFACE_USER_OP: + uop = gfc_get_uop (name); + + if (uop->access == ACCESS_UNKNOWN) + { + uop->access = + (st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE; + } + else + { + gfc_error + ("Access specification of the .%s. operator at %C has " + "already been specified", sym->name); + goto done; + } + + break; + } + + if (gfc_match_char (',') == MATCH_NO) + break; + } + + if (gfc_match_eos () != MATCH_YES) + goto syntax; + return MATCH_YES; + +syntax: + gfc_syntax_error (st); + +done: + return MATCH_ERROR; +} + + +/* The PRIVATE statement is a bit weird in that it can be a attribute + declaration, but also works as a standlone statement inside of a + type declaration or a module. */ + +match +gfc_match_private (gfc_statement * st) +{ + + if (gfc_match ("private") != MATCH_YES) + return MATCH_NO; + + if (gfc_current_state () == COMP_DERIVED) + { + if (gfc_match_eos () == MATCH_YES) + { + *st = ST_PRIVATE; + return MATCH_YES; + } + + gfc_syntax_error (ST_PRIVATE); + return MATCH_ERROR; + } + + if (gfc_match_eos () == MATCH_YES) + { + *st = ST_PRIVATE; + return MATCH_YES; + } + + *st = ST_ATTR_DECL; + return access_attr_decl (ST_PRIVATE); +} + + +match +gfc_match_public (gfc_statement * st) +{ + + if (gfc_match ("public") != MATCH_YES) + return MATCH_NO; + + if (gfc_match_eos () == MATCH_YES) + { + *st = ST_PUBLIC; + return MATCH_YES; + } + + *st = ST_ATTR_DECL; + return access_attr_decl (ST_PUBLIC); +} + + +/* Workhorse for gfc_match_parameter. */ + +static match +do_parm (void) +{ + gfc_symbol *sym; + gfc_expr *init; + match m; + + m = gfc_match_symbol (&sym, 0); + if (m == MATCH_NO) + gfc_error ("Expected variable name at %C in PARAMETER statement"); + + if (m != MATCH_YES) + return m; + + if (gfc_match_char ('=') == MATCH_NO) + { + gfc_error ("Expected = sign in PARAMETER statement at %C"); + return MATCH_ERROR; + } + + m = gfc_match_init_expr (&init); + if (m == MATCH_NO) + gfc_error ("Expected expression at %C in PARAMETER statement"); + if (m != MATCH_YES) + return m; + + if (sym->ts.type == BT_UNKNOWN + && gfc_set_default_type (sym, 1, NULL) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + if (gfc_check_assign_symbol (sym, init) == FAILURE + || gfc_add_flavor (&sym->attr, FL_PARAMETER, NULL) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + sym->value = init; + return MATCH_YES; + +cleanup: + gfc_free_expr (init); + return m; +} + + +/* Match a parameter statement, with the weird syntax that these have. */ + +match +gfc_match_parameter (void) +{ + match m; + + if (gfc_match_char ('(') == MATCH_NO) + return MATCH_NO; + + for (;;) + { + m = do_parm (); + if (m != MATCH_YES) + break; + + if (gfc_match (" )%t") == MATCH_YES) + break; + + if (gfc_match_char (',') != MATCH_YES) + { + gfc_error ("Unexpected characters in PARAMETER statement at %C"); + m = MATCH_ERROR; + break; + } + } + + return m; +} + + +/* Save statements have a special syntax. */ + +match +gfc_match_save (void) +{ + gfc_symbol *sym; + match m; + + if (gfc_match_eos () == MATCH_YES) + { + if (gfc_current_ns->seen_save) + { + gfc_error ("Blanket SAVE statement at %C follows previous " + "SAVE statement"); + + return MATCH_ERROR; + } + + gfc_current_ns->save_all = gfc_current_ns->seen_save = 1; + return MATCH_YES; + } + + if (gfc_current_ns->save_all) + { + gfc_error ("SAVE statement at %C follows blanket SAVE statement"); + return MATCH_ERROR; + } + + gfc_match (" ::"); + + for (;;) + { + m = gfc_match_symbol (&sym, 0); + switch (m) + { + case MATCH_YES: + if (gfc_add_save (&sym->attr, gfc_current_locus ()) == FAILURE) + return MATCH_ERROR; + goto next_item; + + case MATCH_NO: + break; + + case MATCH_ERROR: + return MATCH_ERROR; + } + + m = gfc_match (" / %s /", &sym); + if (m == MATCH_ERROR) + return MATCH_ERROR; + if (m == MATCH_NO) + goto syntax; + + if (gfc_add_saved_common (&sym->attr, NULL) == FAILURE) + return MATCH_ERROR; + gfc_current_ns->seen_save = 1; + + next_item: + if (gfc_match_eos () == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in SAVE statement at %C"); + return MATCH_ERROR; +} + + +/* Match a module procedure statement. Note that we have to modify + symbols in the parent's namespace because the current one was there + to receive symbols that are in a interface's formal argument list. */ + +match +gfc_match_modproc (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + match m; + + if (gfc_state_stack->state != COMP_INTERFACE + || gfc_state_stack->previous == NULL + || current_interface.type == INTERFACE_NAMELESS) + { + gfc_error + ("MODULE PROCEDURE at %C must be in a generic module interface"); + return MATCH_ERROR; + } + + for (;;) + { + m = gfc_match_name (name); + if (m == MATCH_NO) + goto syntax; + if (m != MATCH_YES) + return MATCH_ERROR; + + if (gfc_get_symbol (name, gfc_current_ns->parent, &sym)) + return MATCH_ERROR; + + if (sym->attr.proc != PROC_MODULE + && gfc_add_procedure (&sym->attr, PROC_MODULE, NULL) == FAILURE) + return MATCH_ERROR; + + if (gfc_add_interface (sym) == FAILURE) + return MATCH_ERROR; + + if (gfc_match_eos () == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_MODULE_PROC); + return MATCH_ERROR; +} + + +/* Match the beginning of a derived type declaration. If a type name + was the result of a function, then it is possible to have a symbol + already to be known as a derived type yet have no components. */ + +match +gfc_match_derived_decl (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + symbol_attribute attr; + gfc_symbol *sym; + match m; + + if (gfc_current_state () == COMP_DERIVED) + return MATCH_NO; + + gfc_clear_attr (&attr); + +loop: + if (gfc_match (" , private") == MATCH_YES) + { + if (gfc_find_state (COMP_MODULE) == FAILURE) + { + gfc_error + ("Derived type at %C can only be PRIVATE within a MODULE"); + return MATCH_ERROR; + } + + if (gfc_add_access (&attr, ACCESS_PRIVATE, NULL) == FAILURE) + return MATCH_ERROR; + goto loop; + } + + if (gfc_match (" , public") == MATCH_YES) + { + if (gfc_find_state (COMP_MODULE) == FAILURE) + { + gfc_error ("Derived type at %C can only be PUBLIC within a MODULE"); + return MATCH_ERROR; + } + + if (gfc_add_access (&attr, ACCESS_PUBLIC, NULL) == FAILURE) + return MATCH_ERROR; + goto loop; + } + + if (gfc_match (" ::") != MATCH_YES && attr.access != ACCESS_UNKNOWN) + { + gfc_error ("Expected :: in TYPE definition at %C"); + return MATCH_ERROR; + } + + m = gfc_match (" %n%t", name); + if (m != MATCH_YES) + return m; + + /* Make sure the name isn't the name of an intrinsic type. The + 'double precision' type doesn't get past the name matcher. */ + if (strcmp (name, "integer") == 0 + || strcmp (name, "real") == 0 + || strcmp (name, "character") == 0 + || strcmp (name, "logical") == 0 + || strcmp (name, "complex") == 0) + { + gfc_error + ("Type name '%s' at %C cannot be the same as an intrinsic type", + name); + return MATCH_ERROR; + } + + if (gfc_get_symbol (name, NULL, &sym)) + return MATCH_ERROR; + + if (sym->ts.type != BT_UNKNOWN) + { + gfc_error ("Derived type name '%s' at %C already has a basic type " + "of %s", sym->name, gfc_typename (&sym->ts)); + return MATCH_ERROR; + } + + /* The symbol may already have the derived attribute without the + components. The ways this can happen is via a function + definition, an INTRINSIC statement or a subtype in another + derived type that is a pointer. The first part of the AND clause + is true if a the symbol is not the return value of a function. */ + if (sym->attr.flavor != FL_DERIVED + && gfc_add_flavor (&sym->attr, FL_DERIVED, NULL) == FAILURE) + return MATCH_ERROR; + + if (sym->components != NULL) + { + gfc_error + ("Derived type definition of '%s' at %C has already been defined", + sym->name); + return MATCH_ERROR; + } + + if (attr.access != ACCESS_UNKNOWN + && gfc_add_access (&sym->attr, attr.access, NULL) == FAILURE) + return MATCH_ERROR; + + gfc_new_block = sym; + + return MATCH_YES; +} diff --git a/gcc/fortran/dependency.c b/gcc/fortran/dependency.c new file mode 100644 index 00000000000..03edb8f169f --- /dev/null +++ b/gcc/fortran/dependency.c @@ -0,0 +1,679 @@ +/* Dependency analysis + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* dependency.c -- Expression dependency analysis code. */ +/* There's probably quite a bit of duplication in this file. We currently + have different dependency checking functions for different types + if dependencies. Ideally these would probably be merged. */ + + +#include "config.h" +#include "gfortran.h" +#include "dependency.h" +#include + +/* static declarations */ +/* Enums */ +enum range {LHS, RHS, MID}; + +/* Dependency types. These must be in reverse order of priority. */ +typedef enum +{ + GFC_DEP_ERROR, + GFC_DEP_EQUAL, /* Identical Ranges. */ + GFC_DEP_FORWARD, /* eg. a(1:3), a(2:4). */ + GFC_DEP_OVERLAP, /* May overlap in some other way. */ + GFC_DEP_NODEP /* Distinct ranges. */ +} +gfc_dependency; + +/* Macros */ +#define IS_ARRAY_EXPLICIT(as) ((as->type == AS_EXPLICIT ? 1 : 0)) + + +/* Returns 1 if the expr is an integer constant value 1, 0 if it is not or + def if the value could not be determined. */ + +int +gfc_expr_is_one (gfc_expr * expr, int def) +{ + assert (expr != NULL); + + if (expr->expr_type != EXPR_CONSTANT) + return def; + + if (expr->ts.type != BT_INTEGER) + return def; + + return mpz_cmp_si (expr->value.integer, 1) == 0; +} + + +/* Compare two values. Returns 0 if e1 == e2, -1 if e1 < e2, +1 if e1 > e2, + and -2 if the relationship could not be determined. */ + +int +gfc_dep_compare_expr (gfc_expr * e1, gfc_expr * e2) +{ + int i; + + if (e1->expr_type != e2->expr_type) + return -2; + + switch (e1->expr_type) + { + case EXPR_CONSTANT: + if (e1->ts.type != BT_INTEGER || e2->ts.type != BT_INTEGER) + return -2; + + i = mpz_cmp (e1->value.integer, e2->value.integer); + if (i == 0) + return 0; + else if (i < 0) + return -1; + return 1; + + case EXPR_VARIABLE: + if (e1->ref || e2->ref) + return -2; + if (e1->symtree->n.sym == e2->symtree->n.sym) + return 0; + return -2; + + default: + return -2; + } +} + + +/* Returns 1 if the two ranges are the same, 0 if they are not, and def + if the results are indeterminate. N is the dimension to compare. */ + +int +gfc_is_same_range (gfc_array_ref * ar1, gfc_array_ref * ar2, int n, int def) +{ + gfc_expr *e1; + gfc_expr *e2; + int i; + + /* TODO: More sophisticated range comparison. */ + assert (ar1 && ar2); + + assert (ar1->dimen_type[n] == ar2->dimen_type[n]); + + e1 = ar1->stride[n]; + e2 = ar2->stride[n]; + /* Check for mismatching strides. A NULL stride means a stride of 1. */ + if (e1 && !e2) + { + i = gfc_expr_is_one (e1, -1); + if (i == -1) + return def; + else if (i == 0) + return 0; + } + else if (e2 && !e1) + { + i = gfc_expr_is_one (e2, -1); + if (i == -1) + return def; + else if (i == 0) + return 0; + } + else if (e1 && e2) + { + i = gfc_dep_compare_expr (e1, e2); + if (i == -2) + return def; + else if (i != 0) + return 0; + } + /* The strides match. */ + + /* Check the range start. */ + e1 = ar1->start[n]; + e2 = ar2->start[n]; + + if (!(e1 || e2)) + return 1; + + /* Use the bound of the array if no bound is specified. */ + if (ar1->as && !e1) + e1 = ar1->as->lower[n]; + + if (ar2->as && !e2) + e2 = ar2->as->upper[n]; + + /* Check we have values for both. */ + if (!(e1 && e2)) + return def; + + i = gfc_dep_compare_expr (e1, e2); + + if (i == -2) + return def; + else if (i == 0) + return 1; + return 0; +} + + +/* Dependency checking for direct function return by reference. + Returns true if the arguments of the function depend on the + destination. This is considerably less conservative than other + dependencies because many function arguments will already be + copied into a temporary. */ + +int +gfc_check_fncall_dependency (gfc_expr * dest, gfc_expr * fncall) +{ + gfc_actual_arglist *actual; + gfc_ref *ref; + gfc_expr *expr; + int n; + + assert (dest->expr_type == EXPR_VARIABLE + && fncall->expr_type == EXPR_FUNCTION); + assert (fncall->rank > 0); + + for (actual = fncall->value.function.actual; actual; actual = actual->next) + { + expr = actual->expr; + + /* Skip args which are not present. */ + if (!expr) + continue; + + /* Non-variable expressions will be allocated temporaries anyway. */ + switch (expr->expr_type) + { + case EXPR_VARIABLE: + if (expr->rank > 1) + { + /* This is an array section. */ + for (ref = expr->ref; ref; ref = ref->next) + { + if (ref->type == REF_ARRAY && ref->u.ar.type != AR_ELEMENT) + break; + } + assert (ref); + /* AR_FULL can't contain vector subscripts. */ + if (ref->u.ar.type == AR_SECTION) + { + for (n = 0; n < ref->u.ar.dimen; n++) + { + if (ref->u.ar.dimen_type[n] == DIMEN_VECTOR) + break; + } + /* Vector subscript array sections will be copied to a + temporary. */ + if (n != ref->u.ar.dimen) + continue; + } + } + + if (gfc_check_dependency (dest, actual->expr, NULL, 0)) + return 1; + break; + + case EXPR_ARRAY: + if (gfc_check_dependency (dest, expr, NULL, 0)) + return 1; + break; + + default: + break; + } + } + + return 0; +} + + +/* Return true if the statement body redefines the condition. Returns + true if expr2 depends on expr1. expr1 should be a single term + suitable for the lhs of an assignment. The symbols listed in VARS + must be considered to have all possible values. All other scalar + variables may be considered constant. Used for forall and where + statements. Also used with functions returning arrays without a + temporary. */ + +int +gfc_check_dependency (gfc_expr * expr1, gfc_expr * expr2, gfc_expr ** vars, + int nvars) +{ + gfc_ref *ref; + int n; + gfc_actual_arglist *actual; + + assert (expr1->expr_type == EXPR_VARIABLE); + + /* TODO: -fassume-no-pointer-aliasing */ + if (expr1->symtree->n.sym->attr.pointer) + return 1; + for (ref = expr1->ref; ref; ref = ref->next) + { + if (ref->type == REF_COMPONENT && ref->u.c.component->pointer) + return 1; + } + + switch (expr2->expr_type) + { + case EXPR_OP: + n = gfc_check_dependency (expr1, expr2->op1, vars, nvars); + if (n) + return n; + if (expr2->op2) + return gfc_check_dependency (expr1, expr2->op2, vars, nvars); + return 0; + + case EXPR_VARIABLE: + if (expr2->symtree->n.sym->attr.pointer) + return 1; + + for (ref = expr2->ref; ref; ref = ref->next) + { + if (ref->type == REF_COMPONENT && ref->u.c.component->pointer) + return 1; + } + + if (expr1->symtree->n.sym != expr2->symtree->n.sym) + return 0; + + for (ref = expr2->ref; ref; ref = ref->next) + { + /* Identical ranges return 0, overlapping ranges return 1. */ + if (ref->type == REF_ARRAY) + return 1; + } + return 1; + + case EXPR_FUNCTION: + /* Remember possible differences betweeen elemental and + transformational functions. All functions inside a FORALL + will be pure. */ + for (actual = expr2->value.function.actual; + actual; actual = actual->next) + { + if (!actual->expr) + continue; + n = gfc_check_dependency (expr1, actual->expr, vars, nvars); + if (n) + return n; + } + return 0; + + case EXPR_CONSTANT: + return 0; + + case EXPR_ARRAY: + /* Probably ok in the majority of (constant) cases. */ + return 1; + + default: + return 1; + } +} + + +/* Calculates size of the array reference using lower bound, upper bound + and stride. */ + +static void +get_no_of_elements(mpz_t ele, gfc_expr * u1, gfc_expr * l1, gfc_expr * s1) +{ + /* nNoOfEle = (u1-l1)/s1 */ + + mpz_sub (ele, u1->value.integer, l1->value.integer); + + if (s1 != NULL) + mpz_tdiv_q (ele, ele, s1->value.integer); +} + + +/* Returns if the ranges ((0..Y), (X1..X2)) overlap. */ + +static gfc_dependency +get_deps (mpz_t x1, mpz_t x2, mpz_t y) +{ + int start; + int end; + + start = mpz_cmp_ui (x1, 0); + end = mpz_cmp (x2, y); + + /* Both ranges the same. */ + if (start == 0 && end == 0) + return GFC_DEP_EQUAL; + + /* Distinct ranges. */ + if ((start < 0 && mpz_cmp_ui (x2, 0) < 0) + || (mpz_cmp (x1, y) > 0 && end > 0)) + return GFC_DEP_NODEP; + + /* Overlapping, but with corresponding elements of the second range + greater than the first. */ + if (start > 0 && end > 0) + return GFC_DEP_FORWARD; + + /* Overlapping in some other way. */ + return GFC_DEP_OVERLAP; +} + + +/* Transforms a sections l and r such that + (l_start:l_end:l_stride) -> (0:no_of_elements) + (r_start:r_end:r_stride) -> (X1:X2) + Where r_end is implicit as both sections must have the same number of + elelments. + Returns 0 on success, 1 of the transformation failed. */ +/* TODO: Should this be (0:no_of_elements-1) */ + +static int +transform_sections (mpz_t X1, mpz_t X2, mpz_t no_of_elements, + gfc_expr * l_start, gfc_expr * l_end, gfc_expr * l_stride, + gfc_expr * r_start, gfc_expr * r_stride) +{ + if (NULL == l_start || NULL == l_end || NULL == r_start) + return 1; + + /* TODO : Currently we check the dependency only when start, end and stride + are constant. We could also check for equal (variable) values, and + common subexpressions, eg. x vs. x+1. */ + + if (l_end->expr_type != EXPR_CONSTANT + || l_start->expr_type != EXPR_CONSTANT + || r_start->expr_type != EXPR_CONSTANT + || ((NULL != l_stride) && (l_stride->expr_type != EXPR_CONSTANT)) + || ((NULL != r_stride) && (r_stride->expr_type != EXPR_CONSTANT))) + { + return 1; + } + + + get_no_of_elements (no_of_elements, l_end, l_start, l_stride); + + mpz_sub (X1, r_start->value.integer, l_start->value.integer); + if (l_stride != NULL) + mpz_cdiv_q (X1, X1, l_stride->value.integer); + + if (r_stride == NULL) + mpz_set (X2, no_of_elements); + else + mpz_mul (X2, no_of_elements, r_stride->value.integer); + + if (l_stride != NULL) + mpz_cdiv_q (X2, X2, r_stride->value.integer); + mpz_add (X2, X2, X1); + + return 0; +} + + +/* Determines overlapping for two array sections. */ + +static gfc_dependency +gfc_check_section_vs_section (gfc_ref * lref, gfc_ref * rref, int n) +{ + gfc_expr *l_start; + gfc_expr *l_end; + gfc_expr *l_stride; + + gfc_expr *r_start; + gfc_expr *r_stride; + + gfc_array_ref l_ar; + gfc_array_ref r_ar; + + mpz_t no_of_elements; + mpz_t X1, X2; + gfc_dependency dep; + + l_ar = lref->u.ar; + r_ar = rref->u.ar; + + l_start = l_ar.start[n]; + l_end = l_ar.end[n]; + l_stride = l_ar.stride[n]; + r_start = r_ar.start[n]; + r_stride = r_ar.stride[n]; + + /* if l_start is NULL take it from array specifier */ + if (NULL == l_start && IS_ARRAY_EXPLICIT(l_ar.as)) + l_start = l_ar.as->lower[n]; + + /* if l_end is NULL take it from array specifier */ + if (NULL == l_end && IS_ARRAY_EXPLICIT(l_ar.as)) + l_end = l_ar.as->upper[n]; + + /* if r_start is NULL take it from array specifier */ + if (NULL == r_start && IS_ARRAY_EXPLICIT(r_ar.as)) + r_start = r_ar.as->lower[n]; + + mpz_init (X1); + mpz_init (X2); + mpz_init (no_of_elements); + + if (transform_sections (X1, X2, no_of_elements, + l_start, l_end, l_stride, + r_start, r_stride)) + dep = GFC_DEP_OVERLAP; + else + dep = get_deps (X1, X2, no_of_elements); + + mpz_clear (no_of_elements); + mpz_clear (X1); + mpz_clear (X2); + return dep; +} + + +/* Checks if the expr chk is inside the range left-right. + Returns GFC_DEP_NODEP if chk is outside the range, + GFC_DEP_OVERLAP otherwise. + Assumes left<=right. */ + +static gfc_dependency +gfc_is_inside_range (gfc_expr * chk, gfc_expr * left, gfc_expr * right) +{ + int l; + int r; + int s; + + s = gfc_dep_compare_expr (left, right); + if (s == -2) + return GFC_DEP_OVERLAP; + + l = gfc_dep_compare_expr (chk, left); + r = gfc_dep_compare_expr (chk, right); + + /* Check for indeterminate relationships. */ + if (l == -2 || r == -2 || s == -2) + return GFC_DEP_OVERLAP; + + if (s == 1) + { + /* When left>right we want to check for right <= chk <= left. */ + if (l <= 0 || r >= 0) + return GFC_DEP_OVERLAP; + } + else + { + /* Otherwise check for left <= chk <= right. */ + if (l >= 0 || r <= 0) + return GFC_DEP_OVERLAP; + } + + return GFC_DEP_NODEP; +} + + +/* Determines overlapping for a single element and a section. */ + +static gfc_dependency +gfc_check_element_vs_section( gfc_ref * lref, gfc_ref * rref, int n) +{ + gfc_array_ref l_ar; + gfc_array_ref r_ar; + gfc_expr *l_start; + gfc_expr *r_start; + gfc_expr *r_end; + + l_ar = lref->u.ar; + r_ar = rref->u.ar; + l_start = l_ar.start[n] ; + r_start = r_ar.start[n] ; + r_end = r_ar.end[n] ; + if (NULL == r_start && IS_ARRAY_EXPLICIT (r_ar.as)) + r_start = r_ar.as->lower[n]; + if (NULL == r_end && IS_ARRAY_EXPLICIT (r_ar.as)) + r_end = r_ar.as->upper[n]; + if (NULL == r_start || NULL == r_end || l_start == NULL) + return GFC_DEP_OVERLAP; + + return gfc_is_inside_range (l_start, r_end, r_start); +} + + +/* Determines overlapping for two single element array references. */ + +static gfc_dependency +gfc_check_element_vs_element (gfc_ref * lref, gfc_ref * rref, int n) +{ + gfc_array_ref l_ar; + gfc_array_ref r_ar; + gfc_expr *l_start; + gfc_expr *r_start; + gfc_dependency nIsDep; + + if (lref->type == REF_ARRAY && rref->type == REF_ARRAY) + { + l_ar = lref->u.ar; + r_ar = rref->u.ar; + l_start = l_ar.start[n] ; + r_start = r_ar.start[n] ; + if (gfc_dep_compare_expr (r_start, l_start) == 0) + nIsDep = GFC_DEP_EQUAL; + else + nIsDep = GFC_DEP_NODEP; + } + else + nIsDep = GFC_DEP_NODEP; + + return nIsDep; +} + + +/* Finds if two array references are overlapping or not. + Return value + 1 : array references are overlapping. + 0 : array references are not overlapping. */ + +int +gfc_dep_resolver (gfc_ref * lref, gfc_ref * rref) +{ + int n; + gfc_dependency fin_dep; + gfc_dependency this_dep; + + + fin_dep = GFC_DEP_ERROR; + /* Dependencies due to pointers should already have been identified. + We only need to check for overlapping array references. */ + + while (lref && rref) + { + /* We're resolving from the same base symbol, so both refs should be + the same type. We traverse the reference chain intil we find ranges + that are not equal. */ + assert (lref->type == rref->type); + switch (lref->type) + { + case REF_COMPONENT: + /* The two ranges can't overlap if they are from different + components. */ + if (lref->u.c.component != rref->u.c.component) + return 0; + break; + + case REF_SUBSTRING: + /* Substring overlaps are handled by the string assignment code. */ + return 0; + + case REF_ARRAY: + + for (n=0; n < lref->u.ar.dimen; n++) + { + /* Assume dependency when either of array reference is vector + subscript. */ + if (lref->u.ar.dimen_type[n] == DIMEN_VECTOR + || rref->u.ar.dimen_type[n] == DIMEN_VECTOR) + return 1; + if (lref->u.ar.dimen_type[n] == DIMEN_RANGE + && rref->u.ar.dimen_type[n] == DIMEN_RANGE) + this_dep = gfc_check_section_vs_section (lref, rref, n); + else if (lref->u.ar.dimen_type[n] == DIMEN_ELEMENT + && rref->u.ar.dimen_type[n] == DIMEN_RANGE) + this_dep = gfc_check_element_vs_section (lref, rref, n); + else if (rref->u.ar.dimen_type[n] == DIMEN_ELEMENT + && lref->u.ar.dimen_type[n] == DIMEN_RANGE) + this_dep = gfc_check_element_vs_section (rref, lref, n); + else + { + assert (rref->u.ar.dimen_type[n] == DIMEN_ELEMENT + && lref->u.ar.dimen_type[n] == DIMEN_ELEMENT); + this_dep = gfc_check_element_vs_element (rref, lref, n); + } + + /* If any dimension doesn't overlap, we have no dependency. */ + if (this_dep == GFC_DEP_NODEP) + return 0; + + /* Overlap codes are in order of priority. We only need to + know the worst one.*/ + if (this_dep > fin_dep) + fin_dep = this_dep; + } + /* Exactly matching and forward overlapping ranges don't cause a + dependency. */ + if (fin_dep < GFC_DEP_OVERLAP) + return 0; + + /* Keep checking. We only have a dependency if + subsequent references also overlap. */ + break; + + default: + abort(); + } + lref = lref->next; + rref = rref->next; + } + + /* If we haven't seen any array refs then something went wrong. */ + assert (fin_dep != GFC_DEP_ERROR); + + if (fin_dep < GFC_DEP_OVERLAP) + return 0; + else + return 1; +} + diff --git a/gcc/fortran/dependency.h b/gcc/fortran/dependency.h new file mode 100644 index 00000000000..42a33947505 --- /dev/null +++ b/gcc/fortran/dependency.h @@ -0,0 +1,30 @@ +/* Header for dependency analysis + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + + +int gfc_check_fncall_dependency (gfc_expr *, gfc_expr *); +int gfc_check_dependency (gfc_expr *, gfc_expr *, gfc_expr **, int); +int gfc_is_same_range (gfc_array_ref *, gfc_array_ref *, int, int); +int gfc_dep_compare_expr (gfc_expr *, gfc_expr *); +int gfc_expr_is_one (gfc_expr *, int); + +int gfc_dep_resolver(gfc_ref *, gfc_ref *); diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c new file mode 100644 index 00000000000..1083c6474bf --- /dev/null +++ b/gcc/fortran/dump-parse-tree.c @@ -0,0 +1,1459 @@ +/* Parse tree dumper + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Actually this is just a collection of routines that used to be + scattered around the sources. Now that they are all in a single + file, almost all of them can be static, and the other files don't + have this mess in them. + + As a nice side-effect, this file can act as documentation of the + gfc_code and gfc_expr structures and all their friends and + relatives. + + TODO: Dump DATA. */ + +#include "config.h" +#include "gfortran.h" + +/* Keep track of indentation for symbol tree dumps. */ +static int show_level = 0; + + +/* Forward declaration because this one needs all, and all need + this one. */ +static void gfc_show_expr (gfc_expr *); + +/* Do indentation for a specific level. */ + +static inline void +code_indent (int level, gfc_st_label * label) +{ + int i; + + if (label != NULL) + gfc_status ("%-5d ", label->value); + else + gfc_status (" "); + + for (i = 0; i < 2 * level; i++) + gfc_status_char (' '); +} + + +/* Simple indentation at the current level. This one + is used to show symbols. */ +static inline void +show_indent (void) +{ + gfc_status ("\n"); + code_indent (show_level, NULL); +} + + +/* Show type-specific information. */ +static void +gfc_show_typespec (gfc_typespec * ts) +{ + + gfc_status ("(%s ", gfc_basic_typename (ts->type)); + + switch (ts->type) + { + case BT_DERIVED: + gfc_status ("%s", ts->derived->name); + break; + + case BT_CHARACTER: + gfc_show_expr (ts->cl->length); + break; + + default: + gfc_status ("%d", ts->kind); + break; + } + + gfc_status (")"); +} + + +/* Show an actual argument list. */ + +static void +gfc_show_actual_arglist (gfc_actual_arglist * a) +{ + + gfc_status ("("); + + for (; a; a = a->next) + { + gfc_status_char ('('); + if (a->name[0] != '\0') + gfc_status ("%s = ", a->name); + if (a->expr != NULL) + gfc_show_expr (a->expr); + else + gfc_status ("(arg not-present)"); + + gfc_status_char (')'); + if (a->next != NULL) + gfc_status (" "); + } + + gfc_status (")"); +} + + +/* Show an gfc_array_spec array specification structure. */ + +static void +gfc_show_array_spec (gfc_array_spec * as) +{ + const char *c; + int i; + + if (as == NULL) + { + gfc_status ("()"); + return; + } + + gfc_status ("(%d", as->rank); + + if (as->rank != 0) + { + switch (as->type) + { + case AS_EXPLICIT: c = "AS_EXPLICIT"; break; + case AS_DEFERRED: c = "AS_DEFERRED"; break; + case AS_ASSUMED_SIZE: c = "AS_ASSUMED_SIZE"; break; + case AS_ASSUMED_SHAPE: c = "AS_ASSUMED_SHAPE"; break; + default: + gfc_internal_error + ("gfc_show_array_spec(): Unhandled array shape type."); + } + gfc_status (" %s ", c); + + for (i = 0; i < as->rank; i++) + { + gfc_show_expr (as->lower[i]); + gfc_status_char (' '); + gfc_show_expr (as->upper[i]); + gfc_status_char (' '); + } + } + + gfc_status (")"); +} + + +/* Show an gfc_array_ref array reference structure. */ + +static void +gfc_show_array_ref (gfc_array_ref * ar) +{ + int i; + + gfc_status_char ('('); + + switch (ar->type) + { + case AR_FULL: + gfc_status ("FULL"); + break; + + case AR_SECTION: + for (i = 0; i < ar->dimen; i++) + { + if (ar->start[i] != NULL) + gfc_show_expr (ar->start[i]); + + gfc_status_char (':'); + + if (ar->end[i] != NULL) + gfc_show_expr (ar->end[i]); + + if (ar->stride[i] != NULL) + { + gfc_status_char (':'); + gfc_show_expr (ar->stride[i]); + } + + if (i != ar->dimen - 1) + gfc_status (" , "); + } + break; + + case AR_ELEMENT: + for (i = 0; i < ar->dimen; i++) + { + gfc_show_expr (ar->start[i]); + if (i != ar->dimen - 1) + gfc_status (" , "); + } + break; + + case AR_UNKNOWN: + gfc_status ("UNKNOWN"); + break; + + default: + gfc_internal_error ("gfc_show_array_ref(): Unknown array reference"); + } + + gfc_status_char (')'); +} + + +/* Show a list of gfc_ref structures. */ + +static void +gfc_show_ref (gfc_ref * p) +{ + + for (; p; p = p->next) + switch (p->type) + { + case REF_ARRAY: + gfc_show_array_ref (&p->u.ar); + break; + + case REF_COMPONENT: + gfc_status (" %% %s", p->u.c.component->name); + break; + + case REF_SUBSTRING: + gfc_status_char ('('); + gfc_show_expr (p->u.ss.start); + gfc_status_char (':'); + gfc_show_expr (p->u.ss.end); + gfc_status_char (')'); + break; + + default: + gfc_internal_error ("gfc_show_ref(): Bad component code"); + } +} + + +/* Display a constructor. Works recursively for array constructors. */ + +static void +gfc_show_constructor (gfc_constructor * c) +{ + + for (; c; c = c->next) + { + if (c->iterator == NULL) + gfc_show_expr (c->expr); + else + { + gfc_status_char ('('); + gfc_show_expr (c->expr); + + gfc_status_char (' '); + gfc_show_expr (c->iterator->var); + gfc_status_char ('='); + gfc_show_expr (c->iterator->start); + gfc_status_char (','); + gfc_show_expr (c->iterator->end); + gfc_status_char (','); + gfc_show_expr (c->iterator->step); + + gfc_status_char (')'); + } + + if (c->next != NULL) + gfc_status (" , "); + } +} + + +/* Show an expression. */ + +static void +gfc_show_expr (gfc_expr * p) +{ + const char *c; + int i; + + if (p == NULL) + { + gfc_status ("()"); + return; + } + + switch (p->expr_type) + { + case EXPR_SUBSTRING: + c = p->value.character.string; + + for (i = 0; i < p->value.character.length; i++, c++) + { + if (*c == '\'') + gfc_status ("''"); + else + gfc_status ("%c", *c); + } + + gfc_show_ref (p->ref); + break; + + case EXPR_STRUCTURE: + gfc_status ("%s(", p->ts.derived->name); + gfc_show_constructor (p->value.constructor); + gfc_status_char (')'); + break; + + case EXPR_ARRAY: + gfc_status ("(/ "); + gfc_show_constructor (p->value.constructor); + gfc_status (" /)"); + + gfc_show_ref (p->ref); + break; + + case EXPR_NULL: + gfc_status ("NULL()"); + break; + + case EXPR_CONSTANT: + switch (p->ts.type) + { + case BT_INTEGER: + mpz_out_str (stdout, 10, p->value.integer); + + if (p->ts.kind != gfc_default_integer_kind ()) + gfc_status ("_%d", p->ts.kind); + break; + + case BT_LOGICAL: + if (p->value.logical) + gfc_status (".true."); + else + gfc_status (".false."); + break; + + case BT_REAL: + mpf_out_str (stdout, 10, 0, p->value.real); + if (p->ts.kind != gfc_default_real_kind ()) + gfc_status ("_%d", p->ts.kind); + break; + + case BT_CHARACTER: + c = p->value.character.string; + + gfc_status_char ('\''); + + for (i = 0; i < p->value.character.length; i++, c++) + { + if (*c == '\'') + gfc_status ("''"); + else + gfc_status_char (*c); + } + + gfc_status_char ('\''); + + break; + + case BT_COMPLEX: + gfc_status ("(complex "); + + mpf_out_str (stdout, 10, 0, p->value.complex.r); + if (p->ts.kind != gfc_default_complex_kind ()) + gfc_status ("_%d", p->ts.kind); + + gfc_status (" "); + + mpf_out_str (stdout, 10, 0, p->value.complex.i); + if (p->ts.kind != gfc_default_complex_kind ()) + gfc_status ("_%d", p->ts.kind); + + gfc_status (")"); + break; + + default: + gfc_status ("???"); + break; + } + + break; + + case EXPR_VARIABLE: + gfc_status ("%s", p->symtree->n.sym->name); + gfc_show_ref (p->ref); + break; + + case EXPR_OP: + gfc_status ("("); + switch (p->operator) + { + case INTRINSIC_UPLUS: + gfc_status ("U+ "); + break; + case INTRINSIC_UMINUS: + gfc_status ("U- "); + break; + case INTRINSIC_PLUS: + gfc_status ("+ "); + break; + case INTRINSIC_MINUS: + gfc_status ("- "); + break; + case INTRINSIC_TIMES: + gfc_status ("* "); + break; + case INTRINSIC_DIVIDE: + gfc_status ("/ "); + break; + case INTRINSIC_POWER: + gfc_status ("** "); + break; + case INTRINSIC_CONCAT: + gfc_status ("// "); + break; + case INTRINSIC_AND: + gfc_status ("AND "); + break; + case INTRINSIC_OR: + gfc_status ("OR "); + break; + case INTRINSIC_EQV: + gfc_status ("EQV "); + break; + case INTRINSIC_NEQV: + gfc_status ("NEQV "); + break; + case INTRINSIC_EQ: + gfc_status ("= "); + break; + case INTRINSIC_NE: + gfc_status ("<> "); + break; + case INTRINSIC_GT: + gfc_status ("> "); + break; + case INTRINSIC_GE: + gfc_status (">= "); + break; + case INTRINSIC_LT: + gfc_status ("< "); + break; + case INTRINSIC_LE: + gfc_status ("<= "); + break; + case INTRINSIC_NOT: + gfc_status ("NOT "); + break; + + default: + gfc_internal_error + ("gfc_show_expr(): Bad intrinsic in expression!"); + } + + gfc_show_expr (p->op1); + + if (p->op2) + { + gfc_status (" "); + gfc_show_expr (p->op2); + } + + gfc_status (")"); + break; + + case EXPR_FUNCTION: + if (p->value.function.name == NULL) + { + gfc_status ("%s[", p->symtree->n.sym->name); + gfc_show_actual_arglist (p->value.function.actual); + gfc_status_char (']'); + } + else + { + gfc_status ("%s[[", p->value.function.name); + gfc_show_actual_arglist (p->value.function.actual); + gfc_status_char (']'); + gfc_status_char (']'); + } + + break; + + default: + gfc_internal_error ("gfc_show_expr(): Don't know how to show expr"); + } +} + + +/* Show symbol attributes. The flavor and intent are followed by + whatever single bit attributes are present. */ + +static void +gfc_show_attr (symbol_attribute * attr) +{ + + gfc_status ("(%s %s %s %s", gfc_code2string (flavors, attr->flavor), + gfc_intent_string (attr->intent), + gfc_code2string (access_types, attr->access), + gfc_code2string (procedures, attr->proc)); + + if (attr->allocatable) + gfc_status (" ALLOCATABLE"); + if (attr->dimension) + gfc_status (" DIMENSION"); + if (attr->external) + gfc_status (" EXTERNAL"); + if (attr->intrinsic) + gfc_status (" INTRINSIC"); + if (attr->optional) + gfc_status (" OPTIONAL"); + if (attr->pointer) + gfc_status (" POINTER"); + if (attr->save) + gfc_status (" SAVE"); + if (attr->target) + gfc_status (" TARGET"); + if (attr->dummy) + gfc_status (" DUMMY"); + if (attr->common) + gfc_status (" COMMON"); + if (attr->result) + gfc_status (" RESULT"); + if (attr->entry) + gfc_status (" ENTRY"); + + if (attr->data) + gfc_status (" DATA"); + if (attr->use_assoc) + gfc_status (" USE-ASSOC"); + if (attr->in_namelist) + gfc_status (" IN-NAMELIST"); + if (attr->in_common) + gfc_status (" IN-COMMON"); + if (attr->saved_common) + gfc_status (" SAVED-COMMON"); + + if (attr->function) + gfc_status (" FUNCTION"); + if (attr->subroutine) + gfc_status (" SUBROUTINE"); + if (attr->implicit_type) + gfc_status (" IMPLICIT-TYPE"); + + if (attr->sequence) + gfc_status (" SEQUENCE"); + if (attr->elemental) + gfc_status (" ELEMENTAL"); + if (attr->pure) + gfc_status (" PURE"); + if (attr->recursive) + gfc_status (" RECURSIVE"); + + gfc_status (")"); +} + + +/* Show components of a derived type. */ + +static void +gfc_show_components (gfc_symbol * sym) +{ + gfc_component *c; + + for (c = sym->components; c; c = c->next) + { + gfc_status ("(%s ", c->name); + gfc_show_typespec (&c->ts); + if (c->pointer) + gfc_status (" POINTER"); + if (c->dimension) + gfc_status (" DIMENSION"); + gfc_status_char (' '); + gfc_show_array_spec (c->as); + gfc_status (")"); + if (c->next != NULL) + gfc_status_char (' '); + } +} + + +/* Show a symbol. If a symbol is an ENTRY, SUBROUTINE or FUNCTION, we + show the interface. Information needed to reconstruct the list of + specific interfaces associated with a generic symbol is done within + that symbol. */ + +static void +gfc_show_symbol (gfc_symbol * sym) +{ + gfc_formal_arglist *formal; + gfc_interface *intr; + gfc_symbol *s; + + if (sym == NULL) + return; + + show_indent (); + + gfc_status ("symbol %s ", sym->name); + gfc_show_typespec (&sym->ts); + gfc_show_attr (&sym->attr); + + if (sym->value) + { + show_indent (); + gfc_status ("value: "); + gfc_show_expr (sym->value); + } + + if (sym->as) + { + show_indent (); + gfc_status ("Array spec:"); + gfc_show_array_spec (sym->as); + } + + if (sym->generic) + { + show_indent (); + gfc_status ("Generic interfaces:"); + for (intr = sym->generic; intr; intr = intr->next) + gfc_status (" %s", intr->sym->name); + } + + if (sym->common_head) + { + show_indent (); + gfc_status ("Common members:"); + for (s = sym->common_head; s; s = s->common_next) + gfc_status (" %s", s->name); + } + + if (sym->result) + { + show_indent (); + gfc_status ("result: %s", sym->result->name); + } + + if (sym->components) + { + show_indent (); + gfc_status ("components: "); + gfc_show_components (sym); + } + + if (sym->formal) + { + show_indent (); + gfc_status ("Formal arglist:"); + + for (formal = sym->formal; formal; formal = formal->next) + gfc_status (" %s", formal->sym->name); + } + + if (sym->formal_ns) + { + show_indent (); + gfc_status ("Formal namespace"); + gfc_show_namespace (sym->formal_ns); + } + + gfc_status_char ('\n'); +} + + +/* Show a user-defined operator. Just prints an operator + and the name of the associated subroutine, really. */ +static void +show_uop (gfc_user_op * uop) +{ + gfc_interface *intr; + + show_indent (); + gfc_status ("%s:", uop->name); + + for (intr = uop->operator; intr; intr = intr->next) + gfc_status (" %s", intr->sym->name); +} + + +/* Workhorse function for traversing the user operator symtree. */ + +static void +traverse_uop (gfc_symtree * st, void (*func) (gfc_user_op *)) +{ + + if (st == NULL) + return; + + (*func) (st->n.uop); + + traverse_uop (st->left, func); + traverse_uop (st->right, func); +} + + +/* Traverse the tree of user operator nodes. */ + +void +gfc_traverse_user_op (gfc_namespace * ns, void (*func) (gfc_user_op *)) +{ + + traverse_uop (ns->uop_root, func); +} + + +/* Worker function to display the symbol tree. */ + +static void +show_symtree (gfc_symtree * st) +{ + + show_indent (); + gfc_status ("symtree: %s Ambig %d", st->name, st->ambiguous); + + if (st->n.sym->ns != gfc_current_ns) + gfc_status (" from namespace %s", st->n.sym->ns->proc_name->name); + else + gfc_show_symbol (st->n.sym); +} + + +/******************* Show gfc_code structures **************/ + + + +static void gfc_show_code_node (int level, gfc_code * c); + +/* Show a list of code structures. Mutually recursive with + gfc_show_code_node(). */ + +static void +gfc_show_code (int level, gfc_code * c) +{ + + for (; c; c = c->next) + gfc_show_code_node (level, c); +} + + +/* Show a single code node and everything underneath it if necessary. */ + +static void +gfc_show_code_node (int level, gfc_code * c) +{ + gfc_forall_iterator *fa; + gfc_open *open; + gfc_case *cp; + gfc_alloc *a; + gfc_code *d; + gfc_close *close; + gfc_filepos *fp; + gfc_inquire *i; + gfc_dt *dt; + + code_indent (level, c->here); + + switch (c->op) + { + case EXEC_NOP: + gfc_status ("NOP"); + break; + + case EXEC_CONTINUE: + gfc_status ("CONTINUE"); + break; + + case EXEC_ASSIGN: + gfc_status ("ASSIGN "); + gfc_show_expr (c->expr); + gfc_status_char (' '); + gfc_show_expr (c->expr2); + break; + case EXEC_LABEL_ASSIGN: + gfc_status ("LABEL ASSIGN "); + gfc_show_expr (c->expr); + gfc_status (" %d", c->label->value); + break; + + case EXEC_POINTER_ASSIGN: + gfc_status ("POINTER ASSIGN "); + gfc_show_expr (c->expr); + gfc_status_char (' '); + gfc_show_expr (c->expr2); + break; + + case EXEC_GOTO: + gfc_status ("GOTO "); + if (c->label) + gfc_status ("%d", c->label->value); + else + { + gfc_show_expr (c->expr); + d = c->block; + if (d != NULL) + { + gfc_status (", ("); + for (; d; d = d ->block) + { + code_indent (level, d->label); + if (d->block != NULL) + gfc_status_char (','); + else + gfc_status_char (')'); + } + } + } + break; + + case EXEC_CALL: + gfc_status ("CALL %s ", c->resolved_sym->name); + gfc_show_actual_arglist (c->ext.actual); + break; + + case EXEC_RETURN: + gfc_status ("RETURN "); + if (c->expr) + gfc_show_expr (c->expr); + break; + + case EXEC_PAUSE: + gfc_status ("PAUSE "); + + if (c->expr != NULL) + gfc_show_expr (c->expr); + else + gfc_status ("%d", c->ext.stop_code); + + break; + + case EXEC_STOP: + gfc_status ("STOP "); + + if (c->expr != NULL) + gfc_show_expr (c->expr); + else + gfc_status ("%d", c->ext.stop_code); + + break; + + case EXEC_ARITHMETIC_IF: + gfc_status ("IF "); + gfc_show_expr (c->expr); + gfc_status (" %d, %d, %d", + c->label->value, c->label2->value, c->label3->value); + break; + + case EXEC_IF: + d = c->block; + gfc_status ("IF "); + gfc_show_expr (d->expr); + gfc_status_char ('\n'); + gfc_show_code (level + 1, d->next); + + d = d->block; + for (; d; d = d->block) + { + code_indent (level, 0); + + if (d->expr == NULL) + gfc_status ("ELSE\n"); + else + { + gfc_status ("ELSE IF "); + gfc_show_expr (d->expr); + gfc_status_char ('\n'); + } + + gfc_show_code (level + 1, d->next); + } + + code_indent (level, c->label); + + gfc_status ("ENDIF"); + break; + + case EXEC_SELECT: + d = c->block; + gfc_status ("SELECT CASE "); + gfc_show_expr (c->expr); + gfc_status_char ('\n'); + + for (; d; d = d->block) + { + code_indent (level, 0); + + gfc_status ("CASE "); + for (cp = d->ext.case_list; cp; cp = cp->next) + { + gfc_status_char ('('); + gfc_show_expr (cp->low); + gfc_status_char (' '); + gfc_show_expr (cp->high); + gfc_status_char (')'); + gfc_status_char (' '); + } + gfc_status_char ('\n'); + + gfc_show_code (level + 1, d->next); + } + + code_indent (level, c->label); + gfc_status ("END SELECT"); + break; + + case EXEC_WHERE: + gfc_status ("WHERE "); + + d = c->block; + gfc_show_expr (d->expr); + gfc_status_char ('\n'); + + gfc_show_code (level + 1, d->next); + + for (d = d->block; d; d = d->block) + { + code_indent (level, 0); + gfc_status ("ELSE WHERE "); + gfc_show_expr (d->expr); + gfc_status_char ('\n'); + gfc_show_code (level + 1, d->next); + } + + code_indent (level, 0); + gfc_status ("END WHERE"); + break; + + + case EXEC_FORALL: + gfc_status ("FORALL "); + for (fa = c->ext.forall_iterator; fa; fa = fa->next) + { + gfc_show_expr (fa->var); + gfc_status_char (' '); + gfc_show_expr (fa->start); + gfc_status_char (':'); + gfc_show_expr (fa->end); + gfc_status_char (':'); + gfc_show_expr (fa->stride); + + if (fa->next != NULL) + gfc_status_char (','); + } + + if (c->expr != NULL) + { + gfc_status_char (','); + gfc_show_expr (c->expr); + } + gfc_status_char ('\n'); + + gfc_show_code (level + 1, c->block->next); + + code_indent (level, 0); + gfc_status ("END FORALL"); + break; + + case EXEC_DO: + gfc_status ("DO "); + + gfc_show_expr (c->ext.iterator->var); + gfc_status_char ('='); + gfc_show_expr (c->ext.iterator->start); + gfc_status_char (' '); + gfc_show_expr (c->ext.iterator->end); + gfc_status_char (' '); + gfc_show_expr (c->ext.iterator->step); + gfc_status_char ('\n'); + + gfc_show_code (level + 1, c->block->next); + + code_indent (level, 0); + gfc_status ("END DO"); + break; + + case EXEC_DO_WHILE: + gfc_status ("DO WHILE "); + gfc_show_expr (c->expr); + gfc_status_char ('\n'); + + gfc_show_code (level + 1, c->block->next); + + code_indent (level, c->label); + gfc_status ("END DO"); + break; + + case EXEC_CYCLE: + gfc_status ("CYCLE"); + if (c->symtree) + gfc_status (" %s", c->symtree->n.sym->name); + break; + + case EXEC_EXIT: + gfc_status ("EXIT"); + if (c->symtree) + gfc_status (" %s", c->symtree->n.sym->name); + break; + + case EXEC_ALLOCATE: + gfc_status ("ALLOCATE "); + if (c->expr) + { + gfc_status (" STAT="); + gfc_show_expr (c->expr); + } + + for (a = c->ext.alloc_list; a; a = a->next) + { + gfc_status_char (' '); + gfc_show_expr (a->expr); + } + + break; + + case EXEC_DEALLOCATE: + gfc_status ("DEALLOCATE "); + if (c->expr) + { + gfc_status (" STAT="); + gfc_show_expr (c->expr); + } + + for (a = c->ext.alloc_list; a; a = a->next) + { + gfc_status_char (' '); + gfc_show_expr (a->expr); + } + + break; + + case EXEC_OPEN: + gfc_status ("OPEN"); + open = c->ext.open; + + if (open->unit) + { + gfc_status (" UNIT="); + gfc_show_expr (open->unit); + } + if (open->iostat) + { + gfc_status (" IOSTAT="); + gfc_show_expr (open->iostat); + } + if (open->file) + { + gfc_status (" FILE="); + gfc_show_expr (open->file); + } + if (open->status) + { + gfc_status (" STATUS="); + gfc_show_expr (open->status); + } + if (open->access) + { + gfc_status (" ACCESS="); + gfc_show_expr (open->access); + } + if (open->form) + { + gfc_status (" FORM="); + gfc_show_expr (open->form); + } + if (open->recl) + { + gfc_status (" RECL="); + gfc_show_expr (open->recl); + } + if (open->blank) + { + gfc_status (" BLANK="); + gfc_show_expr (open->blank); + } + if (open->position) + { + gfc_status (" POSITION="); + gfc_show_expr (open->position); + } + if (open->action) + { + gfc_status (" ACTION="); + gfc_show_expr (open->action); + } + if (open->delim) + { + gfc_status (" DELIM="); + gfc_show_expr (open->delim); + } + if (open->pad) + { + gfc_status (" PAD="); + gfc_show_expr (open->pad); + } + if (open->err != NULL) + gfc_status (" ERR=%d", open->err->value); + + break; + + case EXEC_CLOSE: + gfc_status ("CLOSE"); + close = c->ext.close; + + if (close->unit) + { + gfc_status (" UNIT="); + gfc_show_expr (close->unit); + } + if (close->iostat) + { + gfc_status (" IOSTAT="); + gfc_show_expr (close->iostat); + } + if (close->status) + { + gfc_status (" STATUS="); + gfc_show_expr (close->status); + } + if (close->err != NULL) + gfc_status (" ERR=%d", close->err->value); + break; + + case EXEC_BACKSPACE: + gfc_status ("BACKSPACE"); + goto show_filepos; + + case EXEC_ENDFILE: + gfc_status ("ENDFILE"); + goto show_filepos; + + case EXEC_REWIND: + gfc_status ("REWIND"); + + show_filepos: + fp = c->ext.filepos; + + if (fp->unit) + { + gfc_status (" UNIT="); + gfc_show_expr (fp->unit); + } + if (fp->iostat) + { + gfc_status (" IOSTAT="); + gfc_show_expr (fp->iostat); + } + if (fp->err != NULL) + gfc_status (" ERR=%d", fp->err->value); + break; + + case EXEC_INQUIRE: + gfc_status ("INQUIRE"); + i = c->ext.inquire; + + if (i->unit) + { + gfc_status (" UNIT="); + gfc_show_expr (i->unit); + } + if (i->file) + { + gfc_status (" FILE="); + gfc_show_expr (i->file); + } + + if (i->iostat) + { + gfc_status (" IOSTAT="); + gfc_show_expr (i->iostat); + } + if (i->exist) + { + gfc_status (" EXIST="); + gfc_show_expr (i->exist); + } + if (i->opened) + { + gfc_status (" OPENED="); + gfc_show_expr (i->opened); + } + if (i->number) + { + gfc_status (" NUMBER="); + gfc_show_expr (i->number); + } + if (i->named) + { + gfc_status (" NAMED="); + gfc_show_expr (i->named); + } + if (i->name) + { + gfc_status (" NAME="); + gfc_show_expr (i->name); + } + if (i->access) + { + gfc_status (" ACCESS="); + gfc_show_expr (i->access); + } + if (i->sequential) + { + gfc_status (" SEQUENTIAL="); + gfc_show_expr (i->sequential); + } + + if (i->direct) + { + gfc_status (" DIRECT="); + gfc_show_expr (i->direct); + } + if (i->form) + { + gfc_status (" FORM="); + gfc_show_expr (i->form); + } + if (i->formatted) + { + gfc_status (" FORMATTED"); + gfc_show_expr (i->formatted); + } + if (i->unformatted) + { + gfc_status (" UNFORMATTED="); + gfc_show_expr (i->unformatted); + } + if (i->recl) + { + gfc_status (" RECL="); + gfc_show_expr (i->recl); + } + if (i->nextrec) + { + gfc_status (" NEXTREC="); + gfc_show_expr (i->nextrec); + } + if (i->blank) + { + gfc_status (" BLANK="); + gfc_show_expr (i->blank); + } + if (i->position) + { + gfc_status (" POSITION="); + gfc_show_expr (i->position); + } + if (i->action) + { + gfc_status (" ACTION="); + gfc_show_expr (i->action); + } + if (i->read) + { + gfc_status (" READ="); + gfc_show_expr (i->read); + } + if (i->write) + { + gfc_status (" WRITE="); + gfc_show_expr (i->write); + } + if (i->readwrite) + { + gfc_status (" READWRITE="); + gfc_show_expr (i->readwrite); + } + if (i->delim) + { + gfc_status (" DELIM="); + gfc_show_expr (i->delim); + } + if (i->pad) + { + gfc_status (" PAD="); + gfc_show_expr (i->pad); + } + + if (i->err != NULL) + gfc_status (" ERR=%d", i->err->value); + break; + + case EXEC_IOLENGTH: + gfc_status ("IOLENGTH "); + gfc_show_expr (c->expr); + break; + + case EXEC_READ: + gfc_status ("READ"); + goto show_dt; + + case EXEC_WRITE: + gfc_status ("WRITE"); + + show_dt: + dt = c->ext.dt; + if (dt->io_unit) + { + gfc_status (" UNIT="); + gfc_show_expr (dt->io_unit); + } + + if (dt->format_expr) + { + gfc_status (" FMT="); + gfc_show_expr (dt->format_expr); + } + + if (dt->format_label != NULL) + gfc_status (" FMT=%d", dt->format_label->value); + if (dt->namelist) + gfc_status (" NML=%s", dt->namelist->name); + if (dt->iostat) + { + gfc_status (" IOSTAT="); + gfc_show_expr (dt->iostat); + } + if (dt->size) + { + gfc_status (" SIZE="); + gfc_show_expr (dt->size); + } + if (dt->rec) + { + gfc_status (" REC="); + gfc_show_expr (dt->rec); + } + if (dt->advance) + { + gfc_status (" ADVANCE="); + gfc_show_expr (dt->advance); + } + + break; + + case EXEC_TRANSFER: + gfc_status ("TRANSFER "); + gfc_show_expr (c->expr); + break; + + case EXEC_DT_END: + gfc_status ("DT_END"); + dt = c->ext.dt; + + if (dt->err != NULL) + gfc_status (" ERR=%d", dt->err->value); + if (dt->end != NULL) + gfc_status (" END=%d", dt->end->value); + if (dt->eor != NULL) + gfc_status (" EOR=%d", dt->eor->value); + break; + + default: + gfc_internal_error ("gfc_show_code_node(): Bad statement code"); + } + + gfc_status_char ('\n'); +} + + +/* Show a freakin' whole namespace. */ + +void +gfc_show_namespace (gfc_namespace * ns) +{ + gfc_interface *intr; + gfc_namespace *save; + gfc_intrinsic_op op; + int i; + + save = gfc_current_ns; + show_level++; + + show_indent (); + gfc_status ("Namespace:"); + + if (ns != NULL) + { + i = 0; + do + { + int l = i; + while (i < GFC_LETTERS - 1 + && gfc_compare_types(&ns->default_type[i+1], + &ns->default_type[l])) + i++; + + if (i > l) + gfc_status(" %c-%c: ", l+'A', i+'A'); + else + gfc_status(" %c: ", l+'A'); + + gfc_show_typespec(&ns->default_type[l]); + i++; + } while (i < GFC_LETTERS); + + if (ns->proc_name != NULL) + { + show_indent (); + gfc_status ("procedure name = %s", ns->proc_name->name); + } + + gfc_current_ns = ns; + gfc_traverse_symtree (ns, show_symtree); + + for (op = GFC_INTRINSIC_BEGIN; op != GFC_INTRINSIC_END; op++) + { + /* User operator interfaces */ + intr = ns->operator[op]; + if (intr == NULL) + continue; + + show_indent (); + gfc_status ("Operator interfaces for %s:", gfc_op2string (op)); + + for (; intr; intr = intr->next) + gfc_status (" %s", intr->sym->name); + } + + if (ns->uop_root != NULL) + { + show_indent (); + gfc_status ("User operators:\n"); + gfc_traverse_user_op (ns, show_uop); + } + } + + gfc_status_char ('\n'); + gfc_status_char ('\n'); + + gfc_show_code (0, ns->code); + + for (ns = ns->contained; ns; ns = ns->sibling) + { + show_indent (); + gfc_status ("CONTAINS\n"); + gfc_show_namespace (ns); + } + + show_level--; + gfc_status_char ('\n'); + gfc_current_ns = save; +} diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c new file mode 100644 index 00000000000..be3d991f55d --- /dev/null +++ b/gcc/fortran/error.c @@ -0,0 +1,750 @@ +/* Handle errors. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught & Niels Kristian Bech Jensen + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Handle the inevitable errors. A major catch here is that things + flagged as errors in one match subroutine can conceivably be legal + elsewhere. This means that error messages are recorded and saved + for possible use later. If a line does not match a legal + construction, then the saved error message is reported. */ + +#include "config.h" +#include "system.h" + +#include +#include +#include +#include + +#include "flags.h" +#include "gfortran.h" + +int gfc_suppress_error = 0; + +static int terminal_width, buffer_flag, errors, + use_warning_buffer, warnings; + +static char *error_ptr, *warning_ptr; + +static gfc_error_buf error_buffer, warning_buffer; + + +/* Per-file error initialization. */ + +void +gfc_error_init_1 (void) +{ + + terminal_width = gfc_terminal_width(); + errors = 0; + warnings = 0; + buffer_flag = 0; +} + + +/* Set the flag for buffering errors or not. */ + +void +gfc_buffer_error (int flag) +{ + + buffer_flag = flag; +} + + +/* Add a single character to the error buffer or output depending on + buffer_flag. */ + +static void +error_char (char c) +{ + + if (buffer_flag) + { + if (use_warning_buffer) + { + *warning_ptr++ = c; + if (warning_ptr - warning_buffer.message >= MAX_ERROR_MESSAGE) + gfc_internal_error ("error_char(): Warning buffer overflow"); + } + else + { + *error_ptr++ = c; + if (error_ptr - error_buffer.message >= MAX_ERROR_MESSAGE) + gfc_internal_error ("error_char(): Error buffer overflow"); + } + } + else + { + if (c != 0) + fputc (c, stderr); + } +} + + +/* Copy a string to wherever it needs to go. */ + +static void +error_string (const char *p) +{ + + while (*p) + error_char (*p++); +} + + +/* Show the file, where it was included and the source line give a + locus. Calls error_printf() recursively, but the recursion is at + most one level deep. */ + +static void error_printf (const char *, ...) ATTRIBUTE_PRINTF_1; + +static void +show_locus (int offset, locus * l) +{ + gfc_file *f; + char c, *p; + int i, m; + + /* TODO: Either limit the total length and number of included files + displayed or add buffering of arbitrary number of characters in + error messages. */ + f = l->file; + error_printf ("In file %s:%d\n", f->filename, l->lp->start_line + l->line); + + f = f->included_by; + while (f != NULL) + { + error_printf (" Included at %s:%d\n", f->filename, + f->loc.lp->start_line + f->loc.line); + f = f->included_by; + } + + /* Show the line itself, taking care not to print more than what can + show up on the terminal. Tabs are converted to spaces. */ + p = l->lp->line[l->line] + offset; + i = strlen (p); + if (i > terminal_width) + i = terminal_width - 1; + + for (; i > 0; i--) + { + c = *p++; + if (c == '\t') + c = ' '; + + if (ISPRINT (c)) + error_char (c); + else + { + error_char ('\\'); + error_char ('x'); + + m = ((c >> 4) & 0x0F) + '0'; + if (m > '9') + m += 'A' - '9' - 1; + error_char (m); + + m = (c & 0x0F) + '0'; + if (m > '9') + m += 'A' - '9' - 1; + error_char (m); + } + } + + error_char ('\n'); +} + + +/* As part of printing an error, we show the source lines that caused + the problem. We show at least one, possibly two loci. If we're + showing two loci and they both refer to the same file and line, we + only print the line once. */ + +static void +show_loci (locus * l1, locus * l2) +{ + int offset, flag, i, m, c1, c2, cmax; + + if (l1 == NULL) + { + error_printf ("\n"); + return; + } + + c1 = l1->nextc - l1->lp->line[l1->line]; + c2 = 0; + if (l2 == NULL) + goto separate; + + c2 = l2->nextc - l2->lp->line[l2->line]; + + if (c1 < c2) + m = c2 - c1; + else + m = c1 - c2; + + + if (l1->lp != l2->lp || l1->line != l2->line || m > terminal_width - 10) + goto separate; + + offset = 0; + cmax = (c1 < c2) ? c2 : c1; + if (cmax > terminal_width - 5) + offset = cmax - terminal_width + 5; + + if (offset < 0) + offset = 0; + + c1 -= offset; + c2 -= offset; + + show_locus (offset, l1); + + /* Arrange that '1' and '2' will show up even if the two columns are equal. */ + for (i = 1; i <= cmax; i++) + { + flag = 0; + if (i == c1) + { + error_char ('1'); + flag = 1; + } + if (i == c2) + { + error_char ('2'); + flag = 1; + } + if (flag == 0) + error_char (' '); + } + + error_char ('\n'); + + return; + +separate: + offset = 0; + + if (c1 > terminal_width - 5) + { + offset = c1 - 5; + if (offset < 0) + offset = 0; + c1 = c1 - offset; + } + + show_locus (offset, l1); + for (i = 1; i < c1; i++) + error_char (' '); + + error_char ('1'); + error_char ('\n'); + + if (l2 != NULL) + { + offset = 0; + + if (c2 > terminal_width - 20) + { + offset = c2 - 20; + if (offset < 0) + offset = 0; + c2 = c2 - offset; + } + + show_locus (offset, l2); + + for (i = 1; i < c2; i++) + error_char (' '); + + error_char ('2'); + error_char ('\n'); + } +} + + +/* Workhorse for the error printing subroutines. This subroutine is + inspired by g77's error handling and is similar to printf() with + the following %-codes: + + %c Character, %d Integer, %s String, %% Percent + %L Takes locus argument + %C Current locus (no argument) + + If a locus pointer is given, the actual source line is printed out + and the column is indicated. Since we want the error message at + the bottom of any source file information, we must scan the + argument list twice. A maximum of two locus arguments are + permitted. */ + +#define IBUF_LEN 30 +#define MAX_ARGS 10 + +static void +error_print (const char *type, const char *format0, va_list argp) +{ + char c, *p, int_buf[IBUF_LEN], c_arg[MAX_ARGS], *cp_arg[MAX_ARGS]; + int i, n, have_l1, i_arg[MAX_ARGS]; + locus *l1, *l2, *loc; + const char *format; + + l1 = l2 = loc = NULL; + + have_l1 = 0; + + n = 0; + format = format0; + + while (*format) + { + c = *format++; + if (c == '%') + { + c = *format++; + + switch (c) + { + case '%': + break; + + case 'L': + loc = va_arg (argp, locus *); + /* Fall through */ + + case 'C': + if (c == 'C') + loc = gfc_current_locus (); + + if (have_l1) + { + l2 = loc; + } + else + { + l1 = loc; + have_l1 = 1; + } + break; + + case 'd': + case 'i': + i_arg[n++] = va_arg (argp, int); + break; + + case 'c': + c_arg[n++] = va_arg (argp, int); + break; + + case 's': + cp_arg[n++] = va_arg (argp, char *); + break; + } + } + } + + /* Show the current loci if we have to. */ + if (have_l1) + show_loci (l1, l2); + error_string (type); + error_char (' '); + + have_l1 = 0; + format = format0; + n = 0; + + for (; *format; format++) + { + if (*format != '%') + { + error_char (*format); + continue; + } + + format++; + switch (*format) + { + case '%': + error_char ('%'); + break; + + case 'c': + error_char (c_arg[n++]); + break; + + case 's': + error_string (cp_arg[n++]); + break; + + case 'i': + case 'd': + i = i_arg[n++]; + + if (i < 0) + { + i = -i; + error_char ('-'); + } + + p = int_buf + IBUF_LEN - 1; + *p-- = '\0'; + + if (i == 0) + *p-- = '0'; + + while (i > 0) + { + *p-- = i % 10 + '0'; + i = i / 10; + } + + error_string (p + 1); + break; + + case 'C': /* Current locus */ + case 'L': /* Specified locus */ + error_string (have_l1 ? "(2)" : "(1)"); + have_l1 = 1; + break; + } + } + + error_char ('\n'); +} + + +/* Wrapper for error_print(). */ + +static void +error_printf (const char *format, ...) +{ + va_list argp; + + va_start (argp, format); + error_print ("", format, argp); + va_end (argp); +} + + +/* Issue a warning. */ + +void +gfc_warning (const char *format, ...) +{ + va_list argp; + + if (inhibit_warnings) + return; + + warning_buffer.flag = 1; + warning_ptr = warning_buffer.message; + use_warning_buffer = 1; + + va_start (argp, format); + if (buffer_flag == 0) + warnings++; + error_print ("Warning:", format, argp); + va_end (argp); + + error_char ('\0'); +} + + +/* Possibly issue a warning/error about use of a nonstandard (or deleted) + feature. An error/warning will be issued if the currently selected + standard does not contain the requested bits. Return FAILURE if + and error is generated. */ + +try +gfc_notify_std (int std, const char *format, ...) +{ + va_list argp; + bool warning; + + warning = ((gfc_option.warn_std & std) != 0) + && !inhibit_warnings; + if ((gfc_option.allow_std & std) != 0 + && !warning) + return SUCCESS; + + if (gfc_suppress_error) + return warning ? SUCCESS : FAILURE; + + if (warning) + { + warning_buffer.flag = 1; + warning_ptr = warning_buffer.message; + use_warning_buffer = 1; + } + else + { + error_buffer.flag = 1; + error_ptr = error_buffer.message; + use_warning_buffer = 0; + } + + if (buffer_flag == 0) + { + if (warning) + warnings++; + else + errors++; + } + va_start (argp, format); + if (warning) + error_print ("Warning:", format, argp); + else + error_print ("Error:", format, argp); + va_end (argp); + + error_char ('\0'); + return warning ? SUCCESS : FAILURE; +} + + +/* Immediate warning (i.e. do not buffer the warning). */ + +void +gfc_warning_now (const char *format, ...) +{ + va_list argp; + int i; + + if (inhibit_warnings) + return; + + i = buffer_flag; + buffer_flag = 0; + warnings++; + + va_start (argp, format); + error_print ("Warning:", format, argp); + va_end (argp); + + error_char ('\0'); + buffer_flag = i; +} + + +/* Clear the warning flag. */ + +void +gfc_clear_warning (void) +{ + + warning_buffer.flag = 0; +} + + +/* Check to see if any warnings have been saved. + If so, print the warning. */ + +void +gfc_warning_check (void) +{ + + if (warning_buffer.flag) + { + warnings++; + fputs (warning_buffer.message, stderr); + warning_buffer.flag = 0; + } +} + + +/* Issue an error. */ + +void +gfc_error (const char *format, ...) +{ + va_list argp; + + if (gfc_suppress_error) + return; + + error_buffer.flag = 1; + error_ptr = error_buffer.message; + use_warning_buffer = 0; + + va_start (argp, format); + if (buffer_flag == 0) + errors++; + error_print ("Error:", format, argp); + va_end (argp); + + error_char ('\0'); +} + + +/* Immediate error. */ + +void +gfc_error_now (const char *format, ...) +{ + va_list argp; + int i; + + error_buffer.flag = 1; + error_ptr = error_buffer.message; + + i = buffer_flag; + buffer_flag = 0; + errors++; + + va_start (argp, format); + error_print ("Error:", format, argp); + va_end (argp); + + error_char ('\0'); + buffer_flag = i; +} + + +/* Fatal error, never returns. */ + +void +gfc_fatal_error (const char *format, ...) +{ + va_list argp; + + buffer_flag = 0; + + va_start (argp, format); + error_print ("Fatal Error:", format, argp); + va_end (argp); + + exit (3); +} + + +/* This shouldn't happen... but sometimes does. */ + +void +gfc_internal_error (const char *format, ...) +{ + va_list argp; + + buffer_flag = 0; + + va_start (argp, format); + + show_loci (gfc_current_locus (), NULL); + error_printf ("Internal Error at (1):"); + + error_print ("", format, argp); + va_end (argp); + + exit (4); +} + + +/* Clear the error flag when we start to compile a source line. */ + +void +gfc_clear_error (void) +{ + + error_buffer.flag = 0; +} + + +/* Check to see if any errors have been saved. + If so, print the error. Returns the state of error_flag. */ + +int +gfc_error_check (void) +{ + int rc; + + rc = error_buffer.flag; + + if (error_buffer.flag) + { + errors++; + fputs (error_buffer.message, stderr); + error_buffer.flag = 0; + } + + return rc; +} + + +/* Save the existing error state. */ + +void +gfc_push_error (gfc_error_buf * err) +{ + + err->flag = error_buffer.flag; + if (error_buffer.flag) + strcpy (err->message, error_buffer.message); + + error_buffer.flag = 0; +} + + +/* Restore a previous pushed error state. */ + +void +gfc_pop_error (gfc_error_buf * err) +{ + + error_buffer.flag = err->flag; + if (error_buffer.flag) + strcpy (error_buffer.message, err->message); +} + + +/* Debug wrapper for printf. */ + +void +gfc_status (const char *format, ...) +{ + va_list argp; + + va_start (argp, format); + + vprintf (format, argp); + + va_end (argp); +} + + +/* Subroutine for outputting a single char so that we don't have to go + around creating a lot of 1-character strings. */ + +void +gfc_status_char (char c) +{ + putchar (c); +} + + +/* Report the number of warnings and errors that occored to the caller. */ + +void +gfc_get_errors (int *w, int *e) +{ + + if (w != NULL) + *w = warnings; + if (e != NULL) + *e = errors; +} diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c new file mode 100644 index 00000000000..78a8dc29998 --- /dev/null +++ b/gcc/fortran/expr.c @@ -0,0 +1,1954 @@ +/* Routines for manipulation of expression nodes. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include + +#include "gfortran.h" +#include "arith.h" +#include "match.h" + +/* Get a new expr node. */ + +gfc_expr * +gfc_get_expr (void) +{ + gfc_expr *e; + + e = gfc_getmem (sizeof (gfc_expr)); + + gfc_clear_ts (&e->ts); + e->op1 = NULL; + e->op2 = NULL; + e->shape = NULL; + e->ref = NULL; + e->symtree = NULL; + e->uop = NULL; + + return e; +} + + +/* Free an argument list and everything below it. */ + +void +gfc_free_actual_arglist (gfc_actual_arglist * a1) +{ + gfc_actual_arglist *a2; + + while (a1) + { + a2 = a1->next; + gfc_free_expr (a1->expr); + gfc_free (a1); + a1 = a2; + } +} + + +/* Copy an arglist structure and all of the arguments. */ + +gfc_actual_arglist * +gfc_copy_actual_arglist (gfc_actual_arglist * p) +{ + gfc_actual_arglist *head, *tail, *new; + + head = tail = NULL; + + for (; p; p = p->next) + { + new = gfc_get_actual_arglist (); + *new = *p; + + new->expr = gfc_copy_expr (p->expr); + new->next = NULL; + + if (head == NULL) + head = new; + else + tail->next = new; + + tail = new; + } + + return head; +} + + +/* Free a list of reference structures. */ + +void +gfc_free_ref_list (gfc_ref * p) +{ + gfc_ref *q; + int i; + + for (; p; p = q) + { + q = p->next; + + switch (p->type) + { + case REF_ARRAY: + for (i = 0; i < GFC_MAX_DIMENSIONS; i++) + { + gfc_free_expr (p->u.ar.start[i]); + gfc_free_expr (p->u.ar.end[i]); + gfc_free_expr (p->u.ar.stride[i]); + } + + break; + + case REF_SUBSTRING: + gfc_free_expr (p->u.ss.start); + gfc_free_expr (p->u.ss.end); + break; + + case REF_COMPONENT: + break; + } + + gfc_free (p); + } +} + + +/* Workhorse function for gfc_free_expr() that frees everything + beneath an expression node, but not the node itself. This is + useful when we want to simplify a node and replace it with + something else or the expression node belongs to another structure. */ + +static void +free_expr0 (gfc_expr * e) +{ + int n; + + switch (e->expr_type) + { + case EXPR_CONSTANT: + switch (e->ts.type) + { + case BT_INTEGER: + mpz_clear (e->value.integer); + break; + + case BT_REAL: + mpf_clear (e->value.real); + break; + + case BT_CHARACTER: + gfc_free (e->value.character.string); + break; + + case BT_COMPLEX: + mpf_clear (e->value.complex.r); + mpf_clear (e->value.complex.i); + break; + + default: + break; + } + + break; + + case EXPR_OP: + if (e->op1 != NULL) + gfc_free_expr (e->op1); + if (e->op2 != NULL) + gfc_free_expr (e->op2); + break; + + case EXPR_FUNCTION: + gfc_free_actual_arglist (e->value.function.actual); + break; + + case EXPR_VARIABLE: + break; + + case EXPR_ARRAY: + case EXPR_STRUCTURE: + gfc_free_constructor (e->value.constructor); + break; + + case EXPR_SUBSTRING: + gfc_free (e->value.character.string); + break; + + case EXPR_NULL: + break; + + default: + gfc_internal_error ("free_expr0(): Bad expr type"); + } + + /* Free a shape array. */ + if (e->shape != NULL) + { + for (n = 0; n < e->rank; n++) + mpz_clear (e->shape[n]); + + gfc_free (e->shape); + } + + gfc_free_ref_list (e->ref); + + memset (e, '\0', sizeof (gfc_expr)); +} + + +/* Free an expression node and everything beneath it. */ + +void +gfc_free_expr (gfc_expr * e) +{ + + if (e == NULL) + return; + + free_expr0 (e); + gfc_free (e); +} + + +/* Graft the *src expression onto the *dest subexpression. */ + +void +gfc_replace_expr (gfc_expr * dest, gfc_expr * src) +{ + + free_expr0 (dest); + *dest = *src; + + gfc_free (src); +} + + +/* Try to extract an integer constant from the passed expression node. + Returns an error message or NULL if the result is set. It is + tempting to generate an error and return SUCCESS or FAILURE, but + failure is OK for some callers. */ + +const char * +gfc_extract_int (gfc_expr * expr, int *result) +{ + + if (expr->expr_type != EXPR_CONSTANT) + return "Constant expression required at %C"; + + if (expr->ts.type != BT_INTEGER) + return "Integer expression required at %C"; + + if ((mpz_cmp_si (expr->value.integer, INT_MAX) > 0) + || (mpz_cmp_si (expr->value.integer, INT_MIN) < 0)) + { + return "Integer value too large in expression at %C"; + } + + *result = (int) mpz_get_si (expr->value.integer); + + return NULL; +} + + +/* Recursively copy a list of reference structures. */ + +static gfc_ref * +copy_ref (gfc_ref * src) +{ + gfc_array_ref *ar; + gfc_ref *dest; + + if (src == NULL) + return NULL; + + dest = gfc_get_ref (); + dest->type = src->type; + + switch (src->type) + { + case REF_ARRAY: + ar = gfc_copy_array_ref (&src->u.ar); + dest->u.ar = *ar; + gfc_free (ar); + break; + + case REF_COMPONENT: + dest->u.c = src->u.c; + break; + + case REF_SUBSTRING: + dest->u.ss = src->u.ss; + dest->u.ss.start = gfc_copy_expr (src->u.ss.start); + dest->u.ss.end = gfc_copy_expr (src->u.ss.end); + break; + } + + dest->next = copy_ref (src->next); + + return dest; +} + + +/* Copy a shape array. */ + +mpz_t * +gfc_copy_shape (mpz_t * shape, int rank) +{ + mpz_t *new_shape; + int n; + + if (shape == NULL) + return NULL; + + new_shape = gfc_get_shape (rank); + + for (n = 0; n < rank; n++) + mpz_init_set (new_shape[n], shape[n]); + + return new_shape; +} + + +/* Given an expression pointer, return a copy of the expression. This + subroutine is recursive. */ + +gfc_expr * +gfc_copy_expr (gfc_expr * p) +{ + gfc_expr *q; + char *s; + + if (p == NULL) + return NULL; + + q = gfc_get_expr (); + *q = *p; + + switch (q->expr_type) + { + case EXPR_SUBSTRING: + s = gfc_getmem (p->value.character.length + 1); + q->value.character.string = s; + + memcpy (s, p->value.character.string, p->value.character.length + 1); + + q->op1 = gfc_copy_expr (p->op1); + q->op2 = gfc_copy_expr (p->op2); + break; + + case EXPR_CONSTANT: + switch (q->ts.type) + { + case BT_INTEGER: + mpz_init_set (q->value.integer, p->value.integer); + break; + + case BT_REAL: + mpf_init_set (q->value.real, p->value.real); + break; + + case BT_COMPLEX: + mpf_init_set (q->value.complex.r, p->value.complex.r); + mpf_init_set (q->value.complex.i, p->value.complex.i); + break; + + case BT_CHARACTER: + s = gfc_getmem (p->value.character.length + 1); + q->value.character.string = s; + + memcpy (s, p->value.character.string, + p->value.character.length + 1); + break; + + case BT_LOGICAL: + case BT_DERIVED: + break; /* Already done */ + + case BT_PROCEDURE: + case BT_UNKNOWN: + gfc_internal_error ("gfc_copy_expr(): Bad expr node"); + /* Not reached */ + } + + break; + + case EXPR_OP: + switch (q->operator) + { + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + q->op1 = gfc_copy_expr (p->op1); + break; + + default: /* Binary operators */ + q->op1 = gfc_copy_expr (p->op1); + q->op2 = gfc_copy_expr (p->op2); + break; + } + + break; + + case EXPR_FUNCTION: + q->value.function.actual = + gfc_copy_actual_arglist (p->value.function.actual); + break; + + case EXPR_STRUCTURE: + case EXPR_ARRAY: + q->value.constructor = gfc_copy_constructor (p->value.constructor); + break; + + case EXPR_VARIABLE: + case EXPR_NULL: + break; + } + + q->shape = gfc_copy_shape (p->shape, p->rank); + + q->ref = copy_ref (p->ref); + + return q; +} + + +/* Return the maximum kind of two expressions. In general, higher + kind numbers mean more precision for numeric types. */ + +int +gfc_kind_max (gfc_expr * e1, gfc_expr * e2) +{ + + return (e1->ts.kind > e2->ts.kind) ? e1->ts.kind : e2->ts.kind; +} + + +/* Returns nonzero if the type is numeric, zero otherwise. */ + +static int +numeric_type (bt type) +{ + + return type == BT_COMPLEX || type == BT_REAL || type == BT_INTEGER; +} + + +/* Returns nonzero if the typespec is a numeric type, zero otherwise. */ + +int +gfc_numeric_ts (gfc_typespec * ts) +{ + + return numeric_type (ts->type); +} + + +/* Returns an expression node that is an integer constant. */ + +gfc_expr * +gfc_int_expr (int i) +{ + gfc_expr *p; + + p = gfc_get_expr (); + + p->expr_type = EXPR_CONSTANT; + p->ts.type = BT_INTEGER; + p->ts.kind = gfc_default_integer_kind (); + + p->where = *gfc_current_locus (); + mpz_init_set_si (p->value.integer, i); + + return p; +} + + +/* Returns an expression node that is a logical constant. */ + +gfc_expr * +gfc_logical_expr (int i, locus * where) +{ + gfc_expr *p; + + p = gfc_get_expr (); + + p->expr_type = EXPR_CONSTANT; + p->ts.type = BT_LOGICAL; + p->ts.kind = gfc_default_logical_kind (); + + if (where == NULL) + where = gfc_current_locus (); + p->where = *where; + p->value.logical = i; + + return p; +} + + +/* Return an expression node with an optional argument list attached. + A variable number of gfc_expr pointers are strung together in an + argument list with a NULL pointer terminating the list. */ + +gfc_expr * +gfc_build_conversion (gfc_expr * e) +{ + gfc_expr *p; + + p = gfc_get_expr (); + p->expr_type = EXPR_FUNCTION; + p->symtree = NULL; + p->value.function.actual = NULL; + + p->value.function.actual = gfc_get_actual_arglist (); + p->value.function.actual->expr = e; + + return p; +} + + +/* Given an expression node with some sort of numeric binary + expression, insert type conversions required to make the operands + have the same type. + + The exception is that the operands of an exponential don't have to + have the same type. If possible, the base is promoted to the type + of the exponent. For example, 1**2.3 becomes 1.0**2.3, but + 1.0**2 stays as it is. */ + +void +gfc_type_convert_binary (gfc_expr * e) +{ + gfc_expr *op1, *op2; + + op1 = e->op1; + op2 = e->op2; + + if (op1->ts.type == BT_UNKNOWN || op2->ts.type == BT_UNKNOWN) + { + gfc_clear_ts (&e->ts); + return; + } + + /* Kind conversions of same type. */ + if (op1->ts.type == op2->ts.type) + { + + if (op1->ts.kind == op2->ts.kind) + { + /* No type conversions. */ + e->ts = op1->ts; + goto done; + } + + if (op1->ts.kind > op2->ts.kind) + gfc_convert_type (op2, &op1->ts, 2); + else + gfc_convert_type (op1, &op2->ts, 2); + + e->ts = op1->ts; + goto done; + } + + /* Integer combined with real or complex. */ + if (op2->ts.type == BT_INTEGER) + { + e->ts = op1->ts; + + /* Special cose for ** operator. */ + if (e->operator == INTRINSIC_POWER) + goto done; + + gfc_convert_type (e->op2, &e->ts, 2); + goto done; + } + + if (op1->ts.type == BT_INTEGER) + { + e->ts = op2->ts; + gfc_convert_type (e->op1, &e->ts, 2); + goto done; + } + + /* Real combined with complex. */ + e->ts.type = BT_COMPLEX; + if (op1->ts.kind > op2->ts.kind) + e->ts.kind = op1->ts.kind; + else + e->ts.kind = op2->ts.kind; + if (op1->ts.type != BT_COMPLEX || op1->ts.kind != e->ts.kind) + gfc_convert_type (e->op1, &e->ts, 2); + if (op2->ts.type != BT_COMPLEX || op2->ts.kind != e->ts.kind) + gfc_convert_type (e->op2, &e->ts, 2); + +done: + return; +} + + +/* Function to determine if an expression is constant or not. This + function expects that the expression has already been simplified. */ + +int +gfc_is_constant_expr (gfc_expr * e) +{ + gfc_constructor *c; + gfc_actual_arglist *arg; + int rv; + + if (e == NULL) + return 1; + + switch (e->expr_type) + { + case EXPR_OP: + rv = (gfc_is_constant_expr (e->op1) + && (e->op2 == NULL + || gfc_is_constant_expr (e->op2))); + + break; + + case EXPR_VARIABLE: + rv = 0; + break; + + case EXPR_FUNCTION: + /* Call to intrinsic with at least one argument. */ + rv = 0; + if (e->value.function.isym && e->value.function.actual) + { + for (arg = e->value.function.actual; arg; arg = arg->next) + { + if (!gfc_is_constant_expr (arg->expr)) + break; + } + if (arg == NULL) + rv = 1; + } + break; + + case EXPR_CONSTANT: + case EXPR_NULL: + rv = 1; + break; + + case EXPR_SUBSTRING: + rv = gfc_is_constant_expr (e->op1) && gfc_is_constant_expr (e->op2); + break; + + case EXPR_STRUCTURE: + rv = 0; + for (c = e->value.constructor; c; c = c->next) + if (!gfc_is_constant_expr (c->expr)) + break; + + if (c == NULL) + rv = 1; + break; + + case EXPR_ARRAY: + rv = gfc_constant_ac (e); + break; + + default: + gfc_internal_error ("gfc_is_constant_expr(): Unknown expression type"); + } + + return rv; +} + + +/* Try to collapse intrinsic expressions. */ + +static try +simplify_intrinsic_op (gfc_expr * p, int type) +{ + gfc_expr *op1, *op2, *result; + + if (p->operator == INTRINSIC_USER) + return SUCCESS; + + op1 = p->op1; + op2 = p->op2; + + if (gfc_simplify_expr (op1, type) == FAILURE) + return FAILURE; + if (gfc_simplify_expr (op2, type) == FAILURE) + return FAILURE; + + if (!gfc_is_constant_expr (op1) + || (op2 != NULL && !gfc_is_constant_expr (op2))) + return SUCCESS; + + /* Rip p apart */ + p->op1 = NULL; + p->op2 = NULL; + + switch (p->operator) + { + case INTRINSIC_UPLUS: + result = gfc_uplus (op1); + break; + + case INTRINSIC_UMINUS: + result = gfc_uminus (op1); + break; + + case INTRINSIC_PLUS: + result = gfc_add (op1, op2); + break; + + case INTRINSIC_MINUS: + result = gfc_subtract (op1, op2); + break; + + case INTRINSIC_TIMES: + result = gfc_multiply (op1, op2); + break; + + case INTRINSIC_DIVIDE: + result = gfc_divide (op1, op2); + break; + + case INTRINSIC_POWER: + result = gfc_power (op1, op2); + break; + + case INTRINSIC_CONCAT: + result = gfc_concat (op1, op2); + break; + + case INTRINSIC_EQ: + result = gfc_eq (op1, op2); + break; + + case INTRINSIC_NE: + result = gfc_ne (op1, op2); + break; + + case INTRINSIC_GT: + result = gfc_gt (op1, op2); + break; + + case INTRINSIC_GE: + result = gfc_ge (op1, op2); + break; + + case INTRINSIC_LT: + result = gfc_lt (op1, op2); + break; + + case INTRINSIC_LE: + result = gfc_le (op1, op2); + break; + + case INTRINSIC_NOT: + result = gfc_not (op1); + break; + + case INTRINSIC_AND: + result = gfc_and (op1, op2); + break; + + case INTRINSIC_OR: + result = gfc_or (op1, op2); + break; + + case INTRINSIC_EQV: + result = gfc_eqv (op1, op2); + break; + + case INTRINSIC_NEQV: + result = gfc_neqv (op1, op2); + break; + + default: + gfc_internal_error ("simplify_intrinsic_op(): Bad operator"); + } + + if (result == NULL) + { + gfc_free_expr (op1); + gfc_free_expr (op2); + return FAILURE; + } + + gfc_replace_expr (p, result); + + return SUCCESS; +} + + +/* Subroutine to simplify constructor expressions. Mutually recursive + with gfc_simplify_expr(). */ + +static try +simplify_constructor (gfc_constructor * c, int type) +{ + + for (; c; c = c->next) + { + if (c->iterator + && (gfc_simplify_expr (c->iterator->start, type) == FAILURE + || gfc_simplify_expr (c->iterator->end, type) == FAILURE + || gfc_simplify_expr (c->iterator->step, type) == FAILURE)) + return FAILURE; + + if (c->expr && gfc_simplify_expr (c->expr, type) == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +/* Pull a single array element out of an array constructor. */ + +static gfc_constructor * +find_array_element (gfc_constructor * cons, gfc_array_ref * ar) +{ + unsigned long nelemen; + int i; + mpz_t delta; + mpz_t offset; + + mpz_init_set_ui (offset, 0); + mpz_init (delta); + for (i = 0; i < ar->dimen; i++) + { + if (ar->start[i]->expr_type != EXPR_CONSTANT) + { + cons = NULL; + break; + } + mpz_sub (delta, ar->start[i]->value.integer, + ar->as->lower[i]->value.integer); + mpz_add (offset, offset, delta); + } + + if (cons) + { + if (mpz_fits_ulong_p (offset)) + { + for (nelemen = mpz_get_ui (offset); nelemen > 0; nelemen--) + { + if (cons->iterator) + { + cons = NULL; + break; + } + cons = cons->next; + } + } + else + cons = NULL; + } + + mpz_clear (delta); + mpz_clear (offset); + + return cons; +} + + +/* Find a component of a structure constructor. */ + +static gfc_constructor * +find_component_ref (gfc_constructor * cons, gfc_ref * ref) +{ + gfc_component *comp; + gfc_component *pick; + + comp = ref->u.c.sym->components; + pick = ref->u.c.component; + while (comp != pick) + { + comp = comp->next; + cons = cons->next; + } + + return cons; +} + + +/* Replace an expression with the contents of a constructor, removing + the subobject reference in the process. */ + +static void +remove_subobject_ref (gfc_expr * p, gfc_constructor * cons) +{ + gfc_expr *e; + + e = cons->expr; + cons->expr = NULL; + e->ref = p->ref->next; + p->ref->next = NULL; + gfc_replace_expr (p, e); +} + + +/* Simplify a subobject reference of a constructor. This occurs when + parameter variable values are substituted. */ + +static try +simplify_const_ref (gfc_expr * p) +{ + gfc_constructor *cons; + + while (p->ref) + { + switch (p->ref->type) + { + case REF_ARRAY: + switch (p->ref->u.ar.type) + { + case AR_ELEMENT: + cons = find_array_element (p->value.constructor, &p->ref->u.ar); + if (!cons) + return SUCCESS; + remove_subobject_ref (p, cons); + break; + + case AR_FULL: + if (p->ref->next != NULL) + { + /* TODO: Simplify array subobject references. */ + return SUCCESS; + } + gfc_free_ref_list (p->ref); + p->ref = NULL; + break; + + default: + /* TODO: Simplify array subsections. */ + return SUCCESS; + } + + break; + + case REF_COMPONENT: + cons = find_component_ref (p->value.constructor, p->ref); + remove_subobject_ref (p, cons); + break; + + case REF_SUBSTRING: + /* TODO: Constant substrings. */ + return SUCCESS; + } + } + + return SUCCESS; +} + + +/* Simplify a chain of references. */ + +static try +simplify_ref_chain (gfc_ref * ref, int type) +{ + int n; + + for (; ref; ref = ref->next) + { + switch (ref->type) + { + case REF_ARRAY: + for (n = 0; n < ref->u.ar.dimen; n++) + { + if (gfc_simplify_expr (ref->u.ar.start[n], type) + == FAILURE) + return FAILURE; + if (gfc_simplify_expr (ref->u.ar.end[n], type) + == FAILURE) + return FAILURE; + if (gfc_simplify_expr (ref->u.ar.stride[n], type) + == FAILURE) + return FAILURE; + } + break; + + case REF_SUBSTRING: + if (gfc_simplify_expr (ref->u.ss.start, type) == FAILURE) + return FAILURE; + if (gfc_simplify_expr (ref->u.ss.end, type) == FAILURE) + return FAILURE; + break; + + default: + break; + } + } + return SUCCESS; +} + + +/* Try to substitute the value of a parameter variable. */ +static try +simplify_parameter_variable (gfc_expr * p, int type) +{ + gfc_expr *e; + try t; + + e = gfc_copy_expr (p->symtree->n.sym->value); + if (p->ref) + e->ref = copy_ref (p->ref); + t = gfc_simplify_expr (e, type); + + /* Only use the simplification if it eliminated all subobject + references. */ + if (t == SUCCESS && ! e->ref) + gfc_replace_expr (p, e); + else + gfc_free_expr (e); + + return t; +} + +/* Given an expression, simplify it by collapsing constant + expressions. Most simplification takes place when the expression + tree is being constructed. If an intrinsic function is simplified + at some point, we get called again to collapse the result against + other constants. + + We work by recursively simplifying expression nodes, simplifying + intrinsic functions where possible, which can lead to further + constant collapsing. If an operator has constant operand(s), we + rip the expression apart, and rebuild it, hoping that it becomes + something simpler. + + The expression type is defined for: + 0 Basic expression parsing + 1 Simplifying array constructors -- will substitute + iterator values. + Returns FAILURE on error, SUCCESS otherwise. + NOTE: Will return SUCCESS even if the expression can not be simplified. */ + +try +gfc_simplify_expr (gfc_expr * p, int type) +{ + gfc_actual_arglist *ap; + + if (p == NULL) + return SUCCESS; + + switch (p->expr_type) + { + case EXPR_CONSTANT: + case EXPR_NULL: + break; + + case EXPR_FUNCTION: + for (ap = p->value.function.actual; ap; ap = ap->next) + if (gfc_simplify_expr (ap->expr, type) == FAILURE) + return FAILURE; + + if (p->value.function.isym != NULL + && gfc_intrinsic_func_interface (p, 1) == MATCH_ERROR) + return FAILURE; + + break; + + case EXPR_SUBSTRING: + if (gfc_simplify_expr (p->op1, type) == FAILURE + || gfc_simplify_expr (p->op2, type) == FAILURE) + return FAILURE; + + /* TODO: evaluate constant substrings. */ + + break; + + case EXPR_OP: + if (simplify_intrinsic_op (p, type) == FAILURE) + return FAILURE; + break; + + case EXPR_VARIABLE: + /* Only substitute array parameter variables if we are in an + initialization expression, or we want a subsection. */ + if (p->symtree->n.sym->attr.flavor == FL_PARAMETER + && (gfc_init_expr || p->ref + || p->symtree->n.sym->value->expr_type != EXPR_ARRAY)) + { + if (simplify_parameter_variable (p, type) == FAILURE) + return FAILURE; + break; + } + + if (type == 1) + { + gfc_simplify_iterator_var (p); + } + + /* Simplify subcomponent references. */ + if (simplify_ref_chain (p->ref, type) == FAILURE) + return FAILURE; + + break; + + case EXPR_STRUCTURE: + case EXPR_ARRAY: + if (simplify_ref_chain (p->ref, type) == FAILURE) + return FAILURE; + + if (simplify_constructor (p->value.constructor, type) == FAILURE) + return FAILURE; + + if (p->expr_type == EXPR_ARRAY) + gfc_expand_constructor (p); + + if (simplify_const_ref (p) == FAILURE) + return FAILURE; + + break; + } + + return SUCCESS; +} + + +/* Returns the type of an expression with the exception that iterator + variables are automatically integers no matter what else they may + be declared as. */ + +static bt +et0 (gfc_expr * e) +{ + + if (e->expr_type == EXPR_VARIABLE && gfc_check_iter_variable (e) == SUCCESS) + return BT_INTEGER; + + return e->ts.type; +} + + +/* Check an intrinsic arithmetic operation to see if it is consistent + with some type of expression. */ + +static try check_init_expr (gfc_expr *); + +static try +check_intrinsic_op (gfc_expr * e, try (*check_function) (gfc_expr *)) +{ + + if ((*check_function) (e->op1) == FAILURE) + return FAILURE; + + switch (e->operator) + { + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + if (!numeric_type (et0 (e->op1))) + goto not_numeric; + break; + + case INTRINSIC_EQ: + case INTRINSIC_NE: + case INTRINSIC_GT: + case INTRINSIC_GE: + case INTRINSIC_LT: + case INTRINSIC_LE: + + case INTRINSIC_PLUS: + case INTRINSIC_MINUS: + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + case INTRINSIC_POWER: + if ((*check_function) (e->op2) == FAILURE) + return FAILURE; + + if (!numeric_type (et0 (e->op1)) || !numeric_type (et0 (e->op2))) + goto not_numeric; + + if (e->operator != INTRINSIC_POWER) + break; + + if (check_function == check_init_expr && et0 (e->op2) != BT_INTEGER) + { + gfc_error ("Exponent at %L must be INTEGER for an initialization " + "expression", &e->op2->where); + return FAILURE; + } + + break; + + case INTRINSIC_CONCAT: + if ((*check_function) (e->op2) == FAILURE) + return FAILURE; + + if (et0 (e->op1) != BT_CHARACTER || et0 (e->op2) != BT_CHARACTER) + { + gfc_error ("Concatenation operator in expression at %L " + "must have two CHARACTER operands", &e->op1->where); + return FAILURE; + } + + if (e->op1->ts.kind != e->op2->ts.kind) + { + gfc_error ("Concat operator at %L must concatenate strings of the " + "same kind", &e->where); + return FAILURE; + } + + break; + + case INTRINSIC_NOT: + if (et0 (e->op1) != BT_LOGICAL) + { + gfc_error (".NOT. operator in expression at %L must have a LOGICAL " + "operand", &e->op1->where); + return FAILURE; + } + + break; + + case INTRINSIC_AND: + case INTRINSIC_OR: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + if ((*check_function) (e->op2) == FAILURE) + return FAILURE; + + if (et0 (e->op1) != BT_LOGICAL || et0 (e->op2) != BT_LOGICAL) + { + gfc_error ("LOGICAL operands are required in expression at %L", + &e->where); + return FAILURE; + } + + break; + + default: + gfc_error ("Only intrinsic operators can be used in expression at %L", + &e->where); + return FAILURE; + } + + return SUCCESS; + +not_numeric: + gfc_error ("Numeric operands are required in expression at %L", &e->where); + + return FAILURE; +} + + + +/* Certain inquiry functions are specifically allowed to have variable + arguments, which is an exception to the normal requirement that an + initialization function have initialization arguments. We head off + this problem here. */ + +static try +check_inquiry (gfc_expr * e) +{ + const char *name; + + /* FIXME: This should be moved into the intrinsic definitions, + to eliminate this ugly hack. */ + static const char * const inquiry_function[] = { + "digits", "epsilon", "huge", "kind", "maxexponent", "minexponent", + "precision", "radix", "range", "tiny", "bit_size", "size", "shape", + "lbound", "ubound", NULL + }; + + int i; + + /* These functions must have exactly one argument. */ + if (e->value.function.actual == NULL + || e->value.function.actual->next != NULL) + return FAILURE; + + if (e->value.function.name != NULL + && e->value.function.name[0] != '\0') + return FAILURE; + + name = e->symtree->n.sym->name; + + for (i = 0; inquiry_function[i]; i++) + if (strcmp (inquiry_function[i], name) == 0) + break; + + if (inquiry_function[i] == NULL) + return FAILURE; + + e = e->value.function.actual->expr; + + if (e == NULL || e->expr_type != EXPR_VARIABLE) + return FAILURE; + + /* At this point we have a numeric inquiry function with a variable + argument. The type of the variable might be undefined, but we + need it now, because the arguments of these functions are allowed + to be undefined. */ + + if (e->ts.type == BT_UNKNOWN) + { + if (e->symtree->n.sym->ts.type == BT_UNKNOWN + && gfc_set_default_type (e->symtree->n.sym, 0, gfc_current_ns) + == FAILURE) + return FAILURE; + + e->ts = e->symtree->n.sym->ts; + } + + return SUCCESS; +} + + +/* Verify that an expression is an initialization expression. A side + effect is that the expression tree is reduced to a single constant + node if all goes well. This would normally happen when the + expression is constructed but function references are assumed to be + intrinsics in the context of initialization expressions. If + FAILURE is returned an error message has been generated. */ + +static try +check_init_expr (gfc_expr * e) +{ + gfc_actual_arglist *ap; + match m; + try t; + + if (e == NULL) + return SUCCESS; + + switch (e->expr_type) + { + case EXPR_OP: + t = check_intrinsic_op (e, check_init_expr); + if (t == SUCCESS) + t = gfc_simplify_expr (e, 0); + + break; + + case EXPR_FUNCTION: + t = SUCCESS; + + if (check_inquiry (e) != SUCCESS) + { + t = SUCCESS; + for (ap = e->value.function.actual; ap; ap = ap->next) + if (check_init_expr (ap->expr) == FAILURE) + { + t = FAILURE; + break; + } + } + + if (t == SUCCESS) + { + m = gfc_intrinsic_func_interface (e, 0); + + if (m == MATCH_NO) + gfc_error ("Function '%s' in initialization expression at %L " + "must be an intrinsic function", + e->symtree->n.sym->name, &e->where); + + if (m != MATCH_YES) + t = FAILURE; + } + + break; + + case EXPR_VARIABLE: + t = SUCCESS; + + if (gfc_check_iter_variable (e) == SUCCESS) + break; + + if (e->symtree->n.sym->attr.flavor == FL_PARAMETER) + { + t = simplify_parameter_variable (e, 0); + break; + } + + gfc_error ("Variable '%s' at %L cannot appear in an initialization " + "expression", e->symtree->n.sym->name, &e->where); + t = FAILURE; + break; + + case EXPR_CONSTANT: + case EXPR_NULL: + t = SUCCESS; + break; + + case EXPR_SUBSTRING: + t = check_init_expr (e->op1); + if (t == FAILURE) + break; + + t = check_init_expr (e->op2); + if (t == SUCCESS) + t = gfc_simplify_expr (e, 0); + + break; + + case EXPR_STRUCTURE: + t = gfc_check_constructor (e, check_init_expr); + break; + + case EXPR_ARRAY: + t = gfc_check_constructor (e, check_init_expr); + if (t == FAILURE) + break; + + t = gfc_expand_constructor (e); + if (t == FAILURE) + break; + + t = gfc_check_constructor_type (e); + break; + + default: + gfc_internal_error ("check_init_expr(): Unknown expression type"); + } + + return t; +} + + +/* Match an initialization expression. We work by first matching an + expression, then reducing it to a constant. */ + +match +gfc_match_init_expr (gfc_expr ** result) +{ + gfc_expr *expr; + match m; + try t; + + m = gfc_match_expr (&expr); + if (m != MATCH_YES) + return m; + + gfc_init_expr = 1; + t = gfc_resolve_expr (expr); + if (t == SUCCESS) + t = check_init_expr (expr); + gfc_init_expr = 0; + + if (t == FAILURE) + { + gfc_free_expr (expr); + return MATCH_ERROR; + } + + if (expr->expr_type == EXPR_ARRAY + && (gfc_check_constructor_type (expr) == FAILURE + || gfc_expand_constructor (expr) == FAILURE)) + { + gfc_free_expr (expr); + return MATCH_ERROR; + } + + if (!gfc_is_constant_expr (expr)) + gfc_internal_error ("Initialization expression didn't reduce %C"); + + *result = expr; + + return MATCH_YES; +} + + + +static try check_restricted (gfc_expr *); + +/* Given an actual argument list, test to see that each argument is a + restricted expression and optionally if the expression type is + integer or character. */ + +static try +restricted_args (gfc_actual_arglist * a, int check_type) +{ + bt type; + + for (; a; a = a->next) + { + if (check_restricted (a->expr) == FAILURE) + return FAILURE; + + if (!check_type) + continue; + + type = a->expr->ts.type; + if (type != BT_CHARACTER && type != BT_INTEGER) + { + gfc_error + ("Function argument at %L must be of type INTEGER or CHARACTER", + &a->expr->where); + return FAILURE; + } + } + + return SUCCESS; +} + + +/************* Restricted/specification expressions *************/ + + +/* Make sure a non-intrinsic function is a specification function. */ + +static try +external_spec_function (gfc_expr * e) +{ + gfc_symbol *f; + + f = e->value.function.esym; + + if (f->attr.proc == PROC_ST_FUNCTION) + { + gfc_error ("Specification function '%s' at %L cannot be a statement " + "function", f->name, &e->where); + return FAILURE; + } + + if (f->attr.proc == PROC_INTERNAL) + { + gfc_error ("Specification function '%s' at %L cannot be an internal " + "function", f->name, &e->where); + return FAILURE; + } + + if (!f->attr.pure) + { + gfc_error ("Specification function '%s' at %L must be PURE", f->name, + &e->where); + return FAILURE; + } + + if (f->attr.recursive) + { + gfc_error ("Specification function '%s' at %L cannot be RECURSIVE", + f->name, &e->where); + return FAILURE; + } + + return restricted_args (e->value.function.actual, 0); +} + + +/* Check to see that a function reference to an intrinsic is a + restricted expression. Some functions required by the standard are + omitted because references to them have already been simplified. + Strictly speaking, a lot of these checks are redundant with other + checks. If a function is indeed a particular intrinsic, then the + type of its argument have already been checked and passed. */ + +static try +restricted_intrinsic (gfc_expr * e) +{ + gfc_intrinsic_sym *sym; + + static struct + { + const char *name; + int case_number; + } + const *cp, cases[] = + { + {"repeat", 0}, + {"reshape", 0}, + {"selected_int_kind", 0}, + {"selected_real_kind", 0}, + {"transfer", 0}, + {"trim", 0}, + {"null", 1}, + {"lbound", 2}, + {"shape", 2}, + {"size", 2}, + {"ubound", 2}, + /* bit_size() has already been reduced */ + {"len", 0}, + /* kind() has already been reduced */ + /* Numeric inquiry functions have been reduced */ + { NULL, 0} + }; + + try t; + + sym = e->value.function.isym; + if (!sym) + return FAILURE; + + if (sym->elemental) + return restricted_args (e->value.function.actual, 1); + + for (cp = cases; cp->name; cp++) + if (strcmp (cp->name, sym->name) == 0) + break; + + if (cp->name == NULL) + { + gfc_error ("Intrinsic function '%s' at %L is not a restricted function", + sym->name, &e->where); + return FAILURE; + } + + switch (cp->case_number) + { + case 0: + /* Functions that are restricted if they have character/integer args. */ + t = restricted_args (e->value.function.actual, 1); + break; + + case 1: /* NULL() */ + t = SUCCESS; + break; + + case 2: + /* Functions that could be checking the bounds of an assumed-size array. */ + t = SUCCESS; + /* TODO: implement checks from 7.1.6.2 (10) */ + break; + + default: + gfc_internal_error ("restricted_intrinsic(): Bad case"); + } + + return t; +} + + +/* Verify that an expression is a restricted expression. Like its + cousin check_init_expr(), an error message is generated if we + return FAILURE. */ + +static try +check_restricted (gfc_expr * e) +{ + gfc_symbol *sym; + try t; + + if (e == NULL) + return SUCCESS; + + switch (e->expr_type) + { + case EXPR_OP: + t = check_intrinsic_op (e, check_restricted); + if (t == SUCCESS) + t = gfc_simplify_expr (e, 0); + + break; + + case EXPR_FUNCTION: + t = e->value.function.esym ? + external_spec_function (e) : restricted_intrinsic (e); + + break; + + case EXPR_VARIABLE: + sym = e->symtree->n.sym; + t = FAILURE; + + if (sym->attr.optional) + { + gfc_error ("Dummy argument '%s' at %L cannot be OPTIONAL", + sym->name, &e->where); + break; + } + + if (sym->attr.intent == INTENT_OUT) + { + gfc_error ("Dummy argument '%s' at %L cannot be INTENT(OUT)", + sym->name, &e->where); + break; + } + + if (sym->attr.in_common + || sym->attr.use_assoc + || sym->attr.dummy + || sym->ns != gfc_current_ns + || (sym->ns->proc_name != NULL + && sym->ns->proc_name->attr.flavor == FL_MODULE)) + { + t = SUCCESS; + break; + } + + gfc_error ("Variable '%s' cannot appear in the expression at %L", + sym->name, &e->where); + + break; + + case EXPR_NULL: + case EXPR_CONSTANT: + t = SUCCESS; + break; + + case EXPR_SUBSTRING: + t = gfc_specification_expr (e->op1); + if (t == FAILURE) + break; + + t = gfc_specification_expr (e->op2); + if (t == SUCCESS) + t = gfc_simplify_expr (e, 0); + + break; + + case EXPR_STRUCTURE: + t = gfc_check_constructor (e, check_restricted); + break; + + case EXPR_ARRAY: + t = gfc_check_constructor (e, check_restricted); + break; + + default: + gfc_internal_error ("check_restricted(): Unknown expression type"); + } + + return t; +} + + +/* Check to see that an expression is a specification expression. If + we return FAILURE, an error has been generated. */ + +try +gfc_specification_expr (gfc_expr * e) +{ + + if (e->ts.type != BT_INTEGER) + { + gfc_error ("Expression at %L must be of INTEGER type", &e->where); + return FAILURE; + } + + if (e->rank != 0) + { + gfc_error ("Expression at %L must be scalar", &e->where); + return FAILURE; + } + + if (gfc_simplify_expr (e, 0) == FAILURE) + return FAILURE; + + return check_restricted (e); +} + + +/************** Expression conformance checks. *************/ + +/* Given two expressions, make sure that the arrays are conformable. */ + +try +gfc_check_conformance (const char *optype, gfc_expr * op1, gfc_expr * op2) +{ + int op1_flag, op2_flag, d; + mpz_t op1_size, op2_size; + try t; + + if (op1->rank == 0 || op2->rank == 0) + return SUCCESS; + + if (op1->rank != op2->rank) + { + gfc_error ("Incompatible ranks in %s at %L", optype, &op1->where); + return FAILURE; + } + + t = SUCCESS; + + for (d = 0; d < op1->rank; d++) + { + op1_flag = gfc_array_dimen_size (op1, d, &op1_size) == SUCCESS; + op2_flag = gfc_array_dimen_size (op2, d, &op2_size) == SUCCESS; + + if (op1_flag && op2_flag && mpz_cmp (op1_size, op2_size) != 0) + { + gfc_error ("%s at %L has different shape on dimension %d (%d/%d)", + optype, &op1->where, d + 1, (int) mpz_get_si (op1_size), + (int) mpz_get_si (op2_size)); + + t = FAILURE; + } + + if (op1_flag) + mpz_clear (op1_size); + if (op2_flag) + mpz_clear (op2_size); + + if (t == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +/* Given an assignable expression and an arbitrary expression, make + sure that the assignment can take place. */ + +try +gfc_check_assign (gfc_expr * lvalue, gfc_expr * rvalue, int conform) +{ + gfc_symbol *sym; + + sym = lvalue->symtree->n.sym; + + if (sym->attr.intent == INTENT_IN) + { + gfc_error ("Can't assign to INTENT(IN) variable '%s' at %L", + sym->name, &lvalue->where); + return FAILURE; + } + + if (rvalue->rank != 0 && lvalue->rank != rvalue->rank) + { + gfc_error ("Incompatible ranks in assignment at %L", &lvalue->where); + return FAILURE; + } + + if (lvalue->ts.type == BT_UNKNOWN) + { + gfc_error ("Variable type is UNKNOWN in assignment at %L", + &lvalue->where); + return FAILURE; + } + + /* Check size of array assignments. */ + if (lvalue->rank != 0 && rvalue->rank != 0 + && gfc_check_conformance ("Array assignment", lvalue, rvalue) != SUCCESS) + return FAILURE; + + if (gfc_compare_types (&lvalue->ts, &rvalue->ts)) + return SUCCESS; + + if (!conform) + { + if (gfc_numeric_ts (&lvalue->ts) && gfc_numeric_ts (&rvalue->ts)) + return SUCCESS; + + gfc_error ("Incompatible types in assignment at %L, %s to %s", + &rvalue->where, gfc_typename (&rvalue->ts), + gfc_typename (&lvalue->ts)); + + return FAILURE; + } + + return gfc_convert_type (rvalue, &lvalue->ts, 1); +} + + +/* Check that a pointer assignment is OK. We first check lvalue, and + we only check rvalue if it's not an assignment to NULL() or a + NULLIFY statement. */ + +try +gfc_check_pointer_assign (gfc_expr * lvalue, gfc_expr * rvalue) +{ + symbol_attribute attr; + int is_pure; + + if (lvalue->symtree->n.sym->ts.type == BT_UNKNOWN) + { + gfc_error ("Pointer assignment target is not a POINTER at %L", + &lvalue->where); + return FAILURE; + } + + attr = gfc_variable_attr (lvalue, NULL); + if (!attr.pointer) + { + gfc_error ("Pointer assignment to non-POINTER at %L", &lvalue->where); + return FAILURE; + } + + is_pure = gfc_pure (NULL); + + if (is_pure && gfc_impure_variable (lvalue->symtree->n.sym)) + { + gfc_error ("Bad pointer object in PURE procedure at %L", + &lvalue->where); + return FAILURE; + } + + /* If rvalue is a NULL() or NULLIFY, we're done. Otherwise the type, + kind, etc for lvalue and rvalue must match, and rvalue must be a + pure variable if we're in a pure function. */ + if (rvalue->expr_type != EXPR_NULL) + { + + if (!gfc_compare_types (&lvalue->ts, &rvalue->ts)) + { + gfc_error ("Different types in pointer assignment at %L", + &lvalue->where); + return FAILURE; + } + + if (lvalue->ts.kind != rvalue->ts.kind) + { + gfc_error + ("Different kind type parameters in pointer assignment at %L", + &lvalue->where); + return FAILURE; + } + + attr = gfc_expr_attr (rvalue); + if (!attr.target && !attr.pointer) + { + gfc_error + ("Pointer assignment target is neither TARGET nor POINTER at " + "%L", &rvalue->where); + return FAILURE; + } + + if (is_pure && gfc_impure_variable (rvalue->symtree->n.sym)) + { + gfc_error + ("Bad target in pointer assignment in PURE procedure at %L", + &rvalue->where); + } + } + + return SUCCESS; +} + + +/* Relative of gfc_check_assign() except that the lvalue is a single + symbol. */ + +try +gfc_check_assign_symbol (gfc_symbol * sym, gfc_expr * rvalue) +{ + gfc_expr lvalue; + try r; + + memset (&lvalue, '\0', sizeof (gfc_expr)); + + lvalue.expr_type = EXPR_VARIABLE; + lvalue.ts = sym->ts; + if (sym->as) + lvalue.rank = sym->as->rank; + lvalue.symtree = (gfc_symtree *)gfc_getmem (sizeof (gfc_symtree)); + lvalue.symtree->n.sym = sym; + lvalue.where = sym->declared_at; + + r = gfc_check_assign (&lvalue, rvalue, 1); + + gfc_free (lvalue.symtree); + + return r; +} diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c new file mode 100644 index 00000000000..51ce3c4e530 --- /dev/null +++ b/gcc/fortran/f95-lang.c @@ -0,0 +1,838 @@ +/* G95 Backend interface + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook. + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* f95-lang.c-- GCC backend interface stuff */ + +/* declare required prototypes: */ + +#include "config.h" +#include "ansidecl.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-simple.h" +#include "flags.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "timevar.h" +#include "tm.h" +#include "function.h" +#include "ggc.h" +#include "toplev.h" +#include "target.h" +#include "debug.h" +#include "diagnostic.h" +#include "tree-dump.h" +#include "cgraph.h" + +#include "gfortran.h" +#include "trans.h" +#include "trans-types.h" +#include "trans-const.h" + +#include +#include + +/* Language-dependent contents of an identifier. */ + +struct lang_identifier +GTY(()) +{ + struct tree_identifier common; +}; + +/* The resulting tree type. */ + +union lang_tree_node +GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"))) +{ + union tree_node GTY((tag ("0"), + desc ("tree_node_structure (&%h)"))) generic; + struct lang_identifier GTY((tag ("1"))) identifier; +}; + +/* Save and restore the variables in this file and elsewhere + that keep track of the progress of compilation of the current function. + Used for nested functions. */ + +struct language_function +GTY(()) +{ + /* struct gfc_language_function base; */ + tree named_labels; + tree shadowed_labels; + int returns_value; + int returns_abnormally; + int warn_about_return_type; + int extern_inline; + struct binding_level *binding_level; +}; + +/* We don't have a lex/yacc lexer/parser, but toplev expects these to + exist anyway. */ +void yyerror (const char *str); +int yylex (void); + +static void gfc_init_decl_processing (void); +static void gfc_init_builtin_functions (void); + +/* Each front end provides its own. */ +static bool gfc_init (void); +static void gfc_finish (void); +static void gfc_print_identifier (FILE *, tree, int); +static bool gfc_mark_addressable (tree); +void do_function_end (void); +int global_bindings_p (void); +void insert_block (tree); +void set_block (tree); +static void gfc_be_parse_file (int); +static void gfc_expand_function (tree); + +#undef LANG_HOOKS_NAME +#undef LANG_HOOKS_INIT +#undef LANG_HOOKS_FINISH +#undef LANG_HOOKS_INIT_OPTIONS +#undef LANG_HOOKS_HANDLE_OPTION +#undef LANG_HOOKS_POST_OPTIONS +#undef LANG_HOOKS_PRINT_IDENTIFIER +#undef LANG_HOOKS_PARSE_FILE +#undef LANG_HOOKS_TRUTHVALUE_CONVERSION +#undef LANG_HOOKS_MARK_ADDRESSABLE +#undef LANG_HOOKS_TYPE_FOR_MODE +#undef LANG_HOOKS_TYPE_FOR_SIZE +#undef LANG_HOOKS_UNSIGNED_TYPE +#undef LANG_HOOKS_SIGNED_TYPE +#undef LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE +#undef LANG_HOOKS_GIMPLE_BEFORE_INLINING +#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION + +/* Define lang hooks. */ +#define LANG_HOOKS_NAME "GNU F95" +#define LANG_HOOKS_INIT gfc_init +#define LANG_HOOKS_FINISH gfc_finish +#define LANG_HOOKS_INIT_OPTIONS gfc_init_options +#define LANG_HOOKS_HANDLE_OPTION gfc_handle_option +#define LANG_HOOKS_POST_OPTIONS gfc_post_options +#define LANG_HOOKS_PRINT_IDENTIFIER gfc_print_identifier +#define LANG_HOOKS_PARSE_FILE gfc_be_parse_file +#define LANG_HOOKS_TRUTHVALUE_CONVERSION gfc_truthvalue_conversion +#define LANG_HOOKS_MARK_ADDRESSABLE gfc_mark_addressable +#define LANG_HOOKS_TYPE_FOR_MODE gfc_type_for_mode +#define LANG_HOOKS_TYPE_FOR_SIZE gfc_type_for_size +#define LANG_HOOKS_UNSIGNED_TYPE gfc_unsigned_type +#define LANG_HOOKS_SIGNED_TYPE gfc_signed_type +#define LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE gfc_signed_or_unsigned_type +#define LANG_HOOKS_GIMPLE_BEFORE_INLINING false +#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION gfc_expand_function + +const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function + that have names. Here so we can clear out their names' definitions + at the end of the function. */ + +/* Tree code classes. */ + +#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE, + +const char tree_code_type[] = { +#include "tree.def" +}; +#undef DEFTREECODE + +/* Table indexed by tree code giving number of expression + operands beyond the fixed part of the node structure. + Not used for types or decls. */ + +#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH, + +const unsigned char tree_code_length[] = { +#include "tree.def" +}; +#undef DEFTREECODE + +/* Names of tree components. + Used for printing out the tree and error messages. */ +#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME, + +const char *const tree_code_name[] = { +#include "tree.def" +}; +#undef DEFTREECODE + +static tree named_labels; + +#define NULL_BINDING_LEVEL (struct binding_level *) NULL + +/* A chain of binding_level structures awaiting reuse. */ + +static GTY(()) struct binding_level *free_binding_level; + +/* The elements of `ridpointers' are identifier nodes + for the reserved type names and storage classes. + It is indexed by a RID_... value. */ +tree *ridpointers = NULL; + +/* language-specific flags. */ + +static void +gfc_expand_function (tree fndecl) +{ + tree_rest_of_compilation (fndecl, 0); +} + + +/* 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, boolean_false_node, 1), + but we optimize comparisons, &&, ||, and !. + + The resulting type should always be `boolean_type_node'. + This is much simpler than the corresponding C version because we have a + distinct boolean type. */ + +tree +gfc_truthvalue_conversion (tree expr) +{ + switch (TREE_CODE (TREE_TYPE (expr))) + { + case BOOLEAN_TYPE: + if (TREE_TYPE (expr) == boolean_type_node) + return expr; + else if (TREE_CODE_CLASS (TREE_CODE (expr)) == '<') + { + TREE_TYPE (expr) = boolean_type_node; + return expr; + } + else if (TREE_CODE (expr) == NOP_EXPR) + return build1 (NOP_EXPR, boolean_type_node, + TREE_OPERAND (expr, 0)); + else + return build1 (NOP_EXPR, boolean_type_node, expr); + + case INTEGER_TYPE: + if (TREE_CODE (expr) == INTEGER_CST) + return integer_zerop (expr) ? boolean_false_node : boolean_true_node; + else + return build (NE_EXPR, boolean_type_node, expr, integer_zero_node); + + default: + internal_error ("Unexpected type in truthvalue_conversion"); + } +} + +static void +gfc_create_decls (void) +{ + /* GCC builtins. */ + gfc_init_builtin_functions (); + + /* Runtime/IO library functions. */ + gfc_build_builtin_function_decls (); + + gfc_init_constants (); +} + +static void +gfc_be_parse_file (int set_yydebug ATTRIBUTE_UNUSED) +{ + int errors; + int warnings; + + gfc_create_decls (); + gfc_parse_file (); + gfc_generate_constructors (); + + cgraph_finalize_compilation_unit (); + cgraph_optimize (); + + /* Tell the frontent about any errors. */ + gfc_get_errors (&warnings, &errors); + errorcount += errors; + warningcount += warnings; +} + +/* Initialize everything. */ + +static bool +gfc_init (void) +{ + /* First initialize the backend. */ + gfc_init_decl_processing (); + gfc_static_ctors = NULL_TREE; + + /* Then the frontend. */ + gfc_init_1 (); + + if (gfc_new_file (gfc_option.source, gfc_option.source_form) != SUCCESS) + fatal_error ("can't open input file: %s", gfc_option.source); + return true; +} + + +static void +gfc_finish (void) +{ + gfc_done_1 (); + gfc_release_include_path (); + return; +} + +static void +gfc_print_identifier (FILE * file ATTRIBUTE_UNUSED, + tree node ATTRIBUTE_UNUSED, + int indent ATTRIBUTE_UNUSED) +{ + return; +} + + +/* These functions and variables deal with binding contours. We only + need these functions for the list of PARM_DECLs, but we leave the + functions more general; these are a simplified version of the + functions from GNAT. */ + +/* For each binding contour we allocate a binding_level structure which records + the entities defined or declared in that contour. Contours include: + + the global one + one for each subprogram definition + one for each compound statement (declare block) + + Binding contours are used to create GCC tree BLOCK nodes. */ + +struct binding_level +GTY(()) +{ + /* A chain of ..._DECL nodes for all variables, constants, functions, + parameters and type declarations. These ..._DECL nodes are chained + through the TREE_CHAIN field. Note that these ..._DECL nodes are stored + in the reverse of the order supplied to be compatible with the + back-end. */ + tree names; + /* For each level (except the global one), a chain of BLOCK nodes for all + the levels that were entered and exited one level down from this one. */ + tree blocks; + /* The back end may need, for its own internal processing, to create a BLOCK + node. This field is set aside for this purpose. If this field is non-null + when the level is popped, i.e. when poplevel is invoked, we will use such + block instead of creating a new one from the 'names' field, that is the + ..._DECL nodes accumulated so far. Typically the routine 'pushlevel' + will be called before setting this field, so that if the front-end had + inserted ..._DECL nodes in the current block they will not be lost. */ + tree block_created_by_back_end; + /* The binding level containing this one (the enclosing binding level). */ + struct binding_level *level_chain; +}; + +/* The binding level currently in effect. */ +static GTY(()) struct binding_level *current_binding_level = NULL; + +/* The outermost binding level. This binding level is created when the + compiler is started and it will exist through the entire compilation. */ +static GTY(()) 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 }; + +/* Return non-zero if we are currently in the global binding level. */ + +int +global_bindings_p (void) +{ + return current_binding_level == global_binding_level ? -1 : 0; +} + +tree +getdecls (void) +{ + return current_binding_level->names; +} + +/* Enter a new binding level. The input parameter is ignored, but has to be + specified for back-end compatibility. */ + +void +pushlevel (int ignore ATTRIBUTE_UNUSED) +{ + struct binding_level *newlevel + = (struct binding_level *) ggc_alloc (sizeof (struct binding_level)); + + *newlevel = clear_binding_level; + + /* Add this level to the front of the chain (stack) of levels that are + active. */ + newlevel->level_chain = current_binding_level; + current_binding_level = newlevel; +} + +/* Exit a binding level. + Pop the level off, and restore the state of the identifier-decl mappings + that were in effect when this level was entered. + + If KEEP is nonzero, this level had explicit declarations, so + and create a "block" (a BLOCK node) for the level + to record its declarations and subblocks for symbol table output. + + If FUNCTIONBODY is nonzero, this level is the body of a function, + so create a block as if KEEP were set and also clear out all + label names. + + If REVERSE is nonzero, reverse the order of decls before putting + them into the BLOCK. */ + +tree +poplevel (int keep, int reverse, int functionbody) +{ + /* Points to a BLOCK tree node. This is the BLOCK node construted for the + binding level that we are about to exit and which is returned by this + routine. */ + tree block_node = NULL_TREE; + tree decl_chain; + tree subblock_chain = current_binding_level->blocks; + tree subblock_node; + tree block_created_by_back_end; + + /* Reverse the list of XXXX_DECL nodes if desired. Note that the ..._DECL + nodes chained through the `names' field of current_binding_level are in + reverse order except for PARM_DECL node, which are explicitely stored in + the right order. */ + decl_chain = (reverse) ? nreverse (current_binding_level->names) + : current_binding_level->names; + + block_created_by_back_end = + current_binding_level->block_created_by_back_end; + if (block_created_by_back_end != 0) + { + block_node = block_created_by_back_end; + + /* Check if we are about to discard some information that was gathered + by the front-end. Nameley check if the back-end created a new block + without calling pushlevel first. To understand why things are lost + just look at the next case (i.e. no block created by back-end. */ + if ((keep || functionbody) && (decl_chain || subblock_chain)) + abort (); + } + + /* If there were any declarations in the current binding level, or if this + binding level is a function body, or if there are any nested blocks then + create a BLOCK node to record them for the life of this function. */ + else if (keep || functionbody) + block_node = build_block (keep ? decl_chain : 0, 0, subblock_chain, 0, 0); + + /* Record the BLOCK node just built as the subblock its enclosing scope. */ + for (subblock_node = subblock_chain; subblock_node; + subblock_node = TREE_CHAIN (subblock_node)) + BLOCK_SUPERCONTEXT (subblock_node) = block_node; + + /* Clear out the meanings of the local variables of this level. */ + + for (subblock_node = decl_chain; subblock_node; + subblock_node = TREE_CHAIN (subblock_node)) + if (DECL_NAME (subblock_node) != 0) + /* If the identifier was used or addressed via a local extern decl, + don't forget that fact. */ + if (DECL_EXTERNAL (subblock_node)) + { + if (TREE_USED (subblock_node)) + TREE_USED (DECL_NAME (subblock_node)) = 1; + if (TREE_ADDRESSABLE (subblock_node)) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (subblock_node)) = 1; + } + + /* Pop the current level. */ + current_binding_level = current_binding_level->level_chain; + + if (functionbody) + { + /* This is the top level block of a function. The ..._DECL chain stored + in BLOCK_VARS are the function's parameters (PARM_DECL nodes). Don't + leave them in the BLOCK because they are found in the FUNCTION_DECL + instead. */ + DECL_INITIAL (current_function_decl) = block_node; + BLOCK_VARS (block_node) = 0; + } + else if (block_node) + { + if (block_created_by_back_end == NULL) + current_binding_level->blocks + = chainon (current_binding_level->blocks, block_node); + } + + /* 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 (subblock_chain) + current_binding_level->blocks + = chainon (current_binding_level->blocks, subblock_chain); + if (block_node) + TREE_USED (block_node) = 1; + + return block_node; +} + +/* Insert BLOCK at the end of the list of subblocks of the + current binding level. This is used when a BIND_EXPR is expanded, + to handle the BLOCK node inside the BIND_EXPR. */ + +void +insert_block (tree block) +{ + TREE_USED (block) = 1; + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); +} + +/* Set the BLOCK node for the innermost scope + (the one we are currently in). */ + +void +set_block (tree block) +{ + current_binding_level->block_created_by_back_end = block; +} + +/* Records a ..._DECL node DECL as belonging to the current lexical scope. + Returns the ..._DECL node. */ + +tree +pushdecl (tree decl) +{ + /* External objects aren't nested, other objects may be. */ + if ((DECL_EXTERNAL (decl)) || (decl == current_function_decl)) + DECL_CONTEXT (decl) = 0; + else + DECL_CONTEXT (decl) = current_function_decl; + + /* Put the declaration on the list. The list of declarations is in reverse + order. The list will be reversed later if necessary. This needs to be + this way for compatibility with the back-end. */ + + TREE_CHAIN (decl) = current_binding_level->names; + current_binding_level->names = decl; + + /* For the declartion of a type, set its name if it is not already set. */ + + if (TREE_CODE (decl) == TYPE_DECL && TYPE_NAME (TREE_TYPE (decl)) == 0) + { + if (DECL_SOURCE_LINE (decl) == 0) + TYPE_NAME (TREE_TYPE (decl)) = decl; + else + TYPE_NAME (TREE_TYPE (decl)) = DECL_NAME (decl); + } + + return decl; +} + + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL. */ + +tree +pushdecl_top_level (tree x) +{ + tree t; + struct binding_level *b = current_binding_level; + + current_binding_level = global_binding_level; + t = pushdecl (x); + current_binding_level = b; + return t; +} + + +#ifndef CHAR_TYPE_SIZE +#define CHAR_TYPE_SIZE BITS_PER_UNIT +#endif + +#ifndef INT_TYPE_SIZE +#define INT_TYPE_SIZE BITS_PER_WORD +#endif + +#undef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" + +/* Create tree nodes for the basic scalar types of Fortran 95, + and some nodes representing standard constants (0, 1, (void *) 0). + Initialize the global binding level. + Make definitions for built-in primitive functions. */ +static void +gfc_init_decl_processing (void) +{ + current_function_decl = NULL; + named_labels = NULL; + current_binding_level = NULL_BINDING_LEVEL; + free_binding_level = NULL_BINDING_LEVEL; + + /* Make the binding_level structure for global names. We move all + variables that are in a COMMON block to this binding level. */ + pushlevel (0); + global_binding_level = current_binding_level; + + /* Build common tree nodes. char_type_node is unsigned because we + only use it for actual characters, not for INTEGER(1). Also, we + want double_type_node to actually have double precision. */ + build_common_tree_nodes (0); + set_sizetype (long_unsigned_type_node); + build_common_tree_nodes_2 (0); + + /* Set up F95 type nodes. */ + gfc_init_types (); +} + +/* Mark EXP saying that we need to be able to take the + address of it; it should not be allocated in a register. + In Fortran 95 this is only the case for variables with + the TARGET attribute, but we implement it here for a + likely future Cray pointer extension. + Value is 1 if successful. */ +/* TODO: Check/fix mark_addressable. */ +bool +gfc_mark_addressable (tree exp) +{ + register tree x = exp; + while (1) + switch (TREE_CODE (x)) + { + case COMPONENT_REF: + case ADDR_EXPR: + case ARRAY_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + x = TREE_OPERAND (x, 0); + break; + + case CONSTRUCTOR: + TREE_ADDRESSABLE (x) = 1; + return true; + + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x) && DECL_NONLOCAL (x)) + { + if (TREE_PUBLIC (x)) + { + error + ("global register variable `%s' used in nested function", + IDENTIFIER_POINTER (DECL_NAME (x))); + return false; + } + pedwarn ("register variable `%s' used in nested function", + IDENTIFIER_POINTER (DECL_NAME (x))); + } + else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)) + { + if (TREE_PUBLIC (x)) + { + error ("address of global register variable `%s' requested", + IDENTIFIER_POINTER (DECL_NAME (x))); + return true; + } + +#if 0 + /* If we are making this addressable due to its having + volatile components, give a different error message. Also + handle the case of an unnamed parameter by not trying + to give the name. */ + + else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x))) + { + error ("cannot put object with volatile field into register"); + return false; + } +#endif + + pedwarn ("address of register variable `%s' requested", + IDENTIFIER_POINTER (DECL_NAME (x))); + } + put_var_into_stack (x, /*rescan=*/true); + + /* drops in */ + case FUNCTION_DECL: + TREE_ADDRESSABLE (x) = 1; + + default: + return true; + } +} + +/* press the big red button - garbage (ggc) collection is on */ + +int ggc_p = 1; + +/* Builtin function initialisation. */ + +/* Return a definition for a builtin function named NAME and whose data type + is TYPE. TYPE should be a function type with argument types. + FUNCTION_CODE tells later passes how to compile calls to this function. + See tree.h for its possible values. + + If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, + the name to be called if we can't opencode the function. If + ATTRS is nonzero, use that for the function's attribute list. */ + +tree +builtin_function (const char *name, + tree type, + int function_code, + enum built_in_class class, + const char *library_name, + tree attrs ATTRIBUTE_UNUSED) +{ + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + if (library_name) + SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name)); + make_decl_rtl (decl, NULL); + pushdecl (decl); + DECL_BUILT_IN_CLASS (decl) = class; + DECL_FUNCTION_CODE (decl) = function_code; + return decl; +} + + +static void +gfc_define_builtin (const char * name, + tree type, + int code, + const char * library_name, + bool const_p) +{ + tree decl; + + decl = builtin_function (name, type, code, BUILT_IN_NORMAL, + library_name, NULL_TREE); + if (const_p) + TREE_READONLY (decl) = 1; + + built_in_decls[code] = decl; + implicit_built_in_decls[code] = decl; +} + + +#define DEFINE_MATH_BUILTIN(code, name, nargs) \ + gfc_define_builtin ("__builtin_" name, mfunc_double[nargs-1], \ + BUILT_IN_ ## code, name, true); \ + gfc_define_builtin ("__builtin_" name "f", mfunc_float[nargs-1], \ + BUILT_IN_ ## code ## F, name "f", true); + +/* Initialisation of builtin function nodes. */ +static void +gfc_init_builtin_functions (void) +{ + tree mfunc_float[2]; + tree mfunc_double[2]; + tree ftype; + tree tmp; + tree voidchain; + + voidchain = tree_cons (NULL_TREE, void_type_node, NULL_TREE); + + tmp = tree_cons (NULL_TREE, float_type_node, voidchain); + mfunc_float[0] = build_function_type (float_type_node, tmp); + tmp = tree_cons (NULL_TREE, float_type_node, tmp); + mfunc_float[1] = build_function_type (float_type_node, tmp); + + tmp = tree_cons (NULL_TREE, double_type_node, voidchain); + mfunc_double[0] = build_function_type (double_type_node, tmp); + tmp = tree_cons (NULL_TREE, double_type_node, tmp); + mfunc_double[1] = build_function_type (double_type_node, tmp); + +#include "mathbuiltins.def" + + /* We define these seperately as the fortran versions have different + semantics (they return an integer type) */ + gfc_define_builtin ("__builtin_floor", mfunc_double[0], + BUILT_IN_FLOOR, "floor", true); + gfc_define_builtin ("__builtin_floorf", mfunc_float[0], + BUILT_IN_FLOORF, "floorf", true); + gfc_define_builtin ("__builtin_round", mfunc_double[0], + BUILT_IN_ROUND, "round", true); + gfc_define_builtin ("__builtin_roundf", mfunc_float[0], + BUILT_IN_ROUNDF, "roundf", true); + + /* Other builtin functions we use. */ + + tmp = tree_cons (NULL_TREE, long_integer_type_node, voidchain); + tmp = tree_cons (NULL_TREE, long_integer_type_node, tmp); + ftype = build_function_type (long_integer_type_node, tmp); + gfc_define_builtin ("__builtin_expect", ftype, BUILT_IN_EXPECT, + "__builtin_expect", true); + + tmp = tree_cons (NULL_TREE, size_type_node, voidchain); + tmp = tree_cons (NULL_TREE, pvoid_type_node, tmp); + tmp = tree_cons (NULL_TREE, pvoid_type_node, tmp); + ftype = build_function_type (pvoid_type_node, tmp); + gfc_define_builtin ("__builtin_memcpy", ftype, BUILT_IN_MEMCPY, + "memcpy", false); + + tmp = tree_cons (NULL_TREE, integer_type_node, voidchain); + ftype = build_function_type (integer_type_node, tmp); + gfc_define_builtin ("__builtin_clz", ftype, BUILT_IN_CLZ, "clz", true); + + tmp = tree_cons (NULL_TREE, long_integer_type_node, voidchain); + ftype = build_function_type (integer_type_node, tmp); + gfc_define_builtin ("__builtin_clzl", ftype, BUILT_IN_CLZL, "clzl", true); + + tmp = tree_cons (NULL_TREE, long_long_integer_type_node, voidchain); + ftype = build_function_type (integer_type_node, tmp); + gfc_define_builtin ("__builtin_clzll", ftype, BUILT_IN_CLZLL, "clzll", true); + + tmp = tree_cons (NULL_TREE, pvoid_type_node, voidchain); + tmp = tree_cons (NULL_TREE, pvoid_type_node, tmp); + tmp = tree_cons (NULL_TREE, pvoid_type_node, tmp); + ftype = build_function_type (void_type_node, tmp); + gfc_define_builtin ("__builtin_init_trampoline", ftype, + BUILT_IN_INIT_TRAMPOLINE, "init_trampoline", false); + + tmp = tree_cons (NULL_TREE, pvoid_type_node, voidchain); + ftype = build_function_type (pvoid_type_node, tmp); + gfc_define_builtin ("__builtin_adjust_trampoline", ftype, + BUILT_IN_ADJUST_TRAMPOLINE, "adjust_trampoline", true); + + tmp = tree_cons (NULL_TREE, pvoid_type_node, voidchain); + tmp = tree_cons (NULL_TREE, size_type_node, voidchain); + ftype = build_function_type (pvoid_type_node, tmp); + gfc_define_builtin ("__builtin_stack_alloc", ftype, BUILT_IN_STACK_ALLOC, + "stack_alloc", false); + + /* The stack_save and stack_restore builtins aren't used directly. They + are inserted during gimplification to implement stack_alloc calls. */ + ftype = build_function_type (pvoid_type_node, voidchain); + gfc_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE, + "stack_save", false); + tmp = tree_cons (NULL_TREE, pvoid_type_node, voidchain); + ftype = build_function_type (void_type_node, tmp); + gfc_define_builtin ("__builtin_stack_restore", ftype, BUILT_IN_STACK_RESTORE, + "stack_restore", false); +} + +#undef DEFINE_MATH_BUILTIN + +#include "gt-fortran-f95-lang.h" +#include "gtype-fortran.h" diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h new file mode 100644 index 00000000000..71665dd6d07 --- /dev/null +++ b/gcc/fortran/gfortran.h @@ -0,0 +1,1652 @@ +/* gfortran header file + Copyright (C) 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef GCC_GFORTRAN_H +#define GCC_GFORTRAN_H + +/* It's probably insane to have this large of a header file, but it + seemed like everything had to be recompiled anyway when a change + was made to a header file, and there were ordering issues with + multiple header files. Besides, Microsoft's winnt.h was 250k last + time I looked, so by comparison this is perfectly reasonable. */ + +/* We need system.h for HOST_WIDE_INT. Including hwint.h by itself doesn't + seem to be sufficient on some systems. */ +#include "system.h" +#include "coretypes.h" + +/* The following ifdefs are recommended by the autoconf documentation + for any code using alloca. */ + +/* AIX requires this to be the first thing in the file. */ +#ifdef __GNUC__ +#else /* not __GNUC__ */ +#ifdef HAVE_ALLOCA_H +#include +#else /* do not HAVE_ALLOCA_H */ +#ifdef _AIX +#pragma alloca +#else +#ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +#endif /* not predefined */ +#endif /* not _AIX */ +#endif /* do not HAVE_ALLOCA_H */ +#endif /* not __GNUC__ */ + + +#include /* need FILE * here */ + +/* Major control parameters. */ + +#define GFC_VERSION "0.23" +#define GFC_MAX_SYMBOL_LEN 63 +#define GFC_REAL_BITS 100 /* Number of bits in g95's floating point numbers. */ +#define GFC_MAX_LINE 132 /* Characters beyond this are not seen. */ +#define GFC_MAX_DIMENSIONS 7 /* Maximum dimensions in an array. */ +#define GFC_LETTERS 26 /* Number of letters in the alphabet. */ +#define MAX_ERROR_MESSAGE 1000 /* Maximum length of an error message. */ + +#define free(x) Use_gfc_free_instead_of_free() +#define gfc_is_whitespace(c) ((c==' ') || (c=='\t')) + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +/* Stringization. */ +#define stringize(x) expand_macro(x) +#define expand_macro(x) # x + +/* For a the runtime library, a standard prefix is a requirement to + avoid cluttering the namespace with things nobody asked for. It's + ugly to look at and a pain to type when you add the prefix by hand, + so we hide it behind a macro. */ +#define PREFIX(x) "_gfortran_" x + +/* Macro to initialize an mstring structure. */ +#define minit(s, t) { s, NULL, t } + +/* Structure for storing strings to be matched by gfc_match_string. */ +typedef struct +{ + const char *string; + const char *mp; + int tag; +} +mstring; + + +/* Flags to specify which standardi/extension contains a feature. */ +#define GFC_STD_GNU (1<<5) /* GNU Fortran extension. */ +#define GFC_STD_F2003 (1<<4) /* New in F2003. */ +#define GFC_STD_F2003_DEL (1<<3) /* Deleted in F2003. */ +#define GFC_STD_F2003_OBS (1<<2) /* Obsoleted in F2003. */ +#define GFC_STD_F95_DEL (1<<1) /* Deleted in F95. */ +#define GFC_STD_F95_OBS (1<<0) /* Obsoleted in F95. */ + +/*************************** Enums *****************************/ + +/* The author remains confused to this day about the convention of + returning '0' for 'SUCCESS'... or was it the other way around? The + following enum makes things much more readable. We also start + values off at one instead of zero. */ + +typedef enum +{ SUCCESS = 1, FAILURE } +try; + +/* Matchers return one of these three values. The difference between + MATCH_NO and MATCH_ERROR is that MATCH_ERROR means that a match was + successful, but that something non-syntactic is wrong and an error + has already been issued. */ + +typedef enum +{ MATCH_NO = 1, MATCH_YES, MATCH_ERROR } +match; + +typedef enum +{ FORM_FREE, FORM_FIXED, FORM_UNKNOWN } +gfc_source_form; + +typedef enum +{ BT_UNKNOWN = 1, BT_INTEGER, BT_REAL, BT_COMPLEX, + BT_LOGICAL, BT_CHARACTER, BT_DERIVED, BT_PROCEDURE +} +bt; + +/* Expression node types. */ +typedef enum +{ EXPR_OP = 1, EXPR_FUNCTION, EXPR_CONSTANT, EXPR_VARIABLE, + EXPR_SUBSTRING, EXPR_STRUCTURE, EXPR_ARRAY, EXPR_NULL +} +expr_t; + +/* Array types. */ +typedef enum +{ AS_EXPLICIT = 1, AS_ASSUMED_SHAPE, AS_DEFERRED, + AS_ASSUMED_SIZE, AS_UNKNOWN +} +array_type; + +typedef enum +{ AR_FULL = 1, AR_ELEMENT, AR_SECTION, AR_UNKNOWN } +ar_type; + +/* Statement label types. */ +typedef enum +{ ST_LABEL_UNKNOWN = 1, ST_LABEL_TARGET, + ST_LABEL_BAD_TARGET, ST_LABEL_FORMAT +} +gfc_sl_type; + +/* Intrinsic operators. */ +typedef enum +{ GFC_INTRINSIC_BEGIN = 0, + INTRINSIC_NONE = -1, INTRINSIC_UPLUS = GFC_INTRINSIC_BEGIN, + INTRINSIC_UMINUS, INTRINSIC_PLUS, INTRINSIC_MINUS, INTRINSIC_TIMES, + INTRINSIC_DIVIDE, INTRINSIC_POWER, INTRINSIC_CONCAT, + INTRINSIC_AND, INTRINSIC_OR, INTRINSIC_EQV, INTRINSIC_NEQV, + INTRINSIC_EQ, INTRINSIC_NE, INTRINSIC_GT, INTRINSIC_GE, + INTRINSIC_LT, INTRINSIC_LE, INTRINSIC_NOT, INTRINSIC_USER, + INTRINSIC_ASSIGN, + GFC_INTRINSIC_END /* Sentinel */ +} +gfc_intrinsic_op; + + +/* Strings for all intrinsic operators. */ +extern mstring intrinsic_operators[]; + + +/* This macro is the number of intrinsic operators that exist. + Assumptions are made about the numbering of the interface_op enums. */ +#define GFC_INTRINSIC_OPS GFC_INTRINSIC_END + +/* Arithmetic results. */ +typedef enum +{ ARITH_OK = 1, ARITH_OVERFLOW, ARITH_UNDERFLOW, + ARITH_DIV0, ARITH_0TO0, ARITH_INCOMMENSURATE +} +arith; + +/* Statements. */ +typedef enum +{ + ST_ARITHMETIC_IF, ST_ALLOCATE, ST_ATTR_DECL, ST_BACKSPACE, ST_BLOCK_DATA, + ST_CALL, ST_CASE, ST_CLOSE, ST_COMMON, ST_CONTINUE, ST_CONTAINS, ST_CYCLE, + ST_DATA, ST_DATA_DECL, ST_DEALLOCATE, ST_DO, ST_ELSE, ST_ELSEIF, + ST_ELSEWHERE, ST_END_BLOCK_DATA, ST_ENDDO, ST_IMPLIED_ENDDO, + ST_END_FILE, ST_END_FORALL, ST_END_FUNCTION, ST_ENDIF, ST_END_INTERFACE, + ST_END_MODULE, ST_END_PROGRAM, ST_END_SELECT, ST_END_SUBROUTINE, + ST_END_WHERE, ST_END_TYPE, ST_ENTRY, ST_EQUIVALENCE, ST_EXIT, ST_FORALL, + ST_FORALL_BLOCK, ST_FORMAT, ST_FUNCTION, ST_GOTO, ST_IF_BLOCK, ST_IMPLICIT, + ST_IMPLICIT_NONE, ST_INQUIRE, ST_INTERFACE, ST_PARAMETER, ST_MODULE, + ST_MODULE_PROC, ST_NAMELIST, ST_NULLIFY, ST_OPEN, ST_PAUSE, ST_PRIVATE, + ST_PROGRAM, ST_PUBLIC, ST_READ, ST_RETURN, ST_REWIND, ST_STOP, + ST_SUBROUTINE, + ST_TYPE, ST_USE, ST_WHERE_BLOCK, ST_WHERE, ST_WRITE, ST_ASSIGNMENT, + ST_POINTER_ASSIGNMENT, ST_SELECT_CASE, ST_SEQUENCE, ST_SIMPLE_IF, + ST_STATEMENT_FUNCTION, ST_DERIVED_DECL, ST_LABEL_ASSIGNMENT, ST_NONE +} +gfc_statement; + + +/* Types of interfaces that we can have. Assignment interfaces are + considered to be intrinsic operators. */ +typedef enum +{ + INTERFACE_NAMELESS = 1, INTERFACE_GENERIC, + INTERFACE_INTRINSIC_OP, INTERFACE_USER_OP +} +interface_type; + +/* Symbol flavors: these are all mutually exclusive. + 10 elements = 4 bits. */ +typedef enum +{ + FL_UNKNOWN = 0, FL_PROGRAM, FL_BLOCK_DATA, FL_MODULE, FL_VARIABLE, + FL_PARAMETER, FL_LABEL, FL_PROCEDURE, FL_DERIVED, FL_NAMELIST +} +sym_flavor; + +/* Procedure types. 7 elements = 3 bits. */ +typedef enum +{ PROC_UNKNOWN, PROC_MODULE, PROC_INTERNAL, PROC_DUMMY, + PROC_INTRINSIC, PROC_ST_FUNCTION, PROC_EXTERNAL +} +procedure_type; + +/* Intent types. */ +typedef enum +{ INTENT_UNKNOWN = 0, INTENT_IN, INTENT_OUT, INTENT_INOUT +} +sym_intent; + +/* Access types. */ +typedef enum +{ ACCESS_PUBLIC = 1, ACCESS_PRIVATE, ACCESS_UNKNOWN +} +gfc_access; + +/* Flags to keep track of where an interface came from. + 4 elements = 2 bits. */ +typedef enum +{ IFSRC_UNKNOWN = 0, IFSRC_DECL, IFSRC_IFBODY, IFSRC_USAGE +} +ifsrc; + +/* Strings for all symbol attributes. We use these for dumping the + parse tree, in error messages, and also when reading and writing + modules. In symbol.c. */ +extern const mstring flavors[]; +extern const mstring procedures[]; +extern const mstring intents[]; +extern const mstring access_types[]; +extern const mstring ifsrc_types[]; + +/* Enumeration of all the generic intrinsic functions. Used by the + backend for identification of a function. */ + +enum gfc_generic_isym_id +{ + /* GFC_ISYM_NONE is used for intrinsics which will never be seen by + the backend (eg. KIND). */ + GFC_ISYM_NONE = 0, + GFC_ISYM_ABS, + GFC_ISYM_ACHAR, + GFC_ISYM_ACOS, + GFC_ISYM_ADJUSTL, + GFC_ISYM_ADJUSTR, + GFC_ISYM_AIMAG, + GFC_ISYM_AINT, + GFC_ISYM_ALL, + GFC_ISYM_ALLOCATED, + GFC_ISYM_ANINT, + GFC_ISYM_ANY, + GFC_ISYM_ASIN, + GFC_ISYM_ASSOCIATED, + GFC_ISYM_ATAN, + GFC_ISYM_ATAN2, + GFC_ISYM_BTEST, + GFC_ISYM_CEILING, + GFC_ISYM_CHAR, + GFC_ISYM_CMPLX, + GFC_ISYM_CONJG, + GFC_ISYM_COS, + GFC_ISYM_COSH, + GFC_ISYM_COUNT, + GFC_ISYM_CSHIFT, + GFC_ISYM_DBLE, + GFC_ISYM_DIM, + GFC_ISYM_DOT_PRODUCT, + GFC_ISYM_DPROD, + GFC_ISYM_EOSHIFT, + GFC_ISYM_EXP, + GFC_ISYM_EXPONENT, + GFC_ISYM_FLOOR, + GFC_ISYM_FRACTION, + GFC_ISYM_IACHAR, + GFC_ISYM_IAND, + GFC_ISYM_IBCLR, + GFC_ISYM_IBITS, + GFC_ISYM_IBSET, + GFC_ISYM_ICHAR, + GFC_ISYM_IEOR, + GFC_ISYM_INDEX, + GFC_ISYM_INT, + GFC_ISYM_IOR, + GFC_ISYM_ISHFT, + GFC_ISYM_ISHFTC, + GFC_ISYM_LBOUND, + GFC_ISYM_LEN, + GFC_ISYM_LEN_TRIM, + GFC_ISYM_LGE, + GFC_ISYM_LGT, + GFC_ISYM_LLE, + GFC_ISYM_LLT, + GFC_ISYM_LOG, + GFC_ISYM_LOG10, + GFC_ISYM_LOGICAL, + GFC_ISYM_MATMUL, + GFC_ISYM_MAX, + GFC_ISYM_MAXLOC, + GFC_ISYM_MAXVAL, + GFC_ISYM_MERGE, + GFC_ISYM_MIN, + GFC_ISYM_MINLOC, + GFC_ISYM_MINVAL, + GFC_ISYM_MOD, + GFC_ISYM_MODULO, + GFC_ISYM_NEAREST, + GFC_ISYM_NINT, + GFC_ISYM_NOT, + GFC_ISYM_PACK, + GFC_ISYM_PRESENT, + GFC_ISYM_PRODUCT, + GFC_ISYM_REAL, + GFC_ISYM_REPEAT, + GFC_ISYM_RESHAPE, + GFC_ISYM_RRSPACING, + GFC_ISYM_SCALE, + GFC_ISYM_SCAN, + GFC_ISYM_SET_EXPONENT, + GFC_ISYM_SHAPE, + GFC_ISYM_SI_KIND, + GFC_ISYM_SIGN, + GFC_ISYM_SIN, + GFC_ISYM_SINH, + GFC_ISYM_SIZE, + GFC_ISYM_SPACING, + GFC_ISYM_SPREAD, + GFC_ISYM_SQRT, + GFC_ISYM_SR_KIND, + GFC_ISYM_SUM, + GFC_ISYM_TAN, + GFC_ISYM_TANH, + GFC_ISYM_TRANSFER, + GFC_ISYM_TRANSPOSE, + GFC_ISYM_TRIM, + GFC_ISYM_UBOUND, + GFC_ISYM_UNPACK, + GFC_ISYM_VERIFY, + GFC_ISYM_CONVERSION +}; +typedef enum gfc_generic_isym_id gfc_generic_isym_id; + +/************************* Structures *****************************/ + +/* Symbol attribute structure. */ +typedef struct +{ + /* Variable attributes. */ + unsigned allocatable:1, dimension:1, external:1, intrinsic:1, + optional:1, pointer:1, save:1, target:1, + dummy:1, common:1, result:1, entry:1, assign:1; + + unsigned data:1, /* Symbol is named in a DATA statement. */ + use_assoc:1; /* Symbol has been use-associated. */ + + unsigned in_namelist:1, in_common:1, saved_common:1; + unsigned function:1, subroutine:1, generic:1; + unsigned implicit_type:1; /* Type defined via implicit rules */ + + /* Function/subroutine attributes */ + unsigned sequence:1, elemental:1, pure:1, recursive:1; + unsigned unmaskable:1, masked:1, contained:1; + + /* Set if a function must always be referenced by an explicit interface. */ + unsigned always_explicit:1; + + /* Set if the symbol has been referenced in an expression. No further + modification of type or type parameters is permitted. */ + unsigned referenced:1; + + /* Mutually exclusive multibit attributes. */ + gfc_access access:2; + sym_intent intent:2; + sym_flavor flavor:4; + ifsrc if_source:2; + + procedure_type proc:3; + +} +symbol_attribute; + + +typedef struct +{ + char *nextc; + int line; /* line within the lp structure */ + struct linebuf *lp; + struct gfc_file *file; +} +locus; + +/* The linebuf structure deserves some explanation. This is the + primary structure for holding lines. A source file is stored in a + singly linked list of these structures. Each structure holds an + integer number of lines. The line[] member is actually an array of + pointers that point to the NULL-terminated lines. This list grows + upwards, and the actual lines are stored at the top of the + structure and grow downward. Each structure is packed with as many + lines as it can hold, then another linebuf is allocated. */ + +/* Chosen so that sizeof(linebuf) = 4096 on most machines */ +#define LINEBUF_SIZE 4080 + +typedef struct linebuf +{ + int start_line, lines; + struct linebuf *next; + char *line[1]; + char buf[LINEBUF_SIZE]; +} +linebuf; + + +#include +#ifndef PATH_MAX +# include +# define PATH_MAX MAXPATHLEN +#endif + + +typedef struct gfc_file +{ + char filename[PATH_MAX + 1]; + gfc_source_form form; + struct gfc_file *included_by, *next; + locus loc; + struct linebuf *start; +} +gfc_file; + + +extern int gfc_suppress_error; + + +/* Character length structures hold the expression that gives the + length of a character variable. We avoid putting these into + gfc_typespec because doing so prevents us from doing structure + copies and forces us to deallocate any typespecs we create, as well + as structures that contain typespecs. They also can have multiple + character typespecs pointing to them. + + These structures form a singly linked list within the current + namespace and are deallocated with the namespace. It is possible to + end up with gfc_charlen structures that have nothing pointing to them. */ + +typedef struct gfc_charlen +{ + struct gfc_expr *length; + struct gfc_charlen *next; + tree backend_decl; +} +gfc_charlen; + +#define gfc_get_charlen() gfc_getmem(sizeof(gfc_charlen)) + +/* Type specification structure. FIXME: derived and cl could be union??? */ +typedef struct +{ + bt type; + int kind; + struct gfc_symbol *derived; + gfc_charlen *cl; /* For character types only. */ +} +gfc_typespec; + +/* Array specification. */ +typedef struct +{ + int rank; /* A rank of zero means that a variable is a scalar. */ + array_type type; + struct gfc_expr *lower[GFC_MAX_DIMENSIONS], *upper[GFC_MAX_DIMENSIONS]; +} +gfc_array_spec; + +#define gfc_get_array_spec() gfc_getmem(sizeof(gfc_array_spec)) + + +/* Components of derived types. */ +typedef struct gfc_component +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_typespec ts; + + int pointer, dimension; + gfc_array_spec *as; + + tree backend_decl; + locus loc; + struct gfc_expr *initializer; + struct gfc_component *next; +} +gfc_component; + +#define gfc_get_component() gfc_getmem(sizeof(gfc_component)) + +/* Formal argument lists are lists of symbols. */ +typedef struct gfc_formal_arglist +{ + struct gfc_symbol *sym; + struct gfc_formal_arglist *next; +} +gfc_formal_arglist; + +#define gfc_get_formal_arglist() gfc_getmem(sizeof(gfc_formal_arglist)) + + +/* The gfc_actual_arglist structure is for actual arguments. */ +typedef struct gfc_actual_arglist +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + /* Alternate return label when the expr member is null. */ + struct gfc_st_label *label; + + struct gfc_expr *expr; + struct gfc_actual_arglist *next; +} +gfc_actual_arglist; + +#define gfc_get_actual_arglist() gfc_getmem(sizeof(gfc_actual_arglist)) + + +/* Because a symbol can belong to multiple namelists, they must be + linked externally to the symbol itself. */ +typedef struct gfc_namelist +{ + struct gfc_symbol *sym; + struct gfc_namelist *next; +} +gfc_namelist; + +#define gfc_get_namelist() gfc_getmem(sizeof(gfc_namelist)) + + +/* The gfc_st_label structure is a doubly linked list attached to a + namespace that records the usage of statement labels within that + space. */ +/* TODO: Make format/statement specifics a union. */ +typedef struct gfc_st_label +{ + int value; + + gfc_sl_type defined, referenced; + + struct gfc_expr *format; + + tree backend_decl; + + locus where; + + struct gfc_st_label *prev, *next; +} +gfc_st_label; + + +/* gfc_interface()-- Interfaces are lists of symbols strung together. */ +typedef struct gfc_interface +{ + struct gfc_symbol *sym; + locus where; + struct gfc_interface *next; +} +gfc_interface; + +#define gfc_get_interface() gfc_getmem(sizeof(gfc_interface)) + + +/* User operator nodes. These are like stripped down symbols. */ +typedef struct +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + + gfc_interface *operator; + struct gfc_namespace *ns; + gfc_access access; +} +gfc_user_op; + +/* Symbol nodes. These are important things. They are what the + standard refers to as "entities". The possibly multiple names that + refer to the same entity are accomplished by a binary tree of + symtree structures that is balanced by the red-black method-- more + than one symtree node can point to any given symbol. */ + +typedef struct gfc_symbol +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; /* Primary name, before renaming */ + char module[GFC_MAX_SYMBOL_LEN + 1]; /* Module this symbol came from */ + locus declared_at; + + gfc_typespec ts; + symbol_attribute attr; + + /* The interface member points to the formal argument list if the + symbol is a function or subroutine name. If the symbol is a + generic name, the generic member points to the list of + interfaces. */ + + gfc_interface *generic; + gfc_access component_access; + + gfc_formal_arglist *formal; + struct gfc_namespace *formal_ns; + + struct gfc_expr *value; /* Parameter/Initializer value */ + gfc_array_spec *as; + struct gfc_symbol *result; /* function result symbol */ + gfc_component *components; /* Derived type components */ + + /* TODO: These three fields are mutually exclusive. */ + struct gfc_symbol *common_head, *common_next; /* Links for COMMON syms */ + /* Make sure setup code for dummy arguments is generated in the correct + order. */ + int dummy_order; + + gfc_namelist *namelist, *namelist_tail; + + /* Change management fields. Symbols that might be modified by the + current statement have the mark member nonzero and are kept in a + singly linked list through the tlink field. Of these symbols, + symbols with old_symbol equal to NULL are symbols created within + the current statement. Otherwise, old_symbol points to a copy of + the old symbol. */ + + struct gfc_symbol *old_symbol, *tlink; + unsigned mark:1, new:1; + int refs; + struct gfc_namespace *ns; /* namespace containing this symbol */ + + tree backend_decl; + +} +gfc_symbol; + + +/* Within a namespace, symbols are pointed to by symtree nodes that + are linked together in a balanced binary tree. There can be + several symtrees pointing to the same symbol node via USE + statements. */ + +#define BBT_HEADER(self) int priority; struct self *left, *right + +typedef struct gfc_symtree +{ + BBT_HEADER (gfc_symtree); + char name[GFC_MAX_SYMBOL_LEN + 1]; + int ambiguous; + union + { + gfc_symbol *sym; /* Symbol associated with this node */ + gfc_user_op *uop; + } + n; + +} +gfc_symtree; + + +typedef struct gfc_namespace +{ + gfc_symtree *sym_root, *uop_root; /* Roots of the red/black symbol trees */ + + int set_flag[GFC_LETTERS]; + gfc_typespec default_type[GFC_LETTERS]; /* IMPLICIT typespecs */ + + struct gfc_symbol *proc_name; + gfc_interface *operator[GFC_INTRINSIC_OPS]; + struct gfc_namespace *parent, *contained, *sibling; + struct gfc_code *code; + gfc_symbol *blank_common; + struct gfc_equiv *equiv; + gfc_access default_access, operator_access[GFC_INTRINSIC_OPS]; + + gfc_st_label *st_labels; + struct gfc_data *data; + + gfc_charlen *cl_list; + + int save_all, seen_save; +} +gfc_namespace; + +extern gfc_namespace *gfc_current_ns; + + +/* Information on interfaces being built. */ +typedef struct +{ + interface_type type; + gfc_symbol *sym; + gfc_namespace *ns; + gfc_user_op *uop; + gfc_intrinsic_op op; +} +gfc_interface_info; + +extern gfc_interface_info current_interface; + + +/* Array reference. */ +typedef struct gfc_array_ref +{ + ar_type type; + int dimen; /* # of components in the reference */ + locus where; + gfc_array_spec *as; + + locus c_where[GFC_MAX_DIMENSIONS]; /* All expressions can be NULL */ + struct gfc_expr *start[GFC_MAX_DIMENSIONS], *end[GFC_MAX_DIMENSIONS], + *stride[GFC_MAX_DIMENSIONS]; + + enum + { DIMEN_ELEMENT = 1, DIMEN_RANGE, DIMEN_VECTOR, DIMEN_UNKNOWN } + dimen_type[GFC_MAX_DIMENSIONS]; + + struct gfc_expr *offset; +} +gfc_array_ref; + +#define gfc_get_array_ref() gfc_getmem(sizeof(gfc_array_ref)) + + +/* Component reference nodes. A variable is stored as an expression + node that points to the base symbol. After that, a singly linked + list of component reference nodes gives the variable's complete + resolution. The array_ref component may be present and comes + before the component component. */ + +typedef enum + { REF_ARRAY, REF_COMPONENT, REF_SUBSTRING } +ref_type; + +typedef struct gfc_ref +{ + ref_type type; + + union + { + struct gfc_array_ref ar; + + struct + { + gfc_component *component; + gfc_symbol *sym; + } + c; + + struct + { + struct gfc_expr *start, *end; /* Substring */ + gfc_charlen *length; + } + ss; + + } + u; + + struct gfc_ref *next; +} +gfc_ref; + +#define gfc_get_ref() gfc_getmem(sizeof(gfc_ref)) + + +/* Structures representing intrinsic symbols and their arguments lists. */ +typedef struct gfc_intrinsic_arg +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + + gfc_typespec ts; + int optional; + gfc_actual_arglist *actual; + + struct gfc_intrinsic_arg *next; + +} +gfc_intrinsic_arg; + + +typedef union +{ + try (*f1)(struct gfc_expr *); + try (*f1m)(gfc_actual_arglist *); + try (*f2)(struct gfc_expr *, struct gfc_expr *); + try (*f3)(struct gfc_expr *, struct gfc_expr *, struct gfc_expr *); + try (*f4)(struct gfc_expr *, struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *); + try (*f5)(struct gfc_expr *, struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *, struct gfc_expr *); +} +gfc_check_f; + + +typedef union +{ + struct gfc_expr *(*f1)(struct gfc_expr *); + struct gfc_expr *(*f2)(struct gfc_expr *, struct gfc_expr *); + struct gfc_expr *(*f3)(struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *); + struct gfc_expr *(*f4)(struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *, struct gfc_expr *); + struct gfc_expr *(*f5)(struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *); + struct gfc_expr *(*cc)(struct gfc_expr *, bt, int); +} +gfc_simplify_f; + + +typedef union +{ + void (*f0)(struct gfc_expr *); + void (*f1)(struct gfc_expr *, struct gfc_expr *); + void (*f1m)(struct gfc_expr *, struct gfc_actual_arglist *); + void (*f2)(struct gfc_expr *, struct gfc_expr *, struct gfc_expr *); + void (*f3)(struct gfc_expr *, struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *); + void (*f4)(struct gfc_expr *, struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *, struct gfc_expr *); + void (*f5)(struct gfc_expr *, struct gfc_expr *, struct gfc_expr *, + struct gfc_expr *, struct gfc_expr *, struct gfc_expr *); + void (*s1)(struct gfc_code *); +} +gfc_resolve_f; + + +typedef struct gfc_intrinsic_sym +{ + char name[GFC_MAX_SYMBOL_LEN + 1], lib_name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_intrinsic_arg *formal; + gfc_typespec ts; + int elemental, pure, generic, specific, actual_ok; + + gfc_simplify_f simplify; + gfc_check_f check; + gfc_resolve_f resolve; + struct gfc_intrinsic_sym *specific_head, *next; + gfc_generic_isym_id generic_id; + +} +gfc_intrinsic_sym; + + +/* Expression nodes. The expression node types deserve explanations, + since the last couple can be easily misconstrued: + + EXPR_OP Operator node pointing to one or two other nodes + EXPR_FUNCTION Function call, symbol points to function's name + EXPR_CONSTANT A scalar constant: Logical, String, Real, Int or Complex + EXPR_VARIABLE An Lvalue with a root symbol and possible reference list + which expresses structure, array and substring refs. + EXPR_NULL The NULL pointer value (which also has a basic type). + EXPR_SUBSTRING A substring of a constant string + EXPR_STRUCTURE A structure constructor + EXPR_ARRAY An array constructor. */ + +#include + +typedef struct gfc_expr +{ + expr_t expr_type; + + gfc_typespec ts; /* These two refer to the overall expression */ + + int rank; + mpz_t *shape; /* Can be NULL if shape is unknown at compile time */ + + gfc_intrinsic_op operator; + + /* Nonnull for functions and structure constructors */ + gfc_symtree *symtree; + + gfc_user_op *uop; + gfc_ref *ref; + + struct gfc_expr *op1, *op2; + locus where; + + union + { + mpz_t integer; + mpf_t real; + int logical; + + struct + { + mpf_t r, i; + } + complex; + + struct + { + gfc_actual_arglist *actual; + char *name; /* Points to the ultimate name of the function */ + gfc_intrinsic_sym *isym; + gfc_symbol *esym; + } + function; + + struct + { + int length; + char *string; + } + character; + + struct gfc_constructor *constructor; + } + value; + +} +gfc_expr; + + +#define gfc_get_shape(rank) ((mpz_t *) gfc_getmem(rank*sizeof(mpz_t))) + +/* Structures for information associated with different kinds of + numbers. The first set of integer parameters define all there is + to know about a particular kind. The rest of the elements are + computed from the first elements. */ + +typedef struct +{ + int kind, radix, digits, bit_size; + + int range; + mpz_t huge; + + mpz_t min_int, max_int; /* Values really representable by the target */ +} +gfc_integer_info; + +extern gfc_integer_info gfc_integer_kinds[]; + + +typedef struct +{ + int kind, bit_size; + +} +gfc_logical_info; + +extern gfc_logical_info gfc_logical_kinds[]; + + +typedef struct +{ + int kind, radix, digits, min_exponent, max_exponent; + + int range, precision; + mpf_t epsilon, huge, tiny; +} +gfc_real_info; + +extern gfc_real_info gfc_real_kinds[]; + + +/* Equivalence structures. Equivalent lvalues are linked along the + *eq pointer, equivalence sets are strung along the *next node. */ +typedef struct gfc_equiv +{ + struct gfc_equiv *next, *eq; + gfc_expr *expr; + int used; +} +gfc_equiv; + +#define gfc_get_equiv() gfc_getmem(sizeof(gfc_equiv)) + + +/* gfc_case stores the selector list of a case statement. The *low + and *high pointers can point to the same expression in the case of + a single value. If *high is NULL, the selection is from *low + upwards, if *low is NULL the selection is *high downwards. + + This structure has separate fields to allow singe and double linked + lists of CASEs the same time. The singe linked list along the NEXT + field is a list of cases for a single CASE label. The double linked + list along the LEFT/RIGHT fields is used to detect overlap and to + build a table of the cases for SELECT constructs with a CHARACTER + case expression. */ + +typedef struct gfc_case +{ + /* Where we saw this case. */ + locus where; + int n; + + /* Case range values. If (low == high), it's a single value. If one of + the labels is NULL, it's an unbounded case. If both are NULL, this + represents the default case. */ + gfc_expr *low, *high; + + /* Next case label in the list of cases for a single CASE label. */ + struct gfc_case *next; + + /* Used for detecting overlap, and for code generation. */ + struct gfc_case *left, *right; + + /* True if this case label can never be matched. */ + int unreachable; +} +gfc_case; + +#define gfc_get_case() gfc_getmem(sizeof(gfc_case)) + + +typedef struct +{ + gfc_expr *var, *start, *end, *step; +} +gfc_iterator; + +#define gfc_get_iterator() gfc_getmem(sizeof(gfc_iterator)) + + +/* Allocation structure for ALLOCATE, DEALLOCATE and NULLIFY statements. */ + +typedef struct gfc_alloc +{ + gfc_expr *expr; + struct gfc_alloc *next; +} +gfc_alloc; + +#define gfc_get_alloc() gfc_getmem(sizeof(gfc_alloc)) + + +typedef struct +{ + gfc_expr *unit, *file, *status, *access, *form, *recl, + *blank, *position, *action, *delim, *pad, *iostat; + gfc_st_label *err; +} +gfc_open; + + +typedef struct +{ + gfc_expr *unit, *status, *iostat; + gfc_st_label *err; +} +gfc_close; + + +typedef struct +{ + gfc_expr *unit, *iostat; + gfc_st_label *err; +} +gfc_filepos; + + +typedef struct +{ + gfc_expr *unit, *file, *iostat, *exist, *opened, *number, *named, + *name, *access, *sequential, *direct, *form, *formatted, + *unformatted, *recl, *nextrec, *blank, *position, *action, *read, + *write, *readwrite, *delim, *pad, *iolength; + + gfc_st_label *err; + +} +gfc_inquire; + + +typedef struct +{ + gfc_expr *io_unit, *format_expr, *rec, *advance, *iostat, *size; + + gfc_symbol *namelist; + /* A format_label of `format_asterisk' indicates the "*" format */ + gfc_st_label *format_label; + gfc_st_label *err, *end, *eor; + + locus eor_where, end_where; +} +gfc_dt; + + +typedef struct gfc_forall_iterator +{ + gfc_expr *var, *start, *end, *stride; + struct gfc_forall_iterator *next; +} +gfc_forall_iterator; + + +/* Executable statements that fill gfc_code structures. */ +typedef enum +{ + EXEC_NOP = 1, EXEC_ASSIGN, EXEC_LABEL_ASSIGN, EXEC_POINTER_ASSIGN, + EXEC_GOTO, EXEC_CALL, EXEC_RETURN, EXEC_PAUSE, EXEC_STOP, EXEC_CONTINUE, + EXEC_IF, EXEC_ARITHMETIC_IF, EXEC_DO, EXEC_DO_WHILE, EXEC_SELECT, + EXEC_FORALL, EXEC_WHERE, EXEC_CYCLE, EXEC_EXIT, + EXEC_ALLOCATE, EXEC_DEALLOCATE, + EXEC_OPEN, EXEC_CLOSE, + EXEC_READ, EXEC_WRITE, EXEC_IOLENGTH, EXEC_TRANSFER, EXEC_DT_END, + EXEC_BACKSPACE, EXEC_ENDFILE, EXEC_INQUIRE, EXEC_REWIND +} +gfc_exec_op; + +typedef struct gfc_code +{ + gfc_exec_op op; + + struct gfc_code *block, *next; + locus loc; + + gfc_st_label *here, *label, *label2, *label3; + gfc_symtree *symtree; + gfc_expr *expr, *expr2; + /* A name isn't sufficient to identify a subroutine, we need the actual + symbol for the interface definition. + const char *sub_name; */ + gfc_symbol *resolved_sym; + + union + { + gfc_actual_arglist *actual; + gfc_case *case_list; + gfc_iterator *iterator; + gfc_alloc *alloc_list; + gfc_open *open; + gfc_close *close; + gfc_filepos *filepos; + gfc_inquire *inquire; + gfc_dt *dt; + gfc_forall_iterator *forall_iterator; + struct gfc_code *whichloop; + int stop_code; + } + ext; /* Points to additional structures required by statement */ + + /* Backend_decl is used for cycle and break labels in do loops, and + * probably for other constructs as well, once we translate them. */ + tree backend_decl; +} +gfc_code; + + +/* Storage for DATA statements. */ +typedef struct gfc_data_variable +{ + gfc_expr *expr; + gfc_iterator iter; + struct gfc_data_variable *list, *next; +} +gfc_data_variable; + + +typedef struct gfc_data_value +{ + int repeat; + gfc_expr *expr; + + struct gfc_data_value *next; +} +gfc_data_value; + + +typedef struct gfc_data +{ + gfc_data_variable *var; + gfc_data_value *value; + locus where; + + struct gfc_data *next; +} +gfc_data; + +#define gfc_get_data_variable() gfc_getmem(sizeof(gfc_data_variable)) +#define gfc_get_data_value() gfc_getmem(sizeof(gfc_data_value)) +#define gfc_get_data() gfc_getmem(sizeof(gfc_data)) + + +/* Structure for holding compile options */ +typedef struct +{ + const char *source; + char *module_dir; + gfc_source_form source_form; + int fixed_line_length; + int max_identifier_length; + int verbose; + + int warn_aliasing; + int warn_conversion; + int warn_implicit_interface; + int warn_line_truncation; + int warn_surprising; + int warn_unused_labels; + + int flag_dollar_ok; + int flag_underscoring; + int flag_second_underscore; + int flag_implicit_none; + int flag_max_stack_var_size; + int flag_module_access_private; + int flag_no_backend; + int flag_pack_derived; + int flag_repack_arrays; + + int q_kind; + int r8; + int i8; + int d8; + int warn_std; + int allow_std; +} +gfc_option_t; + +extern gfc_option_t gfc_option; + + +/* Constructor nodes for array and structure constructors. */ +typedef struct gfc_constructor +{ + gfc_expr *expr; + gfc_iterator *iterator; + locus where; + struct gfc_constructor *next; + struct + { + mpz_t offset; /* Record the offset of array element which appears in + data statement like "data a(5)/4/". */ + gfc_component *component; /* Record the component being initialized. */ + } + n; + mpz_t repeat; /* Record the repeat number of initial values in data + statement like "data a/5*10/". */ +} +gfc_constructor; + + +typedef struct iterator_stack +{ + gfc_symtree *variable; + mpz_t value; + struct iterator_stack *prev; +} +iterator_stack; +extern iterator_stack *iter_stack; + +/************************ Function prototypes *************************/ + +/* data.c */ +void gfc_formalize_init_value (gfc_symbol *); +void gfc_get_section_index (gfc_array_ref *, mpz_t *, mpz_t *); +void gfc_assign_data_value (gfc_expr *, gfc_expr *, mpz_t); +void gfc_advance_section (mpz_t *, gfc_array_ref *, mpz_t *); + +/* scanner.c */ +void gfc_scanner_done_1 (void); +void gfc_scanner_init_1 (void); + +void gfc_add_include_path (const char *); +void gfc_release_include_path (void); +FILE *gfc_open_included_file (const char *); + +locus *gfc_current_locus (void); +void gfc_set_locus (locus *); + +int gfc_at_end (void); +int gfc_at_eof (void); +int gfc_at_bol (void); +int gfc_at_eol (void); +void gfc_advance_line (void); +int gfc_check_include (void); + +void gfc_skip_comments (void); +int gfc_next_char_literal (int); +int gfc_next_char (void); +int gfc_peek_char (void); +void gfc_error_recovery (void); +void gfc_gobble_whitespace (void); +try gfc_new_file (const char *, gfc_source_form); + +extern gfc_file *gfc_current_file; + +/* misc.c */ +void *gfc_getmem (size_t) ATTRIBUTE_MALLOC; +void gfc_free (void *); +int gfc_terminal_width(void); +void gfc_clear_ts (gfc_typespec *); +FILE *gfc_open_file (const char *); +const char *gfc_article (const char *); +const char *gfc_basic_typename (bt); +const char *gfc_typename (gfc_typespec *); + +#define gfc_op2string(OP) (OP == INTRINSIC_ASSIGN ? \ + "=" : gfc_code2string (intrinsic_operators, OP)) + +const char *gfc_code2string (const mstring *, int); +int gfc_string2code (const mstring *, const char *); +const char *gfc_intent_string (sym_intent); + +void gfc_init_1 (void); +void gfc_init_2 (void); +void gfc_done_1 (void); +void gfc_done_2 (void); + +/* options.c */ +unsigned int gfc_init_options (unsigned int, const char **); +int gfc_handle_option (size_t, const char *, int); +bool gfc_post_options (const char **); + +/* iresolve.c */ +char * gfc_get_string (const char *, ...) ATTRIBUTE_PRINTF_1; +void gfc_iresolve_init_1 (void); +void gfc_iresolve_done_1 (void); + +/* error.c */ + +typedef struct gfc_error_buf +{ + int flag; + char message[MAX_ERROR_MESSAGE]; +} gfc_error_buf; + +void gfc_error_init_1 (void); +void gfc_buffer_error (int); + +void gfc_warning (const char *, ...); +void gfc_warning_now (const char *, ...); +void gfc_clear_warning (void); +void gfc_warning_check (void); + +void gfc_error (const char *, ...); +void gfc_error_now (const char *, ...); +void gfc_fatal_error (const char *, ...) ATTRIBUTE_NORETURN; +void gfc_internal_error (const char *, ...) ATTRIBUTE_NORETURN; +void gfc_clear_error (void); +int gfc_error_check (void); + +try gfc_notify_std (int, const char *, ...); + +/* A general purpose syntax error. */ +#define gfc_syntax_error(ST) \ + gfc_error ("Syntax error in %s statement at %C", gfc_ascii_statement (ST)); + +void gfc_push_error (gfc_error_buf *); +void gfc_pop_error (gfc_error_buf *); + +void gfc_status (const char *, ...) ATTRIBUTE_PRINTF_1; +void gfc_status_char (char); + +void gfc_get_errors (int *, int *); + +/* arith.c */ +void gfc_arith_init_1 (void); +void gfc_arith_done_1 (void); + +/* FIXME: These should go to symbol.c, really... */ +int gfc_default_integer_kind (void); +int gfc_default_real_kind (void); +int gfc_default_double_kind (void); +int gfc_default_character_kind (void); +int gfc_default_logical_kind (void); +int gfc_default_complex_kind (void); +int gfc_validate_kind (bt, int); +extern int gfc_index_integer_kind; + +/* symbol.c */ +void gfc_clear_new_implicit (void); +try gfc_add_new_implicit_range (int, int, gfc_typespec *); +try gfc_merge_new_implicit (void); +void gfc_set_implicit_none (void); +void gfc_set_implicit (void); + +gfc_typespec *gfc_get_default_type (gfc_symbol *, gfc_namespace *); +try gfc_set_default_type (gfc_symbol *, int, gfc_namespace *); + +void gfc_set_component_attr (gfc_component *, symbol_attribute *); +void gfc_get_component_attr (symbol_attribute *, gfc_component *); + +void gfc_set_sym_referenced (gfc_symbol * sym); + +try gfc_add_allocatable (symbol_attribute *, locus *); +try gfc_add_dimension (symbol_attribute *, locus *); +try gfc_add_external (symbol_attribute *, locus *); +try gfc_add_intrinsic (symbol_attribute *, locus *); +try gfc_add_optional (symbol_attribute *, locus *); +try gfc_add_pointer (symbol_attribute *, locus *); +try gfc_add_result (symbol_attribute *, locus *); +try gfc_add_save (symbol_attribute *, locus *); +try gfc_add_saved_common (symbol_attribute *, locus *); +try gfc_add_target (symbol_attribute *, locus *); +try gfc_add_dummy (symbol_attribute *, locus *); +try gfc_add_generic (symbol_attribute *, locus *); +try gfc_add_common (symbol_attribute *, locus *); +try gfc_add_in_common (symbol_attribute *, locus *); +try gfc_add_in_namelist (symbol_attribute *, locus *); +try gfc_add_sequence (symbol_attribute *, locus *); +try gfc_add_elemental (symbol_attribute *, locus *); +try gfc_add_pure (symbol_attribute *, locus *); +try gfc_add_recursive (symbol_attribute *, locus *); +try gfc_add_function (symbol_attribute *, locus *); +try gfc_add_subroutine (symbol_attribute *, locus *); + +try gfc_add_access (symbol_attribute *, gfc_access, locus *); +try gfc_add_flavor (symbol_attribute *, sym_flavor, locus *); +try gfc_add_entry (symbol_attribute *, locus *); +try gfc_add_procedure (symbol_attribute *, procedure_type, locus *); +try gfc_add_intent (symbol_attribute *, sym_intent, locus *); +try gfc_add_explicit_interface (gfc_symbol *, ifsrc, + gfc_formal_arglist *, locus *); +try gfc_add_type (gfc_symbol *, gfc_typespec *, locus *); + +void gfc_clear_attr (symbol_attribute *); +try gfc_missing_attr (symbol_attribute *, locus *); +try gfc_copy_attr (symbol_attribute *, symbol_attribute *, locus *); + +try gfc_add_component (gfc_symbol *, const char *, gfc_component **); +gfc_symbol *gfc_use_derived (gfc_symbol *); +gfc_symtree *gfc_use_derived_tree (gfc_symtree *); +gfc_component *gfc_find_component (gfc_symbol *, const char *); + +gfc_st_label *gfc_get_st_label (int); +void gfc_free_st_label (gfc_st_label *); +void gfc_define_st_label (gfc_st_label *, gfc_sl_type, locus *); +try gfc_reference_st_label (gfc_st_label *, gfc_sl_type); + +gfc_namespace *gfc_get_namespace (gfc_namespace *); +gfc_symtree *gfc_new_symtree (gfc_symtree **, const char *); +gfc_symtree *gfc_find_symtree (gfc_symtree *, const char *); +gfc_user_op *gfc_get_uop (const char *); +gfc_user_op *gfc_find_uop (const char *, gfc_namespace *); +void gfc_free_symbol (gfc_symbol *); +gfc_symbol *gfc_new_symbol (const char *, gfc_namespace *); +int gfc_find_symbol (const char *, gfc_namespace *, int, gfc_symbol **); +int gfc_find_sym_tree (const char *, gfc_namespace *, int, gfc_symtree **); +int gfc_get_symbol (const char *, gfc_namespace *, gfc_symbol **); +int gfc_get_sym_tree (const char *, gfc_namespace *, gfc_symtree **); +int gfc_get_ha_symbol (const char *, gfc_symbol **); +int gfc_get_ha_sym_tree (const char *, gfc_symtree **); + +int gfc_symbols_could_alias (gfc_symbol *, gfc_symbol *); + +void gfc_undo_symbols (void); +void gfc_commit_symbols (void); +void gfc_free_namespace (gfc_namespace *); + +void gfc_symbol_init_2 (void); +void gfc_symbol_done_2 (void); + +void gfc_traverse_symtree (gfc_namespace *, void (*)(gfc_symtree *)); +void gfc_traverse_ns (gfc_namespace *, void (*)(gfc_symbol *)); +void gfc_traverse_user_op (gfc_namespace *, void (*)(gfc_user_op *)); +void gfc_save_all (gfc_namespace *); + +void gfc_symbol_state (void); + +/* intrinsic.c */ +extern int gfc_init_expr; + +/* Given a symbol that we have decided is intrinsic, mark it as such + by placing it into a special module that is otherwise impossible to + read or write. */ + +#define gfc_intrinsic_symbol(SYM) strcpy (SYM->module, "(intrinsic)") + +void gfc_intrinsic_init_1 (void); +void gfc_intrinsic_done_1 (void); + +char gfc_type_letter (bt); +gfc_symbol * gfc_get_intrinsic_sub_symbol (const char *); +try gfc_convert_type (gfc_expr *, gfc_typespec *, int); +try gfc_convert_type_warn (gfc_expr *, gfc_typespec *, int, int); +int gfc_generic_intrinsic (const char *); +int gfc_specific_intrinsic (const char *); +int gfc_intrinsic_name (const char *, int); +gfc_intrinsic_sym *gfc_find_function (const char *); + +match gfc_intrinsic_func_interface (gfc_expr *, int); +match gfc_intrinsic_sub_interface (gfc_code *, int); + +/* simplify.c */ +void gfc_simplify_init_1 (void); +void gfc_simplify_done_1 (void); + +/* match.c -- FIXME */ +void gfc_free_iterator (gfc_iterator *, int); +void gfc_free_forall_iterator (gfc_forall_iterator *); +void gfc_free_alloc_list (gfc_alloc *); +void gfc_free_namelist (gfc_namelist *); +void gfc_free_equiv (gfc_equiv *); +void gfc_free_data (gfc_data *); +void gfc_free_case_list (gfc_case *); + +/* expr.c */ +void gfc_free_actual_arglist (gfc_actual_arglist *); +gfc_actual_arglist *gfc_copy_actual_arglist (gfc_actual_arglist *); +const char *gfc_extract_int (gfc_expr *, int *); + +gfc_expr *gfc_build_conversion (gfc_expr *); +void gfc_free_ref_list (gfc_ref *); +void gfc_type_convert_binary (gfc_expr *); +int gfc_is_constant_expr (gfc_expr *); +try gfc_simplify_expr (gfc_expr *, int); + +gfc_expr *gfc_get_expr (void); +void gfc_free_expr (gfc_expr *); +void gfc_replace_expr (gfc_expr *, gfc_expr *); +gfc_expr *gfc_int_expr (int); +gfc_expr *gfc_logical_expr (int, locus *); +mpz_t *gfc_copy_shape (mpz_t *, int); +gfc_expr *gfc_copy_expr (gfc_expr *); + +try gfc_specification_expr (gfc_expr *); + +int gfc_numeric_ts (gfc_typespec *); +int gfc_kind_max (gfc_expr *, gfc_expr *); + +try gfc_check_conformance (const char *, gfc_expr *, gfc_expr *); +try gfc_check_assign (gfc_expr *, gfc_expr *, int); +try gfc_check_pointer_assign (gfc_expr *, gfc_expr *); +try gfc_check_assign_symbol (gfc_symbol *, gfc_expr *); + +/* st.c */ +extern gfc_code new_st; + +void gfc_clear_new_st (void); +gfc_code *gfc_get_code (void); +gfc_code *gfc_append_code (gfc_code *, gfc_code *); +void gfc_free_statement (gfc_code *); +void gfc_free_statements (gfc_code *); + +/* resolve.c */ +try gfc_resolve_expr (gfc_expr *); +void gfc_resolve (gfc_namespace *); +int gfc_impure_variable (gfc_symbol *); +int gfc_pure (gfc_symbol *); +int gfc_elemental (gfc_symbol *); +try gfc_resolve_iterator (gfc_iterator *); +try gfc_resolve_index (gfc_expr *, int); + +/* array.c */ +void gfc_free_array_spec (gfc_array_spec *); +gfc_array_ref *gfc_copy_array_ref (gfc_array_ref *); + +try gfc_set_array_spec (gfc_symbol *, gfc_array_spec *, locus *); +gfc_array_spec *gfc_copy_array_spec (gfc_array_spec *); +try gfc_resolve_array_spec (gfc_array_spec *, int); + +int gfc_compare_array_spec (gfc_array_spec *, gfc_array_spec *); + +gfc_expr *gfc_start_constructor (bt, int, locus *); +void gfc_append_constructor (gfc_expr *, gfc_expr *); +void gfc_free_constructor (gfc_constructor *); +void gfc_simplify_iterator_var (gfc_expr *); +try gfc_expand_constructor (gfc_expr *); +int gfc_constant_ac (gfc_expr *); +int gfc_expanded_ac (gfc_expr *); +try gfc_resolve_array_constructor (gfc_expr *); +try gfc_check_constructor_type (gfc_expr *); +try gfc_check_iter_variable (gfc_expr *); +try gfc_check_constructor (gfc_expr *, try (*)(gfc_expr *)); +gfc_constructor *gfc_copy_constructor (gfc_constructor * src); +gfc_expr *gfc_get_array_element (gfc_expr *, int); +try gfc_array_size (gfc_expr *, mpz_t *); +try gfc_array_dimen_size (gfc_expr *, int, mpz_t *); +try gfc_array_ref_shape (gfc_array_ref *, mpz_t *); +gfc_array_ref *gfc_find_array_ref (gfc_expr *); +void gfc_insert_constructor (gfc_expr *, gfc_constructor *); +gfc_constructor *gfc_get_constructor (void); +tree gfc_conv_array_initializer (tree type, gfc_expr * expr); +try spec_size (gfc_array_spec *, mpz_t *); + +/* interface.c -- FIXME: some of these should be in symbol.c */ +void gfc_free_interface (gfc_interface *); +int gfc_compare_types (gfc_typespec *, gfc_typespec *); +void gfc_check_interfaces (gfc_namespace *); +void gfc_procedure_use (gfc_symbol *, gfc_actual_arglist **, locus *); +gfc_symbol *gfc_search_interface (gfc_interface *, int, + gfc_actual_arglist **); +try gfc_extend_expr (gfc_expr *); +void gfc_free_formal_arglist (gfc_formal_arglist *); +try gfc_extend_assign (gfc_code *, gfc_namespace *); +try gfc_add_interface (gfc_symbol * sym); + +/* io.c */ +extern gfc_st_label format_asterisk; + +void gfc_free_open (gfc_open *); +try gfc_resolve_open (gfc_open *); +void gfc_free_close (gfc_close *); +try gfc_resolve_close (gfc_close *); +void gfc_free_filepos (gfc_filepos *); +try gfc_resolve_filepos (gfc_filepos *); +void gfc_free_inquire (gfc_inquire *); +try gfc_resolve_inquire (gfc_inquire *); +void gfc_free_dt (gfc_dt *); +try gfc_resolve_dt (gfc_dt *); + +/* module.c */ +void gfc_module_init_2 (void); +void gfc_module_done_2 (void); +void gfc_dump_module (const char *, int); + +/* primary.c */ +symbol_attribute gfc_variable_attr (gfc_expr *, gfc_typespec *); +symbol_attribute gfc_expr_attr (gfc_expr *); + +/* trans.c */ +void gfc_generate_code (gfc_namespace *); +void gfc_generate_module_code (gfc_namespace *); + +/* bbt.c */ +typedef int (*compare_fn) (void *, void *); +void gfc_insert_bbt (void *, void *, compare_fn); +void gfc_delete_bbt (void *, void *, compare_fn); + +/* dump-parse-tree.c */ +void gfc_show_namespace (gfc_namespace *); + +/* parse.c */ +try gfc_parse_file (void); + +#endif /* GFC_GFC_H */ diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi new file mode 100644 index 00000000000..9b6477e8e4b --- /dev/null +++ b/gcc/fortran/gfortran.texi @@ -0,0 +1,829 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename gfortran.info +@set last-update March 10, 2004 +@set copyrights-gfortran 1999-2004 +@set version-gfortran 0.235 + +@include gcc-common.texi + +@c This indicates that this documentation is still under development. +@c For example, if this option is set, overfull boxes are marked with +@c an ugly black square. +set DEVELOPMENT + +@settitle The GNU Fortran 95 Compiler + +@c Create a separate index for command line options +@defcodeindex op +@c Merge the standard indexes into a single one. +@syncodeindex fn cp +@syncodeindex vr cp +@syncodeindex ky cp +@syncodeindex pg cp +@syncodeindex tp cp + +@c %**end of header + +@c Use with @@smallbook. + +@c %** start of document + +@c Cause even numbered pages to be printed on the left hand side of +@c the page and odd numbered pages to be printed on the right hand +@c side of the page. Using this, you can print on both sides of a +@c sheet of paper and have the text on the same part of the sheet. + +@c The text on right hand pages is pushed towards the right hand +@c margin and the text on left hand pages is pushed toward the left +@c hand margin. +@c (To provide the reverse effect, set bindingoffset to -0.75in.) + +@c @tex +@c \global\bindingoffset=0.75in +@c \global\normaloffset =0.75in +@c @end tex + +@copying +Copyright @copyright{} @value{copyrights-gfortran} Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``GNU General Public License'' and ``Funding +Free Software'', the Front-Cover +texts being (a) (see below), and with the Back-Cover Texts being (b) +(see below). A copy of the license is included in the section entitled +``GNU Free Documentation License''. + +(a) The FSF's Front-Cover Text is: + + A GNU Manual + +(b) The FSF's Back-Cover Text is: + + You have freedom to copy and modify this GNU Manual, like GNU + software. Copies published by the Free Software Foundation raise + funds for GNU development. +@end copying + +@ifinfo +@dircategory Programming +@direntry +* gfortran: (gfortran). The GNU Fortran 95 Compiler. +@end direntry +This file documents the use and the internals of +the GNU Fortran 95 compiler, (@command{gfortran}). + +Published by the Free Software Foundation +59 Temple Place - Suite 330 +Boston, MA 02111-1307 USA + +@insertcopying +@end ifinfo + +Contributed by Steven Bosscher (@email{s.bosscher@@gcc.gnu.org}). + +@setchapternewpage odd +@titlepage +@title Using GNU Fortran 95 +@sp 2 +@center Steven Bosscher +@sp 3 +@center Last updated @value{last-update} +@sp 1 +@center for version @value {version-gfortran} +@page +@vskip 0pt plus 1filll +For the @value{version-gfortran} Version* +@sp 1 +Published by the Free Software Foundation @* +59 Temple Place - Suite 330@* +Boston, MA 02111-1307, USA@* +@c Last printed ??ber, 19??.@* +@c Printed copies are available for $? each.@* +@c ISBN ??? +@sp 1 +@insertcopying +@end titlepage +@summarycontents +@contents +@page + +@node Top, Copying,, (DIR) +@top Introduction +@cindex Introduction + +This manual documents the use of @command{gfortran}, +the GNU Fortran 95 compiler. You can find in this manual how to invoke +@command{gfortran}, as well as its features and incompatibilities, +and how to report bugs. + +@ifset DEVELOPMENT +@emph{Warning:} This document, and the compiler it describes, are still +under development. While efforts are made too keep it up-to-date it might +not accurately reflect the status of the most recent @command{gfortran}. +@end ifset + +@menu +* Copying:: GNU General Public License says + how you can copy and share GNU Fortran. +* GNU Free Documentation License:: + How you can copy and share this manual. +* Funding:: How to help assure continued work for free software. +* Getting Started:: What you should know about @command{gfortran}. +* GFORTRAN and GCC:: You can compile Fortran, C, or other programs. +* GFORTRAN and G77:: Why we choose to start from scratch. +* Invoking GFORTRAN:: Command options supported by @command{gfortran}. +* Compiling and Testing:: + Need-to-knows about compiling and testing. +* Project Status:: Status of GFORTRAN, Roadmap, proposed extensions. +* Contributing:: Helping you can help. +* Standards:: Standards supported by GFORTRAN. +* Index:: Index of this documentation. +@end menu + + + +@c --------------------------------------------------------------------- +@c GNU General Public License +@c --------------------------------------------------------------------- + +@include gpl.texi + + + +@c --------------------------------------------------------------------- +@c GNU Free Documentation License +@c --------------------------------------------------------------------- + +@include fdl.texi + + + +@c --------------------------------------------------------------------- +@c Funding Free Software +@c --------------------------------------------------------------------- + +@include funding.texi + + + +@c --------------------------------------------------------------------- +@c Getting Started +@c --------------------------------------------------------------------- + +@node Getting Started +@chapter Getting Started + +Gfortran is the GNU Fortran 95 compiler front end, +designed initially as a free replacement for, +or alternative to, the unix @command{f95} command; +@command{gfortran} is command you'll use to invoke the compiler. + +Gfortran is still in an early state of development. +@command{gfortran} can generate code for most constructs and expressions, +but much work remains to be done. + +When @command{gfortran} is finished, +it will do everything you expect from any decent compiler: + +@itemize @bullet +@item +Read a user's program, +stored in a file and containing instructions written +in Fortran 77, Fortran 90 or Fortran 95. +This file contains @dfn{source code}. + +@item +Translate the user's program into instructions a computer +can carry out more quickly than it takes to translate the +instructions in the first +place. The result after compilation of a program is +@dfn{machine code}, +code designed to be efficiently translated and processed +by a machine such as your computer. +Humans usually aren't as good writing machine code +as they are at writing Fortran (or C++, Ada, or Java), +because is easy to make tiny mistakes writing machine code. + +@item +Provide the user with information about the reasons why +the compiler is unable to create a binary from the source code. +Usually this will be the case if the source code is flawed. +When writing Fortran, it is easy to make big mistakes. +The Fortran 90 requires that the compiler can point out +mistakes to the user. +An incorrect usage of the language causes an @dfn{error message}. + +The compiler will also attempt to diagnose cases where the +user's program contains a correct usage of the language, +but instructs the computer to do something questionable. +This kind of diagnostics message is called a @dfn{warning message}. + +@item +Provide optional information about the translation passes +from the source code to machine code. +This can help a user of the compiler to find the cause of +certain bugs which may not be obvious in the source code, +but may be more easily found at a lower level compiler output. +It also helps developers to find bugs in the compiler itself. + +@item +Provide information in the generated machine code that can +make it easier to find bugs in the program (using a debugging tool, +called a @dfn{debugger}, such as the GNU Debugger @command{gdb}). + +@item +Locate and gather machine code already generated to +perform actions requested by statements in the user's program. +This machine code is organized into @dfn{modules} and is located +and @dfn{linked} to the user program. +@end itemize + +Gfortran consists of several components: + +@itemize @bullet +@item +A version of the @command{gcc} command +(which also might be installed as the system's @command{cc} command) +that also understands and accepts Fortran source code. +The @command{gcc} command is the @dfn{driver} program for +all the languages in the GNU Compiler Collection (GCC); +With @command{gcc}, +you can compiler the source code of any language for +which a front end is available in GCC. + +@item +The @command{gfortran} command itself, +which also might be installed as the +system's @command{f95} command. +@command{gfortran} is just another driver program, +but specifically for the Fortran 95 compiler only. +The difference with @command{gcc} is that @command{gfortran} +will automatically link the correct libraries to your program. + +@item +A collection of run-time libraries. +These libraries contains the machine code needed to support +capabilities of the Fortran language that are not directly +provided by the machine code generated by the +@command{gfortran} compilation phase, +such as intrinsic functions and subroutines, +and routines for interaction with files and the operating system. +@c and mechanisms to spawn, +@c unleash and pause threads in parallelized code. + +@item +The Fortran compiler itself, (@command{f951}). +This is the gfortran parser and code generator, +linked to and interfaced with the GCC backend library. +@command{f951} ``translates'' the source code to +assembler code. You would typically not use this +program directly; +instead, the @command{gcc} or @command{gfortran} driver +programs will call it for you. +@end itemize + + + +@c --------------------------------------------------------------------- +@c GFORTRAN and GCC +@c --------------------------------------------------------------------- + +@node GFORTRAN and GCC +@chapter GFORTRAN and GCC +@cindex GNU Compiler Collection + +GCC used to be the GNU ``C'' Compiler, +but is now known as the @dfn{GNU Compiler Collection}. +GCC provides the GNU system with a very versatile +compiler middle end (shared optimization passes), +and with back ends (code generators) for many different +computer architectures and operating systems. +The code of the middle end and back end are shared by all +compiler front ends that are in the GNU Compiler Collection. + +A GCC front end is essentially a source code parser +and a pass to generate a representation of the semantics +of the program in the source code in the GCC language +independent intermediate language, +called @dfn{GENERIC}. + +The parser takes a source file written in a +particular computer language, reads and parses it, +and tries to make sure that the source code conforms to +the language rules. +Once the correctness of a program has been established, +the compiler will build a data structure known as the +@dfn{Abstract Syntax tree}, +or just @dfn{AST} or ``tree'' for short. +This data structure represents the whole program +or a subroutine or a function. +The ``tree'' is passed to the GCC middle end, +which will perform optimization passes on it, +pass the optimized AST and generate assembly +for the program unit. + +Different phases in this translation process can be, +and in fact @emph{are} merged in many compiler front ends. +GNU Fortran 95 has a strict separation between the +parser and code generator. + +The goal of the gfortran project is to build a new front end for GCC: +A Fortran 95 front end. +In a non-gfortran installation, +@command{gcc} will not be able to compile Fortran 95 source code +(only the ``C'' front end has to be compiled if you want to build GCC, +all other languages are optional). +If you build GCC with gfortran, @command{gcc} will recognize +@file{.f/.f90/.f95} source files and accepts Fortran 95 specific +command line options. + + + +@c --------------------------------------------------------------------- +@c GFORTRAN and G77 +@c --------------------------------------------------------------------- + +@node GFORTRAN and G77 +@chapter GFORTRAN and G77 +@cindex Fortran 77 +@cindex G77 + +Why do we write a compiler front end from scratch? +There's a fine Fortran 77 compiler in the +GNU Compiler Collection that accepts some features +of the Fortran 90 standard as extensions. +Why not start from there and revamp it? + +One of the reasons is that Craig Burley, the author of G77, +has decided to stop working on the G77 front end. +On @uref{http://world.std.com/~burley/g77-why.html, +Craig explains the reasons for his decision to stop working on G77} +in one of the pages in his homepage. +Among the reasons is a lack of interest in improvements to +@command{g77}. +Users appear to be quite satisfied with @command{g77} as it is. +While @command{g77} is still being maintained (by Toon Moene), +it is unlikely that sufficient people will be willing +to completely rewrite the existing code. + +But there are other reasons to start from scratch. +Many people, including Craig Burley, +no longer agreed with certain design decisions in the G77 front end. +Also, the interface of @command{g77} to the back end is written in +a style which is confusing and not up to date on recommended practice. +In fact, a full rewrite had already been planned for GCC 3.0. + +When Craig decided to stop, +it just seemed to be a better idea to start a new project from scratch, +because it was expected to be easier to maintain code we +develop ourselves than to do a major overhaul of @command{g77} first, +and then build a Fortran 95 compiler out of it. + + +@include invoke.texi + +@c --------------------------------------------------------------------- +@c Compiling and Testing +@c --------------------------------------------------------------------- + +@node Compiling and Testing +@chapter Compiling and Testing + +@command{gfortran} is not yet part of an official GCC release, so it is +unlikley that OS distributor will provide it. + +@menu +* Precompiled Binaries:: +* General notes about compiling GFORTRAN:: +* Compiling GFORTRAN:: +* Testing:: +@end menu + +@node Precompiled Binaries +@section Precompiled Binaries + +Precompiled binaries for i686-pc-linux-gnu in rpm format are available from +@uref{http://people.redhat.com/dnovillo/pub/tree-ssa/snapshot/} + +@node General notes about compiling GFORTRAN +@section General notes about compiling GFORTRAN +@cindex GMP +@cindex Multiple Precision Library + +Compiling gfortran requires the presence of GMP, +the GNU Multiple Precision library version 4.0 +or better in order to do its arithmetic. +Download @code{gmp} from your favorite GNU mirror, +configure and compile it. If your OS distributor provides prepackaged +GMP libraries, you may also need the developent pacakges. + +If you do not have GMP installed in a standard system location, you may +need to configure GCC with @option{--with-gmp} or @option{--with-gmp-dir}. + +Note: GMP is only required for the compiler itself. Compiled fortran programs +do not depend on the GMP library. + +@node Compiling GFORTRAN +@section Compiling GFORTRAN +@cindex Make-lang.in + +To build gfortran, you first need to get a copy of the GCC source tree. +gfortran uses the new @dfn{GENERIC} intermediate representation +to communicate with the back end. +This new IR has not been merged yet with the GCC mainline, +so you'll need to get a snapshot of the +@emph{tree-ssa-20020619-branch} from the GCC CVS repository. +This branch also contains the latest version +You can check out this branch from the GNU Subversions server: + +@example +$ export CVS_RSH=ssh +$ cvs -z9 -d :ext:anoncvs@@subversions.gnu.org:/cvsroot/gcc co -r tree-ssa-20020619-branch gcc +@end example + +You can now build GCC following the instructions on the +@uref{htpp://gcc.gnu.org/,GCC homepage}, +(configure with @option{--enable-languages=f95}). + + +@node Testing +@section Testing +@cindex Test suite +@cindex Testing + +The number of possible Fortran 95 programs is unlimited, +and this means that gfortran has to correctly handle lots of possible inputs. +Whenever you make any changes to the compiler, +you should first test your change on a test program, +then test your change against the gfortran test suite. +In this way, we can be assured that once your fix has been made, +the problem isn't re-introduced at some later time. + +The gfortran test suite is included in the gcc source distribution. + +We also encourage you to test gfortran on your own Fortran codes. + +@c --------------------------------------------------------------------- +@c Project Status +@c --------------------------------------------------------------------- + +@node Project Status +@chapter Project Status + +@quotation +As soon as gfortran can parse all of the statements correctly, +it will be in the ``larva'' state. +When we generate code, the ``puppa'' state. +When gfortran is done, +we'll see if it will be a beautiful butterfly, +or just a big bug.... + +--Andy Vaught, April 2000 +@end quotation + +The start of the GNU Fortran 95 project was announced on +the GCC homepage in March 18, 2000 +(even though Andy had already been working on it for a while, +or course). + +Gfortran is currently reaching the stage where is is able to compile real +world programs. However it is still under development and has many rough +edges. + +@menu +* Compiler Status:: +* Library Status:: +* Proposed Extensions:: +@end menu + +@node Compiler Status +@section Compiler Status + +@itemize @emph +@item Front end +This is the part of gfortran which parses a source file, verifies that it +is valid Fortran 95, performs compile time replacement of constants +(PARAMETER variables) and reads and generate module files. This is +almost complete. Every Fortran 95 source should be accepted, and most +none-Fortran 95 source should be rejected. If you find a source file where +this is not true, please tell us. You can use the -fsyntax-only switch to +make gfortran quit after running the front end, effectively reducing it to +a syntax checker. + +@item Middle end interface +These are the parts of gfortran that take the parse tree generated by the +front end and translate it to the GENERIC form required by the GCC back +end. Work is ongoing in these parts of gfortran, but a large part has +already been completed. +@end itemize + +@node Library Status +@section Library Status + +Some intrinsic functions map directly to library functions, and in most +cases the name of the library function used depends on the type of the +arguments. For some intrinsics we generate inline code, and for others, +such as sin, cos and sqrt, we rely on the backend to use special +instructions in the floating point unit of the CPU if available, or to +fall back to a call to libm if these are not available. + +Implementation of some non-elemental intrinsic functions (eg. DOT_PRODUCT, +AVERAGE) is not yet optimal. This is hard because we have to make decisions +whether to use inline code (good for small arrays as no function call +overhead occurs) or generate function calls (good for large arrays as it +allows use of hand-optimized assembly routines, SIMD instructions, etc.) + +The IO library is still under development. The following features should be +usable for real programs: + +@itemize @minus +@item List directed +@item Unformatted sequential +@end itemize + +Usable with bugs: + +@itemize @minus +@item Formatted sequential ('T' edit descriptor, and others) +@item Namelist (can read a namelist that it writes, but not free-form) +@end itemize + +Not recommended: + +@itemize @minus +@item Unformatted direct access +@item Formatted direct access +@end itemize + +Many Fortran programs only use a small subset of the available IO +capabilities, so your milage may vary. + +@node Proposed Extensions +@section Proposed Extensions + +Here's a list of proposed extensions for @command{gfortran}, in no particular +order. Most of these are necessary to be fully compatible with +existing Fortran compilers, but they are not part of the official +J3 Fortran 95 standard. + +@subsection Compiler extensions: +@itemize @bullet +@item +Flag for defining the kind number for default logicals. + +@item +User-specified alignment rules for structures. +@item +Flag to generate a @code{Makefile} info. + +@item +Automatically extend single precision constants to double. + +@item +Cray pointers (this was high on the @command{g77} wishlist). + +@item +Compile code that conserves memory by dynamically allocating common and +module storage either on stack or heap. + +@item +Flag to cause the compiler to distinguish between upper and lower case +names. The Fortran 95 standard does not distinguish them. + +@item +Compile switch for changing the interpretation of a backslash from a +character to ``C''-style escape characters. + +@item +Compile flag to generate code for array conformance checking (suggest -CC). + +@item +User control of symbol names (underscores, etc). + +@item +Compile setting for maximum size of stack frame size before spilling +parts to static or heap. + +@item +Flag to force local variables into static space. + +@item +Flag to force local variables onto stack. + +@item +Flag to compile lines beginning with ``D''. + +@item +Flag to ignore lines beginning with ``D''. + +@item +Flag for maximum errors before ending compile. + +@item +Generate code to check for null pointer dereferences -- prints locus of +dereference instead of segfaulting. There was some discussion about this +option in the g95 development mailing list. + +@item +Allow setting default unit number. + +@item +Option to initialize of otherwise uninitialized integer and floating +point variables. + +@item +Support for OpenMP directives. This also requires support from the runtime +library and the rest of the compiler. + +@item +Support for Fortran 200x. This includes several new features including +floating point exceptions, extended use of allocatable arrays, C +interoperability, Parameterizer data types and function pointers. +@end itemize + + +@subsection Environment Options +@itemize @bullet +@item +Pluggable library modules for random numbers, linear algebra. +LA should use BLAS calling conventions. + +@item +Environment variables controlling actions on arithmetic exceptions like +overflow, underflow, precision loss -- Generate NaN, abort, default. +action. + +@item +Set precision for fp units that support it (i387). + +@item +Variables for setting fp rounding mode. + +@item +Support old style namelists ending in $end or &end. + +@item +Variable to fill uninitialized variables with a user-defined bit +pattern. + +@item +Environment variable controlling filename that is opened for that unit +number. + +@item +Environment variable to clear/trash memory being freed. + +@item +Environment variable to control tracing of allocations and frees. + +@item +Environment variable to display allocated memory at normal program end. + +@item +Environment variable for filename for * IO-unit. + +@item +Environment variable for temporary file directory. + +@item +Environment variable forcing standard output to be line buffered (unix). + +@item +Variable for swapping endianness during unformatted read. + +@item +Variable for swapping Endianness during unformatted write. +@end itemize + + + +@c --------------------------------------------------------------------- +@c Contributing +@c --------------------------------------------------------------------- + +@node Contributing +@chapter Contributing +@cindex Contributing + +Free software is only possible if people contribute to efforts +to create it. +We're always in need of more people helping out with ideas +and comments, writing documentation and contributing code. + +If you want to contribute to GNU Fortran 95, +have a look at the long lists of projects you can take on. +Some of these projects are small, +some of them are large; +some are completely orthogonal to the rest of what is +happening on @command{gfortran}, +but others are ``mainstream'' projects in need of enthusiastic hackers. +All of these projects are important! +We'll eventually get around to the things here, +but they are also things doable by someone who is willing and able. + +@menu +* Contributors:: +* Projects:: +@end menu + + +@node Contributors +@section Contributors to GNU Fortran 95 +@cindex Contributors +@cindex Credits +@cindex Authors + +Most of the parser was hand-crafted by @emph{Andy Vaught}, who is +also the initiator of the whole project. Thanks Andy! +Most of the interface with GCC was written by @emph{Paul Brook}. + +The following individuals have contributed code and/or +ideas and significant help to the gfortran project +(in no particular order): + +@itemize @minus +@item Andy Vaught +@item Katherine Holcomb +@item Tobias Schlüter +@item Steven Bosscher +@item Toon Moene +@item Tim Prince +@item Niels Kristian Bech Jensen +@item Steven Johnson +@item Paul Brook +@item Feng Wang +@item Bud Davis +@end itemize + +The following people have contributed bug reports, +smaller or larger patches, +and much needed feedback and encouragement for the +@command{gfortran} project: + +@itemize @minus +@item Erik Schnetter +@item Bill Clodius +@item Kate Hedstrom +@end itemize + +Many other individuals have helped debug, +test and improve @command{gfortran} over the past two years, +and we welcome you to do the same! +If you already have done so, +and you would like to see your name listed in the +list above, please contact us. + + +@node Projects +@section Projects + +@table @emph + +@item Help build the test suite +Solicit more code for donation to the test suite. +We can keep code private on request. + +@item Bug hunting/squishing +Find bugs and write more test cases! +Test cases are especially very welcome, +because it allows us to concentrate on fixing bugs +instead of isolating them. + +@item Smaller projects (``bug'' fixes): + @itemize @minus + @item Allow init exprs to be numbers raised to integer powers. + @item Implement correct rounding. + @item Implement F restrictions on Fortran 95 syntax. + @item See about making Emacs-parsable error messages. + @end itemize +@end table + +If you wish to work on the runtime libraries, +please contact a project maintainer. +@c TODO: email! + + +@c --------------------------------------------------------------------- +@c Standards +@c --------------------------------------------------------------------- + +@node Standards +@chapter Standards +@cindex Standards + +The GNU Fortran 95 Compiler aims to be a conforming implementation of +ISO/IEC 1539:1997 (Fortran 95). + +In the future it may also support other variants and extensions to the Fortran +language. This includes ANSI Fortran 77, Fortran 90, Fortran 2000 (not yet +finalized), and OpenMP. + +@node Index +@unnumbered Index + +@printindex cp + +@bye diff --git a/gcc/fortran/gfortranspec.c b/gcc/fortran/gfortranspec.c new file mode 100644 index 00000000000..bbf9fa372eb --- /dev/null +++ b/gcc/fortran/gfortranspec.c @@ -0,0 +1,548 @@ +/* Specific flags and argument handling of the Fortran front-end. + Copyright (C) 1997, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +/* This file is copied more or less verbatim from g77. */ +/* This file contains a filter for the main `gcc' driver, which is + replicated for the `gfortran' driver by adding this filter. The purpose + of this filter is to be basically identical to gcc (in that + it faithfully passes all of the original arguments to gcc) but, + unless explicitly overridden by the user in certain ways, ensure + that the needs of the language supported by this wrapper are met. + + For GNU Fortran 95(gfortran), we do the following to the argument list + before passing it to `gcc': + + 1. Make sure `-lgfortran -lm' is at the end of the list. + + 2. Make sure each time `-lgfortran' or `-lm' is seen, it forms + part of the series `-lgfortran -lm'. + + #1 and #2 are not done if `-nostdlib' or any option that disables + the linking phase is present, or if `-xfoo' is in effect. Note that + a lack of source files or -l options disables linking. + + This program was originally made out of gcc/cp/g++spec.c, but the + way it builds the new argument list was rewritten so it is much + easier to maintain, improve the way it decides to add or not add + extra arguments, etc. And several improvements were made in the + handling of arguments, primarily to make it more consistent with + `gcc' itself. */ + +#include "config.h" +#include "system.h" +#include "gcc.h" + +#include "coretypes.h" +#include "tm.h" + +#ifndef MATH_LIBRARY +#define MATH_LIBRARY "-lm" +#endif + +#ifndef FORTRAN_INIT +#define FORTRAN_INIT "-lgfortranbegin" +#endif + +#ifndef FORTRAN_LIBRARY +#define FORTRAN_LIBRARY "-lgfortran" +#endif + +/* Options this driver needs to recognize, not just know how to + skip over. */ +typedef enum +{ + OPTION_b, /* Aka --prefix. */ + OPTION_B, /* Aka --target. */ + OPTION_c, /* Aka --compile. */ + OPTION_E, /* Aka --preprocess. */ + OPTION_help, /* --help. */ + OPTION_i, /* -imacros, -include, -include-*. */ + OPTION_l, + OPTION_L, /* Aka --library-directory. */ + OPTION_nostdlib, /* Aka --no-standard-libraries, or + -nodefaultlibs. */ + OPTION_o, /* Aka --output. */ + OPTION_S, /* Aka --assemble. */ + OPTION_syntax_only, /* -fsyntax-only. */ + OPTION_v, /* Aka --verbose. */ + OPTION_version, /* --version. */ + OPTION_V, /* Aka --use-version. */ + OPTION_x, /* Aka --language. */ + OPTION_ /* Unrecognized or unimportant. */ +} +Option; + +/* The original argument list and related info is copied here. */ +static int g77_xargc; +static const char *const *g77_xargv; +static void lookup_option (Option *, int *, const char **, const char *); +static void append_arg (const char *); + +/* The new argument list will be built here. */ +static int g77_newargc; +static const char **g77_newargv; + +const struct spec_function lang_specific_spec_functions[] = {{0,0}}; + +/* --- This comes from gcc.c (2.8.1) verbatim: */ + +/* This defines which switch letters take arguments. */ + +#ifndef SWITCH_TAKES_ARG +#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR) +#endif + +/* This defines which multi-letter switches take arguments. */ + +#ifndef WORD_SWITCH_TAKES_ARG +#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR) +#endif + +/* --- End of verbatim. */ + +/* Assumes text[0] == '-'. Returns number of argv items that belong to + (and follow) this one, an option id for options important to the + caller, and a pointer to the first char of the arg, if embedded (else + returns NULL, meaning no arg or it's the next argv). + + Note that this also assumes gcc.c's pass converting long options + to short ones, where available, has already been run. */ + +static void +lookup_option (Option *xopt, int *xskip, const char **xarg, const char *text) +{ + Option opt = OPTION_; + int skip; + const char *arg = NULL; + + if ((skip = SWITCH_TAKES_ARG (text[1]))) + skip -= (text[2] != '\0'); /* See gcc.c. */ + + if (text[1] == 'B') + opt = OPTION_B, skip = (text[2] == '\0'), arg = text + 2; + else if (text[1] == 'b') + opt = OPTION_b, skip = (text[2] == '\0'), arg = text + 2; + else if ((text[1] == 'c') && (text[2] == '\0')) + opt = OPTION_c, skip = 0; + else if ((text[1] == 'E') && (text[2] == '\0')) + opt = OPTION_E, skip = 0; + else if (text[1] == 'i') + opt = OPTION_i, skip = 0; + else if (text[1] == 'l') + opt = OPTION_l; + else if (text[1] == 'L') + opt = OPTION_L, arg = text + 2; + else if (text[1] == 'o') + opt = OPTION_o; + else if ((text[1] == 'S') && (text[2] == '\0')) + opt = OPTION_S, skip = 0; + else if (text[1] == 'V') + opt = OPTION_V, skip = (text[2] == '\0'); + else if ((text[1] == 'v') && (text[2] == '\0')) + opt = OPTION_v, skip = 0; + else if (text[1] == 'x') + opt = OPTION_x, arg = text + 2; + else + { + if ((skip = WORD_SWITCH_TAKES_ARG (text + 1)) != 0) /* See gcc.c. */ + ; + else if (!strcmp (text, "-fhelp")) /* Really --help!! */ + opt = OPTION_help; + else if (!strcmp (text, "-nostdlib") + || !strcmp (text, "-nodefaultlibs")) + opt = OPTION_nostdlib; + else if (!strcmp (text, "-fsyntax-only")) + opt = OPTION_syntax_only; + else if (!strcmp (text, "-dumpversion")) + opt = OPTION_version; + else if (!strcmp (text, "-fversion")) /* Really --version!! */ + opt = OPTION_version; + else if (!strcmp (text, "-Xlinker") || !strcmp (text, "-specs")) + skip = 1; + else + skip = 0; + } + + if (xopt != NULL) + *xopt = opt; + if (xskip != NULL) + *xskip = skip; + if (xarg != NULL) + { + if ((arg != NULL) && (arg[0] == '\0')) + *xarg = NULL; + else + *xarg = arg; + } +} + +/* Append another argument to the list being built. As long as it is + identical to the corresponding arg in the original list, just increment + the new arg count. Otherwise allocate a new list, etc. */ + +static void +append_arg (const char *arg) +{ + static int newargsize; + +#if 0 + fprintf (stderr, "`%s'\n", arg); +#endif + + if (g77_newargv == g77_xargv + && g77_newargc < g77_xargc + && (arg == g77_xargv[g77_newargc] + || !strcmp (arg, g77_xargv[g77_newargc]))) + { + ++g77_newargc; + return; /* Nothing new here. */ + } + + if (g77_newargv == g77_xargv) + { /* Make new arglist. */ + int i; + + newargsize = (g77_xargc << 2) + 20; /* This should handle all. */ + g77_newargv = (const char **) xmalloc (newargsize * sizeof (char *)); + + /* Copy what has been done so far. */ + for (i = 0; i < g77_newargc; ++i) + g77_newargv[i] = g77_xargv[i]; + } + + if (g77_newargc == newargsize) + fatal ("overflowed output arg list for `%s'", arg); + + g77_newargv[g77_newargc++] = arg; +} + +void +lang_specific_driver (int *in_argc, const char *const **in_argv, + int *in_added_libraries ATTRIBUTE_UNUSED) +{ + int argc = *in_argc; + const char *const *argv = *in_argv; + int i; + int verbose = 0; + Option opt; + int skip; + const char *arg; + + /* This will be NULL if we encounter a situation where we should not + link in libf2c. */ + const char *library = FORTRAN_LIBRARY; + + /* 0 => -xnone in effect. + 1 => -xfoo in effect. */ + int saw_speclang = 0; + + /* 0 => initial/reset state + 1 => last arg was -l + 2 => last two args were -l -lm. */ + int saw_library = 0; + + /* 0 => initial/reset state + 1 => FORTRAN_INIT linked in */ + int use_init = 0; + + /* By default, we throw on the math library if we have one. */ + int need_math = (MATH_LIBRARY[0] != '\0'); + + /* The number of input and output files in the incoming arg list. */ + int n_infiles = 0; + int n_outfiles = 0; + +#if 0 + fprintf (stderr, "Incoming:"); + for (i = 0; i < argc; i++) + fprintf (stderr, " %s", argv[i]); + fprintf (stderr, "\n"); +#endif + + g77_xargc = argc; + g77_xargv = argv; + g77_newargc = 0; + g77_newargv = (const char **) argv; + + /* First pass through arglist. + + If -nostdlib or a "turn-off-linking" option is anywhere in the + command line, don't do any library-option processing (except + relating to -x). Also, if -v is specified, but no other options + that do anything special (allowing -V version, etc.), remember + to add special stuff to make gcc command actually invoke all + the different phases of the compilation process so all the version + numbers can be seen. + + Also, here is where all problems with missing arguments to options + are caught. If this loop is exited normally, it means all options + have the appropriate number of arguments as far as the rest of this + program is concerned. */ + + for (i = 1; i < argc; ++i) + { + if ((argv[i][0] == '+') && (argv[i][1] == 'e')) + { + continue; + } + + if ((argv[i][0] != '-') || (argv[i][1] == '\0')) + { + ++n_infiles; + continue; + } + + lookup_option (&opt, &skip, NULL, argv[i]); + + switch (opt) + { + case OPTION_nostdlib: + case OPTION_c: + case OPTION_S: + case OPTION_syntax_only: + case OPTION_E: + /* These options disable linking entirely or linking of the + standard libraries. */ + library = 0; + break; + + case OPTION_l: + ++n_infiles; + break; + + case OPTION_o: + ++n_outfiles; + break; + + case OPTION_v: + verbose = 1; + break; + + case OPTION_b: + case OPTION_B: + case OPTION_L: + case OPTION_i: + case OPTION_V: + /* These options are useful in conjunction with -v to get + appropriate version info. */ + break; + + case OPTION_version: + printf ("\ +GNU Fortran 95 (GCC %s)\n\ +Copyright (C) 2003 Free Software Foundation, Inc.\n\ +\n\ +GNU Fortran comes with NO WARRANTY, to the extent permitted by law.\n\ +You may redistribute copies of GNU Fortran\n\ +under the terms of the GNU General Public License.\n\ +For more information about these matters, see the file named COPYING\n\ +", version_string); + exit (0); + break; + + case OPTION_help: + /* Let gcc.c handle this, as it has a really + cool facility for handling --help and --verbose --help. */ + return; + + default: + break; + } + + /* This is the one place we check for missing arguments in the + program. */ + + if (i + skip < argc) + i += skip; + else + fatal ("argument to `%s' missing", argv[i]); + } + + if ((n_outfiles != 0) && (n_infiles == 0)) + fatal ("no input files; unwilling to write output files"); + + /* If there are no input files, no need for the library. */ + if (n_infiles == 0) + library = 0; + + /* Second pass through arglist, transforming arguments as appropriate. */ + + append_arg (argv[0]); /* Start with command name, of course. */ + + for (i = 1; i < argc; ++i) + { + if (argv[i][0] == '\0') + { + append_arg (argv[i]); /* Interesting. Just append as is. */ + continue; + } + + if ((argv[i][0] == '-') && (argv[i][1] == 'M')) + { + char *p; + + if (argv[i][2] == '\0') + { + p = xmalloc (strlen (argv[i + 1]) + 2); + p[0] = '-'; + p[1] = 'J'; + strcpy (&p[2], argv[i + 1]); + i++; + } + else + { + p = xmalloc (strlen (argv[i]) + 1); + strcpy (p, argv[i]); + } + append_arg (p); + continue; + } + + if ((argv[i][0] == '-') && (argv[i][1] != 'l')) + { + /* Not a filename or library. */ + + if (saw_library == 1 && need_math) /* -l. */ + append_arg (MATH_LIBRARY); + + saw_library = 0; + + lookup_option (&opt, &skip, &arg, argv[i]); + + if (argv[i][1] == '\0') + { + append_arg (argv[i]); /* "-" == Standard input. */ + continue; + } + + if (opt == OPTION_x) + { + /* Track input language. */ + const char *lang; + + if (arg == NULL) + lang = argv[i + 1]; + else + lang = arg; + + saw_speclang = (strcmp (lang, "none") != 0); + } + + append_arg (argv[i]); + + for (; skip != 0; --skip) + append_arg (argv[++i]); + + continue; + } + + /* A filename/library, not an option. */ + + if (saw_speclang) + saw_library = 0; /* -xfoo currently active. */ + else + { /* -lfoo or filename. */ + if (strcmp (argv[i], MATH_LIBRARY) == 0) + { + if (saw_library == 1) + saw_library = 2; /* -l -lm. */ + else + { + if (0 == use_init) + { + append_arg (FORTRAN_INIT); + use_init = 1; + } + append_arg (FORTRAN_LIBRARY); + } + } + else if (strcmp (argv[i], FORTRAN_LIBRARY) == 0) + saw_library = 1; /* -l. */ + else + { /* Other library, or filename. */ + if (saw_library == 1 && need_math) + append_arg (MATH_LIBRARY); + saw_library = 0; + } + } + append_arg (argv[i]); + } + + /* Append `-lg2c -lm' as necessary. */ + + if (library) + { /* Doing a link and no -nostdlib. */ + if (saw_speclang) + append_arg ("-xnone"); + + switch (saw_library) + { + case 0: + if (0 == use_init) + { + append_arg (FORTRAN_INIT); + use_init = 1; + } + append_arg (library); + case 1: + if (need_math) + append_arg (MATH_LIBRARY); + default: + break; + } + } + +#ifdef ENABLE_SHARED_LIBGCC + if (library) + { + int i; + + for (i = 1; i < g77_newargc; i++) + if (g77_newargv[i][0] == '-') + if (strcmp (g77_newargv[i], "-static-libgcc") == 0 + || strcmp (g77_newargv[i], "-static") == 0) + break; + + if (i == g77_newargc) + append_arg ("-shared-libgcc"); + } + +#endif + + if (verbose && g77_newargv != g77_xargv) + { + fprintf (stderr, "Driving:"); + for (i = 0; i < g77_newargc; i++) + fprintf (stderr, " %s", g77_newargv[i]); + fprintf (stderr, "\n"); + } + + *in_argc = g77_newargc; + *in_argv = g77_newargv; +} + +/* Called before linking. Returns 0 on success and -1 on failure. */ +int +lang_specific_pre_link (void) /* Not used for F77. */ +{ + return 0; +} + +/* Number of extra output files that lang_specific_pre_link may generate. */ +int lang_specific_extra_outfiles = 0; /* Not used for F77. */ diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c new file mode 100644 index 00000000000..aa31985c7ec --- /dev/null +++ b/gcc/fortran/interface.c @@ -0,0 +1,1858 @@ +/* Deal with interfaces. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Deal with interfaces. An explicit interface is represented as a + singly linked list of formal argument structures attached to the + relevant symbols. For an implicit interface, the arguments don't + point to symbols. Explicit interfaces point to namespaces that + contain the symbols within that interface. + + Implicit interfaces are linked together in a singly linked list + along the next_if member of symbol nodes. Since a particular + symbol can only have a single explicit interface, the symbol cannot + be part of multiple lists and a single next-member suffices. + + This is not the case for general classes, though. An operator + definition is independent of just about all other uses and has it's + own head pointer. + + Nameless interfaces: + Nameless interfaces create symbols with explicit interfaces within + the current namespace. They are otherwise unlinked. + + Generic interfaces: + The generic name points to a linked list of symbols. Each symbol + has an explicit interface. Each explicit interface has it's own + namespace containing the arguments. Module procedures are symbols in + which the interface is added later when the module procedure is parsed. + + User operators: + User-defined operators are stored in a their own set of symtrees + separate from regular symbols. The symtrees point to gfc_user_op + structures which in turn head up a list of relevant interfaces. + + Extended intrinsics and assignment: + The head of these interface lists are stored in the containing namespace. + + Implicit interfaces: + An implicit interface is represented as a singly linked list of + formal argument list structures that don't point to any symbol + nodes -- they just contain types. + + + When a subprogram is defined, the program unit's name points to an + interface as usual, but the link to the namespace is NULL and the + formal argument list points to symbols within the same namespace as + the program unit name. */ + +#include "config.h" +#include +#include + +#include "gfortran.h" +#include "match.h" + + +/* The current_interface structure holds information about the + interface currently being parsed. This structure is saved and + restored during recursive interfaces. */ + +gfc_interface_info current_interface; + + +/* Free a singly linked list of gfc_interface structures. */ + +void +gfc_free_interface (gfc_interface * intr) +{ + gfc_interface *next; + + for (; intr; intr = next) + { + next = intr->next; + gfc_free (intr); + } +} + + +/* Change the operators unary plus and minus into binary plus and + minus respectively, leaving the rest unchanged. */ + +static gfc_intrinsic_op +fold_unary (gfc_intrinsic_op operator) +{ + + switch (operator) + { + case INTRINSIC_UPLUS: + operator = INTRINSIC_PLUS; + break; + case INTRINSIC_UMINUS: + operator = INTRINSIC_MINUS; + break; + default: + break; + } + + return operator; +} + + +/* Match a generic specification. Depending on which type of + interface is found, the 'name' or 'operator' pointers may be set. + This subroutine doesn't return MATCH_NO. */ + +match +gfc_match_generic_spec (interface_type * type, + char *name, + gfc_intrinsic_op *operator) +{ + char buffer[GFC_MAX_SYMBOL_LEN + 1]; + match m; + gfc_intrinsic_op i; + + if (gfc_match (" assignment ( = )") == MATCH_YES) + { + *type = INTERFACE_INTRINSIC_OP; + *operator = INTRINSIC_ASSIGN; + return MATCH_YES; + } + + if (gfc_match (" operator ( %o )", &i) == MATCH_YES) + { /* Operator i/f */ + *type = INTERFACE_INTRINSIC_OP; + *operator = fold_unary (i); + return MATCH_YES; + } + + if (gfc_match (" operator ( ") == MATCH_YES) + { + m = gfc_match_defined_op_name (buffer, 1); + if (m == MATCH_NO) + goto syntax; + if (m != MATCH_YES) + return MATCH_ERROR; + + m = gfc_match_char (')'); + if (m == MATCH_NO) + goto syntax; + if (m != MATCH_YES) + return MATCH_ERROR; + + strcpy (name, buffer); + *type = INTERFACE_USER_OP; + return MATCH_YES; + } + + if (gfc_match_name (buffer) == MATCH_YES) + { + strcpy (name, buffer); + *type = INTERFACE_GENERIC; + return MATCH_YES; + } + + *type = INTERFACE_NAMELESS; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in generic specification at %C"); + return MATCH_ERROR; +} + + +/* Match one of the five forms of an interface statement. */ + +match +gfc_match_interface (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + interface_type type; + gfc_symbol *sym; + gfc_intrinsic_op operator; + match m; + + m = gfc_match_space (); + + if (gfc_match_generic_spec (&type, name, &operator) == MATCH_ERROR) + return MATCH_ERROR; + + + /* If we're not looking at the end of the statement now, or if this + is not a nameless interface but we did not see a space, punt. */ + if (gfc_match_eos () != MATCH_YES + || (type != INTERFACE_NAMELESS + && m != MATCH_YES)) + { + gfc_error + ("Syntax error: Trailing garbage in INTERFACE statement at %C"); + return MATCH_ERROR; + } + + current_interface.type = type; + + switch (type) + { + case INTERFACE_GENERIC: + if (gfc_get_symbol (name, NULL, &sym)) + return MATCH_ERROR; + + if (!sym->attr.generic && gfc_add_generic (&sym->attr, NULL) == FAILURE) + return MATCH_ERROR; + + current_interface.sym = gfc_new_block = sym; + break; + + case INTERFACE_USER_OP: + current_interface.uop = gfc_get_uop (name); + break; + + case INTERFACE_INTRINSIC_OP: + current_interface.op = operator; + break; + + case INTERFACE_NAMELESS: + break; + } + + return MATCH_YES; +} + + +/* Match the different sort of generic-specs that can be present after + the END INTERFACE itself. */ + +match +gfc_match_end_interface (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + interface_type type; + gfc_intrinsic_op operator; + match m; + + m = gfc_match_space (); + + if (gfc_match_generic_spec (&type, name, &operator) == MATCH_ERROR) + return MATCH_ERROR; + + /* If we're not looking at the end of the statement now, or if this + is not a nameless interface but we did not see a space, punt. */ + if (gfc_match_eos () != MATCH_YES + || (type != INTERFACE_NAMELESS + && m != MATCH_YES)) + { + gfc_error + ("Syntax error: Trailing garbage in END INTERFACE statement at %C"); + return MATCH_ERROR; + } + + m = MATCH_YES; + + switch (current_interface.type) + { + case INTERFACE_NAMELESS: + if (type != current_interface.type) + { + gfc_error ("Expected a nameless interface at %C"); + m = MATCH_ERROR; + } + + break; + + case INTERFACE_INTRINSIC_OP: + if (type != current_interface.type || operator != current_interface.op) + { + + if (current_interface.op == INTRINSIC_ASSIGN) + gfc_error ("Expected 'END INTERFACE ASSIGNMENT (=)' at %C"); + else + gfc_error ("Expecting 'END INTERFACE OPERATOR (%s)' at %C", + gfc_op2string (current_interface.op)); + + m = MATCH_ERROR; + } + + break; + + case INTERFACE_USER_OP: + /* Comparing the symbol node names is OK because only use-associated + symbols can be renamed. */ + if (type != current_interface.type + || strcmp (current_interface.sym->name, name) != 0) + { + gfc_error ("Expecting 'END INTERFACE OPERATOR (.%s.)' at %C", + current_interface.sym->name); + m = MATCH_ERROR; + } + + break; + + case INTERFACE_GENERIC: + if (type != current_interface.type + || strcmp (current_interface.sym->name, name) != 0) + { + gfc_error ("Expecting 'END INTERFACE %s' at %C", + current_interface.sym->name); + m = MATCH_ERROR; + } + + break; + } + + return m; +} + + +/* Compare two typespecs, recursively if necessary. */ + +int +gfc_compare_types (gfc_typespec * ts1, gfc_typespec * ts2) +{ + gfc_component *dt1, *dt2; + + if (ts1->type != ts2->type) + return 0; + if (ts1->type != BT_DERIVED) + return (ts1->kind == ts2->kind); + + /* Compare derived types. */ + if (ts1->derived == ts2->derived) + return 1; + + /* Special case for comparing derived types across namespaces. If the + true names and module names are the same and the module name is + nonnull, then they are equal. */ + if (strcmp (ts1->derived->name, ts2->derived->name) == 0 + && ts1->derived->module[0] != '\0' + && strcmp (ts1->derived->module, ts2->derived->module) == 0) + return 1; + + /* Compare type via the rules of the standard. Both types must have + the SEQUENCE attribute to be equal. */ + + if (strcmp (ts1->derived->name, ts2->derived->name)) + return 0; + + dt1 = ts1->derived->components; + dt2 = ts2->derived->components; + + if (ts1->derived->attr.sequence == 0 || ts2->derived->attr.sequence == 0) + return 0; + + /* Since subtypes of SEQUENCE types must be SEQUENCE types as well, a + simple test can speed things up. Otherwise, lots of things have to + match. */ + for (;;) + { + if (strcmp (dt1->name, dt2->name) != 0) + return 0; + + if (dt1->pointer != dt2->pointer) + return 0; + + if (dt1->dimension != dt2->dimension) + return 0; + + if (dt1->dimension && gfc_compare_array_spec (dt1->as, dt2->as) == 0) + return 0; + + if (gfc_compare_types (&dt1->ts, &dt2->ts) == 0) + return 0; + + dt1 = dt1->next; + dt2 = dt2->next; + + if (dt1 == NULL && dt2 == NULL) + break; + if (dt1 == NULL || dt2 == NULL) + return 0; + } + + return 1; +} + + +/* Given two symbols that are formal arguments, compare their ranks + and types. Returns nonzero if they have the same rank and type, + zero otherwise. */ + +static int +compare_type_rank (gfc_symbol * s1, gfc_symbol * s2) +{ + int r1, r2; + + r1 = (s1->as != NULL) ? s1->as->rank : 0; + r2 = (s2->as != NULL) ? s2->as->rank : 0; + + if (r1 != r2) + return 0; /* Ranks differ */ + + return gfc_compare_types (&s1->ts, &s2->ts); +} + + +static int compare_interfaces (gfc_symbol *, gfc_symbol *, int); + +/* Given two symbols that are formal arguments, compare their types + and rank and their formal interfaces if they are both dummy + procedures. Returns nonzero if the same, zero if different. */ + +static int +compare_type_rank_if (gfc_symbol * s1, gfc_symbol * s2) +{ + + if (s1->attr.flavor != FL_PROCEDURE && s2->attr.flavor != FL_PROCEDURE) + return compare_type_rank (s1, s2); + + if (s1->attr.flavor != FL_PROCEDURE || s2->attr.flavor != FL_PROCEDURE) + return 0; + + /* At this point, both symbols are procedures. */ + if ((s1->attr.function == 0 && s1->attr.subroutine == 0) + || (s2->attr.function == 0 && s2->attr.subroutine == 0)) + return 0; + + if (s1->attr.function != s2->attr.function + || s1->attr.subroutine != s2->attr.subroutine) + return 0; + + if (s1->attr.function && compare_type_rank (s1, s2) == 0) + return 0; + + return compare_interfaces (s1, s2, 0); /* Recurse! */ +} + + +/* Given a formal argument list and a keyword name, search the list + for that keyword. Returns the correct symbol node if found, NULL + if not found. */ + +static gfc_symbol * +find_keyword_arg (const char *name, gfc_formal_arglist * f) +{ + + for (; f; f = f->next) + if (strcmp (f->sym->name, name) == 0) + return f->sym; + + return NULL; +} + + +/******** Interface checking subroutines **********/ + + +/* Given an operator interface and the operator, make sure that all + interfaces for that operator are legal. */ + +static void +check_operator_interface (gfc_interface * intr, gfc_intrinsic_op operator) +{ + gfc_formal_arglist *formal; + sym_intent i1, i2; + gfc_symbol *sym; + bt t1, t2; + int args; + + if (intr == NULL) + return; + + args = 0; + t1 = t2 = BT_UNKNOWN; + i1 = i2 = INTENT_UNKNOWN; + + for (formal = intr->sym->formal; formal; formal = formal->next) + { + sym = formal->sym; + + if (args == 0) + { + t1 = sym->ts.type; + i1 = sym->attr.intent; + } + if (args == 1) + { + t2 = sym->ts.type; + i2 = sym->attr.intent; + } + args++; + } + + if (args == 0 || args > 2) + goto num_args; + + sym = intr->sym; + + if (operator == INTRINSIC_ASSIGN) + { + if (!sym->attr.subroutine) + { + gfc_error + ("Assignment operator interface at %L must be a SUBROUTINE", + &intr->where); + return; + } + } + else + { + if (!sym->attr.function) + { + gfc_error ("Intrinsic operator interface at %L must be a FUNCTION", + &intr->where); + return; + } + } + + switch (operator) + { + case INTRINSIC_PLUS: /* Numeric unary or binary */ + case INTRINSIC_MINUS: + if ((args == 1) + && (t1 == BT_INTEGER + || t1 == BT_REAL + || t1 == BT_COMPLEX)) + goto bad_repl; + + if ((args == 2) + && (t1 == BT_INTEGER || t1 == BT_REAL || t1 == BT_COMPLEX) + && (t2 == BT_INTEGER || t2 == BT_REAL || t2 == BT_COMPLEX)) + goto bad_repl; + + break; + + case INTRINSIC_POWER: /* Binary numeric */ + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + + case INTRINSIC_EQ: + case INTRINSIC_NE: + if (args == 1) + goto num_args; + + if ((t1 == BT_INTEGER || t1 == BT_REAL || t1 == BT_COMPLEX) + && (t2 == BT_INTEGER || t2 == BT_REAL || t2 == BT_COMPLEX)) + goto bad_repl; + + break; + + case INTRINSIC_GE: /* Binary numeric operators that do not support */ + case INTRINSIC_LE: /* complex numbers */ + case INTRINSIC_LT: + case INTRINSIC_GT: + if (args == 1) + goto num_args; + + if ((t1 == BT_INTEGER || t1 == BT_REAL) + && (t2 == BT_INTEGER || t2 == BT_REAL)) + goto bad_repl; + + break; + + case INTRINSIC_OR: /* Binary logical */ + case INTRINSIC_AND: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + if (args == 1) + goto num_args; + if (t1 == BT_LOGICAL && t2 == BT_LOGICAL) + goto bad_repl; + break; + + case INTRINSIC_NOT: /* Unary logical */ + if (args != 1) + goto num_args; + if (t1 == BT_LOGICAL) + goto bad_repl; + break; + + case INTRINSIC_CONCAT: /* Binary string */ + if (args != 2) + goto num_args; + if (t1 == BT_CHARACTER && t2 == BT_CHARACTER) + goto bad_repl; + break; + + case INTRINSIC_ASSIGN: /* Class by itself */ + if (args != 2) + goto num_args; + break; + default: + gfc_internal_error ("check_operator_interface(): Bad operator"); + } + + /* Check intents on operator interfaces. */ + if (operator == INTRINSIC_ASSIGN) + { + if (i1 != INTENT_OUT && i1 != INTENT_INOUT) + gfc_error ("First argument of defined assignment at %L must be " + "INTENT(IN) or INTENT(INOUT)", &intr->where); + + if (i2 != INTENT_IN) + gfc_error ("Second argument of defined assignment at %L must be " + "INTENT(IN)", &intr->where); + } + else + { + if (i1 != INTENT_IN) + gfc_error ("First argument of operator interface at %L must be " + "INTENT(IN)", &intr->where); + + if (args == 2 && i2 != INTENT_IN) + gfc_error ("Second argument of operator interface at %L must be " + "INTENT(IN)", &intr->where); + } + + return; + +bad_repl: + gfc_error ("Operator interface at %L conflicts with intrinsic interface", + &intr->where); + return; + +num_args: + gfc_error ("Operator interface at %L has the wrong number of arguments", + &intr->where); + return; +} + + +/* Given a pair of formal argument lists, we see if the two lists can + be distinguished by counting the number of nonoptional arguments of + a given type/rank in f1 and seeing if there are less then that + number of those arguments in f2 (including optional arguments). + Since this test is asymmetric, it has to be called twice to make it + symmetric. Returns nonzero if the argument lists are incompatible + by this test. This subroutine implements rule 1 of section + 14.1.2.3. */ + +static int +count_types_test (gfc_formal_arglist * f1, gfc_formal_arglist * f2) +{ + int rc, ac1, ac2, i, j, k, n1; + gfc_formal_arglist *f; + + typedef struct + { + int flag; + gfc_symbol *sym; + } + arginfo; + + arginfo *arg; + + n1 = 0; + + for (f = f1; f; f = f->next) + n1++; + + /* Build an array of integers that gives the same integer to + arguments of the same type/rank. */ + arg = gfc_getmem (n1 * sizeof (arginfo)); + + f = f1; + for (i = 0; i < n1; i++, f = f->next) + { + arg[i].flag = -1; + arg[i].sym = f->sym; + } + + k = 0; + + for (i = 0; i < n1; i++) + { + if (arg[i].flag != -1) + continue; + + if (arg[i].sym->attr.optional) + continue; /* Skip optional arguments */ + + arg[i].flag = k; + + /* Find other nonoptional arguments of the same type/rank. */ + for (j = i + 1; j < n1; j++) + if (!arg[j].sym->attr.optional + && compare_type_rank_if (arg[i].sym, arg[j].sym)) + arg[j].flag = k; + + k++; + } + + /* Now loop over each distinct type found in f1. */ + k = 0; + rc = 0; + + for (i = 0; i < n1; i++) + { + if (arg[i].flag != k) + continue; + + ac1 = 1; + for (j = i + 1; j < n1; j++) + if (arg[j].flag == k) + ac1++; + + /* Count the number of arguments in f2 with that type, including + those that are optional. */ + ac2 = 0; + + for (f = f2; f; f = f->next) + if (compare_type_rank_if (arg[i].sym, f->sym)) + ac2++; + + if (ac1 > ac2) + { + rc = 1; + break; + } + + k++; + } + + gfc_free (arg); + + return rc; +} + + +/* Perform the abbreviated correspondence test for operators. The + arguments cannot be optional and are always ordered correctly, + which makes this test much easier than that for generic tests. + + This subroutine is also used when comparing a formal and actual + argument list when an actual parameter is a dummy procedure. At + that point, two formal interfaces must be compared for equality + which is what happens here. */ + +static int +operator_correspondence (gfc_formal_arglist * f1, gfc_formal_arglist * f2) +{ + for (;;) + { + if (f1 == NULL && f2 == NULL) + break; + if (f1 == NULL || f2 == NULL) + return 1; + + if (!compare_type_rank (f1->sym, f2->sym)) + return 1; + + f1 = f1->next; + f2 = f2->next; + } + + return 0; +} + + +/* Perform the correspondence test in rule 2 of section 14.1.2.3. + Returns zero if no argument is found that satisifes rule 2, nonzero + otherwise. + + This test is also not symmetric in f1 and f2 and must be called + twice. This test finds problems caused by sorting the actual + argument list with keywords. For example: + + INTERFACE FOO + SUBROUTINE F1(A, B) + INTEGER :: A ; REAL :: B + END SUBROUTINE F1 + + SUBROUTINE F2(B, A) + INTEGER :: A ; REAL :: B + END SUBROUTINE F1 + END INTERFACE FOO + + At this point, 'CALL FOO(A=1, B=1.0)' is ambiguous. */ + +static int +generic_correspondence (gfc_formal_arglist * f1, gfc_formal_arglist * f2) +{ + + gfc_formal_arglist *f2_save, *g; + gfc_symbol *sym; + + f2_save = f2; + + while (f1) + { + if (f1->sym->attr.optional) + goto next; + + if (f2 != NULL && compare_type_rank (f1->sym, f2->sym)) + goto next; + + /* Now search for a disambiguating keyword argument starting at + the current non-match. */ + for (g = f1; g; g = g->next) + { + if (g->sym->attr.optional) + continue; + + sym = find_keyword_arg (g->sym->name, f2_save); + if (sym == NULL || !compare_type_rank (g->sym, sym)) + return 1; + } + + next: + f1 = f1->next; + if (f2 != NULL) + f2 = f2->next; + } + + return 0; +} + + +/* 'Compare' two formal interfaces associated with a pair of symbols. + We return nonzero if there exists an actual argument list that + would be ambiguous between the two interfaces, zero otherwise. */ + +static int +compare_interfaces (gfc_symbol * s1, gfc_symbol * s2, int generic_flag) +{ + gfc_formal_arglist *f1, *f2; + + if (s1->attr.function != s2->attr.function + && s1->attr.subroutine != s2->attr.subroutine) + return 0; /* disagreement between function/subroutine */ + + f1 = s1->formal; + f2 = s2->formal; + + if (f1 == NULL && f2 == NULL) + return 1; /* Special case */ + + if (count_types_test (f1, f2)) + return 0; + if (count_types_test (f2, f1)) + return 0; + + if (generic_flag) + { + if (generic_correspondence (f1, f2)) + return 0; + if (generic_correspondence (f2, f1)) + return 0; + } + else + { + if (operator_correspondence (f1, f2)) + return 0; + } + + return 1; +} + + +/* Given a pointer to an interface pointer, remove duplicate + interfaces and make sure that all symbols are either functions or + subroutines. Returns nonzero if something goes wrong. */ + +static int +check_interface0 (gfc_interface * p, const char *interface_name) +{ + gfc_interface *psave, *q, *qlast; + + psave = p; + /* Make sure all symbols in the interface have been defined as + functions or subroutines. */ + for (; p; p = p->next) + if (!p->sym->attr.function && !p->sym->attr.subroutine) + { + gfc_error ("Procedure '%s' in %s at %L is neither function nor " + "subroutine", p->sym->name, interface_name, + &p->sym->declared_at); + return 1; + } + p = psave; + + /* Remove duplicate interfaces in this interface list. */ + for (; p; p = p->next) + { + qlast = p; + + for (q = p->next; q;) + { + if (p->sym != q->sym) + { + qlast = q; + q = q->next; + + } + else + { + /* Duplicate interface */ + qlast->next = q->next; + gfc_free (q); + q = qlast->next; + } + } + } + + return 0; +} + + +/* Check lists of interfaces to make sure that no two interfaces are + ambiguous. Duplicate interfaces (from the same symbol) are OK + here. */ + +static int +check_interface1 (gfc_interface * p, gfc_interface * q, + int generic_flag, const char *interface_name) +{ + + for (; p; p = p->next) + for (; q; q = q->next) + { + if (p->sym == q->sym) + continue; /* Duplicates OK here */ + + if (strcmp (p->sym->name, q->sym->name) == 0 + && strcmp (p->sym->module, q->sym->module) == 0) + continue; + + if (compare_interfaces (p->sym, q->sym, generic_flag)) + { + gfc_error ("Ambiguous interfaces '%s' and '%s' in %s at %L", + p->sym->name, q->sym->name, interface_name, &p->where); + return 1; + } + } + + return 0; +} + + +/* Check the generic and operator interfaces of symbols to make sure + that none of the interfaces conflict. The check has to be done + after all of the symbols are actually loaded. */ + +static void +check_sym_interfaces (gfc_symbol * sym) +{ + char interface_name[100]; + gfc_symbol *s2; + + if (sym->ns != gfc_current_ns) + return; + + if (sym->generic != NULL) + { + sprintf (interface_name, "generic interface '%s'", sym->name); + if (check_interface0 (sym->generic, interface_name)) + return; + + s2 = sym; + while (s2 != NULL) + { + if (check_interface1 (sym->generic, s2->generic, 1, interface_name)) + return; + + if (s2->ns->parent == NULL) + break; + if (gfc_find_symbol (sym->name, s2->ns->parent, 1, &s2)) + break; + } + } +} + + +static void +check_uop_interfaces (gfc_user_op * uop) +{ + char interface_name[100]; + gfc_user_op *uop2; + gfc_namespace *ns; + + sprintf (interface_name, "operator interface '%s'", uop->name); + if (check_interface0 (uop->operator, interface_name)) + return; + + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + uop2 = gfc_find_uop (uop->name, ns); + if (uop2 == NULL) + continue; + + check_interface1 (uop->operator, uop2->operator, 0, interface_name); + } +} + + +/* For the namespace, check generic, user operator and intrinsic + operator interfaces for consistency and to remove duplicate + interfaces. We traverse the whole namespace, counting on the fact + that most symbols will not have generic or operator interfaces. */ + +void +gfc_check_interfaces (gfc_namespace * ns) +{ + gfc_namespace *old_ns, *ns2; + char interface_name[100]; + gfc_intrinsic_op i; + + old_ns = gfc_current_ns; + gfc_current_ns = ns; + + gfc_traverse_ns (ns, check_sym_interfaces); + + gfc_traverse_user_op (ns, check_uop_interfaces); + + for (i = GFC_INTRINSIC_BEGIN; i != GFC_INTRINSIC_END; i++) + { + if (i == INTRINSIC_USER) + continue; + + if (i == INTRINSIC_ASSIGN) + strcpy (interface_name, "intrinsic assignment operator"); + else + sprintf (interface_name, "intrinsic '%s' operator", + gfc_op2string (i)); + + if (check_interface0 (ns->operator[i], interface_name)) + continue; + + check_operator_interface (ns->operator[i], i); + + for (ns2 = ns->parent; ns2; ns2 = ns2->parent) + if (check_interface1 (ns->operator[i], ns2->operator[i], 0, + interface_name)) + break; + } + + gfc_current_ns = old_ns; +} + + +static int +symbol_rank (gfc_symbol * sym) +{ + + return (sym->as == NULL) ? 0 : sym->as->rank; +} + + +/* Given a symbol of a formal argument list and an expression, if the + formal argument is a pointer, see if the actual argument is a + pointer. Returns nonzero if compatible, zero if not compatible. */ + +static int +compare_pointer (gfc_symbol * formal, gfc_expr * actual) +{ + symbol_attribute attr; + + if (formal->attr.pointer) + { + attr = gfc_expr_attr (actual); + if (!attr.pointer) + return 0; + } + + return 1; +} + + +/* Given a symbol of a formal argument list and an expression, see if + the two are compatible as arguments. Returns nonzero if + compatible, zero if not compatible. */ + +static int +compare_parameter (gfc_symbol * formal, gfc_expr * actual, + int ranks_must_agree, int is_elemental) +{ + gfc_ref *ref; + + if (actual->ts.type == BT_PROCEDURE) + { + if (formal->attr.flavor != FL_PROCEDURE) + return 0; + + if (formal->attr.function + && !compare_type_rank (formal, actual->symtree->n.sym)) + return 0; + + if (formal->attr.if_source == IFSRC_UNKNOWN) + return 1; /* Assume match */ + + return compare_interfaces (formal, actual->symtree->n.sym, 0); + } + + if (!gfc_compare_types (&formal->ts, &actual->ts)) + return 0; + + if (symbol_rank (formal) == actual->rank) + return 1; + + /* At this point the ranks didn't agree. */ + if (ranks_must_agree || formal->attr.pointer) + return 0; + + if (actual->rank != 0) + return is_elemental || formal->attr.dimension; + + /* At this point, we are considering a scalar passed to an array. + This is legal if the scalar is an array element of the right sort. */ + if (formal->as->type == AS_ASSUMED_SHAPE) + return 0; + + for (ref = actual->ref; ref; ref = ref->next) + if (ref->type == REF_SUBSTRING) + return 0; + + for (ref = actual->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->u.ar.type == AR_ELEMENT) + break; + + if (ref == NULL) + return 0; /* Not an array element */ + + return 1; +} + + +/* Given formal and actual argument lists, see if they are compatible. + If they are compatible, the actual argument list is sorted to + correspond with the formal list, and elements for missing optional + arguments are inserted. If WHERE pointer is nonnull, then we issue + errors when things don't match instead of just returning the status + code. */ + +static int +compare_actual_formal (gfc_actual_arglist ** ap, + gfc_formal_arglist * formal, + int ranks_must_agree, int is_elemental, locus * where) +{ + gfc_actual_arglist **new, *a, *actual, temp; + gfc_formal_arglist *f; + int i, n, na; + + actual = *ap; + + if (actual == NULL && formal == NULL) + return 1; + + n = 0; + for (f = formal; f; f = f->next) + n++; + + new = (gfc_actual_arglist **) alloca (n * sizeof (gfc_actual_arglist *)); + + for (i = 0; i < n; i++) + new[i] = NULL; + + na = 0; + f = formal; + i = 0; + + for (a = actual; a; a = a->next, f = f->next) + { + if (a->name[0] != '\0') + { + i = 0; + for (f = formal; f; f = f->next, i++) + { + if (f->sym == NULL) + continue; + if (strcmp (f->sym->name, a->name) == 0) + break; + } + + if (f == NULL) + { + if (where) + gfc_error + ("Keyword argument '%s' at %L is not in the procedure", + a->name, &a->expr->where); + return 0; + } + + if (new[i] != NULL) + { + if (where) + gfc_error + ("Keyword argument '%s' at %L is already associated " + "with another actual argument", a->name, &a->expr->where); + return 0; + } + } + + if (f == NULL) + { + if (where) + gfc_error + ("More actual than formal arguments in procedure call at %L", + where); + + return 0; + } + + if (f->sym == NULL && a->expr == NULL) + goto match; + + if (f->sym == NULL) + { + if (where) + gfc_error + ("Missing alternate return spec in subroutine call at %L", + where); + return 0; + } + + if (a->expr == NULL) + { + if (where) + gfc_error + ("Unexpected alternate return spec in subroutine call at %L", + where); + return 0; + } + + if (!compare_parameter + (f->sym, a->expr, ranks_must_agree, is_elemental)) + { + if (where) + gfc_error ("Type/rank mismatch in argument '%s' at %L", + f->sym->name, &a->expr->where); + return 0; + } + + if (compare_pointer (f->sym, a->expr) == 0) + { + if (where) + gfc_error ("Actual argument for '%s' must be a pointer at %L", + f->sym->name, &a->expr->where); + return 0; + } + + match: + if (a == actual) + na = i; + + new[i++] = a; + } + + /* Make sure missing actual arguments are optional. */ + i = 0; + for (f = formal; f; f = f->next, i++) + { + if (new[i] != NULL) + continue; + if (!f->sym->attr.optional) + { + if (where) + gfc_error ("Missing actual argument for argument '%s' at %L", + f->sym->name, where); + return 0; + } + } + + /* The argument lists are compatible. We now relink a new actual + argument list with null arguments in the right places. The head + of the list remains the head. */ + for (i = 0; i < n; i++) + if (new[i] == NULL) + new[i] = gfc_get_actual_arglist (); + + if (na != 0) + { + temp = *new[0]; + *new[0] = *actual; + *actual = temp; + + a = new[0]; + new[0] = new[na]; + new[na] = a; + } + + for (i = 0; i < n - 1; i++) + new[i]->next = new[i + 1]; + + new[i]->next = NULL; + + if (*ap == NULL && n > 0) + *ap = new[0]; + + return 1; +} + + +typedef struct +{ + gfc_formal_arglist *f; + gfc_actual_arglist *a; +} +argpair; + +/* qsort comparison function for argument pairs, with the following + order: + - p->a->expr == NULL + - p->a->expr->expr_type != EXPR_VARIABLE + - growing p->a->expr->symbol. */ + +static int +pair_cmp (const void *p1, const void *p2) +{ + const gfc_actual_arglist *a1, *a2; + + /* *p1 and *p2 are elements of the to-be-sorted array. */ + a1 = ((const argpair *) p1)->a; + a2 = ((const argpair *) p2)->a; + if (!a1->expr) + { + if (!a2->expr) + return 0; + return -1; + } + if (!a2->expr) + return 1; + if (a1->expr->expr_type != EXPR_VARIABLE) + { + if (a2->expr->expr_type != EXPR_VARIABLE) + return 0; + return -1; + } + if (a2->expr->expr_type != EXPR_VARIABLE) + return 1; + return a1->expr->symtree->n.sym < a2->expr->symtree->n.sym; +} + + +/* Given two expressions from some actual arguments, test whether they + refer to the same expression. The analysis is conservative. + Returning FAILURE will produce no warning. */ + +static try +compare_actual_expr (gfc_expr * e1, gfc_expr * e2) +{ + const gfc_ref *r1, *r2; + + if (!e1 || !e2 + || e1->expr_type != EXPR_VARIABLE + || e2->expr_type != EXPR_VARIABLE + || e1->symtree->n.sym != e2->symtree->n.sym) + return FAILURE; + + /* TODO: improve comparison, see expr.c:show_ref(). */ + for (r1 = e1->ref, r2 = e2->ref; r1 && r2; r1 = r1->next, r2 = r2->next) + { + if (r1->type != r2->type) + return FAILURE; + switch (r1->type) + { + case REF_ARRAY: + if (r1->u.ar.type != r2->u.ar.type) + return FAILURE; + /* TODO: At the moment, consider only full arrays; + we could do better. */ + if (r1->u.ar.type != AR_FULL || r2->u.ar.type != AR_FULL) + return FAILURE; + break; + + case REF_COMPONENT: + if (r1->u.c.component != r2->u.c.component) + return FAILURE; + break; + + case REF_SUBSTRING: + return FAILURE; + + default: + gfc_internal_error ("compare_actual_expr(): Bad component code"); + } + } + if (!r1 && !r2) + return SUCCESS; + return FAILURE; +} + +/* Given formal and actual argument lists that correspond to one + another, check that identical actual arguments aren't not + associated with some incompatible INTENTs. */ + +static try +check_some_aliasing (gfc_formal_arglist * f, gfc_actual_arglist * a) +{ + sym_intent f1_intent, f2_intent; + gfc_formal_arglist *f1; + gfc_actual_arglist *a1; + size_t n, i, j; + argpair *p; + try t = SUCCESS; + + n = 0; + for (f1 = f, a1 = a;; f1 = f1->next, a1 = a1->next) + { + if (f1 == NULL && a1 == NULL) + break; + if (f1 == NULL || a1 == NULL) + gfc_internal_error ("check_some_aliasing(): List mismatch"); + n++; + } + if (n == 0) + return t; + p = (argpair *) alloca (n * sizeof (argpair)); + + for (i = 0, f1 = f, a1 = a; i < n; i++, f1 = f1->next, a1 = a1->next) + { + p[i].f = f1; + p[i].a = a1; + } + + qsort (p, n, sizeof (argpair), pair_cmp); + + for (i = 0; i < n; i++) + { + if (!p[i].a->expr + || p[i].a->expr->expr_type != EXPR_VARIABLE + || p[i].a->expr->ts.type == BT_PROCEDURE) + continue; + f1_intent = p[i].f->sym->attr.intent; + for (j = i + 1; j < n; j++) + { + /* Expected order after the sort. */ + if (!p[j].a->expr || p[j].a->expr->expr_type != EXPR_VARIABLE) + gfc_internal_error ("check_some_aliasing(): corrupted data"); + + /* Are the expression the same? */ + if (compare_actual_expr (p[i].a->expr, p[j].a->expr) == FAILURE) + break; + f2_intent = p[j].f->sym->attr.intent; + if ((f1_intent == INTENT_IN && f2_intent == INTENT_OUT) + || (f1_intent == INTENT_OUT && f2_intent == INTENT_IN)) + { + gfc_warning ("Same actual argument associated with INTENT(%s) " + "argument '%s' and INTENT(%s) argument '%s' at %L", + gfc_intent_string (f1_intent), p[i].f->sym->name, + gfc_intent_string (f2_intent), p[j].f->sym->name, + &p[i].a->expr->where); + t = FAILURE; + } + } + } + + return t; +} + + +/* Given formal and actual argument lists that correspond to one + another, check that they are compatible in the sense that intents + are not mismatched. */ + +static try +check_intents (gfc_formal_arglist * f, gfc_actual_arglist * a) +{ + sym_intent a_intent, f_intent; + + for (;; f = f->next, a = a->next) + { + if (f == NULL && a == NULL) + break; + if (f == NULL || a == NULL) + gfc_internal_error ("check_intents(): List mismatch"); + + if (a->expr == NULL || a->expr->expr_type != EXPR_VARIABLE) + continue; + + a_intent = a->expr->symtree->n.sym->attr.intent; + f_intent = f->sym->attr.intent; + + if (a_intent == INTENT_IN + && (f_intent == INTENT_INOUT + || f_intent == INTENT_OUT)) + { + + gfc_error ("Procedure argument at %L is INTENT(IN) while interface " + "specifies INTENT(%s)", &a->expr->where, + gfc_intent_string (f_intent)); + return FAILURE; + } + + if (gfc_pure (NULL) && gfc_impure_variable (a->expr->symtree->n.sym)) + { + if (f_intent == INTENT_INOUT || f_intent == INTENT_OUT) + { + gfc_error + ("Procedure argument at %L is local to a PURE procedure and " + "is passed to an INTENT(%s) argument", &a->expr->where, + gfc_intent_string (f_intent)); + return FAILURE; + } + + if (a->expr->symtree->n.sym->attr.pointer) + { + gfc_error + ("Procedure argument at %L is local to a PURE procedure and " + "has the POINTER attribute", &a->expr->where); + return FAILURE; + } + } + } + + return SUCCESS; +} + + +/* Check how a procedure is used against its interface. If all goes + well, the actual argument list will also end up being properly + sorted. */ + +void +gfc_procedure_use (gfc_symbol * sym, gfc_actual_arglist ** ap, locus * where) +{ + /* Warn about calls with an implicit interface. */ + if (gfc_option.warn_implicit_interface + && sym->attr.if_source == IFSRC_UNKNOWN) + gfc_warning ("Procedure '%s' called with an implicit interface at %L", + sym->name, where); + + if (sym->attr.if_source == IFSRC_UNKNOWN + || !compare_actual_formal (ap, sym->formal, 0, + sym->attr.elemental, where)) + return; + + check_intents (sym->formal, *ap); + if (gfc_option.warn_aliasing) + check_some_aliasing (sym->formal, *ap); +} + + +/* Given an interface pointer and an actual argument list, search for + a formal argument list that matches the actual. If found, returns + a pointer to the symbol of the correct interface. Returns NULL if + not found. */ + +gfc_symbol * +gfc_search_interface (gfc_interface * intr, int sub_flag, + gfc_actual_arglist ** ap) +{ + int r; + + for (; intr; intr = intr->next) + { + if (sub_flag && intr->sym->attr.function) + continue; + if (!sub_flag && intr->sym->attr.subroutine) + continue; + + r = !intr->sym->attr.elemental; + + if (compare_actual_formal (ap, intr->sym->formal, r, !r, NULL)) + { + check_intents (intr->sym->formal, *ap); + if (gfc_option.warn_aliasing) + check_some_aliasing (intr->sym->formal, *ap); + return intr->sym; + } + } + + return NULL; +} + + +/* Do a brute force recursive search for a symbol. */ + +static gfc_symtree * +find_symtree0 (gfc_symtree * root, gfc_symbol * sym) +{ + gfc_symtree * st; + + if (root->n.sym == sym) + return root; + + st = NULL; + if (root->left) + st = find_symtree0 (root->left, sym); + if (root->right && ! st) + st = find_symtree0 (root->right, sym); + return st; +} + + +/* Find a symtree for a symbol. */ + +static gfc_symtree * +find_sym_in_symtree (gfc_symbol * sym) +{ + gfc_symtree *st; + gfc_namespace *ns; + + /* First try to find it by name. */ + gfc_find_sym_tree (sym->name, gfc_current_ns, 1, &st); + if (st && st->n.sym == sym) + return st; + + /* if it's been renamed, resort to a brute-force search. */ + /* TODO: avoid having to do this search. If the symbol doesn't exist + in the symtree for the current namespace, it should probably be added. */ + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + st = find_symtree0 (ns->sym_root, sym); + if (st) + return st; + } + gfc_internal_error ("Unable to find symbol %s", sym->name); + /* Not reached */ +} + + +/* This subroutine is called when an expression is being resolved. + The expression node in question is either a user defined operator + or an instrinsic operator with arguments that aren't compatible + with the operator. This subroutine builds an actual argument list + corresponding to the operands, then searches for a compatible + interface. If one is found, the expression node is replaced with + the appropriate function call. */ + +try +gfc_extend_expr (gfc_expr * e) +{ + gfc_actual_arglist *actual; + gfc_symbol *sym; + gfc_namespace *ns; + gfc_user_op *uop; + gfc_intrinsic_op i; + + sym = NULL; + + actual = gfc_get_actual_arglist (); + actual->expr = e->op1; + + if (e->op2 != NULL) + { + actual->next = gfc_get_actual_arglist (); + actual->next->expr = e->op2; + } + + i = fold_unary (e->operator); + + if (i == INTRINSIC_USER) + { + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + uop = gfc_find_uop (e->uop->name, ns); + if (uop == NULL) + continue; + + sym = gfc_search_interface (uop->operator, 0, &actual); + if (sym != NULL) + break; + } + } + else + { + for (ns = gfc_current_ns; ns; ns = ns->parent) + { + sym = gfc_search_interface (ns->operator[i], 0, &actual); + if (sym != NULL) + break; + } + } + + if (sym == NULL) + { + /* Don't use gfc_free_actual_arglist() */ + if (actual->next != NULL) + gfc_free (actual->next); + gfc_free (actual); + + return FAILURE; + } + + /* Change the expression node to a function call. */ + e->expr_type = EXPR_FUNCTION; + e->symtree = find_sym_in_symtree (sym); + e->value.function.actual = actual; + + if (gfc_pure (NULL) && !gfc_pure (sym)) + { + gfc_error + ("Function '%s' called in lieu of an operator at %L must be PURE", + sym->name, &e->where); + return FAILURE; + } + + if (gfc_resolve_expr (e) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Tries to replace an assignment code node with a subroutine call to + the subroutine associated with the assignment operator. Return + SUCCESS if the node was replaced. On FAILURE, no error is + generated. */ + +try +gfc_extend_assign (gfc_code * c, gfc_namespace * ns) +{ + gfc_actual_arglist *actual; + gfc_expr *lhs, *rhs; + gfc_symbol *sym; + + lhs = c->expr; + rhs = c->expr2; + + /* Don't allow an intrinsic assignment to be replaced. */ + if (lhs->ts.type != BT_DERIVED && rhs->ts.type != BT_DERIVED + && (lhs->ts.type == rhs->ts.type + || (gfc_numeric_ts (&lhs->ts) + && gfc_numeric_ts (&rhs->ts)))) + return FAILURE; + + actual = gfc_get_actual_arglist (); + actual->expr = lhs; + + actual->next = gfc_get_actual_arglist (); + actual->next->expr = rhs; + + sym = NULL; + + for (; ns; ns = ns->parent) + { + sym = gfc_search_interface (ns->operator[INTRINSIC_ASSIGN], 1, &actual); + if (sym != NULL) + break; + } + + if (sym == NULL) + { + gfc_free (actual->next); + gfc_free (actual); + return FAILURE; + } + + /* Replace the assignment with the call. */ + c->op = EXEC_CALL; + c->symtree = find_sym_in_symtree (sym); + c->expr = NULL; + c->expr2 = NULL; + c->ext.actual = actual; + + if (gfc_pure (NULL) && !gfc_pure (sym)) + { + gfc_error ("Subroutine '%s' called in lieu of assignment at %L must be " + "PURE", sym->name, &c->loc); + return FAILURE; + } + + return SUCCESS; +} + + +/* Make sure that the interface just parsed is not already present in + the given interface list. Ambiguity isn't checked yet since module + procedures can be present without interfaces. */ + +static try +check_new_interface (gfc_interface * base, gfc_symbol * new) +{ + gfc_interface *ip; + + for (ip = base; ip; ip = ip->next) + { + if (ip->sym == new) + { + gfc_error ("Entity '%s' at %C is already present in the interface", + new->name); + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Add a symbol to the current interface. */ + +try +gfc_add_interface (gfc_symbol * new) +{ + gfc_interface **head, *intr; + gfc_namespace *ns; + gfc_symbol *sym; + + switch (current_interface.type) + { + case INTERFACE_NAMELESS: + return SUCCESS; + + case INTERFACE_INTRINSIC_OP: + for (ns = current_interface.ns; ns; ns = ns->parent) + if (check_new_interface (ns->operator[current_interface.op], new) + == FAILURE) + return FAILURE; + + head = ¤t_interface.ns->operator[current_interface.op]; + break; + + case INTERFACE_GENERIC: + for (ns = current_interface.ns; ns; ns = ns->parent) + { + gfc_find_symbol (current_interface.sym->name, ns, 0, &sym); + if (sym == NULL) + continue; + + if (check_new_interface (sym->generic, new) == FAILURE) + return FAILURE; + } + + head = ¤t_interface.sym->generic; + break; + + case INTERFACE_USER_OP: + if (check_new_interface (current_interface.uop->operator, new) == + FAILURE) + return FAILURE; + + head = ¤t_interface.uop->operator; + break; + + default: + gfc_internal_error ("gfc_add_interface(): Bad interface type"); + } + + intr = gfc_get_interface (); + intr->sym = new; + intr->where = *gfc_current_locus (); + + intr->next = *head; + *head = intr; + + return SUCCESS; +} + + +/* Gets rid of a formal argument list. We do not free symbols. + Symbols are freed when a namespace is freed. */ + +void +gfc_free_formal_arglist (gfc_formal_arglist * p) +{ + gfc_formal_arglist *q; + + for (; p; p = q) + { + q = p->next; + gfc_free (p); + } +} diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c new file mode 100644 index 00000000000..3d05b72ca04 --- /dev/null +++ b/gcc/fortran/intrinsic.c @@ -0,0 +1,2560 @@ +/* Build up a list of intrinsic subroutines and functions for the + name-resolution stage. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught & Katherine Holcomb + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include "system.h" +#include "flags.h" + +#include +#include +#include +#include + +#include "gfortran.h" +#include "intrinsic.h" + + +/* Nanespace to hold the resolved symbols for intrinsic subroutines. */ +static gfc_namespace *gfc_intrinsic_namespace; + +int gfc_init_expr = 0; + +/* Pointers to a intrinsic function and its argument names being + checked. */ + +char *gfc_current_intrinsic, *gfc_current_intrinsic_arg[MAX_INTRINSIC_ARGS]; +locus *gfc_current_intrinsic_where; + +static gfc_intrinsic_sym *functions, *subroutines, *conversion, *next_sym; +static gfc_intrinsic_arg *next_arg; + +static int nfunc, nsub, nargs, nconv; + +static enum +{ SZ_NOTHING = 0, SZ_SUBS, SZ_FUNCS, SZ_CONVS } +sizing; + + +/* Return a letter based on the passed type. Used to construct the + name of a type-dependent subroutine. */ + +char +gfc_type_letter (bt type) +{ + char c; + + switch (type) + { + case BT_LOGICAL: + c = 'l'; + break; + case BT_CHARACTER: + c = 's'; + break; + case BT_INTEGER: + c = 'i'; + break; + case BT_REAL: + c = 'r'; + break; + case BT_COMPLEX: + c = 'c'; + break; + + default: + c = 'u'; + break; + } + + return c; +} + + +/* Get a symbol for a resolved name. */ + +gfc_symbol * +gfc_get_intrinsic_sub_symbol (const char * name) +{ + gfc_symbol *sym; + + gfc_get_symbol (name, gfc_intrinsic_namespace, &sym); + sym->attr.always_explicit = 1; + sym->attr.subroutine = 1; + sym->attr.flavor = FL_PROCEDURE; + sym->attr.proc = PROC_INTRINSIC; + + return sym; +} + + +/* Return a pointer to the name of a conversion function given two + typespecs. */ + +static char * +conv_name (gfc_typespec * from, gfc_typespec * to) +{ + static char name[30]; + + sprintf (name, "__convert_%c%d_%c%d", gfc_type_letter (from->type), + from->kind, gfc_type_letter (to->type), to->kind); + + return name; +} + + +/* Given a pair of typespecs, find the gfc_intrinsic_sym node that + corresponds to the conversion. Returns NULL if the conversion + isn't found. */ + +static gfc_intrinsic_sym * +find_conv (gfc_typespec * from, gfc_typespec * to) +{ + gfc_intrinsic_sym *sym; + char *target; + int i; + + target = conv_name (from, to); + sym = conversion; + + for (i = 0; i < nconv; i++, sym++) + if (strcmp (target, sym->name) == 0) + return sym; + + return NULL; +} + + +/* Interface to the check functions. We break apart an argument list + and call the proper check function rather than forcing each + function to manipulate the argument list. */ + +static try +do_check (gfc_intrinsic_sym * specific, gfc_actual_arglist * arg) +{ + gfc_expr *a1, *a2, *a3, *a4, *a5; + try t; + + a1 = arg->expr; + arg = arg->next; + + if (arg == NULL) + t = (*specific->check.f1) (a1); + else + { + a2 = arg->expr; + arg = arg->next; + + if (arg == NULL) + t = (*specific->check.f2) (a1, a2); + else + { + a3 = arg->expr; + arg = arg->next; + + if (arg == NULL) + t = (*specific->check.f3) (a1, a2, a3); + else + { + a4 = arg->expr; + arg = arg->next; + + if (arg == NULL) + t = (*specific->check.f4) (a1, a2, a3, a4); + else + { + a5 = arg->expr; + arg = arg->next; + + if (arg == NULL) + t = (*specific->check.f5) (a1, a2, a3, a4, a5); + else + { + gfc_internal_error ("do_check(): too many args"); + } + } + } + } + } + + return t; +} + + +/*********** Subroutines to build the intrinsic list ****************/ + +/* Add a single intrinsic symbol to the current list. + + Argument list: + char * name of function + int whether function is elemental + int If the function can be used as an actual argument + bt return type of function + int kind of return type of function + check pointer to check function + simplify pointer to simplification function + resolve pointer to resolution function + + Optional arguments come in multiples of four: + char * name of argument + bt type of argument + int kind of argument + int arg optional flag (1=optional, 0=required) + + The sequence is terminated by a NULL name. + + TODO: Are checks on actual_ok implemented elsewhere, or is that just + missing here? */ + +static void +add_sym (const char *name, int elemental, int actual_ok ATTRIBUTE_UNUSED, + bt type, int kind, gfc_check_f check, gfc_simplify_f simplify, + gfc_resolve_f resolve, ...) +{ + + int optional, first_flag; + va_list argp; + + switch (sizing) + { + case SZ_SUBS: + nsub++; + break; + + case SZ_FUNCS: + nfunc++; + break; + + case SZ_NOTHING: + strcpy (next_sym->name, name); + + strcpy (next_sym->lib_name, "_gfortran_"); + strcat (next_sym->lib_name, name); + + next_sym->elemental = elemental; + next_sym->ts.type = type; + next_sym->ts.kind = kind; + next_sym->simplify = simplify; + next_sym->check = check; + next_sym->resolve = resolve; + next_sym->specific = 0; + next_sym->generic = 0; + break; + + default: + gfc_internal_error ("add_sym(): Bad sizing mode"); + } + + va_start (argp, resolve); + + first_flag = 1; + + for (;;) + { + name = va_arg (argp, char *); + if (name == NULL) + break; + + type = (bt) va_arg (argp, int); + kind = va_arg (argp, int); + optional = va_arg (argp, int); + + if (sizing != SZ_NOTHING) + nargs++; + else + { + next_arg++; + + if (first_flag) + next_sym->formal = next_arg; + else + (next_arg - 1)->next = next_arg; + + first_flag = 0; + + strcpy (next_arg->name, name); + next_arg->ts.type = type; + next_arg->ts.kind = kind; + next_arg->optional = optional; + } + } + + va_end (argp); + + next_sym++; +} + + +static void add_sym_0 (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_expr *), + gfc_expr *(*simplify)(gfc_expr *), + void (*resolve)(gfc_expr *,gfc_expr *) + ) { + gfc_simplify_f sf; + gfc_check_f cf; + gfc_resolve_f rf; + + cf.f1 = check; + sf.f1 = simplify; + rf.f1 = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + (void*)0); +} + + +static void add_sym_1 (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_expr *), + gfc_expr *(*simplify)(gfc_expr *), + void (*resolve)(gfc_expr *,gfc_expr *), + const char* a1, bt type1, int kind1, int optional1 + ) { + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f1 = check; + sf.f1 = simplify; + rf.f1 = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + a1, type1, kind1, optional1, + (void*)0); +} + + +static void +add_sym_0s (const char * name, int actual_ok, + void (*resolve)(gfc_code *)) +{ + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f1 = NULL; + sf.f1 = NULL; + rf.s1 = resolve; + + add_sym (name, 1, actual_ok, BT_UNKNOWN, 0, cf, sf, rf, + (void*)0); +} + + +static void add_sym_1s (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_expr *), + gfc_expr *(*simplify)(gfc_expr *), + void (*resolve)(gfc_code *), + const char* a1, bt type1, int kind1, int optional1 + ) { + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f1 = check; + sf.f1 = simplify; + rf.s1 = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + a1, type1, kind1, optional1, + (void*)0); +} + + +static void add_sym_1m (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_actual_arglist *), + gfc_expr *(*simplify)(gfc_expr *), + void (*resolve)(gfc_expr *,gfc_actual_arglist *), + const char* a1, bt type1, int kind1, int optional1, + const char* a2, bt type2, int kind2, int optional2 + ) { + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f1m = check; + sf.f1 = simplify; + rf.f1m = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + a1, type1, kind1, optional1, + a2, type2, kind2, optional2, + (void*)0); +} + + +static void add_sym_2 (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_expr *,gfc_expr *), + gfc_expr *(*simplify)(gfc_expr *,gfc_expr *), + void (*resolve)(gfc_expr *,gfc_expr *,gfc_expr *), + const char* a1, bt type1, int kind1, int optional1, + const char* a2, bt type2, int kind2, int optional2 + ) { + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f2 = check; + sf.f2 = simplify; + rf.f2 = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + a1, type1, kind1, optional1, + a2, type2, kind2, optional2, + (void*)0); +} + + +static void add_sym_3 (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_expr *,gfc_expr *,gfc_expr *), + gfc_expr *(*simplify)(gfc_expr *,gfc_expr *,gfc_expr *), + void (*resolve)(gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *), + const char* a1, bt type1, int kind1, int optional1, + const char* a2, bt type2, int kind2, int optional2, + const char* a3, bt type3, int kind3, int optional3 + ) { + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f3 = check; + sf.f3 = simplify; + rf.f3 = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + a1, type1, kind1, optional1, + a2, type2, kind2, optional2, + a3, type3, kind3, optional3, + (void*)0); +} + + +static void add_sym_4 (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *), + gfc_expr *(*simplify)(gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *), + void (*resolve)(gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *), + const char* a1, bt type1, int kind1, int optional1, + const char* a2, bt type2, int kind2, int optional2, + const char* a3, bt type3, int kind3, int optional3, + const char* a4, bt type4, int kind4, int optional4 + ) { + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f4 = check; + sf.f4 = simplify; + rf.f4 = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + a1, type1, kind1, optional1, + a2, type2, kind2, optional2, + a3, type3, kind3, optional3, + a4, type4, kind4, optional4, + (void*)0); +} + + +static void add_sym_5 (const char *name, int elemental, int actual_ok, bt type, + int kind, + try (*check)(gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *), + gfc_expr *(*simplify)(gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *), + void (*resolve)(gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *,gfc_expr *), + const char* a1, bt type1, int kind1, int optional1, + const char* a2, bt type2, int kind2, int optional2, + const char* a3, bt type3, int kind3, int optional3, + const char* a4, bt type4, int kind4, int optional4, + const char* a5, bt type5, int kind5, int optional5 + ) { + gfc_check_f cf; + gfc_simplify_f sf; + gfc_resolve_f rf; + + cf.f5 = check; + sf.f5 = simplify; + rf.f5 = resolve; + + add_sym (name, elemental, actual_ok, type, kind, cf, sf, rf, + a1, type1, kind1, optional1, + a2, type2, kind2, optional2, + a3, type3, kind3, optional3, + a4, type4, kind4, optional4, + a5, type5, kind5, optional5, + (void*)0); +} + + +/* Locate an intrinsic symbol given a base pointer, number of elements + in the table and a pointer to a name. Returns the NULL pointer if + a name is not found. */ + +static gfc_intrinsic_sym * +find_sym (gfc_intrinsic_sym * start, int n, const char *name) +{ + + while (n > 0) + { + if (strcmp (name, start->name) == 0) + return start; + + start++; + n--; + } + + return NULL; +} + + +/* Given a name, find a function in the intrinsic function table. + Returns NULL if not found. */ + +gfc_intrinsic_sym * +gfc_find_function (const char *name) +{ + + return find_sym (functions, nfunc, name); +} + + +/* Given a name, find a function in the intrinsic subroutine table. + Returns NULL if not found. */ + +static gfc_intrinsic_sym * +find_subroutine (const char *name) +{ + + return find_sym (subroutines, nsub, name); +} + + +/* Given a string, figure out if it is the name of a generic intrinsic + function or not. */ + +int +gfc_generic_intrinsic (const char *name) +{ + gfc_intrinsic_sym *sym; + + sym = gfc_find_function (name); + return (sym == NULL) ? 0 : sym->generic; +} + + +/* Given a string, figure out if it is the name of a specific + intrinsic function or not. */ + +int +gfc_specific_intrinsic (const char *name) +{ + gfc_intrinsic_sym *sym; + + sym = gfc_find_function (name); + return (sym == NULL) ? 0 : sym->specific; +} + + +/* Given a string, figure out if it is the name of an intrinsic + subroutine or function. There are no generic intrinsic + subroutines, they are all specific. */ + +int +gfc_intrinsic_name (const char *name, int subroutine_flag) +{ + + return subroutine_flag ? + find_subroutine (name) != NULL : gfc_find_function (name) != NULL; +} + + +/* Collect a set of intrinsic functions into a generic collection. + The first argument is the name of the generic function, which is + also the name of a specific function. The rest of the specifics + currently in the table are placed into the list of specific + functions associated with that generic. */ + +static void +make_generic (const char *name, gfc_generic_isym_id generic_id) +{ + gfc_intrinsic_sym *g; + + if (sizing != SZ_NOTHING) + return; + + g = gfc_find_function (name); + if (g == NULL) + gfc_internal_error ("make_generic(): Can't find generic symbol '%s'", + name); + + g->generic = 1; + g->specific = 1; + g->generic_id = generic_id; + if ((g + 1)->name[0] != '\0') + g->specific_head = g + 1; + g++; + + while (g->name[0] != '\0') + { + g->next = g + 1; + g->specific = 1; + g->generic_id = generic_id; + g++; + } + + g--; + g->next = NULL; +} + + +/* Create a duplicate intrinsic function entry for the current + function, the only difference being the alternate name. Note that + we use argument lists more than once, but all argument lists are + freed as a single block. */ + +static void +make_alias (const char *name) +{ + + switch (sizing) + { + case SZ_FUNCS: + nfunc++; + break; + + case SZ_SUBS: + nsub++; + break; + + case SZ_NOTHING: + next_sym[0] = next_sym[-1]; + strcpy (next_sym->name, name); + next_sym++; + break; + + default: + break; + } +} + + +/* Add intrinsic functions. */ + +static void +add_functions (void) +{ + + /* Argument names as in the standard (to be used as argument keywords). */ + const char + *a = "a", *f = "field", *pt = "pointer", *tg = "target", + *b = "b", *m = "matrix", *ma = "matrix_a", *mb = "matrix_b", + *c = "c", *n = "ncopies", *pos = "pos", *bck = "back", + *i = "i", *v = "vector", *va = "vector_a", *vb = "vector_b", + *j = "j", *a1 = "a1", *fs = "fsource", *ts = "tsource", + *l = "l", *a2 = "a2", *mo = "mold", *ord = "order", + *p = "p", *ar = "array", *shp = "shape", *src = "source", + *r = "r", *bd = "boundary", *pad = "pad", *set = "set", + *s = "s", *dm = "dim", *kind = "kind", *msk = "mask", + *x = "x", *sh = "shift", *stg = "string", *ssg = "substring", + *y = "y", *sz = "size", *sta = "string_a", *stb = "string_b", + *z = "z", *ln = "len"; + + int di, dr, dd, dl, dc, dz, ii; + + di = gfc_default_integer_kind (); + dr = gfc_default_real_kind (); + dd = gfc_default_double_kind (); + dl = gfc_default_logical_kind (); + dc = gfc_default_character_kind (); + dz = gfc_default_complex_kind (); + ii = gfc_index_integer_kind; + + add_sym_1 ("abs", 1, 1, BT_REAL, dr, + gfc_check_abs, gfc_simplify_abs, gfc_resolve_abs, + a, BT_REAL, dr, 0); + + add_sym_1 ("iabs", 1, 1, BT_INTEGER, di, + NULL, gfc_simplify_abs, gfc_resolve_abs, + a, BT_INTEGER, di, 0); + + add_sym_1 ("dabs", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_abs, gfc_resolve_abs, a, BT_REAL, dd, 0); + + add_sym_1 ("cabs", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_abs, gfc_resolve_abs, + a, BT_COMPLEX, dz, 0); + + add_sym_1 ("zabs", 1, 1, BT_REAL, dd, NULL, gfc_simplify_abs, gfc_resolve_abs, a, BT_COMPLEX, dd, 0); /* Extension */ + + make_alias ("cdabs"); + + make_generic ("abs", GFC_ISYM_ABS); + + add_sym_1 ("achar", 1, 1, BT_CHARACTER, dc, + NULL, gfc_simplify_achar, NULL, i, BT_INTEGER, di, 0); + + make_generic ("achar", GFC_ISYM_ACHAR); + + add_sym_1 ("acos", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_acos, gfc_resolve_acos, + x, BT_REAL, dr, 0); + + add_sym_1 ("dacos", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_acos, gfc_resolve_acos, + x, BT_REAL, dd, 0); + + make_generic ("acos", GFC_ISYM_ACOS); + + add_sym_1 ("adjustl", 1, 1, BT_CHARACTER, dc, + NULL, gfc_simplify_adjustl, NULL, stg, BT_CHARACTER, dc, 0); + + make_generic ("adjustl", GFC_ISYM_ADJUSTL); + + add_sym_1 ("adjustr", 1, 1, BT_CHARACTER, dc, + NULL, gfc_simplify_adjustr, NULL, stg, BT_CHARACTER, dc, 0); + + make_generic ("adjustr", GFC_ISYM_ADJUSTR); + + add_sym_1 ("aimag", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_aimag, gfc_resolve_aimag, + z, BT_COMPLEX, dz, 0); + + add_sym_1 ("dimag", 1, 1, BT_REAL, dd, NULL, gfc_simplify_aimag, gfc_resolve_aimag, z, BT_COMPLEX, dd, 0); /* Extension */ + + make_generic ("aimag", GFC_ISYM_AIMAG); + + add_sym_2 ("aint", 1, 1, BT_REAL, dr, + gfc_check_a_xkind, gfc_simplify_aint, gfc_resolve_aint, + a, BT_REAL, dr, 0, kind, BT_INTEGER, di, 1); + + add_sym_1 ("dint", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_dint, gfc_resolve_dint, + a, BT_REAL, dd, 0); + + make_generic ("aint", GFC_ISYM_AINT); + + add_sym_2 ("all", 0, 1, BT_UNKNOWN, 0, + gfc_check_all_any, NULL, gfc_resolve_all, + msk, BT_LOGICAL, dl, 0, dm, BT_INTEGER, ii, 1); + + make_generic ("all", GFC_ISYM_ALL); + + add_sym_1 ("allocated", 0, 1, BT_LOGICAL, dl, + gfc_check_allocated, NULL, NULL, ar, BT_UNKNOWN, 0, 0); + + make_generic ("allocated", GFC_ISYM_ALLOCATED); + + add_sym_2 ("anint", 1, 1, BT_REAL, dr, + gfc_check_a_xkind, gfc_simplify_anint, gfc_resolve_anint, + a, BT_REAL, dr, 0, kind, BT_INTEGER, di, 1); + + add_sym_1 ("dnint", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_dnint, gfc_resolve_dnint, + a, BT_REAL, dd, 0); + + make_generic ("anint", GFC_ISYM_ANINT); + + add_sym_2 ("any", 0, 1, BT_UNKNOWN, 0, + gfc_check_all_any, NULL, gfc_resolve_any, + msk, BT_LOGICAL, dl, 0, dm, BT_INTEGER, ii, 1); + + make_generic ("any", GFC_ISYM_ANY); + + add_sym_1 ("asin", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_asin, gfc_resolve_asin, + x, BT_REAL, dr, 0); + + add_sym_1 ("dasin", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_asin, gfc_resolve_asin, + x, BT_REAL, dd, 0); + + make_generic ("asin", GFC_ISYM_ASIN); + + add_sym_2 ("associated", 0, 1, BT_LOGICAL, dl, + gfc_check_associated, NULL, NULL, + pt, BT_UNKNOWN, 0, 0, tg, BT_UNKNOWN, 0, 1); + + make_generic ("associated", GFC_ISYM_ASSOCIATED); + + add_sym_1 ("atan", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_atan, gfc_resolve_atan, + x, BT_REAL, dr, 0); + + add_sym_1 ("datan", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_atan, gfc_resolve_atan, + x, BT_REAL, dd, 0); + + make_generic ("atan", GFC_ISYM_ATAN); + + add_sym_2 ("atan2", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_atan2, gfc_resolve_atan2, + y, BT_REAL, dr, 0, x, BT_REAL, dr, 0); + + add_sym_2 ("datan2", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_atan2, gfc_resolve_atan2, + y, BT_REAL, dd, 0, x, BT_REAL, dd, 0); + + make_generic ("atan2", GFC_ISYM_ATAN2); + + add_sym_1 ("bit_size", 0, 1, BT_INTEGER, di, + gfc_check_i, gfc_simplify_bit_size, NULL, + i, BT_INTEGER, di, 0); + + make_generic ("bit_size", GFC_ISYM_NONE); + + add_sym_2 ("btest", 1, 1, BT_LOGICAL, dl, + gfc_check_btest, gfc_simplify_btest, gfc_resolve_btest, + i, BT_INTEGER, di, 0, pos, BT_INTEGER, di, 0); + + make_generic ("btest", GFC_ISYM_BTEST); + + add_sym_2 ("ceiling", 1, 1, BT_INTEGER, di, + gfc_check_a_ikind, gfc_simplify_ceiling, gfc_resolve_ceiling, + a, BT_REAL, dr, 0, kind, BT_INTEGER, di, 1); + + make_generic ("ceiling", GFC_ISYM_CEILING); + + add_sym_2 ("char", 1, 0, BT_CHARACTER, dc, + gfc_check_char, gfc_simplify_char, gfc_resolve_char, + i, BT_INTEGER, di, 0, kind, BT_INTEGER, di, 1); + + make_generic ("char", GFC_ISYM_CHAR); + + add_sym_3 ("cmplx", 1, 1, BT_COMPLEX, dz, + gfc_check_cmplx, gfc_simplify_cmplx, gfc_resolve_cmplx, + x, BT_UNKNOWN, dr, 0, y, BT_UNKNOWN, dr, 1, + kind, BT_INTEGER, di, 1); + + make_generic ("cmplx", GFC_ISYM_CMPLX); + + /* Making dcmplx a specific of cmplx causes cmplx to return a double + complex instead of the default complex. */ + + add_sym_2 ("dcmplx", 1, 1, BT_COMPLEX, dd, + gfc_check_dcmplx, gfc_simplify_dcmplx, gfc_resolve_dcmplx, + x, BT_REAL, dd, 0, y, BT_REAL, dd, 1); /* Extension */ + + make_generic ("dcmplx", GFC_ISYM_CMPLX); + + add_sym_1 ("conjg", 1, 1, BT_COMPLEX, dz, + NULL, gfc_simplify_conjg, gfc_resolve_conjg, + z, BT_COMPLEX, dz, 0); + + add_sym_1 ("dconjg", 1, 1, BT_COMPLEX, dd, NULL, gfc_simplify_conjg, gfc_resolve_conjg, z, BT_COMPLEX, dd, 0); /* Extension */ + + make_generic ("conjg", GFC_ISYM_CONJG); + + add_sym_1 ("cos", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_cos, gfc_resolve_cos, x, BT_REAL, dr, 0); + + add_sym_1 ("dcos", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_cos, gfc_resolve_cos, x, BT_REAL, dd, 0); + + add_sym_1 ("ccos", 1, 1, BT_COMPLEX, dz, + NULL, gfc_simplify_cos, gfc_resolve_cos, + x, BT_COMPLEX, dz, 0); + + add_sym_1 ("zcos", 1, 1, BT_COMPLEX, dd, NULL, gfc_simplify_cos, gfc_resolve_cos, x, BT_COMPLEX, dd, 0); /* Extension */ + + make_alias ("cdcos"); + + make_generic ("cos", GFC_ISYM_COS); + + add_sym_1 ("cosh", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_cosh, gfc_resolve_cosh, + x, BT_REAL, dr, 0); + + add_sym_1 ("dcosh", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_cosh, gfc_resolve_cosh, + x, BT_REAL, dd, 0); + + make_generic ("cosh", GFC_ISYM_COSH); + + add_sym_2 ("count", 0, 1, BT_INTEGER, di, + gfc_check_count, NULL, gfc_resolve_count, + msk, BT_LOGICAL, dl, 0, dm, BT_INTEGER, ii, 1); + + make_generic ("count", GFC_ISYM_COUNT); + + add_sym_3 ("cshift", 0, 1, BT_REAL, dr, + gfc_check_cshift, NULL, gfc_resolve_cshift, + ar, BT_REAL, dr, 0, sh, BT_INTEGER, di, 0, + dm, BT_INTEGER, ii, 1); + + make_generic ("cshift", GFC_ISYM_CSHIFT); + + add_sym_1 ("dble", 1, 1, BT_REAL, dd, + gfc_check_dble, gfc_simplify_dble, gfc_resolve_dble, + a, BT_REAL, dr, 0); + + make_generic ("dble", GFC_ISYM_DBLE); + + add_sym_1 ("digits", 0, 1, BT_INTEGER, di, + gfc_check_digits, gfc_simplify_digits, NULL, + x, BT_UNKNOWN, dr, 0); + + make_generic ("digits", GFC_ISYM_NONE); + + add_sym_2 ("dim", 1, 1, BT_REAL, dr, + gfc_check_a_p, gfc_simplify_dim, gfc_resolve_dim, + x, BT_UNKNOWN, dr, 0, y, BT_UNKNOWN, dr, 0); + + add_sym_2 ("idim", 1, 1, BT_INTEGER, di, + NULL, gfc_simplify_dim, gfc_resolve_dim, + x, BT_INTEGER, di, 0, y, BT_INTEGER, di, 0); + + add_sym_2 ("ddim", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_dim, gfc_resolve_dim, + x, BT_REAL, dd, 0, y, BT_REAL, dd, 0); + + make_generic ("dim", GFC_ISYM_DIM); + + add_sym_2 ("dot_product", 0, 1, BT_UNKNOWN, 0, + gfc_check_dot_product, NULL, gfc_resolve_dot_product, + va, BT_REAL, dr, 0, vb, BT_REAL, dr, 0); + + make_generic ("dot_product", GFC_ISYM_DOT_PRODUCT); + + add_sym_2 ("dprod", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_dprod, gfc_resolve_dprod, + x, BT_REAL, dr, 0, y, BT_REAL, dr, 0); + + make_generic ("dprod", GFC_ISYM_DPROD); + + add_sym_1 ("dreal", 1, 0, BT_REAL, dd, NULL, NULL, NULL, a, BT_COMPLEX, dd, 0); /* Extension */ + + make_generic ("dreal", GFC_ISYM_REAL); + + add_sym_4 ("eoshift", 0, 1, BT_REAL, dr, + gfc_check_eoshift, NULL, gfc_resolve_eoshift, + ar, BT_REAL, dr, 0, sh, BT_INTEGER, ii, 0, + bd, BT_REAL, dr, 1, dm, BT_INTEGER, ii, 1); + + make_generic ("eoshift", GFC_ISYM_EOSHIFT); + + add_sym_1 ("epsilon", 0, 1, BT_REAL, dr, + gfc_check_x, gfc_simplify_epsilon, NULL, + x, BT_REAL, dr, 0); + + make_generic ("epsilon", GFC_ISYM_NONE); + + add_sym_1 ("exp", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_exp, gfc_resolve_exp, x, BT_REAL, dr, 0); + + add_sym_1 ("dexp", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_exp, gfc_resolve_exp, x, BT_REAL, dd, 0); + + add_sym_1 ("cexp", 1, 1, BT_COMPLEX, dz, + NULL, gfc_simplify_exp, gfc_resolve_exp, + x, BT_COMPLEX, dz, 0); + + add_sym_1 ("zexp", 1, 1, BT_COMPLEX, dd, NULL, gfc_simplify_exp, gfc_resolve_exp, x, BT_COMPLEX, dd, 0); /* Extension */ + + make_alias ("cdexp"); + + make_generic ("exp", GFC_ISYM_EXP); + + add_sym_1 ("exponent", 1, 1, BT_INTEGER, di, + gfc_check_x, gfc_simplify_exponent, gfc_resolve_exponent, + x, BT_REAL, dr, 0); + + make_generic ("exponent", GFC_ISYM_EXPONENT); + + add_sym_2 ("floor", 1, 1, BT_INTEGER, di, + gfc_check_a_ikind, gfc_simplify_floor, gfc_resolve_floor, + a, BT_REAL, dr, 0, kind, BT_INTEGER, di, 1); + + make_generic ("floor", GFC_ISYM_FLOOR); + + add_sym_1 ("fraction", 1, 1, BT_REAL, dr, + gfc_check_x, gfc_simplify_fraction, gfc_resolve_fraction, + x, BT_REAL, dr, 0); + + make_generic ("fraction", GFC_ISYM_FRACTION); + + add_sym_1 ("huge", 0, 1, BT_REAL, dr, + gfc_check_huge, gfc_simplify_huge, NULL, + x, BT_UNKNOWN, dr, 0); + + make_generic ("huge", GFC_ISYM_NONE); + + add_sym_1 ("iachar", 1, 1, BT_INTEGER, di, + NULL, gfc_simplify_iachar, NULL, c, BT_CHARACTER, dc, 0); + + make_generic ("iachar", GFC_ISYM_IACHAR); + + add_sym_2 ("iand", 1, 1, BT_INTEGER, di, + gfc_check_iand, gfc_simplify_iand, gfc_resolve_iand, + i, BT_INTEGER, di, 0, j, BT_INTEGER, di, 0); + + make_generic ("iand", GFC_ISYM_IAND); + + add_sym_0 ("iargc", 1, 1, BT_INTEGER, di, NULL, NULL, NULL); /* Extension, takes no arguments */ + + add_sym_2 ("ibclr", 1, 1, BT_INTEGER, di, + gfc_check_ibclr, gfc_simplify_ibclr, gfc_resolve_ibclr, + i, BT_INTEGER, di, 0, pos, BT_INTEGER, di, 0); + + make_generic ("ibclr", GFC_ISYM_IBCLR); + + add_sym_3 ("ibits", 1, 1, BT_INTEGER, di, + gfc_check_ibits, gfc_simplify_ibits, gfc_resolve_ibits, + i, BT_INTEGER, di, 0, pos, BT_INTEGER, di, 0, + ln, BT_INTEGER, di, 0); + + make_generic ("ibits", GFC_ISYM_IBITS); + + add_sym_2 ("ibset", 1, 1, BT_INTEGER, di, + gfc_check_ibset, gfc_simplify_ibset, gfc_resolve_ibset, + i, BT_INTEGER, di, 0, pos, BT_INTEGER, di, 0); + + make_generic ("ibset", GFC_ISYM_IBSET); + + add_sym_1 ("ichar", 1, 0, BT_INTEGER, di, + NULL, gfc_simplify_ichar, gfc_resolve_ichar, + c, BT_CHARACTER, dc, 0); + + make_generic ("ichar", GFC_ISYM_ICHAR); + + add_sym_2 ("ieor", 1, 1, BT_INTEGER, di, + gfc_check_ieor, gfc_simplify_ieor, gfc_resolve_ieor, + i, BT_INTEGER, di, 0, j, BT_INTEGER, di, 0); + + make_generic ("ieor", GFC_ISYM_IEOR); + + add_sym_3 ("index", 1, 1, BT_INTEGER, di, + gfc_check_index, gfc_simplify_index, NULL, + stg, BT_CHARACTER, dc, 0, ssg, BT_CHARACTER, dc, 0, + bck, BT_LOGICAL, dl, 1); + + make_generic ("index", GFC_ISYM_INDEX); + + add_sym_2 ("int", 1, 1, BT_INTEGER, di, + gfc_check_int, gfc_simplify_int, gfc_resolve_int, + a, BT_REAL, dr, 0, kind, BT_INTEGER, di, 1); + + add_sym_1 ("ifix", 1, 0, BT_INTEGER, di, + NULL, gfc_simplify_ifix, NULL, a, BT_REAL, dr, 0); + + add_sym_1 ("idint", 1, 0, BT_INTEGER, di, + NULL, gfc_simplify_idint, NULL, a, BT_REAL, dd, 0); + + make_generic ("int", GFC_ISYM_INT); + + add_sym_2 ("ior", 1, 1, BT_INTEGER, di, + gfc_check_ior, gfc_simplify_ior, gfc_resolve_ior, + i, BT_INTEGER, di, 0, j, BT_INTEGER, di, 0); + + make_generic ("ior", GFC_ISYM_IOR); + + add_sym_2 ("ishft", 1, 1, BT_INTEGER, di, + gfc_check_ishft, gfc_simplify_ishft, gfc_resolve_ishft, + i, BT_INTEGER, di, 0, sh, BT_INTEGER, di, 0); + + make_generic ("ishft", GFC_ISYM_ISHFT); + + add_sym_3 ("ishftc", 1, 1, BT_INTEGER, di, + gfc_check_ishftc, gfc_simplify_ishftc, gfc_resolve_ishftc, + i, BT_INTEGER, di, 0, sh, BT_INTEGER, di, 0, + sz, BT_INTEGER, di, 1); + + make_generic ("ishftc", GFC_ISYM_ISHFTC); + + add_sym_1 ("kind", 0, 1, BT_INTEGER, di, + gfc_check_kind, gfc_simplify_kind, NULL, x, BT_REAL, dr, 0); + + make_generic ("kind", GFC_ISYM_NONE); + + add_sym_2 ("lbound", 0, 1, BT_INTEGER, di, + gfc_check_lbound, gfc_simplify_lbound, gfc_resolve_lbound, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, di, 1); + + make_generic ("lbound", GFC_ISYM_LBOUND); + + add_sym_1 ("len", 0, 1, BT_INTEGER, di, + NULL, gfc_simplify_len, gfc_resolve_len, + stg, BT_CHARACTER, dc, 0); + + make_generic ("len", GFC_ISYM_LEN); + + add_sym_1 ("len_trim", 1, 1, BT_INTEGER, di, + NULL, gfc_simplify_len_trim, gfc_resolve_len_trim, + stg, BT_CHARACTER, dc, 0); + + make_generic ("len_trim", GFC_ISYM_LEN_TRIM); + + add_sym_2 ("lge", 1, 0, BT_LOGICAL, dl, + NULL, gfc_simplify_lge, NULL, + sta, BT_CHARACTER, dc, 0, stb, BT_CHARACTER, dc, 0); + + make_generic ("lge", GFC_ISYM_LGE); + + add_sym_2 ("lgt", 1, 0, BT_LOGICAL, dl, + NULL, gfc_simplify_lgt, NULL, + sta, BT_CHARACTER, dc, 0, stb, BT_CHARACTER, dc, 0); + + make_generic ("lgt", GFC_ISYM_LGT); + + add_sym_2 ("lle", 1, 0, BT_LOGICAL, dl, + NULL, gfc_simplify_lle, NULL, + sta, BT_CHARACTER, dc, 0, stb, BT_CHARACTER, dc, 0); + + make_generic ("lle", GFC_ISYM_LLE); + + add_sym_2 ("llt", 1, 0, BT_LOGICAL, dl, + NULL, gfc_simplify_llt, NULL, + sta, BT_CHARACTER, dc, 0, stb, BT_CHARACTER, dc, 0); + + make_generic ("llt", GFC_ISYM_LLT); + + add_sym_1 ("log", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_log, gfc_resolve_log, x, BT_REAL, dr, 0); + + add_sym_1 ("alog", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_log, gfc_resolve_log, x, BT_REAL, dr, 0); + + add_sym_1 ("dlog", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_log, gfc_resolve_log, x, BT_REAL, dd, 0); + + add_sym_1 ("clog", 1, 1, BT_COMPLEX, dz, + NULL, gfc_simplify_log, gfc_resolve_log, + x, BT_COMPLEX, dz, 0); + + add_sym_1 ("zlog", 1, 1, BT_COMPLEX, dd, NULL, gfc_simplify_log, gfc_resolve_log, x, BT_COMPLEX, dd, 0); /* Extension */ + + make_alias ("cdlog"); + + make_generic ("log", GFC_ISYM_LOG); + + add_sym_1 ("log10", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_log10, gfc_resolve_log10, + x, BT_REAL, dr, 0); + + add_sym_1 ("alog10", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_log10, gfc_resolve_log10, + x, BT_REAL, dr, 0); + + add_sym_1 ("dlog10", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_log10, gfc_resolve_log10, + x, BT_REAL, dd, 0); + + make_generic ("log10", GFC_ISYM_LOG10); + + add_sym_2 ("logical", 0, 1, BT_LOGICAL, dl, + gfc_check_logical, gfc_simplify_logical, gfc_resolve_logical, + l, BT_LOGICAL, dl, 0, kind, BT_INTEGER, di, 1); + + make_generic ("logical", GFC_ISYM_LOGICAL); + + add_sym_2 ("matmul", 0, 1, BT_REAL, dr, + gfc_check_matmul, NULL, gfc_resolve_matmul, + ma, BT_REAL, dr, 0, mb, BT_REAL, dr, 0); + + make_generic ("matmul", GFC_ISYM_MATMUL); + + /* Note: amax0 is equivalent to real(max), max1 is equivalent to + int(max). The max function must take at least two arguments. */ + + add_sym_1m ("max", 1, 0, BT_UNKNOWN, 0, + gfc_check_min_max, gfc_simplify_max, gfc_resolve_max, + a1, BT_UNKNOWN, dr, 0, a2, BT_UNKNOWN, dr, 0); + + add_sym_1m ("max0", 1, 0, BT_INTEGER, di, + gfc_check_min_max_integer, gfc_simplify_max, NULL, + a1, BT_INTEGER, di, 0, a2, BT_INTEGER, di, 0); + + add_sym_1m ("amax0", 1, 0, BT_REAL, dr, + gfc_check_min_max_integer, gfc_simplify_max, NULL, + a1, BT_INTEGER, di, 0, a2, BT_INTEGER, di, 0); + + add_sym_1m ("amax1", 1, 0, BT_REAL, dr, + gfc_check_min_max_real, gfc_simplify_max, NULL, + a1, BT_REAL, dr, 0, a2, BT_REAL, dr, 0); + + add_sym_1m ("max1", 1, 0, BT_INTEGER, di, + gfc_check_min_max_real, gfc_simplify_max, NULL, + a1, BT_REAL, dr, 0, a2, BT_REAL, dr, 0); + + add_sym_1m ("dmax1", 1, 0, BT_REAL, dd, + gfc_check_min_max_double, gfc_simplify_max, NULL, + a1, BT_REAL, dd, 0, a2, BT_REAL, dd, 0); + + make_generic ("max", GFC_ISYM_MAX); + + add_sym_1 ("maxexponent", 0, 1, BT_INTEGER, di, + gfc_check_x, gfc_simplify_maxexponent, NULL, + x, BT_UNKNOWN, dr, 0); + + make_generic ("maxexponent", GFC_ISYM_NONE); + + add_sym_3 ("maxloc", 0, 1, BT_INTEGER, di, + gfc_check_minloc_maxloc, NULL, gfc_resolve_maxloc, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1, + msk, BT_LOGICAL, dl, 1); + + make_generic ("maxloc", GFC_ISYM_MAXLOC); + + add_sym_3 ("maxval", 0, 1, BT_REAL, dr, + gfc_check_minval_maxval, NULL, gfc_resolve_maxval, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1, + msk, BT_LOGICAL, dl, 1); + + make_generic ("maxval", GFC_ISYM_MAXVAL); + + add_sym_3 ("merge", 1, 1, BT_REAL, dr, + gfc_check_merge, NULL, gfc_resolve_merge, + ts, BT_REAL, dr, 0, fs, BT_REAL, dr, 0, + msk, BT_LOGICAL, dl, 0); + + make_generic ("merge", GFC_ISYM_MERGE); + + /* Note: amin0 is equivalent to real(min), min1 is equivalent to int(min). */ + + add_sym_1m ("min", 1, 0, BT_UNKNOWN, 0, + gfc_check_min_max, gfc_simplify_min, gfc_resolve_min, + a1, BT_REAL, dr, 0, a2, BT_REAL, dr, 0); + + add_sym_1m ("min0", 1, 0, BT_INTEGER, di, + gfc_check_min_max_integer, gfc_simplify_min, NULL, + a1, BT_INTEGER, di, 0, a2, BT_INTEGER, di, 0); + + add_sym_1m ("amin0", 1, 0, BT_REAL, dr, + gfc_check_min_max_integer, gfc_simplify_min, NULL, + a1, BT_INTEGER, di, 0, a2, BT_INTEGER, di, 0); + + add_sym_1m ("amin1", 1, 0, BT_REAL, dr, + gfc_check_min_max_real, gfc_simplify_min, NULL, + a1, BT_REAL, dr, 0, a2, BT_REAL, dr, 0); + + add_sym_1m ("min1", 1, 0, BT_INTEGER, di, + gfc_check_min_max_real, gfc_simplify_min, NULL, + a1, BT_REAL, dr, 0, a2, BT_REAL, dr, 0); + + add_sym_1m ("dmin1", 1, 0, BT_REAL, dd, + gfc_check_min_max_double, gfc_simplify_min, NULL, + a1, BT_REAL, dd, 0, a2, BT_REAL, dd, 0); + + make_generic ("min", GFC_ISYM_MIN); + + add_sym_1 ("minexponent", 0, 1, BT_INTEGER, di, + gfc_check_x, gfc_simplify_minexponent, NULL, + x, BT_UNKNOWN, dr, 0); + + make_generic ("minexponent", GFC_ISYM_NONE); + + add_sym_3 ("minloc", 0, 1, BT_INTEGER, di, + gfc_check_minloc_maxloc, NULL, gfc_resolve_minloc, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1, + msk, BT_LOGICAL, dl, 1); + + make_generic ("minloc", GFC_ISYM_MINLOC); + + add_sym_3 ("minval", 0, 1, BT_REAL, dr, + gfc_check_minval_maxval, NULL, gfc_resolve_minval, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1, + msk, BT_LOGICAL, dl, 1); + + make_generic ("minval", GFC_ISYM_MINVAL); + + add_sym_2 ("mod", 1, 1, BT_INTEGER, di, + gfc_check_a_p, gfc_simplify_mod, gfc_resolve_mod, + a, BT_INTEGER, di, 0, p, BT_INTEGER, di, 0); + + add_sym_2 ("amod", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_mod, gfc_resolve_mod, + a, BT_REAL, dr, 0, p, BT_REAL, dr, 0); + + add_sym_2 ("dmod", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_mod, gfc_resolve_mod, + a, BT_REAL, dd, 0, p, BT_REAL, dd, 0); + + make_generic ("mod", GFC_ISYM_MOD); + + add_sym_2 ("modulo", 1, 1, BT_REAL, di, + gfc_check_a_p, gfc_simplify_modulo, gfc_resolve_modulo, + a, BT_REAL, di, 0, p, BT_REAL, di, 0); + + make_generic ("modulo", GFC_ISYM_MODULO); + + add_sym_2 ("nearest", 1, 1, BT_REAL, dr, + gfc_check_nearest, gfc_simplify_nearest, NULL, + x, BT_REAL, dr, 0, s, BT_REAL, dr, 0); + + make_generic ("nearest", GFC_ISYM_NEAREST); + + add_sym_2 ("nint", 1, 1, BT_INTEGER, di, + gfc_check_a_ikind, gfc_simplify_nint, gfc_resolve_nint, + a, BT_REAL, dr, 0, kind, BT_INTEGER, di, 1); + + add_sym_1 ("idnint", 1, 1, BT_INTEGER, di, + gfc_check_idnint, gfc_simplify_idnint, gfc_resolve_idnint, + a, BT_REAL, dd, 0); + + make_generic ("nint", GFC_ISYM_NINT); + + add_sym_1 ("not", 1, 1, BT_INTEGER, di, + gfc_check_i, gfc_simplify_not, gfc_resolve_not, + i, BT_INTEGER, di, 0); + + make_generic ("not", GFC_ISYM_NOT); + + add_sym_1 ("null", 0, 1, BT_INTEGER, di, + gfc_check_null, gfc_simplify_null, NULL, + mo, BT_INTEGER, di, 1); + + make_generic ("null", GFC_ISYM_NONE); + + add_sym_3 ("pack", 0, 1, BT_REAL, dr, + gfc_check_pack, NULL, gfc_resolve_pack, + ar, BT_REAL, dr, 0, msk, BT_LOGICAL, dl, 0, + v, BT_REAL, dr, 1); + + make_generic ("pack", GFC_ISYM_PACK); + + add_sym_1 ("precision", 0, 1, BT_INTEGER, di, + gfc_check_precision, gfc_simplify_precision, NULL, + x, BT_UNKNOWN, 0, 0); + + make_generic ("precision", GFC_ISYM_NONE); + + add_sym_1 ("present", 0, 1, BT_LOGICAL, dl, + gfc_check_present, NULL, NULL, a, BT_REAL, dr, 0); + + make_generic ("present", GFC_ISYM_PRESENT); + + add_sym_3 ("product", 0, 1, BT_REAL, dr, + gfc_check_product, NULL, gfc_resolve_product, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1, + msk, BT_LOGICAL, dl, 1); + + make_generic ("product", GFC_ISYM_PRODUCT); + + add_sym_1 ("radix", 0, 1, BT_INTEGER, di, + gfc_check_radix, gfc_simplify_radix, NULL, + x, BT_UNKNOWN, 0, 0); + + make_generic ("radix", GFC_ISYM_NONE); + + add_sym_1 ("range", 0, 1, BT_INTEGER, di, + gfc_check_range, gfc_simplify_range, NULL, + x, BT_REAL, dr, 0); + + make_generic ("range", GFC_ISYM_NONE); + + add_sym_2 ("real", 1, 0, BT_REAL, dr, + gfc_check_real, gfc_simplify_real, gfc_resolve_real, + a, BT_UNKNOWN, dr, 0, kind, BT_INTEGER, di, 1); + + add_sym_1 ("float", 1, 0, BT_REAL, dr, + NULL, gfc_simplify_float, NULL, a, BT_INTEGER, di, 0); + + add_sym_1 ("sngl", 1, 0, BT_REAL, dr, + NULL, gfc_simplify_sngl, NULL, a, BT_REAL, dd, 0); + + make_generic ("real", GFC_ISYM_REAL); + + add_sym_2 ("repeat", 0, 1, BT_CHARACTER, dc, + gfc_check_repeat, gfc_simplify_repeat, gfc_resolve_repeat, + stg, BT_CHARACTER, dc, 0, n, BT_INTEGER, di, 0); + + make_generic ("repeat", GFC_ISYM_REPEAT); + + add_sym_4 ("reshape", 0, 1, BT_REAL, dr, + gfc_check_reshape, gfc_simplify_reshape, gfc_resolve_reshape, + src, BT_REAL, dr, 0, shp, BT_INTEGER, ii, 0, + pad, BT_REAL, dr, 1, ord, BT_INTEGER, ii, 1); + + make_generic ("reshape", GFC_ISYM_RESHAPE); + + add_sym_1 ("rrspacing", 1, 1, BT_REAL, dr, + gfc_check_x, gfc_simplify_rrspacing, gfc_resolve_rrspacing, + x, BT_REAL, dr, 0); + + make_generic ("rrspacing", GFC_ISYM_RRSPACING); + + add_sym_2 ("scale", 1, 1, BT_REAL, dr, + gfc_check_scale, gfc_simplify_scale, gfc_resolve_scale, + x, BT_REAL, dr, 0, i, BT_INTEGER, di, 0); + + make_generic ("scale", GFC_ISYM_SCALE); + + add_sym_3 ("scan", 1, 1, BT_INTEGER, di, + gfc_check_scan, gfc_simplify_scan, gfc_resolve_scan, + stg, BT_CHARACTER, dc, 0, set, BT_CHARACTER, dc, 0, + bck, BT_LOGICAL, dl, 1); + + make_generic ("scan", GFC_ISYM_SCAN); + + add_sym_1 ("selected_int_kind", 0, 1, BT_INTEGER, di, + NULL, gfc_simplify_selected_int_kind, NULL, + r, BT_INTEGER, di, 0); + + make_generic ("selected_int_kind", GFC_ISYM_SI_KIND); + + add_sym_2 ("selected_real_kind", 0, 1, BT_INTEGER, di, + gfc_check_selected_real_kind, gfc_simplify_selected_real_kind, + NULL, p, BT_INTEGER, di, 1, r, BT_INTEGER, di, 1); + + make_generic ("selected_real_kind", GFC_ISYM_SR_KIND); + + add_sym_2 ("set_exponent", 1, 1, BT_REAL, dr, + gfc_check_set_exponent, gfc_simplify_set_exponent, + gfc_resolve_set_exponent, + x, BT_REAL, dr, 0, i, BT_INTEGER, di, 0); + + make_generic ("set_exponent", GFC_ISYM_SET_EXPONENT); + + add_sym_1 ("shape", 0, 1, BT_INTEGER, di, + gfc_check_shape, gfc_simplify_shape, gfc_resolve_shape, + src, BT_REAL, dr, 0); + + make_generic ("shape", GFC_ISYM_SHAPE); + + add_sym_2 ("sign", 1, 1, BT_REAL, dr, + gfc_check_sign, gfc_simplify_sign, gfc_resolve_sign, + a, BT_REAL, dr, 0, b, BT_REAL, dr, 0); + + add_sym_2 ("isign", 1, 1, BT_INTEGER, di, + NULL, gfc_simplify_sign, gfc_resolve_sign, + a, BT_INTEGER, di, 0, b, BT_INTEGER, di, 0); + + add_sym_2 ("dsign", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_sign, gfc_resolve_sign, + a, BT_REAL, dd, 0, b, BT_REAL, dd, 0); + + make_generic ("sign", GFC_ISYM_SIGN); + + add_sym_1 ("sin", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_sin, gfc_resolve_sin, x, BT_REAL, dr, 0); + + add_sym_1 ("dsin", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_sin, gfc_resolve_sin, x, BT_REAL, dd, 0); + + add_sym_1 ("csin", 1, 1, BT_COMPLEX, dz, + NULL, gfc_simplify_sin, gfc_resolve_sin, + x, BT_COMPLEX, dz, 0); + + add_sym_1 ("zsin", 1, 1, BT_COMPLEX, dd, NULL, gfc_simplify_sin, gfc_resolve_sin, x, BT_COMPLEX, dd, 0); /* Extension */ + + make_alias ("cdsin"); + + make_generic ("sin", GFC_ISYM_SIN); + + add_sym_1 ("sinh", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_sinh, gfc_resolve_sinh, + x, BT_REAL, dr, 0); + + add_sym_1 ("dsinh", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_sinh, gfc_resolve_sinh, + x, BT_REAL, dd, 0); + + make_generic ("sinh", GFC_ISYM_SINH); + + add_sym_2 ("size", 0, 1, BT_INTEGER, di, + gfc_check_size, gfc_simplify_size, NULL, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1); + + make_generic ("size", GFC_ISYM_SIZE); + + add_sym_1 ("spacing", 1, 1, BT_REAL, dr, + gfc_check_x, gfc_simplify_spacing, gfc_resolve_spacing, + x, BT_REAL, dr, 0); + + make_generic ("spacing", GFC_ISYM_SPACING); + + add_sym_3 ("spread", 0, 1, BT_REAL, dr, + gfc_check_spread, NULL, gfc_resolve_spread, + src, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 0, + n, BT_INTEGER, di, 0); + + make_generic ("spread", GFC_ISYM_SPREAD); + + add_sym_1 ("sqrt", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_sqrt, gfc_resolve_sqrt, + x, BT_REAL, dr, 0); + + add_sym_1 ("dsqrt", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_sqrt, gfc_resolve_sqrt, + x, BT_REAL, dd, 0); + + add_sym_1 ("csqrt", 1, 1, BT_COMPLEX, dz, + NULL, gfc_simplify_sqrt, gfc_resolve_sqrt, + x, BT_COMPLEX, dz, 0); + + add_sym_1 ("zsqrt", 1, 1, BT_COMPLEX, dd, NULL, gfc_simplify_sqrt, gfc_resolve_sqrt, x, BT_COMPLEX, dd, 0); /* Extension */ + + make_alias ("cdsqrt"); + + make_generic ("sqrt", GFC_ISYM_SQRT); + + add_sym_3 ("sum", 0, 1, BT_UNKNOWN, 0, + gfc_check_sum, NULL, gfc_resolve_sum, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1, + msk, BT_LOGICAL, dl, 1); + + make_generic ("sum", GFC_ISYM_SUM); + + add_sym_1 ("tan", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_tan, gfc_resolve_tan, x, BT_REAL, dr, 0); + + add_sym_1 ("dtan", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_tan, gfc_resolve_tan, x, BT_REAL, dd, 0); + + make_generic ("tan", GFC_ISYM_TAN); + + add_sym_1 ("tanh", 1, 1, BT_REAL, dr, + NULL, gfc_simplify_tanh, gfc_resolve_tanh, + x, BT_REAL, dr, 0); + + add_sym_1 ("dtanh", 1, 1, BT_REAL, dd, + NULL, gfc_simplify_tanh, gfc_resolve_tanh, + x, BT_REAL, dd, 0); + + make_generic ("tanh", GFC_ISYM_TANH); + + add_sym_1 ("tiny", 0, 1, BT_REAL, dr, + gfc_check_x, gfc_simplify_tiny, NULL, x, BT_REAL, dr, 0); + + make_generic ("tiny", GFC_ISYM_NONE); + + add_sym_3 ("transfer", 0, 1, BT_REAL, dr, + gfc_check_transfer, NULL, gfc_resolve_transfer, + src, BT_REAL, dr, 0, mo, BT_REAL, dr, 0, + sz, BT_INTEGER, di, 1); + + make_generic ("transfer", GFC_ISYM_TRANSFER); + + add_sym_1 ("transpose", 0, 1, BT_REAL, dr, + gfc_check_transpose, NULL, gfc_resolve_transpose, + m, BT_REAL, dr, 0); + + make_generic ("transpose", GFC_ISYM_TRANSPOSE); + + add_sym_1 ("trim", 0, 1, BT_CHARACTER, dc, + gfc_check_trim, gfc_simplify_trim, gfc_resolve_trim, + stg, BT_CHARACTER, dc, 0); + + make_generic ("trim", GFC_ISYM_TRIM); + + add_sym_2 ("ubound", 0, 1, BT_INTEGER, di, + gfc_check_ubound, gfc_simplify_ubound, gfc_resolve_ubound, + ar, BT_REAL, dr, 0, dm, BT_INTEGER, ii, 1); + + make_generic ("ubound", GFC_ISYM_UBOUND); + + add_sym_3 ("unpack", 0, 1, BT_REAL, dr, + gfc_check_unpack, NULL, gfc_resolve_unpack, + v, BT_REAL, dr, 0, msk, BT_LOGICAL, dl, 0, + f, BT_REAL, dr, 0); + + make_generic ("unpack", GFC_ISYM_UNPACK); + + add_sym_3 ("verify", 1, 1, BT_INTEGER, di, + gfc_check_verify, gfc_simplify_verify, gfc_resolve_verify, + stg, BT_CHARACTER, dc, 0, set, BT_CHARACTER, dc, 0, + bck, BT_LOGICAL, dl, 1); + + make_generic ("verify", GFC_ISYM_VERIFY); +} + + + +/* Add intrinsic subroutines. */ + +static void +add_subroutines (void) +{ + /* Argument names as in the standard (to be used as argument keywords). */ + const char + *h = "harvest", *dt = "date", *vl = "values", *pt = "put", + *c = "count", *tm = "time", *tp = "topos", *gt = "get", + *t = "to", *zn = "zone", *fp = "frompos", *cm = "count_max", + *f = "from", *sz = "size", *ln = "len", *cr = "count_rate"; + + int di, dr, dc; + + di = gfc_default_integer_kind (); + dr = gfc_default_real_kind (); + dc = gfc_default_character_kind (); + + add_sym_0s ("abort", 1, NULL); + + add_sym_1s ("cpu_time", 0, 1, BT_UNKNOWN, 0, + gfc_check_cpu_time, NULL, gfc_resolve_cpu_time, + tm, BT_REAL, dr, 0); + + add_sym_4 ("date_and_time", 0, 1, BT_UNKNOWN, 0, + gfc_check_date_and_time, NULL, NULL, + dt, BT_CHARACTER, dc, 1, tm, BT_CHARACTER, dc, 1, + zn, BT_CHARACTER, dc, 1, vl, BT_INTEGER, di, 1); + + add_sym_2 ("getarg", 0, 1, BT_UNKNOWN, 0, + NULL, NULL, NULL, + c, BT_INTEGER, di, 0, vl, BT_CHARACTER, dc, 0); + /* Extension */ + + add_sym_5 ("mvbits", 1, 1, BT_UNKNOWN, 0, + gfc_check_mvbits, gfc_simplify_mvbits, NULL, + f, BT_INTEGER, di, 0, fp, BT_INTEGER, di, 0, + ln, BT_INTEGER, di, 0, t, BT_INTEGER, di, 0, + tp, BT_INTEGER, di, 0); + + add_sym_1s ("random_number", 0, 1, BT_UNKNOWN, 0, + gfc_check_random_number, NULL, gfc_resolve_random_number, + h, BT_REAL, dr, 0); + + add_sym_3 ("random_seed", 0, 1, BT_UNKNOWN, 0, + gfc_check_random_seed, NULL, NULL, + sz, BT_INTEGER, di, 1, pt, BT_INTEGER, di, 1, + gt, BT_INTEGER, di, 1); + + add_sym_3 ("system_clock", 0, 1, BT_UNKNOWN, 0, + NULL, NULL, NULL, + c, BT_INTEGER, di, 1, cr, BT_INTEGER, di, 1, + cm, BT_INTEGER, di, 1); +} + + +/* Add a function to the list of conversion symbols. */ + +static void +add_conv (bt from_type, int from_kind, bt to_type, int to_kind, + gfc_expr * (*simplify) (gfc_expr *, bt, int)) +{ + + gfc_typespec from, to; + gfc_intrinsic_sym *sym; + + if (sizing == SZ_CONVS) + { + nconv++; + return; + } + + gfc_clear_ts (&from); + from.type = from_type; + from.kind = from_kind; + + gfc_clear_ts (&to); + to.type = to_type; + to.kind = to_kind; + + sym = conversion + nconv; + + strcpy (sym->name, conv_name (&from, &to)); + strcpy (sym->lib_name, sym->name); + sym->simplify.cc = simplify; + sym->elemental = 1; + sym->ts = to; + sym->generic_id = GFC_ISYM_CONVERSION; + + nconv++; +} + + +/* Create gfc_intrinsic_sym nodes for all intrinsic conversion + functions by looping over the kind tables. */ + +static void +add_conversions (void) +{ + int i, j; + + /* Integer-Integer conversions. */ + for (i = 0; gfc_integer_kinds[i].kind != 0; i++) + for (j = 0; gfc_integer_kinds[j].kind != 0; j++) + { + if (i == j) + continue; + + add_conv (BT_INTEGER, gfc_integer_kinds[i].kind, + BT_INTEGER, gfc_integer_kinds[j].kind, gfc_convert_constant); + } + + /* Integer-Real/Complex conversions. */ + for (i = 0; gfc_integer_kinds[i].kind != 0; i++) + for (j = 0; gfc_real_kinds[j].kind != 0; j++) + { + add_conv (BT_INTEGER, gfc_integer_kinds[i].kind, + BT_REAL, gfc_real_kinds[j].kind, gfc_convert_constant); + + add_conv (BT_REAL, gfc_real_kinds[j].kind, + BT_INTEGER, gfc_integer_kinds[i].kind, gfc_convert_constant); + + add_conv (BT_INTEGER, gfc_integer_kinds[i].kind, + BT_COMPLEX, gfc_real_kinds[j].kind, gfc_convert_constant); + + add_conv (BT_COMPLEX, gfc_real_kinds[j].kind, + BT_INTEGER, gfc_integer_kinds[i].kind, gfc_convert_constant); + } + + /* Real/Complex - Real/Complex conversions. */ + for (i = 0; gfc_real_kinds[i].kind != 0; i++) + for (j = 0; gfc_real_kinds[j].kind != 0; j++) + { + if (i != j) + { + add_conv (BT_REAL, gfc_real_kinds[i].kind, + BT_REAL, gfc_real_kinds[j].kind, gfc_convert_constant); + + add_conv (BT_COMPLEX, gfc_real_kinds[i].kind, + BT_COMPLEX, gfc_real_kinds[j].kind, gfc_convert_constant); + } + + add_conv (BT_REAL, gfc_real_kinds[i].kind, + BT_COMPLEX, gfc_real_kinds[j].kind, gfc_convert_constant); + + add_conv (BT_COMPLEX, gfc_real_kinds[i].kind, + BT_REAL, gfc_real_kinds[j].kind, gfc_convert_constant); + } + + /* Logical/Logical kind conversion. */ + for (i = 0; gfc_logical_kinds[i].kind; i++) + for (j = 0; gfc_logical_kinds[j].kind; j++) + { + if (i == j) + continue; + + add_conv (BT_LOGICAL, gfc_logical_kinds[i].kind, + BT_LOGICAL, gfc_logical_kinds[j].kind, gfc_convert_constant); + } +} + + +/* Initialize the table of intrinsics. */ +void +gfc_intrinsic_init_1 (void) +{ + int i; + + nargs = nfunc = nsub = nconv = 0; + + /* Create a namespace to hold the resolved intrinsic symbols. */ + gfc_intrinsic_namespace = gfc_get_namespace (NULL); + + sizing = SZ_FUNCS; + add_functions (); + sizing = SZ_SUBS; + add_subroutines (); + sizing = SZ_CONVS; + add_conversions (); + + functions = gfc_getmem (sizeof (gfc_intrinsic_sym) * (nfunc + nsub) + + sizeof (gfc_intrinsic_arg) * nargs); + + next_sym = functions; + subroutines = functions + nfunc; + + conversion = gfc_getmem (sizeof (gfc_intrinsic_sym) * nconv); + + next_arg = ((gfc_intrinsic_arg *) (subroutines + nsub)) - 1; + + sizing = SZ_NOTHING; + nconv = 0; + + add_functions (); + add_subroutines (); + add_conversions (); + + /* Set the pure flag. All intrinsic functions are pure, and + intrinsic subroutines are pure if they are elemental. */ + + for (i = 0; i < nfunc; i++) + functions[i].pure = 1; + + for (i = 0; i < nsub; i++) + subroutines[i].pure = subroutines[i].elemental; +} + + +void +gfc_intrinsic_done_1 (void) +{ + gfc_free (functions); + gfc_free (conversion); + gfc_free_namespace (gfc_intrinsic_namespace); +} + + +/******** Subroutines to check intrinsic interfaces ***********/ + +/* Given a formal argument list, remove any NULL arguments that may + have been left behind by a sort against some formal argument list. */ + +static void +remove_nullargs (gfc_actual_arglist ** ap) +{ + gfc_actual_arglist *head, *tail, *next; + + tail = NULL; + + for (head = *ap; head; head = next) + { + next = head->next; + + if (head->expr == NULL) + { + head->next = NULL; + gfc_free_actual_arglist (head); + } + else + { + if (tail == NULL) + *ap = head; + else + tail->next = head; + + tail = head; + tail->next = NULL; + } + } + + if (tail == NULL) + *ap = NULL; +} + + +/* Given an actual arglist and a formal arglist, sort the actual + arglist so that its arguments are in a one-to-one correspondence + with the format arglist. Arguments that are not present are given + a blank gfc_actual_arglist structure. If something is obviously + wrong (say, a missing required argument) we abort sorting and + return FAILURE. */ + +static try +sort_actual (const char *name, gfc_actual_arglist ** ap, + gfc_intrinsic_arg * formal, locus * where) +{ + + gfc_actual_arglist *actual, *a; + gfc_intrinsic_arg *f; + + remove_nullargs (ap); + actual = *ap; + + for (f = formal; f; f = f->next) + f->actual = NULL; + + f = formal; + a = actual; + + if (f == NULL && a == NULL) /* No arguments */ + return SUCCESS; + + for (;;) + { /* Put the nonkeyword arguments in a 1:1 correspondence */ + if (f == NULL) + break; + if (a == NULL) + goto optional; + + if (a->name[0] != '\0') + goto keywords; + + f->actual = a; + + f = f->next; + a = a->next; + } + + if (a == NULL) + goto do_sort; + + gfc_error ("Too many arguments in call to '%s' at %L", name, where); + return FAILURE; + +keywords: + /* Associate the remaining actual arguments, all of which have + to be keyword arguments. */ + for (; a; a = a->next) + { + for (f = formal; f; f = f->next) + if (strcmp (a->name, f->name) == 0) + break; + + if (f == NULL) + { + gfc_error ("Can't find keyword named '%s' in call to '%s' at %L", + a->name, name, where); + return FAILURE; + } + + if (f->actual != NULL) + { + gfc_error ("Argument '%s' is appears twice in call to '%s' at %L", + f->name, name, where); + return FAILURE; + } + + f->actual = a; + } + +optional: + /* At this point, all unmatched formal args must be optional. */ + for (f = formal; f; f = f->next) + { + if (f->actual == NULL && f->optional == 0) + { + gfc_error ("Missing actual argument '%s' in call to '%s' at %L", + f->name, name, where); + return FAILURE; + } + } + +do_sort: + /* Using the formal argument list, string the actual argument list + together in a way that corresponds with the formal list. */ + actual = NULL; + + for (f = formal; f; f = f->next) + { + a = (f->actual == NULL) ? gfc_get_actual_arglist () : f->actual; + + if (actual == NULL) + *ap = a; + else + actual->next = a; + + actual = a; + } + actual->next = NULL; /* End the sorted argument list. */ + + return SUCCESS; +} + + +/* Compare an actual argument list with an intrinsic's formal argument + list. The lists are checked for agreement of type. We don't check + for arrayness here. */ + +static try +check_arglist (gfc_actual_arglist ** ap, gfc_intrinsic_sym * sym, + int error_flag) +{ + gfc_actual_arglist *actual; + gfc_intrinsic_arg *formal; + int i; + + formal = sym->formal; + actual = *ap; + + i = 0; + for (; formal; formal = formal->next, actual = actual->next, i++) + { + if (actual->expr == NULL) + continue; + + if (!gfc_compare_types (&formal->ts, &actual->expr->ts)) + { + if (error_flag) + gfc_error + ("Type of argument '%s' in call to '%s' at %L should be " + "%s, not %s", gfc_current_intrinsic_arg[i], + gfc_current_intrinsic, &actual->expr->where, + gfc_typename (&formal->ts), gfc_typename (&actual->expr->ts)); + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Given a pointer to an intrinsic symbol and an expression node that + represent the function call to that subroutine, figure out the type + of the result. This may involve calling a resolution subroutine. */ + +static void +resolve_intrinsic (gfc_intrinsic_sym * specific, gfc_expr * e) +{ + gfc_expr *a1, *a2, *a3, *a4, *a5; + gfc_actual_arglist *arg; + + if (specific->resolve.f1 == NULL) + { + if (e->value.function.name == NULL) + e->value.function.name = specific->lib_name; + + if (e->ts.type == BT_UNKNOWN) + e->ts = specific->ts; + return; + } + + arg = e->value.function.actual; + + /* At present only the iargc extension intrinsic takes no arguments, + and it doesn't need a resolution function, but this is here for + generality. */ + if (arg == NULL) + { + (*specific->resolve.f0) (e); + return; + } + + /* Special case hacks for MIN and MAX. */ + if (specific->resolve.f1m == gfc_resolve_max + || specific->resolve.f1m == gfc_resolve_min) + { + (*specific->resolve.f1m) (e, arg); + return; + } + + a1 = arg->expr; + arg = arg->next; + + if (arg == NULL) + { + (*specific->resolve.f1) (e, a1); + return; + } + + a2 = arg->expr; + arg = arg->next; + + if (arg == NULL) + { + (*specific->resolve.f2) (e, a1, a2); + return; + } + + a3 = arg->expr; + arg = arg->next; + + if (arg == NULL) + { + (*specific->resolve.f3) (e, a1, a2, a3); + return; + } + + a4 = arg->expr; + arg = arg->next; + + if (arg == NULL) + { + (*specific->resolve.f4) (e, a1, a2, a3, a4); + return; + } + + a5 = arg->expr; + arg = arg->next; + + if (arg == NULL) + { + (*specific->resolve.f5) (e, a1, a2, a3, a4, a5); + return; + } + + gfc_internal_error ("resolve_intrinsic(): Too many args for intrinsic"); +} + + +/* Given an intrinsic symbol node and an expression node, call the + simplification function (if there is one), perhaps replacing the + expression with something simpler. We return FAILURE on an error + of the simplification, SUCCESS if the simplification worked, even + if nothing has changed in the expression itself. */ + +static try +do_simplify (gfc_intrinsic_sym * specific, gfc_expr * e) +{ + gfc_expr *result, *a1, *a2, *a3, *a4, *a5; + gfc_actual_arglist *arg; + + /* Max and min require special handling due to the variable number + of args. */ + if (specific->simplify.f1 == gfc_simplify_min) + { + result = gfc_simplify_min (e); + goto finish; + } + + if (specific->simplify.f1 == gfc_simplify_max) + { + result = gfc_simplify_max (e); + goto finish; + } + + if (specific->simplify.f1 == NULL) + { + result = NULL; + goto finish; + } + + arg = e->value.function.actual; + + a1 = arg->expr; + arg = arg->next; + + if (specific->simplify.cc == gfc_convert_constant) + { + result = gfc_convert_constant (a1, specific->ts.type, specific->ts.kind); + goto finish; + } + + /* TODO: Warn if -pedantic and initialization expression and arg + types not integer or character */ + + if (arg == NULL) + result = (*specific->simplify.f1) (a1); + else + { + a2 = arg->expr; + arg = arg->next; + + if (arg == NULL) + result = (*specific->simplify.f2) (a1, a2); + else + { + a3 = arg->expr; + arg = arg->next; + + if (arg == NULL) + result = (*specific->simplify.f3) (a1, a2, a3); + else + { + a4 = arg->expr; + arg = arg->next; + + if (arg == NULL) + result = (*specific->simplify.f4) (a1, a2, a3, a4); + else + { + a5 = arg->expr; + arg = arg->next; + + if (arg == NULL) + result = (*specific->simplify.f5) (a1, a2, a3, a4, a5); + else + gfc_internal_error + ("do_simplify(): Too many args for intrinsic"); + } + } + } + } + +finish: + if (result == &gfc_bad_expr) + return FAILURE; + + if (result == NULL) + resolve_intrinsic (specific, e); /* Must call at run-time */ + else + { + result->where = e->where; + gfc_replace_expr (e, result); + } + + return SUCCESS; +} + + +/* Initialize the gfc_current_intrinsic_arg[] array for the benefit of + error messages. This subroutine returns FAILURE if a subroutine + has more than MAX_INTRINSIC_ARGS, in which case the actual argument + list cannot match any intrinsic. */ + +static void +init_arglist (gfc_intrinsic_sym * isym) +{ + gfc_intrinsic_arg *formal; + int i; + + gfc_current_intrinsic = isym->name; + + i = 0; + for (formal = isym->formal; formal; formal = formal->next) + { + if (i >= MAX_INTRINSIC_ARGS) + gfc_internal_error ("init_arglist(): too many arguments"); + gfc_current_intrinsic_arg[i++] = formal->name; + } +} + + +/* Given a pointer to an intrinsic symbol and an expression consisting + of a function call, see if the function call is consistent with the + intrinsic's formal argument list. Return SUCCESS if the expression + and intrinsic match, FAILURE otherwise. */ + +static try +check_specific (gfc_intrinsic_sym * specific, gfc_expr * expr, int error_flag) +{ + gfc_actual_arglist *arg, **ap; + int r; + try t; + + ap = &expr->value.function.actual; + + init_arglist (specific); + + /* Don't attempt to sort the argument list for min or max. */ + if (specific->check.f1m == gfc_check_min_max + || specific->check.f1m == gfc_check_min_max_integer + || specific->check.f1m == gfc_check_min_max_real + || specific->check.f1m == gfc_check_min_max_double) + return (*specific->check.f1m) (*ap); + + if (sort_actual (specific->name, ap, specific->formal, + &expr->where) == FAILURE) + return FAILURE; + + if (specific->check.f1 == NULL) + { + t = check_arglist (ap, specific, error_flag); + if (t == SUCCESS) + expr->ts = specific->ts; + } + else + t = do_check (specific, *ap); + + /* Check ranks for elemental intrinsics. */ + if (t == SUCCESS && specific->elemental) + { + r = 0; + for (arg = expr->value.function.actual; arg; arg = arg->next) + { + if (arg->expr == NULL || arg->expr->rank == 0) + continue; + if (r == 0) + { + r = arg->expr->rank; + continue; + } + + if (arg->expr->rank != r) + { + gfc_error + ("Ranks of arguments to elemental intrinsic '%s' differ " + "at %L", specific->name, &arg->expr->where); + return FAILURE; + } + } + } + + if (t == FAILURE) + remove_nullargs (ap); + + return t; +} + + +/* See if an intrinsic is one of the intrinsics we evaluate + as an extension. */ + +static int +gfc_init_expr_extensions (gfc_intrinsic_sym *isym) +{ + /* FIXME: This should be moved into the intrinsic definitions. */ + static const char * const init_expr_extensions[] = { + "digits", "epsilon", "huge", "kind", "maxexponent", "minexponent", + "precision", "present", "radix", "range", "selected_real_kind", + "tiny", NULL + }; + + int i; + + for (i = 0; init_expr_extensions[i]; i++) + if (strcmp (init_expr_extensions[i], isym->name) == 0) + return 0; + + return 1; +} + + +/* See if a function call corresponds to an intrinsic function call. + We return: + + MATCH_YES if the call corresponds to an intrinsic, simplification + is done if possible. + + MATCH_NO if the call does not correspond to an intrinsic + + MATCH_ERROR if the call corresponds to an intrinsic but there was an + error during the simplification process. + + The error_flag parameter enables an error reporting. */ + +match +gfc_intrinsic_func_interface (gfc_expr * expr, int error_flag) +{ + gfc_intrinsic_sym *isym, *specific; + gfc_actual_arglist *actual; + const char *name; + int flag; + + if (expr->value.function.isym != NULL) + return (do_simplify (expr->value.function.isym, expr) == FAILURE) + ? MATCH_ERROR : MATCH_YES; + + gfc_suppress_error = !error_flag; + flag = 0; + + for (actual = expr->value.function.actual; actual; actual = actual->next) + if (actual->expr != NULL) + flag |= (actual->expr->ts.type != BT_INTEGER + && actual->expr->ts.type != BT_CHARACTER); + + name = expr->symtree->n.sym->name; + + isym = specific = gfc_find_function (name); + if (isym == NULL) + { + gfc_suppress_error = 0; + return MATCH_NO; + } + + gfc_current_intrinsic_where = &expr->where; + + /* Bypass the generic list for min and max. */ + if (isym->check.f1m == gfc_check_min_max) + { + init_arglist (isym); + + if (gfc_check_min_max (expr->value.function.actual) == SUCCESS) + goto got_specific; + + gfc_suppress_error = 0; + return MATCH_NO; + } + + /* If the function is generic, check all of its specific + incarnations. If the generic name is also a specific, we check + that name last, so that any error message will correspond to the + specific. */ + gfc_suppress_error = 1; + + if (isym->generic) + { + for (specific = isym->specific_head; specific; + specific = specific->next) + { + if (specific == isym) + continue; + if (check_specific (specific, expr, 0) == SUCCESS) + goto got_specific; + } + } + + gfc_suppress_error = !error_flag; + + if (check_specific (isym, expr, error_flag) == FAILURE) + { + gfc_suppress_error = 0; + return MATCH_NO; + } + + specific = isym; + +got_specific: + expr->value.function.isym = specific; + gfc_intrinsic_symbol (expr->symtree->n.sym); + + if (do_simplify (specific, expr) == FAILURE) + { + gfc_suppress_error = 0; + return MATCH_ERROR; + } + + /* TODO: We should probably only allow elemental functions here. */ + flag |= (expr->ts.type != BT_INTEGER && expr->ts.type != BT_CHARACTER); + + gfc_suppress_error = 0; + if (pedantic && gfc_init_expr + && flag && gfc_init_expr_extensions (specific)) + { + if (gfc_notify_std (GFC_STD_GNU, "Extension: Evaluation of " + "nonstandard initialization expression at %L", &expr->where) + == FAILURE) + { + return MATCH_ERROR; + } + } + + return MATCH_YES; +} + + +/* See if a CALL statement corresponds to an intrinsic subroutine. + Returns MATCH_YES if the subroutine corresponds to an intrinsic, + MATCH_NO if not, and MATCH_ERROR if there was an error (but did + correspond). */ + +match +gfc_intrinsic_sub_interface (gfc_code * c, int error_flag) +{ + gfc_intrinsic_sym *isym; + const char *name; + + name = c->symtree->n.sym->name; + + isym = find_subroutine (name); + if (isym == NULL) + return MATCH_NO; + + gfc_suppress_error = !error_flag; + + init_arglist (isym); + + if (sort_actual (name, &c->ext.actual, isym->formal, &c->loc) == FAILURE) + goto fail; + + if (isym->check.f1 != NULL) + { + if (do_check (isym, c->ext.actual) == FAILURE) + goto fail; + } + else + { + if (check_arglist (&c->ext.actual, isym, 1) == FAILURE) + goto fail; + } + + /* The subroutine corresponds to an intrinsic. Allow errors to be + seen at this point. */ + gfc_suppress_error = 0; + + if (isym->resolve.s1 != NULL) + isym->resolve.s1 (c); + else + c->resolved_sym = gfc_get_intrinsic_sub_symbol (isym->lib_name); + + if (gfc_pure (NULL) && !isym->elemental) + { + gfc_error ("Subroutine call to intrinsic '%s' at %L is not PURE", name, + &c->loc); + return MATCH_ERROR; + } + + return MATCH_YES; + +fail: + gfc_suppress_error = 0; + return MATCH_NO; +} + + +/* Call gfc_convert_type() with warning enabled. */ + +try +gfc_convert_type (gfc_expr * expr, gfc_typespec * ts, int eflag) +{ + return gfc_convert_type_warn (expr, ts, eflag, 1); +} + + +/* Try to convert an expression (in place) from one type to another. + 'eflag' controls the behavior on error. + + The possible values are: + + 1 Generate a gfc_error() + 2 Generate a gfc_internal_error(). + + 'wflag' controls the warning related to conversion. */ + +try +gfc_convert_type_warn (gfc_expr * expr, gfc_typespec * ts, int eflag, + int wflag) +{ + gfc_intrinsic_sym *sym; + gfc_typespec from_ts; + locus old_where; + gfc_expr *new; + int rank; + + from_ts = expr->ts; /* expr->ts gets clobbered */ + + if (ts->type == BT_UNKNOWN) + goto bad; + + /* NULL and zero size arrays get their type here. */ + if (expr->expr_type == EXPR_NULL + || (expr->expr_type == EXPR_ARRAY + && expr->value.constructor == NULL)) + { + /* Sometimes the RHS acquire the type. */ + expr->ts = *ts; + return SUCCESS; + } + + if (expr->ts.type == BT_UNKNOWN) + goto bad; + + if (expr->ts.type == BT_DERIVED + && ts->type == BT_DERIVED + && gfc_compare_types (&expr->ts, ts)) + return SUCCESS; + + sym = find_conv (&expr->ts, ts); + if (sym == NULL) + goto bad; + + /* At this point, a conversion is necessary. A warning may be needed. */ + if (wflag && gfc_option.warn_conversion) + gfc_warning_now ("Conversion from %s to %s at %L", + gfc_typename (&from_ts), gfc_typename (ts), &expr->where); + + /* Insert a pre-resolved function call to the right function. */ + old_where = expr->where; + rank = expr->rank; + new = gfc_get_expr (); + *new = *expr; + + new = gfc_build_conversion (new); + new->value.function.name = sym->lib_name; + new->value.function.isym = sym; + new->where = old_where; + new->rank = rank; + + *expr = *new; + + gfc_free (new); + expr->ts = *ts; + + if (gfc_is_constant_expr (expr->value.function.actual->expr) + && do_simplify (sym, expr) == FAILURE) + { + + if (eflag == 2) + goto bad; + return FAILURE; /* Error already generated in do_simplify() */ + } + + return SUCCESS; + +bad: + if (eflag == 1) + { + gfc_error ("Can't convert %s to %s at %L", + gfc_typename (&from_ts), gfc_typename (ts), &expr->where); + return FAILURE; + } + + gfc_internal_error ("Can't convert %s to %s at %L", + gfc_typename (&from_ts), gfc_typename (ts), + &expr->where); + /* Not reached */ +} diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h new file mode 100644 index 00000000000..723d1051db1 --- /dev/null +++ b/gcc/fortran/intrinsic.h @@ -0,0 +1,314 @@ +/* Header file for intrinsics check, resolve and simplify function + prototypes. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught & Katherine Holcomb + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Expression returned when simplification fails. */ + +extern gfc_expr gfc_bad_expr; + + +/* Check functions. */ +try gfc_check_a_ikind (gfc_expr *, gfc_expr *); +try gfc_check_a_xkind (gfc_expr *, gfc_expr *); +try gfc_check_a_p (gfc_expr *, gfc_expr *); + +try gfc_check_abs (gfc_expr *); +try gfc_check_all_any (gfc_expr *, gfc_expr *); +try gfc_check_allocated (gfc_expr *); +try gfc_check_associated (gfc_expr *, gfc_expr *); +try gfc_check_btest (gfc_expr *, gfc_expr *); +try gfc_check_char (gfc_expr *, gfc_expr *); +try gfc_check_cmplx (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_count (gfc_expr *, gfc_expr *); +try gfc_check_cshift (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_dcmplx (gfc_expr *, gfc_expr *); +try gfc_check_dble (gfc_expr *); +try gfc_check_digits (gfc_expr *); +try gfc_check_dot_product (gfc_expr *, gfc_expr *); +try gfc_check_eoshift (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_huge (gfc_expr *); +try gfc_check_i (gfc_expr *); +try gfc_check_iand (gfc_expr *, gfc_expr *); +try gfc_check_ibclr (gfc_expr *, gfc_expr *); +try gfc_check_ibits (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_ibset (gfc_expr *, gfc_expr *); +try gfc_check_idnint (gfc_expr *); +try gfc_check_ieor (gfc_expr *, gfc_expr *); +try gfc_check_index (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_int (gfc_expr *, gfc_expr *); +try gfc_check_ior (gfc_expr *, gfc_expr *); +try gfc_check_ishft (gfc_expr *, gfc_expr *); +try gfc_check_ishftc (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_kind (gfc_expr *); +try gfc_check_lbound (gfc_expr *, gfc_expr *); +try gfc_check_logical (gfc_expr *, gfc_expr *); +try gfc_check_min_max (gfc_actual_arglist *); +try gfc_check_min_max_integer (gfc_actual_arglist *); +try gfc_check_min_max_real (gfc_actual_arglist *); +try gfc_check_min_max_double (gfc_actual_arglist *); +try gfc_check_matmul (gfc_expr *, gfc_expr *); +try gfc_check_merge (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_minloc_maxloc (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_minval_maxval (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_nearest (gfc_expr *, gfc_expr *); +try gfc_check_null (gfc_expr *); +try gfc_check_pack (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_precision (gfc_expr *); +try gfc_check_present (gfc_expr *); +try gfc_check_product (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_radix (gfc_expr *); +try gfc_check_range (gfc_expr *); +try gfc_check_real (gfc_expr *, gfc_expr *); +try gfc_check_repeat (gfc_expr *, gfc_expr *); +try gfc_check_reshape (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_scale (gfc_expr *, gfc_expr *); +try gfc_check_scan (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_selected_real_kind (gfc_expr *, gfc_expr *); +try gfc_check_set_exponent (gfc_expr *, gfc_expr *); +try gfc_check_shape (gfc_expr *); +try gfc_check_size (gfc_expr *, gfc_expr *); +try gfc_check_sign (gfc_expr *, gfc_expr *); +try gfc_check_spread (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_sum (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_transfer (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_transpose (gfc_expr *); +try gfc_check_trim (gfc_expr *); +try gfc_check_ubound (gfc_expr *, gfc_expr *); +try gfc_check_unpack (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_verify (gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_x (gfc_expr *); + + +/* Intrinsic subroutines. */ +try gfc_check_cpu_time (gfc_expr *); +try gfc_check_date_and_time (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +try gfc_check_mvbits (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *, + gfc_expr *); +try gfc_check_random_number (gfc_expr *); +try gfc_check_random_seed (gfc_expr *, gfc_expr *, gfc_expr *); + + +/* Simplification functions. */ +gfc_expr *gfc_simplify_abs (gfc_expr *); +gfc_expr *gfc_simplify_achar (gfc_expr *); +gfc_expr *gfc_simplify_acos (gfc_expr *); +gfc_expr *gfc_simplify_adjustl (gfc_expr *); +gfc_expr *gfc_simplify_adjustr (gfc_expr *); +gfc_expr *gfc_simplify_aimag (gfc_expr *); +gfc_expr *gfc_simplify_aint (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_dint (gfc_expr *); +gfc_expr *gfc_simplify_anint (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_dnint (gfc_expr *); +gfc_expr *gfc_simplify_asin (gfc_expr *); +gfc_expr *gfc_simplify_atan (gfc_expr *); +gfc_expr *gfc_simplify_atan2 (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_bit_size (gfc_expr *); +gfc_expr *gfc_simplify_btest (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ceiling (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_char (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_cmplx (gfc_expr *, gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_conjg (gfc_expr *); +gfc_expr *gfc_simplify_cos (gfc_expr *); +gfc_expr *gfc_simplify_cosh (gfc_expr *); +gfc_expr *gfc_simplify_dcmplx (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_dble (gfc_expr *); +gfc_expr *gfc_simplify_digits (gfc_expr *); +gfc_expr *gfc_simplify_dim (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_dprod (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_epsilon (gfc_expr *); +gfc_expr *gfc_simplify_exp (gfc_expr *); +gfc_expr *gfc_simplify_exponent (gfc_expr *); +gfc_expr *gfc_simplify_float (gfc_expr *); +gfc_expr *gfc_simplify_floor (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_fraction (gfc_expr *); +gfc_expr *gfc_simplify_huge (gfc_expr *); +gfc_expr *gfc_simplify_iachar (gfc_expr *); +gfc_expr *gfc_simplify_iand (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ibclr (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ibits (gfc_expr *, gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ibset (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ichar (gfc_expr *); +gfc_expr *gfc_simplify_ieor (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_index (gfc_expr *, gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_int (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ifix (gfc_expr *); +gfc_expr *gfc_simplify_idint (gfc_expr *); +gfc_expr *gfc_simplify_ior (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ishft (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_ishftc (gfc_expr *, gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_kind (gfc_expr *); +gfc_expr *gfc_simplify_lbound (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_len (gfc_expr *); +gfc_expr *gfc_simplify_len_trim (gfc_expr *); +gfc_expr *gfc_simplify_lge (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_lgt (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_lle (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_llt (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_log (gfc_expr *); +gfc_expr *gfc_simplify_log10 (gfc_expr *); +gfc_expr *gfc_simplify_logical (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_min (gfc_expr *); +gfc_expr *gfc_simplify_max (gfc_expr *); +gfc_expr *gfc_simplify_maxexponent (gfc_expr *); +gfc_expr *gfc_simplify_minexponent (gfc_expr *); +gfc_expr *gfc_simplify_mod (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_modulo (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_mvbits (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *, + gfc_expr *); +gfc_expr *gfc_simplify_nearest (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_nint (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_null (gfc_expr *); +gfc_expr *gfc_simplify_idnint (gfc_expr *); +gfc_expr *gfc_simplify_not (gfc_expr *); +gfc_expr *gfc_simplify_precision (gfc_expr *); +gfc_expr *gfc_simplify_radix (gfc_expr *); +gfc_expr *gfc_simplify_range (gfc_expr *); +gfc_expr *gfc_simplify_real (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_repeat (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_reshape (gfc_expr *, gfc_expr *, gfc_expr *, + gfc_expr *); +gfc_expr *gfc_simplify_rrspacing (gfc_expr *); +gfc_expr *gfc_simplify_scale (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_scan (gfc_expr *, gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_selected_int_kind (gfc_expr *); +gfc_expr *gfc_simplify_selected_real_kind (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_set_exponent (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_sign (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_shape (gfc_expr *); +gfc_expr *gfc_simplify_sin (gfc_expr *); +gfc_expr *gfc_simplify_sinh (gfc_expr *); +gfc_expr *gfc_simplify_size (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_sngl (gfc_expr *); +gfc_expr *gfc_simplify_spacing (gfc_expr *); +gfc_expr *gfc_simplify_sqrt (gfc_expr *); +gfc_expr *gfc_simplify_tan (gfc_expr *); +gfc_expr *gfc_simplify_tanh (gfc_expr *); +gfc_expr *gfc_simplify_tiny (gfc_expr *); +gfc_expr *gfc_simplify_trim (gfc_expr *); +gfc_expr *gfc_simplify_ubound (gfc_expr *, gfc_expr *); +gfc_expr *gfc_simplify_verify (gfc_expr *, gfc_expr *, gfc_expr *); + +/* Constant conversion simplification. */ +gfc_expr *gfc_convert_constant (gfc_expr *, bt, int); + + +/* Resolution functions. */ +void gfc_resolve_abs (gfc_expr *, gfc_expr *); +void gfc_resolve_acos (gfc_expr *, gfc_expr *); +void gfc_resolve_aimag (gfc_expr *, gfc_expr *); +void gfc_resolve_aint (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_dint (gfc_expr *, gfc_expr *); +void gfc_resolve_all (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_anint (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_dnint (gfc_expr *, gfc_expr *); +void gfc_resolve_any (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_asin (gfc_expr *, gfc_expr *); +void gfc_resolve_atan (gfc_expr *, gfc_expr *); +void gfc_resolve_atan2 (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_btest (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ceiling (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_char (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_cmplx (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_dcmplx (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_conjg (gfc_expr *, gfc_expr *); +void gfc_resolve_cos (gfc_expr *, gfc_expr *); +void gfc_resolve_cosh (gfc_expr *, gfc_expr *); +void gfc_resolve_count (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_cshift (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_dble (gfc_expr *, gfc_expr *); +void gfc_resolve_dim (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_dot_product (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_dprod (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_eoshift (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *, + gfc_expr *); +void gfc_resolve_exp (gfc_expr *, gfc_expr *); +void gfc_resolve_exponent (gfc_expr *, gfc_expr *); +void gfc_resolve_floor (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_fraction (gfc_expr *, gfc_expr *); +void gfc_resolve_iand (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ibclr (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ibits (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ibset (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ieor (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ichar (gfc_expr *, gfc_expr *); +void gfc_resolve_idnint (gfc_expr *, gfc_expr *); +void gfc_resolve_int (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ior (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ishft (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_ishftc (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_lbound (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_len (gfc_expr *, gfc_expr *); +void gfc_resolve_len_trim (gfc_expr *, gfc_expr *); +void gfc_resolve_log (gfc_expr *, gfc_expr *); +void gfc_resolve_log10 (gfc_expr *, gfc_expr *); +void gfc_resolve_logical (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_matmul (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_max (gfc_expr *, gfc_actual_arglist *); +void gfc_resolve_maxloc (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_maxval (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_merge (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_min (gfc_expr *, gfc_actual_arglist *); +void gfc_resolve_minloc (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_minval (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_mod (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_modulo (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_nint (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_not (gfc_expr *, gfc_expr *); +void gfc_resolve_pack (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_product (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_real (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_repeat (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_reshape (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *, + gfc_expr *); +void gfc_resolve_rrspacing (gfc_expr *, gfc_expr *); +void gfc_resolve_scale (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_scan (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_set_exponent (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_shape (gfc_expr *, gfc_expr *); +void gfc_resolve_sign (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_sin (gfc_expr *, gfc_expr *); +void gfc_resolve_sinh (gfc_expr *, gfc_expr *); +void gfc_resolve_spacing (gfc_expr *, gfc_expr *); +void gfc_resolve_spread (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_sqrt (gfc_expr *, gfc_expr *); +void gfc_resolve_sum (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_tan (gfc_expr *, gfc_expr *); +void gfc_resolve_tanh (gfc_expr *, gfc_expr *); +void gfc_resolve_transfer (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_transpose (gfc_expr *, gfc_expr *); +void gfc_resolve_trim (gfc_expr *, gfc_expr *); +void gfc_resolve_ubound (gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_unpack (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); +void gfc_resolve_verify (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); + + +/* Intrinsic subroutine resolution. */ +void gfc_resolve_cpu_time (gfc_code *); +void gfc_resolve_random_number (gfc_code *); + + +/* The mvbits() subroutine requires the most arguments: five. */ + +#define MAX_INTRINSIC_ARGS 5 + +extern char *gfc_current_intrinsic, + *gfc_current_intrinsic_arg[MAX_INTRINSIC_ARGS]; +extern locus *gfc_current_intrinsic_where; diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi new file mode 100644 index 00000000000..88330e1bda0 --- /dev/null +++ b/gcc/fortran/invoke.texi @@ -0,0 +1,656 @@ +@c Copyright (C) 2004 +@c Free Software Foundation, Inc. +@c This is part of the GFORTRAN manual. +@c For copying conditions, see the file gfortran.texi. + +@ignore +@c man begin COPYRIGHT +Copyright @copyright{} 2004 +Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.2 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``GNU General Public License'' and ``Funding +Free Software'', the Front-Cover texts being (a) (see below), and with +the Back-Cover Texts being (b) (see below). A copy of the license is +included in the gfdl(7) man page. + +(a) The FSF's Front-Cover Text is: + + A GNU Manual + +(b) The FSF's Back-Cover Text is: + + You have freedom to copy and modify this GNU Manual, like GNU + software. Copies published by the Free Software Foundation raise + funds for GNU development. +@c man end +@c Set file name and title for the man page. +@setfilename gfortran +@settitle GNU Fortran 95 compiler. +@c man begin SYNOPSIS +gfortran [@option{-c}|@option{-S}|@option{-E}] + [@option{-g}] [@option{-pg}] [@option{-O}@var{level}] + [@option{-W}@var{warn}@dots{}] [@option{-pedantic}] + [@option{-I}@var{dir}@dots{}] [@option{-L}@var{dir}@dots{}] + [@option{-D}@var{macro}[=@var{defn}]@dots{}] [@option{-U}@var{macro}] + [@option{-f}@var{option}@dots{}] + [@option{-m}@var{machine-option}@dots{}] + [@option{-o} @var{outfile}] @var{infile}@dots{} + +Only the most useful options are listed here; see below for the +remainder. +@c man end +@c man begin SEEALSO +gpl(7), gfdl(7), fsf-funding(7), +cpp(1), gcov(1), gcc(1), as(1), ld(1), gdb(1), adb(1), dbx(1), sdb(1) +and the Info entries for @file{gcc}, @file{cpp}, @file{gfortran}, @file{as}, +@file{ld}, @file{binutils} and @file{gdb}. +@c man end +@c man begin BUGS +For instructions on reporting bugs, see +@w{@uref{http://gcc.gnu.org/bugs.html}}. +@c man end +@c man begin AUTHOR +See the Info entry for @command{gfortran} for contributors to GCC and +GFORTRAN@. +@c man end +@end ignore + +@node Invoking GFORTRAN +@chapter GNU Fortran 95 Command Options +@cindex GNU Fortran 95 command options +@cindex command options +@cindex options, GNU Fortran 95 command + +@c man begin DESCRIPTION + +The @command{gfortran} command supports all the options supported by the +@command{gcc} command. Only options specific to gfortran are documented here. + +@xref{Invoking GCC,,GCC Command Options,gcc,Using the GNU Compiler +Collection (GCC)}, for information +on the non-Fortran-specific aspects of the @command{gcc} command (and, +therefore, the @command{gfortran} command). + +@cindex options, negative forms +@cindex negative forms of options +All @command{gcc} and @command{gfortran} options +are accepted both by @command{gfortran} and by @command{gcc} +(as well as any other drivers built at the same time, +such as @command{g++}), +since adding @command{gfortran} to the @command{gcc} distribution +enables acceptance of @command{gfortran} options +by all of the relevant drivers. + +In some cases, options have positive and negative forms; +the negative form of @option{-ffoo} would be @option{-fno-foo}. +This manual documents only one of these two forms, whichever +one is not the default. +@c man end + +@menu +* Option Summary:: Brief list of all @command{gfortran} options, + without explanations. +* Fortran Dialect Options:: Controlling the variant of Fortran language + compiled. +* Warning Options:: How picky should the compiler be? +* Debugging Options:: Symbol tables, measurements, and debugging dumps. +* Directory Options:: Where to find module files +* Code Gen Options:: Specifying conventions for function calls, data layout + and register usage. +* Environment Variables:: Env vars that affect GNU Fortran. +@end menu + +@node Option Summary +@section Option Summary + +@c man begin OPTIONS + +Here is a summary of all the options specific to GNU Fortran, grouped +by type. Explanations are in the following sections. + +@table @emph +@item Fortran Language Options +@xref{Fortran Dialect Options,,Options Controlling Fortran Dialect}. +@gccoptlist{ +-ffree-form -fno-fixed-form @gol +-fdollar-ok -fimplicit-none -fmax-identifier-length @gol +-std=@var{std} +-ffixed-line-length-@var{n} -ffixed-line-length-none @gol +-i8 -r8 -d8} + +@item Warning Options +@xref{Warning Options,,Options to Request or Suppress Warnings}. +@gccoptlist{ +-fsyntax-only -pedantic -pedantic-errors @gol +-w -Wall -Waliasing -Wconversion @gol +-Wimplicit-interface -Wsurprising -Wunused-labels @gol +-Wline-truncation @gol +-Werror -W} + +@item Debugging Options +@xref{Debugging Options,,Options for Debugging Your Program or GCC}. +@gccoptlist{ +-fdump-parse-tree} + +@item Directory Options +@xref{Directory Options,,Options for Directory Search}. +@gccoptlist{ +-I@var{dir} -M@var{dir}} + +@item Code Generation Options +@xref{Code Gen Options,,Options for Code Generation Conventions}. +@gccoptlist{ +-fno-underscoring -fno-second-underscore @gol +-fbounds-check -fmax-stack-var-size=@var{n} @gol +-fpackderived -frepack-arrays} +@end table + +@c man end + +@menu +* Fortran Dialect Options:: Controlling the variant of Fortran language + compiled. +* Warning Options:: How picky should the compiler be? +* Debugging Options:: Symbol tables, measurements, and debugging dumps. +* Directory Options:: Where to find module files +* Code Gen Options:: Specifying conventions for function calls, data layout + and register usage. +@end menu + +@node Fortran Dialect Options +@section Options Controlling Fortran Dialect +@cindex dialect options +@cindex language, dialect options +@cindex options, dialect + +The following options control the dialect of Fortran +that the compiler accepts: + +@table @gcctabopt +@cindex -ffree-form option +@cindex options, -ffree-form +@cindex -fno-fixed-form option +@cindex options, -fno-fixed-form +@cindex source file format +@cindex free form +@cindex fixed form +@cindex Source Form +@cindex Fortran 90, features +@item -ffree-form +@item -ffixed-form +Specify the layout used by the the source file. The tree form layout +was introduced in Fortran 90. Fixed form was traditionally used in +older Fortran programs. + +@cindex -fdollar-ok option +@cindex options, -fdollar-ok +@item -fdollar-ok +@cindex dollar sign +@cindex symbol names +@cindex character set +Allow @samp{$} as a valid character in a symbol name. + +@cindex -ffixed-line-length-@var{n} option +@cindex options, -ffixed-line-length-@var{n} +@item -ffixed-line-length-@var{n} +@cindex source file format +@cindex lines, length +@cindex length of source lines +@cindex fixed form +@cindex limits, lengths of source lines +Set column after which characters are ignored in typical fixed-form +lines in the source file, and through which spaces are assumed (as +if padded to that length) after the ends of short fixed-form lines. + +@cindex card image +@cindex extended-source option +Popular values for @var{n} include 72 (the +standard and the default), 80 (card image), and 132 (corresponds +to ``extended-source'' options in some popular compilers). +@var{n} may be @samp{none}, meaning that the entire line is meaningful +and that continued character constants never have implicit spaces appended +to them to fill out the line. +@option{-ffixed-line-length-0} means the same thing as +@option{-ffixed-line-length-none}. + +@cindex -fmax-identifier-length=@var{n} option +@cindex option -fmax-identifier-length=@var{n} +@item -fmax-identifier-length=@var{n} +Specify the maximum allowed identifier length. Typical values are +31 (Fortran 95) and 63 (Fortran 200x). + +@cindex -fimpicit-none option +@cindex options, -fimplicit-none +@item -fimplicit-none +Specify that no implicit typing is allowed, unless overridden by explicit +@samp{IMPLICIT} statements. This is the equivalent of adding +@samp{implicit none} to the start of every procedure. + +@cindex -std=@var{std} option +@cindex option, -std=@var{std} +@item -std=@var{std} +Conform to the specified standard. Allowed values for @var{std} are +@samp{gnu}, @samp{f95} and @samp{f90}. + +@cindex option, -i8 +@cindex -i8, option +@cindex option, -r8 +@cindex -r8, option +@cindex option, -d8 +@cindex -d8, option +@item -i8 +@item -r8 +@item -d8 +The @option{-i8} and @option{-j8} options set the default INTEGER and REAL +kinds to KIND=8. The @option{-d8} option is equivalent to specifying +both @option{-i8} and @option{-r8}. + +@end table + +@node Warning Options +@section Options to Request or Suppress Warnings +@cindex options, warnings +@cindex warnings, suppressing +@cindex messages, warning +@cindex suppressing warnings + +Warnings are diagnostic messages that report constructions which +are not inherently erroneous but which are risky or suggest there +might have been an error. + +You can request many specific warnings with options beginning @option{-W}, +for example @option{-Wimplicit} to request warnings on implicit +declarations. Each of these specific warning options also has a +negative form beginning @option{-Wno-} to turn off warnings; +for example, @option{-Wno-implicit}. This manual lists only one of the +two forms, whichever is not the default. + +These options control the amount and kinds of warnings produced by GNU +Fortran: + +@table @gcctabopt +@cindex syntax checking +@cindex -fsyntax-only option +@cindex options, -fsyntax-only +@item -fsyntax-only +Check the code for syntax errors, but don't do anything beyond that. + +@cindex -pedantic option +@cindex options, -pedantic +@item -pedantic +Issue warnings for uses of extensions to FORTRAN 95. +@option{-pedantic} also applies to C-language constructs where they +occur in GNU Fortran source files, such as use of @samp{\e} in a +character constant within a directive like @samp{#include}. + +Valid FORTRAN 95 programs should compile properly with or without +this option. +However, without this option, certain GNU extensions and traditional +Fortran features are supported as well. +With this option, many of them are rejected. + +Some users try to use @option{-pedantic} to check programs for conformance. +They soon find that it does not do quite what they want---it finds some +nonstandard practices, but not all. +However, improvements to @command{gfortran} in this area are welcome. + +This should be used in conjunction with -std=@var{std}. + +@cindex -pedantic-errors option +@cindex options, -pedantic-errors +@item -pedantic-errors +Like @option{-pedantic}, except that errors are produced rather than +warnings. + +@cindex -w option +@cindex options, -w +@item -w +Inhibit all warning messages. + + +@cindex -Wall option +@cindex options, -Wall +@item -Wall +@cindex all warnings +@cindex warnings, all +Enables commonly used warning options that which pertain to usage that +we recommend avoiding and that we believe is easy to avoid. +This currenly includes @option{-Wunused-labels}, @option{-Waliasing}, +@option{-Wsurprising} and @option{-Wline-truncation}. + + +@cindex -Waliasing option +@cindex options, -Waliasing +@item -Waliasing +@cindex aliasing +Warn about possible aliasing of dummy arguments. The following example +witll trigger teh warhing as it would be illegal to @code{bar} to +modify either parameter. +@smallexample + INTEGER A + CALL BAR(A,A) +@end smallexample + + +@cindex -Wconversion option +@cindex options, -Wconversion +@item -Wconversion +@cindex conversion +Warn about implicit conversions between different types. + + +@cindex -Wimplicit-interface option +@cindex options, -Wimplicit-interface +@item -Wimplicit-interface +Warn about when procedure are called without an explicit interface. +Note this only checks that an explicit interface is present. It does not +check that the declared interfaces are consistent across program units. + + +@cindex -Wsurprising +@cindex options, -Wsurprising +@item -Wsurprising +@cindex Suspicious +Produce a warning when ``suspicous'' code constructs are encountered. +While techically legal these usually indicate that an error has been made. + +This currently produces a warning under the following circumstances: + +@itemize @bullet +@item +An INTEGER SELECT construct has a CASE the can never be matched as it's +lower value that is greater than its upper value. + +@item +A LOGICAL SELECT construct has three CASE statements. +@end itemize + +@cindex -Wunused-labels option +@cindex options, -Wunused-labels +@item -Wunused-labels +@cindex unused labels +@cindex labels, unused +Warn whenever a label is defined but never referenced. + + +@cindex -Werror +@cindex options, -Werror +@item -Werror +Turns all warnings into errors. + + +@cindex -W option +@cindex options, -W +@item -W +@cindex extra warnings +@cindex warnings, extra +Turns on ``extra warnings'' and, if optimization is specified +via @option{-O}, the @option{-Wuninitialized} option. +(This might change in future versions of @command{gfortran} +@end table + +@xref{Warning Options,,Options to Request or Suppress Warnings, +gcc,Using the GNU Compiler Collection (GCC)}, for information on more +options offered by the GBE shared by @command{gfortran}, @command{gcc} and +other GNU compilers. + +Some of these have no effect when compiling programs written in Fortran. + +@node Debugging Options +@section Options for Debugging Your Program or GNU Fortran +@cindex options, debugging +@cindex debugging information options + +GNU Fortran has various special options that are used for debugging +either your program or @command{gfortran} + +@table @gcctabopt +@cindex -fdump-parse-tree option +@cindex option, -fdump-parse-tree +@item -fdump-parse-tree +Output the internal parse tree before starting code generation. Only +really usedful for debugging gfortran itself. +@end table + +@xref{Debugging Options,,Options for Debugging Your Program or GCC, +gcc,Using the GNU Compiler Collection (GCC)}, for more information on +debugging options. + +@node Directory Options +@section Options for Directory Search +@cindex directory, options +@cindex options, directory search +@cindex search path + +@cindex INCLUDE directive +@cindex directive, INCLUDE +There options affect how affect how @command{gfortran} searches +for files specified via the @code{INCLUDE} directive, and where it searches +for previously compiled modules. + +It also affects the search paths used by @command{cpp} when used to preprocess +fortran source. + +@table @gcctabopt +@cindex -Idir option +@cindex options, -Idir +@item -I@var{dir} +@cindex directory, search paths for inclusion +@cindex inclusion, directory search paths for +@cindex search paths, for included files +@cindex paths, search +@cindex module search path +These affect interpretation of the @code{INCLUDE} directive +(as well as of the @code{#include} directive of the @command{cpp} +preprocessor). + +Also note that the general behavior of @option{-I} and +@code{INCLUDE} is pretty much the same as of @option{-I} with +@code{#include} in the @command{cpp} preprocessor, with regard to +looking for @file{header.gcc} files and other such things. + +This path is also used to search for @samp{.mod} files when previously +compiled modules are required by a @code{USE} statement. + +@xref{Directory Options,,Options for Directory Search, +gcc,Using the GNU Compiler Collection (GCC)}, for information on the +@option{-I} option. + +@cindex -Mdir option +@cindex option, -Mdir +@item -M@var{dir} +@item -J@var{dir} +This option specifies where to put @samp{.mod} files for compiled modiles. +It is also added to the list of directories to searhed by an @code{USE} +statement. + +The default is the current directory. + +@option{-J} is an alias for @option{-M} to avoid conflicts with existing +GCC options. +@end table + +@node Code Gen Options +@section Options for Code Generation Conventions +@cindex code generation, conventions +@cindex options, code generation +@cindex run-time, options + +These machine-independent options control the interface conventions +used in code generation. + +Most of them have both positive and negative forms; the negative form +of @option{-ffoo} would be @option{-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 @option{no-} or adding +it. + + +@table @gcctabopt +@cindex -fno-underscoring option +@cindex options, -fno-underscoring +@item -fno-underscoring +@cindex underscore +@cindex symbol names, underscores +@cindex transforming symbol names +@cindex symbol names, transforming +Do not transform names of entities specified in the Fortran +source file by appending underscores to them. + +With @option{-funderscoring} in effect, @command{gfortran} appends two +underscores to names with underscores and one underscore to external names +with no underscores. (@command{gfortran} also appends two underscores to +internal names with underscores to avoid naming collisions with external +names. The @option{-fno-second-underscore} option disables appending of the +second underscore in all cases.) + +This is done to ensure compatibility with code produced by many +UNIX Fortran compilers, including @command{f2c} which perform the +same transformations. + +Use of @option{-fno-underscoring} is not recommended unless you are +experimenting with issues such as integration of (GNU) Fortran into +existing system environments (vis-a-vis existing libraries, tools, and +so on). + +For example, with @option{-funderscoring}, and assuming other defaults like +@option{-fcase-lower} and that @samp{j()} and @samp{max_count()} are +external functions while @samp{my_var} and @samp{lvar} are local variables, +a statement like + +@smallexample +I = J() + MAX_COUNT (MY_VAR, LVAR) +@end smallexample + +@noindent +is implemented as something akin to: + +@smallexample +i = j_() + max_count__(&my_var__, &lvar); +@end smallexample + +With @option{-fno-underscoring}, the same statement is implemented as: + +@smallexample +i = j() + max_count(&my_var, &lvar); +@end smallexample + +Use of @option{-fno-underscoring} allows direct specification of +user-defined names while debugging and when interfacing @command{gfortran} +code with other languages. + +Note that just because the names match does @emph{not} mean that the +interface implemented by @command{gfortran} for an external name matches the +interface implemented by some other language for that same name. +That is, getting code produced by @command{gfortran} to link to code produced +by some other compiler using this or any other method can be only a +small part of the overall solution---getting the code generated by +both compilers to agree on issues other than naming can require +significant effort, and, unlike naming disagreements, linkers normally +cannot detect disagreements in these other areas. + +Also, note that with @option{-fno-underscoring}, the lack of appended +underscores introduces the very real possibility that a user-defined +external name will conflict with a name in a system library, which +could make finding unresolved-reference bugs quite difficult in some +cases---they might occur at program run time, and show up only as +buggy behavior at run time. + +In future versions of @command{gfortran} we hope to improve naming and linking +issues so that debugging always involves using the names as they appear +in the source, even if the names as seen by the linker are mangled to +prevent accidental linking between procedures with incompatible +interfaces. + +@cindex -fno-second-underscore option +@cindex options, -fno-second-underscore +@item -fno-second-underscore +@cindex underscore +@cindex symbol names, underscores +@cindex transforming symbol names +@cindex symbol names, transforming +Do not append a second underscore to names of entities specified +in the Fortran source file. + +This option has no effect if @option{-fno-underscoring} is +in effect. + +Otherwise, with this option, an external name such as @samp{MAX_COUNT} +is implemented as a reference to the link-time external symbol +@samp{max_count_}, instead of @samp{max_count__}. + + +@cindex -fbounds-check option +@cindex -ffortran-bounds-check option +@item -fbounds-check +@cindex bounds checking +@cindex range checking +@cindex array bounds checking +@cindex subscript checking +@cindex checking subscripts +Enable generation of run-time checks for array subscripts +and against the declared minimum and maximum values. It also +checks array indices for assumed and deferred +shape arrays against the actual allocated bounds. + +In the future this may also include other forms of checking, eg. checing +substring references. + + +@cindex -fmax-stack-var-size option +@item -fmax-stack-var-size=@var{n} +This option specifies the size in bytes of the largest array that will be put +on the stack. + +This option currently only affects local arrays declared with constant +bounds, and may not apply to all character variables. +Future versions of @command{gfortran} may improve this behavior. + +The default value for @var{n} is 32768. + +@cindex -fpackderived +@item -fpackderived +@cindex Structure packing +This option tells gfortran to pack derived type members as closely as +possible. Code compiled with this option is likley to be incompatible +with code compiled without this option, and may execute slower. + +@cindex -frepack-arrays option +@item -frepack-arrays +@cindex Repacking arrays +In some circumstances @command{gfortran} may pass assumed shape array +sections via a descriptor describing a discontiguous area of memory. +This option adds code to the function prologue to repack the data into +a contiguous block at runtime. + +This should result in faster accesses to the array. However it can introduce +significant overhead to the function call, especially when the passed data +is discontiguous. +@end table + +@xref{Code Gen Options,,Options for Code Generation Conventions, +gcc,Using the GNU Compiler Collection (GCC)}, for information on more options +offered by the GBE +shared by @command{gfortran} @command{gcc} and other GNU compilers. + + +@c man end + +@node Environment Variables +@section Environment Variables Affecting GNU Fortran +@cindex environment variables + +@c man begin ENVIRONMENT + +GNU Fortran 95 currently does not make use of any environment +variables to control its operation above and beyond those +that affect the operation of @command{gcc}. + +@xref{Environment Variables,,Environment Variables Affecting GCC, +gcc,Using the GNU Compiler Collection (GCC)}, for information on environment +variables. + +@c man end diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c new file mode 100644 index 00000000000..5e7240d1622 --- /dev/null +++ b/gcc/fortran/io.c @@ -0,0 +1,2409 @@ +/* Deal with I/O statements & related stuff. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "flags.h" + +#include + +#include "gfortran.h" +#include "match.h" +#include "parse.h" + +gfc_st_label format_asterisk = + { -1, ST_LABEL_FORMAT, ST_LABEL_FORMAT, NULL, 0, + {NULL, 0, NULL, NULL}, NULL, NULL}; + +typedef struct +{ + const char *name, *spec; + bt type; +} +io_tag; + +static const io_tag + tag_file = { "FILE", " file = %e", BT_CHARACTER }, + tag_status = { "STATUS", " status = %e", BT_CHARACTER}, + tag_e_access = {"ACCESS", " access = %e", BT_CHARACTER}, + tag_e_form = {"FORM", " form = %e", BT_CHARACTER}, + tag_e_recl = {"RECL", " recl = %e", BT_INTEGER}, + tag_e_blank = {"BLANK", " blank = %e", BT_CHARACTER}, + tag_e_position = {"POSITION", " position = %e", BT_CHARACTER}, + tag_e_action = {"ACTION", " action = %e", BT_CHARACTER}, + tag_e_delim = {"DELIM", " delim = %e", BT_CHARACTER}, + tag_e_pad = {"PAD", " pad = %e", BT_CHARACTER}, + tag_unit = {"UNIT", " unit = %e", BT_INTEGER}, + tag_advance = {"ADVANCE", " advance = %e", BT_CHARACTER}, + tag_rec = {"REC", " rec = %e", BT_INTEGER}, + tag_format = {"FORMAT", NULL, BT_CHARACTER}, + tag_iostat = {"IOSTAT", " iostat = %v", BT_INTEGER}, + tag_size = {"SIZE", " size = %v", BT_INTEGER}, + tag_exist = {"EXIST", " exist = %v", BT_LOGICAL}, + tag_opened = {"OPENED", " opened = %v", BT_LOGICAL}, + tag_named = {"NAMED", " named = %v", BT_LOGICAL}, + tag_name = {"NAME", " name = %v", BT_CHARACTER}, + tag_number = {"NUMBER", " number = %v", BT_INTEGER}, + tag_s_access = {"ACCESS", " access = %v", BT_CHARACTER}, + tag_sequential = {"SEQUENTIAL", " sequential = %v", BT_CHARACTER}, + tag_direct = {"DIRECT", " direct = %v", BT_CHARACTER}, + tag_s_form = {"FORM", " form = %v", BT_CHARACTER}, + tag_formatted = {"FORMATTED", " formatted = %v", BT_CHARACTER}, + tag_unformatted = {"UNFORMATTED", " unformatted = %v", BT_CHARACTER}, + tag_s_recl = {"RECL", " recl = %v", BT_INTEGER}, + tag_nextrec = {"NEXTREC", " nextrec = %v", BT_INTEGER}, + tag_s_blank = {"BLANK", " blank = %v", BT_CHARACTER}, + tag_s_position = {"POSITION", " position = %v", BT_CHARACTER}, + tag_s_action = {"ACTION", " action = %v", BT_CHARACTER}, + tag_read = {"READ", " read = %v", BT_CHARACTER}, + tag_write = {"WRITE", " write = %v", BT_CHARACTER}, + tag_readwrite = {"READWRITE", " readwrite = %v", BT_CHARACTER}, + tag_s_delim = {"DELIM", " delim = %v", BT_CHARACTER}, + tag_s_pad = {"PAD", " pad = %v", BT_CHARACTER}, + tag_iolength = {"IOLENGTH", " iolength = %v", BT_INTEGER}, + tag_err = {"ERR", " err = %l", BT_UNKNOWN}, + tag_end = {"END", " end = %l", BT_UNKNOWN}, + tag_eor = {"EOR", " eor = %l", BT_UNKNOWN}; + +static gfc_dt *current_dt; + +#define RESOLVE_TAG(x, y) if (resolve_tag(x, y) == FAILURE) return FAILURE; + + +/**************** Fortran 95 FORMAT parser *****************/ + +/* FORMAT tokens returned by format_lex(). */ +typedef enum +{ + FMT_NONE, FMT_UNKNOWN, FMT_SIGNED_INT, FMT_ZERO, FMT_POSINT, FMT_PERIOD, + FMT_COMMA, FMT_COLON, FMT_SLASH, FMT_DOLLAR, FMT_POS, FMT_LPAREN, + FMT_RPAREN, FMT_X, FMT_SIGN, FMT_BLANK, FMT_CHAR, FMT_P, FMT_IBOZ, FMT_F, + FMT_E, FMT_EXT, FMT_G, FMT_L, FMT_A, FMT_D, FMT_H, FMT_END +} +format_token; + +/* Local variables for checking format strings. The saved_token is + used to back up by a single format token during the parsing + process. */ +static char *format_string; +static int format_length, use_last_char; + +static format_token saved_token; + +static enum +{ MODE_STRING, MODE_FORMAT, MODE_COPY } +mode; + + +/* Return the next character in the format string. */ + +static char +next_char (int in_string) +{ + static char c; + + if (use_last_char) + { + use_last_char = 0; + return c; + } + + format_length++; + + if (mode == MODE_STRING) + c = *format_string++; + else + { + c = gfc_next_char_literal (in_string); + if (c == '\n') + c = '\0'; + + if (mode == MODE_COPY) + *format_string++ = c; + } + + c = TOUPPER (c); + return c; +} + + +/* Back up one character position. Only works once. */ + +static void +unget_char (void) +{ + + use_last_char = 1; +} + +static int value = 0; + +/* Simple lexical analyzer for getting the next token in a FORMAT + statement. */ + +static format_token +format_lex (void) +{ + format_token token; + char c, delim; + int zflag; + int negative_flag; + + if (saved_token != FMT_NONE) + { + token = saved_token; + saved_token = FMT_NONE; + return token; + } + + do + { + c = next_char (0); + } + while (gfc_is_whitespace (c)); + + negative_flag = 0; + switch (c) + { + case '-': + negative_flag = 1; + case '+': + c = next_char (0); + if (!ISDIGIT (c)) + { + token = FMT_UNKNOWN; + break; + } + + value = c - '0'; + + do + { + c = next_char (0); + if(ISDIGIT (c)) + value = 10 * value + c - '0'; + } + while (ISDIGIT (c)); + + unget_char (); + + if (negative_flag) + value = -value; + + token = FMT_SIGNED_INT; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + zflag = (c == '0'); + + value = c - '0'; + + do + { + c = next_char (0); + if (c != '0') + zflag = 0; + if (ISDIGIT (c)) + value = 10 * value + c - '0'; + } + while (ISDIGIT (c)); + + unget_char (); + token = zflag ? FMT_ZERO : FMT_POSINT; + break; + + case '.': + token = FMT_PERIOD; + break; + + case ',': + token = FMT_COMMA; + break; + + case ':': + token = FMT_COLON; + break; + + case '/': + token = FMT_SLASH; + break; + + case '$': + token = FMT_DOLLAR; + break; + + case 'T': + c = next_char (0); + if (c != 'L' && c != 'R') + unget_char (); + + token = FMT_POS; + break; + + case '(': + token = FMT_LPAREN; + break; + + case ')': + token = FMT_RPAREN; + break; + + case 'X': + token = FMT_X; + break; + + case 'S': + c = next_char (0); + if (c != 'P' && c != 'S') + unget_char (); + + token = FMT_SIGN; + break; + + case 'B': + c = next_char (0); + if (c == 'N' || c == 'Z') + token = FMT_BLANK; + else + { + unget_char (); + token = FMT_IBOZ; + } + + break; + + case '\'': + case '"': + delim = c; + + value = 0; + + for (;;) + { + c = next_char (1); + if (c == '\0') + { + token = FMT_END; + break; + } + + if (c == delim) + { + c = next_char (1); + + if (c == '\0') + { + token = FMT_END; + break; + } + + if (c != delim) + { + unget_char (); + token = FMT_CHAR; + break; + } + } + value++; + } + break; + + case 'P': + token = FMT_P; + break; + + case 'I': + case 'O': + case 'Z': + token = FMT_IBOZ; + break; + + case 'F': + token = FMT_F; + break; + + case 'E': + c = next_char (0); + if (c == 'N' || c == 'S') + token = FMT_EXT; + else + { + token = FMT_E; + unget_char (); + } + + break; + + case 'G': + token = FMT_G; + break; + + case 'H': + token = FMT_H; + break; + + case 'L': + token = FMT_L; + break; + + case 'A': + token = FMT_A; + break; + + case 'D': + token = FMT_D; + break; + + case '\0': + token = FMT_END; + break; + + default: + token = FMT_UNKNOWN; + break; + } + + return token; +} + + +/* Check a format statement. The format string, either from a FORMAT + statement or a constant in an I/O statement has already been parsed + by itself, and we are checking it for validity. The dual origin + means that the warning message is a little less than great. */ + +static try +check_format (void) +{ + const char *posint_required = "Positive width required"; + const char *period_required = "Period required"; + const char *nonneg_required = "Nonnegative width required"; + const char *unexpected_element = "Unexpected element"; + const char *unexpected_end = "Unexpected end of format string"; + + const char *error; + format_token t, u; + int level; + int repeat; + try rv; + + use_last_char = 0; + saved_token = FMT_NONE; + level = 0; + repeat = 0; + rv = SUCCESS; + + t = format_lex (); + if (t != FMT_LPAREN) + { + error = "Missing leading left parenthesis"; + goto syntax; + } + + t = format_lex (); + if (t == FMT_RPAREN) + goto finished; /* Empty format is legal */ + saved_token = t; + +format_item: + /* In this state, the next thing has to be a format item. */ + t = format_lex (); + switch (t) + { + case FMT_POSINT: + repeat = value; + t = format_lex (); + if (t == FMT_LPAREN) + { + level++; + goto format_item; + } + + if (t == FMT_SLASH) + goto optional_comma; + + goto data_desc; + + case FMT_LPAREN: + level++; + goto format_item; + + case FMT_SIGNED_INT: + /* Signed integer can only precede a P format. */ + t = format_lex (); + if (t != FMT_P) + { + error = "Expected P edit descriptor"; + goto syntax; + } + + goto data_desc; + + case FMT_P: + /* P and X require a prior number. */ + error = "P descriptor requires leading scale factor"; + goto syntax; + + case FMT_X: + error = "X descriptor requires leading space count"; + goto syntax; + + case FMT_SIGN: + case FMT_BLANK: + case FMT_CHAR: + goto between_desc; + + case FMT_COLON: + case FMT_SLASH: + goto optional_comma; + + case FMT_DOLLAR: + t = format_lex (); + if (t != FMT_RPAREN || level > 0) + { + error = "$ must the last specifier"; + goto syntax; + } + + goto finished; + + case FMT_POS: + case FMT_IBOZ: + case FMT_F: + case FMT_E: + case FMT_EXT: + case FMT_G: + case FMT_L: + case FMT_A: + case FMT_D: + goto data_desc; + + case FMT_H: + goto data_desc; + + case FMT_END: + error = unexpected_end; + goto syntax; + + default: + error = unexpected_element; + goto syntax; + } + +data_desc: + /* In this state, t must currently be a data descriptor. + Deal with things that can/must follow the descriptor. */ + switch (t) + { + case FMT_SIGN: + case FMT_BLANK: + case FMT_X: + break; + + case FMT_P: + if (pedantic) + { + t = format_lex (); + if (t == FMT_POSINT) + { + error = "Repeat count cannot follow P descriptor"; + goto syntax; + } + + saved_token = t; + } + + goto optional_comma; + + case FMT_POS: + case FMT_L: + t = format_lex (); + if (t == FMT_POSINT) + break; + + error = posint_required; + goto syntax; + + case FMT_A: + t = format_lex (); + if (t != FMT_POSINT) + saved_token = t; + break; + + case FMT_D: + case FMT_E: + case FMT_G: + case FMT_EXT: + u = format_lex (); + if (u != FMT_POSINT) + { + error = posint_required; + goto syntax; + } + + u = format_lex (); + if (u != FMT_PERIOD) + { + error = period_required; + goto syntax; + } + + u = format_lex (); + if (u != FMT_ZERO && u != FMT_POSINT) + { + error = nonneg_required; + goto syntax; + } + + if (t == FMT_D) + break; + + /* Look for optional exponent. */ + u = format_lex (); + if (u != FMT_E) + { + saved_token = u; + } + else + { + u = format_lex (); + if (u != FMT_POSINT) + { + error = "Positive exponent width required"; + goto syntax; + } + } + + break; + + case FMT_F: + t = format_lex (); + if (t != FMT_ZERO && t != FMT_POSINT) + { + error = nonneg_required; + goto syntax; + } + + t = format_lex (); + if (t != FMT_PERIOD) + { + error = period_required; + goto syntax; + } + + t = format_lex (); + if (t != FMT_ZERO && t != FMT_POSINT) + { + error = nonneg_required; + goto syntax; + } + + break; + + case FMT_H: + if(mode == MODE_STRING) + { + format_string += value; + format_length -= value; + } + else + { + while(repeat >0) + { + next_char(0); + repeat -- ; + } + } + break; + + case FMT_IBOZ: + t = format_lex (); + if (t != FMT_ZERO && t != FMT_POSINT) + { + error = nonneg_required; + goto syntax; + } + + t = format_lex (); + if (t != FMT_PERIOD) + { + saved_token = t; + } + else + { + t = format_lex (); + if (t != FMT_ZERO && t != FMT_POSINT) + { + error = nonneg_required; + goto syntax; + } + } + + break; + + default: + error = unexpected_element; + goto syntax; + } + +between_desc: + /* Between a descriptor and what comes next. */ + t = format_lex (); + switch (t) + { + + case FMT_COMMA: + goto format_item; + + case FMT_RPAREN: + level--; + if (level < 0) + goto finished; + goto between_desc; + + case FMT_COLON: + case FMT_SLASH: + goto optional_comma; + + case FMT_END: + error = unexpected_end; + goto syntax; + + default: + error = "Missing comma"; + goto syntax; + } + +optional_comma: + /* Optional comma is a weird between state where we've just finished + reading a colon, slash or P descriptor. */ + t = format_lex (); + switch (t) + { + case FMT_COMMA: + break; + + case FMT_RPAREN: + level--; + if (level < 0) + goto finished; + goto between_desc; + + default: + /* Assume that we have another format item. */ + saved_token = t; + break; + } + + goto format_item; + +syntax: + /* Something went wrong. If the format we're checking is a string, + generate a warning, since the program is correct. If the format + is in a FORMAT statement, this messes up parsing, which is an + error. */ + if (mode != MODE_STRING) + gfc_error ("%s in format string at %C", error); + else + { + gfc_warning ("%s in format string at %C", error); + + /* TODO: More elaborate measures are needed to show where a problem + is within a format string that has been calculated. */ + } + + rv = FAILURE; + +finished: + return rv; +} + + +/* Given an expression node that is a constant string, see if it looks + like a format string. */ + +static void +check_format_string (gfc_expr * e) +{ + + mode = MODE_STRING; + format_string = e->value.character.string; + check_format (); +} + + +/************ Fortran 95 I/O statement matchers *************/ + +/* Match a FORMAT statement. This amounts to actually parsing the + format descriptors in order to correctly locate the end of the + format string. */ + +match +gfc_match_format (void) +{ + gfc_expr *e; + locus start; + + if (gfc_statement_label == NULL) + { + gfc_error ("Missing format label at %C"); + return MATCH_ERROR; + } + gfc_gobble_whitespace (); + + mode = MODE_FORMAT; + format_length = 0; + + start = *gfc_current_locus (); + + if (check_format () == FAILURE) + return MATCH_ERROR; + + if (gfc_match_eos () != MATCH_YES) + { + gfc_syntax_error (ST_FORMAT); + return MATCH_ERROR; + } + + /* The label doesn't get created until after the statement is done + being matched, so we have to leave the string for later. */ + + gfc_set_locus (&start); /* Back to the beginning */ + + new_st.loc = start; + new_st.op = EXEC_NOP; + + e = gfc_get_expr(); + e->expr_type = EXPR_CONSTANT; + e->ts.type = BT_CHARACTER; + e->ts.kind = gfc_default_character_kind(); + e->where = start; + e->value.character.string = format_string = gfc_getmem(format_length+1); + e->value.character.length = format_length; + gfc_statement_label->format = e; + + mode = MODE_COPY; + check_format (); /* Guaranteed to succeed */ + gfc_match_eos (); /* Guaranteed to succeed */ + + return MATCH_YES; +} + + +/* Match an expression I/O tag of some sort. */ + +static match +match_etag (const io_tag * tag, gfc_expr ** v) +{ + gfc_expr *result; + match m; + + m = gfc_match (tag->spec, &result); + if (m != MATCH_YES) + return m; + + if (*v != NULL) + { + gfc_error ("Duplicate %s specification at %C", tag->name); + gfc_free_expr (result); + return MATCH_ERROR; + } + + *v = result; + return MATCH_YES; +} + + +/* Match a variable I/O tag of some sort. */ + +static match +match_vtag (const io_tag * tag, gfc_expr ** v) +{ + gfc_expr *result; + match m; + + m = gfc_match (tag->spec, &result); + if (m != MATCH_YES) + return m; + + if (*v != NULL) + { + gfc_error ("Duplicate %s specification at %C", tag->name); + gfc_free_expr (result); + return MATCH_ERROR; + } + + if (result->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error ("Variable tag cannot be INTENT(IN) at %C"); + gfc_free_expr (result); + return MATCH_ERROR; + } + + if (gfc_pure (NULL) && gfc_impure_variable (result->symtree->n.sym)) + { + gfc_error ("Variable tag cannot be assigned in PURE procedure at %C"); + gfc_free_expr (result); + return MATCH_ERROR; + } + + *v = result; + return MATCH_YES; +} + + +/* Match a label I/O tag. */ + +static match +match_ltag (const io_tag * tag, gfc_st_label ** label) +{ + match m; + gfc_st_label *old; + + old = *label; + m = gfc_match (tag->spec, label); + if (m == MATCH_YES && old != 0) + { + gfc_error ("Duplicate %s label specification at %C", tag->name); + return MATCH_ERROR; + } + + return m; +} + + +/* Do expression resolution and type-checking on an expression tag. */ + +static try +resolve_tag (const io_tag * tag, gfc_expr * e) +{ + + if (e == NULL) + return SUCCESS; + + if (gfc_resolve_expr (e) == FAILURE) + return FAILURE; + + if (e->ts.type != tag->type) + { + /* Format label can be integer varibale. */ + if (tag != &tag_format) + { + gfc_error ("%s tag at %L must be of type %s", tag->name, &e->where, + gfc_basic_typename (tag->type)); + return FAILURE; + } + } + + if (tag == &tag_format) + { + if (e->rank != 1 && e->rank != 0) + { + gfc_error ("FORMAT tag at %L cannot be array of strings", + &e->where); + return FAILURE; + } + } + else + { + if (e->rank != 0) + { + gfc_error ("%s tag at %L must be scalar", tag->name, &e->where); + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Match a single tag of an OPEN statement. */ + +static match +match_open_element (gfc_open * open) +{ + match m; + + m = match_etag (&tag_unit, &open->unit); + if (m != MATCH_NO) + return m; + m = match_vtag (&tag_iostat, &open->iostat); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_file, &open->file); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_status, &open->status); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_access, &open->access); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_form, &open->form); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_recl, &open->recl); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_blank, &open->blank); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_position, &open->position); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_action, &open->action); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_delim, &open->delim); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_e_pad, &open->pad); + if (m != MATCH_NO) + return m; + m = match_ltag (&tag_err, &open->err); + if (m != MATCH_NO) + return m; + + return MATCH_NO; +} + + +/* Free the gfc_open structure and all the expressions it contains. */ + +void +gfc_free_open (gfc_open * open) +{ + + if (open == NULL) + return; + + gfc_free_expr (open->unit); + gfc_free_expr (open->iostat); + gfc_free_expr (open->file); + gfc_free_expr (open->status); + gfc_free_expr (open->access); + gfc_free_expr (open->form); + gfc_free_expr (open->recl); + gfc_free_expr (open->blank); + gfc_free_expr (open->position); + gfc_free_expr (open->action); + gfc_free_expr (open->delim); + gfc_free_expr (open->pad); + + gfc_free (open); +} + + +/* Resolve everything in a gfc_open structure. */ + +try +gfc_resolve_open (gfc_open * open) +{ + + RESOLVE_TAG (&tag_unit, open->unit); + RESOLVE_TAG (&tag_iostat, open->iostat); + RESOLVE_TAG (&tag_file, open->file); + RESOLVE_TAG (&tag_status, open->status); + RESOLVE_TAG (&tag_e_form, open->form); + RESOLVE_TAG (&tag_e_recl, open->recl); + + RESOLVE_TAG (&tag_e_blank, open->blank); + RESOLVE_TAG (&tag_e_position, open->position); + RESOLVE_TAG (&tag_e_action, open->action); + RESOLVE_TAG (&tag_e_delim, open->delim); + RESOLVE_TAG (&tag_e_pad, open->pad); + + if (gfc_reference_st_label (open->err, ST_LABEL_TARGET) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Match an OPEN statmement. */ + +match +gfc_match_open (void) +{ + gfc_open *open; + match m; + + m = gfc_match_char ('('); + if (m == MATCH_NO) + return m; + + open = gfc_getmem (sizeof (gfc_open)); + + m = match_open_element (open); + + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + m = gfc_match_expr (&open->unit); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + } + + for (;;) + { + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + m = match_open_element (open); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + } + + if (gfc_match_eos () == MATCH_NO) + goto syntax; + + if (gfc_pure (NULL)) + { + gfc_error ("OPEN statement not allowed in PURE procedure at %C"); + goto cleanup; + } + + new_st.op = EXEC_OPEN; + new_st.ext.open = open; + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_OPEN); + +cleanup: + gfc_free_open (open); + return MATCH_ERROR; +} + + +/* Free a gfc_close structure an all its expressions. */ + +void +gfc_free_close (gfc_close * close) +{ + + if (close == NULL) + return; + + gfc_free_expr (close->unit); + gfc_free_expr (close->iostat); + gfc_free_expr (close->status); + + gfc_free (close); +} + + +/* Match elements of a CLOSE statment. */ + +static match +match_close_element (gfc_close * close) +{ + match m; + + m = match_etag (&tag_unit, &close->unit); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_status, &close->status); + if (m != MATCH_NO) + return m; + m = match_vtag (&tag_iostat, &close->iostat); + if (m != MATCH_NO) + return m; + m = match_ltag (&tag_err, &close->err); + if (m != MATCH_NO) + return m; + + return MATCH_NO; +} + + +/* Match a CLOSE statement. */ + +match +gfc_match_close (void) +{ + gfc_close *close; + match m; + + m = gfc_match_char ('('); + if (m == MATCH_NO) + return m; + + close = gfc_getmem (sizeof (gfc_close)); + + m = match_close_element (close); + + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + m = gfc_match_expr (&close->unit); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + } + + for (;;) + { + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + m = match_close_element (close); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + } + + if (gfc_match_eos () == MATCH_NO) + goto syntax; + + if (gfc_pure (NULL)) + { + gfc_error ("CLOSE statement not allowed in PURE procedure at %C"); + goto cleanup; + } + + new_st.op = EXEC_CLOSE; + new_st.ext.close = close; + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_CLOSE); + +cleanup: + gfc_free_close (close); + return MATCH_ERROR; +} + + +/* Resolve everything in a gfc_close structure. */ + +try +gfc_resolve_close (gfc_close * close) +{ + + RESOLVE_TAG (&tag_unit, close->unit); + RESOLVE_TAG (&tag_iostat, close->iostat); + RESOLVE_TAG (&tag_status, close->status); + + if (gfc_reference_st_label (close->err, ST_LABEL_TARGET) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Free a gfc_filepos structure. */ + +void +gfc_free_filepos (gfc_filepos * fp) +{ + + gfc_free_expr (fp->unit); + gfc_free_expr (fp->iostat); + gfc_free (fp); +} + + +/* Match elements of a REWIND, BACKSPACE or ENDFILE statement. */ + +static match +match_file_element (gfc_filepos * fp) +{ + match m; + + m = match_etag (&tag_unit, &fp->unit); + if (m != MATCH_NO) + return m; + m = match_vtag (&tag_iostat, &fp->iostat); + if (m != MATCH_NO) + return m; + m = match_ltag (&tag_err, &fp->err); + if (m != MATCH_NO) + return m; + + return MATCH_NO; +} + + +/* Match the second half of the file-positioning statements, REWIND, + BACKSPACE or ENDFILE. */ + +static match +match_filepos (gfc_statement st, gfc_exec_op op) +{ + gfc_filepos *fp; + match m; + + fp = gfc_getmem (sizeof (gfc_filepos)); + + if (gfc_match_char ('(') == MATCH_NO) + { + m = gfc_match_expr (&fp->unit); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + goto done; + } + + m = match_file_element (fp); + if (m == MATCH_ERROR) + goto done; + if (m == MATCH_NO) + { + m = gfc_match_expr (&fp->unit); + if (m == MATCH_ERROR) + goto done; + if (m == MATCH_NO) + goto syntax; + } + + for (;;) + { + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + m = match_file_element (fp); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + } + +done: + if (gfc_match_eos () != MATCH_YES) + goto syntax; + + if (gfc_pure (NULL)) + { + gfc_error ("%s statement not allowed in PURE procedure at %C", + gfc_ascii_statement (st)); + + goto cleanup; + } + + new_st.op = op; + new_st.ext.filepos = fp; + return MATCH_YES; + +syntax: + gfc_syntax_error (st); + +cleanup: + gfc_free_filepos (fp); + return MATCH_ERROR; +} + + +try +gfc_resolve_filepos (gfc_filepos * fp) +{ + + RESOLVE_TAG (&tag_unit, fp->unit); + if (gfc_reference_st_label (fp->err, ST_LABEL_TARGET) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Match the file positioning statements: ENDFILE, BACKSPACE or + REWIND. */ + +match +gfc_match_endfile (void) +{ + + return match_filepos (ST_END_FILE, EXEC_ENDFILE); +} + +match +gfc_match_backspace (void) +{ + + return match_filepos (ST_BACKSPACE, EXEC_BACKSPACE); +} + +match +gfc_match_rewind (void) +{ + + return match_filepos (ST_REWIND, EXEC_REWIND); +} + + +/******************** Data Transfer Statments *********************/ + +typedef enum +{ M_READ, M_WRITE, M_PRINT, M_INQUIRE } +io_kind; + + +/* Return a default unit number. */ + +static gfc_expr * +default_unit (io_kind k) +{ + int unit; + + if (k == M_READ) + unit = 5; + else + unit = 6; + + return gfc_int_expr (unit); +} + + +/* Match a unit specification for a data transfer statement. */ + +static match +match_dt_unit (io_kind k, gfc_dt * dt) +{ + gfc_expr *e; + + if (gfc_match_char ('*') == MATCH_YES) + { + if (dt->io_unit != NULL) + goto conflict; + + dt->io_unit = default_unit (k); + return MATCH_YES; + } + + if (gfc_match_expr (&e) == MATCH_YES) + { + if (dt->io_unit != NULL) + { + gfc_free_expr (e); + goto conflict; + } + + dt->io_unit = e; + return MATCH_YES; + } + + return MATCH_NO; + +conflict: + gfc_error ("Duplicate UNIT specification at %C"); + return MATCH_ERROR; +} + + +/* Match a format specification. */ + +static match +match_dt_format (gfc_dt * dt) +{ + locus where; + gfc_expr *e; + gfc_st_label *label; + + where = *gfc_current_locus (); + + if (gfc_match_char ('*') == MATCH_YES) + { + if (dt->format_expr != NULL || dt->format_label != NULL) + goto conflict; + + dt->format_label = &format_asterisk; + return MATCH_YES; + } + + if (gfc_match_st_label (&label, 0) == MATCH_YES) + { + if (dt->format_expr != NULL || dt->format_label != NULL) + { + gfc_free_st_label (label); + goto conflict; + } + + if (gfc_reference_st_label (label, ST_LABEL_FORMAT) == FAILURE) + return MATCH_ERROR; + + dt->format_label = label; + return MATCH_YES; + } + + if (gfc_match_expr (&e) == MATCH_YES) + { + if (dt->format_expr != NULL || dt->format_label != NULL) + { + gfc_free_expr (e); + goto conflict; + } + if (e->ts.type == BT_INTEGER && e->rank == 0) + e->symtree->n.sym->attr.assign = 1; + + dt->format_expr = e; + return MATCH_YES; + } + + gfc_set_locus (&where); /* The only case where we have to restore */ + + return MATCH_NO; + +conflict: + gfc_error ("Duplicate format specification at %C"); + return MATCH_ERROR; +} + + +/* Traverse a namelist that is part of a READ statement to make sure + that none of the variables in the namelist are INTENT(IN). Returns + nonzero if we find such a variable. */ + +static int +check_namelist (gfc_symbol * sym) +{ + gfc_namelist *p; + + for (p = sym->namelist; p; p = p->next) + if (p->sym->attr.intent == INTENT_IN) + { + gfc_error ("Symbol '%s' in namelist '%s' is INTENT(IN) at %C", + p->sym->name, sym->name); + return 1; + } + + return 0; +} + + +/* Match a single data transfer element. */ + +static match +match_dt_element (io_kind k, gfc_dt * dt) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + match m; + + if (gfc_match (" unit =") == MATCH_YES) + { + m = match_dt_unit (k, dt); + if (m != MATCH_NO) + return m; + } + + if (gfc_match (" fmt =") == MATCH_YES) + { + m = match_dt_format (dt); + if (m != MATCH_NO) + return m; + } + + if (gfc_match (" nml = %n", name) == MATCH_YES) + { + if (dt->namelist != NULL) + { + gfc_error ("Duplicate NML specification at %C"); + return MATCH_ERROR; + } + + if (gfc_find_symbol (name, NULL, 1, &sym)) + return MATCH_ERROR; + + if (sym == NULL || sym->attr.flavor != FL_NAMELIST) + { + gfc_error ("Symbol '%s' at %C must be a NAMELIST group name", + sym != NULL ? sym->name : name); + return MATCH_ERROR; + } + + dt->namelist = sym; + if (k == M_READ && check_namelist (sym)) + return MATCH_ERROR; + + return MATCH_YES; + } + + m = match_etag (&tag_rec, &dt->rec); + if (m != MATCH_NO) + return m; + m = match_vtag (&tag_iostat, &dt->iostat); + if (m != MATCH_NO) + return m; + m = match_ltag (&tag_err, &dt->err); + if (m != MATCH_NO) + return m; + m = match_etag (&tag_advance, &dt->advance); + if (m != MATCH_NO) + return m; + m = match_vtag (&tag_size, &dt->size); + if (m != MATCH_NO) + return m; + + m = match_ltag (&tag_end, &dt->end); + if (m == MATCH_YES) + dt->end_where = *gfc_current_locus (); + if (m != MATCH_NO) + return m; + + m = match_ltag (&tag_eor, &dt->eor); + if (m == MATCH_YES) + dt->eor_where = *gfc_current_locus (); + if (m != MATCH_NO) + return m; + + return MATCH_NO; +} + + +/* Free a data transfer structure and everything below it. */ + +void +gfc_free_dt (gfc_dt * dt) +{ + + if (dt == NULL) + return; + + gfc_free_expr (dt->io_unit); + gfc_free_expr (dt->format_expr); + gfc_free_expr (dt->rec); + gfc_free_expr (dt->advance); + gfc_free_expr (dt->iostat); + gfc_free_expr (dt->size); + + gfc_free (dt); +} + + +/* Resolve everything in a gfc_dt structure. */ + +try +gfc_resolve_dt (gfc_dt * dt) +{ + gfc_expr *e; + + RESOLVE_TAG (&tag_format, dt->format_expr); + RESOLVE_TAG (&tag_rec, dt->rec); + RESOLVE_TAG (&tag_advance, dt->advance); + RESOLVE_TAG (&tag_iostat, dt->iostat); + RESOLVE_TAG (&tag_size, dt->size); + + e = dt->io_unit; + if (gfc_resolve_expr (e) == SUCCESS + && (e->ts.type != BT_INTEGER + && (e->ts.type != BT_CHARACTER + || e->expr_type != EXPR_VARIABLE))) + { + gfc_error + ("UNIT specification at %L must be an INTEGER expression or a " + "CHARACTER variable", &e->where); + return FAILURE; + } + + /* Sanity checks on data transfer statements. */ + if (e->ts.type == BT_CHARACTER) + { + if (dt->rec != NULL) + { + gfc_error ("REC tag at %L is incompatible with internal file", + &dt->rec->where); + return FAILURE; + } + + if (dt->namelist != NULL) + { + gfc_error ("Internal file at %L is incompatible with namelist", + &dt->io_unit->where); + return FAILURE; + } + + if (dt->advance != NULL) + { + gfc_error ("ADVANCE tag at %L is incompatible with internal file", + &dt->advance->where); + return FAILURE; + } + } + + if (dt->rec != NULL) + { + if (dt->end != NULL) + { + gfc_error ("REC tag at %L is incompatible with END tag", + &dt->rec->where); + return FAILURE; + } + + if (dt->format_label == &format_asterisk) + { + gfc_error + ("END tag at %L is incompatible with list directed format (*)", + &dt->end_where); + return FAILURE; + } + + if (dt->namelist != NULL) + { + gfc_error ("REC tag at %L is incompatible with namelist", + &dt->rec->where); + return FAILURE; + } + } + + if (dt->advance != NULL && dt->format_label == &format_asterisk) + { + gfc_error ("ADVANCE tag at %L is incompatible with list directed " + "format (*)", &dt->advance->where); + return FAILURE; + } + + if (dt->eor != 0 && dt->advance == NULL) + { + gfc_error ("EOR tag at %L requires an ADVANCE tag", &dt->eor_where); + return FAILURE; + } + + if (dt->size != NULL && dt->advance == NULL) + { + gfc_error ("SIZE tag at %L requires an ADVANCE tag", &dt->size->where); + return FAILURE; + } + + /* TODO: Make sure the ADVANCE tag is 'yes' or 'no' if it is a string + constant. */ + + if (gfc_reference_st_label (dt->err, ST_LABEL_TARGET) == FAILURE) + return FAILURE; + + if (gfc_reference_st_label (dt->end, ST_LABEL_TARGET) == FAILURE) + return FAILURE; + + if (gfc_reference_st_label (dt->eor, ST_LABEL_TARGET) == FAILURE) + return FAILURE; + + /* Check the format label ectually exists. */ + if (dt->format_label && dt->format_label != &format_asterisk + && dt->format_label->defined == ST_LABEL_UNKNOWN) + { + gfc_error ("FORMAT label %d at %L not defined", dt->format_label->value, + &dt->format_label->where); + return FAILURE; + } + return SUCCESS; +} + + +/* Given an io_kind, return its name. */ + +static const char * +io_kind_name (io_kind k) +{ + const char *name; + + switch (k) + { + case M_READ: + name = "READ"; + break; + case M_WRITE: + name = "WRITE"; + break; + case M_PRINT: + name = "PRINT"; + break; + case M_INQUIRE: + name = "INQUIRE"; + break; + default: + gfc_internal_error ("io_kind_name(): bad I/O-kind"); + } + + return name; +} + + +/* Match an IO iteration statement of the form: + + ( [ ,] , I = , [, ] ) + + which is equivalent to a single IO element. This function is + mutually recursive with match_io_element(). */ + +static match match_io_element (io_kind k, gfc_code **); + +static match +match_io_iterator (io_kind k, gfc_code ** result) +{ + gfc_code *head, *tail, *new; + gfc_iterator *iter; + locus old_loc; + match m; + int n; + + iter = NULL; + head = NULL; + old_loc = *gfc_current_locus (); + + if (gfc_match_char ('(') != MATCH_YES) + return MATCH_NO; + + m = match_io_element (k, &head); + tail = head; + + if (m != MATCH_YES || gfc_match_char (',') != MATCH_YES) + { + m = MATCH_NO; + goto cleanup; + } + + /* Can't be anything but an IO iterator. Build a list. */ + iter = gfc_get_iterator (); + + for (n = 1;; n++) + { + m = gfc_match_iterator (iter, 0); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_YES) + break; + + m = match_io_element (k, &new); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + if (n > 2) + goto syntax; + goto cleanup; + } + + tail = gfc_append_code (tail, new); + + if (gfc_match_char (',') != MATCH_YES) + { + if (n > 2) + goto syntax; + m = MATCH_NO; + goto cleanup; + } + } + + if (gfc_match_char (')') != MATCH_YES) + goto syntax; + + new = gfc_get_code (); + new->op = EXEC_DO; + new->ext.iterator = iter; + + new->block = gfc_get_code (); + new->block->op = EXEC_DO; + new->block->next = head; + + *result = new; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in I/O iterator at %C"); + m = MATCH_ERROR; + +cleanup: + gfc_free_iterator (iter, 1); + gfc_free_statements (head); + gfc_set_locus (&old_loc); + return m; +} + + +/* Match a single element of an IO list, which is either a single + expression or an IO Iterator. */ + +static match +match_io_element (io_kind k, gfc_code ** cpp) +{ + gfc_expr *expr; + gfc_code *cp; + match m; + + expr = NULL; + + m = match_io_iterator (k, cpp); + if (m == MATCH_YES) + return MATCH_YES; + + if (k == M_READ) + { + m = gfc_match_variable (&expr, 0); + if (m == MATCH_NO) + gfc_error ("Expected variable in READ statement at %C"); + } + else + { + m = gfc_match_expr (&expr); + if (m == MATCH_NO) + gfc_error ("Expected expression in %s statement at %C", + io_kind_name (k)); + } + + if (m == MATCH_YES) + switch (k) + { + case M_READ: + if (expr->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error + ("Variable '%s' in input list at %C cannot be INTENT(IN)", + expr->symtree->n.sym->name); + m = MATCH_ERROR; + } + + if (gfc_pure (NULL) + && gfc_impure_variable (expr->symtree->n.sym) + && current_dt->io_unit->ts.type == BT_CHARACTER) + { + gfc_error ("Cannot read to variable '%s' in PURE procedure at %C", + expr->symtree->n.sym->name); + m = MATCH_ERROR; + } + + break; + + case M_WRITE: + if (current_dt->io_unit->ts.type == BT_CHARACTER + && gfc_pure (NULL) + && current_dt->io_unit->expr_type == EXPR_VARIABLE + && gfc_impure_variable (current_dt->io_unit->symtree->n.sym)) + { + gfc_error + ("Cannot write to internal file unit '%s' at %C inside a " + "PURE procedure", current_dt->io_unit->symtree->n.sym->name); + m = MATCH_ERROR; + } + + break; + + default: + break; + } + + if (m != MATCH_YES) + { + gfc_free_expr (expr); + return MATCH_ERROR; + } + + cp = gfc_get_code (); + cp->op = EXEC_TRANSFER; + cp->expr = expr; + + *cpp = cp; + return MATCH_YES; +} + + +/* Match an I/O list, building gfc_code structures as we go. */ + +static match +match_io_list (io_kind k, gfc_code ** head_p) +{ + gfc_code *head, *tail, *new; + match m; + + *head_p = head = tail = NULL; + if (gfc_match_eos () == MATCH_YES) + return MATCH_YES; + + for (;;) + { + m = match_io_element (k, &new); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + tail = gfc_append_code (tail, new); + if (head == NULL) + head = new; + + if (gfc_match_eos () == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + *head_p = head; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in %s statement at %C", io_kind_name (k)); + +cleanup: + gfc_free_statements (head); + return MATCH_ERROR; +} + + +/* Attach the data transfer end node. */ + +static void +terminate_io (gfc_code * io_code) +{ + gfc_code *c; + + if (io_code == NULL) + io_code = &new_st; + + c = gfc_get_code (); + c->op = EXEC_DT_END; + + /* Point to structure that is already there */ + c->ext.dt = new_st.ext.dt; + gfc_append_code (io_code, c); +} + + +/* Match a READ, WRITE or PRINT statement. */ + +static match +match_io (io_kind k) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_code *io_code; + gfc_symbol *sym; + gfc_expr *expr; + int comma_flag; + locus where; + gfc_dt *dt; + match m; + + comma_flag = 0; + current_dt = dt = gfc_getmem (sizeof (gfc_dt)); + + if (gfc_match_char ('(') == MATCH_NO) + { + if (k == M_WRITE) + goto syntax; + + m = match_dt_format (dt); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + comma_flag = 1; + dt->io_unit = default_unit (k); + goto get_io_list; + } + + /* Match a control list */ + if (match_dt_element (k, dt) == MATCH_YES) + goto next; + if (match_dt_unit (k, dt) != MATCH_YES) + goto loop; + + if (gfc_match_char (')') == MATCH_YES) + goto get_io_list; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + m = match_dt_element (k, dt); + if (m == MATCH_YES) + goto next; + if (m == MATCH_ERROR) + goto cleanup; + + m = match_dt_format (dt); + if (m == MATCH_YES) + goto next; + if (m == MATCH_ERROR) + goto cleanup; + + where = *gfc_current_locus (); + + if (gfc_match_name (name) == MATCH_YES + && !gfc_find_symbol (name, NULL, 1, &sym) + && sym->attr.flavor == FL_NAMELIST) + { + dt->namelist = sym; + if (k == M_READ && check_namelist (sym)) + { + m = MATCH_ERROR; + goto cleanup; + } + goto next; + } + + gfc_set_locus (&where); + + goto loop; /* No matches, try regular elements */ + +next: + if (gfc_match_char (')') == MATCH_YES) + goto get_io_list; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + +loop: + for (;;) + { + m = match_dt_element (k, dt); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + +get_io_list: + /* Optional leading comma (non-standard). */ + if (!comma_flag) + gfc_match_char (','); + + io_code = NULL; + if (gfc_match_eos () != MATCH_YES) + { + if (comma_flag && gfc_match_char (',') != MATCH_YES) + { + gfc_error ("Expected comma in I/O list at %C"); + m = MATCH_ERROR; + goto cleanup; + } + + m = match_io_list (k, &io_code); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + } + + /* A full IO statement has been matched. */ + if (dt->io_unit->expr_type == EXPR_VARIABLE + && k == M_WRITE + && dt->io_unit->ts.type == BT_CHARACTER + && dt->io_unit->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error ("Internal file '%s' at %L is INTENT(IN)", + dt->io_unit->symtree->n.sym->name, &dt->io_unit->where); + m = MATCH_ERROR; + goto cleanup; + } + + expr = dt->format_expr; + + if (expr != NULL && expr->expr_type == EXPR_CONSTANT) + check_format_string (expr); + + if (gfc_pure (NULL) + && (k == M_READ || k == M_WRITE) + && dt->io_unit->ts.type != BT_CHARACTER) + { + gfc_error + ("io-unit in %s statement at %C must be an internal file in a " + "PURE procedure", io_kind_name (k)); + m = MATCH_ERROR; + goto cleanup; + } + + new_st.op = (k == M_READ) ? EXEC_READ : EXEC_WRITE; + new_st.ext.dt = dt; + new_st.next = io_code; + + terminate_io (io_code); + + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in %s statement at %C", io_kind_name (k)); + m = MATCH_ERROR; + +cleanup: + gfc_free_dt (dt); + return m; +} + + +match +gfc_match_read (void) +{ + return match_io (M_READ); +} + +match +gfc_match_write (void) +{ + return match_io (M_WRITE); +} + +match +gfc_match_print (void) +{ + match m; + + m = match_io (M_PRINT); + if (m != MATCH_YES) + return m; + + if (gfc_pure (NULL)) + { + gfc_error ("PRINT statement at %C not allowed within PURE procedure"); + return MATCH_ERROR; + } + + return MATCH_YES; +} + + +/* Free a gfc_inquire structure. */ + +void +gfc_free_inquire (gfc_inquire * inquire) +{ + + if (inquire == NULL) + return; + + gfc_free_expr (inquire->unit); + gfc_free_expr (inquire->file); + gfc_free_expr (inquire->iostat); + gfc_free_expr (inquire->exist); + gfc_free_expr (inquire->opened); + gfc_free_expr (inquire->number); + gfc_free_expr (inquire->named); + gfc_free_expr (inquire->name); + gfc_free_expr (inquire->access); + gfc_free_expr (inquire->sequential); + gfc_free_expr (inquire->direct); + gfc_free_expr (inquire->form); + gfc_free_expr (inquire->formatted); + gfc_free_expr (inquire->unformatted); + gfc_free_expr (inquire->recl); + gfc_free_expr (inquire->nextrec); + gfc_free_expr (inquire->blank); + gfc_free_expr (inquire->position); + gfc_free_expr (inquire->action); + gfc_free_expr (inquire->read); + gfc_free_expr (inquire->write); + gfc_free_expr (inquire->readwrite); + gfc_free_expr (inquire->delim); + gfc_free_expr (inquire->pad); + gfc_free_expr (inquire->iolength); + + gfc_free (inquire); +} + + +/* Match an element of an INQUIRE statement. */ + +#define RETM if (m != MATCH_NO) return m; + +static match +match_inquire_element (gfc_inquire * inquire) +{ + match m; + + m = match_etag (&tag_unit, &inquire->unit); + RETM m = match_etag (&tag_file, &inquire->file); + RETM m = match_ltag (&tag_err, &inquire->err); + RETM m = match_vtag (&tag_iostat, &inquire->iostat); + RETM m = match_vtag (&tag_exist, &inquire->exist); + RETM m = match_vtag (&tag_opened, &inquire->opened); + RETM m = match_vtag (&tag_named, &inquire->named); + RETM m = match_vtag (&tag_name, &inquire->name); + RETM m = match_vtag (&tag_number, &inquire->number); + RETM m = match_vtag (&tag_s_access, &inquire->access); + RETM m = match_vtag (&tag_sequential, &inquire->sequential); + RETM m = match_vtag (&tag_direct, &inquire->direct); + RETM m = match_vtag (&tag_s_form, &inquire->form); + RETM m = match_vtag (&tag_formatted, &inquire->formatted); + RETM m = match_vtag (&tag_unformatted, &inquire->unformatted); + RETM m = match_vtag (&tag_s_recl, &inquire->recl); + RETM m = match_vtag (&tag_nextrec, &inquire->nextrec); + RETM m = match_vtag (&tag_s_blank, &inquire->blank); + RETM m = match_vtag (&tag_s_position, &inquire->position); + RETM m = match_vtag (&tag_s_action, &inquire->action); + RETM m = match_vtag (&tag_read, &inquire->read); + RETM m = match_vtag (&tag_write, &inquire->write); + RETM m = match_vtag (&tag_readwrite, &inquire->readwrite); + RETM m = match_vtag (&tag_s_delim, &inquire->delim); + RETM m = match_vtag (&tag_s_pad, &inquire->pad); + RETM m = match_vtag (&tag_iolength, &inquire->iolength); + RETM return MATCH_NO; +} + +#undef RETM + + +match +gfc_match_inquire (void) +{ + gfc_inquire *inquire; + gfc_code *code; + match m; + + m = gfc_match_char ('('); + if (m == MATCH_NO) + return m; + + inquire = gfc_getmem (sizeof (gfc_inquire)); + + m = match_inquire_element (inquire); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + m = gfc_match_expr (&inquire->unit); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + } + + /* See if we have the IOLENGTH form of the inquire statement. */ + if (inquire->iolength != NULL) + { + if (gfc_match_char (')') != MATCH_YES) + goto syntax; + + m = match_io_list (M_INQUIRE, &code); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + terminate_io (code); + + new_st.op = EXEC_IOLENGTH; + new_st.expr = inquire->iolength; + gfc_free (inquire); + + if (gfc_pure (NULL)) + { + gfc_free_statements (code); + gfc_error ("INQUIRE statement not allowed in PURE procedure at %C"); + return MATCH_ERROR; + } + + new_st.next = code; + return MATCH_YES; + } + + /* At this point, we have the non-IOLENGTH inquire statement. */ + for (;;) + { + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + m = match_inquire_element (inquire); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + if (inquire->iolength != NULL) + { + gfc_error ("IOLENGTH tag invalid in INQUIRE statement at %C"); + goto cleanup; + } + } + + if (gfc_match_eos () != MATCH_YES) + goto syntax; + + if (gfc_pure (NULL)) + { + gfc_error ("INQUIRE statement not allowed in PURE procedure at %C"); + goto cleanup; + } + + new_st.op = EXEC_INQUIRE; + new_st.ext.inquire = inquire; + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_INQUIRE); + +cleanup: + gfc_free_inquire (inquire); + return MATCH_ERROR; +} + + +/* Resolve everything in a gfc_inquire structure. */ + +try +gfc_resolve_inquire (gfc_inquire * inquire) +{ + + RESOLVE_TAG (&tag_unit, inquire->unit); + RESOLVE_TAG (&tag_file, inquire->file); + RESOLVE_TAG (&tag_iostat, inquire->iostat); + RESOLVE_TAG (&tag_exist, inquire->exist); + RESOLVE_TAG (&tag_opened, inquire->opened); + RESOLVE_TAG (&tag_number, inquire->number); + RESOLVE_TAG (&tag_named, inquire->named); + RESOLVE_TAG (&tag_name, inquire->name); + RESOLVE_TAG (&tag_s_access, inquire->access); + RESOLVE_TAG (&tag_sequential, inquire->sequential); + RESOLVE_TAG (&tag_direct, inquire->direct); + RESOLVE_TAG (&tag_s_form, inquire->form); + RESOLVE_TAG (&tag_formatted, inquire->formatted); + RESOLVE_TAG (&tag_unformatted, inquire->unformatted); + RESOLVE_TAG (&tag_s_recl, inquire->recl); + RESOLVE_TAG (&tag_nextrec, inquire->nextrec); + RESOLVE_TAG (&tag_s_blank, inquire->blank); + RESOLVE_TAG (&tag_s_position, inquire->position); + RESOLVE_TAG (&tag_s_action, inquire->action); + RESOLVE_TAG (&tag_read, inquire->read); + RESOLVE_TAG (&tag_write, inquire->write); + RESOLVE_TAG (&tag_readwrite, inquire->readwrite); + RESOLVE_TAG (&tag_s_delim, inquire->delim); + RESOLVE_TAG (&tag_s_pad, inquire->pad); + + if (gfc_reference_st_label (inquire->err, ST_LABEL_TARGET) == FAILURE) + return FAILURE; + + return FAILURE; +} diff --git a/gcc/fortran/iresolve.c b/gcc/fortran/iresolve.c new file mode 100644 index 00000000000..24205939d3b --- /dev/null +++ b/gcc/fortran/iresolve.c @@ -0,0 +1,1377 @@ +/* Intrinsic function resolution. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught & Katherine Holcomb + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Assign name and types to intrinsic procedures. For functions, the + first argument to a resolution function is an expression pointer to + the original function node and the rest are pointers to the + arguments of the function call. For subroutines, a pointer to the + code node is passed. The result type and library subroutine name + are generally set according to the function arguments. */ + +#include "config.h" +#include +#include + +#include "gfortran.h" +#include "intrinsic.h" + + +/* String pool subroutines. This are used to provide static locations + for the string constants that represent library function names. */ + +typedef struct string_node +{ + struct string_node *next; + char string[1]; +} +string_node; + +#define HASH_SIZE 13 + +static string_node *string_head[HASH_SIZE]; + + +/* Return a hash code based on the name. */ + +static int +hash (const char *name) +{ + int h; + + h = 1; + while (*name) + h = 5311966 * h + *name++; + + if (h < 0) + h = -h; + return h % HASH_SIZE; +} + + +/* Given printf-like arguments, return a static address of the + resulting string. If the name is not in the table, it is added. */ + +char * +gfc_get_string (const char *format, ...) +{ + char temp_name[50]; + string_node *p; + va_list ap; + int h; + + va_start (ap, format); + vsprintf (temp_name, format, ap); + va_end (ap); + + h = hash (temp_name); + + /* Search */ + for (p = string_head[h]; p; p = p->next) + if (strcmp (p->string, temp_name) == 0) + return p->string; + + /* Add */ + p = gfc_getmem (sizeof (string_node) + strlen (temp_name)); + + strcpy (p->string, temp_name); + + p->next = string_head[h]; + string_head[h] = p; + + return p->string; +} + + + +static void +free_strings (void) +{ + string_node *p, *q; + int h; + + for (h = 0; h < HASH_SIZE; h++) + { + for (p = string_head[h]; p; p = q) + { + q = p->next; + gfc_free (p); + } + } +} + + +/********************** Resolution functions **********************/ + + +void +gfc_resolve_abs (gfc_expr * f, gfc_expr * a) +{ + + f->ts = a->ts; + if (f->ts.type == BT_COMPLEX) + f->ts.type = BT_REAL; + + f->value.function.name = + gfc_get_string ("__abs_%c%d", gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_acos (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__acos_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_aimag (gfc_expr * f, gfc_expr * x) +{ + + f->ts.type = BT_REAL; + f->ts.kind = x->ts.kind; + f->value.function.name = + gfc_get_string ("__aimag_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_aint (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = a->ts.type; + f->ts.kind = (kind == NULL) ? a->ts.kind : mpz_get_si (kind->value.integer); + + /* The resolved name is only used for specific intrinsics where + the return kind is the same as the arg kind. */ + f->value.function.name = + gfc_get_string ("__aint_%c%d", gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_dint (gfc_expr * f, gfc_expr * a) +{ + gfc_resolve_aint (f, a, NULL); +} + + +void +gfc_resolve_all (gfc_expr * f, gfc_expr * mask, gfc_expr * dim) +{ + + f->ts = mask->ts; + + if (dim != NULL) + { + gfc_resolve_index (dim, 1); + f->rank = mask->rank - 1; + } + + f->value.function.name = + gfc_get_string ("__all_%c%d", gfc_type_letter (mask->ts.type), + mask->ts.kind); +} + + +void +gfc_resolve_anint (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = a->ts.type; + f->ts.kind = (kind == NULL) ? a->ts.kind : mpz_get_si (kind->value.integer); + + /* The resolved name is only used for specific intrinsics where + the return kind is the same as the arg kind. */ + f->value.function.name = + gfc_get_string ("__anint_%c%d", gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_dnint (gfc_expr * f, gfc_expr * a) +{ + gfc_resolve_anint (f, a, NULL); +} + + +void +gfc_resolve_any (gfc_expr * f, gfc_expr * mask, gfc_expr * dim) +{ + + f->ts = mask->ts; + + if (dim != NULL) + { + gfc_resolve_index (dim, 1); + f->rank = mask->rank - 1; + } + + f->value.function.name = + gfc_get_string ("__any_%c%d", gfc_type_letter (mask->ts.type), + mask->ts.kind); +} + + +void +gfc_resolve_asin (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__asin_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_atan (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__atan_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_atan2 (gfc_expr * f, gfc_expr * x, + gfc_expr * y ATTRIBUTE_UNUSED) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__atan2_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_btest (gfc_expr * f, gfc_expr * i, gfc_expr * pos) +{ + + f->ts.type = BT_LOGICAL; + f->ts.kind = gfc_default_logical_kind (); + + f->value.function.name = gfc_get_string ("__btest_%d_%d", i->ts.kind, + pos->ts.kind); +} + + +void +gfc_resolve_ceiling (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = (kind == NULL) ? gfc_default_integer_kind () + : mpz_get_si (kind->value.integer); + + f->value.function.name = + gfc_get_string ("__ceiling_%d_%c%d", f->ts.kind, + gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_char (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = BT_CHARACTER; + f->ts.kind = (kind == NULL) ? gfc_default_character_kind () + : mpz_get_si (kind->value.integer); + + f->value.function.name = + gfc_get_string ("__char_%d_%c%d", f->ts.kind, + gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_cmplx (gfc_expr * f, gfc_expr * x, gfc_expr * y, gfc_expr * kind) +{ + + f->ts.type = BT_COMPLEX; + f->ts.kind = (kind == NULL) ? gfc_default_real_kind () + : mpz_get_si (kind->value.integer); + + if (y == NULL) + f->value.function.name = + gfc_get_string ("__cmplx0_%d_%c%d", f->ts.kind, + gfc_type_letter (x->ts.type), x->ts.kind); + else + f->value.function.name = + gfc_get_string ("__cmplx1_%d_%c%d_%c%d", f->ts.kind, + gfc_type_letter (x->ts.type), x->ts.kind, + gfc_type_letter (y->ts.type), y->ts.kind); +} + +void +gfc_resolve_dcmplx (gfc_expr * f, gfc_expr * x, gfc_expr * y) +{ + gfc_resolve_cmplx (f, x, y, gfc_int_expr (gfc_default_double_kind ())); +} + +void +gfc_resolve_conjg (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = gfc_get_string ("__conjg_%d", x->ts.kind); +} + + +void +gfc_resolve_cos (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__cos_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_cosh (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__cosh_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_count (gfc_expr * f, gfc_expr * mask, gfc_expr * dim) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + + if (dim != NULL) + { + f->rank = mask->rank - 1; + gfc_resolve_index (dim, 1); + } + + f->value.function.name = + gfc_get_string ("__count_%d_%c%d", f->ts.kind, + gfc_type_letter (mask->ts.type), mask->ts.kind); +} + + +void +gfc_resolve_cshift (gfc_expr * f, gfc_expr * array, + gfc_expr * shift, + gfc_expr * dim) +{ + int n; + + f->ts = array->ts; + f->rank = array->rank; + + if (shift->rank > 0) + n = 1; + else + n = 0; + + if (dim != NULL) + { + gfc_resolve_index (dim, 1); + /* Convert dim to shift's kind, so we don't need so many variations. */ + if (dim->ts.kind != shift->ts.kind) + gfc_convert_type (dim, &shift->ts, 2); + } + f->value.function.name = + gfc_get_string ("__cshift%d_%d", n, shift->ts.kind); +} + + +void +gfc_resolve_dble (gfc_expr * f, gfc_expr * a) +{ + + f->ts.type = BT_REAL; + f->ts.kind = gfc_default_double_kind (); + f->value.function.name = + gfc_get_string ("__dble_%c%d", gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_dim (gfc_expr * f, gfc_expr * x, + gfc_expr * y ATTRIBUTE_UNUSED) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__dim_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_dot_product (gfc_expr * f, gfc_expr * a, gfc_expr * b) +{ + gfc_expr temp; + + if (a->ts.type == BT_LOGICAL && b->ts.type == BT_LOGICAL) + { + f->ts.type = BT_LOGICAL; + f->ts.kind = gfc_default_logical_kind (); + } + else + { + temp.expr_type = EXPR_OP; + gfc_clear_ts (&temp.ts); + temp.operator = INTRINSIC_NONE; + temp.op1 = a; + temp.op2 = b; + gfc_type_convert_binary (&temp); + f->ts = temp.ts; + } + + f->value.function.name = + gfc_get_string ("__dot_product_%c%d", gfc_type_letter (f->ts.type), + f->ts.kind); +} + + +void +gfc_resolve_dprod (gfc_expr * f, + gfc_expr * a ATTRIBUTE_UNUSED, + gfc_expr * b ATTRIBUTE_UNUSED) +{ + f->ts.kind = gfc_default_double_kind (); + f->ts.type = BT_REAL; + + f->value.function.name = gfc_get_string ("__dprod_r%d", f->ts.kind); +} + + +void +gfc_resolve_eoshift (gfc_expr * f, gfc_expr * array, + gfc_expr * shift, + gfc_expr * boundary, + gfc_expr * dim) +{ + int n; + + f->ts = array->ts; + f->rank = array->rank; + + n = 0; + if (shift->rank > 0) + n = n | 1; + if (boundary && boundary->rank > 0) + n = n | 2; + + /* Convert dim to the same type as shift, so we don't need quite so many + variations. */ + if (dim != NULL && dim->ts.kind != shift->ts.kind) + gfc_convert_type (dim, &shift->ts, 2); + + f->value.function.name = + gfc_get_string ("__eoshift%d_%d", n, shift->ts.kind); +} + + +void +gfc_resolve_exp (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__exp_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_exponent (gfc_expr * f, gfc_expr * x) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + + f->value.function.name = gfc_get_string ("__exponent_%d", x->ts.kind); +} + + +void +gfc_resolve_floor (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = (kind == NULL) ? gfc_default_integer_kind () + : mpz_get_si (kind->value.integer); + + f->value.function.name = + gfc_get_string ("__floor%d_%c%d", f->ts.kind, + gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_fraction (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = gfc_get_string ("__fraction_%d", x->ts.kind); +} + + +void +gfc_resolve_iand (gfc_expr * f, gfc_expr * i, gfc_expr * j ATTRIBUTE_UNUSED) +{ + + f->ts = i->ts; + f->value.function.name = gfc_get_string ("__iand_%d", i->ts.kind); +} + + +void +gfc_resolve_ibclr (gfc_expr * f, gfc_expr * i, gfc_expr * pos ATTRIBUTE_UNUSED) +{ + + f->ts = i->ts; + f->value.function.name = gfc_get_string ("__ibclr_%d", i->ts.kind); +} + + +void +gfc_resolve_ibits (gfc_expr * f, gfc_expr * i, + gfc_expr * pos ATTRIBUTE_UNUSED, + gfc_expr * len ATTRIBUTE_UNUSED) +{ + + f->ts = i->ts; + f->value.function.name = gfc_get_string ("__ibits_%d", i->ts.kind); +} + + +void +gfc_resolve_ibset (gfc_expr * f, gfc_expr * i, + gfc_expr * pos ATTRIBUTE_UNUSED) +{ + + f->ts = i->ts; + f->value.function.name = gfc_get_string ("__ibset_%d", i->ts.kind); +} + + +void +gfc_resolve_ichar (gfc_expr * f, gfc_expr * c) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + + f->value.function.name = gfc_get_string ("__ichar_%d", c->ts.kind); +} + + +void +gfc_resolve_idnint (gfc_expr * f, gfc_expr * a) +{ + gfc_resolve_nint (f, a, NULL); +} + + +void +gfc_resolve_ieor (gfc_expr * f, gfc_expr * i, + gfc_expr * j ATTRIBUTE_UNUSED) +{ + + f->ts = i->ts; + f->value.function.name = gfc_get_string ("__ieor_%d", i->ts.kind); +} + + +void +gfc_resolve_ior (gfc_expr * f, gfc_expr * i, + gfc_expr * j ATTRIBUTE_UNUSED) +{ + + f->ts = i->ts; + f->value.function.name = gfc_get_string ("__ior_%d", i->ts.kind); +} + + +void +gfc_resolve_int (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = (kind == NULL) ? gfc_default_integer_kind () + : mpz_get_si (kind->value.integer); + + f->value.function.name = + gfc_get_string ("__int_%d_%c%d", f->ts.kind, gfc_type_letter (a->ts.type), + a->ts.kind); +} + + +void +gfc_resolve_ishft (gfc_expr * f, gfc_expr * i, gfc_expr * shift) +{ + + f->ts = i->ts; + f->value.function.name = + gfc_get_string ("__ishft_%d_%d", i->ts.kind, shift->ts.kind); +} + + +void +gfc_resolve_ishftc (gfc_expr * f, gfc_expr * i, gfc_expr * shift, + gfc_expr * size) +{ + int s_kind; + + s_kind = (size == NULL) ? gfc_default_integer_kind () : shift->ts.kind; + + f->ts = i->ts; + f->value.function.name = + gfc_get_string ("__ishftc_%d_%d_%d", i->ts.kind, shift->ts.kind, s_kind); +} + + +void +gfc_resolve_lbound (gfc_expr * f, gfc_expr * array ATTRIBUTE_UNUSED, + gfc_expr * dim) +{ + static char lbound[] = "__lbound"; + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + + f->rank = (dim == NULL) ? 1 : 0; + f->value.function.name = lbound; +} + + +void +gfc_resolve_len (gfc_expr * f, gfc_expr * string) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + f->value.function.name = gfc_get_string ("__len_%d", string->ts.kind); +} + + +void +gfc_resolve_len_trim (gfc_expr * f, gfc_expr * string) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + f->value.function.name = gfc_get_string ("__len_trim%d", string->ts.kind); +} + + +void +gfc_resolve_log (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__log_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_log10 (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__log10_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_logical (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = BT_LOGICAL; + f->ts.kind = (kind == NULL) ? gfc_default_logical_kind () + : mpz_get_si (kind->value.integer); + f->rank = a->rank; + + f->value.function.name = + gfc_get_string ("__logical_%d_%c%d", f->ts.kind, + gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_matmul (gfc_expr * f, gfc_expr * a, gfc_expr * b) +{ + gfc_expr temp; + + if (a->ts.type == BT_LOGICAL && b->ts.type == BT_LOGICAL) + { + f->ts.type = BT_LOGICAL; + f->ts.kind = gfc_default_logical_kind (); + } + else + { + temp.expr_type = EXPR_OP; + gfc_clear_ts (&temp.ts); + temp.operator = INTRINSIC_NONE; + temp.op1 = a; + temp.op2 = b; + gfc_type_convert_binary (&temp); + f->ts = temp.ts; + } + + f->rank = (a->rank == 2 && b->rank == 2) ? 2 : 1; + + f->value.function.name = + gfc_get_string ("__matmul_%c%d", gfc_type_letter (f->ts.type), + f->ts.kind); +} + + +static void +gfc_resolve_minmax (const char * name, gfc_expr * f, gfc_actual_arglist * args) +{ + gfc_actual_arglist *a; + + f->ts.type = args->expr->ts.type; + f->ts.kind = args->expr->ts.kind; + /* Find the largest type kind. */ + for (a = args->next; a; a = a->next) + { + if (a->expr->ts.kind > f->ts.kind) + f->ts.kind = a->expr->ts.kind; + } + + /* Convert all parameters to the required kind. */ + for (a = args; a; a = a->next) + { + if (a->expr->ts.kind != f->ts.kind) + gfc_convert_type (a->expr, &f->ts, 2); + } + + f->value.function.name = + gfc_get_string (name, gfc_type_letter (f->ts.type), f->ts.kind); +} + + +void +gfc_resolve_max (gfc_expr * f, gfc_actual_arglist * args) +{ + gfc_resolve_minmax ("__max_%c%d", f, args); +} + + +void +gfc_resolve_maxloc (gfc_expr * f, gfc_expr * array, gfc_expr * dim, + gfc_expr * mask) +{ + const char *name; + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + + if (dim == NULL) + f->rank = 1; + else + { + f->rank = array->rank - 1; + gfc_resolve_index (dim, 1); + } + + name = mask ? "mmaxloc" : "maxloc"; + f->value.function.name = + gfc_get_string ("__%s%d_%d_%c%d", name, dim != NULL, f->ts.kind, + gfc_type_letter (array->ts.type), array->ts.kind); +} + + +void +gfc_resolve_maxval (gfc_expr * f, gfc_expr * array, gfc_expr * dim, + gfc_expr * mask) +{ + + f->ts = array->ts; + + if (dim != NULL) + { + f->rank = array->rank - 1; + gfc_resolve_index (dim, 1); + } + + f->value.function.name = + gfc_get_string ("__%s_%c%d", mask ? "mmaxval" : "maxval", + gfc_type_letter (array->ts.type), array->ts.kind); +} + + +void +gfc_resolve_merge (gfc_expr * f, gfc_expr * tsource, + gfc_expr * fsource ATTRIBUTE_UNUSED, + gfc_expr * mask ATTRIBUTE_UNUSED) +{ + + f->ts = tsource->ts; + f->value.function.name = + gfc_get_string ("__merge_%c%d", gfc_type_letter (tsource->ts.type), + tsource->ts.kind); +} + + +void +gfc_resolve_min (gfc_expr * f, gfc_actual_arglist * args) +{ + gfc_resolve_minmax ("__min_%c%d", f, args); +} + + +void +gfc_resolve_minloc (gfc_expr * f, gfc_expr * array, gfc_expr * dim, + gfc_expr * mask) +{ + const char *name; + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + + if (dim == NULL) + f->rank = 1; + else + { + f->rank = array->rank - 1; + gfc_resolve_index (dim, 1); + } + + name = mask ? "mminloc" : "minloc"; + f->value.function.name = + gfc_get_string ("__%s%d_%d_%c%d", name, dim != NULL, f->ts.kind, + gfc_type_letter (array->ts.type), array->ts.kind); +} + +void +gfc_resolve_minval (gfc_expr * f, gfc_expr * array, gfc_expr * dim, + gfc_expr * mask) +{ + + f->ts = array->ts; + + if (dim != NULL) + { + f->rank = array->rank - 1; + gfc_resolve_index (dim, 1); + } + + f->value.function.name = + gfc_get_string ("__%s_%c%d", mask ? "mminval" : "minval", + gfc_type_letter (array->ts.type), array->ts.kind); +} + + +void +gfc_resolve_mod (gfc_expr * f, gfc_expr * a, + gfc_expr * p ATTRIBUTE_UNUSED) +{ + + f->ts = a->ts; + f->value.function.name = + gfc_get_string ("__mod_%c%d", gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_modulo (gfc_expr * f, gfc_expr * a, + gfc_expr * p ATTRIBUTE_UNUSED) +{ + + f->ts = a->ts; + f->value.function.name = + gfc_get_string ("__modulo_%c%d", gfc_type_letter (a->ts.type), + a->ts.kind); +} + + +void +gfc_resolve_nint (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = (kind == NULL) ? gfc_default_integer_kind () + : mpz_get_si (kind->value.integer); + + f->value.function.name = + gfc_get_string ("__nint_%d_%d", f->ts.kind, a->ts.kind); +} + + +void +gfc_resolve_not (gfc_expr * f, gfc_expr * i) +{ + + f->ts = i->ts; + f->value.function.name = gfc_get_string ("__not_%d", i->ts.kind); +} + + +void +gfc_resolve_pack (gfc_expr * f, + gfc_expr * array ATTRIBUTE_UNUSED, + gfc_expr * mask ATTRIBUTE_UNUSED, + gfc_expr * vector ATTRIBUTE_UNUSED) +{ + static char pack[] = "__pack"; + + f->ts = array->ts; + f->rank = 1; + + f->value.function.name = pack; +} + + +void +gfc_resolve_product (gfc_expr * f, gfc_expr * array, gfc_expr * dim, + gfc_expr * mask) +{ + + f->ts = array->ts; + + if (dim != NULL) + { + f->rank = array->rank - 1; + gfc_resolve_index (dim, 1); + } + + f->value.function.name = + gfc_get_string ("__%s_%c%d", mask ? "mproduct" : "product", + gfc_type_letter (array->ts.type), array->ts.kind); +} + + +void +gfc_resolve_real (gfc_expr * f, gfc_expr * a, gfc_expr * kind) +{ + + f->ts.type = BT_REAL; + + if (kind != NULL) + f->ts.kind = mpz_get_si (kind->value.integer); + else + f->ts.kind = (a->ts.type == BT_COMPLEX) ? + a->ts.kind : gfc_default_real_kind (); + + f->value.function.name = + gfc_get_string ("__real_%d_%c%d", f->ts.kind, + gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_repeat (gfc_expr * f, gfc_expr * string, + gfc_expr * ncopies ATTRIBUTE_UNUSED) +{ + + f->ts.type = BT_CHARACTER; + f->ts.kind = string->ts.kind; + f->value.function.name = gfc_get_string ("__repeat_%d", string->ts.kind); +} + + +void +gfc_resolve_reshape (gfc_expr * f, gfc_expr * source, gfc_expr * shape, + gfc_expr * pad ATTRIBUTE_UNUSED, + gfc_expr * order ATTRIBUTE_UNUSED) +{ + static char reshape0[] = "__reshape"; + mpz_t rank; + int kind; + int i; + + f->ts = source->ts; + + gfc_array_size (shape, &rank); + f->rank = mpz_get_si (rank); + mpz_clear (rank); + switch (source->ts.type) + { + case BT_COMPLEX: + kind = source->ts.kind * 2; + break; + + case BT_REAL: + case BT_INTEGER: + case BT_LOGICAL: + kind = source->ts.kind; + break; + + default: + kind = 0; + break; + } + + switch (kind) + { + case 4: + case 8: + /* case 16: */ + f->value.function.name = + gfc_get_string ("__reshape_%d", source->ts.kind); + break; + + default: + f->value.function.name = reshape0; + break; + } + + /* TODO: Make this work with a constant ORDER parameter. */ + if (shape->expr_type == EXPR_ARRAY + && gfc_is_constant_expr (shape) + && order == NULL) + { + gfc_constructor *c; + f->shape = gfc_get_shape (f->rank); + c = shape->value.constructor; + for (i = 0; i < f->rank; i++) + { + mpz_init_set (f->shape[i], c->expr->value.integer); + c = c->next; + } + } +} + + +void +gfc_resolve_rrspacing (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = gfc_get_string ("__rrspacing_%d", x->ts.kind); +} + + +void +gfc_resolve_scale (gfc_expr * f, gfc_expr * x, + gfc_expr * y ATTRIBUTE_UNUSED) +{ + + f->ts = x->ts; + f->value.function.name = gfc_get_string ("__scale_%d_%d", x->ts.kind, + x->ts.kind); +} + + +void +gfc_resolve_scan (gfc_expr * f, gfc_expr * string, + gfc_expr * set ATTRIBUTE_UNUSED, + gfc_expr * back ATTRIBUTE_UNUSED) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + f->value.function.name = gfc_get_string ("__scan_%d", string->ts.kind); +} + + +void +gfc_resolve_set_exponent (gfc_expr * f, gfc_expr * x, gfc_expr * i) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__set_exponent_%d_%d", x->ts.kind, i->ts.kind); +} + + +void +gfc_resolve_shape (gfc_expr * f, gfc_expr * array) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + f->rank = 1; + f->value.function.name = gfc_get_string ("__shape_%d", f->ts.kind); + f->shape = gfc_get_shape (1); + mpz_init_set_ui (f->shape[0], array->rank); +} + + +void +gfc_resolve_sign (gfc_expr * f, gfc_expr * a, gfc_expr * b ATTRIBUTE_UNUSED) +{ + + f->ts = a->ts; + f->value.function.name = + gfc_get_string ("__sign_%c%d", gfc_type_letter (a->ts.type), a->ts.kind); +} + + +void +gfc_resolve_sin (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__sin_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_sinh (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__sinh_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_spacing (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = gfc_get_string ("__spacing_%d", x->ts.kind); +} + + +void +gfc_resolve_spread (gfc_expr * f, gfc_expr * source, + gfc_expr * dim, + gfc_expr * ncopies) +{ + static char spread[] = "__spread"; + + f->ts = source->ts; + f->rank = source->rank + 1; + f->value.function.name = spread; + + gfc_resolve_index (dim, 1); + gfc_resolve_index (ncopies, 1); +} + + +void +gfc_resolve_sqrt (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__sqrt_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_sum (gfc_expr * f, gfc_expr * array, gfc_expr * dim, + gfc_expr * mask) +{ + + f->ts = array->ts; + + if (dim != NULL) + { + f->rank = array->rank - 1; + gfc_resolve_index (dim, 1); + } + + f->value.function.name = + gfc_get_string ("__%s_%c%d", mask ? "msum" : "sum", + gfc_type_letter (array->ts.type), array->ts.kind); +} + + +void +gfc_resolve_tan (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__tan_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_tanh (gfc_expr * f, gfc_expr * x) +{ + + f->ts = x->ts; + f->value.function.name = + gfc_get_string ("__tanh_%c%d", gfc_type_letter (x->ts.type), x->ts.kind); +} + + +void +gfc_resolve_transfer (gfc_expr * f, gfc_expr * source ATTRIBUTE_UNUSED, + gfc_expr * mold, gfc_expr * size) +{ + /* TODO: Make this do something meaningful. */ + static char transfer0[] = "__transfer0", transfer1[] = "__transfer1"; + + f->ts = mold->ts; + + if (size == NULL && mold->rank == 0) + { + f->rank = 0; + f->value.function.name = transfer0; + } + else + { + f->rank = 1; + f->value.function.name = transfer1; + } +} + + +void +gfc_resolve_transpose (gfc_expr * f, gfc_expr * matrix) +{ + static char transpose0[] = "__transpose"; + int kind; + + f->ts = matrix->ts; + f->rank = 2; + + switch (matrix->ts.type) + { + case BT_COMPLEX: + kind = matrix->ts.kind * 2; + break; + + case BT_REAL: + case BT_INTEGER: + case BT_LOGICAL: + kind = matrix->ts.kind; + break; + + default: + kind = 0; + break; + + } + + switch (kind) + { + case 4: + case 8: + /* case 16: */ + f->value.function.name = + gfc_get_string ("__transpose_%d", kind); + break; + + default: + f->value.function.name = transpose0; + } +} + + +void +gfc_resolve_trim (gfc_expr * f, gfc_expr * string) +{ + + f->ts.type = BT_CHARACTER; + f->ts.kind = string->ts.kind; + f->value.function.name = gfc_get_string ("__trim_%d", string->ts.kind); +} + + +void +gfc_resolve_ubound (gfc_expr * f, gfc_expr * array ATTRIBUTE_UNUSED, + gfc_expr * dim) +{ + static char ubound[] = "__ubound"; + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + + f->rank = (dim == NULL) ? 1 : 0; + f->value.function.name = ubound; +} + + +void +gfc_resolve_unpack (gfc_expr * f, gfc_expr * vector, gfc_expr * mask, + gfc_expr * field ATTRIBUTE_UNUSED) +{ + + f->ts.type = vector->ts.type; + f->ts.kind = vector->ts.kind; + f->rank = mask->rank; + + f->value.function.name = + gfc_get_string ("__unpack%d", field->rank > 0 ? 1 : 0); +} + + +void +gfc_resolve_verify (gfc_expr * f, gfc_expr * string, + gfc_expr * set ATTRIBUTE_UNUSED, + gfc_expr * back ATTRIBUTE_UNUSED) +{ + + f->ts.type = BT_INTEGER; + f->ts.kind = gfc_default_integer_kind (); + f->value.function.name = gfc_get_string ("__verify_%d", string->ts.kind); +} + + +/* Intrinsic subroutine resolution. */ + +void +gfc_resolve_cpu_time (gfc_code * c ATTRIBUTE_UNUSED) +{ + const char *name; + + name = gfc_get_string (PREFIX("cpu_time_%d"), + c->ext.actual->expr->ts.kind); + c->resolved_sym = gfc_get_intrinsic_sub_symbol (name); +} + + +void +gfc_resolve_random_number (gfc_code * c ATTRIBUTE_UNUSED) +{ + const char *name; + int kind; + + kind = c->ext.actual->expr->ts.kind; + name = gfc_get_string ((c->ext.actual->expr->rank == 0) ? + PREFIX("random_r%d") : PREFIX("arandom_r%d"), + kind); + c->resolved_sym = gfc_get_intrinsic_sub_symbol (name); +} + + +void +gfc_iresolve_init_1 (void) +{ + int i; + + for (i = 0; i < HASH_SIZE; i++) + string_head[i] = NULL; +} + + +void +gfc_iresolve_done_1 (void) +{ + + free_strings (); +} diff --git a/gcc/fortran/lang-specs.h b/gcc/fortran/lang-specs.h new file mode 100644 index 00000000000..3d8d7c4cbca --- /dev/null +++ b/gcc/fortran/lang-specs.h @@ -0,0 +1,35 @@ +/* Contribution to the specs for the GNU Compiler Collection + from GNU Fortran 95 compiler. + Copyright (C) 2002,2004 Free Software Foundation, Inc. + +This file is licensed under the GPL. */ + +/* This is the contribution to the `default_compilers' array in gcc.c + for the f95 language. */ + +{".F", "@f77-cpp-input", 0}, +{".fpp", "@f77-cpp-input", 0}, +{".FPP", "@f77-cpp-input", 0}, +{"@f77-cpp-input", + "cc1 -P -E -traditional-cpp -D_LANGUAGE_FORTRAN %(cpp_options) \ + %{E|M|MM:%(cpp_debug_options)}\ + %{!M:%{!MM:%{!E: -o %|.f |\n\ + f951 %|.f %{!ffree-form:-ffixed-form} %(cc1_options) %{J*} %{I*}\ + %{!fsyntax-only:%(invoke_as)}}}}", 0}, +{".F90", "@f95-cpp-input", 0}, +{".F95", "@f95-cpp-input", 0}, +{"@f95-cpp-input", + "cc1 -P -E -traditional-cpp -D_LANGUAGE_FORTRAN %(cpp_options) \ + %{E|M|MM:%(cpp_debug_options)}\ + %{!M:%{!MM:%{!E: -o %|.f95 |\n\ + f951 %|.f95 %(cc1_options) %{J*} %{I*}\ + %{!fsyntax-only:%(invoke_as)}}}}", 0}, +{".f90", "@f95", 0}, +{".f95", "@f95", 0}, +{"@f95", "%{!E:f951 %i %(cc1_options) %{J*} %{I*}\ + %{!fsyntax-only:%(invoke_as)}}", 0}, +{".f", "@f77", 0}, +{".for", "@f77", 0}, +{".FOR", "@f77", 0}, +{"@f77", "%{!E:f951 %i %{!ffree-form:-ffixed-form} %(cc1_options) %{J*} %{I*}\ + %{!fsyntax-only:%(invoke_as)}}", 0}, diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt new file mode 100644 index 00000000000..593e3f15eed --- /dev/null +++ b/gcc/fortran/lang.opt @@ -0,0 +1,152 @@ +; Options for the Fortran 95 front end. +; Copyright (C) 2003 Free Software Foundation, Inc. +; +; This file is part of GCC. +; +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 2, or (at your option) any later +; version. +; +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; for more details. +; +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING. If not, write to the Free +; Software Foundation, 59 Temple Place - Suite 330, Boston, MA +; 02111-1307, USA. + +; See c.opt for a description of this file's format. + +; Please try to keep this file in ASCII collating order. + +Language +F95 + +I +F95 Joined +-I Add a directory for INCLUDE and MODULE searching + +J +F95 Joined +-J Put MODULE files in 'directory' + +Wall +F95 RejectNegative +; Documented in C + +Waliasing +F95 +Warn about possible aliasing of dummy arguments + +Wconversion +F95 +Warn about implicit conversion + +Wimplicit-interface +F95 +Warn about calls with implicit interface + +Wline-truncation +F95 +Warn about truncated source lines + +Wsurprising +F95 +Warn about \"suspicious\" constructs + +Wunused-labels +F95 +Warn when a label is unused + +d8 +F95 RejectNegative +Set the default real and integer kinds to double precision + +fdollar-ok +F95 +Allow dollar signs in entity names + +fdump-parse-tree +F95 +Display the code tree after parsing. + +ffixed-form +F95 +Assume that the source file is fixed form + +ffree-form +F95 +Assume that the source file is free form + +funderscoring +F95 +Append underscores to externally visible names + +fsecond-underscore +F95 +Append a second underscore if the name already contains an underscore + +fimplicit-none +F95 +Specify that no implicit typing is allowed, unless overridden by explicit IMPLICIT statements + +ffixed-line-length-80 +F95 RejectNegative +Use 80 character line width in fixed mode + +ffixed-line-length-132 +F95 RejectNegative +Use 132 character line width in fixed mode + +fmax-identifier-length= +F95 RejectNegative Joined UInteger +-fmax-identifier-length= Maximum identifier length. + +fmax-stack-var-size= +F95 RejectNegative Joined UInteger +-fmax-stack-var-size= Size in bytes of the largest array that will be put on the stack + +fmodule-private +F95 +Set default accessibility of module entities to PRIVATE + +fno-backend +F95 RejectNegative +Don't generate code, just do syntax and semantics checking + +fpack-derived +F95 +Try to layout derived types as compact as possible + +frepack-arrays +F95 +Copy array sections into a contiguous block on procedure entry + +i8 +F95 +Set the default integer kind to double precision + +qkind= +F95 RejectNegative Joined UInteger +-qkind= Set the kind for a real with the 'q' exponent to 'n' + +r8 +F95 +Set the default real kind to double precision + +std=f95 +F95 +Conform to the ISO Fortran 95 standard. + +std=f2003 +F95 +Conform to the ISO Fortran 2003 standard. + +std=gnu +F95 +Conform nothing in particular. + +; This comment is to ensure we retain the blank line above. diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c new file mode 100644 index 00000000000..3c7504159a9 --- /dev/null +++ b/gcc/fortran/match.c @@ -0,0 +1,3558 @@ +/* Matching subroutines in all sizes, shapes and colors. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include "system.h" +#include "flags.h" + +#include +#include + +#include "gfortran.h" +#include "match.h" +#include "parse.h" + +/* For matching and debugging purposes. Order matters here! The + unary operators /must/ precede the binary plus and minus, or + the expression parser breaks. */ + +mstring intrinsic_operators[] = { + minit ("+", INTRINSIC_UPLUS), + minit ("-", INTRINSIC_UMINUS), + minit ("+", INTRINSIC_PLUS), + minit ("-", INTRINSIC_MINUS), + minit ("**", INTRINSIC_POWER), + minit ("//", INTRINSIC_CONCAT), + minit ("*", INTRINSIC_TIMES), + minit ("/", INTRINSIC_DIVIDE), + minit (".and.", INTRINSIC_AND), + minit (".or.", INTRINSIC_OR), + minit (".eqv.", INTRINSIC_EQV), + minit (".neqv.", INTRINSIC_NEQV), + minit (".eq.", INTRINSIC_EQ), + minit ("==", INTRINSIC_EQ), + minit (".ne.", INTRINSIC_NE), + minit ("/=", INTRINSIC_NE), + minit (".ge.", INTRINSIC_GE), + minit (">=", INTRINSIC_GE), + minit (".le.", INTRINSIC_LE), + minit ("<=", INTRINSIC_LE), + minit (".lt.", INTRINSIC_LT), + minit ("<", INTRINSIC_LT), + minit (".gt.", INTRINSIC_GT), + minit (">", INTRINSIC_GT), + minit (".not.", INTRINSIC_NOT), + minit (NULL, INTRINSIC_NONE) +}; + + +/******************** Generic matching subroutines ************************/ + +/* In free form, match at least one space. Always matches in fixed + form. */ + +match +gfc_match_space (void) +{ + locus old_loc; + int c; + + if (gfc_current_file->form == FORM_FIXED) + return MATCH_YES; + + old_loc = *gfc_current_locus (); + + c = gfc_next_char (); + if (!gfc_is_whitespace (c)) + { + gfc_set_locus (&old_loc); + return MATCH_NO; + } + + gfc_gobble_whitespace (); + + return MATCH_YES; +} + + +/* Match an end of statement. End of statement is optional + whitespace, followed by a ';' or '\n' or comment '!'. If a + semicolon is found, we continue to eat whitespace and semicolons. */ + +match +gfc_match_eos (void) +{ + locus old_loc; + int flag, c; + + flag = 0; + + for (;;) + { + old_loc = *gfc_current_locus (); + gfc_gobble_whitespace (); + + c = gfc_next_char (); + switch (c) + { + case '!': + do + { + c = gfc_next_char (); + } + while (c != '\n'); + + /* Fall through */ + + case '\n': + return MATCH_YES; + + case ';': + flag = 1; + continue; + } + + break; + } + + gfc_set_locus (&old_loc); + return (flag) ? MATCH_YES : MATCH_NO; +} + + +/* Match a literal integer on the input, setting the value on + MATCH_YES. Literal ints occur in kind-parameters as well as + old-style character length specifications. */ + +match +gfc_match_small_literal_int (int *value) +{ + locus old_loc; + char c; + int i; + + old_loc = *gfc_current_locus (); + + gfc_gobble_whitespace (); + c = gfc_next_char (); + + if (!ISDIGIT (c)) + { + gfc_set_locus (&old_loc); + return MATCH_NO; + } + + i = c - '0'; + + for (;;) + { + old_loc = *gfc_current_locus (); + c = gfc_next_char (); + + if (!ISDIGIT (c)) + break; + + i = 10 * i + c - '0'; + + if (i > 99999999) + { + gfc_error ("Integer too large at %C"); + return MATCH_ERROR; + } + } + + gfc_set_locus (&old_loc); + + *value = i; + return MATCH_YES; +} + + +/* Match a small, constant integer expression, like in a kind + statement. On MATCH_YES, 'value' is set. */ + +match +gfc_match_small_int (int *value) +{ + gfc_expr *expr; + const char *p; + match m; + int i; + + m = gfc_match_expr (&expr); + if (m != MATCH_YES) + return m; + + p = gfc_extract_int (expr, &i); + gfc_free_expr (expr); + + if (p != NULL) + { + gfc_error (p); + m = MATCH_ERROR; + } + + *value = i; + return m; +} + + +/* Matches a statement label. Uses gfc_match_small_literal_int() to + do most of the work. */ + +match +gfc_match_st_label (gfc_st_label ** label, int allow_zero) +{ + locus old_loc; + match m; + int i; + + old_loc = *gfc_current_locus (); + + m = gfc_match_small_literal_int (&i); + if (m != MATCH_YES) + return m; + + if (((i == 0) && allow_zero) || i <= 99999) + { + *label = gfc_get_st_label (i); + return MATCH_YES; + } + + gfc_error ("Statement label at %C is out of range"); + gfc_set_locus (&old_loc); + return MATCH_ERROR; +} + + +/* Match and validate a label associated with a named IF, DO or SELECT + statement. If the symbol does not have the label attribute, we add + it. We also make sure the symbol does not refer to another + (active) block. A matched label is pointed to by gfc_new_block. */ + +match +gfc_match_label (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_state_data *p; + match m; + + gfc_new_block = NULL; + + m = gfc_match (" %n :", name); + if (m != MATCH_YES) + return m; + + if (gfc_get_symbol (name, NULL, &gfc_new_block)) + { + gfc_error ("Label name '%s' at %C is ambiguous", name); + return MATCH_ERROR; + } + + if (gfc_new_block->attr.flavor != FL_LABEL + && gfc_add_flavor (&gfc_new_block->attr, FL_LABEL, NULL) == FAILURE) + return MATCH_ERROR; + + for (p = gfc_state_stack; p; p = p->previous) + if (p->sym == gfc_new_block) + { + gfc_error ("Label %s at %C already in use by a parent block", + gfc_new_block->name); + return MATCH_ERROR; + } + + return MATCH_YES; +} + + +/* Try and match the input against an array of possibilities. If one + potential matching string is a substring of another, the longest + match takes precedence. Spaces in the target strings are optional + spaces that do not necessarily have to be found in the input + stream. In fixed mode, spaces never appear. If whitespace is + matched, it matches unlimited whitespace in the input. For this + reason, the 'mp' member of the mstring structure is used to track + the progress of each potential match. + + If there is no match we return the tag associated with the + terminating NULL mstring structure and leave the locus pointer + where it started. If there is a match we return the tag member of + the matched mstring and leave the locus pointer after the matched + character. + + A '%' character is a mandatory space. */ + +int +gfc_match_strings (mstring * a) +{ + mstring *p, *best_match; + int no_match, c, possibles; + locus match_loc; + + possibles = 0; + + for (p = a; p->string != NULL; p++) + { + p->mp = p->string; + possibles++; + } + + no_match = p->tag; + + best_match = NULL; + match_loc = *gfc_current_locus (); + + gfc_gobble_whitespace (); + + while (possibles > 0) + { + c = gfc_next_char (); + + /* Apply the next character to the current possibilities. */ + for (p = a; p->string != NULL; p++) + { + if (p->mp == NULL) + continue; + + if (*p->mp == ' ') + { + /* Space matches 1+ whitespace(s). */ + if ((gfc_current_file->form == FORM_FREE) + && gfc_is_whitespace (c)) + continue; + + p->mp++; + } + + if (*p->mp != c) + { + /* Match failed. */ + p->mp = NULL; + possibles--; + continue; + } + + p->mp++; + if (*p->mp == '\0') + { + /* Found a match. */ + match_loc = *gfc_current_locus (); + best_match = p; + possibles--; + p->mp = NULL; + } + } + } + + gfc_set_locus (&match_loc); + + return (best_match == NULL) ? no_match : best_match->tag; +} + + +/* See if the current input looks like a name of some sort. Modifies + the passed buffer which must be GFC_MAX_SYMBOL_LEN+1 bytes long. */ + +match +gfc_match_name (char *buffer) +{ + locus old_loc; + int i, c; + + old_loc = *gfc_current_locus (); + gfc_gobble_whitespace (); + + c = gfc_next_char (); + if (!ISALPHA (c)) + { + gfc_set_locus (&old_loc); + return MATCH_NO; + } + + i = 0; + + do + { + buffer[i++] = c; + + if (i > gfc_option.max_identifier_length) + { + gfc_error ("Name at %C is too long"); + return MATCH_ERROR; + } + + old_loc = *gfc_current_locus (); + c = gfc_next_char (); + } + while (ISALNUM (c) + || c == '_' + || (gfc_option.flag_dollar_ok && c == '$')); + + buffer[i] = '\0'; + gfc_set_locus (&old_loc); + + return MATCH_YES; +} + + +/* Match a symbol on the input. Modifies the pointer to the symbol + pointer if successful. */ + +match +gfc_match_sym_tree (gfc_symtree ** matched_symbol, int host_assoc) +{ + char buffer[GFC_MAX_SYMBOL_LEN + 1]; + match m; + + m = gfc_match_name (buffer); + if (m != MATCH_YES) + return m; + + if (host_assoc) + return (gfc_get_ha_sym_tree (buffer, matched_symbol)) + ? MATCH_ERROR : MATCH_YES; + + if (gfc_get_sym_tree (buffer, NULL, matched_symbol)) + return MATCH_ERROR; + + return MATCH_YES; +} + + +match +gfc_match_symbol (gfc_symbol ** matched_symbol, int host_assoc) +{ + gfc_symtree *st; + match m; + + m = gfc_match_sym_tree (&st, host_assoc); + + if (m == MATCH_YES) + { + if (st) + *matched_symbol = st->n.sym; + else + *matched_symbol = NULL; + } + return m; +} + +/* Match an intrinsic operator. Returns an INTRINSIC enum. While matching, + we always find INTRINSIC_PLUS before INTRINSIC_UPLUS. We work around this + in matchexp.c. */ + +match +gfc_match_intrinsic_op (gfc_intrinsic_op * result) +{ + gfc_intrinsic_op op; + + op = (gfc_intrinsic_op) gfc_match_strings (intrinsic_operators); + + if (op == INTRINSIC_NONE) + return MATCH_NO; + + *result = op; + return MATCH_YES; +} + + +/* Match a loop control phrase: + + = , [, ] + + If the final integer expression is not present, a constant unity + expression is returned. We don't return MATCH_ERROR until after + the equals sign is seen. */ + +match +gfc_match_iterator (gfc_iterator * iter, int init_flag) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_expr *var, *e1, *e2, *e3; + locus start; + match m; + + /* Match the start of an iterator without affecting the symbol + table. */ + + start = *gfc_current_locus (); + m = gfc_match (" %n =", name); + gfc_set_locus (&start); + + if (m != MATCH_YES) + return MATCH_NO; + + m = gfc_match_variable (&var, 0); + if (m != MATCH_YES) + return MATCH_NO; + + gfc_match_char ('='); + + e1 = e2 = e3 = NULL; + + if (var->ref != NULL) + { + gfc_error ("Loop variable at %C cannot be a sub-component"); + goto cleanup; + } + + if (var->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error ("Loop variable '%s' at %C cannot be INTENT(IN)", + var->symtree->n.sym->name); + goto cleanup; + } + + if (var->symtree->n.sym->attr.pointer) + { + gfc_error ("Loop variable at %C cannot have the POINTER attribute"); + goto cleanup; + } + + m = init_flag ? gfc_match_init_expr (&e1) : gfc_match_expr (&e1); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + m = init_flag ? gfc_match_init_expr (&e2) : gfc_match_expr (&e2); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (',') != MATCH_YES) + { + e3 = gfc_int_expr (1); + goto done; + } + + m = init_flag ? gfc_match_init_expr (&e3) : gfc_match_expr (&e3); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + gfc_error ("Expected a step value in iterator at %C"); + goto cleanup; + } + +done: + iter->var = var; + iter->start = e1; + iter->end = e2; + iter->step = e3; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in iterator at %C"); + +cleanup: + gfc_free_expr (e1); + gfc_free_expr (e2); + gfc_free_expr (e3); + + return MATCH_ERROR; +} + + +/* Tries to match the next non-whitespace character on the input. + This subroutine does not return MATCH_ERROR. */ + +match +gfc_match_char (char c) +{ + locus where; + + where = *gfc_current_locus (); + gfc_gobble_whitespace (); + + if (gfc_next_char () == c) + return MATCH_YES; + + gfc_set_locus (&where); + return MATCH_NO; +} + + +/* General purpose matching subroutine. The target string is a + scanf-like format string in which spaces correspond to arbitrary + whitespace (including no whitespace), characters correspond to + themselves. The %-codes are: + + %% Literal percent sign + %e Expression, pointer to a pointer is set + %s Symbol, pointer to the symbol is set + %n Name, character buffer is set to name + %t Matches end of statement. + %o Matches an intrinsic operator, returned as an INTRINSIC enum. + %l Matches a statement label + %v Matches a variable expression (an lvalue) + % Matches a required space (in free form) and optional spaces. */ + +match +gfc_match (const char *target, ...) +{ + gfc_st_label **label; + int matches, *ip; + locus old_loc; + va_list argp; + char c, *np; + match m, n; + void **vp; + const char *p; + + old_loc = *gfc_current_locus (); + va_start (argp, target); + m = MATCH_NO; + matches = 0; + p = target; + +loop: + c = *p++; + switch (c) + { + case ' ': + gfc_gobble_whitespace (); + goto loop; + case '\0': + m = MATCH_YES; + break; + + case '%': + c = *p++; + switch (c) + { + case 'e': + vp = va_arg (argp, void **); + n = gfc_match_expr ((gfc_expr **) vp); + if (n != MATCH_YES) + { + m = n; + goto not_yes; + } + + matches++; + goto loop; + + case 'v': + vp = va_arg (argp, void **); + n = gfc_match_variable ((gfc_expr **) vp, 0); + if (n != MATCH_YES) + { + m = n; + goto not_yes; + } + + matches++; + goto loop; + + case 's': + vp = va_arg (argp, void **); + n = gfc_match_symbol ((gfc_symbol **) vp, 0); + if (n != MATCH_YES) + { + m = n; + goto not_yes; + } + + matches++; + goto loop; + + case 'n': + np = va_arg (argp, char *); + n = gfc_match_name (np); + if (n != MATCH_YES) + { + m = n; + goto not_yes; + } + + matches++; + goto loop; + + case 'l': + label = va_arg (argp, gfc_st_label **); + n = gfc_match_st_label (label, 0); + if (n != MATCH_YES) + { + m = n; + goto not_yes; + } + + matches++; + goto loop; + + case 'o': + ip = va_arg (argp, int *); + n = gfc_match_intrinsic_op ((gfc_intrinsic_op *) ip); + if (n != MATCH_YES) + { + m = n; + goto not_yes; + } + + matches++; + goto loop; + + case 't': + if (gfc_match_eos () != MATCH_YES) + { + m = MATCH_NO; + goto not_yes; + } + goto loop; + + case ' ': + if (gfc_match_space () == MATCH_YES) + goto loop; + m = MATCH_NO; + goto not_yes; + + case '%': + break; /* Fall through to character matcher */ + + default: + gfc_internal_error ("gfc_match(): Bad match code %c", c); + } + + default: + if (c == gfc_next_char ()) + goto loop; + break; + } + +not_yes: + va_end (argp); + + if (m != MATCH_YES) + { + /* Clean up after a failed match. */ + gfc_set_locus (&old_loc); + va_start (argp, target); + + p = target; + for (; matches > 0; matches--) + { + while (*p++ != '%'); + + switch (*p++) + { + case '%': + matches++; + break; /* Skip */ + + case 'I': + case 'L': + case 'C': + if (*p++ == 'e') + goto undo_expr; + break; + + /* Matches that don't have to be undone */ + case 'o': + case 'l': + case 'n': + case 's': + (void)va_arg (argp, void **); + break; + + case 'e': + case 'E': + case 'v': + undo_expr: + vp = va_arg (argp, void **); + gfc_free_expr (*vp); + *vp = NULL; + break; + } + } + + va_end (argp); + } + + return m; +} + + +/*********************** Statement level matching **********************/ + +/* Matches the start of a program unit, which is the program keyword + followed by an optional symbol. */ + +match +gfc_match_program (void) +{ + gfc_symbol *sym; + match m; + + m = gfc_match_eos (); + if (m == MATCH_YES) + return m; + + m = gfc_match ("% %s%t", &sym); + + if (m == MATCH_NO) + { + gfc_error ("Invalid form of PROGRAM statement at %C"); + m = MATCH_ERROR; + } + + if (m == MATCH_ERROR) + return m; + + if (gfc_add_flavor (&sym->attr, FL_PROGRAM, NULL) == FAILURE) + return MATCH_ERROR; + + gfc_new_block = sym; + + return MATCH_YES; +} + + +/* Match a simple assignment statement. */ + +match +gfc_match_assignment (void) +{ + gfc_expr *lvalue, *rvalue; + locus old_loc; + match m; + + old_loc = *gfc_current_locus (); + + lvalue = rvalue = NULL; + m = gfc_match (" %v =", &lvalue); + if (m != MATCH_YES) + goto cleanup; + + m = gfc_match (" %e%t", &rvalue); + if (m != MATCH_YES) + goto cleanup; + + gfc_set_sym_referenced (lvalue->symtree->n.sym); + + new_st.op = EXEC_ASSIGN; + new_st.expr = lvalue; + new_st.expr2 = rvalue; + + return MATCH_YES; + +cleanup: + gfc_set_locus (&old_loc); + gfc_free_expr (lvalue); + gfc_free_expr (rvalue); + return m; +} + + +/* Match a pointer assignment statement. */ + +match +gfc_match_pointer_assignment (void) +{ + gfc_expr *lvalue, *rvalue; + locus old_loc; + match m; + + old_loc = *gfc_current_locus (); + + lvalue = rvalue = NULL; + + m = gfc_match (" %v =>", &lvalue); + if (m != MATCH_YES) + { + m = MATCH_NO; + goto cleanup; + } + + m = gfc_match (" %e%t", &rvalue); + if (m != MATCH_YES) + goto cleanup; + + new_st.op = EXEC_POINTER_ASSIGN; + new_st.expr = lvalue; + new_st.expr2 = rvalue; + + return MATCH_YES; + +cleanup: + gfc_set_locus (&old_loc); + gfc_free_expr (lvalue); + gfc_free_expr (rvalue); + return m; +} + + +/* The IF statement is a bit of a pain. First of all, there are three + forms of it, the simple IF, the IF that starts a block and the + arithmetic IF. + + There is a problem with the simple IF and that is the fact that we + only have a single level of undo information on symbols. What this + means is for a simple IF, we must re-match the whole IF statement + multiple times in order to guarantee that the symbol table ends up + in the proper state. */ + +match +gfc_match_if (gfc_statement * if_type) +{ + gfc_expr *expr; + gfc_st_label *l1, *l2, *l3; + locus old_loc; + gfc_code *p; + match m, n; + + n = gfc_match_label (); + if (n == MATCH_ERROR) + return n; + + old_loc = *gfc_current_locus (); + + m = gfc_match (" if ( %e", &expr); + if (m != MATCH_YES) + return m; + + if (gfc_match_char (')') != MATCH_YES) + { + gfc_error ("Syntax error in IF-expression at %C"); + gfc_free_expr (expr); + return MATCH_ERROR; + } + + m = gfc_match (" %l , %l , %l%t", &l1, &l2, &l3); + + if (m == MATCH_YES) + { + if (n == MATCH_YES) + { + gfc_error + ("Block label not appropriate for arithmetic IF statement " + "at %C"); + + gfc_free_expr (expr); + return MATCH_ERROR; + } + + if (gfc_reference_st_label (l1, ST_LABEL_TARGET) == FAILURE + || gfc_reference_st_label (l2, ST_LABEL_TARGET) == FAILURE + || gfc_reference_st_label (l3, ST_LABEL_TARGET) == FAILURE) + { + + gfc_free_expr (expr); + return MATCH_ERROR; + } + + new_st.op = EXEC_ARITHMETIC_IF; + new_st.expr = expr; + new_st.label = l1; + new_st.label2 = l2; + new_st.label3 = l3; + + *if_type = ST_ARITHMETIC_IF; + return MATCH_YES; + } + + if (gfc_match (" then %t") == MATCH_YES) + { + new_st.op = EXEC_IF; + new_st.expr = expr; + + *if_type = ST_IF_BLOCK; + return MATCH_YES; + } + + if (n == MATCH_YES) + { + gfc_error ("Block label is not appropriate IF statement at %C"); + + gfc_free_expr (expr); + return MATCH_ERROR; + } + + /* At this point the only thing left is a simple IF statement. At + this point, n has to be MATCH_NO, so we don't have to worry about + re-matching a block label. From what we've got so far, try + matching an assignment. */ + + *if_type = ST_SIMPLE_IF; + + m = gfc_match_assignment (); + if (m == MATCH_YES) + goto got_match; + + gfc_free_expr (expr); + gfc_undo_symbols (); + gfc_set_locus (&old_loc); + + gfc_match (" if ( %e ) ", &expr); /* Guaranteed to match */ + + m = gfc_match_pointer_assignment (); + if (m == MATCH_YES) + goto got_match; + + gfc_free_expr (expr); + gfc_undo_symbols (); + gfc_set_locus (&old_loc); + + gfc_match (" if ( %e ) ", &expr); /* Guaranteed to match */ + + /* Look at the next keyword to see which matcher to call. Matching + the keyword doesn't affect the symbol table, so we don't have to + restore between tries. */ + +#define match(string, subr, statement) \ + if (gfc_match(string) == MATCH_YES) { m = subr(); goto got_match; } + + gfc_clear_error (); + + match ("allocate", gfc_match_allocate, ST_ALLOCATE) + match ("backspace", gfc_match_backspace, ST_BACKSPACE) + match ("call", gfc_match_call, ST_CALL) + match ("close", gfc_match_close, ST_CLOSE) + match ("continue", gfc_match_continue, ST_CONTINUE) + match ("cycle", gfc_match_cycle, ST_CYCLE) + match ("deallocate", gfc_match_deallocate, ST_DEALLOCATE) + match ("end file", gfc_match_endfile, ST_END_FILE) + match ("exit", gfc_match_exit, ST_EXIT) + match ("assign", gfc_match_assign, ST_LABEL_ASSIGNMENT) + match ("go to", gfc_match_goto, ST_GOTO) + match ("inquire", gfc_match_inquire, ST_INQUIRE) + match ("nullify", gfc_match_nullify, ST_NULLIFY) + match ("open", gfc_match_open, ST_OPEN) + match ("pause", gfc_match_pause, ST_NONE) + match ("print", gfc_match_print, ST_WRITE) + match ("read", gfc_match_read, ST_READ) + match ("return", gfc_match_return, ST_RETURN) + match ("rewind", gfc_match_rewind, ST_REWIND) + match ("pause", gfc_match_stop, ST_PAUSE) + match ("stop", gfc_match_stop, ST_STOP) + match ("write", gfc_match_write, ST_WRITE) + + /* All else has failed, so give up. See if any of the matchers has + stored an error message of some sort. */ + if (gfc_error_check () == 0) + gfc_error ("Unclassifiable statement in IF-clause at %C"); + + gfc_free_expr (expr); + return MATCH_ERROR; + +got_match: + if (m == MATCH_NO) + gfc_error ("Syntax error in IF-clause at %C"); + if (m != MATCH_YES) + { + gfc_free_expr (expr); + return MATCH_ERROR; + } + + /* At this point, we've matched the single IF and the action clause + is in new_st. Rearrange things so that the IF statement appears + in new_st. */ + + p = gfc_get_code (); + p->next = gfc_get_code (); + *p->next = new_st; + p->next->loc = *gfc_current_locus (); + + p->expr = expr; + p->op = EXEC_IF; + + gfc_clear_new_st (); + + new_st.op = EXEC_IF; + new_st.block = p; + + return MATCH_YES; +} + +#undef match + + +/* Match an ELSE statement. */ + +match +gfc_match_else (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + + if (gfc_match_eos () == MATCH_YES) + return MATCH_YES; + + if (gfc_match_name (name) != MATCH_YES + || gfc_current_block () == NULL + || gfc_match_eos () != MATCH_YES) + { + gfc_error ("Unexpected junk after ELSE statement at %C"); + return MATCH_ERROR; + } + + if (strcmp (name, gfc_current_block ()->name) != 0) + { + gfc_error ("Label '%s' at %C doesn't match IF label '%s'", + name, gfc_current_block ()->name); + return MATCH_ERROR; + } + + return MATCH_YES; +} + + +/* Match an ELSE IF statement. */ + +match +gfc_match_elseif (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_expr *expr; + match m; + + m = gfc_match (" ( %e ) then", &expr); + if (m != MATCH_YES) + return m; + + if (gfc_match_eos () == MATCH_YES) + goto done; + + if (gfc_match_name (name) != MATCH_YES + || gfc_current_block () == NULL + || gfc_match_eos () != MATCH_YES) + { + gfc_error ("Unexpected junk after ELSE IF statement at %C"); + goto cleanup; + } + + if (strcmp (name, gfc_current_block ()->name) != 0) + { + gfc_error ("Label '%s' at %C doesn't match IF label '%s'", + name, gfc_current_block ()->name); + goto cleanup; + } + +done: + new_st.op = EXEC_IF; + new_st.expr = expr; + return MATCH_YES; + +cleanup: + gfc_free_expr (expr); + return MATCH_ERROR; +} + + +/* Free a gfc_iterator structure. */ + +void +gfc_free_iterator (gfc_iterator * iter, int flag) +{ + + if (iter == NULL) + return; + + gfc_free_expr (iter->var); + gfc_free_expr (iter->start); + gfc_free_expr (iter->end); + gfc_free_expr (iter->step); + + if (flag) + gfc_free (iter); +} + + +/* Match a DO statement. */ + +match +gfc_match_do (void) +{ + gfc_iterator iter, *ip; + locus old_loc; + gfc_st_label *label; + match m; + + old_loc = *gfc_current_locus (); + + label = NULL; + iter.var = iter.start = iter.end = iter.step = NULL; + + m = gfc_match_label (); + if (m == MATCH_ERROR) + return m; + + if (gfc_match (" do") != MATCH_YES) + return MATCH_NO; + +/* Match an infinite DO, make it like a DO WHILE(.TRUE.) */ + + if (gfc_match_eos () == MATCH_YES) + { + iter.end = gfc_logical_expr (1, NULL); + new_st.op = EXEC_DO_WHILE; + goto done; + } + + m = gfc_match_st_label (&label, 0); + if (m == MATCH_ERROR) + goto cleanup; + + gfc_match_char (','); + + if (gfc_match ("% ") != MATCH_YES) + return MATCH_NO; + + /* See if we have a DO WHILE. */ + if (gfc_match (" while ( %e )%t", &iter.end) == MATCH_YES) + { + new_st.op = EXEC_DO_WHILE; + goto done; + } + + /* The abortive DO WHILE may have done something to the symbol + table, so we start over: */ + gfc_undo_symbols (); + gfc_set_locus (&old_loc); + + gfc_match_label (); /* This won't error */ + gfc_match (" do "); /* This will work */ + + gfc_match_st_label (&label, 0); /* Can't error out */ + gfc_match_char (','); /* Optional comma */ + + m = gfc_match_iterator (&iter, 0); + if (m == MATCH_NO) + return MATCH_NO; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_eos () != MATCH_YES) + { + gfc_syntax_error (ST_DO); + goto cleanup; + } + + new_st.op = EXEC_DO; + +done: + if (label != NULL + && gfc_reference_st_label (label, ST_LABEL_TARGET) == FAILURE) + goto cleanup; + + new_st.label = label; + + if (new_st.op == EXEC_DO_WHILE) + new_st.expr = iter.end; + else + { + new_st.ext.iterator = ip = gfc_get_iterator (); + *ip = iter; + } + + return MATCH_YES; + +cleanup: + gfc_free_iterator (&iter, 0); + + return MATCH_ERROR; +} + + +/* Match an EXIT or CYCLE statement. */ + +static match +match_exit_cycle (gfc_statement st, gfc_exec_op op) +{ + gfc_state_data *p; + gfc_symbol *sym; + match m; + + if (gfc_match_eos () == MATCH_YES) + sym = NULL; + else + { + m = gfc_match ("% %s%t", &sym); + if (m == MATCH_ERROR) + return MATCH_ERROR; + if (m == MATCH_NO) + { + gfc_syntax_error (st); + return MATCH_ERROR; + } + + if (sym->attr.flavor != FL_LABEL) + { + gfc_error ("Name '%s' in %s statement at %C is not a loop name", + sym->name, gfc_ascii_statement (st)); + return MATCH_ERROR; + } + } + + /* Find the loop mentioned specified by the label (or lack of a + label). */ + for (p = gfc_state_stack; p; p = p->previous) + if (p->state == COMP_DO && (sym == NULL || sym == p->sym)) + break; + + if (p == NULL) + { + if (sym == NULL) + gfc_error ("%s statement at %C is not within a loop", + gfc_ascii_statement (st)); + else + gfc_error ("%s statement at %C is not within loop '%s'", + gfc_ascii_statement (st), sym->name); + + return MATCH_ERROR; + } + + /* Save the first statement in the loop - needed by the backend. */ + new_st.ext.whichloop = p->head; + + new_st.op = op; +/* new_st.sym = sym;*/ + + return MATCH_YES; +} + + +/* Match the EXIT statement. */ + +match +gfc_match_exit (void) +{ + + return match_exit_cycle (ST_EXIT, EXEC_EXIT); +} + + +/* Match the CYCLE statement. */ + +match +gfc_match_cycle (void) +{ + + return match_exit_cycle (ST_CYCLE, EXEC_CYCLE); +} + + +/* Match a number or character constant after a STOP or PAUSE statement. */ + +static match +gfc_match_stopcode (gfc_statement st) +{ + int stop_code; + gfc_expr *e; + match m; + + stop_code = 0; + e = NULL; + + if (gfc_match_eos () != MATCH_YES) + { + m = gfc_match_small_literal_int (&stop_code); + if (m == MATCH_ERROR) + goto cleanup; + + if (m == MATCH_YES && stop_code > 99999) + { + gfc_error ("STOP code out of range at %C"); + goto cleanup; + } + + if (m == MATCH_NO) + { + /* Try a character constant. */ + m = gfc_match_expr (&e); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + if (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_CONSTANT) + goto syntax; + } + + if (gfc_match_eos () != MATCH_YES) + goto syntax; + } + + if (gfc_pure (NULL)) + { + gfc_error ("%s statement not allowed in PURE procedure at %C", + gfc_ascii_statement (st)); + goto cleanup; + } + + new_st.op = st == ST_STOP ? EXEC_STOP : EXEC_PAUSE; + new_st.expr = e; + new_st.ext.stop_code = stop_code; + + return MATCH_YES; + +syntax: + gfc_syntax_error (st); + +cleanup: + + gfc_free_expr (e); + return MATCH_ERROR; +} + +/* Match the (deprecated) PAUSE statement. */ + +match +gfc_match_pause (void) +{ + match m; + + m = gfc_match_stopcode (ST_PAUSE); + if (m == MATCH_YES) + { + if (gfc_notify_std (GFC_STD_F95_DEL, + "Obsolete: PAUSE statement at %C") + == FAILURE) + m = MATCH_ERROR; + } + return m; +} + + +/* Match the STOP statement. */ + +match +gfc_match_stop (void) +{ + return gfc_match_stopcode (ST_STOP); +} + + +/* Match a CONTINUE statement. */ + +match +gfc_match_continue (void) +{ + + if (gfc_match_eos () != MATCH_YES) + { + gfc_syntax_error (ST_CONTINUE); + return MATCH_ERROR; + } + + new_st.op = EXEC_CONTINUE; + return MATCH_YES; +} + + +/* Match the (deprecated) ASSIGN statement. */ + +match +gfc_match_assign (void) +{ + gfc_expr *expr; + gfc_st_label *label; + + if (gfc_match (" %l", &label) == MATCH_YES) + { + if (gfc_reference_st_label (label, ST_LABEL_UNKNOWN) == FAILURE) + return MATCH_ERROR; + if (gfc_match (" to %v%t", &expr) == MATCH_YES) + { + if (gfc_notify_std (GFC_STD_F95_DEL, + "Obsolete: ASSIGN statement at %C") + == FAILURE) + return MATCH_ERROR; + + expr->symtree->n.sym->attr.assign = 1; + + new_st.op = EXEC_LABEL_ASSIGN; + new_st.label = label; + new_st.expr = expr; + return MATCH_YES; + } + } + return MATCH_NO; +} + + +/* Match the GO TO statement. As a computed GOTO statement is + matched, it is transformed into an equivalent SELECT block. No + tree is necessary, and the resulting jumps-to-jumps are + specifically optimized away by the back end. */ + +match +gfc_match_goto (void) +{ + gfc_code *head, *tail; + gfc_expr *expr; + gfc_case *cp; + gfc_st_label *label; + int i; + match m; + + if (gfc_match (" %l%t", &label) == MATCH_YES) + { + if (gfc_reference_st_label (label, ST_LABEL_TARGET) == FAILURE) + return MATCH_ERROR; + + new_st.op = EXEC_GOTO; + new_st.label = label; + return MATCH_YES; + } + + /* The assigned GO TO statement. */ + + if (gfc_match_variable (&expr, 0) == MATCH_YES) + { + if (gfc_notify_std (GFC_STD_F95_DEL, + "Obsolete: Assigned GOTO statement at %C") + == FAILURE) + return MATCH_ERROR; + + expr->symtree->n.sym->attr.assign = 1; + new_st.op = EXEC_GOTO; + new_st.expr = expr; + + if (gfc_match_eos () == MATCH_YES) + return MATCH_YES; + + /* Match label list. */ + gfc_match_char (','); + if (gfc_match_char ('(') != MATCH_YES) + { + gfc_syntax_error (ST_GOTO); + return MATCH_ERROR; + } + head = tail = NULL; + + do + { + m = gfc_match_st_label (&label, 0); + if (m != MATCH_YES) + goto syntax; + + if (gfc_reference_st_label (label, ST_LABEL_TARGET) == FAILURE) + goto cleanup; + + if (head == NULL) + head = tail = gfc_get_code (); + else + { + tail->block = gfc_get_code (); + tail = tail->block; + } + + tail->label = label; + tail->op = EXEC_GOTO; + } + while (gfc_match_char (',') == MATCH_YES); + + if (gfc_match (")%t") != MATCH_YES) + goto syntax; + + if (head == NULL) + { + gfc_error ( + "Statement label list in GOTO at %C cannot be empty"); + goto syntax; + } + new_st.block = head; + + return MATCH_YES; + } + + /* Last chance is a computed GO TO statement. */ + if (gfc_match_char ('(') != MATCH_YES) + { + gfc_syntax_error (ST_GOTO); + return MATCH_ERROR; + } + + head = tail = NULL; + i = 1; + + do + { + m = gfc_match_st_label (&label, 0); + if (m != MATCH_YES) + goto syntax; + + if (gfc_reference_st_label (label, ST_LABEL_TARGET) == FAILURE) + goto cleanup; + + if (head == NULL) + head = tail = gfc_get_code (); + else + { + tail->block = gfc_get_code (); + tail = tail->block; + } + + cp = gfc_get_case (); + cp->low = cp->high = gfc_int_expr (i++); + + tail->op = EXEC_SELECT; + tail->ext.case_list = cp; + + tail->next = gfc_get_code (); + tail->next->op = EXEC_GOTO; + tail->next->label = label; + } + while (gfc_match_char (',') == MATCH_YES); + + if (gfc_match_char (')') != MATCH_YES) + goto syntax; + + if (head == NULL) + { + gfc_error ("Statement label list in GOTO at %C cannot be empty"); + goto syntax; + } + + /* Get the rest of the statement. */ + gfc_match_char (','); + + if (gfc_match (" %e%t", &expr) != MATCH_YES) + goto syntax; + + /* At this point, a computed GOTO has been fully matched and an + equivalent SELECT statement constructed. */ + + new_st.op = EXEC_SELECT; + new_st.expr = NULL; + + /* Hack: For a "real" SELECT, the expression is in expr. We put + it in expr2 so we can distinguish then and produce the correct + diagnostics. */ + new_st.expr2 = expr; + new_st.block = head; + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_GOTO); +cleanup: + gfc_free_statements (head); + return MATCH_ERROR; +} + + +/* Frees a list of gfc_alloc structures. */ + +void +gfc_free_alloc_list (gfc_alloc * p) +{ + gfc_alloc *q; + + for (; p; p = q) + { + q = p->next; + gfc_free_expr (p->expr); + gfc_free (p); + } +} + + +/* Match an ALLOCATE statement. */ + +match +gfc_match_allocate (void) +{ + gfc_alloc *head, *tail; + gfc_expr *stat; + match m; + + head = tail = NULL; + stat = NULL; + + if (gfc_match_char ('(') != MATCH_YES) + goto syntax; + + for (;;) + { + if (head == NULL) + head = tail = gfc_get_alloc (); + else + { + tail->next = gfc_get_alloc (); + tail = tail->next; + } + + m = gfc_match_variable (&tail->expr, 0); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_pure (NULL) + && gfc_impure_variable (tail->expr->symtree->n.sym)) + { + gfc_error ("Bad allocate-object in ALLOCATE statement at %C for a " + "PURE procedure"); + goto cleanup; + } + + if (gfc_match_char (',') != MATCH_YES) + break; + + m = gfc_match (" stat = %v", &stat); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_YES) + break; + } + + if (stat != NULL) + { + if (stat->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error + ("STAT variable '%s' of ALLOCATE statement at %C cannot be " + "INTENT(IN)", stat->symtree->n.sym->name); + goto cleanup; + } + + if (gfc_pure (NULL) && gfc_impure_variable (stat->symtree->n.sym)) + { + gfc_error + ("Illegal STAT variable in ALLOCATE statement at %C for a PURE " + "procedure"); + goto cleanup; + } + } + + if (gfc_match (" )%t") != MATCH_YES) + goto syntax; + + new_st.op = EXEC_ALLOCATE; + new_st.expr = stat; + new_st.ext.alloc_list = head; + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_ALLOCATE); + +cleanup: + gfc_free_expr (stat); + gfc_free_alloc_list (head); + return MATCH_ERROR; +} + + +/* Match a NULLIFY statement. A NULLIFY statement is transformed into + a set of pointer assignments to intrinsic NULL(). */ + +match +gfc_match_nullify (void) +{ + gfc_code *tail; + gfc_expr *e, *p; + match m; + + tail = NULL; + + if (gfc_match_char ('(') != MATCH_YES) + goto syntax; + + for (;;) + { + m = gfc_match_variable (&p, 0); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + if (gfc_pure (NULL) && gfc_impure_variable (p->symtree->n.sym)) + { + gfc_error + ("Illegal variable in NULLIFY at %C for a PURE procedure"); + goto cleanup; + } + + /* build ' => NULL() ' */ + e = gfc_get_expr (); + e->where = *gfc_current_locus (); + e->expr_type = EXPR_NULL; + e->ts.type = BT_UNKNOWN; + + /* Chain to list */ + if (tail == NULL) + tail = &new_st; + else + { + tail->next = gfc_get_code (); + tail = tail->next; + } + + tail->op = EXEC_POINTER_ASSIGN; + tail->expr = p; + tail->expr2 = e; + + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_NULLIFY); + +cleanup: + gfc_free_statements (tail); + return MATCH_ERROR; +} + + +/* Match a DEALLOCATE statement. */ + +match +gfc_match_deallocate (void) +{ + gfc_alloc *head, *tail; + gfc_expr *stat; + match m; + + head = tail = NULL; + stat = NULL; + + if (gfc_match_char ('(') != MATCH_YES) + goto syntax; + + for (;;) + { + if (head == NULL) + head = tail = gfc_get_alloc (); + else + { + tail->next = gfc_get_alloc (); + tail = tail->next; + } + + m = gfc_match_variable (&tail->expr, 0); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + if (gfc_pure (NULL) + && gfc_impure_variable (tail->expr->symtree->n.sym)) + { + gfc_error + ("Illegal deallocate-expression in DEALLOCATE at %C for a PURE " + "procedure"); + goto cleanup; + } + + if (gfc_match_char (',') != MATCH_YES) + break; + + m = gfc_match (" stat = %v", &stat); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_YES) + break; + } + + if (stat != NULL && stat->symtree->n.sym->attr.intent == INTENT_IN) + { + gfc_error ("STAT variable '%s' of DEALLOCATE statement at %C cannot be " + "INTENT(IN)", stat->symtree->n.sym->name); + goto cleanup; + } + + if (gfc_match (" )%t") != MATCH_YES) + goto syntax; + + new_st.op = EXEC_DEALLOCATE; + new_st.expr = stat; + new_st.ext.alloc_list = head; + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_DEALLOCATE); + +cleanup: + gfc_free_expr (stat); + gfc_free_alloc_list (head); + return MATCH_ERROR; +} + + +/* Match a RETURN statement. */ + +match +gfc_match_return (void) +{ + gfc_expr *e; + match m; + + e = NULL; + if (gfc_match_eos () == MATCH_YES) + goto done; + + if (gfc_find_state (COMP_SUBROUTINE) == FAILURE) + { + gfc_error ("Alternate RETURN statement at %C is only allowed within " + "a SUBROUTINE"); + goto cleanup; + } + + m = gfc_match ("% %e%t", &e); + if (m == MATCH_YES) + goto done; + if (m == MATCH_ERROR) + goto cleanup; + + gfc_syntax_error (ST_RETURN); + +cleanup: + gfc_free_expr (e); + return MATCH_ERROR; + +done: + new_st.op = EXEC_RETURN; + new_st.expr = e; + + return MATCH_YES; +} + + +/* Match a CALL statement. The tricky part here are possible + alternate return specifiers. We handle these by having all + "subroutines" actually return an integer via a register that gives + the return number. If the call specifies alternate returns, we + generate code for a SELECT statement whose case clauses contain + GOTOs to the various labels. */ + +match +gfc_match_call (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_actual_arglist *a, *arglist; + gfc_case *new_case; + gfc_symbol *sym; + gfc_symtree *st; + gfc_code *c; + match m; + int i; + + arglist = NULL; + + m = gfc_match ("% %n", name); + if (m == MATCH_NO) + goto syntax; + if (m != MATCH_YES) + return m; + + if (gfc_get_ha_sym_tree (name, &st)) + return MATCH_ERROR; + + sym = st->n.sym; + gfc_set_sym_referenced (sym); + + if (!sym->attr.generic + && !sym->attr.subroutine + && gfc_add_subroutine (&sym->attr, NULL) == FAILURE) + return MATCH_ERROR; + + if (gfc_match_eos () != MATCH_YES) + { + m = gfc_match_actual_arglist (1, &arglist); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_eos () != MATCH_YES) + goto syntax; + } + + /* If any alternate return labels were found, construct a SELECT + statement that will jump to the right place. */ + + i = 0; + for (a = arglist; a; a = a->next) + if (a->expr == NULL) + i = 1; + + if (i) + { + gfc_symtree *select_st; + gfc_symbol *select_sym; + char name[GFC_MAX_SYMBOL_LEN + 1]; + + new_st.next = c = gfc_get_code (); + c->op = EXEC_SELECT; + sprintf (name, "_result_%s",sym->name); + gfc_get_ha_sym_tree (name, &select_st); /* Can't fail */ + + select_sym = select_st->n.sym; + select_sym->ts.type = BT_INTEGER; + select_sym->ts.kind = gfc_default_integer_kind (); + gfc_set_sym_referenced (select_sym); + c->expr = gfc_get_expr (); + c->expr->expr_type = EXPR_VARIABLE; + c->expr->symtree = select_st; + c->expr->ts = select_sym->ts; + c->expr->where = *gfc_current_locus (); + + i = 0; + for (a = arglist; a; a = a->next) + { + if (a->expr != NULL) + continue; + + if (gfc_reference_st_label (a->label, ST_LABEL_TARGET) == FAILURE) + continue; + + i++; + + c->block = gfc_get_code (); + c = c->block; + c->op = EXEC_SELECT; + + new_case = gfc_get_case (); + new_case->high = new_case->low = gfc_int_expr (i); + c->ext.case_list = new_case; + + c->next = gfc_get_code (); + c->next->op = EXEC_GOTO; + c->next->label = a->label; + } + } + + new_st.op = EXEC_CALL; + new_st.symtree = st; + new_st.ext.actual = arglist; + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_CALL); + +cleanup: + gfc_free_actual_arglist (arglist); + return MATCH_ERROR; +} + + +/* Match an IMPLICIT NONE statement. Actually, this statement is + already matched in parse.c, or we would not end up here in the + first place. So the only thing we need to check, is if there is + trailing garbage. If not, the match is successful. */ + +match +gfc_match_implicit_none (void) +{ + + return (gfc_match_eos () == MATCH_YES) ? MATCH_YES : MATCH_NO; +} + + +/* Match the letter range(s) of an IMPLICIT statement. */ + +static match +match_implicit_range (gfc_typespec * ts) +{ + int c, c1, c2, inner; + locus cur_loc; + + cur_loc = *gfc_current_locus (); + + gfc_gobble_whitespace (); + c = gfc_next_char (); + if (c != '(') + { + gfc_error ("Missing character range in IMPLICIT at %C"); + goto bad; + } + + inner = 1; + while (inner) + { + gfc_gobble_whitespace (); + c1 = gfc_next_char (); + if (!ISALPHA (c1)) + goto bad; + + gfc_gobble_whitespace (); + c = gfc_next_char (); + + switch (c) + { + case ')': + inner = 0; /* Fall through */ + + case ',': + c2 = c1; + break; + + case '-': + gfc_gobble_whitespace (); + c2 = gfc_next_char (); + if (!ISALPHA (c2)) + goto bad; + + gfc_gobble_whitespace (); + c = gfc_next_char (); + + if ((c != ',') && (c != ')')) + goto bad; + if (c == ')') + inner = 0; + + break; + + default: + goto bad; + } + + if (c1 > c2) + { + gfc_error ("Letters must be in alphabetic order in " + "IMPLICIT statement at %C"); + goto bad; + } + + /* See if we can add the newly matched range to the pending + implicits from this IMPLICIT statement. We do not check for + conflicts with whatever earlier IMPLICIT statements may have + set. This is done when we've successfully finished matching + the current one. */ + if (gfc_add_new_implicit_range (c1, c2, ts) != SUCCESS) + goto bad; + } + + return MATCH_YES; + +bad: + gfc_syntax_error (ST_IMPLICIT); + + gfc_set_locus (&cur_loc); + return MATCH_ERROR; +} + + +/* Match an IMPLICIT statement, storing the types for + gfc_set_implicit() if the statement is accepted by the parser. + There is a strange looking, but legal syntactic construction + possible. It looks like: + + IMPLICIT INTEGER (a-b) (c-d) + + This is legal if "a-b" is a constant expression that happens to + equal one of the legal kinds for integers. The real problem + happens with an implicit specification that looks like: + + IMPLICIT INTEGER (a-b) + + In this case, a typespec matcher that is "greedy" (as most of the + matchers are) gobbles the character range as a kindspec, leaving + nothing left. We therefore have to go a bit more slowly in the + matching process by inhibiting the kindspec checking during + typespec matching and checking for a kind later. */ + +match +gfc_match_implicit (void) +{ + gfc_typespec ts; + locus cur_loc; + int c; + match m; + + /* We don't allow empty implicit statements. */ + if (gfc_match_eos () == MATCH_YES) + { + gfc_error ("Empty IMPLICIT statement at %C"); + return MATCH_ERROR; + } + + /* First cleanup. */ + gfc_clear_new_implicit (); + + do + { + /* A basic type is mandatory here. */ + m = gfc_match_type_spec (&ts, 0); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_NO) + goto syntax; + + cur_loc = *gfc_current_locus (); + m = match_implicit_range (&ts); + + if (m == MATCH_YES) + { + /* Looks like we have the (). */ + gfc_gobble_whitespace (); + c = gfc_next_char (); + if ((c == '\n') || (c == ',')) + continue; + + gfc_set_locus (&cur_loc); + } + + /* Last chance -- check () (). */ + m = gfc_match_kind_spec (&ts); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_NO) + { + m = gfc_match_old_kind_spec (&ts); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_NO) + goto syntax; + } + + m = match_implicit_range (&ts); + if (m == MATCH_ERROR) + goto error; + if (m == MATCH_NO) + goto syntax; + + gfc_gobble_whitespace (); + c = gfc_next_char (); + if ((c != '\n') && (c != ',')) + goto syntax; + + } + while (c == ','); + + /* All we need to now is try to merge the new implicit types back + into the existing types. This will fail if another implicit + type is already defined for a letter. */ + return (gfc_merge_new_implicit () == SUCCESS) ? + MATCH_YES : MATCH_ERROR; + +syntax: + gfc_syntax_error (ST_IMPLICIT); + +error: + return MATCH_ERROR; +} + + +/* Match a common block name. */ + +static match +match_common_name (gfc_symbol ** sym) +{ + match m; + + if (gfc_match_char ('/') == MATCH_NO) + return MATCH_NO; + + if (gfc_match_char ('/') == MATCH_YES) + { + *sym = NULL; + return MATCH_YES; + } + + m = gfc_match_symbol (sym, 0); + + if (m == MATCH_ERROR) + return MATCH_ERROR; + if (m == MATCH_YES && gfc_match_char ('/') == MATCH_YES) + return MATCH_YES; + + gfc_error ("Syntax error in common block name at %C"); + return MATCH_ERROR; +} + + +/* Match a COMMON statement. */ + +match +gfc_match_common (void) +{ + gfc_symbol *sym, *common_name, **head, *tail, *old_blank_common; + gfc_array_spec *as; + match m; + + old_blank_common = gfc_current_ns->blank_common; + if (old_blank_common) + { + while (old_blank_common->common_next) + old_blank_common = old_blank_common->common_next; + } + + common_name = NULL; + as = NULL; + + if (gfc_match_eos () == MATCH_YES) + goto syntax; + + for (;;) + { + m = match_common_name (&common_name); + if (m == MATCH_ERROR) + goto cleanup; + + if (common_name == NULL) + head = &gfc_current_ns->blank_common; + else + { + head = &common_name->common_head; + + if (!common_name->attr.common + && gfc_add_common (&common_name->attr, NULL) == FAILURE) + goto cleanup; + } + + if (*head == NULL) + tail = NULL; + else + { + tail = *head; + while (tail->common_next) + tail = tail->common_next; + } + + /* Grab the list of symbols. */ + for (;;) + { + m = gfc_match_symbol (&sym, 0); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + if (sym->attr.in_common) + { + gfc_error ("Symbol '%s' at %C is already in a COMMON block", + sym->name); + goto cleanup; + } + + if (gfc_add_in_common (&sym->attr, NULL) == FAILURE) + goto cleanup; + + /* Derived type names must have the SEQUENCE attribute. */ + if (sym->ts.type == BT_DERIVED && !sym->ts.derived->attr.sequence) + { + gfc_error + ("Derived type variable in COMMON at %C does not have the " + "SEQUENCE attribute"); + goto cleanup; + } + + if (tail != NULL) + tail->common_next = sym; + else + *head = sym; + + tail = sym; + + /* Deal with an optional array specification after the + symbol name. */ + m = gfc_match_array_spec (&as); + if (m == MATCH_ERROR) + goto cleanup; + + if (m == MATCH_YES) + { + if (as->type != AS_EXPLICIT) + { + gfc_error + ("Array specification for symbol '%s' in COMMON at %C " + "must be explicit", sym->name); + goto cleanup; + } + + if (gfc_add_dimension (&sym->attr, NULL) == FAILURE) + goto cleanup; + + if (sym->attr.pointer) + { + gfc_error + ("Symbol '%s' in COMMON at %C cannot be a POINTER array", + sym->name); + goto cleanup; + } + + sym->as = as; + as = NULL; + } + + if (gfc_match_eos () == MATCH_YES) + goto done; + if (gfc_peek_char () == '/') + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + if (gfc_peek_char () == '/') + break; + } + } + +done: + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_COMMON); + +cleanup: + if (old_blank_common) + old_blank_common->common_next = NULL; + else + gfc_current_ns->blank_common = NULL; + gfc_free_array_spec (as); + return MATCH_ERROR; +} + + +/* Match a BLOCK DATA program unit. */ + +match +gfc_match_block_data (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + match m; + + if (gfc_match_eos () == MATCH_YES) + { + gfc_new_block = NULL; + return MATCH_YES; + } + + m = gfc_match (" %n%t", name); + if (m != MATCH_YES) + return MATCH_ERROR; + + if (gfc_get_symbol (name, NULL, &sym)) + return MATCH_ERROR; + + if (gfc_add_flavor (&sym->attr, FL_BLOCK_DATA, NULL) == FAILURE) + return MATCH_ERROR; + + gfc_new_block = sym; + + return MATCH_YES; +} + + +/* Free a namelist structure. */ + +void +gfc_free_namelist (gfc_namelist * name) +{ + gfc_namelist *n; + + for (; name; name = n) + { + n = name->next; + gfc_free (name); + } +} + + +/* Match a NAMELIST statement. */ + +match +gfc_match_namelist (void) +{ + gfc_symbol *group_name, *sym; + gfc_namelist *nl; + match m, m2; + + m = gfc_match (" / %s /", &group_name); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto error; + + for (;;) + { + if (group_name->ts.type != BT_UNKNOWN) + { + gfc_error + ("Namelist group name '%s' at %C already has a basic type " + "of %s", group_name->name, gfc_typename (&group_name->ts)); + return MATCH_ERROR; + } + + if (group_name->attr.flavor != FL_NAMELIST + && gfc_add_flavor (&group_name->attr, FL_NAMELIST, NULL) == FAILURE) + return MATCH_ERROR; + + for (;;) + { + m = gfc_match_symbol (&sym, 1); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto error; + + if (sym->attr.in_namelist == 0 + && gfc_add_in_namelist (&sym->attr, NULL) == FAILURE) + goto error; + + /* TODO: worry about PRIVATE members of a PUBLIC namelist + group. */ + + nl = gfc_get_namelist (); + nl->sym = sym; + + if (group_name->namelist == NULL) + group_name->namelist = group_name->namelist_tail = nl; + else + { + group_name->namelist_tail->next = nl; + group_name->namelist_tail = nl; + } + + if (gfc_match_eos () == MATCH_YES) + goto done; + + m = gfc_match_char (','); + + if (gfc_match_char ('/') == MATCH_YES) + { + m2 = gfc_match (" %s /", &group_name); + if (m2 == MATCH_YES) + break; + if (m2 == MATCH_ERROR) + goto error; + goto syntax; + } + + if (m != MATCH_YES) + goto syntax; + } + } + +done: + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_NAMELIST); + +error: + return MATCH_ERROR; +} + + +/* Match a MODULE statement. */ + +match +gfc_match_module (void) +{ + match m; + + m = gfc_match (" %s%t", &gfc_new_block); + if (m != MATCH_YES) + return m; + + if (gfc_add_flavor (&gfc_new_block->attr, FL_MODULE, NULL) == FAILURE) + return MATCH_ERROR; + + return MATCH_YES; +} + + +/* Free equivalence sets and lists. Recursively is the easiest way to + do this. */ + +void +gfc_free_equiv (gfc_equiv * eq) +{ + + if (eq == NULL) + return; + + gfc_free_equiv (eq->eq); + gfc_free_equiv (eq->next); + + gfc_free_expr (eq->expr); + gfc_free (eq); +} + + +/* Match an EQUIVALENCE statement. */ + +match +gfc_match_equivalence (void) +{ + gfc_equiv *eq, *set, *tail; + gfc_ref *ref; + match m; + + tail = NULL; + + for (;;) + { + eq = gfc_get_equiv (); + if (tail == NULL) + tail = eq; + + eq->next = gfc_current_ns->equiv; + gfc_current_ns->equiv = eq; + + if (gfc_match_char ('(') != MATCH_YES) + goto syntax; + + set = eq; + + for (;;) + { + m = gfc_match_variable (&set->expr, 1); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + for (ref = set->expr->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->u.ar.type == AR_SECTION) + { + gfc_error + ("Array reference in EQUIVALENCE at %C cannot be an " + "array section"); + goto cleanup; + } + + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + set->eq = gfc_get_equiv (); + set = set->eq; + } + + if (gfc_match_eos () == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_EQUIVALENCE); + +cleanup: + eq = tail->next; + tail->next = NULL; + + gfc_free_equiv (gfc_current_ns->equiv); + gfc_current_ns->equiv = eq; + + return MATCH_ERROR; +} + + +/* Match a statement function declaration. It is so easy to match + non-statement function statements with a MATCH_ERROR as opposed to + MATCH_NO that we suppress error message in most cases. */ + +match +gfc_match_st_function (void) +{ + gfc_error_buf old_error; + gfc_symbol *sym; + gfc_expr *expr; + match m; + + m = gfc_match_symbol (&sym, 0); + if (m != MATCH_YES) + return m; + + gfc_push_error (&old_error); + + if (gfc_add_procedure (&sym->attr, PROC_ST_FUNCTION, NULL) == FAILURE) + goto undo_error; + + if (gfc_match_formal_arglist (sym, 1, 0) != MATCH_YES) + goto undo_error; + + m = gfc_match (" = %e%t", &expr); + if (m == MATCH_NO) + goto undo_error; + if (m == MATCH_ERROR) + return m; + + sym->value = expr; + + return MATCH_YES; + +undo_error: + gfc_pop_error (&old_error); + return MATCH_NO; +} + + +/********************* DATA statement subroutines *********************/ + +/* Free a gfc_data_variable structure and everything beneath it. */ + +static void +free_variable (gfc_data_variable * p) +{ + gfc_data_variable *q; + + for (; p; p = q) + { + q = p->next; + gfc_free_expr (p->expr); + gfc_free_iterator (&p->iter, 0); + free_variable (p->list); + + gfc_free (p); + } +} + + +/* Free a gfc_data_value structure and everything beneath it. */ + +static void +free_value (gfc_data_value * p) +{ + gfc_data_value *q; + + for (; p; p = q) + { + q = p->next; + gfc_free_expr (p->expr); + gfc_free (p); + } +} + + +/* Free a list of gfc_data structures. */ + +void +gfc_free_data (gfc_data * p) +{ + gfc_data *q; + + for (; p; p = q) + { + q = p->next; + + free_variable (p->var); + free_value (p->value); + + gfc_free (p); + } +} + + +static match var_element (gfc_data_variable *); + +/* Match a list of variables terminated by an iterator and a right + parenthesis. */ + +static match +var_list (gfc_data_variable * parent) +{ + gfc_data_variable *tail, var; + match m; + + m = var_element (&var); + if (m == MATCH_ERROR) + return MATCH_ERROR; + if (m == MATCH_NO) + goto syntax; + + tail = gfc_get_data_variable (); + *tail = var; + + parent->list = tail; + + for (;;) + { + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + m = gfc_match_iterator (&parent->iter, 1); + if (m == MATCH_YES) + break; + if (m == MATCH_ERROR) + return MATCH_ERROR; + + m = var_element (&var); + if (m == MATCH_ERROR) + return MATCH_ERROR; + if (m == MATCH_NO) + goto syntax; + + tail->next = gfc_get_data_variable (); + tail = tail->next; + + *tail = var; + } + + if (gfc_match_char (')') != MATCH_YES) + goto syntax; + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_DATA); + return MATCH_ERROR; +} + + +/* Match a single element in a data variable list, which can be a + variable-iterator list. */ + +static match +var_element (gfc_data_variable * new) +{ + match m; + + memset (new, '\0', sizeof (gfc_data_variable)); + + if (gfc_match_char ('(') == MATCH_YES) + return var_list (new); + + m = gfc_match_variable (&new->expr, 0); + if (m != MATCH_YES) + return m; + + if (new->expr->symtree->n.sym->value != NULL) + { + gfc_error ("Variable '%s' at %C already has an initialization", + new->expr->symtree->n.sym->name); + return MATCH_ERROR; + } + + new->expr->symtree->n.sym->attr.data = 1; + return MATCH_YES; +} + + +/* Match the top-level list of data variables. */ + +static match +top_var_list (gfc_data * d) +{ + gfc_data_variable var, *tail, *new; + match m; + + tail = NULL; + + for (;;) + { + m = var_element (&var); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + return MATCH_ERROR; + + new = gfc_get_data_variable (); + *new = var; + + if (tail == NULL) + d->var = new; + else + tail->next = new; + + tail = new; + + if (gfc_match_char ('/') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_DATA); + return MATCH_ERROR; +} + + +static match +match_data_constant (gfc_expr ** result) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + gfc_expr *expr; + match m; + + m = gfc_match_literal_constant (&expr, 1); + if (m == MATCH_YES) + { + *result = expr; + return MATCH_YES; + } + + if (m == MATCH_ERROR) + return MATCH_ERROR; + + m = gfc_match_null (result); + if (m != MATCH_NO) + return m; + + m = gfc_match_name (name); + if (m != MATCH_YES) + return m; + + if (gfc_find_symbol (name, NULL, 1, &sym)) + return MATCH_ERROR; + + if (sym == NULL || sym->attr.flavor != FL_PARAMETER) + { + gfc_error ("Symbol '%s' must be a PARAMETER in DATA statement at %C", + name); + return MATCH_ERROR; + } + + *result = gfc_copy_expr (sym->value); + return MATCH_YES; +} + + +/* Match a list of values in a DATA statement. The leading '/' has + already been seen at this point. */ + +static match +top_val_list (gfc_data * data) +{ + gfc_data_value *new, *tail; + gfc_expr *expr; + const char *msg; + match m; + + tail = NULL; + + for (;;) + { + m = match_data_constant (&expr); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + return MATCH_ERROR; + + new = gfc_get_data_value (); + + if (tail == NULL) + data->value = new; + else + tail->next = new; + + tail = new; + + if (expr->ts.type != BT_INTEGER || gfc_match_char ('*') != MATCH_YES) + { + tail->expr = expr; + tail->repeat = 1; + } + else + { + msg = gfc_extract_int (expr, &tail->repeat); + gfc_free_expr (expr); + if (msg != NULL) + { + gfc_error (msg); + return MATCH_ERROR; + } + + m = match_data_constant (&tail->expr); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + return MATCH_ERROR; + } + + if (gfc_match_char ('/') == MATCH_YES) + break; + if (gfc_match_char (',') == MATCH_NO) + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_DATA); + return MATCH_ERROR; +} + + +/* Match a DATA statement. */ + +match +gfc_match_data (void) +{ + gfc_data *new; + match m; + + for (;;) + { + new = gfc_get_data (); + new->where = *gfc_current_locus (); + + m = top_var_list (new); + if (m != MATCH_YES) + goto cleanup; + + m = top_val_list (new); + if (m != MATCH_YES) + goto cleanup; + + new->next = gfc_current_ns->data; + gfc_current_ns->data = new; + + if (gfc_match_eos () == MATCH_YES) + break; + + gfc_match_char (','); /* Optional comma */ + } + + if (gfc_pure (NULL)) + { + gfc_error ("DATA statement at %C is not allowed in a PURE procedure"); + return MATCH_ERROR; + } + + return MATCH_YES; + +cleanup: + gfc_free_data (new); + return MATCH_ERROR; +} + + +/***************** SELECT CASE subroutines ******************/ + +/* Free a single case structure. */ + +static void +free_case (gfc_case * p) +{ + if (p->low == p->high) + p->high = NULL; + gfc_free_expr (p->low); + gfc_free_expr (p->high); + gfc_free (p); +} + + +/* Free a list of case structures. */ + +void +gfc_free_case_list (gfc_case * p) +{ + gfc_case *q; + + for (; p; p = q) + { + q = p->next; + free_case (p); + } +} + + +/* Match a single case selector. */ + +static match +match_case_selector (gfc_case ** cp) +{ + gfc_case *c; + match m; + + c = gfc_get_case (); + c->where = *gfc_current_locus (); + + if (gfc_match_char (':') == MATCH_YES) + { + m = gfc_match_expr (&c->high); + if (m == MATCH_NO) + goto need_expr; + if (m == MATCH_ERROR) + goto cleanup; + } + + else + { + m = gfc_match_expr (&c->low); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto need_expr; + + /* If we're not looking at a ':' now, make a range out of a single + target. Else get the upper bound for the case range. */ + if (gfc_match_char (':') != MATCH_YES) + c->high = c->low; + else + { + m = gfc_match_expr (&c->high); + if (m == MATCH_ERROR) + goto cleanup; + /* MATCH_NO is fine. It's OK if nothing is there! */ + } + } + + *cp = c; + return MATCH_YES; + +need_expr: + gfc_error ("Expected expression in CASE at %C"); + +cleanup: + free_case (c); + return MATCH_ERROR; +} + + +/* Match the end of a case statement. */ + +static match +match_case_eos (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + match m; + + if (gfc_match_eos () == MATCH_YES) + return MATCH_YES; + + gfc_gobble_whitespace (); + + m = gfc_match_name (name); + if (m != MATCH_YES) + return m; + + if (strcmp (name, gfc_current_block ()->name) != 0) + { + gfc_error ("Expected case name of '%s' at %C", + gfc_current_block ()->name); + return MATCH_ERROR; + } + + return gfc_match_eos (); +} + + +/* Match a SELECT statement. */ + +match +gfc_match_select (void) +{ + gfc_expr *expr; + match m; + + m = gfc_match_label (); + if (m == MATCH_ERROR) + return m; + + m = gfc_match (" select case ( %e )%t", &expr); + if (m != MATCH_YES) + return m; + + new_st.op = EXEC_SELECT; + new_st.expr = expr; + + return MATCH_YES; +} + + +/* Match a CASE statement. */ + +match +gfc_match_case (void) +{ + gfc_case *c, *head, *tail; + match m; + + head = tail = NULL; + + if (gfc_current_state () != COMP_SELECT) + { + gfc_error ("Unexpected CASE statement at %C"); + return MATCH_ERROR; + } + + if (gfc_match ("% default") == MATCH_YES) + { + m = match_case_eos (); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + new_st.op = EXEC_SELECT; + c = gfc_get_case (); + c->where = *gfc_current_locus (); + new_st.ext.case_list = c; + return MATCH_YES; + } + + if (gfc_match_char ('(') != MATCH_YES) + goto syntax; + + for (;;) + { + if (match_case_selector (&c) == MATCH_ERROR) + goto cleanup; + + if (head == NULL) + head = c; + else + tail->next = c; + + tail = c; + + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + m = match_case_eos (); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + new_st.op = EXEC_SELECT; + new_st.ext.case_list = head; + + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in CASE-specification at %C"); + +cleanup: + gfc_free_case_list (head); /* new_st is cleaned up in parse.c. */ + return MATCH_ERROR; +} + +/********************* WHERE subroutines ********************/ + +/* Match a WHERE statement. */ + +match +gfc_match_where (gfc_statement * st) +{ + gfc_expr *expr; + match m0, m; + gfc_code *c; + + m0 = gfc_match_label (); + if (m0 == MATCH_ERROR) + return m0; + + m = gfc_match (" where ( %e )", &expr); + if (m != MATCH_YES) + return m; + + if (gfc_match_eos () == MATCH_YES) + { + *st = ST_WHERE_BLOCK; + + new_st.op = EXEC_WHERE; + new_st.expr = expr; + return MATCH_YES; + } + + m = gfc_match_assignment (); + if (m == MATCH_NO) + gfc_syntax_error (ST_WHERE); + + if (m != MATCH_YES) + { + gfc_free_expr (expr); + return MATCH_ERROR; + } + + /* We've got a simple WHERE statement. */ + *st = ST_WHERE; + c = gfc_get_code (); + + c->op = EXEC_WHERE; + c->expr = expr; + c->next = gfc_get_code (); + + *c->next = new_st; + gfc_clear_new_st (); + + new_st.op = EXEC_WHERE; + new_st.block = c; + + return MATCH_YES; +} + + +/* Match an ELSEWHERE statement. We leave behind a WHERE node in + new_st if successful. */ + +match +gfc_match_elsewhere (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_expr *expr; + match m; + + if (gfc_current_state () != COMP_WHERE) + { + gfc_error ("ELSEWHERE statement at %C not enclosed in WHERE block"); + return MATCH_ERROR; + } + + expr = NULL; + + if (gfc_match_char ('(') == MATCH_YES) + { + m = gfc_match_expr (&expr); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + return MATCH_ERROR; + + if (gfc_match_char (')') != MATCH_YES) + goto syntax; + } + + if (gfc_match_eos () != MATCH_YES) + { /* Better be a name at this point */ + m = gfc_match_name (name); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_eos () != MATCH_YES) + goto syntax; + + if (strcmp (name, gfc_current_block ()->name) != 0) + { + gfc_error ("Label '%s' at %C doesn't match WHERE label '%s'", + name, gfc_current_block ()->name); + goto cleanup; + } + } + + new_st.op = EXEC_WHERE; + new_st.expr = expr; + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_ELSEWHERE); + +cleanup: + gfc_free_expr (expr); + return MATCH_ERROR; +} + + +/******************** FORALL subroutines ********************/ + +/* Free a list of FORALL iterators. */ + +void +gfc_free_forall_iterator (gfc_forall_iterator * iter) +{ + gfc_forall_iterator *next; + + while (iter) + { + next = iter->next; + + gfc_free_expr (iter->var); + gfc_free_expr (iter->start); + gfc_free_expr (iter->end); + gfc_free_expr (iter->stride); + + gfc_free (iter); + iter = next; + } +} + + +/* Match an iterator as part of a FORALL statement. The format is: + + = :[:][, ] */ + +static match +match_forall_iterator (gfc_forall_iterator ** result) +{ + gfc_forall_iterator *iter; + locus where; + match m; + + where = *gfc_current_locus (); + iter = gfc_getmem (sizeof (gfc_forall_iterator)); + + m = gfc_match_variable (&iter->var, 0); + if (m != MATCH_YES) + goto cleanup; + + if (gfc_match_char ('=') != MATCH_YES) + { + m = MATCH_NO; + goto cleanup; + } + + m = gfc_match_expr (&iter->start); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (':') != MATCH_YES) + goto syntax; + + m = gfc_match_expr (&iter->end); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (':') == MATCH_NO) + iter->stride = gfc_int_expr (1); + else + { + m = gfc_match_expr (&iter->stride); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + } + + *result = iter; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in FORALL iterator at %C"); + m = MATCH_ERROR; + +cleanup: + gfc_set_locus (&where); + gfc_free_forall_iterator (iter); + return m; +} + + +/* Match a FORALL statement. */ + +match +gfc_match_forall (gfc_statement * st) +{ + gfc_forall_iterator *head, *tail, *new; + gfc_expr *mask; + gfc_code *c; + match m0, m; + + head = tail = NULL; + mask = NULL; + c = NULL; + + m0 = gfc_match_label (); + if (m0 == MATCH_ERROR) + return MATCH_ERROR; + + m = gfc_match (" forall ("); + if (m != MATCH_YES) + return m; + + m = match_forall_iterator (&new); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + + head = tail = new; + + for (;;) + { + if (gfc_match_char (',') != MATCH_YES) + break; + + m = match_forall_iterator (&new); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_YES) + { + tail->next = new; + tail = new; + continue; + } + + /* Have to have a mask expression. */ + m = gfc_match_expr (&mask); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + break; + } + + if (gfc_match_char (')') == MATCH_NO) + goto syntax; + + if (gfc_match_eos () == MATCH_YES) + { + *st = ST_FORALL_BLOCK; + + new_st.op = EXEC_FORALL; + new_st.expr = mask; + new_st.ext.forall_iterator = head; + + return MATCH_YES; + } + + m = gfc_match_assignment (); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + m = gfc_match_pointer_assignment (); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + } + + c = gfc_get_code (); + *c = new_st; + + if (gfc_match_eos () != MATCH_YES) + goto syntax; + + gfc_clear_new_st (); + new_st.op = EXEC_FORALL; + new_st.expr = mask; + new_st.ext.forall_iterator = head; + new_st.block = gfc_get_code (); + + new_st.block->op = EXEC_FORALL; + new_st.block->next = c; + + *st = ST_FORALL; + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_FORALL); + +cleanup: + gfc_free_forall_iterator (head); + gfc_free_expr (mask); + gfc_free_statements (c); + return MATCH_NO; +} diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h new file mode 100644 index 00000000000..6cd71339c49 --- /dev/null +++ b/gcc/fortran/match.h @@ -0,0 +1,164 @@ +/* All matcher functions. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef GFC_MATCH_H +#define GFC_MATCH_H + +#include "gfortran.h" + +/* gfc_new_block points to the symbol of a newly matched block. */ +extern gfc_symbol *gfc_new_block; + +/* Current statement label. Zero means no statement label. Because + new_st can get wiped during statement matching, we have to keep it + separate. */ +extern gfc_st_label *gfc_statement_label; + +/****************** All gfc_match* routines *****************/ + +/* match.c */ + +/* Generic match subroutines */ +match gfc_match_space (void); +match gfc_match_eos (void); +match gfc_match_small_literal_int (int *); +match gfc_match_st_label (gfc_st_label **, int); +match gfc_match_label (void); +match gfc_match_small_int (int *); +int gfc_match_strings (mstring *); +match gfc_match_name (char *); +match gfc_match_symbol (gfc_symbol **, int); +match gfc_match_sym_tree (gfc_symtree **, int); +match gfc_match_intrinsic_op (gfc_intrinsic_op *); +match gfc_match_char (char); +match gfc_match (const char *, ...); +match gfc_match_iterator (gfc_iterator *, int); + +/* Statement matchers */ +match gfc_match_program (void); +match gfc_match_pointer_assignment (void); +match gfc_match_assignment (void); +match gfc_match_if (gfc_statement *); +match gfc_match_else (void); +match gfc_match_elseif (void); +match gfc_match_do (void); +match gfc_match_cycle (void); +match gfc_match_exit (void); +match gfc_match_pause (void); +match gfc_match_stop (void); +match gfc_match_continue (void); +match gfc_match_assign (void); +match gfc_match_goto (void); + +match gfc_match_allocate (void); +match gfc_match_nullify (void); +match gfc_match_deallocate (void); +match gfc_match_return (void); +match gfc_match_call (void); +match gfc_match_common (void); +match gfc_match_implicit_none (void); +match gfc_match_implicit (void); +match gfc_match_block_data (void); +match gfc_match_namelist (void); +match gfc_match_module (void); +match gfc_match_equivalence (void); +match gfc_match_st_function (void); +match gfc_match_data (void); +match gfc_match_case (void); +match gfc_match_select (void); +match gfc_match_where (gfc_statement *); +match gfc_match_elsewhere (void); +match gfc_match_forall (gfc_statement *); + +/* decl.c */ + +match gfc_match_null (gfc_expr **); +match gfc_match_kind_spec (gfc_typespec *); +match gfc_match_old_kind_spec (gfc_typespec *); +match gfc_match_type_spec (gfc_typespec *, int); + +match gfc_match_end (gfc_statement *); +match gfc_match_data_decl (void); +match gfc_match_formal_arglist (gfc_symbol *, int, int); +match gfc_match_function_decl (void); +match gfc_match_entry (void); +match gfc_match_subroutine (void); +match gfc_match_derived_decl (void); + +/* Matchers for attribute declarations */ +match gfc_match_allocatable (void); +match gfc_match_dimension (void); +match gfc_match_external (void); +match gfc_match_intent (void); +match gfc_match_intrinsic (void); +match gfc_match_optional (void); +match gfc_match_parameter (void); +match gfc_match_pointer (void); +match gfc_match_private (gfc_statement *); +match gfc_match_public (gfc_statement *); +match gfc_match_save (void); +match gfc_match_modproc (void); +match gfc_match_target (void); + +/* primary.c */ +match gfc_match_rvalue (gfc_expr **); +match gfc_match_variable (gfc_expr **, int); +match gfc_match_actual_arglist (int, gfc_actual_arglist **); +match gfc_match_literal_constant (gfc_expr **, int); + +/* expr.c -- FIXME: this one should be eliminated by moving the + matcher to matchexp.c and a call to a new function in expr.c that + only makes sure the init expr. is valid. */ +match gfc_match_init_expr (gfc_expr **); + +/* array.c */ +match gfc_match_array_spec (gfc_array_spec **); +match gfc_match_array_ref (gfc_array_ref *, gfc_array_spec *, int); +match gfc_match_array_constructor (gfc_expr **); + +/* interface.c */ +match gfc_match_generic_spec (interface_type *, char *, gfc_intrinsic_op *); +match gfc_match_interface (void); +match gfc_match_end_interface (void); + +/* io.c */ +match gfc_match_format (void); +match gfc_match_open (void); +match gfc_match_close (void); +match gfc_match_endfile (void); +match gfc_match_backspace (void); +match gfc_match_rewind (void); +match gfc_match_inquire (void); +match gfc_match_read (void); +match gfc_match_write (void); +match gfc_match_print (void); + +/* matchexp.c */ +match gfc_match_defined_op_name (char *, int); +match gfc_match_expr (gfc_expr **); + +/* module.c */ +match gfc_match_use (void); +void gfc_use_module (void); + +#endif /* GFC_MATCH_H */ + diff --git a/gcc/fortran/matchexp.c b/gcc/fortran/matchexp.c new file mode 100644 index 00000000000..4acd98e66fc --- /dev/null +++ b/gcc/fortran/matchexp.c @@ -0,0 +1,776 @@ +/* Expression parser. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include +#include "gfortran.h" +#include "arith.h" +#include "match.h" + +static char expression_syntax[] = "Syntax error in expression at %C"; + + +/* Match a user-defined operator name. This is a normal name with a + few restrictions. The error_flag controls whether an error is + raised if 'true' or 'false' are used or not. */ + +match +gfc_match_defined_op_name (char *result, int error_flag) +{ + static const char * const badops[] = { + "and", "or", "not", "eqv", "neqv", "eq", "ne", "ge", "le", "lt", "gt", + NULL + }; + + char name[GFC_MAX_SYMBOL_LEN + 1]; + locus old_loc; + match m; + int i; + + old_loc = *gfc_current_locus (); + + m = gfc_match (" . %n .", name); + if (m != MATCH_YES) + return m; + + /* .true. and .false. have interpretations as constants. Trying to + use these as operators will fail at a later time. */ + + if (strcmp (name, "true") == 0 || strcmp (name, "false") == 0) + { + if (error_flag) + goto error; + gfc_set_locus (&old_loc); + return MATCH_NO; + } + + for (i = 0; badops[i]; i++) + if (strcmp (badops[i], name) == 0) + goto error; + + for (i = 0; name[i]; i++) + if (!ISALPHA (name[i])) + { + gfc_error ("Bad character '%c' in OPERATOR name at %C", name[i]); + return MATCH_ERROR; + } + + strcpy (result, name); + return MATCH_YES; + +error: + gfc_error ("The name '%s' cannot be used as a defined operator at %C", + name); + + gfc_set_locus (&old_loc); + return MATCH_ERROR; +} + + +/* Match a user defined operator. The symbol found must be an + operator already. */ + +static match +match_defined_operator (gfc_user_op ** result) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + match m; + + m = gfc_match_defined_op_name (name, 0); + if (m != MATCH_YES) + return m; + + *result = gfc_get_uop (name); + return MATCH_YES; +} + + +/* Check to see if the given operator is next on the input. If this + is not the case, the parse pointer remains where it was. */ + +static int +next_operator (gfc_intrinsic_op t) +{ + gfc_intrinsic_op u; + locus old_loc; + + old_loc = *gfc_current_locus (); + if (gfc_match_intrinsic_op (&u) == MATCH_YES && t == u) + return 1; + + gfc_set_locus (&old_loc); + return 0; +} + + +/* Match a primary expression. */ + +static match +match_primary (gfc_expr ** result) +{ + match m; + + m = gfc_match_literal_constant (result, 0); + if (m != MATCH_NO) + return m; + + m = gfc_match_array_constructor (result); + if (m != MATCH_NO) + return m; + + m = gfc_match_rvalue (result); + if (m != MATCH_NO) + return m; + + /* Match an expression in parenthesis. */ + if (gfc_match_char ('(') != MATCH_YES) + return MATCH_NO; + + m = gfc_match_expr (result); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + return m; + + m = gfc_match_char (')'); + if (m == MATCH_NO) + gfc_error ("Expected a right parenthesis in expression at %C"); + + if (m != MATCH_YES) + { + gfc_free_expr (*result); + return MATCH_ERROR; + } + + return MATCH_YES; + +syntax: + gfc_error (expression_syntax); + return MATCH_ERROR; +} + + +/* Build an operator expression node. */ + +static gfc_expr * +build_node (gfc_intrinsic_op operator, locus * where, + gfc_expr * op1, gfc_expr * op2) +{ + gfc_expr *new; + + new = gfc_get_expr (); + new->expr_type = EXPR_OP; + new->operator = operator; + new->where = *where; + + new->op1 = op1; + new->op2 = op2; + + return new; +} + + +/* Match a level 1 expression. */ + +static match +match_level_1 (gfc_expr ** result) +{ + gfc_user_op *uop; + gfc_expr *e, *f; + locus where; + match m; + + where = *gfc_current_locus (); + uop = NULL; + m = match_defined_operator (&uop); + if (m == MATCH_ERROR) + return m; + + m = match_primary (&e); + if (m != MATCH_YES) + return m; + + if (uop == NULL) + *result = e; + else + { + f = build_node (INTRINSIC_USER, &where, e, NULL); + f->uop = uop; + *result = f; + } + + return MATCH_YES; +} + + +static match +match_mult_operand (gfc_expr ** result) +{ + gfc_expr *e, *exp, *r; + locus where; + match m; + + m = match_level_1 (&e); + if (m != MATCH_YES) + return m; + + if (!next_operator (INTRINSIC_POWER)) + { + *result = e; + return MATCH_YES; + } + + where = *gfc_current_locus (); + + m = match_mult_operand (&exp); + if (m == MATCH_NO) + gfc_error ("Expected exponent in expression at %C"); + if (m != MATCH_YES) + { + gfc_free_expr (e); + return MATCH_ERROR; + } + + r = gfc_power (e, exp); + if (r == NULL) + { + gfc_free_expr (e); + gfc_free_expr (exp); + return MATCH_ERROR; + } + + r->where = where; + *result = r; + + return MATCH_YES; +} + + +static match +match_add_operand (gfc_expr ** result) +{ + gfc_expr *all, *e, *total; + locus where, old_loc; + match m; + gfc_intrinsic_op i; + + m = match_mult_operand (&all); + if (m != MATCH_YES) + return m; + + for (;;) + { + /* Build up a string of products or quotients. */ + + old_loc = *gfc_current_locus (); + + if (next_operator (INTRINSIC_TIMES)) + i = INTRINSIC_TIMES; + else + { + if (next_operator (INTRINSIC_DIVIDE)) + i = INTRINSIC_DIVIDE; + else + break; + } + + where = *gfc_current_locus (); + + m = match_mult_operand (&e); + if (m == MATCH_NO) + { + gfc_set_locus (&old_loc); + break; + } + + if (m == MATCH_ERROR) + { + gfc_free_expr (all); + return MATCH_ERROR; + } + + if (i == INTRINSIC_TIMES) + total = gfc_multiply (all, e); + else + total = gfc_divide (all, e); + + if (total == NULL) + { + gfc_free_expr (all); + gfc_free_expr (e); + return MATCH_ERROR; + } + + all = total; + all->where = where; + } + + *result = all; + return MATCH_YES; +} + + +static int +match_add_op (void) +{ + + if (next_operator (INTRINSIC_MINUS)) + return -1; + if (next_operator (INTRINSIC_PLUS)) + return 1; + return 0; +} + + +/* Match a level 2 expression. */ + +static match +match_level_2 (gfc_expr ** result) +{ + gfc_expr *all, *e, *total; + locus where; + match m; + int i; + + where = *gfc_current_locus (); + i = match_add_op (); + + m = match_add_operand (&e); + if (i != 0 && m == MATCH_NO) + { + gfc_error (expression_syntax); + m = MATCH_ERROR; + } + + if (m != MATCH_YES) + return m; + + if (i == 0) + all = e; + else + { + if (i == -1) + all = gfc_uminus (e); + else + all = gfc_uplus (e); + + if (all == NULL) + { + gfc_free_expr (e); + return MATCH_ERROR; + } + } + + all->where = where; + +/* Append add-operands to the sum */ + + for (;;) + { + where = *gfc_current_locus (); + i = match_add_op (); + if (i == 0) + break; + + m = match_add_operand (&e); + if (m == MATCH_NO) + gfc_error (expression_syntax); + if (m != MATCH_YES) + { + gfc_free_expr (all); + return MATCH_ERROR; + } + + if (i == -1) + total = gfc_subtract (all, e); + else + total = gfc_add (all, e); + + if (total == NULL) + { + gfc_free_expr (all); + gfc_free_expr (e); + return MATCH_ERROR; + } + + all = total; + all->where = where; + } + + *result = all; + return MATCH_YES; +} + + +/* Match a level three expression. */ + +static match +match_level_3 (gfc_expr ** result) +{ + gfc_expr *all, *e, *total; + locus where; + match m; + + m = match_level_2 (&all); + if (m != MATCH_YES) + return m; + + for (;;) + { + if (!next_operator (INTRINSIC_CONCAT)) + break; + + where = *gfc_current_locus (); + + m = match_level_2 (&e); + if (m == MATCH_NO) + { + gfc_error (expression_syntax); + gfc_free_expr (all); + } + if (m != MATCH_YES) + return MATCH_ERROR; + + total = gfc_concat (all, e); + if (total == NULL) + { + gfc_free_expr (all); + gfc_free_expr (e); + return MATCH_ERROR; + } + + all = total; + all->where = where; + } + + *result = all; + return MATCH_YES; +} + + +/* Match a level 4 expression. */ + +static match +match_level_4 (gfc_expr ** result) +{ + gfc_expr *left, *right, *r; + gfc_intrinsic_op i; + locus old_loc; + locus where; + match m; + + m = match_level_3 (&left); + if (m != MATCH_YES) + return m; + + old_loc = *gfc_current_locus (); + + if (gfc_match_intrinsic_op (&i) != MATCH_YES) + { + *result = left; + return MATCH_YES; + } + + if (i != INTRINSIC_EQ && i != INTRINSIC_NE && i != INTRINSIC_GE + && i != INTRINSIC_LE && i != INTRINSIC_LT && i != INTRINSIC_GT) + { + gfc_set_locus (&old_loc); + *result = left; + return MATCH_YES; + } + + where = *gfc_current_locus (); + + m = match_level_3 (&right); + if (m == MATCH_NO) + gfc_error (expression_syntax); + if (m != MATCH_YES) + { + gfc_free_expr (left); + return MATCH_ERROR; + } + + switch (i) + { + case INTRINSIC_EQ: + r = gfc_eq (left, right); + break; + + case INTRINSIC_NE: + r = gfc_ne (left, right); + break; + + case INTRINSIC_LT: + r = gfc_lt (left, right); + break; + + case INTRINSIC_LE: + r = gfc_le (left, right); + break; + + case INTRINSIC_GT: + r = gfc_gt (left, right); + break; + + case INTRINSIC_GE: + r = gfc_ge (left, right); + break; + + default: + gfc_internal_error ("match_level_4(): Bad operator"); + } + + if (r == NULL) + { + gfc_free_expr (left); + gfc_free_expr (right); + return MATCH_ERROR; + } + + r->where = where; + *result = r; + + return MATCH_YES; +} + + +static match +match_and_operand (gfc_expr ** result) +{ + gfc_expr *e, *r; + locus where; + match m; + int i; + + i = next_operator (INTRINSIC_NOT); + where = *gfc_current_locus (); + + m = match_level_4 (&e); + if (m != MATCH_YES) + return m; + + r = e; + if (i) + { + r = gfc_not (e); + if (r == NULL) + { + gfc_free_expr (e); + return MATCH_ERROR; + } + } + + r->where = where; + *result = r; + + return MATCH_YES; +} + + +static match +match_or_operand (gfc_expr ** result) +{ + gfc_expr *all, *e, *total; + locus where; + match m; + + m = match_and_operand (&all); + if (m != MATCH_YES) + return m; + + for (;;) + { + if (!next_operator (INTRINSIC_AND)) + break; + where = *gfc_current_locus (); + + m = match_and_operand (&e); + if (m == MATCH_NO) + gfc_error (expression_syntax); + if (m != MATCH_YES) + { + gfc_free_expr (all); + return MATCH_ERROR; + } + + total = gfc_and (all, e); + if (total == NULL) + { + gfc_free_expr (all); + gfc_free_expr (e); + return MATCH_ERROR; + } + + all = total; + all->where = where; + } + + *result = all; + return MATCH_YES; +} + + +static match +match_equiv_operand (gfc_expr ** result) +{ + gfc_expr *all, *e, *total; + locus where; + match m; + + m = match_or_operand (&all); + if (m != MATCH_YES) + return m; + + for (;;) + { + if (!next_operator (INTRINSIC_OR)) + break; + where = *gfc_current_locus (); + + m = match_or_operand (&e); + if (m == MATCH_NO) + gfc_error (expression_syntax); + if (m != MATCH_YES) + { + gfc_free_expr (all); + return MATCH_ERROR; + } + + total = gfc_or (all, e); + if (total == NULL) + { + gfc_free_expr (all); + gfc_free_expr (e); + return MATCH_ERROR; + } + + all = total; + all->where = where; + } + + *result = all; + return MATCH_YES; +} + + +/* Match a level 5 expression. */ + +static match +match_level_5 (gfc_expr ** result) +{ + gfc_expr *all, *e, *total; + locus where; + match m; + gfc_intrinsic_op i; + + m = match_equiv_operand (&all); + if (m != MATCH_YES) + return m; + + for (;;) + { + if (next_operator (INTRINSIC_EQV)) + i = INTRINSIC_EQV; + else + { + if (next_operator (INTRINSIC_NEQV)) + i = INTRINSIC_NEQV; + else + break; + } + + where = *gfc_current_locus (); + + m = match_equiv_operand (&e); + if (m == MATCH_NO) + gfc_error (expression_syntax); + if (m != MATCH_YES) + { + gfc_free_expr (all); + return MATCH_ERROR; + } + + if (i == INTRINSIC_EQV) + total = gfc_eqv (all, e); + else + total = gfc_neqv (all, e); + + if (total == NULL) + { + gfc_free_expr (all); + gfc_free_expr (e); + return MATCH_ERROR; + } + + all = total; + all->where = where; + } + + *result = all; + return MATCH_YES; +} + + +/* Match an expression. At this level, we are stringing together + level 5 expressions separated by binary operators. */ + +match +gfc_match_expr (gfc_expr ** result) +{ + gfc_expr *all, *e; + gfc_user_op *uop; + locus where; + match m; + + m = match_level_5 (&all); + if (m != MATCH_YES) + return m; + + for (;;) + { + m = match_defined_operator (&uop); + if (m == MATCH_NO) + break; + if (m == MATCH_ERROR) + { + gfc_free_expr (all); + return MATCH_ERROR; + } + + where = *gfc_current_locus (); + + m = match_level_5 (&e); + if (m == MATCH_NO) + gfc_error (expression_syntax); + if (m != MATCH_YES) + { + gfc_free_expr (all); + return MATCH_ERROR; + } + + all = build_node (INTRINSIC_USER, &where, all, e); + all->uop = uop; + } + + *result = all; + return MATCH_YES; +} diff --git a/gcc/fortran/mathbuiltins.def b/gcc/fortran/mathbuiltins.def new file mode 100644 index 00000000000..c46c1d523a5 --- /dev/null +++ b/gcc/fortran/mathbuiltins.def @@ -0,0 +1,14 @@ +DEFINE_MATH_BUILTIN (ACOS, "acos", 1) +DEFINE_MATH_BUILTIN (ASIN, "asin", 1) +DEFINE_MATH_BUILTIN (ATAN, "atan", 1) +DEFINE_MATH_BUILTIN (ATAN2, "atan2", 2) +DEFINE_MATH_BUILTIN (COS, "cos", 1) +DEFINE_MATH_BUILTIN (COSH, "cosh", 1) +DEFINE_MATH_BUILTIN (EXP, "exp", 1) +DEFINE_MATH_BUILTIN (LOG, "log", 1) +DEFINE_MATH_BUILTIN (LOG10, "log10", 1) +DEFINE_MATH_BUILTIN (SIN, "sin", 1) +DEFINE_MATH_BUILTIN (SINH, "sinh", 1) +DEFINE_MATH_BUILTIN (SQRT, "sqrt", 1) +DEFINE_MATH_BUILTIN (TAN, "tan", 1) +DEFINE_MATH_BUILTIN (TANH, "tanh", 1) diff --git a/gcc/fortran/misc.c b/gcc/fortran/misc.c new file mode 100644 index 00000000000..1054386e0e3 --- /dev/null +++ b/gcc/fortran/misc.c @@ -0,0 +1,327 @@ +/* Miscellaneous stuff that doesn't fit anywhere else. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include +#include +#include + +#include "gfortran.h" + + +/* Get a block of memory. Many callers assume that the memory we + return is zeroed. */ + +void * +gfc_getmem (size_t n) +{ + void *p; + + if (n == 0) + return NULL; + + p = xmalloc (n); + if (p == NULL) + gfc_fatal_error ("Out of memory-- malloc() failed"); + memset (p, 0, n); + return p; +} + + +/* gfortran.h defines free to something that triggers a syntax error, + but we need free() here. */ + +#define temp free +#undef free + +void +gfc_free (void *p) +{ + + if (p != NULL) + free (p); +} + +#define free temp +#undef temp + + +/* Get terminal width */ + +int +gfc_terminal_width(void) +{ + return 80; +} + + +/* Initialize a typespec to unknown. */ + +void +gfc_clear_ts (gfc_typespec * ts) +{ + + ts->type = BT_UNKNOWN; + ts->kind = 0; + ts->derived = NULL; + ts->cl = NULL; +} + + +/* Open a file for reading. */ + +FILE * +gfc_open_file (const char *name) +{ + struct stat statbuf; + + if (!*name) + return stdin; + + if (stat (name, &statbuf) < 0) + return NULL; + + if (!S_ISREG (statbuf.st_mode)) + return NULL; + + return fopen (name, "r"); +} + + +/* Given a word, return the correct article. */ + +const char * +gfc_article (const char *word) +{ + const char *p; + + switch (*word) + { + case 'a': + case 'A': + case 'e': + case 'E': + case 'i': + case 'I': + case 'o': + case 'O': + case 'u': + case 'U': + p = "an"; + break; + + default: + p = "a"; + } + + return p; +} + + +/* Return a string for each type. */ + +const char * +gfc_basic_typename (bt type) +{ + const char *p; + + switch (type) + { + case BT_INTEGER: + p = "INTEGER"; + break; + case BT_REAL: + p = "REAL"; + break; + case BT_COMPLEX: + p = "COMPLEX"; + break; + case BT_LOGICAL: + p = "LOGICAL"; + break; + case BT_CHARACTER: + p = "CHARACTER"; + break; + case BT_DERIVED: + p = "DERIVED"; + break; + case BT_PROCEDURE: + p = "PROCEDURE"; + break; + case BT_UNKNOWN: + p = "UNKNOWN"; + break; + default: + gfc_internal_error ("gfc_basic_typename(): Undefined type"); + } + + return p; +} + + +/* Return a string descibing the type and kind of a typespec. Because + we return alternating buffers, this subroutine can appear twice in + the argument list of a single statement. */ + +const char * +gfc_typename (gfc_typespec * ts) +{ + static char buffer1[60], buffer2[60]; + static int flag = 0; + char *buffer; + + buffer = flag ? buffer1 : buffer2; + flag = !flag; + + switch (ts->type) + { + case BT_INTEGER: + sprintf (buffer, "INTEGER(%d)", ts->kind); + break; + case BT_REAL: + sprintf (buffer, "REAL(%d)", ts->kind); + break; + case BT_COMPLEX: + sprintf (buffer, "COMPLEX(%d)", ts->kind); + break; + case BT_LOGICAL: + sprintf (buffer, "LOGICAL(%d)", ts->kind); + break; + case BT_CHARACTER: + sprintf (buffer, "CHARACTER(%d)", ts->kind); + break; + case BT_DERIVED: + sprintf (buffer, "TYPE(%s)", ts->derived->name); + break; + case BT_PROCEDURE: + strcpy (buffer, "PROCEDURE"); + break; + case BT_UNKNOWN: + strcpy (buffer, "UNKNOWN"); + break; + default: + gfc_internal_error ("gfc_typespec(): Undefined type"); + } + + return buffer; +} + + +/* Given an mstring array and a code, locate the code in the table, + returning a pointer to the string. */ + +const char * +gfc_code2string (const mstring * m, int code) +{ + + while (m->string != NULL) + { + if (m->tag == code) + return m->string; + m++; + } + + gfc_internal_error ("gfc_code2string(): Bad code"); + /* Not reached */ +} + + +/* Given an mstring array and a string, returns the value of the tag + field. Returns the final tag if no matches to the string are + found. */ + +int +gfc_string2code (const mstring * m, const char *string) +{ + + for (; m->string != NULL; m++) + if (strcmp (m->string, string) == 0) + return m->tag; + + return m->tag; +} + + +/* Convert an intent code to a string. */ +/* TODO: move to gfortran.h as define. */ +const char * +gfc_intent_string (sym_intent i) +{ + + return gfc_code2string (intents, i); +} + + +/***************** Initialization functions ****************/ + +/* Top level initialization. */ + +void +gfc_init_1 (void) +{ + + gfc_error_init_1 (); + gfc_scanner_init_1 (); + gfc_arith_init_1 (); + gfc_intrinsic_init_1 (); + gfc_iresolve_init_1 (); + gfc_simplify_init_1 (); +} + + +/* Per program unit initialization. */ + +void +gfc_init_2 (void) +{ + + gfc_symbol_init_2 (); + gfc_module_init_2 (); +} + + +/******************* Destructor functions ******************/ + +/* Call all of the top level destructors. */ + +void +gfc_done_1 (void) +{ + + gfc_scanner_done_1 (); + gfc_intrinsic_done_1 (); + gfc_simplify_done_1 (); + gfc_iresolve_done_1 (); + gfc_arith_done_1 (); +} + + +/* Per program unit destructors. */ + +void +gfc_done_2 (void) +{ + + gfc_symbol_done_2 (); + gfc_module_done_2 (); +} + diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c new file mode 100644 index 00000000000..3498f75d463 --- /dev/null +++ b/gcc/fortran/module.c @@ -0,0 +1,3459 @@ +/* Handle modules, which amounts to loading and saving symbols and + their attendant structures. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* The syntax of g95 modules resembles that of lisp lists, ie a + sequence of atoms, which can be left or right parenthesis, names, + integers or strings. Parenthesis are always matched which allows + us to skip over sections at high speed without having to know + anything about the internal structure of the lists. A "name" is + usually a fortran 95 identifier, but can also start with '@' in + order to reference a hidden symbol. + + The first line of a module is an informational message about what + created the module, the file it came from and when it was created. + The second line is a warning for people not to edit the module. + The rest of the module looks like: + + ( ( ) + ( ) + ... + ) + ( ( ... ) + ... + ) + ( ( ... ) + ... + ) + ( + + + ( ) + ... + ) + ( + + + ... + ) + + In general, symbols refer to other symbols by their symbol number, + which are zero based. Symbols are written to the module in no + particular order. */ + +#include "config.h" +#include +#include +#include +#include +#include + +#include "gfortran.h" +#include "match.h" +#include "parse.h" /* FIXME */ + +#define MODULE_EXTENSION ".mod" + + +/* Structure that descibes a position within a module file */ + +typedef struct +{ + int column, line; + fpos_t pos; +} +module_locus; + + +typedef enum +{ + P_UNKNOWN = 0, P_OTHER, P_NAMESPACE, P_COMPONENT, P_SYMBOL +} +pointer_t; + +/* The fixup structure lists pointers to pointers that have to + be updated when a pointer value becomes known. */ + +typedef struct fixup_t +{ + void **pointer; + struct fixup_t *next; +} +fixup_t; + + +/* Structure for holding extra info needed for pointers being read */ + +typedef struct pointer_info +{ + BBT_HEADER (pointer_info); + int integer; + pointer_t type; + + /* The first component of each member of the union is the pointer + being stored */ + + fixup_t *fixup; + + union + { + void *pointer; /* Member for doing pointer searches */ + + struct + { + gfc_symbol *sym; + char true_name[GFC_MAX_SYMBOL_LEN + 1], module[GFC_MAX_SYMBOL_LEN + 1]; + enum + { UNUSED, NEEDED, USED } + state; + int ns, referenced; + module_locus where; + fixup_t *stfixup; + gfc_symtree *symtree; + } + rsym; + + struct + { + gfc_symbol *sym; + enum + { UNREFERENCED = 0, NEEDS_WRITE, WRITTEN } + state; + } + wsym; + } + u; + +} +pointer_info; + +#define gfc_get_pointer_info() gfc_getmem(sizeof(pointer_info)) + + +/* Lists of rename info for the USE statement */ + +typedef struct gfc_use_rename +{ + char local_name[GFC_MAX_SYMBOL_LEN + 1], use_name[GFC_MAX_SYMBOL_LEN + 1]; + struct gfc_use_rename *next; + int found; + gfc_intrinsic_op operator; + locus where; +} +gfc_use_rename; + +#define gfc_get_use_rename() gfc_getmem(sizeof(gfc_use_rename)) + +/* Local variables */ + +/* The FILE for the module we're reading or writing. */ +static FILE *module_fp; + +/* The name of the module we're reading (USE'ing) or writing. */ +static char module_name[GFC_MAX_SYMBOL_LEN + 1]; + +static int module_line, module_column, only_flag; +static enum +{ IO_INPUT, IO_OUTPUT } +iomode; + +static gfc_use_rename *gfc_rename_list; +static pointer_info *pi_root; +static int symbol_number; /* Counter for assigning symbol numbers */ + + + +/*****************************************************************/ + +/* Pointer/integer conversion. Pointers between structures are stored + as integers in the module file. The next couple of subroutines + handle this translation for reading and writing. */ + +/* Recursively free the tree of pointer structures. */ + +static void +free_pi_tree (pointer_info * p) +{ + + if (p == NULL) + return; + + if (p->fixup != NULL) + gfc_internal_error ("free_pi_tree(): Unresolved fixup"); + + free_pi_tree (p->left); + free_pi_tree (p->right); + + gfc_free (p); +} + + +/* Compare pointers when searching by pointer. Used when writing a + module. */ + +static int +compare_pointers (void * _sn1, void * _sn2) +{ + pointer_info *sn1, *sn2; + + sn1 = (pointer_info *) _sn1; + sn2 = (pointer_info *) _sn2; + + if (sn1->u.pointer < sn2->u.pointer) + return -1; + if (sn1->u.pointer > sn2->u.pointer) + return 1; + + return 0; +} + + +/* Compare integers when searching by integer. Used when reading a + module. */ + +static int +compare_integers (void * _sn1, void * _sn2) +{ + pointer_info *sn1, *sn2; + + sn1 = (pointer_info *) _sn1; + sn2 = (pointer_info *) _sn2; + + if (sn1->integer < sn2->integer) + return -1; + if (sn1->integer > sn2->integer) + return 1; + + return 0; +} + + +/* Initialize the pointer_info tree. */ + +static void +init_pi_tree (void) +{ + compare_fn compare; + pointer_info *p; + + pi_root = NULL; + compare = (iomode == IO_INPUT) ? compare_integers : compare_pointers; + + /* Pointer 0 is the NULL pointer. */ + p = gfc_get_pointer_info (); + p->u.pointer = NULL; + p->integer = 0; + p->type = P_OTHER; + + gfc_insert_bbt (&pi_root, p, compare); + + /* Pointer 1 is the current namespace. */ + p = gfc_get_pointer_info (); + p->u.pointer = gfc_current_ns; + p->integer = 1; + p->type = P_NAMESPACE; + + gfc_insert_bbt (&pi_root, p, compare); + + symbol_number = 2; +} + + +/* During module writing, call here with a pointer to something, + returning the pointer_info node. */ + +static pointer_info * +find_pointer (void *gp) +{ + pointer_info *p; + + p = pi_root; + while (p != NULL) + { + if (p->u.pointer == gp) + break; + p = (gp < p->u.pointer) ? p->left : p->right; + } + + return p; +} + + +/* Given a pointer while writing, returns the pointer_info tree node, + creating it if it doesn't exist. */ + +static pointer_info * +get_pointer (void *gp) +{ + pointer_info *p; + + p = find_pointer (gp); + if (p != NULL) + return p; + + /* Pointer doesn't have an integer. Give it one. */ + p = gfc_get_pointer_info (); + + p->u.pointer = gp; + p->integer = symbol_number++; + + gfc_insert_bbt (&pi_root, p, compare_pointers); + + return p; +} + + +/* Given an integer during reading, find it in the pointer_info tree, + creating the node if not found. */ + +static pointer_info * +get_integer (int integer) +{ + pointer_info *p, t; + int c; + + t.integer = integer; + + p = pi_root; + while (p != NULL) + { + c = compare_integers (&t, p); + if (c == 0) + break; + + p = (c < 0) ? p->left : p->right; + } + + if (p != NULL) + return p; + + p = gfc_get_pointer_info (); + p->integer = integer; + p->u.pointer = NULL; + + gfc_insert_bbt (&pi_root, p, compare_integers); + + return p; +} + + +/* Recursive function to find a pointer within a tree by brute force. */ + +static pointer_info * +fp2 (pointer_info * p, const void *target) +{ + pointer_info *q; + + if (p == NULL) + return NULL; + + if (p->u.pointer == target) + return p; + + q = fp2 (p->left, target); + if (q != NULL) + return q; + + return fp2 (p->right, target); +} + + +/* During reading, find a pointer_info node from the pointer value. + This amounts to a brute-force search. */ + +static pointer_info * +find_pointer2 (void *p) +{ + + return fp2 (pi_root, p); +} + + +/* Resolve any fixups using a known pointer. */ +static void +resolve_fixups (fixup_t *f, void * gp) +{ + fixup_t *next; + + for (; f; f = next) + { + next = f->next; + *(f->pointer) = gp; + gfc_free (f); + } +} + +/* Call here during module reading when we know what pointer to + associate with an integer. Any fixups that exist are resolved at + this time. */ + +static void +associate_integer_pointer (pointer_info * p, void *gp) +{ + if (p->u.pointer != NULL) + gfc_internal_error ("associate_integer_pointer(): Already associated"); + + p->u.pointer = gp; + + resolve_fixups (p->fixup, gp); + + p->fixup = NULL; +} + + +/* During module reading, given an integer and a pointer to a pointer, + either store the pointer from an already-known value or create a + fixup structure in order to store things later. Returns zero if + the reference has been actually stored, or nonzero if the reference + must be fixed later (ie associate_integer_pointer must be called + sometime later. Returns the pointer_info structure. */ + +static pointer_info * +add_fixup (int integer, void *gp) +{ + pointer_info *p; + fixup_t *f; + char **cp; + + p = get_integer (integer); + + if (p->integer == 0 || p->u.pointer != NULL) + { + cp = gp; + *cp = p->u.pointer; + } + else + { + f = gfc_getmem (sizeof (fixup_t)); + + f->next = p->fixup; + p->fixup = f; + + f->pointer = gp; + } + + return p; +} + + +/*****************************************************************/ + +/* Parser related subroutines */ + +/* Free the rename list left behind by a USE statement. */ + +static void +free_rename (void) +{ + gfc_use_rename *next; + + for (; gfc_rename_list; gfc_rename_list = next) + { + next = gfc_rename_list->next; + gfc_free (gfc_rename_list); + } +} + + +/* Match a USE statement. */ + +match +gfc_match_use (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_use_rename *tail = NULL, *new; + interface_type type; + gfc_intrinsic_op operator; + match m; + + m = gfc_match_name (module_name); + if (m != MATCH_YES) + return m; + + free_rename (); + only_flag = 0; + + if (gfc_match_eos () == MATCH_YES) + return MATCH_YES; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + + if (gfc_match (" only :") == MATCH_YES) + only_flag = 1; + + if (gfc_match_eos () == MATCH_YES) + return MATCH_YES; + + for (;;) + { + /* Get a new rename struct and add it to the rename list. */ + new = gfc_get_use_rename (); + new->where = *gfc_current_locus (); + new->found = 0; + + if (gfc_rename_list == NULL) + gfc_rename_list = new; + else + tail->next = new; + tail = new; + + /* See what kind of interface we're dealing with. Asusume it is + not an operator. */ + new->operator = INTRINSIC_NONE; + if (gfc_match_generic_spec (&type, name, &operator) == MATCH_ERROR) + goto cleanup; + + switch (type) + { + case INTERFACE_NAMELESS: + gfc_error ("Missing generic specification in USE statement at %C"); + goto cleanup; + + case INTERFACE_GENERIC: + m = gfc_match (" =>"); + + if (only_flag) + { + if (m != MATCH_YES) + strcpy (new->use_name, name); + else + { + strcpy (new->local_name, name); + + m = gfc_match_name (new->use_name); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + } + } + else + { + if (m != MATCH_YES) + goto syntax; + strcpy (new->local_name, name); + + m = gfc_match_name (new->use_name); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + } + + break; + + case INTERFACE_USER_OP: + strcpy (new->use_name, name); + /* Fall through */ + + case INTERFACE_INTRINSIC_OP: + new->operator = operator; + break; + } + + if (gfc_match_eos () == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + return MATCH_YES; + +syntax: + gfc_syntax_error (ST_USE); + +cleanup: + free_rename (); + return MATCH_ERROR; +} + + +/* Given a name, return the name under which to load this symbol. + Returns NULL if this symbol shouldn't be loaded. */ + +static const char * +find_use_name (const char *name) +{ + gfc_use_rename *u; + + for (u = gfc_rename_list; u; u = u->next) + if (strcmp (u->use_name, name) == 0) + break; + + if (u == NULL) + return only_flag ? NULL : name; + + u->found = 1; + + return (u->local_name[0] != '\0') ? u->local_name : name; +} + + +/* Try to find the operator in the current list. */ + +static gfc_use_rename * +find_use_operator (gfc_intrinsic_op operator) +{ + gfc_use_rename *u; + + for (u = gfc_rename_list; u; u = u->next) + if (u->operator == operator) + return u; + + return NULL; +} + + +/*****************************************************************/ + +/* The next couple of subroutines maintain a tree used to avoid a + brute-force search for a combination of true name and module name. + While symtree names, the name that a particular symbol is known by + can changed with USE statements, we still have to keep track of the + true names to generate the correct reference, and also avoid + loading the same real symbol twice in a program unit. + + When we start reading, the true name tree is built and maintained + as symbols are read. The tree is searched as we load new symbols + to see if it already exists someplace in the namespace. */ + +typedef struct true_name +{ + BBT_HEADER (true_name); + gfc_symbol *sym; +} +true_name; + +static true_name *true_name_root; + + +/* Compare two true_name structures. */ + +static int +compare_true_names (void * _t1, void * _t2) +{ + true_name *t1, *t2; + int c; + + t1 = (true_name *) _t1; + t2 = (true_name *) _t2; + + c = strcmp (t1->sym->module, t2->sym->module); + if (c != 0) + return c; + + return strcmp (t1->sym->name, t2->sym->name); +} + + +/* Given a true name, search the true name tree to see if it exists + within the main namespace. */ + +static gfc_symbol * +find_true_name (const char *name, const char *module) +{ + true_name t, *p; + gfc_symbol sym; + int c; + + strcpy (sym.name, name); + strcpy (sym.module, module); + t.sym = &sym; + + p = true_name_root; + while (p != NULL) + { + c = compare_true_names ((void *)(&t), (void *) p); + if (c == 0) + return p->sym; + + p = (c < 0) ? p->left : p->right; + } + + return NULL; +} + + +/* Given a gfc_symbol pointer that is not in the true name tree, add + it. */ + +static void +add_true_name (gfc_symbol * sym) +{ + true_name *t; + + t = gfc_getmem (sizeof (true_name)); + t->sym = sym; + + gfc_insert_bbt (&true_name_root, t, compare_true_names); +} + + +/* Recursive function to build the initial true name tree by + recursively traversing the current namespace. */ + +static void +build_tnt (gfc_symtree * st) +{ + + if (st == NULL) + return; + + build_tnt (st->left); + build_tnt (st->right); + + if (find_true_name (st->n.sym->name, st->n.sym->module) != NULL) + return; + + add_true_name (st->n.sym); +} + + +/* Initialize the true name tree with the current namespace. */ + +static void +init_true_name_tree (void) +{ + true_name_root = NULL; + + build_tnt (gfc_current_ns->sym_root); +} + + +/* Recursively free a true name tree node. */ + +static void +free_true_name (true_name * t) +{ + + if (t == NULL) + return; + free_true_name (t->left); + free_true_name (t->right); + + gfc_free (t); +} + + +/*****************************************************************/ + +/* Module reading and writing. */ + +typedef enum +{ + ATOM_NAME, ATOM_LPAREN, ATOM_RPAREN, ATOM_INTEGER, ATOM_STRING +} +atom_type; + +static atom_type last_atom; + + +/* The name buffer must be at least as long as a symbol name. Right + now it's not clear how we're going to store numeric constants-- + probably as a hexadecimal string, since this will allow the exact + number to be preserved (this can't be done by a decimal + representation). Worry about that later. TODO! */ + +#define MAX_ATOM_SIZE 100 + +static int atom_int; +static char *atom_string, atom_name[MAX_ATOM_SIZE]; + + +/* Report problems with a module. Error reporting is not very + elaborate, since this sorts of errors shouldn't really happen. + This subroutine never returns. */ + +static void bad_module (const char *) ATTRIBUTE_NORETURN; + +static void +bad_module (const char *message) +{ + const char *p; + + switch (iomode) + { + case IO_INPUT: + p = "Reading"; + break; + case IO_OUTPUT: + p = "Writing"; + break; + default: + p = "???"; + break; + } + + fclose (module_fp); + + gfc_fatal_error ("%s module %s at line %d column %d: %s", p, + module_name, module_line, module_column, message); +} + + +/* Set the module's input pointer. */ + +static void +set_module_locus (module_locus * m) +{ + + module_column = m->column; + module_line = m->line; + fsetpos (module_fp, &m->pos); +} + + +/* Get the module's input pointer so that we can restore it later. */ + +static void +get_module_locus (module_locus * m) +{ + + m->column = module_column; + m->line = module_line; + fgetpos (module_fp, &m->pos); +} + + +/* Get the next character in the module, updating our reckoning of + where we are. */ + +static int +module_char (void) +{ + int c; + + c = fgetc (module_fp); + + if (c == EOF) + bad_module ("Unexpected EOF"); + + if (c == '\n') + { + module_line++; + module_column = 0; + } + + module_column++; + return c; +} + + +/* Parse a string constant. The delimiter is guaranteed to be a + single quote. */ + +static void +parse_string (void) +{ + module_locus start; + int len, c; + char *p; + + get_module_locus (&start); + + len = 0; + + /* See how long the string is */ + for ( ; ; ) + { + c = module_char (); + if (c == EOF) + bad_module ("Unexpected end of module in string constant"); + + if (c != '\'') + { + len++; + continue; + } + + c = module_char (); + if (c == '\'') + { + len++; + continue; + } + + break; + } + + set_module_locus (&start); + + atom_string = p = gfc_getmem (len + 1); + + for (; len > 0; len--) + { + c = module_char (); + if (c == '\'') + module_char (); /* Guaranteed to be another \' */ + *p++ = c; + } + + module_char (); /* Terminating \' */ + *p = '\0'; /* C-style string for debug purposes */ +} + + +/* Parse a small integer. */ + +static void +parse_integer (int c) +{ + module_locus m; + + atom_int = c - '0'; + + for (;;) + { + get_module_locus (&m); + + c = module_char (); + if (!ISDIGIT (c)) + break; + + atom_int = 10 * atom_int + c - '0'; + if (atom_int > 99999999) + bad_module ("Integer overflow"); + } + + set_module_locus (&m); +} + + +/* Parse a name. */ + +static void +parse_name (int c) +{ + module_locus m; + char *p; + int len; + + p = atom_name; + + *p++ = c; + len = 1; + + get_module_locus (&m); + + for (;;) + { + c = module_char (); + if (!ISALNUM (c) && c != '_' && c != '-') + break; + + *p++ = c; + if (++len > GFC_MAX_SYMBOL_LEN) + bad_module ("Name too long"); + } + + *p = '\0'; + + fseek (module_fp, -1, SEEK_CUR); + module_column = m.column + len - 1; + + if (c == '\n') + module_line--; +} + + +/* Read the next atom in the module's input stream. */ + +static atom_type +parse_atom (void) +{ + int c; + + do + { + c = module_char (); + } + while (c == ' ' || c == '\n'); + + switch (c) + { + case '(': + return ATOM_LPAREN; + + case ')': + return ATOM_RPAREN; + + case '\'': + parse_string (); + return ATOM_STRING; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + parse_integer (c); + return ATOM_INTEGER; + + 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': + parse_name (c); + return ATOM_NAME; + + default: + bad_module ("Bad name"); + } + + /* Not reached */ +} + + +/* Peek at the next atom on the input. */ + +static atom_type +peek_atom (void) +{ + module_locus m; + atom_type a; + + get_module_locus (&m); + + a = parse_atom (); + if (a == ATOM_STRING) + gfc_free (atom_string); + + set_module_locus (&m); + return a; +} + + +/* Read the next atom from the input, requiring that it be a + particular kind. */ + +static void +require_atom (atom_type type) +{ + module_locus m; + atom_type t; + const char *p; + + get_module_locus (&m); + + t = parse_atom (); + if (t != type) + { + switch (type) + { + case ATOM_NAME: + p = "Expected name"; + break; + case ATOM_LPAREN: + p = "Expected left parenthesis"; + break; + case ATOM_RPAREN: + p = "Expected right parenthesis"; + break; + case ATOM_INTEGER: + p = "Expected integer"; + break; + case ATOM_STRING: + p = "Expected string"; + break; + default: + gfc_internal_error ("require_atom(): bad atom type required"); + } + + set_module_locus (&m); + bad_module (p); + } +} + + +/* Given a pointer to an mstring array, require that the current input + be one of the strings in the array. We return the enum value. */ + +static int +find_enum (const mstring * m) +{ + int i; + + i = gfc_string2code (m, atom_name); + if (i >= 0) + return i; + + bad_module ("find_enum(): Enum not found"); + + /* Not reached */ +} + + +/**************** Module output subroutines ***************************/ + +/* Output a character to a module file. */ + +static void +write_char (char out) +{ + + if (fputc (out, module_fp) == EOF) + gfc_fatal_error ("Error writing modules file: %s", strerror (errno)); + + if (out != '\n') + module_column++; + else + { + module_column = 1; + module_line++; + } +} + + +/* Write an atom to a module. The line wrapping isn't perfect, but it + should work most of the time. This isn't that big of a deal, since + the file really isn't meant to be read by people anyway. */ + +static void +write_atom (atom_type atom, const void *v) +{ + char buffer[20]; + int i, len; + const char *p; + + switch (atom) + { + case ATOM_STRING: + case ATOM_NAME: + p = v; + break; + + case ATOM_LPAREN: + p = "("; + break; + + case ATOM_RPAREN: + p = ")"; + break; + + case ATOM_INTEGER: + i = *((const int *) v); + if (i < 0) + gfc_internal_error ("write_atom(): Writing negative integer"); + + sprintf (buffer, "%d", i); + p = buffer; + break; + + default: + gfc_internal_error ("write_atom(): Trying to write dab atom"); + + } + + len = strlen (p); + + if (atom != ATOM_RPAREN) + { + if (module_column + len > 72) + write_char ('\n'); + else + { + + if (last_atom != ATOM_LPAREN && module_column != 1) + write_char (' '); + } + } + + if (atom == ATOM_STRING) + write_char ('\''); + + while (*p) + { + if (atom == ATOM_STRING && *p == '\'') + write_char ('\''); + write_char (*p++); + } + + if (atom == ATOM_STRING) + write_char ('\''); + + last_atom = atom; +} + + + +/***************** Mid-level I/O subroutines *****************/ + +/* These subroutines let their caller read or write atoms without + caring about which of the two is actually happening. This lets a + subroutine concentrate on the actual format of the data being + written. */ + +static void mio_expr (gfc_expr **); +static void mio_symbol_ref (gfc_symbol **); +static void mio_symtree_ref (gfc_symtree **); + +/* Read or write an enumerated value. On writing, we return the input + value for the convenience of callers. We avoid using an integer + pointer because enums are sometimes inside bitfields. */ + +static int +mio_name (int t, const mstring * m) +{ + + if (iomode == IO_OUTPUT) + write_atom (ATOM_NAME, gfc_code2string (m, t)); + else + { + require_atom (ATOM_NAME); + t = find_enum (m); + } + + return t; +} + +/* Specialisation of mio_name. */ + +#define DECL_MIO_NAME(TYPE) \ + static inline TYPE \ + MIO_NAME(TYPE) (TYPE t, const mstring * m) \ + { \ + return (TYPE)mio_name ((int)t, m); \ + } +#define MIO_NAME(TYPE) mio_name_##TYPE + +static void +mio_lparen (void) +{ + + if (iomode == IO_OUTPUT) + write_atom (ATOM_LPAREN, NULL); + else + require_atom (ATOM_LPAREN); +} + + +static void +mio_rparen (void) +{ + + if (iomode == IO_OUTPUT) + write_atom (ATOM_RPAREN, NULL); + else + require_atom (ATOM_RPAREN); +} + + +static void +mio_integer (int *ip) +{ + + if (iomode == IO_OUTPUT) + write_atom (ATOM_INTEGER, ip); + else + { + require_atom (ATOM_INTEGER); + *ip = atom_int; + } +} + + +/* Read or write a character pointer that points to a string on the + heap. */ + +static void +mio_allocated_string (char **sp) +{ + + if (iomode == IO_OUTPUT) + write_atom (ATOM_STRING, *sp); + else + { + require_atom (ATOM_STRING); + *sp = atom_string; + } +} + + +/* Read or write a string that is in static memory or inside of some + already-allocated structure. */ + +static void +mio_internal_string (char *string) +{ + + if (iomode == IO_OUTPUT) + write_atom (ATOM_STRING, string); + else + { + require_atom (ATOM_STRING); + strcpy (string, atom_string); + gfc_free (atom_string); + } +} + + + +typedef enum +{ AB_ALLOCATABLE, AB_DIMENSION, AB_EXTERNAL, AB_INTRINSIC, AB_OPTIONAL, + AB_POINTER, AB_SAVE, AB_TARGET, AB_DUMMY, AB_COMMON, AB_RESULT, + AB_ENTRY, AB_DATA, AB_IN_NAMELIST, AB_IN_COMMON, AB_SAVED_COMMON, + AB_FUNCTION, AB_SUBROUTINE, AB_SEQUENCE, AB_ELEMENTAL, AB_PURE, + AB_RECURSIVE, AB_GENERIC, AB_ALWAYS_EXPLICIT +} +ab_attribute; + +static const mstring attr_bits[] = +{ + minit ("ALLOCATABLE", AB_ALLOCATABLE), + minit ("DIMENSION", AB_DIMENSION), + minit ("EXTERNAL", AB_EXTERNAL), + minit ("INTRINSIC", AB_INTRINSIC), + minit ("OPTIONAL", AB_OPTIONAL), + minit ("POINTER", AB_POINTER), + minit ("SAVE", AB_SAVE), + minit ("TARGET", AB_TARGET), + minit ("DUMMY", AB_DUMMY), + minit ("COMMON", AB_COMMON), + minit ("RESULT", AB_RESULT), + minit ("ENTRY", AB_ENTRY), + minit ("DATA", AB_DATA), + minit ("IN_NAMELIST", AB_IN_NAMELIST), + minit ("IN_COMMON", AB_IN_COMMON), + minit ("SAVED_COMMON", AB_SAVED_COMMON), + minit ("FUNCTION", AB_FUNCTION), + minit ("SUBROUTINE", AB_SUBROUTINE), + minit ("SEQUENCE", AB_SEQUENCE), + minit ("ELEMENTAL", AB_ELEMENTAL), + minit ("PURE", AB_PURE), + minit ("RECURSIVE", AB_RECURSIVE), + minit ("GENERIC", AB_GENERIC), + minit ("ALWAYS_EXPLICIT", AB_ALWAYS_EXPLICIT), + minit (NULL, -1) +}; + +/* Specialisation of mio_name. */ +DECL_MIO_NAME(ab_attribute) +DECL_MIO_NAME(ar_type) +DECL_MIO_NAME(array_type) +DECL_MIO_NAME(bt) +DECL_MIO_NAME(expr_t) +DECL_MIO_NAME(gfc_access) +DECL_MIO_NAME(gfc_intrinsic_op) +DECL_MIO_NAME(ifsrc) +DECL_MIO_NAME(procedure_type) +DECL_MIO_NAME(ref_type) +DECL_MIO_NAME(sym_flavor) +DECL_MIO_NAME(sym_intent) +#undef DECL_MIO_NAME + +/* Symbol attributes are stored in list with the first three elements + being the enumerated fields, while the remaining elements (if any) + indicate the individual attribute bits. The access field is not + saved-- it controls what symbols are exported when a module is + written. */ + +static void +mio_symbol_attribute (symbol_attribute * attr) +{ + atom_type t; + + mio_lparen (); + + attr->flavor = MIO_NAME(sym_flavor) (attr->flavor, flavors); + attr->intent = MIO_NAME(sym_intent) (attr->intent, intents); + attr->proc = MIO_NAME(procedure_type) (attr->proc, procedures); + attr->if_source = MIO_NAME(ifsrc) (attr->if_source, ifsrc_types); + + if (iomode == IO_OUTPUT) + { + if (attr->allocatable) + MIO_NAME(ab_attribute) (AB_ALLOCATABLE, attr_bits); + if (attr->dimension) + MIO_NAME(ab_attribute) (AB_DIMENSION, attr_bits); + if (attr->external) + MIO_NAME(ab_attribute) (AB_EXTERNAL, attr_bits); + if (attr->intrinsic) + MIO_NAME(ab_attribute) (AB_INTRINSIC, attr_bits); + if (attr->optional) + MIO_NAME(ab_attribute) (AB_OPTIONAL, attr_bits); + if (attr->pointer) + MIO_NAME(ab_attribute) (AB_POINTER, attr_bits); + if (attr->save) + MIO_NAME(ab_attribute) (AB_SAVE, attr_bits); + if (attr->target) + MIO_NAME(ab_attribute) (AB_TARGET, attr_bits); + if (attr->dummy) + MIO_NAME(ab_attribute) (AB_DUMMY, attr_bits); + if (attr->common) + MIO_NAME(ab_attribute) (AB_COMMON, attr_bits); + if (attr->result) + MIO_NAME(ab_attribute) (AB_RESULT, attr_bits); + if (attr->entry) + MIO_NAME(ab_attribute) (AB_ENTRY, attr_bits); + + if (attr->data) + MIO_NAME(ab_attribute) (AB_DATA, attr_bits); + if (attr->in_namelist) + MIO_NAME(ab_attribute) (AB_IN_NAMELIST, attr_bits); + if (attr->in_common) + MIO_NAME(ab_attribute) (AB_IN_COMMON, attr_bits); + if (attr->saved_common) + MIO_NAME(ab_attribute) (AB_SAVED_COMMON, attr_bits); + + if (attr->function) + MIO_NAME(ab_attribute) (AB_FUNCTION, attr_bits); + if (attr->subroutine) + MIO_NAME(ab_attribute) (AB_SUBROUTINE, attr_bits); + if (attr->generic) + MIO_NAME(ab_attribute) (AB_GENERIC, attr_bits); + + if (attr->sequence) + MIO_NAME(ab_attribute) (AB_SEQUENCE, attr_bits); + if (attr->elemental) + MIO_NAME(ab_attribute) (AB_ELEMENTAL, attr_bits); + if (attr->pure) + MIO_NAME(ab_attribute) (AB_PURE, attr_bits); + if (attr->recursive) + MIO_NAME(ab_attribute) (AB_RECURSIVE, attr_bits); + if (attr->always_explicit) + MIO_NAME(ab_attribute) (AB_ALWAYS_EXPLICIT, attr_bits); + + mio_rparen (); + + } + else + { + + for (;;) + { + t = parse_atom (); + if (t == ATOM_RPAREN) + break; + if (t != ATOM_NAME) + bad_module ("Expected attribute bit name"); + + switch ((ab_attribute) find_enum (attr_bits)) + { + case AB_ALLOCATABLE: + attr->allocatable = 1; + break; + case AB_DIMENSION: + attr->dimension = 1; + break; + case AB_EXTERNAL: + attr->external = 1; + break; + case AB_INTRINSIC: + attr->intrinsic = 1; + break; + case AB_OPTIONAL: + attr->optional = 1; + break; + case AB_POINTER: + attr->pointer = 1; + break; + case AB_SAVE: + attr->save = 1; + break; + case AB_TARGET: + attr->target = 1; + break; + case AB_DUMMY: + attr->dummy = 1; + break; + case AB_COMMON: + attr->common = 1; + break; + case AB_RESULT: + attr->result = 1; + break; + case AB_ENTRY: + attr->entry = 1; + break; + case AB_DATA: + attr->data = 1; + break; + case AB_IN_NAMELIST: + attr->in_namelist = 1; + break; + case AB_IN_COMMON: + attr->in_common = 1; + break; + case AB_SAVED_COMMON: + attr->saved_common = 1; + break; + case AB_FUNCTION: + attr->function = 1; + break; + case AB_SUBROUTINE: + attr->subroutine = 1; + break; + case AB_GENERIC: + attr->generic = 1; + break; + case AB_SEQUENCE: + attr->sequence = 1; + break; + case AB_ELEMENTAL: + attr->elemental = 1; + break; + case AB_PURE: + attr->pure = 1; + break; + case AB_RECURSIVE: + attr->recursive = 1; + break; + case AB_ALWAYS_EXPLICIT: + attr->always_explicit = 1; + break; + } + } + } +} + + +static const mstring bt_types[] = { + minit ("INTEGER", BT_INTEGER), + minit ("REAL", BT_REAL), + minit ("COMPLEX", BT_COMPLEX), + minit ("LOGICAL", BT_LOGICAL), + minit ("CHARACTER", BT_CHARACTER), + minit ("DERIVED", BT_DERIVED), + minit ("PROCEDURE", BT_PROCEDURE), + minit ("UNKNOWN", BT_UNKNOWN), + minit (NULL, -1) +}; + + +static void +mio_charlen (gfc_charlen ** clp) +{ + gfc_charlen *cl; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + cl = *clp; + if (cl != NULL) + mio_expr (&cl->length); + } + else + { + + if (peek_atom () != ATOM_RPAREN) + { + cl = gfc_get_charlen (); + mio_expr (&cl->length); + + *clp = cl; + + cl->next = gfc_current_ns->cl_list; + gfc_current_ns->cl_list = cl; + } + } + + mio_rparen (); +} + + +/* Return a symtree node with a name that is guaranteed to be unique + within the namespace and corresponds to an illegal fortran name. */ + +static gfc_symtree * +get_unique_symtree (gfc_namespace * ns) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + static int serial = 0; + + sprintf (name, "@%d", serial++); + return gfc_new_symtree (&ns->sym_root, name); +} + + +/* See if a name is a generated name. */ + +static int +check_unique_name (const char *name) +{ + + return *name == '@'; +} + + +static void +mio_typespec (gfc_typespec * ts) +{ + + mio_lparen (); + + ts->type = MIO_NAME(bt) (ts->type, bt_types); + + if (ts->type != BT_DERIVED) + mio_integer (&ts->kind); + else + mio_symbol_ref (&ts->derived); + + mio_charlen (&ts->cl); + + mio_rparen (); +} + + +static const mstring array_spec_types[] = { + minit ("EXPLICIT", AS_EXPLICIT), + minit ("ASSUMED_SHAPE", AS_ASSUMED_SHAPE), + minit ("DEFERRED", AS_DEFERRED), + minit ("ASSUMED_SIZE", AS_ASSUMED_SIZE), + minit (NULL, -1) +}; + + +static void +mio_array_spec (gfc_array_spec ** asp) +{ + gfc_array_spec *as; + int i; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + if (*asp == NULL) + goto done; + as = *asp; + } + else + { + if (peek_atom () == ATOM_RPAREN) + { + *asp = NULL; + goto done; + } + + *asp = as = gfc_get_array_spec (); + } + + mio_integer (&as->rank); + as->type = MIO_NAME(array_type) (as->type, array_spec_types); + + for (i = 0; i < as->rank; i++) + { + mio_expr (&as->lower[i]); + mio_expr (&as->upper[i]); + } + +done: + mio_rparen (); +} + + +/* Given a pointer to an array reference structure (which lives in a + gfc_ref structure), find the corresponding array specification + structure. Storing the pointer in the ref structure doesn't quite + work when loading from a module. Generating code for an array + reference also needs more infomation than just the array spec. */ + +static const mstring array_ref_types[] = { + minit ("FULL", AR_FULL), + minit ("ELEMENT", AR_ELEMENT), + minit ("SECTION", AR_SECTION), + minit (NULL, -1) +}; + +static void +mio_array_ref (gfc_array_ref * ar) +{ + int i; + + mio_lparen (); + ar->type = MIO_NAME(ar_type) (ar->type, array_ref_types); + mio_integer (&ar->dimen); + + switch (ar->type) + { + case AR_FULL: + break; + + case AR_ELEMENT: + for (i = 0; i < ar->dimen; i++) + mio_expr (&ar->start[i]); + + break; + + case AR_SECTION: + for (i = 0; i < ar->dimen; i++) + { + mio_expr (&ar->start[i]); + mio_expr (&ar->end[i]); + mio_expr (&ar->stride[i]); + } + + break; + + case AR_UNKNOWN: + gfc_internal_error ("mio_array_ref(): Unknown array ref"); + } + + for (i = 0; i < ar->dimen; i++) + mio_integer ((int *) &ar->dimen_type[i]); + + if (iomode == IO_INPUT) + { + ar->where = *gfc_current_locus (); + + for (i = 0; i < ar->dimen; i++) + ar->c_where[i] = *gfc_current_locus (); + } + + mio_rparen (); +} + + +/* Saves or restores a pointer. The pointer is converted back and + forth from an integer. We return the pointer_info pointer so that + the caller can take additional action based on the pointer type. */ + +static pointer_info * +mio_pointer_ref (void *gp) +{ + pointer_info *p; + + if (iomode == IO_OUTPUT) + { + p = get_pointer (*((char **) gp)); + write_atom (ATOM_INTEGER, &p->integer); + } + else + { + require_atom (ATOM_INTEGER); + p = add_fixup (atom_int, gp); + } + + return p; +} + + +/* Save and load references to components that occur within + expressions. We have to describe these references by a number and + by name. The number is necessary for forward references during + reading, and the name is necessary if the symbol already exists in + the namespace and is not loaded again. */ + +static void +mio_component_ref (gfc_component ** cp, gfc_symbol * sym) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_component *q; + pointer_info *p; + + p = mio_pointer_ref (cp); + if (p->type == P_UNKNOWN) + p->type = P_COMPONENT; + + if (iomode == IO_OUTPUT) + mio_internal_string ((*cp)->name); + else + { + mio_internal_string (name); + + if (sym->components != NULL && p->u.pointer == NULL) + { + /* Symbol already loaded, so search by name. */ + for (q = sym->components; q; q = q->next) + if (strcmp (q->name, name) == 0) + break; + + if (q == NULL) + gfc_internal_error ("mio_component_ref(): Component not found"); + + associate_integer_pointer (p, q); + } + + /* Make sure this symbol will eventually be loaded. */ + p = find_pointer2 (sym); + if (p->u.rsym.state == UNUSED) + p->u.rsym.state = NEEDED; + } +} + + +static void +mio_component (gfc_component * c) +{ + pointer_info *p; + int n; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + p = get_pointer (c); + mio_integer (&p->integer); + } + else + { + mio_integer (&n); + p = get_integer (n); + associate_integer_pointer (p, c); + } + + if (p->type == P_UNKNOWN) + p->type = P_COMPONENT; + + mio_internal_string (c->name); + mio_typespec (&c->ts); + mio_array_spec (&c->as); + + mio_integer (&c->dimension); + mio_integer (&c->pointer); + + mio_expr (&c->initializer); + mio_rparen (); +} + + +static void +mio_component_list (gfc_component ** cp) +{ + gfc_component *c, *tail; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + for (c = *cp; c; c = c->next) + mio_component (c); + } + else + { + + *cp = NULL; + tail = NULL; + + for (;;) + { + if (peek_atom () == ATOM_RPAREN) + break; + + c = gfc_get_component (); + mio_component (c); + + if (tail == NULL) + *cp = c; + else + tail->next = c; + + tail = c; + } + } + + mio_rparen (); +} + + +static void +mio_actual_arg (gfc_actual_arglist * a) +{ + + mio_lparen (); + mio_internal_string (a->name); + mio_expr (&a->expr); + mio_rparen (); +} + + +static void +mio_actual_arglist (gfc_actual_arglist ** ap) +{ + gfc_actual_arglist *a, *tail; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + for (a = *ap; a; a = a->next) + mio_actual_arg (a); + + } + else + { + tail = NULL; + + for (;;) + { + if (peek_atom () != ATOM_LPAREN) + break; + + a = gfc_get_actual_arglist (); + + if (tail == NULL) + *ap = a; + else + tail->next = a; + + tail = a; + mio_actual_arg (a); + } + } + + mio_rparen (); +} + + +/* Read and write formal argument lists. */ + +static void +mio_formal_arglist (gfc_symbol * sym) +{ + gfc_formal_arglist *f, *tail; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + for (f = sym->formal; f; f = f->next) + mio_symbol_ref (&f->sym); + + } + else + { + sym->formal = tail = NULL; + + while (peek_atom () != ATOM_RPAREN) + { + f = gfc_get_formal_arglist (); + mio_symbol_ref (&f->sym); + + if (sym->formal == NULL) + sym->formal = f; + else + tail->next = f; + + tail = f; + } + } + + mio_rparen (); +} + + +/* Save or restore a reference to a symbol node. */ + +void +mio_symbol_ref (gfc_symbol ** symp) +{ + pointer_info *p; + + p = mio_pointer_ref (symp); + if (p->type == P_UNKNOWN) + p->type = P_SYMBOL; + + if (iomode == IO_OUTPUT) + { + if (p->u.wsym.state == UNREFERENCED) + p->u.wsym.state = NEEDS_WRITE; + } + else + { + if (p->u.rsym.state == UNUSED) + p->u.rsym.state = NEEDED; + } +} + + +/* Save or restore a reference to a symtree node. */ + +static void +mio_symtree_ref (gfc_symtree ** stp) +{ + pointer_info *p; + fixup_t *f; + + if (iomode == IO_OUTPUT) + { + mio_symbol_ref (&(*stp)->n.sym); + } + else + { + require_atom (ATOM_INTEGER); + p = get_integer (atom_int); + if (p->type == P_UNKNOWN) + p->type = P_SYMBOL; + + if (p->u.rsym.state == UNUSED) + p->u.rsym.state = NEEDED; + + if (p->u.rsym.symtree != NULL) + { + *stp = p->u.rsym.symtree; + } + else + { + f = gfc_getmem (sizeof (fixup_t)); + + f->next = p->u.rsym.stfixup; + p->u.rsym.stfixup = f; + + f->pointer = (void **)stp; + } + } +} + +static void +mio_iterator (gfc_iterator ** ip) +{ + gfc_iterator *iter; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + if (*ip == NULL) + goto done; + } + else + { + if (peek_atom () == ATOM_RPAREN) + { + *ip = NULL; + goto done; + } + + *ip = gfc_get_iterator (); + } + + iter = *ip; + + mio_expr (&iter->var); + mio_expr (&iter->start); + mio_expr (&iter->end); + mio_expr (&iter->step); + +done: + mio_rparen (); +} + + + +static void +mio_constructor (gfc_constructor ** cp) +{ + gfc_constructor *c, *tail; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + for (c = *cp; c; c = c->next) + { + mio_lparen (); + mio_expr (&c->expr); + mio_iterator (&c->iterator); + mio_rparen (); + } + } + else + { + + *cp = NULL; + tail = NULL; + + while (peek_atom () != ATOM_RPAREN) + { + c = gfc_get_constructor (); + + if (tail == NULL) + *cp = c; + else + tail->next = c; + + tail = c; + + mio_lparen (); + mio_expr (&c->expr); + mio_iterator (&c->iterator); + mio_rparen (); + } + } + + mio_rparen (); +} + + + +static const mstring ref_types[] = { + minit ("ARRAY", REF_ARRAY), + minit ("COMPONENT", REF_COMPONENT), + minit ("SUBSTRING", REF_SUBSTRING), + minit (NULL, -1) +}; + + +static void +mio_ref (gfc_ref ** rp) +{ + gfc_ref *r; + + mio_lparen (); + + r = *rp; + r->type = MIO_NAME(ref_type) (r->type, ref_types); + + switch (r->type) + { + case REF_ARRAY: + mio_array_ref (&r->u.ar); + break; + + case REF_COMPONENT: + mio_symbol_ref (&r->u.c.sym); + mio_component_ref (&r->u.c.component, r->u.c.sym); + break; + + case REF_SUBSTRING: + mio_expr (&r->u.ss.start); + mio_expr (&r->u.ss.end); + mio_charlen (&r->u.ss.length); + break; + } + + mio_rparen (); +} + + +static void +mio_ref_list (gfc_ref ** rp) +{ + gfc_ref *ref, *head, *tail; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + for (ref = *rp; ref; ref = ref->next) + mio_ref (&ref); + } + else + { + head = tail = NULL; + + while (peek_atom () != ATOM_RPAREN) + { + if (head == NULL) + head = tail = gfc_get_ref (); + else + { + tail->next = gfc_get_ref (); + tail = tail->next; + } + + mio_ref (&tail); + } + + *rp = head; + } + + mio_rparen (); +} + + +/* Read and write an integer value. */ + +static void +mio_gmp_integer (mpz_t * integer) +{ + char *p; + + if (iomode == IO_INPUT) + { + if (parse_atom () != ATOM_STRING) + bad_module ("Expected integer string"); + + mpz_init (*integer); + if (mpz_set_str (*integer, atom_string, 10)) + bad_module ("Error converting integer"); + + gfc_free (atom_string); + + } + else + { + p = mpz_get_str (NULL, 10, *integer); + write_atom (ATOM_STRING, p); + gfc_free (p); + } +} + + +static void +mio_gmp_real (mpf_t * real) +{ + mp_exp_t exponent; + char *p; + + if (iomode == IO_INPUT) + { + if (parse_atom () != ATOM_STRING) + bad_module ("Expected real string"); + + mpf_init (*real); + mpf_set_str (*real, atom_string, -16); + gfc_free (atom_string); + + } + else + { + p = mpf_get_str (NULL, &exponent, 16, 0, *real); + atom_string = gfc_getmem (strlen (p) + 20); + + sprintf (atom_string, "0.%s@%ld", p, exponent); + write_atom (ATOM_STRING, atom_string); + + gfc_free (atom_string); + gfc_free (p); + } +} + + +/* Save and restore the shape of an array constructor. */ + +static void +mio_shape (mpz_t ** pshape, int rank) +{ + mpz_t *shape; + atom_type t; + int n; + + /* A NULL shape is represented by (). */ + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + shape = *pshape; + if (!shape) + { + mio_rparen (); + return; + } + } + else + { + t = peek_atom (); + if (t == ATOM_RPAREN) + { + *pshape = NULL; + mio_rparen (); + return; + } + + shape = gfc_get_shape (rank); + *pshape = shape; + } + + for (n = 0; n < rank; n++) + mio_gmp_integer (&shape[n]); + + mio_rparen (); +} + + +static const mstring expr_types[] = { + minit ("OP", EXPR_OP), + minit ("FUNCTION", EXPR_FUNCTION), + minit ("CONSTANT", EXPR_CONSTANT), + minit ("VARIABLE", EXPR_VARIABLE), + minit ("SUBSTRING", EXPR_SUBSTRING), + minit ("STRUCTURE", EXPR_STRUCTURE), + minit ("ARRAY", EXPR_ARRAY), + minit ("NULL", EXPR_NULL), + minit (NULL, -1) +}; + +/* INTRINSIC_ASSIGN is missing because it is used as an index for + generic operators, not in expressions. INTRINSIC_USER is also + replaced by the correct function name by the time we see it. */ + +static const mstring intrinsics[] = +{ + minit ("UPLUS", INTRINSIC_UPLUS), + minit ("UMINUS", INTRINSIC_UMINUS), + minit ("PLUS", INTRINSIC_PLUS), + minit ("MINUS", INTRINSIC_MINUS), + minit ("TIMES", INTRINSIC_TIMES), + minit ("DIVIDE", INTRINSIC_DIVIDE), + minit ("POWER", INTRINSIC_POWER), + minit ("CONCAT", INTRINSIC_CONCAT), + minit ("AND", INTRINSIC_AND), + minit ("OR", INTRINSIC_OR), + minit ("EQV", INTRINSIC_EQV), + minit ("NEQV", INTRINSIC_NEQV), + minit ("EQ", INTRINSIC_EQ), + minit ("NE", INTRINSIC_NE), + minit ("GT", INTRINSIC_GT), + minit ("GE", INTRINSIC_GE), + minit ("LT", INTRINSIC_LT), + minit ("LE", INTRINSIC_LE), + minit ("NOT", INTRINSIC_NOT), + minit (NULL, -1) +}; + +/* Read and write expressions. The form "()" is allowed to indicate a + NULL expression. */ + +static void +mio_expr (gfc_expr ** ep) +{ + gfc_expr *e; + atom_type t; + int flag; + + mio_lparen (); + + if (iomode == IO_OUTPUT) + { + if (*ep == NULL) + { + mio_rparen (); + return; + } + + e = *ep; + MIO_NAME(expr_t) (e->expr_type, expr_types); + + } + else + { + t = parse_atom (); + if (t == ATOM_RPAREN) + { + *ep = NULL; + return; + } + + if (t != ATOM_NAME) + bad_module ("Expected expression type"); + + e = *ep = gfc_get_expr (); + e->where = *gfc_current_locus (); + e->expr_type = (expr_t) find_enum (expr_types); + } + + mio_typespec (&e->ts); + mio_integer (&e->rank); + + switch (e->expr_type) + { + case EXPR_OP: + e->operator = MIO_NAME(gfc_intrinsic_op) (e->operator, intrinsics); + + switch (e->operator) + { + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + case INTRINSIC_NOT: + mio_expr (&e->op1); + break; + + case INTRINSIC_PLUS: + case INTRINSIC_MINUS: + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + case INTRINSIC_POWER: + case INTRINSIC_CONCAT: + case INTRINSIC_AND: + case INTRINSIC_OR: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + case INTRINSIC_EQ: + case INTRINSIC_NE: + case INTRINSIC_GT: + case INTRINSIC_GE: + case INTRINSIC_LT: + case INTRINSIC_LE: + mio_expr (&e->op1); + mio_expr (&e->op2); + break; + + default: + bad_module ("Bad operator"); + } + + break; + + case EXPR_FUNCTION: + mio_symtree_ref (&e->symtree); + mio_actual_arglist (&e->value.function.actual); + + if (iomode == IO_OUTPUT) + { + mio_allocated_string (&e->value.function.name); + flag = e->value.function.esym != NULL; + mio_integer (&flag); + if (flag) + mio_symbol_ref (&e->value.function.esym); + else + write_atom (ATOM_STRING, e->value.function.isym->name); + + } + else + { + require_atom (ATOM_STRING); + e->value.function.name = gfc_get_string (atom_string); + gfc_free (atom_string); + + mio_integer (&flag); + if (flag) + mio_symbol_ref (&e->value.function.esym); + else + { + require_atom (ATOM_STRING); + e->value.function.isym = gfc_find_function (atom_string); + gfc_free (atom_string); + } + } + + break; + + case EXPR_VARIABLE: + mio_symtree_ref (&e->symtree); + mio_ref_list (&e->ref); + break; + + case EXPR_SUBSTRING: + mio_allocated_string (&e->value.character.string); + mio_expr (&e->op1); + mio_expr (&e->op2); + break; + + case EXPR_STRUCTURE: + case EXPR_ARRAY: + mio_constructor (&e->value.constructor); + mio_shape (&e->shape, e->rank); + break; + + case EXPR_CONSTANT: + switch (e->ts.type) + { + case BT_INTEGER: + mio_gmp_integer (&e->value.integer); + break; + + case BT_REAL: + mio_gmp_real (&e->value.real); + break; + + case BT_COMPLEX: + mio_gmp_real (&e->value.complex.r); + mio_gmp_real (&e->value.complex.i); + break; + + case BT_LOGICAL: + mio_integer (&e->value.logical); + break; + + case BT_CHARACTER: + mio_integer (&e->value.character.length); + mio_allocated_string (&e->value.character.string); + break; + + default: + bad_module ("Bad type in constant expression"); + } + + break; + + case EXPR_NULL: + break; + } + + mio_rparen (); +} + + +/* Save/restore lists of gfc_interface stuctures. When loading an + interface, we are really appending to the existing list of + interfaces. Checking for duplicate and ambiguous interfaces has to + be done later when all symbols have been loaded. */ + +static void +mio_interface_rest (gfc_interface ** ip) +{ + gfc_interface *tail, *p; + + if (iomode == IO_OUTPUT) + { + if (ip != NULL) + for (p = *ip; p; p = p->next) + mio_symbol_ref (&p->sym); + } + else + { + + if (*ip == NULL) + tail = NULL; + else + { + tail = *ip; + while (tail->next) + tail = tail->next; + } + + for (;;) + { + if (peek_atom () == ATOM_RPAREN) + break; + + p = gfc_get_interface (); + mio_symbol_ref (&p->sym); + + if (tail == NULL) + *ip = p; + else + tail->next = p; + + tail = p; + } + } + + mio_rparen (); +} + + +/* Save/restore a nameless operator interface. */ + +static void +mio_interface (gfc_interface ** ip) +{ + + mio_lparen (); + mio_interface_rest (ip); +} + + +/* Save/restore a named operator interface. */ + +static void +mio_symbol_interface (char *name, char *module, + gfc_interface ** ip) +{ + + mio_lparen (); + + mio_internal_string (name); + mio_internal_string (module); + + mio_interface_rest (ip); +} + + +static void +mio_namespace_ref (gfc_namespace ** nsp) +{ + gfc_namespace *ns; + pointer_info *p; + + p = mio_pointer_ref (nsp); + + if (p->type == P_UNKNOWN) + p->type = P_NAMESPACE; + + if (iomode == IO_INPUT && p->integer != 0 && p->u.pointer == NULL) + { + ns = gfc_get_namespace (NULL); + associate_integer_pointer (p, ns); + } +} + + +/* Unlike most other routines, the address of the symbol node is + already fixed on input and the name/module has already been filled + in. */ + +static void +mio_symbol (gfc_symbol * sym) +{ + gfc_formal_arglist *formal; + + mio_lparen (); + + mio_symbol_attribute (&sym->attr); + mio_typespec (&sym->ts); + + /* Contained procedures don't have formal namespaces. Instead we output the + procedure namespace. The will contain the formal arguments. */ + if (iomode == IO_OUTPUT) + { + formal = sym->formal; + while (formal && !formal->sym) + formal = formal->next; + + if (formal) + mio_namespace_ref (&formal->sym->ns); + else + mio_namespace_ref (&sym->formal_ns); + } + else + { + mio_namespace_ref (&sym->formal_ns); + if (sym->formal_ns) + { + sym->formal_ns->proc_name = sym; + sym->refs++; + } + } + + /* Save/restore common block links */ + mio_symbol_ref (&sym->common_head); + mio_symbol_ref (&sym->common_next); + + mio_formal_arglist (sym); + + mio_expr (&sym->value); + mio_array_spec (&sym->as); + + mio_symbol_ref (&sym->result); + + /* Note that components are always saved, even if they are supposed + to be private. Component access is checked during searching. */ + + mio_component_list (&sym->components); + + if (sym->components != NULL) + sym->component_access = + MIO_NAME(gfc_access) (sym->component_access, access_types); + + mio_symbol_ref (&sym->common_head); + mio_symbol_ref (&sym->common_next); + + mio_rparen (); +} + + +/************************* Top level subroutines *************************/ + +/* Skip a list between balanced left and right parens. */ + +static void +skip_list (void) +{ + int level; + + level = 0; + do + { + switch (parse_atom ()) + { + case ATOM_LPAREN: + level++; + break; + + case ATOM_RPAREN: + level--; + break; + + case ATOM_STRING: + gfc_free (atom_string); + break; + + case ATOM_NAME: + case ATOM_INTEGER: + break; + } + } + while (level > 0); +} + + +/* Load operator interfaces from the module. Interfaces are unusual + in that they attach themselves to existing symbols. */ + +static void +load_operator_interfaces (void) +{ + const char *p; + char name[GFC_MAX_SYMBOL_LEN + 1], module[GFC_MAX_SYMBOL_LEN + 1]; + gfc_user_op *uop; + + mio_lparen (); + + while (peek_atom () != ATOM_RPAREN) + { + mio_lparen (); + + mio_internal_string (name); + mio_internal_string (module); + + /* Decide if we need to load this one or not. */ + p = find_use_name (name); + if (p == NULL) + { + while (parse_atom () != ATOM_RPAREN); + } + else + { + uop = gfc_get_uop (p); + mio_interface_rest (&uop->operator); + } + } + + mio_rparen (); +} + + +/* Load interfaces from the module. Interfaces are unusual in that + they attach themselves to existing symbols. */ + +static void +load_generic_interfaces (void) +{ + const char *p; + char name[GFC_MAX_SYMBOL_LEN + 1], module[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + + mio_lparen (); + + while (peek_atom () != ATOM_RPAREN) + { + mio_lparen (); + + mio_internal_string (name); + mio_internal_string (module); + + /* Decide if we need to load this one or not. */ + p = find_use_name (name); + + if (p == NULL || gfc_find_symbol (p, NULL, 0, &sym)) + { + while (parse_atom () != ATOM_RPAREN); + continue; + } + + if (sym == NULL) + { + gfc_get_symbol (p, NULL, &sym); + + sym->attr.flavor = FL_PROCEDURE; + sym->attr.generic = 1; + sym->attr.use_assoc = 1; + } + + mio_interface_rest (&sym->generic); + } + + mio_rparen (); +} + + +/* Recursive function to traverse the pointer_info tree and load a + needed symbol. We return nonzero if we load a symbol and stop the + traversal, because the act of loading can alter the tree. */ + +static int +load_needed (pointer_info * p) +{ + gfc_namespace *ns; + pointer_info *q; + gfc_symbol *sym; + + if (p == NULL) + return 0; + if (load_needed (p->left)) + return 1; + if (load_needed (p->right)) + return 1; + + if (p->type != P_SYMBOL || p->u.rsym.state != NEEDED) + return 0; + + p->u.rsym.state = USED; + + set_module_locus (&p->u.rsym.where); + + sym = p->u.rsym.sym; + if (sym == NULL) + { + q = get_integer (p->u.rsym.ns); + + ns = (gfc_namespace *) q->u.pointer; + if (ns == NULL) + { + /* Create an interface namespace if necessary. These are + the namespaces that hold the formal parameters of module + procedures. */ + + ns = gfc_get_namespace (NULL); + associate_integer_pointer (q, ns); + } + + sym = gfc_new_symbol (p->u.rsym.true_name, ns); + strcpy (sym->module, p->u.rsym.module); + + associate_integer_pointer (p, sym); + } + + mio_symbol (sym); + sym->attr.use_assoc = 1; + + return 1; +} + + +/* Recursive function for cleaning up things after a module has been + read. */ + +static void +read_cleanup (pointer_info * p) +{ + gfc_symtree *st; + pointer_info *q; + + if (p == NULL) + return; + + read_cleanup (p->left); + read_cleanup (p->right); + + if (p->type == P_SYMBOL && p->u.rsym.state == USED && !p->u.rsym.referenced) + { + /* Add hidden symbols to the symtree. */ + q = get_integer (p->u.rsym.ns); + st = get_unique_symtree ((gfc_namespace *) q->u.pointer); + + st->n.sym = p->u.rsym.sym; + st->n.sym->refs++; + + /* Fixup any symtree references. */ + p->u.rsym.symtree = st; + resolve_fixups (p->u.rsym.stfixup, st); + p->u.rsym.stfixup = NULL; + } + + /* Free unused symbols. */ + if (p->type == P_SYMBOL && p->u.rsym.state == UNUSED) + gfc_free_symbol (p->u.rsym.sym); +} + + +/* Read a module file. */ + +static void +read_module (void) +{ + module_locus operator_interfaces, user_operators; + const char *p; + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_intrinsic_op i; + int ambiguous, symbol; + pointer_info *info; + gfc_use_rename *u; + gfc_symtree *st; + gfc_symbol *sym; + + get_module_locus (&operator_interfaces); /* Skip these for now */ + skip_list (); + + get_module_locus (&user_operators); + skip_list (); + skip_list (); + + mio_lparen (); + + /* Create the fixup nodes for all the symbols. */ + + while (peek_atom () != ATOM_RPAREN) + { + require_atom (ATOM_INTEGER); + info = get_integer (atom_int); + + info->type = P_SYMBOL; + info->u.rsym.state = UNUSED; + + mio_internal_string (info->u.rsym.true_name); + mio_internal_string (info->u.rsym.module); + + require_atom (ATOM_INTEGER); + info->u.rsym.ns = atom_int; + + get_module_locus (&info->u.rsym.where); + skip_list (); + + /* See if the symbol has already been loaded by a previous module. + If so, we reference the existing symbol and prevent it from + being loaded again. */ + + sym = find_true_name (info->u.rsym.true_name, info->u.rsym.module); + if (sym == NULL) + continue; + + info->u.rsym.state = USED; + info->u.rsym.referenced = 1; + info->u.rsym.sym = sym; + } + + mio_rparen (); + + /* Parse the symtree lists. This lets us mark which symbols need to + be loaded. Renaming is also done at this point by replacing the + symtree name. */ + + mio_lparen (); + + while (peek_atom () != ATOM_RPAREN) + { + mio_internal_string (name); + mio_integer (&ambiguous); + mio_integer (&symbol); + + info = get_integer (symbol); + + /* Get the local name for this symbol. */ + p = find_use_name (name); + + /* Skip symtree nodes not in an ONLY caluse. */ + if (p == NULL) + continue; + + /* Check for ambiguous symbols. */ + st = gfc_find_symtree (gfc_current_ns->sym_root, p); + + if (st != NULL) + { + if (st->n.sym != info->u.rsym.sym) + st->ambiguous = 1; + info->u.rsym.symtree = st; + } + else + { + /* Create a symtree node in the current namespace for this symbol. */ + st = check_unique_name (p) ? get_unique_symtree (gfc_current_ns) : + gfc_new_symtree (&gfc_current_ns->sym_root, p); + + st->ambiguous = ambiguous; + + sym = info->u.rsym.sym; + + /* Create a symbol node if it doesn't already exist. */ + if (sym == NULL) + { + sym = info->u.rsym.sym = + gfc_new_symbol (info->u.rsym.true_name, gfc_current_ns); + + strcpy (sym->module, info->u.rsym.module); + } + + st->n.sym = sym; + st->n.sym->refs++; + + /* Store the symtree pointing to this symbol. */ + info->u.rsym.symtree = st; + + if (info->u.rsym.state == UNUSED) + info->u.rsym.state = NEEDED; + info->u.rsym.referenced = 1; + } + } + + mio_rparen (); + + /* Load intrinsic operator interfaces. */ + set_module_locus (&operator_interfaces); + mio_lparen (); + + for (i = GFC_INTRINSIC_BEGIN; i != GFC_INTRINSIC_END; i++) + { + if (i == INTRINSIC_USER) + continue; + + if (only_flag) + { + u = find_use_operator (i); + + if (u == NULL) + { + skip_list (); + continue; + } + + u->found = 1; + } + + mio_interface (&gfc_current_ns->operator[i]); + } + + mio_rparen (); + + /* Load generic and user operator interfaces. These must follow the + loading of symtree because otherwise symbols can be marked as + ambiguous. */ + + set_module_locus (&user_operators); + + load_operator_interfaces (); + load_generic_interfaces (); + + /* At this point, we read those symbols that are needed but haven't + been loaded yet. If one symbol requires another, the other gets + marked as NEEDED if its previous state was UNUSED. */ + + while (load_needed (pi_root)); + + /* Make sure all elements of the rename-list were found in the + module. */ + + for (u = gfc_rename_list; u; u = u->next) + { + if (u->found) + continue; + + if (u->operator == INTRINSIC_NONE) + { + gfc_error ("Symbol '%s' referenced at %L not found in module '%s'", + u->use_name, &u->where, module_name); + continue; + } + + if (u->operator == INTRINSIC_USER) + { + gfc_error + ("User operator '%s' referenced at %L not found in module '%s'", + u->use_name, &u->where, module_name); + continue; + } + + gfc_error + ("Intrinsic operator '%s' referenced at %L not found in module " + "'%s'", gfc_op2string (u->operator), &u->where, module_name); + } + + gfc_check_interfaces (gfc_current_ns); + + /* Clean up symbol nodes that were never loaded, create references + to hidden symbols. */ + + read_cleanup (pi_root); +} + + +/* Given an access type that is specific to an entity and the default + access, return nonzero if we should write the entity. */ + +static int +check_access (gfc_access specific_access, gfc_access default_access) +{ + + if (specific_access == ACCESS_PUBLIC) + return 1; + if (specific_access == ACCESS_PRIVATE) + return 0; + + if (gfc_option.flag_module_access_private) + { + if (default_access == ACCESS_PUBLIC) + return 1; + } + else + { + if (default_access != ACCESS_PRIVATE) + return 1; + } + + return 0; +} + + +/* Write a symbol to the module. */ + +static void +write_symbol (int n, gfc_symbol * sym) +{ + + if (sym->attr.flavor == FL_UNKNOWN || sym->attr.flavor == FL_LABEL) + gfc_internal_error ("write_symbol(): bad module symbol '%s'", sym->name); + + mio_integer (&n); + mio_internal_string (sym->name); + + if (sym->module[0] == '\0') + strcpy (sym->module, module_name); + + mio_internal_string (sym->module); + mio_pointer_ref (&sym->ns); + + mio_symbol (sym); + write_char ('\n'); +} + + +/* Recursive traversal function to write the initial set of symbols to + the module. We check to see if the symbol should be written + according to the access specification. */ + +static void +write_symbol0 (gfc_symtree * st) +{ + gfc_symbol *sym; + pointer_info *p; + + if (st == NULL) + return; + + write_symbol0 (st->left); + write_symbol0 (st->right); + + sym = st->n.sym; + + if (sym->attr.flavor == FL_PROCEDURE && sym->attr.generic + && !sym->attr.subroutine && !sym->attr.function) + return; + + if (!check_access (sym->attr.access, sym->ns->default_access)) + return; + + p = get_pointer (sym); + if (p->type == P_UNKNOWN) + p->type = P_SYMBOL; + + if (p->u.wsym.state == WRITTEN) + return; + + write_symbol (p->integer, sym); + p->u.wsym.state = WRITTEN; + + return; +} + + +/* Recursive traversal function to write the secondary set of symbols + to the module file. These are symbols that were not public yet are + needed by the public symbols or another dependent symbol. The act + of writing a symbol can modify the pointer_info tree, so we cease + traversal if we find a symbol to write. We return nonzero if a + symbol was written and pass that information upwards. */ + +static int +write_symbol1 (pointer_info * p) +{ + + if (p == NULL) + return 0; + + if (write_symbol1 (p->left)) + return 1; + if (write_symbol1 (p->right)) + return 1; + + if (p->type != P_SYMBOL || p->u.wsym.state != NEEDS_WRITE) + return 0; + + p->u.wsym.state = WRITTEN; + write_symbol (p->integer, p->u.wsym.sym); + + return 1; +} + + +/* Write operator interfaces associated with a symbol. */ + +static void +write_operator (gfc_user_op * uop) +{ + static char nullstring[] = ""; + + if (uop->operator == NULL + || !check_access (uop->access, uop->ns->default_access)) + return; + + mio_symbol_interface (uop->name, nullstring, &uop->operator); +} + + +/* Write generic interfaces associated with a symbol. */ + +static void +write_generic (gfc_symbol * sym) +{ + + if (sym->generic == NULL + || !check_access (sym->attr.access, sym->ns->default_access)) + return; + + mio_symbol_interface (sym->name, sym->module, &sym->generic); +} + + +static void +write_symtree (gfc_symtree * st) +{ + gfc_symbol *sym; + pointer_info *p; + + sym = st->n.sym; + if (!check_access (sym->attr.access, sym->ns->default_access) + || (sym->attr.flavor == FL_PROCEDURE && sym->attr.generic + && !sym->attr.subroutine && !sym->attr.function)) + return; + + if (check_unique_name (st->name)) + return; + + p = find_pointer (sym); + if (p == NULL) + gfc_internal_error ("write_symtree(): Symbol not written"); + + mio_internal_string (st->name); + mio_integer (&st->ambiguous); + mio_integer (&p->integer); +} + + +static void +write_module (void) +{ + gfc_intrinsic_op i; + + /* Write the operator interfaces. */ + mio_lparen (); + + for (i = GFC_INTRINSIC_BEGIN; i != GFC_INTRINSIC_END; i++) + { + if (i == INTRINSIC_USER) + continue; + + mio_interface (check_access (gfc_current_ns->operator_access[i], + gfc_current_ns->default_access) + ? &gfc_current_ns->operator[i] : NULL); + } + + mio_rparen (); + write_char ('\n'); + write_char ('\n'); + + mio_lparen (); + gfc_traverse_user_op (gfc_current_ns, write_operator); + mio_rparen (); + write_char ('\n'); + write_char ('\n'); + + mio_lparen (); + gfc_traverse_ns (gfc_current_ns, write_generic); + mio_rparen (); + write_char ('\n'); + write_char ('\n'); + + /* Write symbol information. First we traverse all symbols in the + primary namespace, writing those that need to be written. + Sometimes writing one symbol will cause another to need to be + written. A list of these symbols ends up on the write stack, and + we end by popping the bottom of the stack and writing the symbol + until the stack is empty. */ + + mio_lparen (); + + write_symbol0 (gfc_current_ns->sym_root); + while (write_symbol1 (pi_root)); + + mio_rparen (); + + write_char ('\n'); + write_char ('\n'); + + mio_lparen (); + gfc_traverse_symtree (gfc_current_ns, write_symtree); + mio_rparen (); +} + + +/* Given module, dump it to disk. If there was an error while + processing the module, dump_flag will be set to zero and we delete + the module file, even if it was already there. */ + +void +gfc_dump_module (const char *name, int dump_flag) +{ + char filename[PATH_MAX], *p; + gfc_file *g; + time_t now; + + filename[0] = '\0'; + if (gfc_option.module_dir != NULL) + strcpy (filename, gfc_option.module_dir); + + strcat (filename, name); + strcat (filename, MODULE_EXTENSION); + + if (!dump_flag) + { + unlink (filename); + return; + } + + module_fp = fopen (filename, "w"); + if (module_fp == NULL) + gfc_fatal_error ("Can't open module file '%s' for writing: %s", + filename, strerror (errno)); + + /* Find the top level filename. */ + g = gfc_current_file; + while (g->next) + g = g->next; + + now = time (NULL); + p = ctime (&now); + + *strchr (p, '\n') = '\0'; + + fprintf (module_fp, "GFORTRAN module created from %s on %s\n", g->filename, p); + fputs ("If you edit this, you'll get what you deserve.\n\n", module_fp); + + iomode = IO_OUTPUT; + strcpy (module_name, name); + + init_pi_tree (); + + write_module (); + + free_pi_tree (pi_root); + pi_root = NULL; + + write_char ('\n'); + + if (fclose (module_fp)) + gfc_fatal_error ("Error writing module file '%s' for writing: %s", + filename, strerror (errno)); +} + + +/* Process a USE directive. */ + +void +gfc_use_module (void) +{ + char filename[GFC_MAX_SYMBOL_LEN + 5]; + gfc_state_data *p; + int c, line; + + strcpy (filename, module_name); + strcat (filename, MODULE_EXTENSION); + + module_fp = gfc_open_included_file (filename); + if (module_fp == NULL) + gfc_fatal_error ("Can't open module file '%s' for reading: %s", + filename, strerror (errno)); + + iomode = IO_INPUT; + module_line = 1; + module_column = 1; + + /* Skip the first two lines of the module. */ + /* FIXME: Could also check for valid two lines here, instead. */ + line = 0; + while (line < 2) + { + c = module_char (); + if (c == EOF) + bad_module ("Unexpected end of module"); + if (c == '\n') + line++; + } + + /* Make sure we're not reading the same module that we may be building. */ + for (p = gfc_state_stack; p; p = p->previous) + if (p->state == COMP_MODULE && strcmp (p->sym->name, module_name) == 0) + gfc_fatal_error ("Can't USE the same module we're building!"); + + init_pi_tree (); + init_true_name_tree (); + + read_module (); + + free_true_name (true_name_root); + true_name_root = NULL; + + free_pi_tree (pi_root); + pi_root = NULL; + + fclose (module_fp); +} + + +void +gfc_module_init_2 (void) +{ + + last_atom = ATOM_LPAREN; +} + + +void +gfc_module_done_2 (void) +{ + + free_rename (); +} diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c new file mode 100644 index 00000000000..7d6d8f31efc --- /dev/null +++ b/gcc/fortran/options.c @@ -0,0 +1,320 @@ +/* Parse and display command line options. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "flags.h" +#include "intl.h" +#include "opts.h" +#include "options.h" +#include "tree-inline.h" + +#include "gfortran.h" + +gfc_option_t gfc_option; + + +/* Get ready for options handling. */ + +unsigned int +gfc_init_options (unsigned int argc ATTRIBUTE_UNUSED, + const char **argv ATTRIBUTE_UNUSED) +{ + + gfc_option.source = NULL; + gfc_option.module_dir = NULL; + gfc_option.source_form = FORM_UNKNOWN; + gfc_option.fixed_line_length = 72; + gfc_option.max_identifier_length = GFC_MAX_SYMBOL_LEN; + gfc_option.verbose = 0; + + gfc_option.warn_aliasing = 0; + gfc_option.warn_conversion = 0; + gfc_option.warn_implicit_interface = 0; + gfc_option.warn_line_truncation = 0; + gfc_option.warn_surprising = 0; + gfc_option.warn_unused_labels = 0; + + gfc_option.flag_dollar_ok = 0; + gfc_option.flag_underscoring = 1; + gfc_option.flag_second_underscore = 1; + gfc_option.flag_implicit_none = 0; + gfc_option.flag_max_stack_var_size = 32768; + gfc_option.flag_module_access_private = 0; + gfc_option.flag_no_backend = 0; + gfc_option.flag_pack_derived = 0; + gfc_option.flag_repack_arrays = 0; + + gfc_option.q_kind = gfc_default_double_kind (); + gfc_option.i8 = 0; + gfc_option.r8 = 0; + gfc_option.d8 = 0; + + flag_argument_noalias = 2; + + gfc_option.allow_std = GFC_STD_F95_OBS | GFC_STD_F95_DEL + | GFC_STD_F2003_OBS | GFC_STD_F2003_DEL | GFC_STD_F2003 | GFC_STD_GNU; + gfc_option.warn_std = GFC_STD_F95_OBS | GFC_STD_F95_DEL + | GFC_STD_F2003 | GFC_STD_GNU; + + return CL_F95; +} + + +/* Finalize commandline options. */ + +bool +gfc_post_options (const char **pfilename) +{ + const char *filename = *pfilename; + + /* Verify the input file name. */ + if (!filename || strcmp (filename, "-") == 0) + { + filename = ""; + } + + gfc_option.source = filename; + + flag_inline_trees = 1; + + /* Use tree inlining. */ + if (!flag_no_inline) + flag_no_inline = 1; + if (flag_inline_functions) + { + flag_inline_trees = 2; + flag_inline_functions = 0; + } + + return false; +} + + +/* Set the options for -Wall. */ + +static void +set_Wall (void) +{ + + gfc_option.warn_aliasing = 1; + gfc_option.warn_line_truncation = 1; + gfc_option.warn_surprising = 1; + gfc_option.warn_unused_labels = 1; + + set_Wunused (1); + warn_return_type = 1; + warn_switch = 1; + + /* We save the value of warn_uninitialized, since if they put + -Wuninitialized on the command line, we need to generate a + warning about not using it without also specifying -O. */ + + if (warn_uninitialized != 1) + warn_uninitialized = 2; +} + + +static void +gfc_handle_module_path_options (const char *arg) +{ + + if (gfc_option.module_dir != NULL) + { + gfc_status ("gfortran: Only one -M option allowed\n"); + exit (3); + } + + if (arg == NULL) + { + gfc_status ("gfortran: Directory required after -M\n"); + exit (3); + } + + gfc_option.module_dir = (char *) gfc_getmem (strlen (arg)); + strcpy (gfc_option.module_dir, arg); + strcat (gfc_option.module_dir, "/"); +} + +/* Handle command-line options. Returns 0 if unrecognized, 1 if + recognized and handled. */ +int +gfc_handle_option (size_t scode, const char *arg, int value) +{ + int result = 1; + enum opt_code code = (enum opt_code) scode; + + /* Ignore file names. */ + if (code == N_OPTS) + return 1; + + switch (code) + { + default: + result = 0; + break; + + case OPT_Wall: + set_Wall (); + break; + + case OPT_Waliasing: + gfc_option.warn_aliasing = value; + break; + + case OPT_Wconversion: + gfc_option.warn_conversion = value; + break; + + case OPT_Wimplicit_interface: + gfc_option.warn_implicit_interface = value; + break; + + case OPT_Wline_truncation: + gfc_option.warn_line_truncation = value; + break; + + case OPT_Wsurprising: + gfc_option.warn_surprising = value; + break; + + case OPT_Wunused_labels: + gfc_option.warn_unused_labels = value; + break; + + case OPT_fdollar_ok: + gfc_option.flag_dollar_ok = value; + break; + + case OPT_fdump_parse_tree: + gfc_option.verbose = value; + break; + + case OPT_ffixed_form: + gfc_option.source_form = FORM_FIXED; + break; + + case OPT_ffree_form: + gfc_option.source_form = FORM_FREE; + break; + + case OPT_funderscoring: + gfc_option.flag_underscoring = value; + break; + + case OPT_fsecond_underscore: + gfc_option.flag_second_underscore = value; + break; + + case OPT_fimplicit_none: + gfc_option.flag_implicit_none = value; + break; + + case OPT_fmax_stack_var_size_: + gfc_option.flag_max_stack_var_size = value; + break; + + case OPT_fmodule_private: + gfc_option.flag_module_access_private = value; + break; + + case OPT_fno_backend: + gfc_option.flag_no_backend = value; + break; + + case OPT_fpack_derived: + gfc_option.flag_pack_derived = value; + break; + + case OPT_frepack_arrays: + gfc_option.flag_repack_arrays = value; + break; + + case OPT_ffixed_line_length_80: + gfc_option.fixed_line_length = 80; + break; + + case OPT_ffixed_line_length_132: + gfc_option.fixed_line_length = 132; + break; + + case OPT_fmax_identifier_length_: + if (value > GFC_MAX_SYMBOL_LEN) + gfc_fatal_error ("Maximum supported idenitifier length is %d", + GFC_MAX_SYMBOL_LEN); + gfc_option.max_identifier_length = value; + break; + + case OPT_qkind_: + if (gfc_validate_kind (BT_REAL, value) < 0) + gfc_fatal_error ("Argument to -fqkind isn't a valid real kind"); + gfc_option.q_kind = value; + break; + + case OPT_i8: + gfc_option.i8 = value; + break; + + case OPT_r8: + gfc_option.r8 = value; + break; + + case OPT_d8: + gfc_option.d8 = value; + break; + + case OPT_I: + gfc_add_include_path (arg); + break; + + case OPT_J: + case OPT_M: + gfc_handle_module_path_options (arg); + + case OPT_std_f95: + gfc_option.allow_std = GFC_STD_F95_OBS | GFC_STD_F2003_OBS + | GFC_STD_F2003_DEL; + gfc_option.warn_std = GFC_STD_F95_OBS; + gfc_option.max_identifier_length = 31; + break; + + case OPT_std_f2003: + gfc_option.allow_std = GFC_STD_F95_OBS | GFC_STD_F2003_OBS + | GFC_STD_F2003; + gfc_option.warn_std = GFC_STD_F95_OBS | GFC_STD_F2003_OBS; + gfc_option.max_identifier_length = 63; + break; + + case OPT_std_gnu: + gfc_option.allow_std = GFC_STD_F95_OBS | GFC_STD_F95_DEL + | GFC_STD_F2003_OBS | GFC_STD_F2003_DEL | GFC_STD_F2003 | GFC_STD_GNU; + gfc_option.warn_std = GFC_STD_F95_OBS | GFC_STD_F95_DEL + | GFC_STD_F2003_OBS | GFC_STD_F2003_DEL | GFC_STD_GNU; + break; + } + + return result; +} diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c new file mode 100644 index 00000000000..6494ba8e578 --- /dev/null +++ b/gcc/fortran/parse.c @@ -0,0 +1,2503 @@ +/* Main parser. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include +#include + +#include "gfortran.h" +#include "match.h" +#include "parse.h" + +/* Current statement label. Zero means no statement label. Because + new_st can get wiped during statement matching, we have to keep it + separate. */ + +gfc_st_label *gfc_statement_label; + +static locus label_locus; +static jmp_buf eof; + +gfc_state_data *gfc_state_stack; + +/* TODO: Re-order functions to kill these forward decls. */ +static void check_statement_label (gfc_statement); +static void undo_new_statement (void); +static void reject_statement (void); + +/* A sort of half-matching function. We try to match the word on the + input with the passed string. If this succeeds, we call the + keyword-dependent matching function that will match the rest of the + statement. For single keywords, the matching subroutine is + gfc_match_eos(). */ + +static match +match_word (const char *str, match (*subr) (void), locus * old_locus) +{ + match m; + + if (str != NULL) + { + m = gfc_match (str); + if (m != MATCH_YES) + return m; + } + + m = (*subr) (); + + if (m != MATCH_YES) + { + gfc_set_locus (old_locus); + reject_statement (); + } + + return m; +} + + +/* Figure out what the next statement is, (mostly) regardless of + proper ordering. */ + +#define match(keyword, subr, st) \ + if (match_word(keyword, subr, &old_locus) == MATCH_YES) \ + return st; \ + else \ + undo_new_statement (); + +static gfc_statement +decode_statement (void) +{ + gfc_statement st; + locus old_locus; + match m; + int c; + +#ifdef GFC_DEBUG + gfc_symbol_state (); +#endif + + gfc_clear_error (); /* Clear any pending errors. */ + gfc_clear_warning (); /* Clear any pending warnings. */ + + if (gfc_match_eos () == MATCH_YES) + return ST_NONE; + + old_locus = *gfc_current_locus (); + + /* Try matching a data declaration or function declaration. The + input "REALFUNCTIONA(N)" can mean several things in different + contexts, so it (and its relatives) get special treatment. */ + + if (gfc_current_state () == COMP_NONE + || gfc_current_state () == COMP_INTERFACE + || gfc_current_state () == COMP_CONTAINS) + { + m = gfc_match_function_decl (); + if (m == MATCH_YES) + return ST_FUNCTION; + else if (m == MATCH_ERROR) + reject_statement (); + + gfc_undo_symbols (); + gfc_set_locus (&old_locus); + } + + /* Match statements whose error messages are meant to be overwritten + by something better. */ + + match (NULL, gfc_match_assignment, ST_ASSIGNMENT); + match (NULL, gfc_match_pointer_assignment, ST_POINTER_ASSIGNMENT); + match (NULL, gfc_match_st_function, ST_STATEMENT_FUNCTION); + + match (NULL, gfc_match_data_decl, ST_DATA_DECL); + + /* Try to match a subroutine statement, which has the same optional + prefixes that functions can have. */ + + if (gfc_match_subroutine () == MATCH_YES) + return ST_SUBROUTINE; + gfc_undo_symbols (); + gfc_set_locus (&old_locus); + + /* Check for the IF, DO, SELECT, WHERE and FORALL statements, which + might begin with a block label. The match functions for these + statements are unusual in that their keyword is not seen before + the matcher is called. */ + + if (gfc_match_if (&st) == MATCH_YES) + return st; + gfc_undo_symbols (); + gfc_set_locus (&old_locus); + + if (gfc_match_where (&st) == MATCH_YES) + return st; + gfc_undo_symbols (); + gfc_set_locus (&old_locus); + + if (gfc_match_forall (&st) == MATCH_YES) + return st; + gfc_undo_symbols (); + gfc_set_locus (&old_locus); + + match (NULL, gfc_match_do, ST_DO); + match (NULL, gfc_match_select, ST_SELECT_CASE); + + /* General statement matching: Instead of testing every possible + statement, we eliminate most possibilities by peeking at the + first character. */ + + c = gfc_peek_char (); + + switch (c) + { + case 'a': + match ("allocate", gfc_match_allocate, ST_ALLOCATE); + match ("allocatable", gfc_match_allocatable, ST_ATTR_DECL); + match ("assign", gfc_match_assign, ST_LABEL_ASSIGNMENT); + break; + + case 'b': + match ("backspace", gfc_match_backspace, ST_BACKSPACE); + match ("block data", gfc_match_block_data, ST_BLOCK_DATA); + break; + + case 'c': + match ("call", gfc_match_call, ST_CALL); + match ("close", gfc_match_close, ST_CLOSE); + match ("continue", gfc_match_continue, ST_CONTINUE); + match ("cycle", gfc_match_cycle, ST_CYCLE); + match ("case", gfc_match_case, ST_CASE); + match ("common", gfc_match_common, ST_COMMON); + match ("contains", gfc_match_eos, ST_CONTAINS); + break; + + case 'd': + match ("deallocate", gfc_match_deallocate, ST_DEALLOCATE); + match ("data", gfc_match_data, ST_DATA); + match ("dimension", gfc_match_dimension, ST_ATTR_DECL); + break; + + case 'e': + match ("end file", gfc_match_endfile, ST_END_FILE); + match ("exit", gfc_match_exit, ST_EXIT); + match ("else", gfc_match_else, ST_ELSE); + match ("else where", gfc_match_elsewhere, ST_ELSEWHERE); + match ("else if", gfc_match_elseif, ST_ELSEIF); + + if (gfc_match_end (&st) == MATCH_YES) + return st; + + match ("entry", gfc_match_entry, ST_ENTRY); + match ("equivalence", gfc_match_equivalence, ST_EQUIVALENCE); + match ("external", gfc_match_external, ST_ATTR_DECL); + break; + + case 'f': + match ("format", gfc_match_format, ST_FORMAT); + break; + + case 'g': + match ("go to", gfc_match_goto, ST_GOTO); + break; + + case 'i': + match ("inquire", gfc_match_inquire, ST_INQUIRE); + match ("implicit", gfc_match_implicit, ST_IMPLICIT); + match ("implicit% none", gfc_match_implicit_none, ST_IMPLICIT_NONE); + match ("interface", gfc_match_interface, ST_INTERFACE); + match ("intent", gfc_match_intent, ST_ATTR_DECL); + match ("intrinsic", gfc_match_intrinsic, ST_ATTR_DECL); + break; + + case 'm': + match ("module% procedure", gfc_match_modproc, ST_MODULE_PROC); + match ("module", gfc_match_module, ST_MODULE); + break; + + case 'n': + match ("nullify", gfc_match_nullify, ST_NULLIFY); + match ("namelist", gfc_match_namelist, ST_NAMELIST); + break; + + case 'o': + match ("open", gfc_match_open, ST_OPEN); + match ("optional", gfc_match_optional, ST_ATTR_DECL); + break; + + case 'p': + match ("print", gfc_match_print, ST_WRITE); + match ("parameter", gfc_match_parameter, ST_PARAMETER); + match ("pause", gfc_match_pause, ST_PAUSE); + match ("pointer", gfc_match_pointer, ST_ATTR_DECL); + if (gfc_match_private (&st) == MATCH_YES) + return st; + match ("program", gfc_match_program, ST_PROGRAM); + if (gfc_match_public (&st) == MATCH_YES) + return st; + break; + + case 'r': + match ("read", gfc_match_read, ST_READ); + match ("return", gfc_match_return, ST_RETURN); + match ("rewind", gfc_match_rewind, ST_REWIND); + break; + + case 's': + match ("sequence", gfc_match_eos, ST_SEQUENCE); + match ("stop", gfc_match_stop, ST_STOP); + match ("save", gfc_match_save, ST_ATTR_DECL); + break; + + case 't': + match ("target", gfc_match_target, ST_ATTR_DECL); + match ("type", gfc_match_derived_decl, ST_DERIVED_DECL); + break; + + case 'u': + match ("use", gfc_match_use, ST_USE); + break; + + case 'w': + match ("write", gfc_match_write, ST_WRITE); + break; + } + + /* All else has failed, so give up. See if any of the matchers has + stored an error message of some sort. */ + + if (gfc_error_check () == 0) + gfc_error_now ("Unclassifiable statement at %C"); + + reject_statement (); + + gfc_error_recovery (); + + return ST_NONE; +} + +#undef match + + +/* Get the next statement in free form source. */ + +static gfc_statement +next_free (void) +{ + match m; + int c, d; + + gfc_gobble_whitespace (); + + c = gfc_peek_char (); + + if (ISDIGIT (c)) + { + /* Found a statement label? */ + m = gfc_match_st_label (&gfc_statement_label, 0); + + d = gfc_peek_char (); + if (m != MATCH_YES || !gfc_is_whitespace (d)) + { + do + { + /* Skip the bad statement label. */ + gfc_warning_now ("Ignoring bad statement label at %C"); + c = gfc_next_char (); + } + while (ISDIGIT (c)); + } + else + { + label_locus = *gfc_current_locus (); + + if (gfc_statement_label->value == 0) + { + gfc_warning_now ("Ignoring statement label of zero at %C"); + gfc_free_st_label (gfc_statement_label); + gfc_statement_label = NULL; + } + + gfc_gobble_whitespace (); + + if (gfc_match_eos () == MATCH_YES) + { + gfc_warning_now + ("Ignoring statement label in empty statement at %C"); + gfc_free_st_label (gfc_statement_label); + gfc_statement_label = NULL; + return ST_NONE; + } + } + } + + return decode_statement (); +} + + +/* Get the next statement in fixed-form source. */ + +static gfc_statement +next_fixed (void) +{ + int label, digit_flag, i; + locus loc; + char c; + + if (!gfc_at_bol ()) + return decode_statement (); + + /* Skip past the current label field, parsing a statement label if + one is there. This is a weird number parser, since the number is + contained within five columns and can have any kind of embedded + spaces. We also check for characters that make the rest of the + line a comment. */ + + label = 0; + digit_flag = 0; + + for (i = 0; i < 5; i++) + { + c = gfc_next_char_literal (0); + + switch (c) + { + case ' ': + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + label = label * 10 + c - '0'; + label_locus = *gfc_current_locus (); + digit_flag = 1; + break; + + /* Comments have already been skipped by the time we get + here so don't bother checking for them. */ + + default: + gfc_buffer_error (0); + gfc_error ("Non-numeric character in statement label at %C"); + return ST_NONE; + } + } + + if (digit_flag) + { + if (label == 0) + gfc_warning_now ("Zero is not a valid statement label at %C"); + else + { + /* We've found a valid statement label. */ + gfc_statement_label = gfc_get_st_label (label); + } + } + + /* Since this line starts a statement, it cannot be a continuation + of a previous statement. Hence we mostly ignore column 6. */ + + if (gfc_next_char_literal (0) == '\n') + goto blank_line; + + /* Now that we've taken care of the statement label columns, we have + to make sure that the first nonblank character is not a '!'. If + it is, the rest of the line is a comment. */ + + do + { + loc = *gfc_current_locus (); + c = gfc_next_char_literal (0); + } + while (gfc_is_whitespace (c)); + + if (c == '!') + goto blank_line; + gfc_set_locus (&loc); + + if (gfc_match_eos () == MATCH_YES) + goto blank_line; + + /* At this point, we've got a nonblank statement to parse. */ + return decode_statement (); + +blank_line: + if (digit_flag) + gfc_warning ("Statement label in blank line will be " "ignored at %C"); + gfc_advance_line (); + return ST_NONE; +} + + +/* Return the next non-ST_NONE statement to the caller. We also worry + about including files and the ends of include files at this stage. */ + +static gfc_statement +next_statement (void) +{ + gfc_statement st; + + gfc_new_block = NULL; + + for (;;) + { + gfc_statement_label = NULL; + gfc_buffer_error (1); + + if (gfc_at_eol ()) + gfc_advance_line (); + + gfc_skip_comments (); + + if (gfc_at_bol () && gfc_check_include ()) + continue; + + if (gfc_at_eof () && gfc_current_file->included_by != NULL) + { + gfc_current_file = gfc_current_file->included_by; + gfc_advance_line (); + continue; + } + + if (gfc_at_end ()) + { + st = ST_NONE; + break; + } + + st = + (gfc_current_file->form == FORM_FIXED) ? next_fixed () : next_free (); + if (st != ST_NONE) + break; + } + + gfc_buffer_error (0); + + if (st != ST_NONE) + check_statement_label (st); + + return st; +} + + +/****************************** Parser ***********************************/ + +/* The parser subroutines are of type 'try' that fail if the file ends + unexpectedly. */ + +/* Macros that expand to case-labels for various classes of + statements. Start with executable statements that directly do + things. */ + +#define case_executable case ST_ALLOCATE: case ST_BACKSPACE: case ST_CALL: \ + case ST_CLOSE: case ST_CONTINUE: case ST_DEALLOCATE: case ST_END_FILE: \ + case ST_GOTO: case ST_INQUIRE: case ST_NULLIFY: case ST_OPEN: \ + case ST_READ: case ST_RETURN: case ST_REWIND: case ST_SIMPLE_IF: \ + case ST_PAUSE: case ST_STOP: case ST_WRITE: case ST_ASSIGNMENT: \ + case ST_POINTER_ASSIGNMENT: case ST_EXIT: case ST_CYCLE: \ + case ST_ARITHMETIC_IF: case ST_WHERE: case ST_FORALL: case ST_LABEL_ASSIGNMENT + +/* Statements that mark other executable statements. */ + +#define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: case ST_IF_BLOCK: \ + case ST_WHERE_BLOCK: case ST_SELECT_CASE + +/* Declaration statements */ + +#define case_decl case ST_ATTR_DECL: case ST_COMMON: case ST_DATA_DECL: \ + case ST_EQUIVALENCE: case ST_NAMELIST: case ST_STATEMENT_FUNCTION: \ + case ST_TYPE: case ST_INTERFACE + +/* Block end statements. Errors associated with interchanging these + are detected in gfc_match_end(). */ + +#define case_end case ST_END_BLOCK_DATA: case ST_END_FUNCTION: \ + case ST_END_PROGRAM: case ST_END_SUBROUTINE + + +/* Push a new state onto the stack. */ + +static void +push_state (gfc_state_data * p, gfc_compile_state new_state, gfc_symbol * sym) +{ + + p->state = new_state; + p->previous = gfc_state_stack; + p->sym = sym; + p->head = p->tail = NULL; + + gfc_state_stack = p; +} + + +/* Pop the current state. */ + +static void +pop_state (void) +{ + + gfc_state_stack = gfc_state_stack->previous; +} + + +/* Try to find the given state in the state stack. */ + +try +gfc_find_state (gfc_compile_state state) +{ + gfc_state_data *p; + + for (p = gfc_state_stack; p; p = p->previous) + if (p->state == state) + break; + + return (p == NULL) ? FAILURE : SUCCESS; +} + + +/* Starts a new level in the statement list. */ + +static gfc_code * +new_level (gfc_code * q) +{ + gfc_code *p; + + p = q->block = gfc_get_code (); + + gfc_state_stack->head = gfc_state_stack->tail = p; + + return p; +} + + +/* Add the current new_st code structure and adds it to the current + program unit. As a side-effect, it zeroes the new_st. */ + +static gfc_code * +add_statement (void) +{ + gfc_code *p; + + p = gfc_get_code (); + *p = new_st; + + p->loc = *gfc_current_locus (); + + if (gfc_state_stack->head == NULL) + gfc_state_stack->head = p; + else + gfc_state_stack->tail->next = p; + + while (p->next != NULL) + p = p->next; + + gfc_state_stack->tail = p; + + gfc_clear_new_st (); + + return p; +} + + +/* Frees everything associated with the current statement. */ + +static void +undo_new_statement (void) +{ + gfc_free_statements (new_st.block); + gfc_free_statements (new_st.next); + gfc_free_statement (&new_st); + gfc_clear_new_st (); +} + + +/* If the current statement has a statement label, make sure that it + is allowed to, or should have one. */ + +static void +check_statement_label (gfc_statement st) +{ + gfc_sl_type type; + + if (gfc_statement_label == NULL) + { + if (st == ST_FORMAT) + gfc_error ("FORMAT statement at %L does not have a statement label", + &new_st.loc); + return; + } + + switch (st) + { + case ST_END_PROGRAM: + case ST_END_FUNCTION: + case ST_END_SUBROUTINE: + case ST_ENDDO: + case ST_ENDIF: + case ST_END_SELECT: + case_executable: + case_exec_markers: + type = ST_LABEL_TARGET; + break; + + case ST_FORMAT: + type = ST_LABEL_FORMAT; + break; + + /* Statement labels are not restricted from appearing on a + particular line. However, there are plenty of situations + where the resulting label can't be referenced. */ + + default: + type = ST_LABEL_BAD_TARGET; + break; + } + + gfc_define_st_label (gfc_statement_label, type, &label_locus); + + new_st.here = gfc_statement_label; +} + + +/* Figures out what the enclosing program unit is. This will be a + function, subroutine, program, block data or module. */ + +gfc_state_data * +gfc_enclosing_unit (gfc_compile_state * result) +{ + gfc_state_data *p; + + for (p = gfc_state_stack; p; p = p->previous) + if (p->state == COMP_FUNCTION || p->state == COMP_SUBROUTINE + || p->state == COMP_MODULE || p->state == COMP_BLOCK_DATA + || p->state == COMP_PROGRAM) + { + + if (result != NULL) + *result = p->state; + return p; + } + + if (result != NULL) + *result = COMP_PROGRAM; + return NULL; +} + + +/* Translate a statement enum to a string. */ + +const char * +gfc_ascii_statement (gfc_statement st) +{ + const char *p; + + switch (st) + { + case ST_ARITHMETIC_IF: + p = "arithmetic IF"; + break; + case ST_ALLOCATE: + p = "ALLOCATE"; + break; + case ST_ATTR_DECL: + p = "attribute declaration"; + break; + case ST_BACKSPACE: + p = "BACKSPACE"; + break; + case ST_BLOCK_DATA: + p = "BLOCK DATA"; + break; + case ST_CALL: + p = "CALL"; + break; + case ST_CASE: + p = "CASE"; + break; + case ST_CLOSE: + p = "CLOSE"; + break; + case ST_COMMON: + p = "COMMON"; + break; + case ST_CONTINUE: + p = "CONTINUE"; + break; + case ST_CONTAINS: + p = "CONTAINS"; + break; + case ST_CYCLE: + p = "CYCLE"; + break; + case ST_DATA_DECL: + p = "data declaration"; + break; + case ST_DATA: + p = "DATA"; + break; + case ST_DEALLOCATE: + p = "DEALLOCATE"; + break; + case ST_DERIVED_DECL: + p = "Derived type declaration"; + break; + case ST_DO: + p = "DO"; + break; + case ST_ELSE: + p = "ELSE"; + break; + case ST_ELSEIF: + p = "ELSE IF"; + break; + case ST_ELSEWHERE: + p = "ELSEWHERE"; + break; + case ST_END_BLOCK_DATA: + p = "END BLOCK DATA"; + break; + case ST_ENDDO: + p = "END DO"; + break; + case ST_END_FILE: + p = "END FILE"; + break; + case ST_END_FORALL: + p = "END FORALL"; + break; + case ST_END_FUNCTION: + p = "END FUNCTION"; + break; + case ST_ENDIF: + p = "END IF"; + break; + case ST_END_INTERFACE: + p = "END INTERFACE"; + break; + case ST_END_MODULE: + p = "END MODULE"; + break; + case ST_END_PROGRAM: + p = "END PROGRAM"; + break; + case ST_END_SELECT: + p = "END SELECT"; + break; + case ST_END_SUBROUTINE: + p = "END SUBROUTINE"; + break; + case ST_END_WHERE: + p = "END WHERE"; + break; + case ST_END_TYPE: + p = "END TYPE"; + break; + case ST_ENTRY: + p = "ENTRY"; + break; + case ST_EQUIVALENCE: + p = "EQUIVALENCE"; + break; + case ST_EXIT: + p = "EXIT"; + break; + case ST_FORALL_BLOCK: /* Fall through */ + case ST_FORALL: + p = "FORALL"; + break; + case ST_FORMAT: + p = "FORMAT"; + break; + case ST_FUNCTION: + p = "FUNCTION"; + break; + case ST_GOTO: + p = "GOTO"; + break; + case ST_IF_BLOCK: + p = "block IF"; + break; + case ST_IMPLICIT: + p = "IMPLICIT"; + break; + case ST_IMPLICIT_NONE: + p = "IMPLICIT NONE"; + break; + case ST_IMPLIED_ENDDO: + p = "implied END DO"; + break; + case ST_INQUIRE: + p = "INQUIRE"; + break; + case ST_INTERFACE: + p = "INTERFACE"; + break; + case ST_PARAMETER: + p = "PARAMETER"; + break; + case ST_PRIVATE: + p = "PRIVATE"; + break; + case ST_PUBLIC: + p = "PUBLIC"; + break; + case ST_MODULE: + p = "MODULE"; + break; + case ST_PAUSE: + p = "PAUSE"; + break; + case ST_MODULE_PROC: + p = "MODULE PROCEDURE"; + break; + case ST_NAMELIST: + p = "NAMELIST"; + break; + case ST_NULLIFY: + p = "NULLIFY"; + break; + case ST_OPEN: + p = "OPEN"; + break; + case ST_PROGRAM: + p = "PROGRAM"; + break; + case ST_READ: + p = "READ"; + break; + case ST_RETURN: + p = "RETURN"; + break; + case ST_REWIND: + p = "REWIND"; + break; + case ST_STOP: + p = "STOP"; + break; + case ST_SUBROUTINE: + p = "SUBROUTINE"; + break; + case ST_TYPE: + p = "TYPE"; + break; + case ST_USE: + p = "USE"; + break; + case ST_WHERE_BLOCK: /* Fall through */ + case ST_WHERE: + p = "WHERE"; + break; + case ST_WRITE: + p = "WRITE"; + break; + case ST_ASSIGNMENT: + p = "assignment"; + break; + case ST_POINTER_ASSIGNMENT: + p = "pointer assignment"; + break; + case ST_SELECT_CASE: + p = "SELECT CASE"; + break; + case ST_SEQUENCE: + p = "SEQUENCE"; + break; + case ST_SIMPLE_IF: + p = "Simple IF"; + break; + case ST_STATEMENT_FUNCTION: + p = "STATEMENT FUNCTION"; + break; + case ST_LABEL_ASSIGNMENT: + p = "LABEL ASSIGNMENT"; + break; + default: + gfc_internal_error ("gfc_ascii_statement(): Bad statement code"); + } + + return p; +} + + +/* Return the name of a compile state. */ + +const char * +gfc_state_name (gfc_compile_state state) +{ + const char *p; + + switch (state) + { + case COMP_PROGRAM: + p = "a PROGRAM"; + break; + case COMP_MODULE: + p = "a MODULE"; + break; + case COMP_SUBROUTINE: + p = "a SUBROUTINE"; + break; + case COMP_FUNCTION: + p = "a FUNCTION"; + break; + case COMP_BLOCK_DATA: + p = "a BLOCK DATA"; + break; + case COMP_INTERFACE: + p = "an INTERFACE"; + break; + case COMP_DERIVED: + p = "a DERIVED TYPE block"; + break; + case COMP_IF: + p = "an IF-THEN block"; + break; + case COMP_DO: + p = "a DO block"; + break; + case COMP_SELECT: + p = "a SELECT block"; + break; + case COMP_FORALL: + p = "a FORALL block"; + break; + case COMP_WHERE: + p = "a WHERE block"; + break; + case COMP_CONTAINS: + p = "a contained subprogram"; + break; + + default: + gfc_internal_error ("gfc_state_name(): Bad state"); + } + + return p; +} + + +/* Do whatever is necessary to accept the last statement. */ + +static void +accept_statement (gfc_statement st) +{ + + switch (st) + { + case ST_USE: + gfc_use_module (); + break; + + case ST_IMPLICIT_NONE: + gfc_set_implicit_none (); + break; + + case ST_IMPLICIT: + gfc_set_implicit (); + break; + + case ST_FUNCTION: + case ST_SUBROUTINE: + case ST_MODULE: + gfc_current_ns->proc_name = gfc_new_block; + break; + + /* If the statement is the end of a block, lay down a special code + that allows a branch to the end of the block from within the + construct. */ + + case ST_ENDIF: + case ST_ENDDO: + case ST_END_SELECT: + if (gfc_statement_label != NULL) + { + new_st.op = EXEC_NOP; + add_statement (); + } + + break; + + /* The end-of-program unit statements do not get the special + marker and require a statement of some sort if they are a + branch target. */ + + case ST_END_PROGRAM: + case ST_END_FUNCTION: + case ST_END_SUBROUTINE: + if (gfc_statement_label != NULL) + { + new_st.op = EXEC_RETURN; + add_statement (); + } + + break; + + case ST_BLOCK_DATA: + { + gfc_symbol *block_data = NULL; + symbol_attribute attr; + + gfc_get_symbol ("_BLOCK_DATA__", gfc_current_ns, &block_data); + gfc_clear_attr (&attr); + attr.flavor = FL_PROCEDURE; + attr.proc = PROC_UNKNOWN; + attr.subroutine = 1; + attr.access = ACCESS_PUBLIC; + block_data->attr = attr; + gfc_current_ns->proc_name = block_data; + gfc_commit_symbols (); + } + + break; + + case_executable: + case_exec_markers: + add_statement (); + break; + + default: + break; + } + + gfc_commit_symbols (); + gfc_warning_check (); + gfc_clear_new_st (); +} + + +/* Undo anything tentative that has been built for the current + statement. */ + +static void +reject_statement (void) +{ + + gfc_undo_symbols (); + gfc_clear_warning (); + undo_new_statement (); +} + + +/* Generic complaint about an out of order statement. We also do + whatever is necessary to clean up. */ + +static void +unexpected_statement (gfc_statement st) +{ + + gfc_error ("Unexpected %s statement at %C", gfc_ascii_statement (st)); + + reject_statement (); +} + + +/* Given the next statement seen by the matcher, make sure that it is + in proper order with the last. This subroutine is initialized by + calling it with an argument of ST_NONE. If there is a problem, we + issue an error and return FAILURE. Otherwise we return SUCCESS. + + Individual parsers need to verify that the statements seen are + valid before calling here, ie ENTRY statements are not allowed in + INTERFACE blocks. The following diagram is taken from the standard: + + +---------------------------------------+ + | program subroutine function module | + +---------------------------------------+ + | use | + |---------------------------------------+ + | | implicit none | + | +-----------+------------------+ + | | parameter | implicit | + | +-----------+------------------+ + | format | | derived type | + | entry | parameter | interface | + | | data | specification | + | | | statement func | + | +-----------+------------------+ + | | data | executable | + +--------+-----------+------------------+ + | contains | + +---------------------------------------+ + | internal module/subprogram | + +---------------------------------------+ + | end | + +---------------------------------------+ + +*/ + +typedef struct +{ + enum + { ORDER_START, ORDER_USE, ORDER_IMPLICIT_NONE, ORDER_IMPLICIT, + ORDER_SPEC, ORDER_EXEC + } + state; + gfc_statement last_statement; + locus where; +} +st_state; + +static try +verify_st_order (st_state * p, gfc_statement st) +{ + + switch (st) + { + case ST_NONE: + p->state = ORDER_START; + break; + + case ST_USE: + if (p->state > ORDER_USE) + goto order; + p->state = ORDER_USE; + break; + + case ST_IMPLICIT_NONE: + if (p->state > ORDER_IMPLICIT_NONE) + goto order; + + /* The '>' sign cannot be a '>=', because a FORMAT or ENTRY + statement disqualifies a USE but not an IMPLICIT NONE. + Duplicate IMPLICIT NONEs are caught when the implicit types + are set. */ + + p->state = ORDER_IMPLICIT_NONE; + break; + + case ST_IMPLICIT: + if (p->state > ORDER_IMPLICIT) + goto order; + p->state = ORDER_IMPLICIT; + break; + + case ST_FORMAT: + case ST_ENTRY: + if (p->state < ORDER_IMPLICIT_NONE) + p->state = ORDER_IMPLICIT_NONE; + break; + + case ST_PARAMETER: + if (p->state >= ORDER_EXEC) + goto order; + if (p->state < ORDER_IMPLICIT) + p->state = ORDER_IMPLICIT; + break; + + case ST_DATA: + if (p->state < ORDER_SPEC) + p->state = ORDER_SPEC; + break; + + case ST_PUBLIC: + case ST_PRIVATE: + case ST_DERIVED_DECL: + case_decl: + if (p->state >= ORDER_EXEC) + goto order; + if (p->state < ORDER_SPEC) + p->state = ORDER_SPEC; + break; + + case_executable: + case_exec_markers: + if (p->state < ORDER_EXEC) + p->state = ORDER_EXEC; + break; + + default: + gfc_internal_error + ("Unexpected %s statement in verify_st_order() at %C", + gfc_ascii_statement (st)); + } + + /* All is well, record the statement in case we need it next time. */ + p->where = *gfc_current_locus (); + p->last_statement = st; + return SUCCESS; + +order: + gfc_error ("%s statement at %C cannot follow %s statement at %L", + gfc_ascii_statement (st), + gfc_ascii_statement (p->last_statement), &p->where); + + return FAILURE; +} + + +/* Handle an unexpected end of file. This is a show-stopper... */ + +static void unexpected_eof (void) ATTRIBUTE_NORETURN; + +static void +unexpected_eof (void) +{ + gfc_state_data *p; + + gfc_error ("Unexpected end of file in '%s'", gfc_current_file->filename); + + /* Memory cleanup. Move to "second to last". */ + for (p = gfc_state_stack; p && p->previous && p->previous->previous; + p = p->previous); + + gfc_current_ns->code = (p && p->previous) ? p->head : NULL; + gfc_done_2 (); + + longjmp (eof, 1); +} + + +/* Parse a derived type. */ + +static void +parse_derived (void) +{ + int compiling_type, seen_private, seen_sequence, seen_component, error_flag; + gfc_statement st; + gfc_component *c; + gfc_state_data s; + + error_flag = 0; + + accept_statement (ST_DERIVED_DECL); + push_state (&s, COMP_DERIVED, gfc_new_block); + + gfc_new_block->component_access = ACCESS_PUBLIC; + seen_private = 0; + seen_sequence = 0; + seen_component = 0; + + compiling_type = 1; + + while (compiling_type) + { + st = next_statement (); + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_DATA_DECL: + accept_statement (st); + seen_component = 1; + break; + + case ST_END_TYPE: + compiling_type = 0; + + if (!seen_component) + { + gfc_error ("Derived type definition at %C has no components"); + error_flag = 1; + } + + accept_statement (ST_END_TYPE); + break; + + case ST_PRIVATE: + if (gfc_find_state (COMP_MODULE) == FAILURE) + { + gfc_error + ("PRIVATE statement in TYPE at %C must be inside a MODULE"); + error_flag = 1; + break; + } + + if (seen_component) + { + gfc_error ("PRIVATE statement at %C must precede " + "structure components"); + error_flag = 1; + break; + } + + if (seen_private) + { + gfc_error ("Duplicate PRIVATE statement at %C"); + error_flag = 1; + } + + s.sym->component_access = ACCESS_PRIVATE; + accept_statement (ST_PRIVATE); + seen_private = 1; + break; + + case ST_SEQUENCE: + if (seen_component) + { + gfc_error ("SEQUENCE statement at %C must precede " + "structure components"); + error_flag = 1; + break; + } + + if (gfc_current_block ()->attr.sequence) + gfc_warning ("SEQUENCE attribute at %C already specified in " + "TYPE statement"); + + if (seen_sequence) + { + gfc_error ("Duplicate SEQUENCE statement at %C"); + error_flag = 1; + } + + seen_sequence = 1; + gfc_add_sequence (&gfc_current_block ()->attr, NULL); + break; + + default: + unexpected_statement (st); + break; + } + } + + /* Sanity checks on the structure. If the structure has the + SEQUENCE attribute, then all component structures must also have + SEQUENCE. */ + if (error_flag == 0 && gfc_current_block ()->attr.sequence) + for (c = gfc_current_block ()->components; c; c = c->next) + { + if (c->ts.type == BT_DERIVED && c->ts.derived->attr.sequence == 0) + { + gfc_error + ("Component %s of SEQUENCE type declared at %C does not " + "have the SEQUENCE attribute", c->ts.derived->name); + } + } + + pop_state (); +} + + + +/* Parse an interface. We must be able to deal with the possibility + of recursive interfaces. The parse_spec() subroutine is mutually + recursive with parse_interface(). */ + +static gfc_statement parse_spec (gfc_statement); + +static void +parse_interface (void) +{ + gfc_compile_state new_state, current_state; + gfc_symbol *prog_unit, *sym; + gfc_interface_info save; + gfc_state_data s1, s2; + gfc_statement st; + int seen_body; + + accept_statement (ST_INTERFACE); + + current_interface.ns = gfc_current_ns; + save = current_interface; + + sym = (current_interface.type == INTERFACE_GENERIC + || current_interface.type == INTERFACE_USER_OP) ? gfc_new_block : NULL; + + push_state (&s1, COMP_INTERFACE, sym); + seen_body = 0; + current_state = COMP_NONE; + +loop: + gfc_current_ns = gfc_get_namespace (current_interface.ns); + + st = next_statement (); + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_SUBROUTINE: + new_state = COMP_SUBROUTINE; + gfc_add_explicit_interface (gfc_new_block, IFSRC_IFBODY, + gfc_new_block->formal, NULL); + break; + + case ST_FUNCTION: + new_state = COMP_FUNCTION; + gfc_add_explicit_interface (gfc_new_block, IFSRC_IFBODY, + gfc_new_block->formal, NULL); + break; + + case ST_MODULE_PROC: /* The module procedure matcher makes + sure the context is correct. */ + seen_body = 1; + accept_statement (st); + gfc_free_namespace (gfc_current_ns); + goto loop; + + case ST_END_INTERFACE: + gfc_free_namespace (gfc_current_ns); + gfc_current_ns = current_interface.ns; + goto done; + + default: + gfc_error ("Unexpected %s statement in INTERFACE block at %C", + gfc_ascii_statement (st)); + reject_statement (); + gfc_free_namespace (gfc_current_ns); + goto loop; + } + + + /* Make sure that a generic interface has only subroutines or + functions and that the generic name has the right attribute. */ + if (current_interface.type == INTERFACE_GENERIC) + { + if (current_state == COMP_NONE) + { + if (new_state == COMP_FUNCTION) + gfc_add_function (&sym->attr, NULL); + if (new_state == COMP_SUBROUTINE) + gfc_add_subroutine (&sym->attr, NULL); + + current_state = new_state; + } + else + { + if (new_state != current_state) + { + if (new_state == COMP_SUBROUTINE) + gfc_error + ("SUBROUTINE at %C does not belong in a generic function " + "interface"); + + if (new_state == COMP_FUNCTION) + gfc_error + ("FUNCTION at %C does not belong in a generic subroutine " + "interface"); + } + } + } + + push_state (&s2, new_state, gfc_new_block); + accept_statement (st); + prog_unit = gfc_new_block; + prog_unit->formal_ns = gfc_current_ns; + +decl: + /* Read data declaration statements. */ + st = parse_spec (ST_NONE); + + if (st != ST_END_SUBROUTINE && st != ST_END_FUNCTION) + { + gfc_error ("Unexpected %s statement at %C in INTERFACE body", + gfc_ascii_statement (st)); + reject_statement (); + goto decl; + } + + seen_body = 1; + + current_interface = save; + gfc_add_interface (prog_unit); + + pop_state (); + goto loop; + +done: + if (!seen_body) + gfc_error ("INTERFACE block at %C is empty"); + + pop_state (); +} + + +/* Parse a set of specification statements. Returns the statement + that doesn't fit. */ + +static gfc_statement +parse_spec (gfc_statement st) +{ + st_state ss; + + verify_st_order (&ss, ST_NONE); + if (st == ST_NONE) + st = next_statement (); + +loop: + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_FORMAT: + case ST_ENTRY: + case ST_DATA: /* Not allowed in interfaces */ + if (gfc_current_state () == COMP_INTERFACE) + break; + + /* Fall through */ + + case ST_USE: + case ST_IMPLICIT_NONE: + case ST_IMPLICIT: + case ST_PARAMETER: + case ST_PUBLIC: + case ST_PRIVATE: + case ST_DERIVED_DECL: + case_decl: + if (verify_st_order (&ss, st) == FAILURE) + { + reject_statement (); + st = next_statement (); + goto loop; + } + + switch (st) + { + case ST_INTERFACE: + parse_interface (); + break; + + case ST_DERIVED_DECL: + parse_derived (); + break; + + case ST_PUBLIC: + case ST_PRIVATE: + if (gfc_current_state () != COMP_MODULE) + { + gfc_error ("%s statement must appear in a MODULE", + gfc_ascii_statement (st)); + break; + } + + if (gfc_current_ns->default_access != ACCESS_UNKNOWN) + { + gfc_error ("%s statement at %C follows another accessibility " + "specification", gfc_ascii_statement (st)); + break; + } + + gfc_current_ns->default_access = (st == ST_PUBLIC) + ? ACCESS_PUBLIC : ACCESS_PRIVATE; + + break; + + default: + break; + } + + accept_statement (st); + st = next_statement (); + goto loop; + + default: + break; + } + + return st; +} + + +/* Parse a WHERE block, (not a simple WHERE statement). */ + +static void +parse_where_block (void) +{ + int seen_empty_else; + gfc_code *top, *d; + gfc_state_data s; + gfc_statement st; + + accept_statement (ST_WHERE_BLOCK); + top = gfc_state_stack->tail; + + push_state (&s, COMP_WHERE, gfc_new_block); + + d = add_statement (); + d->expr = top->expr; + d->op = EXEC_WHERE; + + top->expr = NULL; + top->block = d; + + seen_empty_else = 0; + + do + { + st = next_statement (); + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_WHERE_BLOCK: + parse_where_block (); + /* Fall through */ + + case ST_ASSIGNMENT: + case ST_WHERE: + accept_statement (st); + break; + + case ST_ELSEWHERE: + if (seen_empty_else) + { + gfc_error + ("ELSEWHERE statement at %C follows previous unmasked " + "ELSEWHERE"); + break; + } + + if (new_st.expr == NULL) + seen_empty_else = 1; + + d = new_level (gfc_state_stack->head); + d->op = EXEC_WHERE; + d->expr = new_st.expr; + + accept_statement (st); + + break; + + case ST_END_WHERE: + accept_statement (st); + break; + + default: + gfc_error ("Unexpected %s statement in WHERE block at %C", + gfc_ascii_statement (st)); + reject_statement (); + break; + } + + } + while (st != ST_END_WHERE); + + pop_state (); +} + + +/* Parse a FORALL block (not a simple FORALL statement). */ + +static void +parse_forall_block (void) +{ + gfc_code *top, *d; + gfc_state_data s; + gfc_statement st; + + accept_statement (ST_FORALL_BLOCK); + top = gfc_state_stack->tail; + + push_state (&s, COMP_FORALL, gfc_new_block); + + d = add_statement (); + d->op = EXEC_FORALL; + top->block = d; + + do + { + st = next_statement (); + switch (st) + { + + case ST_ASSIGNMENT: + case ST_POINTER_ASSIGNMENT: + case ST_WHERE: + case ST_FORALL: + accept_statement (st); + break; + + case ST_WHERE_BLOCK: + parse_where_block (); + break; + + case ST_FORALL_BLOCK: + parse_forall_block (); + break; + + case ST_END_FORALL: + accept_statement (st); + break; + + case ST_NONE: + unexpected_eof (); + + default: + gfc_error ("Unexpected %s statement in FORALL block at %C", + gfc_ascii_statement (st)); + + reject_statement (); + break; + } + } + while (st != ST_END_FORALL); + + pop_state (); +} + + +static gfc_statement parse_executable (gfc_statement); + +/* parse the statements of an IF-THEN-ELSEIF-ELSE-ENDIF block. */ + +static void +parse_if_block (void) +{ + gfc_code *top, *d; + gfc_statement st; + locus else_locus; + gfc_state_data s; + int seen_else; + + seen_else = 0; + accept_statement (ST_IF_BLOCK); + + top = gfc_state_stack->tail; + push_state (&s, COMP_IF, gfc_new_block); + + new_st.op = EXEC_IF; + d = add_statement (); + + d->expr = top->expr; + top->expr = NULL; + top->block = d; + + do + { + st = parse_executable (ST_NONE); + + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_ELSEIF: + if (seen_else) + { + gfc_error + ("ELSE IF statement at %C cannot follow ELSE statement at %L", + &else_locus); + + reject_statement (); + break; + } + + d = new_level (gfc_state_stack->head); + d->op = EXEC_IF; + d->expr = new_st.expr; + + accept_statement (st); + + break; + + case ST_ELSE: + if (seen_else) + { + gfc_error ("Duplicate ELSE statements at %L and %C", + &else_locus); + reject_statement (); + break; + } + + seen_else = 1; + else_locus = *gfc_current_locus (); + + d = new_level (gfc_state_stack->head); + d->op = EXEC_IF; + + accept_statement (st); + + break; + + case ST_ENDIF: + break; + + default: + unexpected_statement (st); + break; + } + } + while (st != ST_ENDIF); + + pop_state (); + accept_statement (st); +} + + +/* Parse a SELECT block. */ + +static void +parse_select_block (void) +{ + gfc_statement st; + gfc_code *cp; + gfc_state_data s; + + accept_statement (ST_SELECT_CASE); + + cp = gfc_state_stack->tail; + push_state (&s, COMP_SELECT, gfc_new_block); + + /* Make sure that the next statement is a CASE or END SELECT. */ + for (;;) + { + st = next_statement (); + if (st == ST_NONE) + unexpected_eof (); + if (st == ST_END_SELECT) + { + /* Empty SELECT CASE is OK. */ + accept_statement (st); + pop_state (); + return; + } + if (st == ST_CASE) + break; + + gfc_error + ("Expected a CASE or END SELECT statement following SELECT CASE " + "at %C"); + + reject_statement (); + } + + /* At this point, we're got a nonempty select block. */ + cp = new_level (cp); + *cp = new_st; + + accept_statement (st); + + do + { + st = parse_executable (ST_NONE); + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_CASE: + cp = new_level (gfc_state_stack->head); + *cp = new_st; + gfc_clear_new_st (); + + accept_statement (st); + /* Fall through */ + + case ST_END_SELECT: + break; + + /* Can't have an executable statement because of + parse_executable(). */ + default: + unexpected_statement (st); + break; + } + } + while (st != ST_END_SELECT); + + pop_state (); + accept_statement (st); +} + + +/* Checks to see if the current statement label closes an enddo. + Returns 0 if not, 1 if closes an ENDDO correctly, or 2 (and issues + an error) if it incorrectly closes an ENDDO. */ + +static int +check_do_closure (void) +{ + gfc_state_data *p; + + if (gfc_statement_label == NULL) + return 0; + + for (p = gfc_state_stack; p; p = p->previous) + if (p->state == COMP_DO) + break; + + if (p == NULL) + return 0; /* No loops to close */ + + if (p->ext.end_do_label == gfc_statement_label) + { + + if (p == gfc_state_stack) + return 1; + + gfc_error + ("End of nonblock DO statement at %C is within another block"); + return 2; + } + + /* At this point, the label doesn't terminate the innermost loop. + Make sure it doesn't terminate another one. */ + for (; p; p = p->previous) + if (p->state == COMP_DO && p->ext.end_do_label == gfc_statement_label) + { + gfc_error ("End of nonblock DO statement at %C is interwoven " + "with another DO loop"); + return 2; + } + + return 0; +} + + +/* Parse a DO loop. Note that the ST_CYCLE and ST_EXIT statements are + handled inside of parse_executable(), because they aren't really + loop statements. */ + +static void +parse_do_block (void) +{ + gfc_statement st; + gfc_code *top; + gfc_state_data s; + + s.ext.end_do_label = new_st.label; + + accept_statement (ST_DO); + + top = gfc_state_stack->tail; + push_state (&s, COMP_DO, gfc_new_block); + + top->block = new_level (top); + top->block->op = EXEC_DO; + +loop: + st = parse_executable (ST_NONE); + + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_ENDDO: + if (s.ext.end_do_label != NULL + && s.ext.end_do_label != gfc_statement_label) + gfc_error_now + ("Statement label in ENDDO at %C doesn't match DO label"); + /* Fall through */ + + case ST_IMPLIED_ENDDO: + break; + + default: + unexpected_statement (st); + goto loop; + } + + pop_state (); + accept_statement (st); +} + + +/* Accept a series of executable statements. We return the first + statement that doesn't fit to the caller. Any block statements are + passed on to the correct handler, which usually passes the buck + right back here. */ + +static gfc_statement +parse_executable (gfc_statement st) +{ + int close_flag; + + if (st == ST_NONE) + st = next_statement (); + + for (;; st = next_statement ()) + { + + close_flag = check_do_closure (); + if (close_flag) + switch (st) + { + case ST_GOTO: + case ST_END_PROGRAM: + case ST_RETURN: + case ST_EXIT: + case ST_END_FUNCTION: + case ST_CYCLE: + case ST_PAUSE: + case ST_STOP: + case ST_END_SUBROUTINE: + + case ST_DO: + case ST_FORALL: + case ST_WHERE: + case ST_SELECT_CASE: + gfc_error + ("%s statement at %C cannot terminate a non-block DO loop", + gfc_ascii_statement (st)); + break; + + default: + break; + } + + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_FORMAT: + case ST_DATA: + case ST_ENTRY: + case_executable: + accept_statement (st); + if (close_flag == 1) + return ST_IMPLIED_ENDDO; + continue; + + case ST_IF_BLOCK: + parse_if_block (); + continue; + + case ST_SELECT_CASE: + parse_select_block (); + continue; + + case ST_DO: + parse_do_block (); + if (check_do_closure () == 1) + return ST_IMPLIED_ENDDO; + continue; + + case ST_WHERE_BLOCK: + parse_where_block (); + continue; + + case ST_FORALL_BLOCK: + parse_forall_block (); + continue; + + default: + break; + } + + break; + } + + return st; +} + + +/* Parse a series of contained program units. */ + +static void parse_progunit (gfc_statement); + + +/* Fix the symbols for sibling functions. These are incorrectly added to + the child namespace as the parser didn't know about this procedure. */ + +static void +gfc_fixup_sibling_symbols (gfc_symbol * sym, gfc_namespace * siblings) +{ + gfc_namespace *ns; + gfc_symtree *st; + gfc_symbol *old_sym; + + for (ns = siblings; ns; ns = ns->sibling) + { + gfc_find_sym_tree (sym->name, ns, 0, &st); + if (!st) + continue; + + old_sym = st->n.sym; + if (old_sym->attr.flavor == FL_PROCEDURE && old_sym->ns == ns + && ! old_sym->attr.contained) + { + /* Replace it with the symbol from the parent namespace. */ + st->n.sym = sym; + sym->refs++; + + /* Free the old (local) symbol. */ + old_sym->refs--; + if (old_sym->refs == 0) + gfc_free_symbol (old_sym); + } + + /* Do the same for any contined procedures. */ + gfc_fixup_sibling_symbols (sym, ns->contained); + } +} + +static void +parse_contained (int module) +{ + gfc_namespace *ns, *parent_ns; + gfc_state_data s1, s2; + gfc_statement st; + gfc_symbol *sym; + + push_state (&s1, COMP_CONTAINS, NULL); + parent_ns = gfc_current_ns; + + do + { + gfc_current_ns = gfc_get_namespace (parent_ns); + + gfc_current_ns->sibling = parent_ns->contained; + parent_ns->contained = gfc_current_ns; + + st = next_statement (); + + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_FUNCTION: + case ST_SUBROUTINE: + accept_statement (st); + + push_state (&s2, + (st == ST_FUNCTION) ? COMP_FUNCTION : COMP_SUBROUTINE, + gfc_new_block); + + /* For internal procedures, create/update the symbol in the + * parent namespace */ + + if (!module) + { + if (gfc_get_symbol (gfc_new_block->name, parent_ns, &sym)) + gfc_error + ("Contained procedure '%s' at %C is already ambiguous", + gfc_new_block->name); + else + { + if (gfc_add_procedure (&sym->attr, PROC_INTERNAL, + &gfc_new_block->declared_at) == + SUCCESS) + { + if (st == ST_FUNCTION) + gfc_add_function (&sym->attr, + &gfc_new_block->declared_at); + else + gfc_add_subroutine (&sym->attr, + &gfc_new_block->declared_at); + } + } + + gfc_commit_symbols (); + } + else + sym = gfc_new_block; + + /* Mark this as a contained function, so it isn't replaced + by other module functions. */ + sym->attr.contained = 1; + + /* Fix up any sibling functions that refer to this one. */ + gfc_fixup_sibling_symbols (sym, gfc_current_ns); + + parse_progunit (ST_NONE); + + gfc_current_ns->code = s2.head; + gfc_current_ns = parent_ns; + + pop_state (); + break; + + /* These statements are associated with the end of the host + unit. */ + case ST_END_FUNCTION: + case ST_END_MODULE: + case ST_END_PROGRAM: + case ST_END_SUBROUTINE: + accept_statement (st); + break; + + default: + gfc_error ("Unexpected %s statement in CONTAINS section at %C", + gfc_ascii_statement (st)); + reject_statement (); + break; + } + } + while (st != ST_END_FUNCTION && st != ST_END_SUBROUTINE + && st != ST_END_MODULE && st != ST_END_PROGRAM); + + /* The first namespace in the list is guaranteed to not have + anything (worthwhile) in it. */ + + gfc_current_ns = parent_ns; + + ns = gfc_current_ns->contained; + gfc_current_ns->contained = ns->sibling; + gfc_free_namespace (ns); + + pop_state (); +} + + +/* Parse a PROGRAM, SUBROUTINE or FUNCTION unit. */ + +static void +parse_progunit (gfc_statement st) +{ + gfc_state_data *p; + int n; + + st = parse_spec (st); + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_CONTAINS: + goto contains; + + case_end: + accept_statement (st); + goto done; + + default: + break; + } + +loop: + for (;;) + { + st = parse_executable (st); + + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_CONTAINS: + goto contains; + + case_end: + accept_statement (st); + goto done; + + default: + break; + } + + unexpected_statement (st); + reject_statement (); + st = next_statement (); + } + +contains: + n = 0; + + for (p = gfc_state_stack; p; p = p->previous) + if (p->state == COMP_CONTAINS) + n++; + + if (gfc_find_state (COMP_MODULE) == SUCCESS) + n--; + + if (n > 0) + { + gfc_error ("CONTAINS statement at %C is already in a contained " + "program unit"); + st = next_statement (); + goto loop; + } + + parse_contained (0); + +done: + gfc_current_ns->code = gfc_state_stack->head; +} + + +/* Parse a block data program unit. */ + +static void +parse_block_data (void) +{ + gfc_statement st; + + st = parse_spec (ST_NONE); + + while (st != ST_END_BLOCK_DATA) + { + gfc_error ("Unexpected %s statement in BLOCK DATA at %C", + gfc_ascii_statement (st)); + reject_statement (); + st = next_statement (); + } +} + + +/* Parse a module subprogram. */ + +static void +parse_module (void) +{ + gfc_statement st; + + st = parse_spec (ST_NONE); + +loop: + switch (st) + { + case ST_NONE: + unexpected_eof (); + + case ST_CONTAINS: + parse_contained (1); + break; + + case ST_END_MODULE: + accept_statement (st); + break; + + default: + gfc_error ("Unexpected %s statement in MODULE at %C", + gfc_ascii_statement (st)); + + reject_statement (); + st = next_statement (); + goto loop; + } +} + + +/* Top level parser. */ + +try +gfc_parse_file (void) +{ + int seen_program, errors_before, errors; + gfc_state_data top, s; + gfc_statement st; + locus prog_locus; + + top.state = COMP_NONE; + top.sym = NULL; + top.previous = NULL; + top.head = top.tail = NULL; + + gfc_state_stack = ⊤ + + gfc_clear_new_st (); + + gfc_statement_label = NULL; + + if (setjmp (eof)) + return FAILURE; /* Come here on unexpected EOF */ + + seen_program = 0; + +loop: + gfc_init_2 (); + st = next_statement (); + switch (st) + { + case ST_NONE: + gfc_done_2 (); + goto done; + + case ST_PROGRAM: + if (seen_program) + goto duplicate_main; + seen_program = 1; + prog_locus = *gfc_current_locus (); + + push_state (&s, COMP_PROGRAM, gfc_new_block); + accept_statement (st); + parse_progunit (ST_NONE); + break; + + case ST_SUBROUTINE: + push_state (&s, COMP_SUBROUTINE, gfc_new_block); + accept_statement (st); + parse_progunit (ST_NONE); + break; + + case ST_FUNCTION: + push_state (&s, COMP_FUNCTION, gfc_new_block); + accept_statement (st); + parse_progunit (ST_NONE); + break; + + case ST_BLOCK_DATA: + push_state (&s, COMP_BLOCK_DATA, gfc_new_block); + accept_statement (st); + parse_block_data (); + break; + + case ST_MODULE: + push_state (&s, COMP_MODULE, gfc_new_block); + accept_statement (st); + + gfc_get_errors (NULL, &errors_before); + parse_module (); + break; + + /* Anything else starts a nameless main program block. */ + default: + if (seen_program) + goto duplicate_main; + seen_program = 1; + prog_locus = *gfc_current_locus (); + + push_state (&s, COMP_PROGRAM, gfc_new_block); + parse_progunit (st); + break; + } + + gfc_current_ns->code = s.head; + + gfc_resolve (gfc_current_ns); + + /* Dump the parse tree if requested. */ + if (gfc_option.verbose) + gfc_show_namespace (gfc_current_ns); + + gfc_get_errors (NULL, &errors); + if (s.state == COMP_MODULE) + { + gfc_dump_module (s.sym->name, errors_before == errors); + if (errors == 0 && ! gfc_option.flag_no_backend) + gfc_generate_module_code (gfc_current_ns); + } + else + { + if (errors == 0 && ! gfc_option.flag_no_backend) + gfc_generate_code (gfc_current_ns); + } + + pop_state (); + gfc_done_2 (); + goto loop; + +done: + return SUCCESS; + +duplicate_main: + /* If we see a duplicate main program, shut down. If the second + instance is an implied main program, ie data decls or executable + statements, we're in for lots of errors. */ + gfc_error ("Two main PROGRAMs at %L and %C", &prog_locus); + reject_statement (); + gfc_done_2 (); + return SUCCESS; +} diff --git a/gcc/fortran/parse.h b/gcc/fortran/parse.h new file mode 100644 index 00000000000..7598441d736 --- /dev/null +++ b/gcc/fortran/parse.h @@ -0,0 +1,65 @@ +/* Parser header + Copyright (C) 2003 Free Software Foundaton, Inc. + Contributed by Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef GFC_PARSE_H +#define GFC_PARSE_H + +#include "gfortran.h" + +/* Enum for what the compiler is currently doing. */ +typedef enum +{ + COMP_NONE, COMP_PROGRAM, COMP_MODULE, COMP_SUBROUTINE, COMP_FUNCTION, + COMP_BLOCK_DATA, COMP_INTERFACE, COMP_DERIVED, COMP_IF, COMP_DO, + COMP_SELECT, COMP_FORALL, COMP_WHERE, COMP_CONTAINS +} +gfc_compile_state; + +/* Stack element for the current compilation state. These structures + are allocated as automatic variables. */ +typedef struct gfc_state_data +{ + gfc_compile_state state; + gfc_symbol *sym; /* Block name associated with this level */ + struct gfc_code *head, *tail; + struct gfc_state_data *previous; + + /* Block-specific state data. */ + union + { + gfc_st_label *end_do_label; + } + ext; +} +gfc_state_data; + +extern gfc_state_data *gfc_state_stack; + +#define gfc_current_block() (gfc_state_stack->sym) +#define gfc_current_state() (gfc_state_stack->state) + +try gfc_find_state (gfc_compile_state); +gfc_state_data *gfc_enclosing_unit (gfc_compile_state *); +const char *gfc_ascii_statement (gfc_statement); +const char *gfc_state_name (gfc_compile_state); + +#endif /* GFC_PARSE_H */ diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c new file mode 100644 index 00000000000..03e975776ea --- /dev/null +++ b/gcc/fortran/primary.c @@ -0,0 +1,2214 @@ +/* Primary expression subroutines + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include "system.h" +#include "flags.h" + +#include +#include +#include "gfortran.h" +#include "arith.h" +#include "match.h" +#include "parse.h" + +/* Matches a kind-parameter expression, which is either a named + symbolic constant or a nonnegative integer constant. If + successful, sets the kind value to the correct integer. */ + +static match +match_kind_param (int *kind) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + const char *p; + match m; + + m = gfc_match_small_literal_int (kind); + if (m != MATCH_NO) + return m; + + m = gfc_match_name (name); + if (m != MATCH_YES) + return m; + + if (gfc_find_symbol (name, NULL, 1, &sym)) + return MATCH_ERROR; + + if (sym == NULL) + return MATCH_NO; + + if (sym->attr.flavor != FL_PARAMETER) + return MATCH_NO; + + p = gfc_extract_int (sym->value, kind); + if (p != NULL) + return MATCH_NO; + + if (*kind < 0) + return MATCH_NO; + + return MATCH_YES; +} + + +/* Get a trailing kind-specification for non-character variables. + Returns: + the integer kind value or: + -1 if an error was generated + -2 if no kind was found */ + +static int +get_kind (void) +{ + int kind; + match m; + + if (gfc_match_char ('_') != MATCH_YES) + return -2; + + m = match_kind_param (&kind); + if (m == MATCH_NO) + gfc_error ("Missing kind-parameter at %C"); + + return (m == MATCH_YES) ? kind : -1; +} + + +/* Given a character and a radix, see if the character is a valid + digit in that radix. */ + +static int +check_digit (int c, int radix) +{ + int r; + + switch (radix) + { + case 2: + r = ('0' <= c && c <= '1'); + break; + + case 8: + r = ('0' <= c && c <= '7'); + break; + + case 10: + r = ('0' <= c && c <= '9'); + break; + + case 16: + r = ('0' <= c && c <= '9') || ('a' <= c && c <= 'f'); + break; + + default: + gfc_internal_error ("check_digit(): bad radix"); + } + + return r; +} + + +/* Match the digit string part of an integer if signflag is not set, + the signed digit string part if signflag is set. If the buffer + is NULL, we just count characters for the resolution pass. Returns + the number of characters matched, -1 for no match. */ + +static int +match_digits (int signflag, int radix, char *buffer) +{ + locus old_loc; + int length, c; + + length = 0; + c = gfc_next_char (); + + if (signflag && (c == '+' || c == '-')) + { + if (buffer != NULL) + *buffer++ = c; + c = gfc_next_char (); + length++; + } + + if (!check_digit (c, radix)) + return -1; + + length++; + if (buffer != NULL) + *buffer++ = c; + + for (;;) + { + old_loc = *gfc_current_locus (); + c = gfc_next_char (); + + if (!check_digit (c, radix)) + break; + + if (buffer != NULL) + *buffer++ = c; + length++; + } + + gfc_set_locus (&old_loc); + + return length; +} + + +/* Match an integer (digit string and optional kind). + A sign will be accepted if signflag is set. */ + +static match +match_integer_constant (gfc_expr ** result, int signflag) +{ + int length, kind; + locus old_loc; + char *buffer; + gfc_expr *e; + + old_loc = *gfc_current_locus (); + gfc_gobble_whitespace (); + + length = match_digits (signflag, 10, NULL); + gfc_set_locus (&old_loc); + if (length == -1) + return MATCH_NO; + + buffer = alloca (length + 1); + memset (buffer, '\0', length + 1); + + gfc_gobble_whitespace (); + + match_digits (signflag, 10, buffer); + + kind = get_kind (); + if (kind == -2) + kind = gfc_default_integer_kind (); + if (kind == -1) + return MATCH_ERROR; + + if (gfc_validate_kind (BT_INTEGER, kind) == -1) + { + gfc_error ("Integer kind %d at %C not available", kind); + return MATCH_ERROR; + } + + e = gfc_convert_integer (buffer, kind, 10, gfc_current_locus ()); + + if (gfc_range_check (e) != ARITH_OK) + { + gfc_error ("Integer too big for its kind at %C"); + + gfc_free_expr (e); + return MATCH_ERROR; + } + + *result = e; + return MATCH_YES; +} + + +/* Match a binary, octal or hexadecimal constant that can be found in + a DATA statement. */ + +static match +match_boz_constant (gfc_expr ** result) +{ + int radix, delim, length; + locus old_loc; + char *buffer; + gfc_expr *e; + const char *rname; + + old_loc = *gfc_current_locus (); + gfc_gobble_whitespace (); + + switch (gfc_next_char ()) + { + case 'b': + radix = 2; + rname = "binary"; + break; + case 'o': + radix = 8; + rname = "octal"; + break; + case 'x': + if (pedantic) + gfc_warning_now ("Hexadecimal constant at %C uses non-standard " + "syntax. Use \"Z\" instead."); + /* Fall through. */ + case 'z': + radix = 16; + rname = "hexadecimal"; + break; + default: + goto backup; + } + + /* No whitespace allowed here. */ + + delim = gfc_next_char (); + if (delim != '\'' && delim != '\"') + goto backup; + + old_loc = *gfc_current_locus (); + + length = match_digits (0, radix, NULL); + if (length == -1) + { + gfc_error ("Empty set of digits in %s constants at %C", rname); + return MATCH_ERROR; + } + + if (gfc_next_char () != delim) + { + gfc_error ("Illegal character in %s constant at %C.", rname); + return MATCH_ERROR; + } + + gfc_set_locus (&old_loc); + + buffer = alloca (length + 1); + memset (buffer, '\0', length + 1); + + match_digits (0, radix, buffer); + gfc_next_char (); + + e = gfc_convert_integer (buffer, gfc_default_integer_kind (), radix, + gfc_current_locus ()); + + if (gfc_range_check (e) != ARITH_OK) + { + gfc_error ("Integer too big for default integer kind at %C"); + + gfc_free_expr (e); + return MATCH_ERROR; + } + + *result = e; + return MATCH_YES; + +backup: + gfc_set_locus (&old_loc); + return MATCH_NO; +} + + +/* Match a real constant of some sort. */ + +static match +match_real_constant (gfc_expr ** result, int signflag) +{ + int kind, c, count, seen_dp, seen_digits, exp_char; + locus old_loc, temp_loc; + char *p, *buffer; + gfc_expr *e; + + old_loc = *gfc_current_locus (); + gfc_gobble_whitespace (); + + e = NULL; + + count = 0; + seen_dp = 0; + seen_digits = 0; + exp_char = ' '; + + c = gfc_next_char (); + if (signflag && (c == '+' || c == '-')) + { + c = gfc_next_char (); + count++; + } + + /* Scan significand. */ + for (;; c = gfc_next_char (), count++) + { + if (c == '.') + { + if (seen_dp) + goto done; + + /* Check to see if "." goes with a following operator like ".eq.". */ + temp_loc = *gfc_current_locus (); + c = gfc_next_char (); + + if (c == 'e' || c == 'd' || c == 'q') + { + c = gfc_next_char (); + if (c == '.') + goto done; /* Operator named .e. or .d. */ + } + + if (ISALPHA (c)) + goto done; /* Distinguish 1.e9 from 1.eq.2 */ + + gfc_set_locus (&temp_loc); + seen_dp = 1; + continue; + } + + if (ISDIGIT (c)) + { + seen_digits = 1; + continue; + } + + break; + } + + if (!seen_digits || (c != 'e' && c != 'd' && c != 'q')) + goto done; + exp_char = c; + + /* Scan exponent. */ + c = gfc_next_char (); + count++; + + if (c == '+' || c == '-') + { /* optional sign */ + c = gfc_next_char (); + count++; + } + + if (!ISDIGIT (c)) + { + /* TODO: seen_digits is always true at this point */ + if (!seen_digits) + { + gfc_set_locus (&old_loc); + return MATCH_NO; /* ".e" can be something else */ + } + + gfc_error ("Missing exponent in real number at %C"); + return MATCH_ERROR; + } + + while (ISDIGIT (c)) + { + c = gfc_next_char (); + count++; + } + +done: + /* See what we've got! */ + if (!seen_digits || (!seen_dp && exp_char == ' ')) + { + gfc_set_locus (&old_loc); + return MATCH_NO; + } + + /* Convert the number. */ + gfc_set_locus (&old_loc); + gfc_gobble_whitespace (); + + buffer = alloca (count + 1); + memset (buffer, '\0', count + 1); + + /* Hack for mpf_init_set_str(). */ + p = buffer; + while (count > 0) + { + *p = gfc_next_char (); + if (*p == 'd' || *p == 'q') + *p = 'e'; + p++; + count--; + } + + kind = get_kind (); + if (kind == -1) + goto cleanup; + + switch (exp_char) + { + case 'd': + if (kind != -2) + { + gfc_error + ("Real number at %C has a 'd' exponent and an explicit kind"); + goto cleanup; + } + kind = gfc_default_double_kind (); + break; + + case 'q': + if (kind != -2) + { + gfc_error + ("Real number at %C has a 'q' exponent and an explicit kind"); + goto cleanup; + } + kind = gfc_option.q_kind; + break; + + default: + if (kind == -2) + kind = gfc_default_real_kind (); + + if (gfc_validate_kind (BT_REAL, kind) == -1) + { + gfc_error ("Invalid real kind %d at %C", kind); + goto cleanup; + } + } + + e = gfc_convert_real (buffer, kind, gfc_current_locus ()); + + switch (gfc_range_check (e)) + { + case ARITH_OK: + break; + case ARITH_OVERFLOW: + gfc_error ("Real constant overflows its kind at %C"); + goto cleanup; + + case ARITH_UNDERFLOW: + gfc_error ("Real constant underflows its kind at %C"); + goto cleanup; + + default: + gfc_internal_error ("gfc_range_check() returned bad value"); + } + + *result = e; + return MATCH_YES; + +cleanup: + gfc_free_expr (e); + return MATCH_ERROR; +} + + +/* Match a substring reference. */ + +static match +match_substring (gfc_charlen * cl, int init, gfc_ref ** result) +{ + gfc_expr *start, *end; + locus old_loc; + gfc_ref *ref; + match m; + + start = NULL; + end = NULL; + + old_loc = *gfc_current_locus (); + + m = gfc_match_char ('('); + if (m != MATCH_YES) + return MATCH_NO; + + if (gfc_match_char (':') != MATCH_YES) + { + if (init) + m = gfc_match_init_expr (&start); + else + m = gfc_match_expr (&start); + + if (m != MATCH_YES) + { + m = MATCH_NO; + goto cleanup; + } + + m = gfc_match_char (':'); + if (m != MATCH_YES) + goto cleanup; + } + + if (gfc_match_char (')') != MATCH_YES) + { + if (init) + m = gfc_match_init_expr (&end); + else + m = gfc_match_expr (&end); + + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + m = gfc_match_char (')'); + if (m == MATCH_NO) + goto syntax; + } + + /* Optimize away the (:) reference. */ + if (start == NULL && end == NULL) + ref = NULL; + else + { + ref = gfc_get_ref (); + + ref->type = REF_SUBSTRING; + if (start == NULL) + start = gfc_int_expr (1); + ref->u.ss.start = start; + if (end == NULL && cl) + end = gfc_copy_expr (cl->length); + ref->u.ss.end = end; + ref->u.ss.length = cl; + } + + *result = ref; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in SUBSTRING specification at %C"); + m = MATCH_ERROR; + +cleanup: + gfc_free_expr (start); + gfc_free_expr (end); + + gfc_set_locus (&old_loc); + return m; +} + + +/* Reads the next character of a string constant, taking care to + return doubled delimiters on the input as a single instance of + the delimiter. + + Special return values are: + -1 End of the string, as determined by the delimiter + -2 Unterminated string detected + + Backslash codes are also expanded at this time. */ + +static int +next_string_char (char delimiter) +{ + locus old_locus; + int c; + + c = gfc_next_char_literal (1); + + if (c == '\n') + return -2; + + if (c == '\\') + { + old_locus = *gfc_current_locus (); + + switch (gfc_next_char_literal (1)) + { + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 't': + c = '\t'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 'v': + c = '\v'; + break; + case '\\': + c = '\\'; + break; + + default: + /* Unknown backslash codes are simply not expanded */ + gfc_set_locus (&old_locus); + break; + } + } + + if (c != delimiter) + return c; + + old_locus = *gfc_current_locus (); + c = gfc_next_char_literal (1); + + if (c == delimiter) + return c; + gfc_set_locus (&old_locus); + + return -1; +} + + +/* Special case of gfc_match_name() that matches a parameter kind name + before a string constant. This takes case of the weird but legal + case of: weird case of: + + kind_____'string' + + where kind____ is a parameter. gfc_match_name() will happily slurp + up all the underscores, which leads to problems. If we return + MATCH_YES, the parse pointer points to the final underscore, which + is not part of the name. We never return MATCH_ERROR-- errors in + the name will be detected later. */ + +static match +match_charkind_name (char *name) +{ + locus old_loc; + char c, peek; + int len; + + gfc_gobble_whitespace (); + c = gfc_next_char (); + if (!ISALPHA (c)) + return MATCH_NO; + + *name++ = c; + len = 1; + + for (;;) + { + old_loc = *gfc_current_locus (); + c = gfc_next_char (); + + if (c == '_') + { + peek = gfc_peek_char (); + + if (peek == '\'' || peek == '\"') + { + gfc_set_locus (&old_loc); + *name = '\0'; + return MATCH_YES; + } + } + + if (!ISALNUM (c) + && c != '_' + && (gfc_option.flag_dollar_ok && c != '$')) + break; + + *name++ = c; + if (++len > GFC_MAX_SYMBOL_LEN) + break; + } + + return MATCH_NO; +} + + +/* See if the current input matches a character constant. Lots of + contortions have to be done to match the kind parameter which comes + before the actual string. The main consideration is that we don't + want to error out too quickly. For example, we don't actually do + any validation of the kinds until we have actually seen a legal + delimiter. Using match_kind_param() generates errors too quickly. */ + +static match +match_string_constant (gfc_expr ** result) +{ + char *p, name[GFC_MAX_SYMBOL_LEN + 1]; + int i, c, kind, length, delimiter; + locus old_locus, start_locus; + gfc_symbol *sym; + gfc_expr *e; + const char *q; + match m; + + old_locus = *gfc_current_locus (); + + gfc_gobble_whitespace (); + + start_locus = *gfc_current_locus (); + + c = gfc_next_char (); + if (c == '\'' || c == '"') + { + kind = gfc_default_character_kind (); + goto got_delim; + } + + if (ISDIGIT (c)) + { + kind = 0; + + while (ISDIGIT (c)) + { + kind = kind * 10 + c - '0'; + if (kind > 9999999) + goto no_match; + c = gfc_next_char (); + } + + } + else + { + gfc_set_locus (&old_locus); + + m = match_charkind_name (name); + if (m != MATCH_YES) + goto no_match; + + if (gfc_find_symbol (name, NULL, 1, &sym) + || sym == NULL + || sym->attr.flavor != FL_PARAMETER) + goto no_match; + + kind = -1; + c = gfc_next_char (); + } + + if (c == ' ') + { + gfc_gobble_whitespace (); + c = gfc_next_char (); + } + + if (c != '_') + goto no_match; + + gfc_gobble_whitespace (); + start_locus = *gfc_current_locus (); + + c = gfc_next_char (); + if (c != '\'' && c != '"') + goto no_match; + + if (kind == -1) + { + q = gfc_extract_int (sym->value, &kind); + if (q != NULL) + { + gfc_error (q); + return MATCH_ERROR; + } + } + + if (gfc_validate_kind (BT_CHARACTER, kind) == -1) + { + gfc_error ("Invalid kind %d for CHARACTER constant at %C", kind); + return MATCH_ERROR; + } + +got_delim: + /* Scan the string into a block of memory by first figuring out how + long it is, allocating the structure, then re-reading it. This + isn't particularly efficient, but string constants aren't that + common in most code. TODO: Use obstacks? */ + + delimiter = c; + length = 0; + + for (;;) + { + c = next_string_char (delimiter); + if (c == -1) + break; + if (c == -2) + { + gfc_set_locus (&start_locus); + gfc_error ("Unterminated character constant beginning at %C"); + return MATCH_ERROR; + } + + length++; + } + + e = gfc_get_expr (); + + e->expr_type = EXPR_CONSTANT; + e->ref = NULL; + e->ts.type = BT_CHARACTER; + e->ts.kind = kind; + e->where = start_locus; + + e->value.character.string = p = gfc_getmem (length + 1); + e->value.character.length = length; + + gfc_set_locus (&start_locus); + gfc_next_char (); /* Skip delimiter */ + + for (i = 0; i < length; i++) + *p++ = next_string_char (delimiter); + + *p = '\0'; /* TODO: C-style string is for development/debug purposes. */ + + if (next_string_char (delimiter) != -1) + gfc_internal_error ("match_string_constant(): Delimiter not found"); + + if (match_substring (NULL, 0, &e->ref) != MATCH_NO) + e->expr_type = EXPR_SUBSTRING; + + *result = e; + + return MATCH_YES; + +no_match: + gfc_set_locus (&old_locus); + return MATCH_NO; +} + + +/* Match a .true. or .false. */ + +static match +match_logical_constant (gfc_expr ** result) +{ + static mstring logical_ops[] = { + minit (".false.", 0), + minit (".true.", 1), + minit (NULL, -1) + }; + + gfc_expr *e; + int i, kind; + + i = gfc_match_strings (logical_ops); + if (i == -1) + return MATCH_NO; + + kind = get_kind (); + if (kind == -1) + return MATCH_ERROR; + if (kind == -2) + kind = gfc_default_logical_kind (); + + if (gfc_validate_kind (BT_LOGICAL, kind) == -1) + gfc_error ("Bad kind for logical constant at %C"); + + e = gfc_get_expr (); + + e->expr_type = EXPR_CONSTANT; + e->value.logical = i; + e->ts.type = BT_LOGICAL; + e->ts.kind = kind; + e->where = *gfc_current_locus (); + + *result = e; + return MATCH_YES; +} + + +/* Match a real or imaginary part of a complex constant that is a + symbolic constant. */ + +static match +match_sym_complex_part (gfc_expr ** result) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symbol *sym; + gfc_expr *e; + match m; + + m = gfc_match_name (name); + if (m != MATCH_YES) + return m; + + if (gfc_find_symbol (name, NULL, 1, &sym) || sym == NULL) + return MATCH_NO; + + if (sym->attr.flavor != FL_PARAMETER) + { + gfc_error ("Expected PARAMETER symbol in complex constant at %C"); + return MATCH_ERROR; + } + + if (!gfc_numeric_ts (&sym->value->ts)) + { + gfc_error ("Numeric PARAMETER required in complex constant at %C"); + return MATCH_ERROR; + } + + if (sym->value->rank != 0) + { + gfc_error ("Scalar PARAMETER required in complex constant at %C"); + return MATCH_ERROR; + } + + switch (sym->value->ts.type) + { + case BT_REAL: + e = gfc_copy_expr (sym->value); + break; + + case BT_COMPLEX: + e = gfc_complex2real (sym->value, sym->value->ts.kind); + if (e == NULL) + goto error; + break; + + case BT_INTEGER: + e = gfc_int2real (sym->value, gfc_default_real_kind ()); + if (e == NULL) + goto error; + break; + + default: + gfc_internal_error ("gfc_match_sym_complex_part(): Bad type"); + } + + *result = e; /* e is a scalar, real, constant expression */ + return MATCH_YES; + +error: + gfc_error ("Error converting PARAMETER constant in complex constant at %C"); + return MATCH_ERROR; +} + + +/* Match the real and imaginary parts of a complex number. This + subroutine is essentially match_real_constant() modified in a + couple of ways: A sign is always allowed and numbers that would + look like an integer to match_real_constant() are automatically + created as floating point numbers. The messiness involved with + making sure a decimal point belongs to the number and not a + trailing operator is not necessary here either (Hooray!). */ + +static match +match_const_complex_part (gfc_expr ** result) +{ + int kind, seen_digits, seen_dp, count; + char *p, c, exp_char, *buffer; + locus old_loc; + + old_loc = *gfc_current_locus (); + gfc_gobble_whitespace (); + + seen_dp = 0; + seen_digits = 0; + count = 0; + exp_char = ' '; + + c = gfc_next_char (); + if (c == '-' || c == '+') + { + c = gfc_next_char (); + count++; + } + + for (;; c = gfc_next_char (), count++) + { + if (c == '.') + { + if (seen_dp) + goto no_match; + seen_dp = 1; + continue; + } + + if (ISDIGIT (c)) + { + seen_digits = 1; + continue; + } + + break; + } + + if (!seen_digits || (c != 'd' && c != 'e')) + goto done; + exp_char = c; + + /* Scan exponent. */ + c = gfc_next_char (); + count++; + + if (c == '+' || c == '-') + { /* optional sign */ + c = gfc_next_char (); + count++; + } + + if (!ISDIGIT (c)) + { + gfc_error ("Missing exponent in real number at %C"); + return MATCH_ERROR; + } + + while (ISDIGIT (c)) + { + c = gfc_next_char (); + count++; + } + +done: + if (!seen_digits) + goto no_match; + + /* Convert the number. */ + gfc_set_locus (&old_loc); + gfc_gobble_whitespace (); + + buffer = alloca (count + 1); + memset (buffer, '\0', count + 1); + + /* Hack for mpf_init_set_str(). */ + p = buffer; + while (count > 0) + { + c = gfc_next_char (); + if (c == 'd') + c = 'e'; + *p++ = c; + count--; + } + + *p = '\0'; + + kind = get_kind (); + if (kind == -1) + return MATCH_ERROR; + + /* If the number looked like an integer, forget about a kind we may + have seen, otherwise validate the kind against real kinds. */ + if (seen_dp == 0 && exp_char == ' ') + { + if (kind == -2) + kind = gfc_default_integer_kind (); + + } + else + { + if (exp_char == 'd') + { + if (kind != -2) + { + gfc_error + ("Real number at %C has a 'd' exponent and an explicit kind"); + return MATCH_ERROR; + } + kind = gfc_default_double_kind (); + + } + else + { + if (kind == -2) + kind = gfc_default_real_kind (); + } + + if (gfc_validate_kind (BT_REAL, kind) == -1) + { + gfc_error ("Invalid real kind %d at %C", kind); + return MATCH_ERROR; + } + } + + *result = gfc_convert_real (buffer, kind, gfc_current_locus ()); + return MATCH_YES; + +no_match: + gfc_set_locus (&old_loc); + return MATCH_NO; +} + + +/* Match a real or imaginary part of a complex number. */ + +static match +match_complex_part (gfc_expr ** result) +{ + match m; + + m = match_sym_complex_part (result); + if (m != MATCH_NO) + return m; + + return match_const_complex_part (result); +} + + +/* Try to match a complex constant. */ + +static match +match_complex_constant (gfc_expr ** result) +{ + gfc_expr *e, *real, *imag; + gfc_error_buf old_error; + gfc_typespec target; + locus old_loc; + int kind; + match m; + + old_loc = *gfc_current_locus (); + real = imag = e = NULL; + + m = gfc_match_char ('('); + if (m != MATCH_YES) + return m; + + gfc_push_error (&old_error); + + m = match_complex_part (&real); + if (m == MATCH_NO) + goto cleanup; + + if (gfc_match_char (',') == MATCH_NO) + { + gfc_pop_error (&old_error); + m = MATCH_NO; + goto cleanup; + } + + /* If m is error, then something was wrong with the real part and we + assume we have a complex constant because we've seen the ','. An + ambiguous case here is the start of an iterator list of some + sort. These sort of lists are matched prior to coming here. */ + + if (m == MATCH_ERROR) + goto cleanup; + gfc_pop_error (&old_error); + + m = match_complex_part (&imag); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + m = gfc_match_char (')'); + if (m == MATCH_NO) + goto syntax; + + if (m == MATCH_ERROR) + goto cleanup; + + /* Decide on the kind of this complex number. */ + kind = gfc_kind_max (real, imag); + target.type = BT_REAL; + target.kind = kind; + + if (kind != real->ts.kind) + gfc_convert_type (real, &target, 2); + if (kind != imag->ts.kind) + gfc_convert_type (imag, &target, 2); + + e = gfc_convert_complex (real, imag, kind); + e->where = *gfc_current_locus (); + + gfc_free_expr (real); + gfc_free_expr (imag); + + *result = e; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in COMPLEX constant at %C"); + m = MATCH_ERROR; + +cleanup: + gfc_free_expr (e); + gfc_free_expr (real); + gfc_free_expr (imag); + gfc_set_locus (&old_loc); + + return m; +} + + +/* Match constants in any of several forms. Returns nonzero for a + match, zero for no match. */ + +match +gfc_match_literal_constant (gfc_expr ** result, int signflag) +{ + match m; + + m = match_complex_constant (result); + if (m != MATCH_NO) + return m; + + m = match_string_constant (result); + if (m != MATCH_NO) + return m; + + m = match_boz_constant (result); + if (m != MATCH_NO) + return m; + + m = match_real_constant (result, signflag); + if (m != MATCH_NO) + return m; + + m = match_integer_constant (result, signflag); + if (m != MATCH_NO) + return m; + + m = match_logical_constant (result); + if (m != MATCH_NO) + return m; + + return MATCH_NO; +} + + +/* Match a single actual argument value. An actual argument is + usually an expression, but can also be a procedure name. If the + argument is a single name, it is not always possible to tell + whether the name is a dummy procedure or not. We treat these cases + by creating an argument that looks like a dummy procedure and + fixing things later during resolution. */ + +static match +match_actual_arg (gfc_expr ** result) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_symtree *symtree; + locus where, w; + gfc_expr *e; + int c; + + where = *gfc_current_locus (); + + switch (gfc_match_name (name)) + { + case MATCH_ERROR: + return MATCH_ERROR; + + case MATCH_NO: + break; + + case MATCH_YES: + w = *gfc_current_locus (); + gfc_gobble_whitespace (); + c = gfc_next_char (); + gfc_set_locus (&w); + + if (c != ',' && c != ')') + break; + + if (gfc_find_sym_tree (name, NULL, 1, &symtree)) + break; + /* Handle error elsewhere. */ + + /* Eliminate a couple of common cases where we know we don't + have a function argument. */ + if (symtree == NULL) + { + gfc_get_sym_tree (name, NULL, &symtree); + gfc_set_sym_referenced (symtree->n.sym); + } + else + { + gfc_symbol *sym; + + sym = symtree->n.sym; + gfc_set_sym_referenced (sym); + if (sym->attr.flavor != FL_PROCEDURE + && sym->attr.flavor != FL_UNKNOWN) + break; + + /* If the symbol is a function with itself as the result and + is being defined, then we have a variable. */ + if (sym->result == sym + && (gfc_current_ns->proc_name == sym + || (gfc_current_ns->parent != NULL + && gfc_current_ns->parent->proc_name == sym))) + break; + } + + e = gfc_get_expr (); /* Leave it unknown for now */ + e->symtree = symtree; + e->expr_type = EXPR_VARIABLE; + e->ts.type = BT_PROCEDURE; + e->where = where; + + *result = e; + return MATCH_YES; + } + + gfc_set_locus (&where); + return gfc_match_expr (result); +} + + +/* Match a keyword argument. */ + +static match +match_keyword_arg (gfc_actual_arglist * actual, gfc_actual_arglist * base) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_actual_arglist *a; + locus name_locus; + match m; + + name_locus = *gfc_current_locus (); + m = gfc_match_name (name); + + if (m != MATCH_YES) + goto cleanup; + if (gfc_match_char ('=') != MATCH_YES) + { + m = MATCH_NO; + goto cleanup; + } + + m = match_actual_arg (&actual->expr); + if (m != MATCH_YES) + goto cleanup; + + /* Make sure this name has not appeared yet. */ + + if (name[0] != '\0') + { + for (a = base; a; a = a->next) + if (strcmp (a->name, name) == 0) + { + gfc_error + ("Keyword '%s' at %C has already appeared in the current " + "argument list", name); + return MATCH_ERROR; + } + } + + strcpy (actual->name, name); + return MATCH_YES; + +cleanup: + gfc_set_locus (&name_locus); + return m; +} + + +/* Matches an actual argument list of a function or subroutine, from + the opening parenthesis to the closing parenthesis. The argument + list is assumed to allow keyword arguments because we don't know if + the symbol associated with the procedure has an implicit interface + or not. We make sure keywords are unique. */ + +match +gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp) +{ + gfc_actual_arglist *head, *tail; + int seen_keyword; + gfc_st_label *label; + locus old_loc; + match m; + + *argp = tail = NULL; + old_loc = *gfc_current_locus (); + + seen_keyword = 0; + + if (gfc_match_char ('(') == MATCH_NO) + return (sub_flag) ? MATCH_YES : MATCH_NO; + + if (gfc_match_char (')') == MATCH_YES) + return MATCH_YES; + head = NULL; + + for (;;) + { + if (head == NULL) + head = tail = gfc_get_actual_arglist (); + else + { + tail->next = gfc_get_actual_arglist (); + tail = tail->next; + } + + if (sub_flag && gfc_match_char ('*') == MATCH_YES) + { + m = gfc_match_st_label (&label, 0); + if (m == MATCH_NO) + gfc_error ("Expected alternate return label at %C"); + if (m != MATCH_YES) + goto cleanup; + + tail->label = label; + goto next; + } + + /* After the first keyword argument is seen, the following + arguments must also have keywords. */ + if (seen_keyword) + { + m = match_keyword_arg (tail, head); + + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + { + gfc_error + ("Missing keyword name in actual argument list at %C"); + goto cleanup; + } + + } + else + { + /* See if we have the first keyword argument. */ + m = match_keyword_arg (tail, head); + if (m == MATCH_YES) + seen_keyword = 1; + if (m == MATCH_ERROR) + goto cleanup; + + if (m == MATCH_NO) + { + /* Try for a non-keyword argument. */ + m = match_actual_arg (&tail->expr); + if (m == MATCH_ERROR) + goto cleanup; + if (m == MATCH_NO) + goto syntax; + } + } + + next: + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + *argp = head; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in argument list at %C"); + +cleanup: + gfc_free_actual_arglist (head); + gfc_set_locus (&old_loc); + + return MATCH_ERROR; +} + + +/* Used by match_varspec() to extend the reference list by one + element. */ + +static gfc_ref * +extend_ref (gfc_expr * primary, gfc_ref * tail) +{ + + if (primary->ref == NULL) + primary->ref = tail = gfc_get_ref (); + else + { + if (tail == NULL) + gfc_internal_error ("extend_ref(): Bad tail"); + tail->next = gfc_get_ref (); + tail = tail->next; + } + + return tail; +} + + +/* Match any additional specifications associated with the current + variable like member references or substrings. If equiv_flag is + set we only match stuff that is allowed inside an EQUIVALENCE + statement. */ + +static match +match_varspec (gfc_expr * primary, int equiv_flag) +{ + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_ref *substring, *tail; + gfc_component *component; + gfc_symbol *sym; + match m; + + tail = NULL; + + if (primary->symtree->n.sym->attr.dimension + || (equiv_flag + && gfc_peek_char () == '(')) + { + + tail = extend_ref (primary, tail); + tail->type = REF_ARRAY; + + m = gfc_match_array_ref (&tail->u.ar, primary->symtree->n.sym->as, + equiv_flag); + if (m != MATCH_YES) + return m; + } + + sym = primary->symtree->n.sym; + primary->ts = sym->ts; + + if (sym->ts.type != BT_DERIVED || gfc_match_char ('%') != MATCH_YES) + goto check_substring; + + sym = sym->ts.derived; + + for (;;) + { + m = gfc_match_name (name); + if (m == MATCH_NO) + gfc_error ("Expected structure component name at %C"); + if (m != MATCH_YES) + return MATCH_ERROR; + + component = gfc_find_component (sym, name); + if (component == NULL) + return MATCH_ERROR; + + tail = extend_ref (primary, tail); + tail->type = REF_COMPONENT; + + tail->u.c.component = component; + tail->u.c.sym = sym; + + primary->ts = component->ts; + + if (component->as != NULL) + { + tail = extend_ref (primary, tail); + tail->type = REF_ARRAY; + + m = gfc_match_array_ref (&tail->u.ar, component->as, equiv_flag); + if (m != MATCH_YES) + return m; + } + + if (component->ts.type != BT_DERIVED + || gfc_match_char ('%') != MATCH_YES) + break; + + sym = component->ts.derived; + } + +check_substring: + if (primary->ts.type == BT_CHARACTER) + { + switch (match_substring (primary->ts.cl, equiv_flag, &substring)) + { + case MATCH_YES: + if (tail == NULL) + primary->ref = substring; + else + tail->next = substring; + + if (primary->expr_type == EXPR_CONSTANT) + primary->expr_type = EXPR_SUBSTRING; + + break; + + case MATCH_NO: + break; + + case MATCH_ERROR: + return MATCH_ERROR; + } + } + + return MATCH_YES; +} + + +/* Given an expression that is a variable, figure out what the + ultimate variable's type and attribute is, traversing the reference + structures if necessary. + + This subroutine is trickier than it looks. We start at the base + symbol and store the attribute. Component references load a + completely new attribute. + + A couple of rules come into play. Subobjects of targets are always + targets themselves. If we see a component that goes through a + pointer, then the expression must also be a target, since the + pointer is associated with something (if it isn't core will soon be + dumped). If we see a full part or section of an array, the + expression is also an array. + + We can have at most one full array reference. */ + +symbol_attribute +gfc_variable_attr (gfc_expr * expr, gfc_typespec * ts) +{ + int dimension, pointer, target; + symbol_attribute attr; + gfc_ref *ref; + + if (expr->expr_type != EXPR_VARIABLE) + gfc_internal_error ("gfc_variable_attr(): Expression isn't a variable"); + + ref = expr->ref; + attr = expr->symtree->n.sym->attr; + + dimension = attr.dimension; + pointer = attr.pointer; + + target = attr.target; + if (pointer) + target = 1; + + if (ts != NULL && expr->ts.type == BT_UNKNOWN) + *ts = expr->symtree->n.sym->ts; + + for (; ref; ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + + switch (ref->u.ar.type) + { + case AR_FULL: + dimension = 1; + break; + + case AR_SECTION: + pointer = 0; + dimension = 1; + break; + + case AR_ELEMENT: + pointer = 0; + break; + + case AR_UNKNOWN: + gfc_internal_error ("gfc_variable_attr(): Bad array reference"); + } + + break; + + case REF_COMPONENT: + gfc_get_component_attr (&attr, ref->u.c.component); + if (ts != NULL) + *ts = ref->u.c.component->ts; + + pointer = ref->u.c.component->pointer; + if (pointer) + target = 1; + + break; + + case REF_SUBSTRING: + pointer = 0; + break; + } + + attr.dimension = dimension; + attr.pointer = pointer; + attr.target = target; + + return attr; +} + + +/* Return the attribute from a general expression. */ + +symbol_attribute +gfc_expr_attr (gfc_expr * e) +{ + symbol_attribute attr; + + switch (e->expr_type) + { + case EXPR_VARIABLE: + attr = gfc_variable_attr (e, NULL); + break; + + case EXPR_FUNCTION: + gfc_clear_attr (&attr); + + if (e->value.function.esym != NULL) + attr = e->value.function.esym->result->attr; + + /* TODO: NULL() returns pointers. May have to take care of this + here. */ + + break; + + default: + gfc_clear_attr (&attr); + break; + } + + return attr; +} + + +/* Match a structure constructor. The initial symbol has already been + seen. */ + +static match +match_structure_constructor (gfc_symbol * sym, gfc_expr ** result) +{ + gfc_constructor *head, *tail; + gfc_component *comp; + gfc_expr *e; + locus where; + match m; + + head = tail = NULL; + + if (gfc_match_char ('(') != MATCH_YES) + goto syntax; + + where = *gfc_current_locus (); + + gfc_find_component (sym, NULL); + + for (comp = sym->components; comp; comp = comp->next) + { + if (head == NULL) + tail = head = gfc_get_constructor (); + else + { + tail->next = gfc_get_constructor (); + tail = tail->next; + } + + m = gfc_match_expr (&tail->expr); + if (m == MATCH_NO) + goto syntax; + if (m == MATCH_ERROR) + goto cleanup; + + if (gfc_match_char (',') == MATCH_YES) + { + if (comp->next == NULL) + { + gfc_error + ("Too many components in structure constructor at %C"); + goto cleanup; + } + + continue; + } + + break; + } + + if (gfc_match_char (')') != MATCH_YES) + goto syntax; + + if (comp->next != NULL) + { + gfc_error ("Too few components in structure constructor at %C"); + goto cleanup; + } + + e = gfc_get_expr (); + + e->expr_type = EXPR_STRUCTURE; + + e->ts.type = BT_DERIVED; + e->ts.derived = sym; + e->where = where; + + e->value.constructor = head; + + *result = e; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in structure constructor at %C"); + +cleanup: + gfc_free_constructor (head); + return MATCH_ERROR; +} + + +/* Matches a variable name followed by anything that might follow it-- + array reference, argument list of a function, etc. */ + +match +gfc_match_rvalue (gfc_expr ** result) +{ + gfc_actual_arglist *actual_arglist; + char name[GFC_MAX_SYMBOL_LEN + 1]; + gfc_state_data *st; + gfc_symbol *sym; + gfc_symtree *symtree; + locus where; + gfc_expr *e; + match m; + int i; + + m = gfc_match_name (name); + if (m != MATCH_YES) + return m; + + if (gfc_find_state (COMP_INTERFACE) == SUCCESS) + i = gfc_get_sym_tree (name, NULL, &symtree); + else + i = gfc_get_ha_sym_tree (name, &symtree); + + if (i) + return MATCH_ERROR; + + sym = symtree->n.sym; + e = NULL; + where = *gfc_current_locus (); + + gfc_set_sym_referenced (sym); + + if (sym->attr.function && sym->result == sym + && (gfc_current_ns->proc_name == sym + || (gfc_current_ns->parent != NULL + && gfc_current_ns->parent->proc_name == sym))) + goto variable; + + if (sym->attr.function || sym->attr.external || sym->attr.intrinsic) + goto function0; + + if (sym->attr.generic) + goto generic_function; + + switch (sym->attr.flavor) + { + case FL_VARIABLE: + variable: + if (sym->ts.type == BT_UNKNOWN && gfc_peek_char () == '%' + && gfc_get_default_type (sym, sym->ns)->type == BT_DERIVED) + gfc_set_default_type (sym, 0, sym->ns); + + e = gfc_get_expr (); + + e->expr_type = EXPR_VARIABLE; + e->symtree = symtree; + + m = match_varspec (e, 0); + break; + + case FL_PARAMETER: + if (sym->value + && sym->value->expr_type != EXPR_ARRAY) + e = gfc_copy_expr (sym->value); + else + { + e = gfc_get_expr (); + e->expr_type = EXPR_VARIABLE; + } + + e->symtree = symtree; + m = match_varspec (e, 0); + break; + + case FL_DERIVED: + sym = gfc_use_derived (sym); + if (sym == NULL) + m = MATCH_ERROR; + else + m = match_structure_constructor (sym, &e); + break; + + /* If we're here, then the name is known to be the name of a + procedure, yet it is not sure to be the name of a function. */ + case FL_PROCEDURE: + if (sym->attr.subroutine) + { + gfc_error ("Unexpected use of subroutine name '%s' at %C", + sym->name); + m = MATCH_ERROR; + break; + } + + /* At this point, the name has to be a non-statement function. + If the name is the same as the current function being + compiled, then we have a variable reference (to the function + result) if the name is non-recursive. */ + + st = gfc_enclosing_unit (NULL); + + if (st != NULL && st->state == COMP_FUNCTION + && st->sym == sym + && !sym->attr.recursive) + { + e = gfc_get_expr (); + e->symtree = symtree; + e->expr_type = EXPR_VARIABLE; + + m = match_varspec (e, 0); + break; + } + + /* Match a function reference. */ + function0: + m = gfc_match_actual_arglist (0, &actual_arglist); + if (m == MATCH_NO) + { + if (sym->attr.proc == PROC_ST_FUNCTION) + gfc_error ("Statement function '%s' requires argument list at %C", + sym->name); + else + gfc_error ("Function '%s' requires an argument list at %C", + sym->name); + + m = MATCH_ERROR; + break; + } + + if (m != MATCH_YES) + { + m = MATCH_ERROR; + break; + } + + gfc_get_ha_sym_tree (name, &symtree); /* Can't fail */ + sym = symtree->n.sym; + + e = gfc_get_expr (); + e->symtree = symtree; + e->expr_type = EXPR_FUNCTION; + e->value.function.actual = actual_arglist; + e->where = *gfc_current_locus (); + + if (sym->as != NULL) + e->rank = sym->as->rank; + + if (!sym->attr.function + && gfc_add_function (&sym->attr, NULL) == FAILURE) + { + m = MATCH_ERROR; + break; + } + + if (sym->result == NULL) + sym->result = sym; + + m = MATCH_YES; + break; + + case FL_UNKNOWN: + + /* Special case for derived type variables that get their types + via an IMPLICIT statement. This can't wait for the + resolution phase. */ + + if (gfc_peek_char () == '%' + && gfc_get_default_type (sym, sym->ns)->type == BT_DERIVED) + gfc_set_default_type (sym, 0, sym->ns); + + /* If the symbol has a dimension attribute, the expression is a + variable. */ + + if (sym->attr.dimension) + { + if (gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE) + { + m = MATCH_ERROR; + break; + } + + e = gfc_get_expr (); + e->symtree = symtree; + e->expr_type = EXPR_VARIABLE; + m = match_varspec (e, 0); + break; + } + + /* Name is not an array, so we peek to see if a '(' implies a + function call or a substring reference. Otherwise the + variable is just a scalar. */ + + gfc_gobble_whitespace (); + if (gfc_peek_char () != '(') + { + /* Assume a scalar variable */ + e = gfc_get_expr (); + e->symtree = symtree; + e->expr_type = EXPR_VARIABLE; + + if (gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE) + { + m = MATCH_ERROR; + break; + } + + e->ts = sym->ts; + m = match_varspec (e, 0); + break; + } + + /* See if this could possibly be a substring reference of a name + that we're not sure is a variable yet. */ + + e = gfc_get_expr (); + e->symtree = symtree; + + if ((sym->ts.type == BT_UNKNOWN || sym->ts.type == BT_CHARACTER) + && match_substring (sym->ts.cl, 0, &e->ref) == MATCH_YES) + { + + e->expr_type = EXPR_VARIABLE; + + if (sym->attr.flavor != FL_VARIABLE + && gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE) + { + m = MATCH_ERROR; + break; + } + + if (sym->ts.type == BT_UNKNOWN + && gfc_set_default_type (sym, 1, NULL) == FAILURE) + { + m = MATCH_ERROR; + break; + } + + e->ts = sym->ts; + m = MATCH_YES; + break; + } + + /* Give up, assume we have a function. */ + + gfc_get_sym_tree (name, NULL, &symtree); /* Can't fail */ + sym = symtree->n.sym; + e->expr_type = EXPR_FUNCTION; + + if (!sym->attr.function + && gfc_add_function (&sym->attr, NULL) == FAILURE) + { + m = MATCH_ERROR; + break; + } + + sym->result = sym; + + m = gfc_match_actual_arglist (0, &e->value.function.actual); + if (m == MATCH_NO) + gfc_error ("Missing argument list in function '%s' at %C", sym->name); + + if (m != MATCH_YES) + { + m = MATCH_ERROR; + break; + } + + /* If our new function returns a character, array or structure + type, it might have subsequent references. */ + + m = match_varspec (e, 0); + if (m == MATCH_NO) + m = MATCH_YES; + + break; + + generic_function: + gfc_get_sym_tree (name, NULL, &symtree); /* Can't fail */ + + e = gfc_get_expr (); + e->symtree = symtree; + e->expr_type = EXPR_FUNCTION; + + m = gfc_match_actual_arglist (0, &e->value.function.actual); + break; + + default: + gfc_error ("Symbol at %C is not appropriate for an expression"); + return MATCH_ERROR; + } + + if (m == MATCH_YES) + { + e->where = where; + *result = e; + } + else + gfc_free_expr (e); + + return m; +} + + +/* Match a variable, ie something that can be assigned to. This + starts as a symbol, can be a structure component or an array + reference. It can be a function if the function doesn't have a + separate RESULT variable. If the symbol has not been previously + seen, we assume it is a variable. */ + +match +gfc_match_variable (gfc_expr ** result, int equiv_flag) +{ + gfc_symbol *sym; + gfc_symtree *st; + gfc_expr *expr; + locus where; + match m; + + m = gfc_match_sym_tree (&st, 1); + if (m != MATCH_YES) + return m; + where = *gfc_current_locus (); + + sym = st->n.sym; + gfc_set_sym_referenced (sym); + switch (sym->attr.flavor) + { + case FL_VARIABLE: + break; + + case FL_UNKNOWN: + if (gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE) + return MATCH_ERROR; + + /* Special case for derived type variables that get their types + via an IMPLICIT statement. This can't wait for the + resolution phase. */ + + if (gfc_peek_char () == '%' + && gfc_get_default_type (sym, sym->ns)->type == BT_DERIVED) + gfc_set_default_type (sym, 0, sym->ns); + + break; + + case FL_PROCEDURE: + /* Check for a nonrecursive function result */ + if (sym->attr.function && (sym->result == sym || sym->attr.entry)) + { + + /* If a function result is a derived type, then the derived + type may still have to be resolved. */ + + if (sym->ts.type == BT_DERIVED + && gfc_use_derived (sym->ts.derived) == NULL) + return MATCH_ERROR; + + break; + } + + /* Fall through to error */ + + default: + gfc_error ("Expected VARIABLE at %C"); + return MATCH_ERROR; + } + + expr = gfc_get_expr (); + + expr->expr_type = EXPR_VARIABLE; + expr->symtree = st; + expr->ts = sym->ts; + expr->where = where; + + /* Now see if we have to do more. */ + m = match_varspec (expr, equiv_flag); + if (m != MATCH_YES) + { + gfc_free_expr (expr); + return m; + } + + *result = expr; + return MATCH_YES; +} diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c new file mode 100644 index 00000000000..cec47165c02 --- /dev/null +++ b/gcc/fortran/resolve.c @@ -0,0 +1,4435 @@ +/* Perform type resolution on the various stuctures. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "gfortran.h" +#include "arith.h" /* For gfc_compare_expr(). */ +#include +#include + +/* Stack to push the current if we descend into a block during + resolution. See resolve_branch() and resolve_code(). */ + +typedef struct code_stack +{ + struct gfc_code *head, *current; + struct code_stack *prev; +} +code_stack; + +static code_stack *cs_base = NULL; + + +/* Nonzero if we're inside a FORALL block */ + +static int forall_flag; + +/* Resolve types of formal argument lists. These have to be done early so that + the formal argument lists of module procedures can be copied to the + containing module before the individual procedures are resolved + individually. We also resolve argument lists of procedures in interface + blocks because they are self-contained scoping units. + + Since a dummy argument cannot be a non-dummy procedure, the only + resort left for untyped names are the IMPLICIT types. */ + +static void +resolve_formal_arglist (gfc_symbol * proc) +{ + gfc_formal_arglist *f; + gfc_symbol *sym; + int i; + + /* TODO: Procedures whose return character length parameter is not constant + or assumed must also have explicit interfaces. */ + if (proc->result != NULL) + sym = proc->result; + else + sym = proc; + + if (gfc_elemental (proc) + || sym->attr.pointer || sym->attr.allocatable + || (sym->as && sym->as->rank > 0)) + proc->attr.always_explicit = 1; + + for (f = proc->formal; f; f = f->next) + { + sym = f->sym; + + if (sym == NULL) + { + /* Alternate return placeholder. */ + if (gfc_elemental (proc)) + gfc_error ("Alternate return specifier in elemental subroutine " + "'%s' at %L is not allowed", proc->name, + &proc->declared_at); + if (proc->attr.function) + gfc_error ("Alternate return specifier in function " + "'%s' at %L is not allowed", proc->name, + &proc->declared_at); + continue; + } + + if (sym->attr.if_source != IFSRC_UNKNOWN) + resolve_formal_arglist (sym); + + if (sym->attr.subroutine || sym->attr.external || sym->attr.intrinsic) + { + if (gfc_pure (proc) && !gfc_pure (sym)) + { + gfc_error + ("Dummy procedure '%s' of PURE procedure at %L must also " + "be PURE", sym->name, &sym->declared_at); + continue; + } + + if (gfc_elemental (proc)) + { + gfc_error + ("Dummy procedure at %L not allowed in ELEMENTAL procedure", + &sym->declared_at); + continue; + } + + continue; + } + + if (sym->ts.type == BT_UNKNOWN) + { + if (!sym->attr.function || sym->result == sym) + gfc_set_default_type (sym, 1, sym->ns); + else + { + /* Set the type of the RESULT, then copy. */ + if (sym->result->ts.type == BT_UNKNOWN) + gfc_set_default_type (sym->result, 1, sym->result->ns); + + sym->ts = sym->result->ts; + if (sym->as == NULL) + sym->as = gfc_copy_array_spec (sym->result->as); + } + } + + gfc_resolve_array_spec (sym->as, 0); + + /* We can't tell if an array with dimension (:) is assumed or deferred + shape until we know if it has the pointer or allocatable attributes. + */ + if (sym->as && sym->as->rank > 0 && sym->as->type == AS_DEFERRED + && !(sym->attr.pointer || sym->attr.allocatable)) + { + sym->as->type = AS_ASSUMED_SHAPE; + for (i = 0; i < sym->as->rank; i++) + sym->as->lower[i] = gfc_int_expr (1); + } + + if ((sym->as && sym->as->rank > 0 && sym->as->type == AS_ASSUMED_SHAPE) + || sym->attr.pointer || sym->attr.allocatable || sym->attr.target + || sym->attr.optional) + proc->attr.always_explicit = 1; + + /* If the flavor is unknown at this point, it has to be a variable. + A procedure specification would have already set the type. */ + + if (sym->attr.flavor == FL_UNKNOWN) + gfc_add_flavor (&sym->attr, FL_VARIABLE, &sym->declared_at); + + if (gfc_pure (proc)) + { + if (proc->attr.function && !sym->attr.pointer + && sym->attr.flavor != FL_PROCEDURE + && sym->attr.intent != INTENT_IN) + + gfc_error ("Argument '%s' of pure function '%s' at %L must be " + "INTENT(IN)", sym->name, proc->name, + &sym->declared_at); + + if (proc->attr.subroutine && !sym->attr.pointer + && sym->attr.intent == INTENT_UNKNOWN) + + gfc_error + ("Argument '%s' of pure subroutine '%s' at %L must have " + "its INTENT specified", sym->name, proc->name, + &sym->declared_at); + } + + + if (gfc_elemental (proc)) + { + if (sym->as != NULL) + { + gfc_error + ("Argument '%s' of elemental procedure at %L must be scalar", + sym->name, &sym->declared_at); + continue; + } + + if (sym->attr.pointer) + { + gfc_error + ("Argument '%s' of elemental procedure at %L cannot have " + "the POINTER attribute", sym->name, &sym->declared_at); + continue; + } + } + + /* Each dummy shall be specified to be scalar. */ + if (proc->attr.proc == PROC_ST_FUNCTION) + { + if (sym->as != NULL) + { + gfc_error + ("Argument '%s' of statement function at %L must be scalar", + sym->name, &sym->declared_at); + continue; + } + + if (sym->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->ts.cl; + if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT) + { + gfc_error + ("Character-valued argument '%s' of statement function at " + "%L must has constant length", + sym->name, &sym->declared_at); + continue; + } + } + } + } +} + + +/* Work function called when searching for symbols that have argument lists + associated with them. */ + +static void +find_arglists (gfc_symbol * sym) +{ + + if (sym->attr.if_source == IFSRC_UNKNOWN || sym->ns != gfc_current_ns) + return; + + resolve_formal_arglist (sym); +} + + +/* Given a namespace, resolve all formal argument lists within the namespace. + */ + +static void +resolve_formal_arglists (gfc_namespace * ns) +{ + + if (ns == NULL) + return; + + gfc_traverse_ns (ns, find_arglists); +} + + +/* Resolve contained function types. Because contained functions can call one + another, they have to be worked out before any of the contained procedures + can be resolved. + + The good news is that if a function doesn't already have a type, the only + way it can get one is through an IMPLICIT type or a RESULT variable, because + by definition contained functions are contained namespace they're contained + in, not in a sibling or parent namespace. */ + +static void +resolve_contained_functions (gfc_namespace * ns) +{ + gfc_symbol *contained_sym, *sym_lower; + gfc_namespace *child; + try t; + + resolve_formal_arglists (ns); + + for (child = ns->contained; child; child = child->sibling) + { + sym_lower = child->proc_name; + + /* If this namespace is not a function, ignore it. */ + if (! sym_lower + || !( sym_lower->attr.function + || sym_lower->attr.flavor == FL_VARIABLE)) + continue; + + /* Find the contained symbol in the current namespace. */ + gfc_find_symbol (sym_lower->name, ns, 0, &contained_sym); + + if (contained_sym == NULL) + gfc_internal_error ("resolve_contained_functions(): Contained " + "function not found in parent namespace"); + + /* Try to find out of what type the function is. If there was an + explicit RESULT clause, try to get the type from it. If the + function is never defined, set it to the implicit type. If + even that fails, give up. */ + if (sym_lower->result != NULL) + sym_lower = sym_lower->result; + + if (sym_lower->ts.type == BT_UNKNOWN) + { + /* Assume we can find an implicit type. */ + t = SUCCESS; + + if (sym_lower->result == NULL) + t = gfc_set_default_type (sym_lower, 0, child); + else + { + if (sym_lower->result->ts.type == BT_UNKNOWN) + t = gfc_set_default_type (sym_lower->result, 0, NULL); + + sym_lower->ts = sym_lower->result->ts; + } + + if (t == FAILURE) + gfc_error ("Contained function '%s' at %L has no IMPLICIT type", + sym_lower->name, &sym_lower->declared_at); /* FIXME */ + } + + /* If the symbol in the parent of the contained namespace is not + the same as the one in contained namespace itself, copy over + the type information. */ + /* ??? Shouldn't we replace the symbol with the parent symbol instead? */ + if (contained_sym != sym_lower) + { + contained_sym->ts = sym_lower->ts; + contained_sym->as = gfc_copy_array_spec (sym_lower->as); + } + } +} + + +/* Resolve all of the elements of a structure constructor and make sure that + the types are correct. */ + +static try +resolve_structure_cons (gfc_expr * expr) +{ + gfc_constructor *cons; + gfc_component *comp; + try t; + + t = SUCCESS; + cons = expr->value.constructor; + /* A constructor may have references if it is the result of substituting a + parameter variable. In this case we just pull out the component we + want. */ + if (expr->ref) + comp = expr->ref->u.c.sym->components; + else + comp = expr->ts.derived->components; + + for (; comp; comp = comp->next, cons = cons->next) + { + if (! cons->expr) + { + t = FAILURE; + continue; + } + + if (gfc_resolve_expr (cons->expr) == FAILURE) + { + t = FAILURE; + continue; + } + + /* If we don't have the right type, try to convert it. */ + + if (!gfc_compare_types (&cons->expr->ts, &comp->ts) + && gfc_convert_type (cons->expr, &comp->ts, 1) == FAILURE) + t = FAILURE; + } + + return t; +} + + + +/****************** Expression name resolution ******************/ + +/* Returns 0 if a symbol was not declared with a type or + or attribute declaration statement, nonzero otherwise. */ + +static int +was_declared (gfc_symbol * sym) +{ + symbol_attribute a; + + a = sym->attr; + + if (!a.implicit_type && sym->ts.type != BT_UNKNOWN) + return 1; + + if (a.allocatable || a.dimension || a.external || a.intrinsic + || a.optional || a.pointer || a.save || a.target + || a.access != ACCESS_UNKNOWN || a.intent != INTENT_UNKNOWN) + return 1; + + return 0; +} + + +/* Determine if a symbol is generic or not. */ + +static int +generic_sym (gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.generic || + (sym->attr.intrinsic && gfc_generic_intrinsic (sym->name))) + return 1; + + if (was_declared (sym) || sym->ns->parent == NULL) + return 0; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &s); + + return (s == NULL) ? 0 : generic_sym (s); +} + + +/* Determine if a symbol is specific or not. */ + +static int +specific_sym (gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.if_source == IFSRC_IFBODY + || sym->attr.proc == PROC_MODULE + || sym->attr.proc == PROC_INTERNAL + || sym->attr.proc == PROC_ST_FUNCTION + || (sym->attr.intrinsic && + gfc_specific_intrinsic (sym->name)) + || sym->attr.external) + return 1; + + if (was_declared (sym) || sym->ns->parent == NULL) + return 0; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &s); + + return (s == NULL) ? 0 : specific_sym (s); +} + + +/* Figure out if the procedure is specific, generic or unknown. */ + +typedef enum +{ PTYPE_GENERIC = 1, PTYPE_SPECIFIC, PTYPE_UNKNOWN } +proc_type; + +static proc_type +procedure_kind (gfc_symbol * sym) +{ + + if (generic_sym (sym)) + return PTYPE_GENERIC; + + if (specific_sym (sym)) + return PTYPE_SPECIFIC; + + return PTYPE_UNKNOWN; +} + + +/* Resolve an actual argument list. Most of the time, this is just + resolving the expressions in the list. + The exception is that we sometimes have to decide whether arguments + that look like procedure arguments are really simple variable + references. */ + +static try +resolve_actual_arglist (gfc_actual_arglist * arg) +{ + gfc_symbol *sym; + gfc_symtree *parent_st; + gfc_expr *e; + + for (; arg; arg = arg->next) + { + + e = arg->expr; + if (e == NULL) + { + /* Check the label is a valid branching target. */ + if (arg->label) + { + if (arg->label->defined == ST_LABEL_UNKNOWN) + { + gfc_error ("Label %d referenced at %L is never defined", + arg->label->value, &arg->label->where); + return FAILURE; + } + } + continue; + } + + if (e->ts.type != BT_PROCEDURE) + { + if (gfc_resolve_expr (e) != SUCCESS) + return FAILURE; + continue; + } + + /* See if the expression node should really be a variable + reference. */ + + sym = e->symtree->n.sym; + + if (sym->attr.flavor == FL_PROCEDURE + || sym->attr.intrinsic + || sym->attr.external) + { + + /* If the symbol is the function that names the current (or + parent) scope, then we really have a variable reference. */ + + if (sym->attr.function && sym->result == sym + && (sym->ns->proc_name == sym + || (sym->ns->parent != NULL + && sym->ns->parent->proc_name == sym))) + goto got_variable; + + continue; + } + + /* See if the name is a module procedure in a parent unit. */ + + if (was_declared (sym) || sym->ns->parent == NULL) + goto got_variable; + + if (gfc_find_sym_tree (sym->name, sym->ns->parent, 1, &parent_st)) + { + gfc_error ("Symbol '%s' at %L is ambiguous", sym->name, &e->where); + return FAILURE; + } + + if (parent_st == NULL) + goto got_variable; + + sym = parent_st->n.sym; + e->symtree = parent_st; /* Point to the right thing. */ + + if (sym->attr.flavor == FL_PROCEDURE + || sym->attr.intrinsic + || sym->attr.external) + { + continue; + } + + got_variable: + e->expr_type = EXPR_VARIABLE; + e->ts = sym->ts; + if (sym->as != NULL) + { + e->rank = sym->as->rank; + e->ref = gfc_get_ref (); + e->ref->type = REF_ARRAY; + e->ref->u.ar.type = AR_FULL; + e->ref->u.ar.as = sym->as; + } + } + + return SUCCESS; +} + + +/************* Function resolution *************/ + +/* Resolve a function call known to be generic. + Section 14.1.2.4.1. */ + +static match +resolve_generic_f0 (gfc_expr * expr, gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.generic) + { + s = + gfc_search_interface (sym->generic, 0, &expr->value.function.actual); + if (s != NULL) + { + expr->value.function.name = s->name; + expr->value.function.esym = s; + expr->ts = s->ts; + if (s->as != NULL) + expr->rank = s->as->rank; + return MATCH_YES; + } + + /* TODO: Need to search for elemental references in generic interface */ + } + + if (sym->attr.intrinsic) + return gfc_intrinsic_func_interface (expr, 0); + + return MATCH_NO; +} + + +static try +resolve_generic_f (gfc_expr * expr) +{ + gfc_symbol *sym; + match m; + + sym = expr->symtree->n.sym; + + for (;;) + { + m = resolve_generic_f0 (expr, sym); + if (m == MATCH_YES) + return SUCCESS; + else if (m == MATCH_ERROR) + return FAILURE; + +generic: + if (sym->ns->parent == NULL) + break; + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + + if (sym == NULL) + break; + if (!generic_sym (sym)) + goto generic; + } + + /* Last ditch attempt. */ + + if (!gfc_generic_intrinsic (expr->symtree->n.sym->name)) + { + gfc_error ("Generic function '%s' at %L is not an intrinsic function", + expr->symtree->n.sym->name, &expr->where); + return FAILURE; + } + + m = gfc_intrinsic_func_interface (expr, 0); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_NO) + gfc_error + ("Generic function '%s' at %L is not consistent with a specific " + "intrinsic interface", expr->symtree->n.sym->name, &expr->where); + + return FAILURE; +} + + +/* Resolve a function call known to be specific. */ + +static match +resolve_specific_f0 (gfc_symbol * sym, gfc_expr * expr) +{ + match m; + + if (sym->attr.external || sym->attr.if_source == IFSRC_IFBODY) + { + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + goto found; + } + + sym->attr.proc = PROC_EXTERNAL; + goto found; + } + + if (sym->attr.proc == PROC_MODULE + || sym->attr.proc == PROC_ST_FUNCTION + || sym->attr.proc == PROC_INTERNAL) + goto found; + + if (sym->attr.intrinsic) + { + m = gfc_intrinsic_func_interface (expr, 1); + if (m == MATCH_YES) + return MATCH_YES; + if (m == MATCH_NO) + gfc_error + ("Function '%s' at %L is INTRINSIC but is not compatible with " + "an intrinsic", sym->name, &expr->where); + + return MATCH_ERROR; + } + + return MATCH_NO; + +found: + gfc_procedure_use (sym, &expr->value.function.actual, &expr->where); + + expr->ts = sym->ts; + expr->value.function.name = sym->name; + expr->value.function.esym = sym; + if (sym->as != NULL) + expr->rank = sym->as->rank; + + return MATCH_YES; +} + + +static try +resolve_specific_f (gfc_expr * expr) +{ + gfc_symbol *sym; + match m; + + sym = expr->symtree->n.sym; + + for (;;) + { + m = resolve_specific_f0 (sym, expr); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + + if (sym->ns->parent == NULL) + break; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + + if (sym == NULL) + break; + } + + gfc_error ("Unable to resolve the specific function '%s' at %L", + expr->symtree->n.sym->name, &expr->where); + + return SUCCESS; +} + + +/* Resolve a procedure call not known to be generic nor specific. */ + +static try +resolve_unknown_f (gfc_expr * expr) +{ + gfc_symbol *sym; + gfc_typespec *ts; + + sym = expr->symtree->n.sym; + + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + expr->value.function.name = sym->name; + goto set_type; + } + + /* See if we have an intrinsic function reference. */ + + if (gfc_intrinsic_name (sym->name, 0)) + { + if (gfc_intrinsic_func_interface (expr, 1) == MATCH_YES) + return SUCCESS; + return FAILURE; + } + + /* The reference is to an external name. */ + + sym->attr.proc = PROC_EXTERNAL; + expr->value.function.name = sym->name; + expr->value.function.esym = expr->symtree->n.sym; + + if (sym->as != NULL) + expr->rank = sym->as->rank; + + /* Type of the expression is either the type of the symbol or the + default type of the symbol. */ + +set_type: + gfc_procedure_use (sym, &expr->value.function.actual, &expr->where); + + if (sym->ts.type != BT_UNKNOWN) + expr->ts = sym->ts; + else + { + ts = gfc_get_default_type (sym, sym->ns); + + if (ts->type == BT_UNKNOWN) + { + gfc_error ("Function '%s' at %L has no implicit type", + sym->name, &expr->where); + return FAILURE; + } + else + expr->ts = *ts; + } + + return SUCCESS; +} + + +/* Figure out if if a function reference is pure or not. Also sets the name + of the function for a potential error message. Returns nonzero if the + function is PURE, zero if not. */ + +static int +pure_function (gfc_expr * e, char **name) +{ + int pure; + + if (e->value.function.esym) + { + pure = gfc_pure (e->value.function.esym); + *name = e->value.function.esym->name; + } + else if (e->value.function.isym) + { + pure = e->value.function.isym->pure + || e->value.function.isym->elemental; + *name = e->value.function.isym->name; + } + else + { + /* Implicit functions are not pure. */ + pure = 0; + *name = e->value.function.name; + } + + return pure; +} + + +/* Resolve a function call, which means resolving the arguments, then figuring + out which entity the name refers to. */ +/* TODO: Check procedure arguments so that an INTENT(IN) isn't passed + to INTENT(OUT) or INTENT(INOUT). */ + +static try +resolve_function (gfc_expr * expr) +{ + gfc_actual_arglist *arg; + char *name; + try t; + + if (resolve_actual_arglist (expr->value.function.actual) == FAILURE) + return FAILURE; + +/* See if function is already resolved. */ + + if (expr->value.function.name != NULL) + { + if (expr->ts.type == BT_UNKNOWN) + expr->ts = expr->symtree->n.sym->ts; + t = SUCCESS; + } + else + { + /* Apply the rules of section 14.1.2. */ + + switch (procedure_kind (expr->symtree->n.sym)) + { + case PTYPE_GENERIC: + t = resolve_generic_f (expr); + break; + + case PTYPE_SPECIFIC: + t = resolve_specific_f (expr); + break; + + case PTYPE_UNKNOWN: + t = resolve_unknown_f (expr); + break; + + default: + gfc_internal_error ("resolve_function(): bad function type"); + } + } + + /* If the expression is still a function (it might have simplified), + then we check to see if we are calling an elemental function. */ + + if (expr->expr_type != EXPR_FUNCTION) + return t; + + if (expr->value.function.actual != NULL + && ((expr->value.function.esym != NULL + && expr->value.function.esym->attr.elemental) + || (expr->value.function.isym != NULL + && expr->value.function.isym->elemental))) + { + + /* The rank of an elemental is the rank of its array argument(s). */ + + for (arg = expr->value.function.actual; arg; arg = arg->next) + { + if (arg->expr != NULL && arg->expr->rank > 0) + { + expr->rank = arg->expr->rank; + break; + } + } + } + + if (!pure_function (expr, &name)) + { + if (forall_flag) + { + gfc_error + ("Function reference to '%s' at %L is inside a FORALL block", + name, &expr->where); + t = FAILURE; + } + else if (gfc_pure (NULL)) + { + gfc_error ("Function reference to '%s' at %L is to a non-PURE " + "procedure within a PURE procedure", name, &expr->where); + t = FAILURE; + } + } + + return t; +} + + +/************* Subroutine resolution *************/ + +static void +pure_subroutine (gfc_code * c, gfc_symbol * sym) +{ + + if (gfc_pure (sym)) + return; + + if (forall_flag) + gfc_error ("Subroutine call to '%s' in FORALL block at %L is not PURE", + sym->name, &c->loc); + else if (gfc_pure (NULL)) + gfc_error ("Subroutine call to '%s' at %L is not PURE", sym->name, + &c->loc); +} + + +static match +resolve_generic_s0 (gfc_code * c, gfc_symbol * sym) +{ + gfc_symbol *s; + + if (sym->attr.generic) + { + s = gfc_search_interface (sym->generic, 1, &c->ext.actual); + if (s != NULL) + { + c->resolved_sym = s; + pure_subroutine (c, s); + return MATCH_YES; + } + + /* TODO: Need to search for elemental references in generic interface. */ + } + + if (sym->attr.intrinsic) + return gfc_intrinsic_sub_interface (c, 0); + + return MATCH_NO; +} + + +static try +resolve_generic_s (gfc_code * c) +{ + gfc_symbol *sym; + match m; + + sym = c->symtree->n.sym; + + m = resolve_generic_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + + if (sym->ns->parent != NULL) + { + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + if (sym != NULL) + { + m = resolve_generic_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + } + } + + /* Last ditch attempt. */ + + if (!gfc_generic_intrinsic (sym->name)) + { + gfc_error + ("Generic subroutine '%s' at %L is not an intrinsic subroutine", + sym->name, &c->loc); + return FAILURE; + } + + m = gfc_intrinsic_sub_interface (c, 0); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_NO) + gfc_error ("Generic subroutine '%s' at %L is not consistent with an " + "intrinsic subroutine interface", sym->name, &c->loc); + + return FAILURE; +} + + +/* Resolve a subroutine call known to be specific. */ + +static match +resolve_specific_s0 (gfc_code * c, gfc_symbol * sym) +{ + match m; + + if (sym->attr.external || sym->attr.if_source == IFSRC_IFBODY) + { + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + goto found; + } + + sym->attr.proc = PROC_EXTERNAL; + goto found; + } + + if (sym->attr.proc == PROC_MODULE || sym->attr.proc == PROC_INTERNAL) + goto found; + + if (sym->attr.intrinsic) + { + m = gfc_intrinsic_sub_interface (c, 1); + if (m == MATCH_YES) + return MATCH_YES; + if (m == MATCH_NO) + gfc_error ("Subroutine '%s' at %L is INTRINSIC but is not compatible " + "with an intrinsic", sym->name, &c->loc); + + return MATCH_ERROR; + } + + return MATCH_NO; + +found: + gfc_procedure_use (sym, &c->ext.actual, &c->loc); + + c->resolved_sym = sym; + pure_subroutine (c, sym); + + return MATCH_YES; +} + + +static try +resolve_specific_s (gfc_code * c) +{ + gfc_symbol *sym; + match m; + + sym = c->symtree->n.sym; + + m = resolve_specific_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + + gfc_find_symbol (sym->name, sym->ns->parent, 1, &sym); + + if (sym != NULL) + { + m = resolve_specific_s0 (c, sym); + if (m == MATCH_YES) + return SUCCESS; + if (m == MATCH_ERROR) + return FAILURE; + } + + gfc_error ("Unable to resolve the specific subroutine '%s' at %L", + sym->name, &c->loc); + + return FAILURE; +} + + +/* Resolve a subroutine call not known to be generic nor specific. */ + +static try +resolve_unknown_s (gfc_code * c) +{ + gfc_symbol *sym; + + sym = c->symtree->n.sym; + + if (sym->attr.dummy) + { + sym->attr.proc = PROC_DUMMY; + goto found; + } + + /* See if we have an intrinsic function reference. */ + + if (gfc_intrinsic_name (sym->name, 1)) + { + if (gfc_intrinsic_sub_interface (c, 1) == MATCH_YES) + return SUCCESS; + return FAILURE; + } + + /* The reference is to an external name. */ + +found: + gfc_procedure_use (sym, &c->ext.actual, &c->loc); + + c->resolved_sym = sym; + + pure_subroutine (c, sym); + + return SUCCESS; +} + + +/* Resolve a subroutine call. Although it was tempting to use the same code + for functions, subroutines and functions are stored differently and this + makes things awkward. */ + +static try +resolve_call (gfc_code * c) +{ + try t; + + if (resolve_actual_arglist (c->ext.actual) == FAILURE) + return FAILURE; + + if (c->resolved_sym != NULL) + return SUCCESS; + + switch (procedure_kind (c->symtree->n.sym)) + { + case PTYPE_GENERIC: + t = resolve_generic_s (c); + break; + + case PTYPE_SPECIFIC: + t = resolve_specific_s (c); + break; + + case PTYPE_UNKNOWN: + t = resolve_unknown_s (c); + break; + + default: + gfc_internal_error ("resolve_subroutine(): bad function type"); + } + + return t; +} + + +/* Resolve an operator expression node. This can involve replacing the + operation with a user defined function call. */ + +static try +resolve_operator (gfc_expr * e) +{ + gfc_expr *op1, *op2; + char msg[200]; + try t; + + /* Resolve all subnodes-- give them types. */ + + switch (e->operator) + { + default: + if (gfc_resolve_expr (e->op2) == FAILURE) + return FAILURE; + + /* Fall through... */ + + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + if (gfc_resolve_expr (e->op1) == FAILURE) + return FAILURE; + break; + } + + /* Typecheck the new node. */ + + op1 = e->op1; + op2 = e->op2; + + switch (e->operator) + { + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + if (op1->ts.type == BT_INTEGER + || op1->ts.type == BT_REAL + || op1->ts.type == BT_COMPLEX) + { + e->ts = op1->ts; + break; + } + + sprintf (msg, "Operand of unary numeric operator '%s' at %%L is %s", + gfc_op2string (e->operator), gfc_typename (&e->ts)); + goto bad_op; + + case INTRINSIC_PLUS: + case INTRINSIC_MINUS: + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + case INTRINSIC_POWER: + if (gfc_numeric_ts (&op1->ts) && gfc_numeric_ts (&op2->ts)) + { + gfc_type_convert_binary (e); + break; + } + + sprintf (msg, + "Operands of binary numeric operator '%s' at %%L are %s/%s", + gfc_op2string (e->operator), gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + goto bad_op; + + case INTRINSIC_CONCAT: + if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER) + { + e->ts.type = BT_CHARACTER; + e->ts.kind = op1->ts.kind; + break; + } + + sprintf (msg, + "Operands of string concatenation operator at %%L are %s/%s", + gfc_typename (&op1->ts), gfc_typename (&op2->ts)); + goto bad_op; + + case INTRINSIC_AND: + case INTRINSIC_OR: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + if (op1->ts.type == BT_LOGICAL && op2->ts.type == BT_LOGICAL) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_kind_max (op1, op2); + if (op1->ts.kind < e->ts.kind) + gfc_convert_type (op1, &e->ts, 2); + else if (op2->ts.kind < e->ts.kind) + gfc_convert_type (op2, &e->ts, 2); + break; + } + + sprintf (msg, "Operands of logical operator '%s' at %%L are %s/%s", + gfc_op2string (e->operator), gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + + goto bad_op; + + case INTRINSIC_NOT: + if (op1->ts.type == BT_LOGICAL) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = op1->ts.kind; + break; + } + + sprintf (msg, "Operand of .NOT. operator at %%L is %s", + gfc_typename (&op1->ts)); + goto bad_op; + + case INTRINSIC_GT: + case INTRINSIC_GE: + case INTRINSIC_LT: + case INTRINSIC_LE: + if (op1->ts.type == BT_COMPLEX || op2->ts.type == BT_COMPLEX) + { + strcpy (msg, "COMPLEX quantities cannot be compared at %L"); + goto bad_op; + } + + /* Fall through... */ + + case INTRINSIC_EQ: + case INTRINSIC_NE: + if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER) + { + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_default_logical_kind (); + break; + } + + if (gfc_numeric_ts (&op1->ts) && gfc_numeric_ts (&op2->ts)) + { + gfc_type_convert_binary (e); + + e->ts.type = BT_LOGICAL; + e->ts.kind = gfc_default_logical_kind (); + break; + } + + sprintf (msg, "Operands of comparison operator '%s' at %%L are %s/%s", + gfc_op2string (e->operator), gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + + goto bad_op; + + case INTRINSIC_USER: + if (op2 == NULL) + sprintf (msg, "Operand of user operator '%s' at %%L is %s", + e->uop->ns->proc_name->name, gfc_typename (&op1->ts)); + else + sprintf (msg, "Operands of user operator '%s' at %%L are %s/%s", + e->uop->ns->proc_name->name, gfc_typename (&op1->ts), + gfc_typename (&op2->ts)); + + goto bad_op; + + default: + gfc_internal_error ("resolve_operator(): Bad intrinsic"); + } + + /* Deal with arrayness of an operand through an operator. */ + + t = SUCCESS; + + switch (e->operator) + { + case INTRINSIC_PLUS: + case INTRINSIC_MINUS: + case INTRINSIC_TIMES: + case INTRINSIC_DIVIDE: + case INTRINSIC_POWER: + case INTRINSIC_CONCAT: + case INTRINSIC_AND: + case INTRINSIC_OR: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + case INTRINSIC_EQ: + case INTRINSIC_NE: + case INTRINSIC_GT: + case INTRINSIC_GE: + case INTRINSIC_LT: + case INTRINSIC_LE: + + if (op1->rank == 0 && op2->rank == 0) + e->rank = 0; + + if (op1->rank == 0 && op2->rank != 0) + { + e->rank = op2->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op2->shape, op2->rank); + } + + if (op1->rank != 0 && op2->rank == 0) + { + e->rank = op1->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op1->shape, op1->rank); + } + + if (op1->rank != 0 && op2->rank != 0) + { + if (op1->rank == op2->rank) + { + e->rank = op1->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op1->shape, op1->rank); + + } + else + { + gfc_error ("Inconsistent ranks for operator at %L and %L", + &op1->where, &op2->where); + t = FAILURE; + + /* Allow higher level expressions to work. */ + e->rank = 0; + } + } + + break; + + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + e->rank = op1->rank; + + if (e->shape == NULL) + e->shape = gfc_copy_shape (op1->shape, op1->rank); + + /* Simply copy arrayness attribute */ + break; + + default: + break; + } + + /* Attempt to simplify the expression. */ + if (t == SUCCESS) + t = gfc_simplify_expr (e, 0); + return t; + +bad_op: + if (gfc_extend_expr (e) == SUCCESS) + return SUCCESS; + + gfc_error (msg, &e->where); + return FAILURE; +} + + +/************** Array resolution subroutines **************/ + + +typedef enum +{ CMP_LT, CMP_EQ, CMP_GT, CMP_UNKNOWN } +comparison; + +/* Compare two integer expressions. */ + +static comparison +compare_bound (gfc_expr * a, gfc_expr * b) +{ + int i; + + if (a == NULL || a->expr_type != EXPR_CONSTANT + || b == NULL || b->expr_type != EXPR_CONSTANT) + return CMP_UNKNOWN; + + if (a->ts.type != BT_INTEGER || b->ts.type != BT_INTEGER) + gfc_internal_error ("compare_bound(): Bad expression"); + + i = mpz_cmp (a->value.integer, b->value.integer); + + if (i < 0) + return CMP_LT; + if (i > 0) + return CMP_GT; + return CMP_EQ; +} + + +/* Compare an integer expression with an integer. */ + +static comparison +compare_bound_int (gfc_expr * a, int b) +{ + int i; + + if (a == NULL || a->expr_type != EXPR_CONSTANT) + return CMP_UNKNOWN; + + if (a->ts.type != BT_INTEGER) + gfc_internal_error ("compare_bound_int(): Bad expression"); + + i = mpz_cmp_si (a->value.integer, b); + + if (i < 0) + return CMP_LT; + if (i > 0) + return CMP_GT; + return CMP_EQ; +} + + +/* Compare a single dimension of an array reference to the array + specification. */ + +static try +check_dimension (int i, gfc_array_ref * ar, gfc_array_spec * as) +{ + +/* Given start, end and stride values, calculate the minimum and + maximum referenced indexes. */ + + switch (ar->type) + { + case AR_FULL: + break; + + case AR_ELEMENT: + if (compare_bound (ar->start[i], as->lower[i]) == CMP_LT) + goto bound; + if (compare_bound (ar->start[i], as->upper[i]) == CMP_GT) + goto bound; + + break; + + case AR_SECTION: + if (compare_bound_int (ar->stride[i], 0) == CMP_EQ) + { + gfc_error ("Illegal stride of zero at %L", &ar->c_where[i]); + return FAILURE; + } + + if (compare_bound (ar->start[i], as->lower[i]) == CMP_LT) + goto bound; + if (compare_bound (ar->start[i], as->upper[i]) == CMP_GT) + goto bound; + + /* TODO: Possibly, we could warn about end[i] being out-of-bound although + it is legal (see 6.2.2.3.1). */ + + break; + + default: + gfc_internal_error ("check_dimension(): Bad array reference"); + } + + return SUCCESS; + +bound: + gfc_warning ("Array reference at %L is out of bounds", &ar->c_where[i]); + return SUCCESS; +} + + +/* Compare an array reference with an array specification. */ + +static try +compare_spec_to_ref (gfc_array_ref * ar) +{ + gfc_array_spec *as; + int i; + + as = ar->as; + i = as->rank - 1; + /* TODO: Full array sections are only allowed as actual parameters. */ + if (as->type == AS_ASSUMED_SIZE + && (/*ar->type == AR_FULL + ||*/ (ar->type == AR_SECTION + && ar->dimen_type[i] == DIMEN_RANGE && ar->end[i] == NULL))) + { + gfc_error ("Rightmost upper bound of assumed size array section" + " not specified at %L", &ar->where); + return FAILURE; + } + + if (ar->type == AR_FULL) + return SUCCESS; + + if (as->rank != ar->dimen) + { + gfc_error ("Rank mismatch in array reference at %L (%d/%d)", + &ar->where, ar->dimen, as->rank); + return FAILURE; + } + + for (i = 0; i < as->rank; i++) + if (check_dimension (i, ar, as) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +/* Resolve one part of an array index. */ + +try +gfc_resolve_index (gfc_expr * index, int check_scalar) +{ + gfc_typespec ts; + + if (index == NULL) + return SUCCESS; + + if (gfc_resolve_expr (index) == FAILURE) + return FAILURE; + + if (index->ts.type != BT_INTEGER) + { + gfc_error ("Array index at %L must be of INTEGER type", &index->where); + return FAILURE; + } + + if (check_scalar && index->rank != 0) + { + gfc_error ("Array index at %L must be scalar", &index->where); + return FAILURE; + } + + if (index->ts.kind != gfc_index_integer_kind) + { + ts.type = BT_INTEGER; + ts.kind = gfc_index_integer_kind; + + gfc_convert_type_warn (index, &ts, 2, 0); + } + + return SUCCESS; +} + + +/* Given an expression that contains array references, update those array + references to point to the right array specifications. While this is + filled in during matching, this information is difficult to save and load + in a module, so we take care of it here. + + The idea here is that the original array reference comes from the + base symbol. We traverse the list of reference structures, setting + the stored reference to references. Component references can + provide an additional array specification. */ + +static void +find_array_spec (gfc_expr * e) +{ + gfc_array_spec *as; + gfc_component *c; + gfc_ref *ref; + + as = e->symtree->n.sym->as; + c = e->symtree->n.sym->components; + + for (ref = e->ref; ref; ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (as == NULL) + gfc_internal_error ("find_array_spec(): Missing spec"); + + ref->u.ar.as = as; + as = NULL; + break; + + case REF_COMPONENT: + for (; c; c = c->next) + if (c == ref->u.c.component) + break; + + if (c == NULL) + gfc_internal_error ("find_array_spec(): Component not found"); + + if (c->dimension) + { + if (as != NULL) + gfc_internal_error ("find_array_spec(): unused as(1)"); + as = c->as; + } + + c = c->ts.derived->components; + break; + + case REF_SUBSTRING: + break; + } + + if (as != NULL) + gfc_internal_error ("find_array_spec(): unused as(2)"); +} + + +/* Resolve an array reference. */ + +static try +resolve_array_ref (gfc_array_ref * ar) +{ + int i, check_scalar; + + for (i = 0; i < ar->dimen; i++) + { + check_scalar = ar->dimen_type[i] == DIMEN_RANGE; + + if (gfc_resolve_index (ar->start[i], check_scalar) == FAILURE) + return FAILURE; + if (gfc_resolve_index (ar->end[i], check_scalar) == FAILURE) + return FAILURE; + if (gfc_resolve_index (ar->stride[i], check_scalar) == FAILURE) + return FAILURE; + + if (ar->dimen_type[i] == DIMEN_UNKNOWN) + switch (ar->start[i]->rank) + { + case 0: + ar->dimen_type[i] = DIMEN_ELEMENT; + break; + + case 1: + ar->dimen_type[i] = DIMEN_VECTOR; + break; + + default: + gfc_error ("Array index at %L is an array of rank %d", + &ar->c_where[i], ar->start[i]->rank); + return FAILURE; + } + } + + /* If the reference type is unknown, figure out what kind it is. */ + + if (ar->type == AR_UNKNOWN) + { + ar->type = AR_ELEMENT; + for (i = 0; i < ar->dimen; i++) + if (ar->dimen_type[i] == DIMEN_RANGE + || ar->dimen_type[i] == DIMEN_VECTOR) + { + ar->type = AR_SECTION; + break; + } + } + + if (compare_spec_to_ref (ar) == FAILURE) + return FAILURE; + + return SUCCESS; +} + + +static try +resolve_substring (gfc_ref * ref) +{ + + if (ref->u.ss.start != NULL) + { + if (gfc_resolve_expr (ref->u.ss.start) == FAILURE) + return FAILURE; + + if (ref->u.ss.start->ts.type != BT_INTEGER) + { + gfc_error ("Substring start index at %L must be of type INTEGER", + &ref->u.ss.start->where); + return FAILURE; + } + + if (ref->u.ss.start->rank != 0) + { + gfc_error ("Substring start index at %L must be scalar", + &ref->u.ss.start->where); + return FAILURE; + } + + if (compare_bound_int (ref->u.ss.start, 1) == CMP_LT) + { + gfc_error ("Substring start index at %L is less than one", + &ref->u.ss.start->where); + return FAILURE; + } + } + + if (ref->u.ss.end != NULL) + { + if (gfc_resolve_expr (ref->u.ss.end) == FAILURE) + return FAILURE; + + if (ref->u.ss.end->ts.type != BT_INTEGER) + { + gfc_error ("Substring end index at %L must be of type INTEGER", + &ref->u.ss.end->where); + return FAILURE; + } + + if (ref->u.ss.end->rank != 0) + { + gfc_error ("Substring end index at %L must be scalar", + &ref->u.ss.end->where); + return FAILURE; + } + + if (ref->u.ss.length != NULL + && compare_bound (ref->u.ss.end, ref->u.ss.length->length) == CMP_GT) + { + gfc_error ("Substring end index at %L is out of bounds", + &ref->u.ss.start->where); + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Resolve subtype references. */ + +static try +resolve_ref (gfc_expr * expr) +{ + int current_part_dimension, n_components, seen_part_dimension; + gfc_ref *ref; + + for (ref = expr->ref; ref; ref = ref->next) + if (ref->type == REF_ARRAY && ref->u.ar.as == NULL) + { + find_array_spec (expr); + break; + } + + for (ref = expr->ref; ref; ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (resolve_array_ref (&ref->u.ar) == FAILURE) + return FAILURE; + break; + + case REF_COMPONENT: + break; + + case REF_SUBSTRING: + resolve_substring (ref); + break; + } + + /* Check constraints on part references. */ + + current_part_dimension = 0; + seen_part_dimension = 0; + n_components = 0; + + for (ref = expr->ref; ref; ref = ref->next) + { + switch (ref->type) + { + case REF_ARRAY: + switch (ref->u.ar.type) + { + case AR_FULL: + case AR_SECTION: + current_part_dimension = 1; + break; + + case AR_ELEMENT: + current_part_dimension = 0; + break; + + case AR_UNKNOWN: + gfc_internal_error ("resolve_ref(): Bad array reference"); + } + + break; + + case REF_COMPONENT: + if ((current_part_dimension || seen_part_dimension) + && ref->u.c.component->pointer) + { + gfc_error + ("Component to the right of a part reference with nonzero " + "rank must not have the POINTER attribute at %L", + &expr->where); + return FAILURE; + } + + n_components++; + break; + + case REF_SUBSTRING: + break; + } + + if (((ref->type == REF_COMPONENT && n_components > 1) + || ref->next == NULL) + && current_part_dimension + && seen_part_dimension) + { + + gfc_error ("Two or more part references with nonzero rank must " + "not be specified at %L", &expr->where); + return FAILURE; + } + + if (ref->type == REF_COMPONENT) + { + if (current_part_dimension) + seen_part_dimension = 1; + + /* reset to make sure */ + current_part_dimension = 0; + } + } + + return SUCCESS; +} + + +/* Given an expression, determine its shape. This is easier than it sounds. + Leaves the shape array NULL if it is not possible to determine the shape. */ + +static void +expression_shape (gfc_expr * e) +{ + mpz_t array[GFC_MAX_DIMENSIONS]; + int i; + + if (e->rank == 0 || e->shape != NULL) + return; + + for (i = 0; i < e->rank; i++) + if (gfc_array_dimen_size (e, i, &array[i]) == FAILURE) + goto fail; + + e->shape = gfc_get_shape (e->rank); + + memcpy (e->shape, array, e->rank * sizeof (mpz_t)); + + return; + +fail: + for (i--; i >= 0; i--) + mpz_clear (array[i]); +} + + +/* Given a variable expression node, compute the rank of the expression by + examining the base symbol and any reference structures it may have. */ + +static void +expression_rank (gfc_expr * e) +{ + gfc_ref *ref; + int i, rank; + + if (e->ref == NULL) + { + if (e->expr_type == EXPR_ARRAY) + goto done; + /* Constructors can have a rank different from one via RESHAPE(). */ + + if (e->symtree == NULL) + { + e->rank = 0; + goto done; + } + + e->rank = (e->symtree->n.sym->as == NULL) + ? 0 : e->symtree->n.sym->as->rank; + goto done; + } + + rank = 0; + + for (ref = e->ref; ref; ref = ref->next) + { + if (ref->type != REF_ARRAY) + continue; + + if (ref->u.ar.type == AR_FULL) + { + rank = ref->u.ar.as->rank; + break; + } + + if (ref->u.ar.type == AR_SECTION) + { + /* Figure out the rank of the section. */ + if (rank != 0) + gfc_internal_error ("expression_rank(): Two array specs"); + + for (i = 0; i < ref->u.ar.dimen; i++) + if (ref->u.ar.dimen_type[i] == DIMEN_RANGE + || ref->u.ar.dimen_type[i] == DIMEN_VECTOR) + rank++; + + break; + } + } + + e->rank = rank; + +done: + expression_shape (e); +} + + +/* Resolve a variable expression. */ + +static try +resolve_variable (gfc_expr * e) +{ + gfc_symbol *sym; + + if (e->ref && resolve_ref (e) == FAILURE) + return FAILURE; + + sym = e->symtree->n.sym; + if (sym->attr.flavor == FL_PROCEDURE && !sym->attr.function) + { + e->ts.type = BT_PROCEDURE; + return SUCCESS; + } + + if (sym->ts.type != BT_UNKNOWN) + gfc_variable_attr (e, &e->ts); + else + { + /* Must be a simple variable reference. */ + if (gfc_set_default_type (sym, 1, NULL) == FAILURE) + return FAILURE; + e->ts = sym->ts; + } + + return SUCCESS; +} + + +/* Resolve an expression. That is, make sure that types of operands agree + with their operators, intrinsic operators are converted to function calls + for overloaded types and unresolved function references are resolved. */ + +try +gfc_resolve_expr (gfc_expr * e) +{ + try t; + + if (e == NULL) + return SUCCESS; + + switch (e->expr_type) + { + case EXPR_OP: + t = resolve_operator (e); + break; + + case EXPR_FUNCTION: + t = resolve_function (e); + break; + + case EXPR_VARIABLE: + t = resolve_variable (e); + if (t == SUCCESS) + expression_rank (e); + break; + + case EXPR_SUBSTRING: + t = resolve_ref (e); + break; + + case EXPR_CONSTANT: + case EXPR_NULL: + t = SUCCESS; + break; + + case EXPR_ARRAY: + t = FAILURE; + if (resolve_ref (e) == FAILURE) + break; + + t = gfc_resolve_array_constructor (e); + /* Also try to expand a constructor. */ + if (t == SUCCESS) + { + expression_rank (e); + gfc_expand_constructor (e); + } + + break; + + case EXPR_STRUCTURE: + t = resolve_ref (e); + if (t == FAILURE) + break; + + t = resolve_structure_cons (e); + if (t == FAILURE) + break; + + t = gfc_simplify_expr (e, 0); + break; + + default: + gfc_internal_error ("gfc_resolve_expr(): Bad expression type"); + } + + return t; +} + + +/* Resolve the expressions in an iterator structure and require that they all + be of integer type. */ + +try +gfc_resolve_iterator (gfc_iterator * iter) +{ + + if (gfc_resolve_expr (iter->var) == FAILURE) + return FAILURE; + + if (iter->var->ts.type != BT_INTEGER || iter->var->rank != 0) + { + gfc_error ("Loop variable at %L must be a scalar INTEGER", + &iter->var->where); + return FAILURE; + } + + if (gfc_pure (NULL) && gfc_impure_variable (iter->var->symtree->n.sym)) + { + gfc_error ("Cannot assign to loop variable in PURE procedure at %L", + &iter->var->where); + return FAILURE; + } + + if (gfc_resolve_expr (iter->start) == FAILURE) + return FAILURE; + + if (iter->start->ts.type != BT_INTEGER || iter->start->rank != 0) + { + gfc_error ("Start expression in DO loop at %L must be a scalar INTEGER", + &iter->start->where); + return FAILURE; + } + + if (gfc_resolve_expr (iter->end) == FAILURE) + return FAILURE; + + if (iter->end->ts.type != BT_INTEGER || iter->end->rank != 0) + { + gfc_error ("End expression in DO loop at %L must be a scalar INTEGER", + &iter->end->where); + return FAILURE; + } + + if (gfc_resolve_expr (iter->step) == FAILURE) + return FAILURE; + + if (iter->step->ts.type != BT_INTEGER || iter->step->rank != 0) + { + gfc_error ("Step expression in DO loop at %L must be a scalar INTEGER", + &iter->step->where); + return FAILURE; + } + + if (iter->step->expr_type == EXPR_CONSTANT + && mpz_cmp_ui (iter->step->value.integer, 0) == 0) + { + gfc_error ("Step expression in DO loop at %L cannot be zero", + &iter->step->where); + return FAILURE; + } + + return SUCCESS; +} + + +/* Resolve a list of FORALL iterators. */ + +static void +resolve_forall_iterators (gfc_forall_iterator * iter) +{ + + while (iter) + { + if (gfc_resolve_expr (iter->var) == SUCCESS + && iter->var->ts.type != BT_INTEGER) + gfc_error ("FORALL Iteration variable at %L must be INTEGER", + &iter->var->where); + + if (gfc_resolve_expr (iter->start) == SUCCESS + && iter->start->ts.type != BT_INTEGER) + gfc_error ("FORALL start expression at %L must be INTEGER", + &iter->start->where); + if (iter->var->ts.kind != iter->start->ts.kind) + gfc_convert_type (iter->start, &iter->var->ts, 2); + + if (gfc_resolve_expr (iter->end) == SUCCESS + && iter->end->ts.type != BT_INTEGER) + gfc_error ("FORALL end expression at %L must be INTEGER", + &iter->end->where); + if (iter->var->ts.kind != iter->end->ts.kind) + gfc_convert_type (iter->end, &iter->var->ts, 2); + + if (gfc_resolve_expr (iter->stride) == SUCCESS + && iter->stride->ts.type != BT_INTEGER) + gfc_error ("FORALL Stride expression at %L must be INTEGER", + &iter->stride->where); + if (iter->var->ts.kind != iter->stride->ts.kind) + gfc_convert_type (iter->stride, &iter->var->ts, 2); + + iter = iter->next; + } +} + + +/* Given a pointer to a symbol that is a derived type, see if any components + have the POINTER attribute. The search is recursive if necessary. + Returns zero if no pointer components are found, nonzero otherwise. */ + +static int +derived_pointer (gfc_symbol * sym) +{ + gfc_component *c; + + for (c = sym->components; c; c = c->next) + { + if (c->pointer) + return 1; + + if (c->ts.type == BT_DERIVED && derived_pointer (c->ts.derived)) + return 1; + } + + return 0; +} + + +/* Resolve the argument of a deallocate expression. The expression must be + a pointer or a full array. */ + +static try +resolve_deallocate_expr (gfc_expr * e) +{ + symbol_attribute attr; + int allocatable; + gfc_ref *ref; + + if (gfc_resolve_expr (e) == FAILURE) + return FAILURE; + + attr = gfc_expr_attr (e); + if (attr.pointer) + return SUCCESS; + + if (e->expr_type != EXPR_VARIABLE) + goto bad; + + allocatable = e->symtree->n.sym->attr.allocatable; + for (ref = e->ref; ref; ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (ref->u.ar.type != AR_FULL) + allocatable = 0; + break; + + case REF_COMPONENT: + allocatable = (ref->u.c.component->as != NULL + && ref->u.c.component->as->type == AS_DEFERRED); + break; + + case REF_SUBSTRING: + allocatable = 0; + break; + } + + if (allocatable == 0) + { + bad: + gfc_error ("Expression in DEALLOCATE statement at %L must be " + "ALLOCATABLE or a POINTER", &e->where); + } + + return SUCCESS; +} + + +/* Resolve the expression in an ALLOCATE statement, doing the additional + checks to see whether the expression is OK or not. The expression must + have a trailing array reference that gives the size of the array. */ + +static try +resolve_allocate_expr (gfc_expr * e) +{ + int i, pointer, allocatable, dimension; + symbol_attribute attr; + gfc_ref *ref, *ref2; + gfc_array_ref *ar; + + if (gfc_resolve_expr (e) == FAILURE) + return FAILURE; + + /* Make sure the expression is allocatable or a pointer. If it is + pointer, the next-to-last reference must be a pointer. */ + + ref2 = NULL; + + if (e->expr_type != EXPR_VARIABLE) + { + allocatable = 0; + + attr = gfc_expr_attr (e); + pointer = attr.pointer; + dimension = attr.dimension; + + } + else + { + allocatable = e->symtree->n.sym->attr.allocatable; + pointer = e->symtree->n.sym->attr.pointer; + dimension = e->symtree->n.sym->attr.dimension; + + for (ref = e->ref; ref; ref2 = ref, ref = ref->next) + switch (ref->type) + { + case REF_ARRAY: + if (ref->next != NULL) + pointer = 0; + break; + + case REF_COMPONENT: + allocatable = (ref->u.c.component->as != NULL + && ref->u.c.component->as->type == AS_DEFERRED); + + pointer = ref->u.c.component->pointer; + dimension = ref->u.c.component->dimension; + break; + + case REF_SUBSTRING: + allocatable = 0; + pointer = 0; + break; + } + } + + if (allocatable == 0 && pointer == 0) + { + gfc_error ("Expression in ALLOCATE statement at %L must be " + "ALLOCATABLE or a POINTER", &e->where); + return FAILURE; + } + + if (pointer && dimension == 0) + return SUCCESS; + + /* Make sure the next-to-last reference node is an array specification. */ + + if (ref2 == NULL || ref2->type != REF_ARRAY || ref2->u.ar.type == AR_FULL) + { + gfc_error ("Array specification required in ALLOCATE statement " + "at %L", &e->where); + return FAILURE; + } + + if (ref2->u.ar.type == AR_ELEMENT) + return SUCCESS; + + /* Make sure that the array section reference makes sense in the + context of an ALLOCATE specification. */ + + ar = &ref2->u.ar; + + for (i = 0; i < ar->dimen; i++) + switch (ar->dimen_type[i]) + { + case DIMEN_ELEMENT: + break; + + case DIMEN_RANGE: + if (ar->start[i] != NULL + && ar->end[i] != NULL + && ar->stride[i] == NULL) + break; + + /* Fall Through... */ + + case DIMEN_UNKNOWN: + case DIMEN_VECTOR: + gfc_error ("Bad array specification in ALLOCATE statement at %L", + &e->where); + return FAILURE; + } + + return SUCCESS; +} + + +/************ SELECT CASE resolution subroutines ************/ + +/* Callback function for our mergesort variant. Determines interval + overlaps for CASEs. Return <0 if op1 < op2, 0 for overlap, >0 for + op1 > op2. Assumes we're not dealing with the default case. */ + +static int +compare_cases (const void * _op1, const void * _op2) +{ + const gfc_case *op1, *op2; + + op1 = (const gfc_case *) _op1; + op2 = (const gfc_case *) _op2; + + if (op1->low == NULL) /* op1 = (:N) */ + { + if (op2->low == NULL) /* op2 = (:M), so overlap. */ + return 0; + + else if (op2->high == NULL) /* op2 = (M:) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* N < M */ + else + return 0; + } + + else /* op2 = (L:M) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* N < L */ + else + return 0; + } + } + + else if (op1->high == NULL) /* op1 = (N:) */ + { + if (op2->low == NULL) /* op2 = (:M) */ + { + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + else + return 0; + } + + else if (op2->high == NULL) /* op2 = (M:), so overlap. */ + return 0; + + else /* op2 = (L:M) */ + { + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + else + return 0; + } + } + + else /* op1 = (N:P) */ + { + if (op2->low == NULL) /* op2 = (:M) */ + { + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + else + return 0; + } + + else if (op2->high == NULL) /* op2 = (M:) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* P < M */ + else + return 0; + } + + else /* op2 = (L:M) */ + { + if (gfc_compare_expr (op1->high, op2->low) < 0) + return -1; /* P < L */ + + if (gfc_compare_expr (op1->low, op2->high) > 0) + return 1; /* N > M */ + + return 0; + } + } +} + + +/* Merge-sort a double linked case list, detecting overlap in the + process. LIST is the head of the double linked case list before it + is sorted. Returns the head of the sorted list if we don't see any + overlap, or NULL otherwise. */ + +static gfc_case * +check_case_overlap (gfc_case * list) +{ + gfc_case *p, *q, *e, *tail; + int insize, nmerges, psize, qsize, cmp, overlap_seen; + + /* If the passed list was empty, return immediately. */ + if (!list) + return NULL; + + overlap_seen = 0; + insize = 1; + + /* Loop unconditionally. The only exit from this loop is a return + statement, when we've finished sorting the case list. */ + for (;;) + { + p = list; + list = NULL; + tail = NULL; + + /* Count the number of merges we do in this pass. */ + nmerges = 0; + + /* Loop while there exists a merge to be done. */ + while (p) + { + int i; + + /* Count this merge. */ + nmerges++; + + /* Cut the list in two pieces by steppin INSIZE places + forward in the list, starting from P. */ + psize = 0; + q = p; + for (i = 0; i < insize; i++) + { + psize++; + q = q->right; + if (!q) + break; + } + qsize = insize; + + /* Now we have two lists. Merge them! */ + while (psize > 0 || (qsize > 0 && q != NULL)) + { + + /* See from which the next case to merge comes from. */ + if (psize == 0) + { + /* P is empty so the next case must come from Q. */ + e = q; + q = q->right; + qsize--; + } + else if (qsize == 0 || q == NULL) + { + /* Q is empty. */ + e = p; + p = p->right; + psize--; + } + else + { + cmp = compare_cases (p, q); + if (cmp < 0) + { + /* The whole case range for P is less than the + one for Q. */ + e = p; + p = p->right; + psize--; + } + else if (cmp > 0) + { + /* The whole case range for Q is greater than + the case range for P. */ + e = q; + q = q->right; + qsize--; + } + else + { + /* The cases overlap, or they are the same + element in the list. Either way, we must + issue an error and get the next case from P. */ + /* FIXME: Sort P and Q by line number. */ + gfc_error ("CASE label at %L overlaps with CASE " + "label at %L", &p->where, &q->where); + overlap_seen = 1; + e = p; + p = p->right; + psize--; + } + } + + /* Add the next element to the merged list. */ + if (tail) + tail->right = e; + else + list = e; + e->left = tail; + tail = e; + } + + /* P has now stepped INSIZE places along, and so has Q. So + they're the same. */ + p = q; + } + tail->right = NULL; + + /* If we have done only one merge or none at all, we've + finished sorting the cases. */ + if (nmerges <= 1) + { + if (!overlap_seen) + return list; + else + return NULL; + } + + /* Otherwise repeat, merging lists twice the size. */ + insize *= 2; + } +} + + +/* Check to see if an expression is suitable for use in a CASE + statement. Makes sure that all case expressions are scalar + constants of the same type/kind. Return FAILURE if anything + is wrong. */ + +static try +validate_case_label_expr (gfc_expr * e, gfc_expr * case_expr) +{ + gfc_typespec case_ts = case_expr->ts; + + if (e == NULL) return SUCCESS; + + if (e->expr_type != EXPR_CONSTANT) + { + gfc_error ("Expression in CASE statement at %L must be a constant", + &e->where); + return FAILURE; + } + + if (e->ts.type != case_ts.type) + { + gfc_error ("Expression in CASE statement at %L must be of type %s", + &e->where, gfc_basic_typename (case_ts.type)); + return FAILURE; + } + + if (e->ts.kind != case_ts.kind) + { + gfc_error("Expression in CASE statement at %L must be kind %d", + &e->where, case_ts.kind); + return FAILURE; + } + + if (e->rank != 0) + { + gfc_error ("Expression in CASE statement at %L must be scalar", + &e->where); + return FAILURE; + } + + return SUCCESS; +} + + +/* Given a completely parsed select statement, we: + + - Validate all expressions and code within the SELECT. + - Make sure that the selection expression is not of the wrong type. + - Make sure that no case ranges overlap. + - Eliminate unreachable cases and unreachable code resulting from + removing case labels. + + The standard does allow unreachable cases, e.g. CASE (5:3). But + they are a hassle for code generation, and to prevent that, we just + cut them out here. This is not necessary for overlapping cases + because they are illegal and we never even try to generate code. + + We have the additional caveat that a SELECT construct could have + been a computed GOTO in the source code. Furtunately we can fairly + easily work around that here: The case_expr for a "real" SELECT CASE + is in code->expr1, but for a computed GOTO it is in code->expr2. All + we have to do is make sure that the case_expr is a scalar integer + expression. */ + +static void +resolve_select (gfc_code * code) +{ + gfc_code *body; + gfc_expr *case_expr; + gfc_case *cp, *default_case, *tail, *head; + int seen_unreachable; + int ncases; + bt type; + try t; + + if (code->expr == NULL) + { + /* This was actually a computed GOTO statement. */ + case_expr = code->expr2; + if (case_expr->ts.type != BT_INTEGER + || case_expr->rank != 0) + gfc_error ("Selection expression in computed GOTO statement " + "at %L must be a scalar integer expression", + &case_expr->where); + + /* Further checking is not necessary because this SELECT was built + by the compiler, so it should always be OK. Just move the + case_expr from expr2 to expr so that we can handle computed + GOTOs as normal SELECTs from here on. */ + code->expr = code->expr2; + code->expr2 = NULL; + return; + } + + case_expr = code->expr; + + type = case_expr->ts.type; + if (type != BT_LOGICAL && type != BT_INTEGER && type != BT_CHARACTER) + { + gfc_error ("Argument of SELECT statement at %L cannot be %s", + &case_expr->where, gfc_typename (&case_expr->ts)); + + /* Punt. Going on here just produce more garbage error messages. */ + return; + } + + if (case_expr->rank != 0) + { + gfc_error ("Argument of SELECT statement at %L must be a scalar " + "expression", &case_expr->where); + + /* Punt. */ + return; + } + + /* Assume there is no DEFAULT case. */ + default_case = NULL; + head = tail = NULL; + ncases = 0; + + for (body = code->block; body; body = body->block) + { + /* Assume the CASE list is OK, and all CASE labels can be matched. */ + t = SUCCESS; + seen_unreachable = 0; + + /* Walk the case label list, making sure that all case labels + are legal. */ + for (cp = body->ext.case_list; cp; cp = cp->next) + { + /* Count the number of cases in the whole construct. */ + ncases++; + + /* Intercept the DEFAULT case. */ + if (cp->low == NULL && cp->high == NULL) + { + if (default_case != NULL) + { + gfc_error ("The DEFAULT CASE at %L cannot be followed " + "by a second DEFAULT CASE at %L", + &default_case->where, &cp->where); + t = FAILURE; + break; + } + else + { + default_case = cp; + continue; + } + } + + /* Deal with single value cases and case ranges. Errors are + issued from the validation function. */ + if(validate_case_label_expr (cp->low, case_expr) != SUCCESS + || validate_case_label_expr (cp->high, case_expr) != SUCCESS) + { + t = FAILURE; + break; + } + + if (type == BT_LOGICAL + && ((cp->low == NULL || cp->high == NULL) + || cp->low != cp->high)) + { + gfc_error + ("Logical range in CASE statement at %L is not allowed", + &cp->low->where); + t = FAILURE; + break; + } + + if (cp->low != NULL && cp->high != NULL + && cp->low != cp->high + && gfc_compare_expr (cp->low, cp->high) > 0) + { + if (gfc_option.warn_surprising) + gfc_warning ("Range specification at %L can never " + "be matched", &cp->where); + + cp->unreachable = 1; + seen_unreachable = 1; + } + else + { + /* If the case range can be matched, it can also overlap with + other cases. To make sure it does not, we put it in a + double linked list here. We sort that with a merge sort + later on to detect any overlapping cases. */ + if (!head) + { + head = tail = cp; + head->right = head->left = NULL; + } + else + { + tail->right = cp; + tail->right->left = tail; + tail = tail->right; + tail->right = NULL; + } + } + } + + /* It there was a failure in the previous case label, give up + for this case label list. Continue with the next block. */ + if (t == FAILURE) + continue; + + /* See if any case labels that are unreachable have been seen. + If so, we eliminate them. This is a bit of a kludge because + the case lists for a single case statement (label) is a + single forward linked lists. */ + if (seen_unreachable) + { + /* Advance until the first case in the list is reachable. */ + while (body->ext.case_list != NULL + && body->ext.case_list->unreachable) + { + gfc_case *n = body->ext.case_list; + body->ext.case_list = body->ext.case_list->next; + n->next = NULL; + gfc_free_case_list (n); + } + + /* Strip all other unreachable cases. */ + if (body->ext.case_list) + { + for (cp = body->ext.case_list; cp->next; cp = cp->next) + { + if (cp->next->unreachable) + { + gfc_case *n = cp->next; + cp->next = cp->next->next; + n->next = NULL; + gfc_free_case_list (n); + } + } + } + } + } + + /* See if there were overlapping cases. If the check returns NULL, + there was overlap. In that case we don't do anything. If head + is non-NULL, we prepend the DEFAULT case. The sorted list can + then used during code generation for SELECT CASE constructs with + a case expression of a CHARACTER type. */ + if (head) + { + head = check_case_overlap (head); + + /* Prepend the default_case if it is there. */ + if (head != NULL && default_case) + { + default_case->left = NULL; + default_case->right = head; + head->left = default_case; + } + } + + /* Eliminate dead blocks that may be the result if we've seen + unreachable case labels for a block. */ + for (body = code; body && body->block; body = body->block) + { + if (body->block->ext.case_list == NULL) + { + /* Cut the unreachable block from the code chain. */ + gfc_code *c = body->block; + body->block = c->block; + + /* Kill the dead block, but not the blocks below it. */ + c->block = NULL; + gfc_free_statements (c); + } + } + + /* More than two cases is legal but insane for logical selects. + Issue a warning for it. */ + if (gfc_option.warn_surprising && type == BT_LOGICAL + && ncases > 2) + gfc_warning ("Logical SELECT CASE block at %L has more that two cases", + &code->loc); +} + + +/*********** Toplevel code resolution subroutines ***********/ + +/* Given a branch to a label and a namespace, if the branch is conforming. + The code node described where the branch is located. */ + +static void +resolve_branch (gfc_st_label * label, gfc_code * code) +{ + gfc_code *block, *found; + code_stack *stack; + gfc_st_label *lp; + + if (label == NULL) + return; + lp = label; + + /* Step one: is this a valid branching target? */ + + if (lp->defined == ST_LABEL_UNKNOWN) + { + gfc_error ("Label %d referenced at %L is never defined", lp->value, + &lp->where); + return; + } + + if (lp->defined != ST_LABEL_TARGET) + { + gfc_error ("Statement at %L is not a valid branch target statement " + "for the branch statement at %L", &lp->where, &code->loc); + return; + } + + /* Step two: make sure this branch is not a branch to itself ;-) */ + + if (code->here == label) + { + gfc_warning ("Branch at %L causes an infinite loop", &code->loc); + return; + } + + /* Step three: Try to find the label in the parse tree. To do this, + we traverse the tree block-by-block: first the block that + contains this GOTO, then the block that it is nested in, etc. We + can ignore other blocks because branching into another block is + not allowed. */ + + found = NULL; + + for (stack = cs_base; stack; stack = stack->prev) + { + for (block = stack->head; block; block = block->next) + { + if (block->here == label) + { + found = block; + break; + } + } + + if (found) + break; + } + + if (found == NULL) + { + /* still nothing, so illegal. */ + gfc_error_now ("Label at %L is not in the same block as the " + "GOTO statement at %L", &lp->where, &code->loc); + return; + } + + /* Step four: Make sure that the branching target is legal if + the statement is an END {SELECT,DO,IF}. */ + + if (found->op == EXEC_NOP) + { + for (stack = cs_base; stack; stack = stack->prev) + if (stack->current->next == found) + break; + + if (stack == NULL) + gfc_notify_std (GFC_STD_F95_DEL, + "Obsolete: GOTO at %L jumps to END of construct at %L", + &code->loc, &found->loc); + } +} + + +/* Check whether EXPR1 has the same shape as EXPR2. */ + +static try +resolve_where_shape (gfc_expr *expr1, gfc_expr *expr2) +{ + mpz_t shape[GFC_MAX_DIMENSIONS]; + mpz_t shape2[GFC_MAX_DIMENSIONS]; + try result = FAILURE; + int i; + + /* Compare the rank. */ + if (expr1->rank != expr2->rank) + return result; + + /* Compare the size of each dimension. */ + for (i=0; irank; i++) + { + if (gfc_array_dimen_size (expr1, i, &shape[i]) == FAILURE) + goto ignore; + + if (gfc_array_dimen_size (expr2, i, &shape2[i]) == FAILURE) + goto ignore; + + if (mpz_cmp (shape[i], shape2[i])) + goto over; + } + + /* When either of the two expression is an assumed size array, we + ignore the comparison of dimension sizes. */ +ignore: + result = SUCCESS; + +over: + for (i--; i>=0; i--) + { + mpz_clear (shape[i]); + mpz_clear (shape2[i]); + } + return result; +} + + +/* Check whether a WHERE assignment target or a WHERE mask expression + has the same shape as the outmost WHERE mask expression. */ + +static void +resolve_where (gfc_code *code, gfc_expr *mask) +{ + gfc_code *cblock; + gfc_code *cnext; + gfc_expr *e = NULL; + + cblock = code->block; + + /* Store the first WHERE mask-expr of the WHERE statement or construct. + In case of nested WHERE, only the outmost one is stored. */ + if (mask == NULL) /* outmost WHERE */ + e = cblock->expr; + else /* inner WHERE */ + e = mask; + + while (cblock) + { + if (cblock->expr) + { + /* Check if the mask-expr has a consistent shape with the + outmost WHERE mask-expr. */ + if (resolve_where_shape (cblock->expr, e) == FAILURE) + gfc_error ("WHERE mask at %L has inconsistent shape", + &cblock->expr->where); + } + + /* the assignment statement of a WHERE statement, or the first + statement in where-body-construct of a WHERE construct */ + cnext = cblock->next; + while (cnext) + { + switch (cnext->op) + { + /* WHERE assignment statement */ + case EXEC_ASSIGN: + + /* Check shape consistent for WHERE assignment target. */ + if (e && resolve_where_shape (cnext->expr, e) == FAILURE) + gfc_error ("WHERE assignment target at %L has " + "inconsistent shape", &cnext->expr->where); + break; + + /* WHERE or WHERE construct is part of a where-body-construct */ + case EXEC_WHERE: + resolve_where (cnext, e); + break; + + default: + gfc_error ("Unsupported statement inside WHERE at %L", + &cnext->loc); + } + /* the next statement within the same where-body-construct */ + cnext = cnext->next; + } + /* the next masked-elsewhere-stmt, elsewhere-stmt, or end-where-stmt */ + cblock = cblock->block; + } +} + + +/* Check whether the FORALL index appears in the expression or not. */ + +static try +gfc_find_forall_index (gfc_expr *expr, gfc_symbol *symbol) +{ + gfc_array_ref ar; + gfc_ref *tmp; + gfc_actual_arglist *args; + int i; + + switch (expr->expr_type) + { + case EXPR_VARIABLE: + assert (expr->symtree->n.sym); + + /* A scalar assignment */ + if (!expr->ref) + { + if (expr->symtree->n.sym == symbol) + return SUCCESS; + else + return FAILURE; + } + + /* the expr is array ref, substring or struct component. */ + tmp = expr->ref; + while (tmp != NULL) + { + switch (tmp->type) + { + case REF_ARRAY: + /* Check if the symbol appears in the array subscript. */ + ar = tmp->u.ar; + for (i = 0; i < GFC_MAX_DIMENSIONS; i++) + { + if (ar.start[i]) + if (gfc_find_forall_index (ar.start[i], symbol) == SUCCESS) + return SUCCESS; + + if (ar.end[i]) + if (gfc_find_forall_index (ar.end[i], symbol) == SUCCESS) + return SUCCESS; + + if (ar.stride[i]) + if (gfc_find_forall_index (ar.stride[i], symbol) == SUCCESS) + return SUCCESS; + } /* end for */ + break; + + case REF_SUBSTRING: + if (expr->symtree->n.sym == symbol) + return SUCCESS; + tmp = expr->ref; + /* Check if the symbol appears in the substring section. */ + if (gfc_find_forall_index (tmp->u.ss.start, symbol) == SUCCESS) + return SUCCESS; + if (gfc_find_forall_index (tmp->u.ss.end, symbol) == SUCCESS) + return SUCCESS; + break; + + case REF_COMPONENT: + break; + + default: + gfc_error("expresion reference type error at %L", &expr->where); + } + tmp = tmp->next; + } + break; + + /* If the expression is a function call, then check if the symbol + appears in the actual arglist of the function. */ + case EXPR_FUNCTION: + for (args = expr->value.function.actual; args; args = args->next) + { + if (gfc_find_forall_index(args->expr,symbol) == SUCCESS) + return SUCCESS; + } + break; + + /* It seems not to happen. */ + case EXPR_SUBSTRING: + if (expr->ref) + { + tmp = expr->ref; + assert(expr->ref->type == REF_SUBSTRING); + if (gfc_find_forall_index (tmp->u.ss.start, symbol) == SUCCESS) + return SUCCESS; + if (gfc_find_forall_index (tmp->u.ss.end, symbol) == SUCCESS) + return SUCCESS; + } + break; + + /* It seems not to happen. */ + case EXPR_STRUCTURE: + case EXPR_ARRAY: + gfc_error ("Unsupported statement while finding forall index in " + "expression"); + break; + default: + break; + } + + /* Find the FORALL index in the first operand. */ + if (expr->op1) + { + if (gfc_find_forall_index (expr->op1, symbol) == SUCCESS) + return SUCCESS; + } + + /* Find the FORALL index in the second operand. */ + if (expr->op2) + { + if (gfc_find_forall_index (expr->op2, symbol) == SUCCESS) + return SUCCESS; + } + return FAILURE; +} + + +/* Resolve assignment in FORALL construct. + NVAR is the number of FORALL index variables, and VAR_EXPR records the + FORALL index variables. */ + +static void +gfc_resolve_assign_in_forall (gfc_code *code, int nvar, gfc_expr **var_expr) +{ + int n; + + for (n = 0; n < nvar; n++) + { + gfc_symbol *forall_index; + + forall_index = var_expr[n]->symtree->n.sym; + + /* Check whether the assignment target is one of the FORALL index + variable. */ + if ((code->expr->expr_type == EXPR_VARIABLE) + && (code->expr->symtree->n.sym == forall_index)) + gfc_error ("Assignment to a FORALL index variable at %L", + &code->expr->where); + else + { + /* If one of the FORALL index variables doesn't appear in the + assignment target, then there will be a many-to-one + assignment. */ + if (gfc_find_forall_index (code->expr, forall_index) == FAILURE) + gfc_error ("The FORALL with index '%s' cause more than one " + "assignment to this object at %L", + var_expr[n]->symtree->name, &code->expr->where); + } + } +} + + +/* Resolve WHERE statement in FORALL construct. */ + +static void +gfc_resolve_where_code_in_forall (gfc_code *code, int nvar, gfc_expr **var_expr){ + gfc_code *cblock; + gfc_code *cnext; + + cblock = code->block; + while (cblock) + { + /* the assignment statement of a WHERE statement, or the first + statement in where-body-construct of a WHERE construct */ + cnext = cblock->next; + while (cnext) + { + switch (cnext->op) + { + /* WHERE assignment statement */ + case EXEC_ASSIGN: + gfc_resolve_assign_in_forall (cnext, nvar, var_expr); + break; + + /* WHERE or WHERE construct is part of a where-body-construct */ + case EXEC_WHERE: + gfc_resolve_where_code_in_forall (cnext, nvar, var_expr); + break; + + default: + gfc_error ("Unsupported statement inside WHERE at %L", + &cnext->loc); + } + /* the next statement within the same where-body-construct */ + cnext = cnext->next; + } + /* the next masked-elsewhere-stmt, elsewhere-stmt, or end-where-stmt */ + cblock = cblock->block; + } +} + + +/* Traverse the FORALL body to check whether the following errors exist: + 1. For assignment, check if a many-to-one assignment happens. + 2. For WHERE statement, check the WHERE body to see if there is any + many-to-one assignment. */ + +static void +gfc_resolve_forall_body (gfc_code *code, int nvar, gfc_expr **var_expr) +{ + gfc_code *c; + + c = code->block->next; + while (c) + { + switch (c->op) + { + case EXEC_ASSIGN: + case EXEC_POINTER_ASSIGN: + gfc_resolve_assign_in_forall (c, nvar, var_expr); + break; + + /* Because the resolve_blocks() will handle the nested FORALL, + there is no need to handle it here. */ + case EXEC_FORALL: + break; + case EXEC_WHERE: + gfc_resolve_where_code_in_forall(c, nvar, var_expr); + break; + default: + break; + } + /* The next statement in the FORALL body. */ + c = c->next; + } +} + + +/* Given a FORALL construct, first resolve the FORALL iterator, then call + gfc_resolve_forall_body to resolve the FORALL body. */ + +static void resolve_blocks (gfc_code *, gfc_namespace *); + +static void +gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save) +{ + static gfc_expr **var_expr; + static int total_var = 0; + static int nvar = 0; + gfc_forall_iterator *fa; + gfc_symbol *forall_index; + gfc_code *next; + int i; + + /* Start to resolve a FORALL construct */ + if (forall_save == 0) + { + /* Count the total number of FORALL index in the nested FORALL + construct in order to allocate the VAR_EXPR with proper size. */ + next = code; + while ((next != NULL) && (next->op == EXEC_FORALL)) + { + for (fa = next->ext.forall_iterator; fa; fa = fa->next) + total_var ++; + next = next->block->next; + } + + /* allocate VAR_EXPR with NUMBER_OF_FORALL_INDEX elements. */ + var_expr = (gfc_expr **) gfc_getmem (total_var * sizeof (gfc_expr *)); + } + + /* The information about FORALL iterator, including FORALL index start, end + and stride. The FORALL index can not appear in start, end or stride. */ + for (fa = code->ext.forall_iterator; fa; fa = fa->next) + { + /* Check if any outer FORALL index name is the same as the current + one. */ + for (i = 0; i < nvar; i++) + { + if (fa->var->symtree->n.sym == var_expr[i]->symtree->n.sym) + { + gfc_error ("An outer FORALL construct already has an index " + "with this name %L", &fa->var->where); + } + } + + /* Record the current FORALL index. */ + var_expr[nvar] = gfc_copy_expr (fa->var); + + forall_index = fa->var->symtree->n.sym; + + /* Check if the FORALL index appears in start, end or stride. */ + if (gfc_find_forall_index (fa->start, forall_index) == SUCCESS) + gfc_error ("A FORALL index must not appear in a limit or stride " + "expression in the same FORALL at %L", &fa->start->where); + if (gfc_find_forall_index (fa->end, forall_index) == SUCCESS) + gfc_error ("A FORALL index must not appear in a limit or stride " + "expression in the same FORALL at %L", &fa->end->where); + if (gfc_find_forall_index (fa->stride, forall_index) == SUCCESS) + gfc_error ("A FORALL index must not appear in a limit or stride " + "expression in the same FORALL at %L", &fa->stride->where); + nvar++; + } + + /* Resolve the FORALL body. */ + gfc_resolve_forall_body (code, nvar, var_expr); + + /* May call gfc_resolve_forall to resolve the inner FORALL loop. */ + resolve_blocks (code->block, ns); + + /* Free VAR_EXPR after the whole FORALL construct resolved. */ + for (i = 0; i < total_var; i++) + gfc_free_expr (var_expr[i]); + + /* Reset the counters. */ + total_var = 0; + nvar = 0; +} + + +/* Resolve lists of blocks found in IF, SELECT CASE, WHERE, FORALL ,GOTO and + DO code nodes. */ + +static void resolve_code (gfc_code *, gfc_namespace *); + +static void +resolve_blocks (gfc_code * b, gfc_namespace * ns) +{ + try t; + + for (; b; b = b->block) + { + t = gfc_resolve_expr (b->expr); + if (gfc_resolve_expr (b->expr2) == FAILURE) + t = FAILURE; + + switch (b->op) + { + case EXEC_IF: + if (t == SUCCESS && b->expr != NULL + && (b->expr->ts.type != BT_LOGICAL || b->expr->rank != 0)) + gfc_error + ("ELSE IF clause at %L requires a scalar LOGICAL expression", + &b->expr->where); + break; + + case EXEC_WHERE: + if (t == SUCCESS + && b->expr != NULL + && (b->expr->ts.type != BT_LOGICAL + || b->expr->rank == 0)) + gfc_error + ("WHERE/ELSEWHERE clause at %L requires a LOGICAL array", + &b->expr->where); + break; + + case EXEC_GOTO: + resolve_branch (b->label, b); + break; + + case EXEC_SELECT: + case EXEC_FORALL: + case EXEC_DO: + case EXEC_DO_WHILE: + break; + + default: + gfc_internal_error ("resolve_block(): Bad block type"); + } + + resolve_code (b->next, ns); + } +} + + +/* Given a block of code, recursively resolve everything pointed to by this + code block. */ + +static void +resolve_code (gfc_code * code, gfc_namespace * ns) +{ + int forall_save = 0; + code_stack frame; + gfc_alloc *a; + try t; + + frame.prev = cs_base; + frame.head = code; + cs_base = &frame; + + for (; code; code = code->next) + { + frame.current = code; + + if (code->op == EXEC_FORALL) + { + forall_save = forall_flag; + forall_flag = 1; + gfc_resolve_forall (code, ns, forall_save); + } + else + resolve_blocks (code->block, ns); + + if (code->op == EXEC_FORALL) + forall_flag = forall_save; + + t = gfc_resolve_expr (code->expr); + if (gfc_resolve_expr (code->expr2) == FAILURE) + t = FAILURE; + + switch (code->op) + { + case EXEC_NOP: + case EXEC_CYCLE: + case EXEC_IOLENGTH: + case EXEC_PAUSE: + case EXEC_STOP: + case EXEC_EXIT: + case EXEC_CONTINUE: + case EXEC_DT_END: + case EXEC_TRANSFER: + break; + + case EXEC_WHERE: + resolve_where (code, NULL); + break; + + case EXEC_GOTO: + if (code->expr != NULL && code->expr->ts.type != BT_INTEGER) + gfc_error ("ASSIGNED GOTO statement at %L requires an INTEGER " + "variable", &code->expr->where); + else + resolve_branch (code->label, code); + break; + + case EXEC_RETURN: + if (code->expr != NULL && code->expr->ts.type != BT_INTEGER) + gfc_error ("Alternate RETURN statement at %L requires an INTEGER " + "return specifier", &code->expr->where); + break; + + case EXEC_ASSIGN: + if (t == FAILURE) + break; + + if (gfc_extend_assign (code, ns) == SUCCESS) + goto call; + + if (gfc_pure (NULL)) + { + if (gfc_impure_variable (code->expr->symtree->n.sym)) + { + gfc_error + ("Cannot assign to variable '%s' in PURE procedure at %L", + code->expr->symtree->n.sym->name, &code->expr->where); + break; + } + + if (code->expr2->ts.type == BT_DERIVED + && derived_pointer (code->expr2->ts.derived)) + { + gfc_error + ("Right side of assignment at %L is a derived type " + "containing a POINTER in a PURE procedure", + &code->expr2->where); + break; + } + } + + gfc_check_assign (code->expr, code->expr2, 1); + break; + + case EXEC_LABEL_ASSIGN: + if (code->label->defined == ST_LABEL_UNKNOWN) + gfc_error ("Label %d referenced at %L is never defined", + code->label->value, &code->label->where); + if (t == SUCCESS && code->expr->ts.type != BT_INTEGER) + gfc_error ("ASSIGN statement at %L requires an INTEGER " + "variable", &code->expr->where); + break; + + case EXEC_POINTER_ASSIGN: + if (t == FAILURE) + break; + + gfc_check_pointer_assign (code->expr, code->expr2); + break; + + case EXEC_ARITHMETIC_IF: + if (t == SUCCESS + && code->expr->ts.type != BT_INTEGER + && code->expr->ts.type != BT_REAL) + gfc_error ("Arithmetic IF statement at %L requires a numeric " + "expression", &code->expr->where); + + resolve_branch (code->label, code); + resolve_branch (code->label2, code); + resolve_branch (code->label3, code); + break; + + case EXEC_IF: + if (t == SUCCESS && code->expr != NULL + && (code->expr->ts.type != BT_LOGICAL + || code->expr->rank != 0)) + gfc_error ("IF clause at %L requires a scalar LOGICAL expression", + &code->expr->where); + break; + + case EXEC_CALL: + call: + resolve_call (code); + break; + + case EXEC_SELECT: + /* Select is complicated. Also, a SELECT construct could be + a transformed computed GOTO. */ + resolve_select (code); + break; + + case EXEC_DO: + if (code->ext.iterator != NULL) + gfc_resolve_iterator (code->ext.iterator); + break; + + case EXEC_DO_WHILE: + if (code->expr == NULL) + gfc_internal_error ("resolve_code(): No expression on DO WHILE"); + if (t == SUCCESS + && (code->expr->rank != 0 + || code->expr->ts.type != BT_LOGICAL)) + gfc_error ("Exit condition of DO WHILE loop at %L must be " + "a scalar LOGICAL expression", &code->expr->where); + break; + + case EXEC_ALLOCATE: + if (t == SUCCESS && code->expr != NULL + && code->expr->ts.type != BT_INTEGER) + gfc_error ("STAT tag in ALLOCATE statement at %L must be " + "of type INTEGER", &code->expr->where); + + for (a = code->ext.alloc_list; a; a = a->next) + resolve_allocate_expr (a->expr); + + break; + + case EXEC_DEALLOCATE: + if (t == SUCCESS && code->expr != NULL + && code->expr->ts.type != BT_INTEGER) + gfc_error + ("STAT tag in DEALLOCATE statement at %L must be of type " + "INTEGER", &code->expr->where); + + for (a = code->ext.alloc_list; a; a = a->next) + resolve_deallocate_expr (a->expr); + + break; + + case EXEC_OPEN: + if (gfc_resolve_open (code->ext.open) == FAILURE) + break; + + resolve_branch (code->ext.open->err, code); + break; + + case EXEC_CLOSE: + if (gfc_resolve_close (code->ext.close) == FAILURE) + break; + + resolve_branch (code->ext.close->err, code); + break; + + case EXEC_BACKSPACE: + case EXEC_ENDFILE: + case EXEC_REWIND: + if (gfc_resolve_filepos (code->ext.filepos) == FAILURE) + break; + + resolve_branch (code->ext.filepos->err, code); + break; + + case EXEC_INQUIRE: + if (gfc_resolve_inquire (code->ext.inquire) == FAILURE) + break; + + resolve_branch (code->ext.inquire->err, code); + break; + + case EXEC_READ: + case EXEC_WRITE: + if (gfc_resolve_dt (code->ext.dt) == FAILURE) + break; + + resolve_branch (code->ext.dt->err, code); + resolve_branch (code->ext.dt->end, code); + resolve_branch (code->ext.dt->eor, code); + break; + + case EXEC_FORALL: + resolve_forall_iterators (code->ext.forall_iterator); + + if (code->expr != NULL && code->expr->ts.type != BT_LOGICAL) + gfc_error + ("FORALL mask clause at %L requires a LOGICAL expression", + &code->expr->where); + break; + + default: + gfc_internal_error ("resolve_code(): Bad statement code"); + } + } + + cs_base = frame.prev; +} + + +/* Resolve initial values and make sure they are compatible with + the variable. */ + +static void +resolve_values (gfc_symbol * sym) +{ + + if (sym->value == NULL) + return; + + if (gfc_resolve_expr (sym->value) == FAILURE) + return; + + gfc_check_assign_symbol (sym, sym->value); +} + + +/* Do anything necessary to resolve a symbol. Right now, we just + assume that an otherwise unknown symbol is a variable. This sort + of thing commonly happens for symbols in module. */ + +static void +resolve_symbol (gfc_symbol * sym) +{ + /* Zero if we are checking a formal namespace. */ + static int formal_ns_flag = 1; + int formal_ns_save, check_constant, mp_flag; + + if (sym->attr.flavor == FL_UNKNOWN) + { + if (sym->attr.external == 0 && sym->attr.intrinsic == 0) + sym->attr.flavor = FL_VARIABLE; + else + { + sym->attr.flavor = FL_PROCEDURE; + if (sym->attr.dimension) + sym->attr.function = 1; + } + } + + /* Symbols that are module procedures with results (functions) have + the types and array specification copied for type checking in + procedures that call them, as well as for saving to a module + file. These symbols can't stand the scrutiny that their results + can. */ + mp_flag = (sym->result != NULL && sym->result != sym); + + /* Assign default type to symbols that need one and don't have one. */ + if (sym->ts.type == BT_UNKNOWN) + { + if (sym->attr.flavor == FL_VARIABLE || sym->attr.flavor == FL_PARAMETER) + gfc_set_default_type (sym, 0, NULL); + + if (sym->attr.flavor == FL_PROCEDURE && sym->attr.function) + { + if (!mp_flag) + gfc_set_default_type (sym, 0, NULL); + else + { + /* Result may be in another namespace. */ + resolve_symbol (sym->result); + + sym->ts = sym->result->ts; + sym->as = gfc_copy_array_spec (sym->result->as); + } + } + } + + if (sym->as != NULL + && (sym->as->type == AS_ASSUMED_SIZE + || sym->as->type == AS_ASSUMED_SHAPE) + && sym->attr.dummy == 0) + { + gfc_error("Assumed %s array at %L must be a dummy argument", + sym->as->type == AS_ASSUMED_SIZE ? "size" : "shape", + &sym->declared_at); + return; + } + + /* Make sure that character string variables with assumed length are + dummy argument. */ + + if (sym->attr.flavor == FL_VARIABLE && !sym->attr.result + && sym->ts.type == BT_CHARACTER + && sym->ts.cl->length == NULL && sym->attr.dummy == 0) + { + gfc_error ("Entity with assumed character length at %L must be a " + "dummy argument or a PARAMETER", &sym->declared_at); + return; + } + + /* Make sure a parameter that has been implicitly typed still + matches the implicit type, since PARAMETER statements can precede + IMPLICIT statements. */ + + if (sym->attr.flavor == FL_PARAMETER + && sym->attr.implicit_type + && !gfc_compare_types (&sym->ts, gfc_get_default_type (sym, sym->ns))) + gfc_error ("Implicitly typed PARAMETER '%s' at %L doesn't match a " + "later IMPLICIT type", sym->name, &sym->declared_at); + + /* Make sure the types of derived parameters are consistent. This + type checking is deferred until resolution because the type may + refer to a derived type from the host. */ + + if (sym->attr.flavor == FL_PARAMETER + && sym->ts.type == BT_DERIVED + && !gfc_compare_types (&sym->ts, &sym->value->ts)) + gfc_error ("Incompatible derived type in PARAMETER at %L", + &sym->value->where); + + /* Make sure symbols with known intent or optional are really dummy + variable. Because of ENTRY statement, this has to be deferred + until resolution time. */ + + if (! sym->attr.dummy + && (sym->attr.optional + || sym->attr.intent != INTENT_UNKNOWN)) + { + gfc_error ("Symbol at %L is not a DUMMY variable", &sym->declared_at); + return; + } + + if (sym->attr.proc == PROC_ST_FUNCTION) + { + if (sym->ts.type == BT_CHARACTER) + { + gfc_charlen *cl = sym->ts.cl; + if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT) + { + gfc_error ("Character-valued statement function '%s' at %L must " + "have constant length", sym->name, &sym->declared_at); + return; + } + } + } + + /* Constraints on deferred shape variable. */ + if (sym->attr.flavor == FL_VARIABLE + || (sym->attr.flavor == FL_PROCEDURE + && sym->attr.function)) + { + if (sym->as == NULL || sym->as->type != AS_DEFERRED) + { + if (sym->attr.allocatable) + { + if (sym->attr.dimension) + gfc_error ("Allocatable array at %L must have a deferred shape", + &sym->declared_at); + else + gfc_error ("Object at %L may not be ALLOCATABLE", + &sym->declared_at); + return; + } + + if (sym->attr.pointer && sym->attr.dimension) + { + gfc_error ("Pointer to array at %L must have a deferred shape", + &sym->declared_at); + return; + } + + } + else + { + if (!mp_flag && !sym->attr.allocatable + && !sym->attr.pointer && !sym->attr.dummy) + { + gfc_error ("Array at %L cannot have a deferred shape", + &sym->declared_at); + return; + } + } + } + + /* Make sure that intrinsic exist */ + if (sym->attr.intrinsic + && ! gfc_intrinsic_name(sym->name, 0) + && ! gfc_intrinsic_name(sym->name, 1)) + gfc_error("Intrinsic at %L does not exist", &sym->declared_at); + + /* Resolve array specifier. Check as well some constraints + on COMMON blocks. */ + + check_constant = sym->attr.in_common && !sym->attr.pointer; + gfc_resolve_array_spec (sym->as, check_constant); + + /* Resolve formal namespaces. */ + + if (formal_ns_flag && sym != NULL && sym->formal_ns != NULL) + { + formal_ns_save = formal_ns_flag; + formal_ns_flag = 0; + gfc_resolve (sym->formal_ns); + formal_ns_flag = formal_ns_save; + } +} + + + +/************* Resolve DATA statements *************/ + +static struct +{ + gfc_data_value *vnode; + int left; +} +values; + + +/* Advance the values structure to point to the next value in the data list. */ + +static try +next_data_value (void) +{ + + while (values.left == 0) + { + if (values.vnode->next == NULL) + return FAILURE; + + values.vnode = values.vnode->next; + values.left = values.vnode->repeat; + } + + values.left--; + return SUCCESS; +} + + +static try +check_data_variable (gfc_data_variable * var, locus * where) +{ + gfc_expr *e; + mpz_t size; + mpz_t offset; + try t; + int mark = 0; + int i; + mpz_t section_index[GFC_MAX_DIMENSIONS]; + gfc_ref *ref; + gfc_array_ref *ar; + + if (gfc_resolve_expr (var->expr) == FAILURE) + return FAILURE; + + ar = NULL; + mpz_init_set_si (offset, 0); + e = var->expr; + + if (e->expr_type != EXPR_VARIABLE) + gfc_internal_error ("check_data_variable(): Bad expression"); + + if (e->rank == 0) + mpz_init_set_ui (size, 1); + else + { + ref = e->ref; + + /* Find the array section reference. */ + for (ref = e->ref; ref; ref = ref->next) + { + if (ref->type != REF_ARRAY) + continue; + if (ref->u.ar.type == AR_ELEMENT) + continue; + break; + } + assert (ref); + + /* Set marks asscording to the reference pattern. */ + switch (ref->u.ar.type) + { + case AR_FULL: + mark = 1; + break; + + case AR_SECTION: + ar = &ref->u.ar; + /* Get the start position of array section. */ + gfc_get_section_index (ar, section_index, &offset); + mark = 2; + break; + + default: + abort(); + } + + if (gfc_array_size (e, &size) == FAILURE) + { + gfc_error ("Nonconstant array section at %L in DATA statement", + &e->where); + mpz_clear (offset); + return FAILURE; + } + } + + t = SUCCESS; + + while (mpz_cmp_ui (size, 0) > 0) + { + if (next_data_value () == FAILURE) + { + gfc_error ("DATA statement at %L has more variables than values", + where); + t = FAILURE; + break; + } + + t = gfc_check_assign (var->expr, values.vnode->expr, 0); + if (t == FAILURE) + break; + + /* Assign initial value to symbol. */ + gfc_assign_data_value (var->expr, values.vnode->expr, offset); + + if (mark == 1) + mpz_add_ui (offset, offset, 1); + + /* Modify the array section indexes and recalculate the offset for + next element. */ + else if (mark == 2) + gfc_advance_section (section_index, ar, &offset); + + mpz_sub_ui (size, size, 1); + } + if (mark == 2) + { + for (i = 0; i < ar->dimen; i++) + mpz_clear (section_index[i]); + } + + mpz_clear (size); + mpz_clear (offset); + + return t; +} + + +static try traverse_data_var (gfc_data_variable *, locus *); + +/* Iterate over a list of elements in a DATA statement. */ + +static try +traverse_data_list (gfc_data_variable * var, locus * where) +{ + mpz_t trip; + iterator_stack frame; + gfc_expr *e; + + mpz_init (frame.value); + + mpz_init_set (trip, var->iter.end->value.integer); + mpz_sub (trip, trip, var->iter.start->value.integer); + mpz_add (trip, trip, var->iter.step->value.integer); + + mpz_div (trip, trip, var->iter.step->value.integer); + + mpz_set (frame.value, var->iter.start->value.integer); + + frame.prev = iter_stack; + frame.variable = var->iter.var->symtree; + iter_stack = &frame; + + while (mpz_cmp_ui (trip, 0) > 0) + { + if (traverse_data_var (var->list, where) == FAILURE) + { + mpz_clear (trip); + return FAILURE; + } + + e = gfc_copy_expr (var->expr); + if (gfc_simplify_expr (e, 1) == FAILURE) + { + gfc_free_expr (e); + return FAILURE; + } + + mpz_add (frame.value, frame.value, var->iter.step->value.integer); + + mpz_sub_ui (trip, trip, 1); + } + + mpz_clear (trip); + mpz_clear (frame.value); + + iter_stack = frame.prev; + return SUCCESS; +} + + +/* Type resolve variables in the variable list of a DATA statement. */ + +static try +traverse_data_var (gfc_data_variable * var, locus * where) +{ + try t; + + for (; var; var = var->next) + { + if (var->expr == NULL) + t = traverse_data_list (var, where); + else + t = check_data_variable (var, where); + + if (t == FAILURE) + return FAILURE; + } + + return SUCCESS; +} + + +/* Resolve the expressions and iterators associated with a data statement. + This is separate from the assignment checking because data lists should + only be resolved once. */ + +static try +resolve_data_variables (gfc_data_variable * d) +{ + + for (; d; d = d->next) + { + if (d->list == NULL) + { + if (gfc_resolve_expr (d->expr) == FAILURE) + return FAILURE; + } + else + { + if (gfc_resolve_iterator (&d->iter) == FAILURE) + return FAILURE; + + if (d->iter.start->expr_type != EXPR_CONSTANT + || d->iter.end->expr_type != EXPR_CONSTANT + || d->iter.step->expr_type != EXPR_CONSTANT) + gfc_internal_error ("resolve_data_variables(): Bad iterator"); + + if (resolve_data_variables (d->list) == FAILURE) + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Resolve a single DATA statement. We implement this by storing a pointer to + the value list into static variables, and then recursively traversing the + variables list, expanding iterators and such. */ + +static void +resolve_data (gfc_data * d) +{ + + if (resolve_data_variables (d->var) == FAILURE) + return; + + values.vnode = d->value; + values.left = (d->value == NULL) ? 0 : d->value->repeat; + + if (traverse_data_var (d->var, &d->where) == FAILURE) + return; + + /* At this point, we better not have any values left. */ + + if (next_data_value () == SUCCESS) + gfc_error ("DATA statement at %L has more values than variables", + &d->where); +} + + +/* Determines if a variable is not 'pure', ie not assignable within a pure + procedure. Returns zero if assignment is OK, nonzero if there is a problem. + */ + +int +gfc_impure_variable (gfc_symbol * sym) +{ + + if (sym->attr.use_assoc || sym->attr.in_common) + return 1; + + if (sym->ns != gfc_current_ns) + return !sym->attr.function; + + /* TODO: Check storage association through EQUIVALENCE statements */ + + return 0; +} + + +/* Test whether a symbol is pure or not. For a NULL pointer, checks the + symbol of the current procedure. */ + +int +gfc_pure (gfc_symbol * sym) +{ + symbol_attribute attr; + + if (sym == NULL) + sym = gfc_current_ns->proc_name; + if (sym == NULL) + return 0; + + attr = sym->attr; + + return attr.flavor == FL_PROCEDURE && (attr.pure || attr.elemental); +} + + +/* Test whether the current procedure is elemental or not. */ + +int +gfc_elemental (gfc_symbol * sym) +{ + symbol_attribute attr; + + if (sym == NULL) + sym = gfc_current_ns->proc_name; + if (sym == NULL) + return 0; + attr = sym->attr; + + return attr.flavor == FL_PROCEDURE && attr.elemental; +} + + +/* Warn about unused labels. */ + +static void +warn_unused_label (gfc_namespace * ns) +{ + gfc_st_label *l; + + l = ns->st_labels; + if (l == NULL) + return; + + while (l->next) + l = l->next; + + for (; l; l = l->prev) + { + if (l->defined == ST_LABEL_UNKNOWN) + continue; + + switch (l->referenced) + { + case ST_LABEL_UNKNOWN: + gfc_warning ("Label %d at %L defined but not used", l->value, + &l->where); + break; + + case ST_LABEL_BAD_TARGET: + gfc_warning ("Label %d at %L defined but cannot be used", l->value, + &l->where); + break; + + default: + break; + } + } +} + + +/* Resolve derived type EQUIVALENCE object. */ + +static try +resolve_equivalence_derived (gfc_symbol *derived, gfc_symbol *sym, gfc_expr *e) +{ + gfc_symbol *d; + gfc_component *c = derived->components; + + if (!derived) + return SUCCESS; + + /* Shall not be an object of nonsequence derived type. */ + if (!derived->attr.sequence) + { + gfc_error ("Derived type variable '%s' at %L must have SEQUENCE " + "attribute to be an EQUIVALENCE object", sym->name, &e->where); + return FAILURE; + } + + for (; c ; c = c->next) + { + d = c->ts.derived; + if (d && (resolve_equivalence_derived (c->ts.derived, sym, e) == FAILURE)) + return FAILURE; + + /* Shall not be an object of sequence derived type containing a pointer + in the structure. */ + if (c->pointer) + { + gfc_error ("Derived type variable '%s' at %L has pointer componet(s) " + "cannot be an EQUIVALENCE object", sym->name, &e->where); + return FAILURE; + } + } + return SUCCESS; +} + + +/* Resolve equivalence object. + An EQUIVALENCE object shall not be a dummy argument, a pointer, an + allocatable array, an object of nonsequence derived type, an object of + sequence derived type containing a pointer at any level of component + selection, an automatic object, a function name, an entry name, a result + name, a named constant, a structure component, or a subobject of any of + the preceding objects. */ + +static void +resolve_equivalence (gfc_equiv *eq) +{ + gfc_symbol *sym; + gfc_symbol *derived; + gfc_expr *e; + gfc_ref *r; + + for (; eq; eq = eq->eq) + { + e = eq->expr; + if (gfc_resolve_expr (e) == FAILURE) + continue; + + sym = e->symtree->n.sym; + + /* Shall not be a dummy argument. */ + if (sym->attr.dummy) + { + gfc_error ("Dummy argument '%s' at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } + + /* Shall not be an allocatable array. */ + if (sym->attr.allocatable) + { + gfc_error ("Allocatable array '%s' at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } + + /* Shall not be a pointer. */ + if (sym->attr.pointer) + { + gfc_error ("Pointer '%s' at %L cannot be an EQUIVALENCE object", + sym->name, &e->where); + continue; + } + + /* Shall not be a function name, ... */ + if (sym->attr.function || sym->attr.result || sym->attr.entry + || sym->attr.subroutine) + { + gfc_error ("Entity '%s' at %L cannot be an EQUIVALENCE object", + sym->name, &e->where); + continue; + } + + /* Shall not be a named constant. */ + if (e->expr_type == EXPR_CONSTANT) + { + gfc_error ("Named constant '%s' at %L cannot be an EQUIVALENCE " + "object", sym->name, &e->where); + continue; + } + + derived = e->ts.derived; + if (derived && resolve_equivalence_derived (derived, sym, e) == FAILURE) + continue; + + if (!e->ref) + continue; + + /* Shall not be an automatic array. */ + if (e->ref->type == REF_ARRAY + && gfc_resolve_array_spec (e->ref->u.ar.as, 1) == FAILURE) + { + gfc_error ("Array '%s' at %L with non-constant bounds cannot be " + "an EQUIVALENCE object", sym->name, &e->where); + continue; + } + + /* Shall not be a structure component. */ + r = e->ref; + while (r) + { + if (r->type == REF_COMPONENT) + { + gfc_error ("Structure component '%s' at %L cannot be an " + "EQUIVALENCE object", + r->u.c.component->name, &e->where); + break; + } + r = r->next; + } + } +} + + +/* This function is called after a complete program unit has been compiled. + Its purpose is to examine all of the expressions associated with a program + unit, assign types to all intermediate expressions, make sure that all + assignments are to compatible types and figure out which names refer to + which functions or subroutines. */ + +void +gfc_resolve (gfc_namespace * ns) +{ + gfc_namespace *old_ns, *n; + gfc_charlen *cl; + gfc_data *d; + gfc_equiv *eq; + + old_ns = gfc_current_ns; + gfc_current_ns = ns; + + resolve_contained_functions (ns); + + gfc_traverse_ns (ns, resolve_symbol); + + for (n = ns->contained; n; n = n->sibling) + { + if (gfc_pure (ns->proc_name) && !gfc_pure (n->proc_name)) + gfc_error ("Contained procedure '%s' at %L of a PURE procedure must " + "also be PURE", n->proc_name->name, + &n->proc_name->declared_at); + + gfc_resolve (n); + } + + forall_flag = 0; + gfc_check_interfaces (ns); + + for (cl = ns->cl_list; cl; cl = cl->next) + { + if (cl->length == NULL || gfc_resolve_expr (cl->length) == FAILURE) + continue; + + if (cl->length->ts.type != BT_INTEGER) + gfc_error + ("Character length specification at %L must be of type INTEGER", + &cl->length->where); + } + + gfc_traverse_ns (ns, resolve_values); + + if (ns->save_all) + gfc_save_all (ns); + + iter_stack = NULL; + for (d = ns->data; d; d = d->next) + resolve_data (d); + + iter_stack = NULL; + gfc_traverse_ns (ns, gfc_formalize_init_value); + + for (eq = ns->equiv; eq; eq = eq->next) + resolve_equivalence (eq); + + cs_base = NULL; + resolve_code (ns->code, ns); + + /* Warn about unused labels. */ + if (gfc_option.warn_unused_labels) + warn_unused_label (ns); + + gfc_current_ns = old_ns; +} + diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c new file mode 100644 index 00000000000..c3e3acb8bf3 --- /dev/null +++ b/gcc/fortran/scanner.c @@ -0,0 +1,1073 @@ +/* Character scanner. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Set of subroutines to (ultimately) return the next character to the + various matching subroutines. This file's job is to read files and + build up lines that are parsed by the parser. This means that we + handle continuation lines and "include" lines. + + The first thing the scanner does is to load an entire file into + memory. We load the entire file into memory for a couple reasons. + The first is that we want to be able to deal with nonseekable input + (pipes, stdin) and there is a lot of backing up involved during + parsing. + + The second is that we want to be able to print the locus of errors, + and an error on line 999999 could conflict with something on line + one. Given nonseekable input, we've got to store the whole thing. + + One thing that helps are the column truncation limits that give us + an upper bound on the size of individual lines. We don't store the + truncated stuff. + + From the scanner's viewpoint, the higher level subroutines ask for + new characters and do a lot of jumping backwards. */ + +#include "config.h" +#include +#include +#include +#include + +#include "gfortran.h" + +/* Structure for holding module and include file search path. */ +typedef struct gfc_directorylist +{ + char *path; + struct gfc_directorylist *next; +} +gfc_directorylist; + +/* List of include file search directories. */ +static gfc_directorylist *include_dirs; + +static gfc_file *first_file, *first_duplicated_file; +static int continue_flag, end_flag; + +gfc_file *gfc_current_file; + + +/* Main scanner initialization. */ + +void +gfc_scanner_init_1 (void) +{ + + gfc_current_file = NULL; + first_file = NULL; + first_duplicated_file = NULL; + end_flag = 0; +} + + +/* Main scanner destructor. */ + +void +gfc_scanner_done_1 (void) +{ + + linebuf *lp, *lp2; + gfc_file *fp, *fp2; + + for (fp = first_file; fp; fp = fp2) + { + + if (fp->start != NULL) + { + /* Free linebuf blocks */ + for (fp2 = fp->next; fp2; fp2 = fp2->next) + if (fp->start == fp2->start) + fp2->start = NULL; + + for (lp = fp->start; lp; lp = lp2) + { + lp2 = lp->next; + gfc_free (lp); + } + } + + fp2 = fp->next; + gfc_free (fp); + } + + for (fp = first_duplicated_file; fp; fp = fp2) + { + fp2 = fp->next; + gfc_free (fp); + } +} + + +/* Adds path to the list pointed to by list. */ + +void +gfc_add_include_path (const char *path) +{ + gfc_directorylist *dir; + const char *p; + + p = path; + while (*p == ' ' || *p == '\t') /* someone might do 'gfortran "-I include"' */ + if (*p++ == '\0') + return; + + dir = include_dirs; + if (!dir) + { + dir = include_dirs = gfc_getmem (sizeof (gfc_directorylist)); + } + else + { + while (dir->next) + dir = dir->next; + + dir->next = gfc_getmem (sizeof (gfc_directorylist)); + dir = dir->next; + } + + dir->next = NULL; + dir->path = gfc_getmem (strlen (p) + 2); + strcpy (dir->path, p); + strcat (dir->path, "/"); /* make '/' last character */ +} + + +/* Release resources allocated for options. */ + +void +gfc_release_include_path (void) +{ + gfc_directorylist *p; + + gfc_free (gfc_option.module_dir); + while (include_dirs != NULL) + { + p = include_dirs; + include_dirs = include_dirs->next; + gfc_free (p->path); + gfc_free (p); + } +} + + +/* Opens file for reading, searching through the include directories + given if necessary. */ + +FILE * +gfc_open_included_file (const char *name) +{ + char fullname[PATH_MAX]; + gfc_directorylist *p; + FILE *f; + + f = gfc_open_file (name); + if (f != NULL) + return f; + + for (p = include_dirs; p; p = p->next) + { + if (strlen (p->path) + strlen (name) + 1 > PATH_MAX) + continue; + + strcpy (fullname, p->path); + strcat (fullname, name); + + f = gfc_open_file (fullname); + if (f != NULL) + return f; + } + + return NULL; +} + + +/* Return a pointer to the current locus. */ + +locus * +gfc_current_locus (void) +{ + + if (gfc_current_file == NULL) + return NULL; + return &gfc_current_file->loc; +} + + +/* Let a caller move the current read pointer (backwards). */ + +void +gfc_set_locus (locus * lp) +{ + + gfc_current_file->loc = *lp; +} + + +/* Test to see if we're at the end of the main source file. */ + +int +gfc_at_end (void) +{ + + return end_flag; +} + + +/* Test to see if we're at the end of the current file. */ + +int +gfc_at_eof (void) +{ + + if (gfc_at_end ()) + return 1; + + if (gfc_current_file->start->lines == 0) + return 1; /* Null file */ + + if (gfc_current_file->loc.lp == NULL) + return 1; + + return 0; +} + + +/* Test to see if we're at the beginning of a new line. */ + +int +gfc_at_bol (void) +{ + int i; + + if (gfc_at_eof ()) + return 1; + + i = gfc_current_file->loc.line; + + return gfc_current_file->loc.nextc == gfc_current_file->loc.lp->line[i]; +} + + +/* Test to see if we're at the end of a line. */ + +int +gfc_at_eol (void) +{ + + if (gfc_at_eof ()) + return 1; + + return *gfc_current_file->loc.nextc == '\0'; +} + + +/* Advance the current line pointer to the next line. */ + +void +gfc_advance_line (void) +{ + locus *locp; + linebuf *lp; + + if (gfc_at_end ()) + return; + + locp = &gfc_current_file->loc; + lp = locp->lp; + if (lp == NULL) + return; + + if (++locp->line >= lp->lines) + { + locp->lp = lp = lp->next; + if (lp == NULL) + return; /* End of this file */ + + locp->line = 0; + } + + locp->nextc = lp->line[locp->line]; +} + + +/* Get the next character from the input, advancing gfc_current_file's + locus. When we hit the end of the line or the end of the file, we + start returning a '\n' in order to complete the current statement. + No Fortran line conventions are implemented here. + + Requiring explicit advances to the next line prevents the parse + pointer from being on the wrong line if the current statement ends + prematurely. */ + +static int +next_char (void) +{ + locus *locp; + int c; + + /* End the current include level, but not if we're in the middle + of processing a continuation. */ + if (gfc_at_eof ()) + { + if (continue_flag != 0 || gfc_at_end ()) + return '\n'; + + if (gfc_current_file->included_by == NULL) + end_flag = 1; + + return '\n'; + } + + locp = &gfc_current_file->loc; + if (locp->nextc == NULL) + return '\n'; + + c = *locp->nextc++; + if (c == '\0') + { + locp->nextc--; /* Stay stuck on this line */ + c = '\n'; + } + + return c; +} + + +/* Checks the current line buffer to see if it is an include line. If + so, we load the new file and prepare to read from it. Include + lines happen at a lower level than regular parsing because the + string-matching subroutine is far simpler than the normal one. + + We never return a syntax error because a statement like "include = 5" + is perfectly legal. We return zero if no include was processed or + nonzero if we matched an include. */ + +int +gfc_check_include (void) +{ + char c, quote, path[PATH_MAX + 1]; + const char *include; + locus start; + int i; + + include = "include"; + + start = *gfc_current_locus (); + gfc_gobble_whitespace (); + + /* Match the 'include' */ + while (*include != '\0') + if (*include++ != gfc_next_char ()) + goto no_include; + + gfc_gobble_whitespace (); + + quote = next_char (); + if (quote != '"' && quote != '\'') + goto no_include; + + /* Copy the filename */ + for (i = 0;;) + { + c = next_char (); + if (c == '\n') + goto no_include; /* No close quote */ + if (c == quote) + break; + + /* This shouldn't happen-- PATH_MAX should be way longer than the + max line length. */ + + if (i >= PATH_MAX) + gfc_internal_error ("Pathname of include file is too long at %C"); + + path[i++] = c; + } + + path[i] = '\0'; + if (i == 0) + goto no_include; /* No filename! */ + + /* At this point, we've got a filename to be included. The rest + of the include line is ignored */ + + gfc_new_file (path, gfc_current_file->form); + return 1; + +no_include: + gfc_set_locus (&start); + return 0; +} + + +/* Skip a comment. When we come here the parse pointer is positioned + immediately after the comment character. If we ever implement + compiler directives withing comments, here is where we parse the + directive. */ + +static void +skip_comment_line (void) +{ + char c; + + do + { + c = next_char (); + } + while (c != '\n'); + + gfc_advance_line (); +} + + +/* Comment lines are null lines, lines containing only blanks or lines + on which the first nonblank line is a '!'. */ + +static void +skip_free_comments (void) +{ + locus start; + char c; + + for (;;) + { + start = *gfc_current_locus (); + if (gfc_at_eof ()) + break; + + do + { + c = next_char (); + } + while (gfc_is_whitespace (c)); + + if (c == '\n') + { + gfc_advance_line (); + continue; + } + + if (c == '!') + { + skip_comment_line (); + continue; + } + + break; + } + + gfc_set_locus (&start); +} + + +/* Skip comment lines in fixed source mode. We have the same rules as + in skip_free_comment(), except that we can have a 'c', 'C' or '*' + in column 1. and a '!' cannot be in* column 6. */ + +static void +skip_fixed_comments (void) +{ + locus start; + int col; + char c; + + for (;;) + { + start = *gfc_current_locus (); + if (gfc_at_eof ()) + break; + + c = next_char (); + if (c == '\n') + { + gfc_advance_line (); + continue; + } + + if (c == '!' || c == 'c' || c == 'C' || c == '*') + { + skip_comment_line (); + continue; + } + + col = 1; + do + { + c = next_char (); + col++; + } + while (gfc_is_whitespace (c)); + + if (c == '\n') + { + gfc_advance_line (); + continue; + } + + if (col != 6 && c == '!') + { + skip_comment_line (); + continue; + } + + break; + } + + gfc_set_locus (&start); +} + + +/* Skips the current line if it is a comment. Assumes that we are at + the start of the current line. */ + +void +gfc_skip_comments (void) +{ + + if (!gfc_at_bol () || gfc_current_file->form == FORM_FREE) + skip_free_comments (); + else + skip_fixed_comments (); +} + + +/* Get the next character from the input, taking continuation lines + and end-of-line comments into account. This implies that comment + lines between continued lines must be eaten here. For higher-level + subroutines, this flattens continued lines into a single logical + line. The in_string flag denotes whether we're inside a character + context or not. */ + +int +gfc_next_char_literal (int in_string) +{ + locus old_loc; + int i, c; + + continue_flag = 0; + +restart: + c = next_char (); + if (gfc_at_end ()) + return c; + + if (gfc_current_file->form == FORM_FREE) + { + + if (!in_string && c == '!') + { + /* This line can't be continued */ + do + { + c = next_char (); + } + while (c != '\n'); + + goto done; + } + + if (c != '&') + goto done; + + /* If the next nonblank character is a ! or \n, we've got a + continuation line. */ + old_loc = gfc_current_file->loc; + + c = next_char (); + while (gfc_is_whitespace (c)) + c = next_char (); + + /* Character constants to be continued cannot have commentary + after the '&'. */ + + if (in_string && c != '\n') + { + gfc_set_locus (&old_loc); + c = '&'; + goto done; + } + + if (c != '!' && c != '\n') + { + gfc_set_locus (&old_loc); + c = '&'; + goto done; + } + + continue_flag = 1; + if (c == '!') + skip_comment_line (); + else + gfc_advance_line (); + + /* We've got a continuation line and need to find where it continues. + First eat any comment lines. */ + gfc_skip_comments (); + + /* Now that we have a non-comment line, probe ahead for the + first non-whitespace character. If it is another '&', then + reading starts at the next character, otherwise we must back + up to where the whitespace started and resume from there. */ + + old_loc = *gfc_current_locus (); + + c = next_char (); + while (gfc_is_whitespace (c)) + c = next_char (); + + if (c != '&') + gfc_set_locus (&old_loc); + + } + else + { + /* Fixed form continuation. */ + if (!in_string && c == '!') + { + /* Skip comment at end of line. */ + do + { + c = next_char (); + } + while (c != '\n'); + } + + if (c != '\n') + goto done; + + continue_flag = 1; + old_loc = *gfc_current_locus (); + + gfc_advance_line (); + gfc_skip_comments (); + + /* See if this line is a continuation line. */ + for (i = 0; i < 5; i++) + { + c = next_char (); + if (c != ' ') + goto not_continuation; + } + + c = next_char (); + if (c == '0' || c == ' ') + goto not_continuation; + } + + /* Ready to read first character of continuation line, which might + be another continuation line! */ + goto restart; + +not_continuation: + c = '\n'; + gfc_set_locus (&old_loc); + +done: + continue_flag = 0; + return c; +} + + +/* Get the next character of input, folded to lowercase. In fixed + form mode, we also ignore spaces. When matcher subroutines are + parsing character literals, they have to call + gfc_next_char_literal(). */ + +int +gfc_next_char (void) +{ + int c; + + do + { + c = gfc_next_char_literal (0); + } + while (gfc_current_file->form == FORM_FIXED && gfc_is_whitespace (c)); + + return TOLOWER (c); +} + + +int +gfc_peek_char (void) +{ + locus old_loc; + int c; + + old_loc = *gfc_current_locus (); + c = gfc_next_char (); + gfc_set_locus (&old_loc); + + return c; +} + + +/* Recover from an error. We try to get past the current statement + and get lined up for the next. The next statement follows a '\n' + or a ';'. We also assume that we are not within a character + constant, and deal with finding a '\'' or '"'. */ + +void +gfc_error_recovery (void) +{ + char c, delim; + + if (gfc_at_eof ()) + return; + + for (;;) + { + c = gfc_next_char (); + if (c == '\n' || c == ';') + break; + + if (c != '\'' && c != '"') + { + if (gfc_at_eof ()) + break; + continue; + } + delim = c; + + for (;;) + { + c = next_char (); + + if (c == delim) + break; + if (c == '\n') + goto done; + if (c == '\\') + { + c = next_char (); + if (c == '\n') + goto done; + } + } + if (gfc_at_eof ()) + break; + } + +done: + if (c == '\n') + gfc_advance_line (); +} + + +/* Read ahead until the next character to be read is not whitespace. */ + +void +gfc_gobble_whitespace (void) +{ + locus old_loc; + int c; + + do + { + old_loc = *gfc_current_locus (); + c = gfc_next_char_literal (0); + } + while (gfc_is_whitespace (c)); + + gfc_set_locus (&old_loc); +} + + +/* Load a single line into the buffer. We truncate lines that are too + long. In fixed mode, we expand a tab that occurs within the + statement label region to expand to spaces that leave the next + character in the source region. */ + +static void +load_line (FILE * input, gfc_source_form form, char *buffer, + char *filename, int linenum) +{ + int c, maxlen, i, trunc_flag; + + maxlen = (form == FORM_FREE) ? 132 : gfc_option.fixed_line_length; + + i = 0; + + for (;;) + { + c = fgetc (input); + + if (c == EOF) + break; + if (c == '\n') + break; + + if (c == '\r') + continue; /* Gobble characters */ + if (c == '\0') + continue; + + if (form == FORM_FIXED && c == '\t' && i <= 6) + { /* Tab expandsion */ + while (i <= 6) + { + *buffer++ = ' '; + i++; + } + + continue; + } + + *buffer++ = c; + i++; + + if (i >= maxlen) + { /* Truncate the rest of the line */ + trunc_flag = 1; + + for (;;) + { + c = fgetc (input); + if (c == '\n' || c == EOF) + break; + + if (gfc_option.warn_line_truncation + && trunc_flag + && !gfc_is_whitespace (c)) + { + gfc_warning_now ("Line %d of %s is being truncated", + linenum, filename); + trunc_flag = 0; + } + } + + ungetc ('\n', input); + } + } + + *buffer = '\0'; +} + + +/* Load a file into memory by calling load_line until the file ends. */ + +static void +load_file (FILE * input, gfc_file * fp) +{ + char *linep, line[GFC_MAX_LINE + 1]; + int len, linenum; + linebuf *lp; + + fp->start = lp = gfc_getmem (sizeof (linebuf)); + + linenum = 1; + lp->lines = 0; + lp->start_line = 1; + lp->next = NULL; + + linep = (char *) (lp + 1); + + /* Load the file. */ + for (;;) + { + load_line (input, fp->form, line, fp->filename, linenum); + linenum++; + + len = strlen (line); + + if (feof (input) && len == 0) + break; + + /* See if we need another linebuf. */ + if (((char *) &lp->line[lp->lines + 2]) > linep - len - 1) + { + lp->next = gfc_getmem (sizeof (linebuf)); + + lp->next->start_line = lp->start_line + lp->lines; + lp = lp->next; + lp->lines = 0; + + linep = (char *) (lp + 1); + } + + linep = linep - len - 1; + lp->line[lp->lines++] = linep; + strcpy (linep, line); + } +} + + +/* Determine the source form from the filename extension. We assume + case insensitivity. */ + +static gfc_source_form +form_from_filename (const char *filename) +{ + + static const struct + { + const char *extension; + gfc_source_form form; + } + exttype[] = + { + { + ".f90", FORM_FREE} + , + { + ".f95", FORM_FREE} + , + { + ".f", FORM_FIXED} + , + { + ".for", FORM_FIXED} + , + { + "", FORM_UNKNOWN} + }; /* sentinel value */ + + gfc_source_form f_form; + const char *fileext; + int i; + + /* Find end of file name. */ + i = 0; + while ((i < PATH_MAX) && (filename[i] != '\0')) + i++; + + /* Improperly terminated or too-long filename. */ + if (i == PATH_MAX) + return FORM_UNKNOWN; + + /* Find last period. */ + while (i >= 0 && (filename[i] != '.')) + i--; + + /* Did we see a file extension? */ + if (i < 0) + return FORM_UNKNOWN; /* Nope */ + + /* Get file extension and compare it to others. */ + fileext = &(filename[i]); + + i = -1; + f_form = FORM_UNKNOWN; + do + { + i++; + if (strcasecmp (fileext, exttype[i].extension) == 0) + { + f_form = exttype[i].form; + break; + } + } + while (exttype[i].form != FORM_UNKNOWN); + + return f_form; +} + + +/* Open a new file and start scanning from that file. Every new file + gets a gfc_file node, even if it is a duplicate file. Returns SUCCESS + if everything went OK, FAILURE otherwise. */ + +try +gfc_new_file (const char *filename, gfc_source_form form) +{ + gfc_file *fp, *fp2; + FILE *input; + int len; + + len = strlen (filename); + if (len > PATH_MAX) + { + gfc_error_now ("Filename '%s' is too long- ignoring it", filename); + return FAILURE; + } + + fp = gfc_getmem (sizeof (gfc_file)); + + /* Make sure this file isn't being included recursively. */ + for (fp2 = gfc_current_file; fp2; fp2 = fp2->included_by) + if (strcmp (filename, fp2->filename) == 0) + { + gfc_error_now ("Recursive inclusion of file '%s' at %C- ignoring it", + filename); + gfc_free (fp); + return FAILURE; + } + + /* See if the file has already been included. */ + for (fp2 = first_file; fp2; fp2 = fp2->next) + if (strcmp (filename, fp2->filename) == 0) + { + *fp = *fp2; + fp->next = first_duplicated_file; + first_duplicated_file = fp; + goto init_fp; + } + + strcpy (fp->filename, filename); + + if (gfc_current_file == NULL) + input = gfc_open_file (filename); + else + input = gfc_open_included_file (filename); + + if (input == NULL) + { + if (gfc_current_file == NULL) + gfc_error_now ("Can't open file '%s'", filename); + else + gfc_error_now ("Can't open file '%s' included at %C", filename); + + gfc_free (fp); + return FAILURE; + } + + /* Decide which form the file will be read in as. */ + if (form != FORM_UNKNOWN) + fp->form = form; + else + { + fp->form = form_from_filename (filename); + + if (fp->form == FORM_UNKNOWN) + { + fp->form = FORM_FREE; + gfc_warning_now ("Reading file %s as free form", filename); + } + } + + fp->next = first_file; + first_file = fp; + + load_file (input, fp); + fclose (input); + +init_fp: + fp->included_by = gfc_current_file; + gfc_current_file = fp; + + fp->loc.line = 0; + fp->loc.lp = fp->start; + fp->loc.nextc = fp->start->line[0]; + fp->loc.file = fp; + + return SUCCESS; +} diff --git a/gcc/fortran/simplify.c b/gcc/fortran/simplify.c new file mode 100644 index 00000000000..876eb2fdaf1 --- /dev/null +++ b/gcc/fortran/simplify.c @@ -0,0 +1,4008 @@ +/* Simplify intrinsic functions at compile-time. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught & Katherine Holcomb + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "flags.h" + +#include + +#include "gfortran.h" +#include "arith.h" +#include "intrinsic.h" + +static mpf_t mpf_zero, mpf_half, mpf_one; +static mpz_t mpz_zero; + +gfc_expr gfc_bad_expr; + + +/* Note that 'simplification' is not just transforming expressions. + For functions that are not simplified at compile time, range + checking is done if possible. + + The return convention is that each simplification function returns: + + A new expression node corresponding to the simplified arguments. + The original arguments are destroyed by the caller, and must not + be a part of the new expression. + + NULL pointer indicating that no simplification was possible and + the original expression should remain intact. If the + simplification function sets the type and/or the function name + via the pointer gfc_simple_expression, then this type is + retained. + + An expression pointer to gfc_bad_expr (a static placeholder) + indicating that some error has prevented simplification. For + example, sqrt(-1.0). The error is generated within the function + and should be propagated upwards + + By the time a simplification function gets control, it has been + decided that the function call is really supposed to be the + intrinsic. No type checking is strictly necessary, since only + valid types will be passed on. On the other hand, a simplification + subroutine may have to look at the type of an argument as part of + its processing. + + Array arguments are never passed to these subroutines. + + The functions in this file don't have much comment with them, but + everything is reasonably straight-forward. The Standard, chapter 13 + is the best comment you'll find for this file anyway. */ + +/* Static table for converting non-ascii character sets to ascii. + The xascii_table[] is the inverse table. */ + +static int ascii_table[256] = { + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\b', '\t', '\n', '\v', '\0', '\r', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + ' ', '!', '\'', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', '\?' +}; + +static int xascii_table[256]; + + +/* Range checks an expression node. If all goes well, returns the + node, otherwise returns &gfc_bad_expr and frees the node. */ + +static gfc_expr * +range_check (gfc_expr * result, const char *name) +{ + + if (gfc_range_check (result) == ARITH_OK) + return result; + + gfc_error ("Result of %s overflows its kind at %L", name, &result->where); + gfc_free_expr (result); + return &gfc_bad_expr; +} + + +/* A helper function that gets an optional and possibly missing + kind parameter. Returns the kind, -1 if something went wrong. */ + +static int +get_kind (bt type, gfc_expr * k, const char *name, int default_kind) +{ + int kind; + + if (k == NULL) + return default_kind; + + if (k->expr_type != EXPR_CONSTANT) + { + gfc_error ("KIND parameter of %s at %L must be an initialization " + "expression", name, &k->where); + + return -1; + } + + if (gfc_extract_int (k, &kind) != NULL + || gfc_validate_kind (type, kind) == -1) + { + + gfc_error ("Invalid KIND parameter of %s at %L", name, &k->where); + return -1; + } + + return kind; +} + + +/********************** Simplification functions *****************************/ + +gfc_expr * +gfc_simplify_abs (gfc_expr * e) +{ + gfc_expr *result; + mpf_t a, b; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + switch (e->ts.type) + { + case BT_INTEGER: + result = gfc_constant_result (BT_INTEGER, e->ts.kind, &e->where); + + mpz_abs (result->value.integer, e->value.integer); + + result = range_check (result, "IABS"); + break; + + case BT_REAL: + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + + mpf_abs (result->value.real, e->value.real); + + result = range_check (result, "ABS"); + break; + + case BT_COMPLEX: + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + + mpf_init (a); + mpf_mul (a, e->value.complex.r, e->value.complex.r); + + mpf_init (b); + mpf_mul (b, e->value.complex.i, e->value.complex.i); + + mpf_add (a, a, b); + mpf_sqrt (result->value.real, a); + + mpf_clear (a); + mpf_clear (b); + + result = range_check (result, "CABS"); + break; + + default: + gfc_internal_error ("gfc_simplify_abs(): Bad type"); + } + + return result; +} + + +gfc_expr * +gfc_simplify_achar (gfc_expr * e) +{ + gfc_expr *result; + int index; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + /* We cannot assume that the native character set is ASCII in this + function. */ + if (gfc_extract_int (e, &index) != NULL || index < 0 || index > 127) + { + gfc_error ("Extended ASCII not implemented: argument of ACHAR at %L " + "must be between 0 and 127", &e->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (BT_CHARACTER, gfc_default_character_kind (), + &e->where); + + result->value.character.string = gfc_getmem (2); + + result->value.character.length = 1; + result->value.character.string[0] = ascii_table[index]; + result->value.character.string[1] = '\0'; /* For debugger */ + return result; +} + + +gfc_expr * +gfc_simplify_acos (gfc_expr * x) +{ + gfc_expr *result; + mpf_t negative, square, term; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + if (mpf_cmp_si (x->value.real, 1) > 0 || mpf_cmp_si (x->value.real, -1) < 0) + { + gfc_error ("Argument of ACOS at %L must be between -1 and 1", + &x->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + if (mpf_cmp_si (x->value.real, 1) == 0) + { + mpf_set_ui (result->value.real, 0); + return range_check (result, "ACOS"); + } + + if (mpf_cmp_si (x->value.real, -1) == 0) + { + mpf_set (result->value.real, pi); + return range_check (result, "ACOS"); + } + + mpf_init (negative); + mpf_init (square); + mpf_init (term); + + mpf_pow_ui (square, x->value.real, 2); + mpf_ui_sub (term, 1, square); + mpf_sqrt (term, term); + mpf_div (term, x->value.real, term); + mpf_neg (term, term); + arctangent (&term, &negative); + mpf_add (result->value.real, half_pi, negative); + + mpf_clear (negative); + mpf_clear (square); + mpf_clear (term); + + return range_check (result, "ACOS"); +} + + +gfc_expr * +gfc_simplify_adjustl (gfc_expr * e) +{ + gfc_expr *result; + int count, i, len; + char ch; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + len = e->value.character.length; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + result->value.character.length = len; + result->value.character.string = gfc_getmem (len + 1); + + for (count = 0, i = 0; i < len; ++i) + { + ch = e->value.character.string[i]; + if (ch != ' ') + break; + ++count; + } + + for (i = 0; i < len - count; ++i) + { + result->value.character.string[i] = + e->value.character.string[count + i]; + } + + for (i = len - count; i < len; ++i) + { + result->value.character.string[i] = ' '; + } + + result->value.character.string[len] = '\0'; /* For debugger */ + + return result; +} + + +gfc_expr * +gfc_simplify_adjustr (gfc_expr * e) +{ + gfc_expr *result; + int count, i, len; + char ch; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + len = e->value.character.length; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + result->value.character.length = len; + result->value.character.string = gfc_getmem (len + 1); + + for (count = 0, i = len - 1; i >= 0; --i) + { + ch = e->value.character.string[i]; + if (ch != ' ') + break; + ++count; + } + + for (i = 0; i < count; ++i) + { + result->value.character.string[i] = ' '; + } + + for (i = count; i < len; ++i) + { + result->value.character.string[i] = + e->value.character.string[i - count]; + } + + result->value.character.string[len] = '\0'; /* For debugger */ + + return result; +} + + +gfc_expr * +gfc_simplify_aimag (gfc_expr * e) +{ + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + mpf_set (result->value.real, e->value.complex.i); + + return range_check (result, "AIMAG"); +} + + +gfc_expr * +gfc_simplify_aint (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *rtrunc, *result; + int kind; + + kind = get_kind (BT_REAL, k, "AINT", e->ts.kind); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + rtrunc = gfc_copy_expr (e); + + mpf_trunc (rtrunc->value.real, e->value.real); + + result = gfc_real2real (rtrunc, kind); + gfc_free_expr (rtrunc); + + return range_check (result, "AINT"); +} + + +gfc_expr * +gfc_simplify_dint (gfc_expr * e) +{ + gfc_expr *rtrunc, *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + rtrunc = gfc_copy_expr (e); + + mpf_trunc (rtrunc->value.real, e->value.real); + + result = gfc_real2real (rtrunc, gfc_default_double_kind ()); + gfc_free_expr (rtrunc); + + return range_check (result, "DINT"); + +} + + +gfc_expr * +gfc_simplify_anint (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *rtrunc, *result; + int kind, cmp; + + kind = get_kind (BT_REAL, k, "ANINT", e->ts.kind); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (e->ts.type, kind, &e->where); + + rtrunc = gfc_copy_expr (e); + + cmp = mpf_cmp_ui (e->value.real, 0); + + if (cmp > 0) + { + mpf_add (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else if (cmp < 0) + { + mpf_sub (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else + mpf_set_ui (result->value.real, 0); + + gfc_free_expr (rtrunc); + + return range_check (result, "ANINT"); +} + + +gfc_expr * +gfc_simplify_dnint (gfc_expr * e) +{ + gfc_expr *rtrunc, *result; + int cmp; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = + gfc_constant_result (BT_REAL, gfc_default_double_kind (), &e->where); + + rtrunc = gfc_copy_expr (e); + + cmp = mpf_cmp_ui (e->value.real, 0); + + if (cmp > 0) + { + mpf_add (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else if (cmp < 0) + { + mpf_sub (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (result->value.real, rtrunc->value.real); + } + else + mpf_set_ui (result->value.real, 0); + + gfc_free_expr (rtrunc); + + return range_check (result, "DNINT"); +} + + +gfc_expr * +gfc_simplify_asin (gfc_expr * x) +{ + gfc_expr *result; + mpf_t negative, square, term; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + if (mpf_cmp_si (x->value.real, 1) > 0 || mpf_cmp_si (x->value.real, -1) < 0) + { + gfc_error ("Argument of ASIN at %L must be between -1 and 1", + &x->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + if (mpf_cmp_si (x->value.real, 1) == 0) + { + mpf_set (result->value.real, half_pi); + return range_check (result, "ASIN"); + } + + if (mpf_cmp_si (x->value.real, -1) == 0) + { + mpf_init (negative); + mpf_neg (negative, half_pi); + mpf_set (result->value.real, negative); + mpf_clear (negative); + return range_check (result, "ASIN"); + } + + mpf_init (square); + mpf_init (term); + + mpf_pow_ui (square, x->value.real, 2); + mpf_ui_sub (term, 1, square); + mpf_sqrt (term, term); + mpf_div (term, x->value.real, term); + arctangent (&term, &result->value.real); + + mpf_clear (square); + mpf_clear (term); + + return range_check (result, "ASIN"); +} + + +gfc_expr * +gfc_simplify_atan (gfc_expr * x) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + arctangent (&x->value.real, &result->value.real); + + return range_check (result, "ATAN"); + +} + + +gfc_expr * +gfc_simplify_atan2 (gfc_expr * y, gfc_expr * x) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + + if (mpf_sgn (y->value.real) == 0 && mpf_sgn (x->value.real) == 0) + { + gfc_error + ("If first argument of ATAN2 %L is zero, the second argument " + "must not be zero", &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + arctangent2 (&y->value.real, &x->value.real, &result->value.real); + + return range_check (result, "ATAN2"); + +} + + +gfc_expr * +gfc_simplify_bit_size (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + gfc_internal_error ("In gfc_simplify_bit_size(): Bad kind"); + + result = gfc_constant_result (BT_INTEGER, e->ts.kind, &e->where); + mpz_set_ui (result->value.integer, gfc_integer_kinds[i].bit_size); + + return result; +} + + +gfc_expr * +gfc_simplify_btest (gfc_expr * e, gfc_expr * bit) +{ + int b; + + if (e->expr_type != EXPR_CONSTANT || bit->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (bit, &b) != NULL || b < 0) + return gfc_logical_expr (0, &e->where); + + return gfc_logical_expr (mpz_tstbit (e->value.integer, b), &e->where); +} + + +gfc_expr * +gfc_simplify_ceiling (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *ceil, *result; + int kind; + + kind = get_kind (BT_REAL, k, "CEILING", gfc_default_real_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + ceil = gfc_copy_expr (e); + + mpf_ceil (ceil->value.real, e->value.real); + mpz_set_f (result->value.integer, ceil->value.real); + + gfc_free_expr (ceil); + + return range_check (result, "CEILING"); +} + + +gfc_expr * +gfc_simplify_char (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + int c, kind; + + kind = get_kind (BT_CHARACTER, k, "CHAR", gfc_default_character_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (e, &c) != NULL || c < 0 || c > 255) + { + gfc_error ("Bad character in CHAR function at %L", &e->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (BT_CHARACTER, kind, &e->where); + + result->value.character.length = 1; + result->value.character.string = gfc_getmem (2); + + result->value.character.string[0] = c; + result->value.character.string[1] = '\0'; /* For debugger */ + + return result; +} + + +/* Common subroutine for simplifying CMPLX and DCMPLX. */ + +static gfc_expr * +simplify_cmplx (const char *name, gfc_expr * x, gfc_expr * y, int kind) +{ + gfc_expr *result; + + result = gfc_constant_result (BT_COMPLEX, kind, &x->where); + + mpf_set_ui (result->value.complex.i, 0); + + switch (x->ts.type) + { + case BT_INTEGER: + mpf_set_z (result->value.complex.r, x->value.integer); + break; + + case BT_REAL: + mpf_set (result->value.complex.r, x->value.real); + break; + + case BT_COMPLEX: + mpf_set (result->value.complex.r, x->value.complex.r); + mpf_set (result->value.complex.i, x->value.complex.i); + break; + + default: + gfc_internal_error ("gfc_simplify_dcmplx(): Bad type (x)"); + } + + if (y != NULL) + { + switch (y->ts.type) + { + case BT_INTEGER: + mpf_set_z (result->value.complex.i, y->value.integer); + break; + + case BT_REAL: + mpf_set (result->value.complex.i, y->value.real); + break; + + default: + gfc_internal_error ("gfc_simplify_dcmplx(): Bad type (y)"); + } + } + + return range_check (result, name); +} + + +gfc_expr * +gfc_simplify_cmplx (gfc_expr * x, gfc_expr * y, gfc_expr * k) +{ + int kind; + + if (x->expr_type != EXPR_CONSTANT + || (y != NULL && y->expr_type != EXPR_CONSTANT)) + return NULL; + + kind = get_kind (BT_REAL, k, "CMPLX", gfc_default_real_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + return simplify_cmplx ("CMPLX", x, y, kind); +} + + +gfc_expr * +gfc_simplify_conjg (gfc_expr * e) +{ + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_copy_expr (e); + mpf_neg (result->value.complex.i, result->value.complex.i); + + return range_check (result, "CONJG"); +} + + +gfc_expr * +gfc_simplify_cos (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_REAL: + cosine (&x->value.real, &result->value.real); + break; + case BT_COMPLEX: + mpf_init (xp); + mpf_init (xq); + + cosine (&x->value.complex.r, &xp); + hypercos (&x->value.complex.i, &xq); + mpf_mul (result->value.complex.r, xp, xq); + + sine (&x->value.complex.r, &xp); + hypersine (&x->value.complex.i, &xq); + mpf_mul (xp, xp, xq); + mpf_neg (result->value.complex.i, xp); + + mpf_clear (xp); + mpf_clear (xq); + break; + default: + gfc_internal_error ("in gfc_simplify_cos(): Bad type"); + } + + return range_check (result, "COS"); + +} + + +gfc_expr * +gfc_simplify_cosh (gfc_expr * x) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + hypercos (&x->value.real, &result->value.real); + + return range_check (result, "COSH"); +} + + +gfc_expr * +gfc_simplify_dcmplx (gfc_expr * x, gfc_expr * y) +{ + + if (x->expr_type != EXPR_CONSTANT + || (y != NULL && y->expr_type != EXPR_CONSTANT)) + return NULL; + + return simplify_cmplx ("DCMPLX", x, y, gfc_default_double_kind ()); +} + + +gfc_expr * +gfc_simplify_dble (gfc_expr * e) +{ + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + switch (e->ts.type) + { + case BT_INTEGER: + result = gfc_int2real (e, gfc_default_double_kind ()); + break; + + case BT_REAL: + result = gfc_real2real (e, gfc_default_double_kind ()); + break; + + case BT_COMPLEX: + result = gfc_complex2real (e, gfc_default_double_kind ()); + break; + + default: + gfc_internal_error ("gfc_simplify_dble(): bad type at %L", &e->where); + } + + return range_check (result, "DBLE"); +} + + +gfc_expr * +gfc_simplify_digits (gfc_expr * x) +{ + int i, digits; + + i = gfc_validate_kind (x->ts.type, x->ts.kind); + if (i == -1) + goto bad; + + switch (x->ts.type) + { + case BT_INTEGER: + digits = gfc_integer_kinds[i].digits; + break; + + case BT_REAL: + case BT_COMPLEX: + digits = gfc_real_kinds[i].digits; + break; + + default: + bad: + gfc_internal_error ("gfc_simplify_digits(): Bad type"); + } + + return gfc_int_expr (digits); +} + + +gfc_expr * +gfc_simplify_dim (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_INTEGER: + if (mpz_cmp (x->value.integer, y->value.integer) > 0) + mpz_sub (result->value.integer, x->value.integer, y->value.integer); + else + mpz_set (result->value.integer, mpz_zero); + + break; + + case BT_REAL: + if (mpf_cmp (x->value.real, y->value.real) > 0) + mpf_sub (result->value.real, x->value.real, y->value.real); + else + mpf_set (result->value.real, mpf_zero); + + break; + + default: + gfc_internal_error ("gfc_simplify_dim(): Bad type"); + } + + return range_check (result, "DIM"); +} + + +gfc_expr * +gfc_simplify_dprod (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *mult1, *mult2, *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = + gfc_constant_result (BT_REAL, gfc_default_double_kind (), &x->where); + + mult1 = gfc_real2real (x, gfc_default_double_kind ()); + mult2 = gfc_real2real (y, gfc_default_double_kind ()); + + mpf_mul (result->value.real, mult1->value.real, mult2->value.real); + + gfc_free_expr (mult1); + gfc_free_expr (mult2); + + return range_check (result, "DPROD"); +} + + +gfc_expr * +gfc_simplify_epsilon (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_epsilon(): Bad kind"); + + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + + mpf_set (result->value.real, gfc_real_kinds[i].epsilon); + + return range_check (result, "EPSILON"); +} + + +gfc_expr * +gfc_simplify_exp (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + double ln2, absval, rhuge; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + /* Exactitude doesn't matter here */ + ln2 = .6931472; + rhuge = ln2 * mpz_get_d (gfc_integer_kinds[0].huge); + + switch (x->ts.type) + { + case BT_REAL: + absval = mpf_get_d (x->value.real); + if (absval < 0) + absval = -absval; + if (absval > rhuge) + { + /* Underflow (set arg to zero) if x is negative and its + magnitude is greater than the maximum C long int times + ln2, because the exponential method in arith.c will fail + for such values. */ + if (mpf_cmp_ui (x->value.real, 0) < 0) + { + if (pedantic == 1) + gfc_warning_now + ("Argument of EXP at %L is negative and too large, " + "setting result to zero", &x->where); + mpf_set_ui (result->value.real, 0); + return range_check (result, "EXP"); + } + /* Overflow if magnitude of x is greater than C long int + huge times ln2. */ + else + { + gfc_error ("Argument of EXP at %L too large", &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + } + exponential (&x->value.real, &result->value.real); + break; + + case BT_COMPLEX: + /* Using Euler's formula. */ + absval = mpf_get_d (x->value.complex.r); + if (absval < 0) + absval = -absval; + if (absval > rhuge) + { + if (mpf_cmp_ui (x->value.complex.r, 0) < 0) + { + if (pedantic == 1) + gfc_warning_now + ("Real part of argument of EXP at %L is negative " + "and too large, setting result to zero", &x->where); + + mpf_set_ui (result->value.complex.r, 0); + mpf_set_ui (result->value.complex.i, 0); + return range_check (result, "EXP"); + } + else + { + gfc_error ("Real part of argument of EXP at %L too large", + &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + } + mpf_init (xp); + mpf_init (xq); + exponential (&x->value.complex.r, &xq); + cosine (&x->value.complex.i, &xp); + mpf_mul (result->value.complex.r, xq, xp); + sine (&x->value.complex.i, &xp); + mpf_mul (result->value.complex.i, xq, xp); + mpf_clear (xp); + mpf_clear (xq); + break; + + default: + gfc_internal_error ("in gfc_simplify_exp(): Bad type"); + } + + return range_check (result, "EXP"); +} + + +gfc_expr * +gfc_simplify_exponent (gfc_expr * x) +{ + mpf_t i2, absv, ln2, lnx; + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpz_set_ui (result->value.integer, 0); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (absv); + mpf_init (ln2); + mpf_init (lnx); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + mpz_set_f (result->value.integer, lnx); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (lnx); + mpf_clear (absv); + + return range_check (result, "EXPONENT"); +} + + +gfc_expr * +gfc_simplify_float (gfc_expr * a) +{ + gfc_expr *result; + + if (a->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_int2real (a, gfc_default_real_kind ()); + return range_check (result, "FLOAT"); +} + + +gfc_expr * +gfc_simplify_floor (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + mpf_t floor; + int kind; + + kind = get_kind (BT_REAL, k, "FLOOR", gfc_default_real_kind ()); + if (kind == -1) + gfc_internal_error ("gfc_simplify_floor(): Bad kind"); + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + mpf_init (floor); + mpf_floor (floor, e->value.real); + mpz_set_f (result->value.integer, floor); + mpf_clear (floor); + + return range_check (result, "FLOOR"); +} + + +gfc_expr * +gfc_simplify_fraction (gfc_expr * x) +{ + gfc_expr *result; + mpf_t i2, absv, ln2, lnx, pow2; + unsigned long exp2; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_set (result->value.real, mpf_zero); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (absv); + mpf_init (ln2); + mpf_init (lnx); + mpf_init (pow2); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + exp2 = (unsigned long) mpf_get_d (lnx); + mpf_pow_ui (pow2, i2, exp2); + + mpf_div (result->value.real, absv, pow2); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + mpf_clear (pow2); + + return range_check (result, "FRACTION"); +} + + +gfc_expr * +gfc_simplify_huge (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + goto bad_type; + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + switch (e->ts.type) + { + case BT_INTEGER: + mpz_set (result->value.integer, gfc_integer_kinds[i].huge); + break; + + case BT_REAL: + mpf_set (result->value.real, gfc_real_kinds[i].huge); + break; + + bad_type: + default: + gfc_internal_error ("gfc_simplify_huge(): Bad type"); + } + + return result; +} + + +gfc_expr * +gfc_simplify_iachar (gfc_expr * e) +{ + gfc_expr *result; + int index; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + if (e->value.character.length != 1) + { + gfc_error ("Argument of IACHAR at %L must be of length one", &e->where); + return &gfc_bad_expr; + } + + index = xascii_table[(int) e->value.character.string[0] & 0xFF]; + + result = gfc_int_expr (index); + result->where = e->where; + + return range_check (result, "IACHAR"); +} + + +gfc_expr * +gfc_simplify_iand (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, x->ts.kind, &x->where); + + mpz_and (result->value.integer, x->value.integer, y->value.integer); + + return range_check (result, "IAND"); +} + + +gfc_expr * +gfc_simplify_ibclr (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + int k, pos; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (y, &pos) != NULL || pos < 0) + { + gfc_error ("Invalid second argument of IBCLR at %L", &y->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (x->ts.type, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ibclr(): Bad kind"); + + if (pos > gfc_integer_kinds[k].bit_size) + { + gfc_error ("Second argument of IBCLR exceeds bit size at %L", + &y->where); + return &gfc_bad_expr; + } + + result = gfc_copy_expr (x); + + mpz_clrbit (result->value.integer, pos); + return range_check (result, "IBCLR"); +} + + +gfc_expr * +gfc_simplify_ibits (gfc_expr * x, gfc_expr * y, gfc_expr * z) +{ + gfc_expr *result; + int pos, len; + int i, k, bitsize; + int *bits; + + if (x->expr_type != EXPR_CONSTANT + || y->expr_type != EXPR_CONSTANT + || z->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (y, &pos) != NULL || pos < 0) + { + gfc_error ("Invalid second argument of IBITS at %L", &y->where); + return &gfc_bad_expr; + } + + if (gfc_extract_int (z, &len) != NULL || len < 0) + { + gfc_error ("Invalid third argument of IBITS at %L", &z->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (BT_INTEGER, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ibits(): Bad kind"); + + bitsize = gfc_integer_kinds[k].bit_size; + + if (pos + len > bitsize) + { + gfc_error + ("Sum of second and third arguments of IBITS exceeds bit size " + "at %L", &y->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + bits = gfc_getmem (bitsize * sizeof (int)); + + for (i = 0; i < bitsize; i++) + bits[i] = 0; + + for (i = 0; i < len; i++) + bits[i] = mpz_tstbit (x->value.integer, i + pos); + + for (i = 0; i < bitsize; i++) + { + if (bits[i] == 0) + { + mpz_clrbit (result->value.integer, i); + } + else if (bits[i] == 1) + { + mpz_setbit (result->value.integer, i); + } + else + { + gfc_internal_error ("IBITS: Bad bit"); + } + } + + gfc_free (bits); + + return range_check (result, "IBITS"); +} + + +gfc_expr * +gfc_simplify_ibset (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + int k, pos; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (y, &pos) != NULL || pos < 0) + { + gfc_error ("Invalid second argument of IBSET at %L", &y->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (x->ts.type, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ibset(): Bad kind"); + + if (pos > gfc_integer_kinds[k].bit_size) + { + gfc_error ("Second argument of IBSET exceeds bit size at %L", + &y->where); + return &gfc_bad_expr; + } + + result = gfc_copy_expr (x); + + mpz_setbit (result->value.integer, pos); + return range_check (result, "IBSET"); +} + + +gfc_expr * +gfc_simplify_ichar (gfc_expr * e) +{ + gfc_expr *result; + int index; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + if (e->value.character.length != 1) + { + gfc_error ("Argument of ICHAR at %L must be of length one", &e->where); + return &gfc_bad_expr; + } + + index = (int) e->value.character.string[0]; + + if (index < CHAR_MIN || index > CHAR_MAX) + { + gfc_error ("Argument of ICHAR at %L out of range of this processor", + &e->where); + return &gfc_bad_expr; + } + + result = gfc_int_expr (index); + result->where = e->where; + return range_check (result, "ICHAR"); +} + + +gfc_expr * +gfc_simplify_ieor (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, x->ts.kind, &x->where); + + mpz_xor (result->value.integer, x->value.integer, y->value.integer); + + return range_check (result, "IEOR"); +} + + +gfc_expr * +gfc_simplify_index (gfc_expr * x, gfc_expr * y, gfc_expr * b) +{ + gfc_expr *result; + int back, len, lensub; + int i, j, k, count, index = 0, start; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + if (b != NULL && b->value.logical != 0) + back = 1; + else + back = 0; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &x->where); + + len = x->value.character.length; + lensub = y->value.character.length; + + if (len < lensub) + { + mpz_set_si (result->value.integer, 0); + return result; + } + + if (back == 0) + { + + if (lensub == 0) + { + mpz_set_si (result->value.integer, 1); + return result; + } + else if (lensub == 1) + { + for (i = 0; i < len; i++) + { + for (j = 0; j < lensub; j++) + { + if (y->value.character.string[j] == + x->value.character.string[i]) + { + index = i + 1; + goto done; + } + } + } + } + else + { + for (i = 0; i < len; i++) + { + for (j = 0; j < lensub; j++) + { + if (y->value.character.string[j] == + x->value.character.string[i]) + { + start = i; + count = 0; + + for (k = 0; k < lensub; k++) + { + if (y->value.character.string[k] == + x->value.character.string[k + start]) + count++; + } + + if (count == lensub) + { + index = start + 1; + goto done; + } + } + } + } + } + + } + else + { + + if (lensub == 0) + { + mpz_set_si (result->value.integer, len + 1); + return result; + } + else if (lensub == 1) + { + for (i = 0; i < len; i++) + { + for (j = 0; j < lensub; j++) + { + if (y->value.character.string[j] == + x->value.character.string[len - i]) + { + index = len - i + 1; + goto done; + } + } + } + } + else + { + for (i = 0; i < len; i++) + { + for (j = 0; j < lensub; j++) + { + if (y->value.character.string[j] == + x->value.character.string[len - i]) + { + start = len - i; + if (start <= len - lensub) + { + count = 0; + for (k = 0; k < lensub; k++) + if (y->value.character.string[k] == + x->value.character.string[k + start]) + count++; + + if (count == lensub) + { + index = start + 1; + goto done; + } + } + else + { + continue; + } + } + } + } + } + } + +done: + mpz_set_si (result->value.integer, index); + return range_check (result, "INDEX"); +} + + +gfc_expr * +gfc_simplify_int (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *rpart, *rtrunc, *result; + int kind; + + kind = get_kind (BT_REAL, k, "INT", gfc_default_real_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + switch (e->ts.type) + { + case BT_INTEGER: + mpz_set (result->value.integer, e->value.integer); + break; + + case BT_REAL: + rtrunc = gfc_copy_expr (e); + mpf_trunc (rtrunc->value.real, e->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + gfc_free_expr (rtrunc); + break; + + case BT_COMPLEX: + rpart = gfc_complex2real (e, kind); + rtrunc = gfc_copy_expr (rpart); + mpf_trunc (rtrunc->value.real, rpart->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + gfc_free_expr (rpart); + gfc_free_expr (rtrunc); + break; + + default: + gfc_error ("Argument of INT at %L is not a valid type", &e->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + return range_check (result, "INT"); +} + + +gfc_expr * +gfc_simplify_ifix (gfc_expr * e) +{ + gfc_expr *rtrunc, *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + rtrunc = gfc_copy_expr (e); + + mpf_trunc (rtrunc->value.real, e->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + + gfc_free_expr (rtrunc); + return range_check (result, "IFIX"); +} + + +gfc_expr * +gfc_simplify_idint (gfc_expr * e) +{ + gfc_expr *rtrunc, *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + rtrunc = gfc_copy_expr (e); + + mpf_trunc (rtrunc->value.real, e->value.real); + mpz_set_f (result->value.integer, rtrunc->value.real); + + gfc_free_expr (rtrunc); + return range_check (result, "IDINT"); +} + + +gfc_expr * +gfc_simplify_ior (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, x->ts.kind, &x->where); + + mpz_ior (result->value.integer, x->value.integer, y->value.integer); + return range_check (result, "IOR"); +} + + +gfc_expr * +gfc_simplify_ishft (gfc_expr * e, gfc_expr * s) +{ + gfc_expr *result; + int shift, ashift, isize, k; + long e_int; + + if (e->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (s, &shift) != NULL) + { + gfc_error ("Invalid second argument of ISHFT at %L", &s->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (BT_INTEGER, e->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ishft(): Bad kind"); + + isize = gfc_integer_kinds[k].bit_size; + + if (shift >= 0) + ashift = shift; + else + ashift = -shift; + + if (ashift > isize) + { + gfc_error + ("Magnitude of second argument of ISHFT exceeds bit size at %L", + &s->where); + return &gfc_bad_expr; + } + + e_int = mpz_get_si (e->value.integer); + if (e_int > INT_MAX || e_int < INT_MIN) + gfc_internal_error ("ISHFT: unable to extract integer"); + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + if (shift == 0) + { + mpz_set (result->value.integer, e->value.integer); + return range_check (result, "ISHFT"); + } + + if (shift > 0) + mpz_set_si (result->value.integer, e_int << shift); + else + mpz_set_si (result->value.integer, e_int >> ashift); + + return range_check (result, "ISHFT"); +} + + +gfc_expr * +gfc_simplify_ishftc (gfc_expr * e, gfc_expr * s, gfc_expr * sz) +{ + gfc_expr *result; + int shift, ashift, isize, delta, k; + int i, *bits; + + if (e->expr_type != EXPR_CONSTANT || s->expr_type != EXPR_CONSTANT) + return NULL; + + if (gfc_extract_int (s, &shift) != NULL) + { + gfc_error ("Invalid second argument of ISHFTC at %L", &s->where); + return &gfc_bad_expr; + } + + k = gfc_validate_kind (e->ts.type, e->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_ishftc(): Bad kind"); + + if (sz != NULL) + { + if (gfc_extract_int (sz, &isize) != NULL || isize < 0) + { + gfc_error ("Invalid third argument of ISHFTC at %L", &sz->where); + return &gfc_bad_expr; + } + } + else + isize = gfc_integer_kinds[k].bit_size; + + if (shift >= 0) + ashift = shift; + else + ashift = -shift; + + if (ashift > isize) + { + gfc_error + ("Magnitude of second argument of ISHFTC exceeds third argument " + "at %L", &s->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + bits = gfc_getmem (isize * sizeof (int)); + + for (i = 0; i < isize; i++) + bits[i] = mpz_tstbit (e->value.integer, i); + + delta = isize - ashift; + + if (shift == 0) + { + mpz_set (result->value.integer, e->value.integer); + gfc_free (bits); + return range_check (result, "ISHFTC"); + } + + else if (shift > 0) + { + for (i = 0; i < delta; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i + shift); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i + shift); + } + + for (i = delta; i < isize; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i - delta); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i - delta); + } + + gfc_free (bits); + return range_check (result, "ISHFTC"); + } + else + { + for (i = 0; i < ashift; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i + delta); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i + delta); + } + + for (i = ashift; i < isize; i++) + { + if (bits[i] == 0) + mpz_clrbit (result->value.integer, i + shift); + if (bits[i] == 1) + mpz_setbit (result->value.integer, i + shift); + } + + gfc_free (bits); + return range_check (result, "ISHFTC"); + } +} + + +gfc_expr * +gfc_simplify_kind (gfc_expr * e) +{ + + if (e->ts.type == BT_DERIVED) + { + gfc_error ("Argument of KIND at %L is a DERIVED type", &e->where); + return &gfc_bad_expr; + } + + return gfc_int_expr (e->ts.kind); +} + + +static gfc_expr * +gfc_simplify_bound (gfc_expr * array, gfc_expr * dim, int upper) +{ + gfc_ref *ref; + gfc_array_spec *as; + int i; + + if (array->expr_type != EXPR_VARIABLE) + return NULL; + + if (dim == NULL) + return NULL; + + if (dim->expr_type != EXPR_CONSTANT) + return NULL; + + /* Follow any component references. */ + as = array->symtree->n.sym->as; + ref = array->ref; + while (ref->next != NULL) + { + if (ref->type == REF_COMPONENT) + as = ref->u.c.sym->as; + ref = ref->next; + } + + if (ref->type != REF_ARRAY || ref->u.ar.type != AR_FULL) + return NULL; + + i = mpz_get_si (dim->value.integer); + if (upper) + return as->upper[i-1]; + else + return as->lower[i-1]; +} + + +gfc_expr * +gfc_simplify_lbound (gfc_expr * array, gfc_expr * dim) +{ + return gfc_simplify_bound (array, dim, 0); +} + + +gfc_expr * +gfc_simplify_len (gfc_expr * e) +{ + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + mpz_set_si (result->value.integer, e->value.character.length); + return range_check (result, "LEN"); +} + + +gfc_expr * +gfc_simplify_len_trim (gfc_expr * e) +{ + gfc_expr *result; + int count, len, lentrim, i; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + len = e->value.character.length; + + for (count = 0, i = 1; i <= len; i++) + if (e->value.character.string[len - i] == ' ') + count++; + else + break; + + lentrim = len - count; + + mpz_set_si (result->value.integer, lentrim); + return range_check (result, "LEN_TRIM"); +} + + +gfc_expr * +gfc_simplify_lge (gfc_expr * a, gfc_expr * b) +{ + + if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) + return NULL; + + return gfc_logical_expr (gfc_compare_string (a, b, xascii_table) >= 0, + &a->where); +} + + +gfc_expr * +gfc_simplify_lgt (gfc_expr * a, gfc_expr * b) +{ + + if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) + return NULL; + + return gfc_logical_expr (gfc_compare_string (a, b, xascii_table) > 0, + &a->where); +} + + +gfc_expr * +gfc_simplify_lle (gfc_expr * a, gfc_expr * b) +{ + + if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) + return NULL; + + return gfc_logical_expr (gfc_compare_string (a, b, xascii_table) <= 0, + &a->where); +} + + +gfc_expr * +gfc_simplify_llt (gfc_expr * a, gfc_expr * b) +{ + + if (a->expr_type != EXPR_CONSTANT || b->expr_type != EXPR_CONSTANT) + return NULL; + + return gfc_logical_expr (gfc_compare_string (a, b, xascii_table) < 0, + &a->where); +} + + +gfc_expr * +gfc_simplify_log (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xr, xi; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_REAL: + if (mpf_cmp (x->value.real, mpf_zero) <= 0) + { + gfc_error + ("Argument of LOG at %L cannot be less than or equal to zero", + &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + natural_logarithm (&x->value.real, &result->value.real); + break; + + case BT_COMPLEX: + if ((mpf_cmp (x->value.complex.r, mpf_zero) == 0) + && (mpf_cmp (x->value.complex.i, mpf_zero) == 0)) + { + gfc_error ("Complex argument of LOG at %L cannot be zero", + &x->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + mpf_init (xr); + mpf_init (xi); + + mpf_div (xr, x->value.complex.i, x->value.complex.r); + arctangent2 (&x->value.complex.i, &x->value.complex.r, + &result->value.complex.i); + + mpf_mul (xr, x->value.complex.r, x->value.complex.r); + mpf_mul (xi, x->value.complex.i, x->value.complex.i); + mpf_add (xr, xr, xi); + mpf_sqrt (xr, xr); + natural_logarithm (&xr, &result->value.complex.r); + + mpf_clear (xr); + mpf_clear (xi); + + break; + + default: + gfc_internal_error ("gfc_simplify_log: bad type"); + } + + return range_check (result, "LOG"); +} + + +gfc_expr * +gfc_simplify_log10 (gfc_expr * x) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + if (mpf_cmp (x->value.real, mpf_zero) <= 0) + { + gfc_error + ("Argument of LOG10 at %L cannot be less than or equal to zero", + &x->where); + return &gfc_bad_expr; + } + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + common_logarithm (&x->value.real, &result->value.real); + + return range_check (result, "LOG10"); +} + + +gfc_expr * +gfc_simplify_logical (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + int kind; + + kind = get_kind (BT_LOGICAL, k, "LOGICAL", gfc_default_logical_kind ()); + if (kind < 0) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_LOGICAL, kind, &e->where); + + result->value.logical = e->value.logical; + + return result; +} + + +/* This function is special since MAX() can take any number of + arguments. The simplified expression is a rewritten version of the + argument list containing at most one constant element. Other + constant elements are deleted. Because the argument list has + already been checked, this function always succeeds. sign is 1 for + MAX(), -1 for MIN(). */ + +static gfc_expr * +simplify_min_max (gfc_expr * expr, int sign) +{ + gfc_actual_arglist *arg, *last, *extremum; + gfc_intrinsic_sym * specific; + + last = NULL; + extremum = NULL; + specific = expr->value.function.isym; + + arg = expr->value.function.actual; + + for (; arg; last = arg, arg = arg->next) + { + if (arg->expr->expr_type != EXPR_CONSTANT) + continue; + + if (extremum == NULL) + { + extremum = arg; + continue; + } + + switch (arg->expr->ts.type) + { + case BT_INTEGER: + if (mpz_cmp (arg->expr->value.integer, + extremum->expr->value.integer) * sign > 0) + mpz_set (extremum->expr->value.integer, arg->expr->value.integer); + + break; + + case BT_REAL: + if (mpf_cmp (arg->expr->value.real, extremum->expr->value.real) * + sign > 0) + mpf_set (extremum->expr->value.real, arg->expr->value.real); + + break; + + default: + gfc_internal_error ("gfc_simplify_max(): Bad type in arglist"); + } + + /* Delete the extra constant argument. */ + if (last == NULL) + expr->value.function.actual = arg->next; + else + last->next = arg->next; + + arg->next = NULL; + gfc_free_actual_arglist (arg); + arg = last; + } + + /* If there is one value left, replace the function call with the + expression. */ + if (expr->value.function.actual->next != NULL) + return NULL; + + /* Convert to the correct type and kind. */ + if (expr->ts.type != BT_UNKNOWN) + return gfc_convert_constant (expr->value.function.actual->expr, + expr->ts.type, expr->ts.kind); + + if (specific->ts.type != BT_UNKNOWN) + return gfc_convert_constant (expr->value.function.actual->expr, + specific->ts.type, specific->ts.kind); + + return gfc_copy_expr (expr->value.function.actual->expr); +} + + +gfc_expr * +gfc_simplify_min (gfc_expr * e) +{ + + return simplify_min_max (e, -1); +} + + +gfc_expr * +gfc_simplify_max (gfc_expr * e) +{ + + return simplify_min_max (e, 1); +} + + +gfc_expr * +gfc_simplify_maxexponent (gfc_expr * x) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (BT_REAL, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_maxexponent(): Bad kind"); + + result = gfc_int_expr (gfc_real_kinds[i].max_exponent); + result->where = x->where; + + return result; +} + + +gfc_expr * +gfc_simplify_minexponent (gfc_expr * x) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (BT_REAL, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_minexponent(): Bad kind"); + + result = gfc_int_expr (gfc_real_kinds[i].min_exponent); + result->where = x->where; + + return result; +} + + +gfc_expr * +gfc_simplify_mod (gfc_expr * a, gfc_expr * p) +{ + gfc_expr *result; + mpf_t quot, iquot, term; + + if (a->expr_type != EXPR_CONSTANT || p->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (a->ts.type, a->ts.kind, &a->where); + + switch (a->ts.type) + { + case BT_INTEGER: + if (mpz_cmp_ui (p->value.integer, 0) == 0) + { + /* Result is processor-dependent. */ + gfc_error ("Second argument MOD at %L is zero", &a->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + mpz_tdiv_r (result->value.integer, a->value.integer, p->value.integer); + break; + + case BT_REAL: + if (mpf_cmp_ui (p->value.real, 0) == 0) + { + /* Result is processor-dependent. */ + gfc_error ("Second argument of MOD at %L is zero", &p->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + mpf_init (quot); + mpf_init (iquot); + mpf_init (term); + + mpf_div (quot, a->value.real, p->value.real); + mpf_trunc (iquot, quot); + mpf_mul (term, iquot, p->value.real); + mpf_sub (result->value.real, a->value.real, term); + + mpf_clear (quot); + mpf_clear (iquot); + mpf_clear (term); + break; + + default: + gfc_internal_error ("gfc_simplify_mod(): Bad arguments"); + } + + return range_check (result, "MOD"); +} + + +gfc_expr * +gfc_simplify_modulo (gfc_expr * a, gfc_expr * p) +{ + gfc_expr *result; + mpf_t quot, iquot, term; + + if (a->expr_type != EXPR_CONSTANT || p->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (a->ts.type, a->ts.kind, &a->where); + + switch (a->ts.type) + { + case BT_INTEGER: + if (mpz_cmp_ui (p->value.integer, 0) == 0) + { + /* Result is processor-dependent. This processor just opts + to not handle it at all. */ + gfc_error ("Second argument of MODULO at %L is zero", &a->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + mpz_fdiv_r (result->value.integer, a->value.integer, p->value.integer); + + break; + + case BT_REAL: + if (mpf_cmp_ui (p->value.real, 0) == 0) + { + /* Result is processor-dependent. */ + gfc_error ("Second argument of MODULO at %L is zero", &p->where); + gfc_free_expr (result); + return &gfc_bad_expr; + } + + mpf_init (quot); + mpf_init (iquot); + mpf_init (term); + + mpf_div (quot, a->value.real, p->value.real); + mpf_floor (iquot, quot); + mpf_mul (term, iquot, p->value.real); + + mpf_clear (quot); + mpf_clear (iquot); + mpf_clear (term); + + mpf_sub (result->value.real, a->value.real, term); + break; + + default: + gfc_internal_error ("gfc_simplify_modulo(): Bad arguments"); + } + + return range_check (result, "MODULO"); +} + + +/* Exists for the sole purpose of consistency with other intrinsics. */ +gfc_expr * +gfc_simplify_mvbits (gfc_expr * f ATTRIBUTE_UNUSED, + gfc_expr * fp ATTRIBUTE_UNUSED, + gfc_expr * l ATTRIBUTE_UNUSED, + gfc_expr * to ATTRIBUTE_UNUSED, + gfc_expr * tp ATTRIBUTE_UNUSED) +{ + return NULL; +} + + +gfc_expr * +gfc_simplify_nearest (gfc_expr * x, gfc_expr * s) +{ + gfc_expr *result; + float rval; + double val, eps; + int p, i, k, match_float; + + /* FIXME: This implementation is dopey and probably not quite right, + but it's a start. */ + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + k = gfc_validate_kind (x->ts.type, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_precision(): Bad kind"); + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + val = mpf_get_d (x->value.real); + p = gfc_real_kinds[k].digits; + + eps = 1.; + for (i = 1; i < p; ++i) + { + eps = eps / 2.; + } + + /* TODO we should make sure that 'float' matches kind 4 */ + match_float = gfc_real_kinds[k].kind == 4; + if (mpf_cmp_ui (s->value.real, 0) > 0) + { + if (match_float) + { + rval = (float) val; + rval = rval + eps; + mpf_set_d (result->value.real, rval); + } + else + { + val = val + eps; + mpf_set_d (result->value.real, val); + } + } + else if (mpf_cmp_ui (s->value.real, 0) < 0) + { + if (match_float) + { + rval = (float) val; + rval = rval - eps; + mpf_set_d (result->value.real, rval); + } + else + { + val = val - eps; + mpf_set_d (result->value.real, val); + } + } + else + { + gfc_error ("Invalid second argument of NEAREST at %L", &s->where); + gfc_free (result); + return &gfc_bad_expr; + } + + return range_check (result, "NEAREST"); + +} + + +static gfc_expr * +simplify_nint (const char *name, gfc_expr * e, gfc_expr * k) +{ + gfc_expr *rtrunc, *itrunc, *result; + int kind, cmp; + + kind = get_kind (BT_INTEGER, k, name, gfc_default_integer_kind ()); + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_INTEGER, kind, &e->where); + + rtrunc = gfc_copy_expr (e); + itrunc = gfc_copy_expr (e); + + cmp = mpf_cmp_ui (e->value.real, 0); + + if (cmp > 0) + { + mpf_add (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (itrunc->value.real, rtrunc->value.real); + } + else if (cmp < 0) + { + mpf_sub (rtrunc->value.real, e->value.real, mpf_half); + mpf_trunc (itrunc->value.real, rtrunc->value.real); + } + else + mpf_set_ui (itrunc->value.real, 0); + + mpz_set_f (result->value.integer, itrunc->value.real); + + gfc_free_expr (itrunc); + gfc_free_expr (rtrunc); + + return range_check (result, name); +} + + +gfc_expr * +gfc_simplify_nint (gfc_expr * e, gfc_expr * k) +{ + + return simplify_nint ("NINT", e, k); +} + + +gfc_expr * +gfc_simplify_idnint (gfc_expr * e) +{ + + return simplify_nint ("IDNINT", e, NULL); +} + + +gfc_expr * +gfc_simplify_not (gfc_expr * e) +{ + gfc_expr *result; + int i; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + mpz_com (result->value.integer, e->value.integer); + + /* Because of how GMP handles numbers, the result must be ANDed with + the max_int mask. For radices <> 2, this will require change. */ + + i = gfc_validate_kind (BT_INTEGER, e->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_not(): Bad kind"); + + mpz_and (result->value.integer, result->value.integer, + gfc_integer_kinds[i].max_int); + + return range_check (result, "NOT"); +} + + +gfc_expr * +gfc_simplify_null (gfc_expr * mold) +{ + gfc_expr *result; + + result = gfc_get_expr (); + result->expr_type = EXPR_NULL; + + if (mold == NULL) + result->ts.type = BT_UNKNOWN; + else + { + result->ts = mold->ts; + result->where = mold->where; + } + + return result; +} + + +gfc_expr * +gfc_simplify_precision (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_precision(): Bad kind"); + + result = gfc_int_expr (gfc_real_kinds[i].precision); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_radix (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + goto bad; + + switch (e->ts.type) + { + case BT_INTEGER: + i = gfc_integer_kinds[i].radix; + break; + + case BT_REAL: + i = gfc_real_kinds[i].radix; + break; + + default: + bad: + gfc_internal_error ("gfc_simplify_radix(): Bad type"); + } + + result = gfc_int_expr (i); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_range (gfc_expr * e) +{ + gfc_expr *result; + int i; + long j; + + i = gfc_validate_kind (e->ts.type, e->ts.kind); + if (i == -1) + goto bad_type; + + switch (e->ts.type) + { + case BT_INTEGER: + j = gfc_integer_kinds[i].range; + break; + + case BT_REAL: + case BT_COMPLEX: + j = gfc_real_kinds[i].range; + break; + + bad_type: + default: + gfc_internal_error ("gfc_simplify_range(): Bad kind"); + } + + result = gfc_int_expr (j); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_real (gfc_expr * e, gfc_expr * k) +{ + gfc_expr *result; + int kind; + + if (e->ts.type == BT_COMPLEX) + kind = get_kind (BT_REAL, k, "REAL", e->ts.kind); + else + kind = get_kind (BT_REAL, k, "REAL", gfc_default_real_kind ()); + + if (kind == -1) + return &gfc_bad_expr; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + switch (e->ts.type) + { + case BT_INTEGER: + result = gfc_int2real (e, kind); + break; + + case BT_REAL: + result = gfc_real2real (e, kind); + break; + + case BT_COMPLEX: + result = gfc_complex2real (e, kind); + break; + + default: + gfc_internal_error ("bad type in REAL"); + /* Not reached */ + } + + return range_check (result, "REAL"); +} + +gfc_expr * +gfc_simplify_repeat (gfc_expr * e, gfc_expr * n) +{ + gfc_expr *result; + int i, j, len, ncopies, nlen; + + if (e->expr_type != EXPR_CONSTANT || n->expr_type != EXPR_CONSTANT) + return NULL; + + if (n != NULL && (gfc_extract_int (n, &ncopies) != NULL || ncopies < 0)) + { + gfc_error ("Invalid second argument of REPEAT at %L", &n->where); + return &gfc_bad_expr; + } + + len = e->value.character.length; + nlen = ncopies * len; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + if (ncopies == 0) + { + result->value.character.string = gfc_getmem (1); + result->value.character.length = 0; + result->value.character.string[0] = '\0'; + return result; + } + + result->value.character.length = nlen; + result->value.character.string = gfc_getmem (nlen + 1); + + for (i = 0; i < ncopies; i++) + for (j = 0; j < len; j++) + result->value.character.string[j + i * len] = + e->value.character.string[j]; + + result->value.character.string[nlen] = '\0'; /* For debugger */ + return result; +} + + +/* This one is a bear, but mainly has to do with shuffling elements. */ + +gfc_expr * +gfc_simplify_reshape (gfc_expr * source, gfc_expr * shape_exp, + gfc_expr * pad, gfc_expr * order_exp) +{ + + int order[GFC_MAX_DIMENSIONS], shape[GFC_MAX_DIMENSIONS]; + int i, rank, npad, x[GFC_MAX_DIMENSIONS]; + gfc_constructor *head, *tail; + mpz_t index, size; + unsigned long j; + size_t nsource; + gfc_expr *e; + + /* Unpack the shape array. */ + if (source->expr_type != EXPR_ARRAY || !gfc_is_constant_expr (source)) + return NULL; + + if (shape_exp->expr_type != EXPR_ARRAY || !gfc_is_constant_expr (shape_exp)) + return NULL; + + if (pad != NULL + && (pad->expr_type != EXPR_ARRAY + || !gfc_is_constant_expr (pad))) + return NULL; + + if (order_exp != NULL + && (order_exp->expr_type != EXPR_ARRAY + || !gfc_is_constant_expr (order_exp))) + return NULL; + + mpz_init (index); + rank = 0; + head = tail = NULL; + + for (;;) + { + e = gfc_get_array_element (shape_exp, rank); + if (e == NULL) + break; + + if (gfc_extract_int (e, &shape[rank]) != NULL) + { + gfc_error ("Integer too large in shape specification at %L", + &e->where); + gfc_free_expr (e); + goto bad_reshape; + } + + gfc_free_expr (e); + + if (rank >= GFC_MAX_DIMENSIONS) + { + gfc_error ("Too many dimensions in shape specification for RESHAPE " + "at %L", &e->where); + + goto bad_reshape; + } + + if (shape[rank] < 0) + { + gfc_error ("Shape specification at %L cannot be negative", + &e->where); + goto bad_reshape; + } + + rank++; + } + + if (rank == 0) + { + gfc_error ("Shape specification at %L cannot be the null array", + &shape_exp->where); + goto bad_reshape; + } + + /* Now unpack the order array if present. */ + if (order_exp == NULL) + { + for (i = 0; i < rank; i++) + order[i] = i; + + } + else + { + + for (i = 0; i < rank; i++) + x[i] = 0; + + for (i = 0; i < rank; i++) + { + e = gfc_get_array_element (order_exp, i); + if (e == NULL) + { + gfc_error + ("ORDER parameter of RESHAPE at %L is not the same size " + "as SHAPE parameter", &order_exp->where); + goto bad_reshape; + } + + if (gfc_extract_int (e, &order[i]) != NULL) + { + gfc_error ("Error in ORDER parameter of RESHAPE at %L", + &e->where); + gfc_free_expr (e); + goto bad_reshape; + } + + gfc_free_expr (e); + + if (order[i] < 1 || order[i] > rank) + { + gfc_error ("ORDER parameter of RESHAPE at %L is out of range", + &e->where); + goto bad_reshape; + } + + order[i]--; + + if (x[order[i]]) + { + gfc_error ("Invalid permutation in ORDER parameter at %L", + &e->where); + goto bad_reshape; + } + + x[order[i]] = 1; + } + } + + /* Count the elements in the source and padding arrays. */ + + npad = 0; + if (pad != NULL) + { + gfc_array_size (pad, &size); + npad = mpz_get_ui (size); + mpz_clear (size); + } + + gfc_array_size (source, &size); + nsource = mpz_get_ui (size); + mpz_clear (size); + + /* If it weren't for that pesky permutation we could just loop + through the source and round out any shortage with pad elements. + But no, someone just had to have the compiler do something the + user should be doing. */ + + for (i = 0; i < rank; i++) + x[i] = 0; + + for (;;) + { + /* Figure out which element to extract. */ + mpz_set_ui (index, 0); + + for (i = rank - 1; i >= 0; i--) + { + mpz_add_ui (index, index, x[order[i]]); + if (i != 0) + mpz_mul_ui (index, index, shape[order[i - 1]]); + } + + if (mpz_cmp_ui (index, INT_MAX) > 0) + gfc_internal_error ("Reshaped array too large at %L", &e->where); + + j = mpz_get_ui (index); + + if (j < nsource) + e = gfc_get_array_element (source, j); + else + { + j = j - nsource; + + if (npad == 0) + { + gfc_error + ("PAD parameter required for short SOURCE parameter at %L", + &source->where); + goto bad_reshape; + } + + j = j % npad; + e = gfc_get_array_element (pad, j); + } + + if (head == NULL) + head = tail = gfc_get_constructor (); + else + { + tail->next = gfc_get_constructor (); + tail = tail->next; + } + + if (e == NULL) + goto bad_reshape; + + tail->where = e->where; + tail->expr = e; + + /* Calculate the next element. */ + i = 0; + +inc: + if (++x[i] < shape[i]) + continue; + x[i++] = 0; + if (i < rank) + goto inc; + + break; + } + + mpz_clear (index); + + e = gfc_get_expr (); + e->where = source->where; + e->expr_type = EXPR_ARRAY; + e->value.constructor = head; + e->shape = gfc_get_shape (rank); + + for (i = 0; i < rank; i++) + mpz_init_set_ui (e->shape[i], shape[order[i]]); + + e->ts = head->expr->ts; + e->rank = rank; + + return e; + +bad_reshape: + gfc_free_constructor (head); + mpz_clear (index); + return &gfc_bad_expr; +} + + +gfc_expr * +gfc_simplify_rrspacing (gfc_expr * x) +{ + gfc_expr *result; + mpf_t i2, absv, ln2, lnx, frac, pow2; + unsigned long exp2; + int i, p; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + i = gfc_validate_kind (x->ts.type, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_rrspacing(): Bad kind"); + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + p = gfc_real_kinds[i].digits; + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_ui_div (result->value.real, 1, gfc_real_kinds[i].tiny); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (ln2); + mpf_init (absv); + mpf_init (lnx); + mpf_init (frac); + mpf_init (pow2); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + exp2 = (unsigned long) mpf_get_d (lnx); + mpf_pow_ui (pow2, i2, exp2); + mpf_div (frac, absv, pow2); + + exp2 = (unsigned long) p; + mpf_mul_2exp (result->value.real, frac, exp2); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + mpf_clear (frac); + mpf_clear (pow2); + + return range_check (result, "RRSPACING"); +} + + +gfc_expr * +gfc_simplify_scale (gfc_expr * x, gfc_expr * i) +{ + int k, neg_flag, power, exp_range; + mpf_t scale, radix; + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || i->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_sgn (x->value.real) == 0) + { + mpf_set_ui (result->value.real, 0); + return result; + } + + k = gfc_validate_kind (BT_REAL, x->ts.kind); + if (k == -1) + gfc_internal_error ("gfc_simplify_scale(): Bad kind"); + + exp_range = gfc_real_kinds[k].max_exponent - gfc_real_kinds[k].min_exponent; + + /* This check filters out values of i that would overflow an int. */ + if (mpz_cmp_si (i->value.integer, exp_range + 2) > 0 + || mpz_cmp_si (i->value.integer, -exp_range - 2) < 0) + { + gfc_error ("Result of SCALE overflows its kind at %L", &result->where); + return &gfc_bad_expr; + } + + /* Compute scale = radix ** power. */ + power = mpz_get_si (i->value.integer); + + if (power >= 0) + neg_flag = 0; + else + { + neg_flag = 1; + power = -power; + } + + mpf_init_set_ui (radix, gfc_real_kinds[k].radix); + mpf_init (scale); + mpf_pow_ui (scale, radix, power); + + if (neg_flag) + mpf_div (result->value.real, x->value.real, scale); + else + mpf_mul (result->value.real, x->value.real, scale); + + mpf_clear (scale); + mpf_clear (radix); + + return range_check (result, "SCALE"); +} + + +gfc_expr * +gfc_simplify_scan (gfc_expr * e, gfc_expr * c, gfc_expr * b) +{ + gfc_expr *result; + int back; + size_t i; + size_t indx, len, lenc; + + if (e->expr_type != EXPR_CONSTANT || c->expr_type != EXPR_CONSTANT) + return NULL; + + if (b != NULL && b->value.logical != 0) + back = 1; + else + back = 0; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &e->where); + + len = e->value.character.length; + lenc = c->value.character.length; + + if (len == 0 || lenc == 0) + { + indx = 0; + } + else + { + if (back == 0) + { + indx = + strcspn (e->value.character.string, c->value.character.string) + 1; + if (indx > len) + indx = 0; + } + else + { + i = 0; + for (indx = len; indx > 0; indx--) + { + for (i = 0; i < lenc; i++) + { + if (c->value.character.string[i] + == e->value.character.string[indx - 1]) + break; + } + if (i < lenc) + break; + } + } + } + mpz_set_ui (result->value.integer, indx); + return range_check (result, "SCAN"); +} + + +gfc_expr * +gfc_simplify_selected_int_kind (gfc_expr * e) +{ + int i, kind, range; + gfc_expr *result; + + if (e->expr_type != EXPR_CONSTANT || gfc_extract_int (e, &range) != NULL) + return NULL; + + kind = INT_MAX; + + for (i = 0; gfc_integer_kinds[i].kind != 0; i++) + if (gfc_integer_kinds[i].range >= range + && gfc_integer_kinds[i].kind < kind) + kind = gfc_integer_kinds[i].kind; + + if (kind == INT_MAX) + kind = -1; + + result = gfc_int_expr (kind); + result->where = e->where; + + return result; +} + + +gfc_expr * +gfc_simplify_selected_real_kind (gfc_expr * p, gfc_expr * q) +{ + int range, precision, i, kind, found_precision, found_range; + gfc_expr *result; + + if (p == NULL) + precision = 0; + else + { + if (p->expr_type != EXPR_CONSTANT + || gfc_extract_int (p, &precision) != NULL) + return NULL; + } + + if (q == NULL) + range = 0; + else + { + if (q->expr_type != EXPR_CONSTANT + || gfc_extract_int (q, &range) != NULL) + return NULL; + } + + kind = INT_MAX; + found_precision = 0; + found_range = 0; + + for (i = 0; gfc_real_kinds[i].kind != 0; i++) + { + if (gfc_real_kinds[i].precision >= precision) + found_precision = 1; + + if (gfc_real_kinds[i].range >= range) + found_range = 1; + + if (gfc_real_kinds[i].precision >= precision + && gfc_real_kinds[i].range >= range && gfc_real_kinds[i].kind < kind) + kind = gfc_real_kinds[i].kind; + } + + if (kind == INT_MAX) + { + kind = 0; + + if (!found_precision) + kind = -1; + if (!found_range) + kind -= 2; + } + + result = gfc_int_expr (kind); + result->where = (p != NULL) ? p->where : q->where; + + return result; +} + + +gfc_expr * +gfc_simplify_set_exponent (gfc_expr * x, gfc_expr * i) +{ + gfc_expr *result; + mpf_t i2, ln2, absv, lnx, pow2, frac; + unsigned long exp2; + + if (x->expr_type != EXPR_CONSTANT || i->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_set (result->value.real, mpf_zero); + return result; + } + + mpf_init_set_ui (i2, 2); + mpf_init (ln2); + mpf_init (absv); + mpf_init (lnx); + mpf_init (pow2); + mpf_init (frac); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + /* Old exponent value, and fraction. */ + exp2 = (unsigned long) mpf_get_d (lnx); + mpf_pow_ui (pow2, i2, exp2); + + mpf_div (frac, absv, pow2); + + /* New exponent. */ + exp2 = (unsigned long) mpz_get_d (i->value.integer); + mpf_mul_2exp (result->value.real, frac, exp2); + + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + mpf_clear (pow2); + mpf_clear (frac); + + return range_check (result, "SET_EXPONENT"); +} + + +gfc_expr * +gfc_simplify_shape (gfc_expr * source) +{ + mpz_t shape[GFC_MAX_DIMENSIONS]; + gfc_expr *result, *e, *f; + gfc_array_ref *ar; + int n; + try t; + + result = gfc_start_constructor (BT_INTEGER, gfc_default_integer_kind (), + &source->where); + + if (source->rank == 0 || source->expr_type != EXPR_VARIABLE) + return result; + + ar = gfc_find_array_ref (source); + + t = gfc_array_ref_shape (ar, shape); + + for (n = 0; n < source->rank; n++) + { + e = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &source->where); + + if (t == SUCCESS) + { + mpz_set (e->value.integer, shape[n]); + mpz_clear (shape[n]); + } + else + { + mpz_set_ui (e->value.integer, n + 1); + + f = gfc_simplify_size (source, e); + gfc_free_expr (e); + if (f == NULL) + { + gfc_free_expr (result); + return NULL; + } + else + { + e = f; + } + } + + gfc_append_constructor (result, e); + } + + return result; +} + + +gfc_expr * +gfc_simplify_size (gfc_expr * array, gfc_expr * dim) +{ + mpz_t size; + gfc_expr *result; + int d; + + if (dim == NULL) + { + if (gfc_array_size (array, &size) == FAILURE) + return NULL; + } + else + { + if (dim->expr_type != EXPR_CONSTANT) + return NULL; + + d = mpz_get_ui (dim->value.integer) - 1; + if (gfc_array_dimen_size (array, d, &size) == FAILURE) + return NULL; + } + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &array->where); + + mpz_set (result->value.integer, size); + + return result; +} + + +gfc_expr * +gfc_simplify_sign (gfc_expr * x, gfc_expr * y) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_INTEGER: + mpz_abs (result->value.integer, x->value.integer); + if (mpz_sgn (y->value.integer) < 0) + mpz_neg (result->value.integer, result->value.integer); + + break; + + case BT_REAL: + /* TODO: Handle -0.0 and +0.0 correctly on machines that support + it. */ + mpf_abs (result->value.real, x->value.real); + if (mpf_sgn (y->value.integer) < 0) + mpf_neg (result->value.real, result->value.real); + + break; + + default: + gfc_internal_error ("Bad type in gfc_simplify_sign"); + } + + return result; +} + + +gfc_expr * +gfc_simplify_sin (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + switch (x->ts.type) + { + case BT_REAL: + sine (&x->value.real, &result->value.real); + break; + + case BT_COMPLEX: + mpf_init (xp); + mpf_init (xq); + + sine (&x->value.complex.r, &xp); + hypercos (&x->value.complex.i, &xq); + mpf_mul (result->value.complex.r, xp, xq); + + cosine (&x->value.complex.r, &xp); + hypersine (&x->value.complex.i, &xq); + mpf_mul (result->value.complex.i, xp, xq); + + mpf_clear (xp); + mpf_clear (xq); + break; + + default: + gfc_internal_error ("in gfc_simplify_sin(): Bad type"); + } + + return range_check (result, "SIN"); +} + + +gfc_expr * +gfc_simplify_sinh (gfc_expr * x) +{ + gfc_expr *result; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + hypersine (&x->value.real, &result->value.real); + + return range_check (result, "SINH"); +} + + +/* The argument is always a double precision real that is converted to + single precision. TODO: Rounding! */ + +gfc_expr * +gfc_simplify_sngl (gfc_expr * a) +{ + gfc_expr *result; + + if (a->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_real2real (a, gfc_default_real_kind ()); + return range_check (result, "SNGL"); +} + + +gfc_expr * +gfc_simplify_spacing (gfc_expr * x) +{ + gfc_expr *result; + mpf_t i1, i2, ln2, absv, lnx; + long diff; + unsigned long exp2; + int i, p; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + i = gfc_validate_kind (x->ts.type, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_spacing(): Bad kind"); + + p = gfc_real_kinds[i].digits; + + result = gfc_constant_result (BT_REAL, x->ts.kind, &x->where); + + if (mpf_cmp (x->value.real, mpf_zero) == 0) + { + mpf_set (result->value.real, gfc_real_kinds[i].tiny); + return result; + } + + mpf_init_set_ui (i1, 1); + mpf_init_set_ui (i2, 2); + mpf_init (ln2); + mpf_init (absv); + mpf_init (lnx); + + natural_logarithm (&i2, &ln2); + + mpf_abs (absv, x->value.real); + natural_logarithm (&absv, &lnx); + + mpf_div (lnx, lnx, ln2); + mpf_trunc (lnx, lnx); + mpf_add_ui (lnx, lnx, 1); + + diff = (long) mpf_get_d (lnx) - (long) p; + if (diff >= 0) + { + exp2 = (unsigned) diff; + mpf_mul_2exp (result->value.real, i1, exp2); + } + else + { + diff = -diff; + exp2 = (unsigned) diff; + mpf_div_2exp (result->value.real, i1, exp2); + } + + mpf_clear (i1); + mpf_clear (i2); + mpf_clear (ln2); + mpf_clear (absv); + mpf_clear (lnx); + + if (mpf_cmp (result->value.real, gfc_real_kinds[i].tiny) < 0) + mpf_set (result->value.real, gfc_real_kinds[i].tiny); + + return range_check (result, "SPACING"); +} + + +gfc_expr * +gfc_simplify_sqrt (gfc_expr * e) +{ + gfc_expr *result; + mpf_t ac, ad, s, t, w; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (e->ts.type, e->ts.kind, &e->where); + + switch (e->ts.type) + { + case BT_REAL: + if (mpf_cmp_si (e->value.real, 0) < 0) + goto negative_arg; + mpf_sqrt (result->value.real, e->value.real); + + break; + + case BT_COMPLEX: + /* Formula taken from Numerical Recipes to avoid over- and + underflow. */ + + mpf_init (ac); + mpf_init (ad); + mpf_init (s); + mpf_init (t); + mpf_init (w); + + if (mpf_cmp_ui (e->value.complex.r, 0) == 0 + && mpf_cmp_ui (e->value.complex.i, 0) == 0) + { + + mpf_set_ui (result->value.complex.r, 0); + mpf_set_ui (result->value.complex.i, 0); + break; + } + + mpf_abs (ac, e->value.complex.r); + mpf_abs (ad, e->value.complex.i); + + if (mpf_cmp (ac, ad) >= 0) + { + mpf_div (t, e->value.complex.i, e->value.complex.r); + mpf_mul (t, t, t); + mpf_add_ui (t, t, 1); + mpf_sqrt (t, t); + mpf_add_ui (t, t, 1); + mpf_div_ui (t, t, 2); + mpf_sqrt (t, t); + mpf_sqrt (s, ac); + mpf_mul (w, s, t); + } + else + { + mpf_div (s, e->value.complex.r, e->value.complex.i); + mpf_mul (t, s, s); + mpf_add_ui (t, t, 1); + mpf_sqrt (t, t); + mpf_abs (s, s); + mpf_add (t, t, s); + mpf_div_ui (t, t, 2); + mpf_sqrt (t, t); + mpf_sqrt (s, ad); + mpf_mul (w, s, t); + } + + if (mpf_cmp_ui (w, 0) != 0 && mpf_cmp_ui (e->value.complex.r, 0) >= 0) + { + mpf_mul_ui (t, w, 2); + mpf_div (result->value.complex.i, e->value.complex.i, t); + mpf_set (result->value.complex.r, w); + } + else if (mpf_cmp_ui (w, 0) != 0 + && mpf_cmp_ui (e->value.complex.r, 0) < 0 + && mpf_cmp_ui (e->value.complex.i, 0) >= 0) + { + mpf_mul_ui (t, w, 2); + mpf_div (result->value.complex.r, e->value.complex.i, t); + mpf_set (result->value.complex.i, w); + } + else if (mpf_cmp_ui (w, 0) != 0 + && mpf_cmp_ui (e->value.complex.r, 0) < 0 + && mpf_cmp_ui (e->value.complex.i, 0) < 0) + { + mpf_mul_ui (t, w, 2); + mpf_div (result->value.complex.r, ad, t); + mpf_neg (w, w); + mpf_set (result->value.complex.i, w); + } + else + gfc_internal_error ("invalid complex argument of SQRT at %L", + &e->where); + + mpf_clear (s); + mpf_clear (t); + mpf_clear (ac); + mpf_clear (ad); + mpf_clear (w); + + break; + + default: + gfc_internal_error ("invalid argument of SQRT at %L", &e->where); + } + + return range_check (result, "SQRT"); + +negative_arg: + gfc_free_expr (result); + gfc_error ("Argument of SQRT at %L has a negative value", &e->where); + return &gfc_bad_expr; +} + + +gfc_expr * +gfc_simplify_tan (gfc_expr * x) +{ + gfc_expr *result; + mpf_t mpf_sin, mpf_cos, mag_cos; + int i; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + i = gfc_validate_kind (BT_REAL, x->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_tan(): Bad kind"); + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + mpf_init (mpf_sin); + mpf_init (mpf_cos); + mpf_init (mag_cos); + sine (&x->value.real, &mpf_sin); + cosine (&x->value.real, &mpf_cos); + mpf_abs (mag_cos, mpf_cos); + if (mpf_cmp_ui (mag_cos, 0) == 0) + { + gfc_error ("Tangent undefined at %L", &x->where); + mpf_clear (mpf_sin); + mpf_clear (mpf_cos); + mpf_clear (mag_cos); + gfc_free_expr (result); + return &gfc_bad_expr; + } + else if (mpf_cmp (mag_cos, gfc_real_kinds[i].tiny) < 0) + { + gfc_error ("Tangent cannot be accurately evaluated at %L", &x->where); + mpf_clear (mpf_sin); + mpf_clear (mpf_cos); + mpf_clear (mag_cos); + gfc_free_expr (result); + return &gfc_bad_expr; + } + else + { + mpf_div (result->value.real, mpf_sin, mpf_cos); + mpf_clear (mpf_sin); + mpf_clear (mpf_cos); + mpf_clear (mag_cos); + } + + return range_check (result, "TAN"); +} + + +gfc_expr * +gfc_simplify_tanh (gfc_expr * x) +{ + gfc_expr *result; + mpf_t xp, xq; + + if (x->expr_type != EXPR_CONSTANT) + return NULL; + + result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); + + mpf_init (xp); + mpf_init (xq); + + hypersine (&x->value.real, &xq); + hypercos (&x->value.real, &xp); + + mpf_div (result->value.real, xq, xp); + + mpf_clear (xp); + mpf_clear (xq); + + return range_check (result, "TANH"); + +} + + +gfc_expr * +gfc_simplify_tiny (gfc_expr * e) +{ + gfc_expr *result; + int i; + + i = gfc_validate_kind (BT_REAL, e->ts.kind); + if (i == -1) + gfc_internal_error ("gfc_simplify_error(): Bad kind"); + + result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); + mpf_set (result->value.real, gfc_real_kinds[i].tiny); + + return result; +} + + +gfc_expr * +gfc_simplify_trim (gfc_expr * e) +{ + gfc_expr *result; + int count, i, len, lentrim; + + if (e->expr_type != EXPR_CONSTANT) + return NULL; + + len = e->value.character.length; + + result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); + + for (count = 0, i = 1; i <= len; ++i) + { + if (e->value.character.string[len - i] == ' ') + count++; + else + break; + } + + lentrim = len - count; + + result->value.character.length = lentrim; + result->value.character.string = gfc_getmem (lentrim + 1); + + for (i = 0; i < lentrim; i++) + result->value.character.string[i] = e->value.character.string[i]; + + result->value.character.string[lentrim] = '\0'; /* For debugger */ + + return result; +} + + +gfc_expr * +gfc_simplify_ubound (gfc_expr * array, gfc_expr * dim) +{ + return gfc_simplify_bound (array, dim, 1); +} + + +gfc_expr * +gfc_simplify_verify (gfc_expr * s, gfc_expr * set, gfc_expr * b) +{ + gfc_expr *result; + int back; + size_t index, len, lenset; + size_t i; + + if (s->expr_type != EXPR_CONSTANT || set->expr_type != EXPR_CONSTANT) + return NULL; + + if (b != NULL && b->value.logical != 0) + back = 1; + else + back = 0; + + result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind (), + &s->where); + + len = s->value.character.length; + lenset = set->value.character.length; + + if (len == 0) + { + mpz_set_ui (result->value.integer, 0); + return result; + } + + if (back == 0) + { + if (lenset == 0) + { + mpz_set_ui (result->value.integer, len); + return result; + } + + index = + strspn (s->value.character.string, set->value.character.string) + 1; + if (index > len) + index = 0; + + } + else + { + if (lenset == 0) + { + mpz_set_ui (result->value.integer, 1); + return result; + } + for (index = len; index > 0; index --) + { + for (i = 0; i < lenset; i++) + { + if (s->value.character.string[index - 1] + == set->value.character.string[i]) + break; + } + if (i == lenset) + break; + } + } + + mpz_set_ui (result->value.integer, index); + return result; +} + +/****************** Constant simplification *****************/ + +/* Master function to convert one constant to another. While this is + used as a simplification function, it requires the destination type + and kind information which is supplied by a special case in + do_simplify(). */ + +gfc_expr * +gfc_convert_constant (gfc_expr * e, bt type, int kind) +{ + gfc_expr *g, *result, *(*f) (gfc_expr *, int); + gfc_constructor *head, *c, *tail = NULL; + + switch (e->ts.type) + { + case BT_INTEGER: + switch (type) + { + case BT_INTEGER: + f = gfc_int2int; + break; + case BT_REAL: + f = gfc_int2real; + break; + case BT_COMPLEX: + f = gfc_int2complex; + break; + default: + goto oops; + } + break; + + case BT_REAL: + switch (type) + { + case BT_INTEGER: + f = gfc_real2int; + break; + case BT_REAL: + f = gfc_real2real; + break; + case BT_COMPLEX: + f = gfc_real2complex; + break; + default: + goto oops; + } + break; + + case BT_COMPLEX: + switch (type) + { + case BT_INTEGER: + f = gfc_complex2int; + break; + case BT_REAL: + f = gfc_complex2real; + break; + case BT_COMPLEX: + f = gfc_complex2complex; + break; + + default: + goto oops; + } + break; + + case BT_LOGICAL: + if (type != BT_LOGICAL) + goto oops; + f = gfc_log2log; + break; + + default: + oops: + gfc_internal_error ("gfc_convert_constant(): Unexpected type"); + } + + result = NULL; + + switch (e->expr_type) + { + case EXPR_CONSTANT: + result = f (e, kind); + if (result == NULL) + return &gfc_bad_expr; + break; + + case EXPR_ARRAY: + if (!gfc_is_constant_expr (e)) + break; + + head = NULL; + + for (c = e->value.constructor; c; c = c->next) + { + if (head == NULL) + head = tail = gfc_get_constructor (); + else + { + tail->next = gfc_get_constructor (); + tail = tail->next; + } + + tail->where = c->where; + + if (c->iterator == NULL) + tail->expr = f (c->expr, kind); + else + { + g = gfc_convert_constant (c->expr, type, kind); + if (g == &gfc_bad_expr) + return g; + tail->expr = g; + } + + if (tail->expr == NULL) + { + gfc_free_constructor (head); + return NULL; + } + } + + result = gfc_get_expr (); + result->ts.type = type; + result->ts.kind = kind; + result->expr_type = EXPR_ARRAY; + result->value.constructor = head; + result->shape = gfc_copy_shape (e->shape, e->rank); + result->where = e->where; + result->rank = e->rank; + break; + + default: + break; + } + + return result; +} + + +/****************** Helper functions ***********************/ + +/* Given a collating table, create the inverse table. */ + +static void +invert_table (const int *table, int *xtable) +{ + int i; + + for (i = 0; i < 256; i++) + xtable[i] = 0; + + for (i = 0; i < 256; i++) + xtable[table[i]] = i; +} + + +void +gfc_simplify_init_1 (void) +{ + + mpf_init_set_str (mpf_zero, "0.0", 10); + mpf_init_set_str (mpf_half, "0.5", 10); + mpf_init_set_str (mpf_one, "1.0", 10); + mpz_init_set_str (mpz_zero, "0", 10); + + invert_table (ascii_table, xascii_table); +} + + +void +gfc_simplify_done_1 (void) +{ + + mpf_clear (mpf_zero); + mpf_clear (mpf_half); + mpf_clear (mpf_one); + mpz_clear (mpz_zero); +} diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c new file mode 100644 index 00000000000..c4f4533e94f --- /dev/null +++ b/gcc/fortran/st.c @@ -0,0 +1,186 @@ +/* Build executable statement trees. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Executable statements are strung together into a singly linked list + of code structures. These structures are later translated into GCC + GENERIC tree structures and from there to executable code for a + target. */ + +#include "config.h" +#include "gfortran.h" +#include + +gfc_code new_st; + + +/* Zeroes out the new_st structure. */ + +void +gfc_clear_new_st (void) +{ + + memset (&new_st, '\0', sizeof (new_st)); + new_st.op = EXEC_NOP; +} + + +/* Get a gfc_code structure. */ + +gfc_code * +gfc_get_code (void) +{ + gfc_code *c; + + c = gfc_getmem (sizeof (gfc_code)); + c->loc = *gfc_current_locus (); + return c; +} + + +/* Given some part of a gfc_code structure, append a set of code to + its tail, returning a pointer to the new tail. */ + +gfc_code * +gfc_append_code (gfc_code * tail, gfc_code * new) +{ + + if (tail != NULL) + { + while (tail->next != NULL) + tail = tail->next; + + tail->next = new; + } + + while (new->next != NULL) + new = new->next; + + return new; +} + + +/* Free a single code structure, but not the actual structure itself. */ + +void +gfc_free_statement (gfc_code * p) +{ + + if (p->expr) + gfc_free_expr (p->expr); + if (p->expr2) + gfc_free_expr (p->expr2); + + switch (p->op) + { + case EXEC_NOP: + case EXEC_ASSIGN: + case EXEC_GOTO: + case EXEC_CYCLE: + case EXEC_RETURN: + case EXEC_IF: + case EXEC_PAUSE: + case EXEC_STOP: + case EXEC_EXIT: + case EXEC_WHERE: + case EXEC_IOLENGTH: + case EXEC_POINTER_ASSIGN: + case EXEC_DO_WHILE: + case EXEC_CONTINUE: + case EXEC_TRANSFER: + case EXEC_LABEL_ASSIGN: + + case EXEC_ARITHMETIC_IF: + break; + + case EXEC_CALL: + gfc_free_actual_arglist (p->ext.actual); + break; + + case EXEC_SELECT: + if (p->ext.case_list) + gfc_free_case_list (p->ext.case_list); + break; + + case EXEC_DO: + gfc_free_iterator (p->ext.iterator, 1); + break; + + case EXEC_ALLOCATE: + case EXEC_DEALLOCATE: + gfc_free_alloc_list (p->ext.alloc_list); + break; + + case EXEC_OPEN: + gfc_free_open (p->ext.open); + break; + + case EXEC_CLOSE: + gfc_free_close (p->ext.close); + break; + + case EXEC_BACKSPACE: + case EXEC_ENDFILE: + case EXEC_REWIND: + gfc_free_filepos (p->ext.filepos); + break; + + case EXEC_INQUIRE: + gfc_free_inquire (p->ext.inquire); + break; + + case EXEC_READ: + case EXEC_WRITE: + gfc_free_dt (p->ext.dt); + break; + + case EXEC_DT_END: + /* The ext.dt member is a duplicate pointer and doesn't need to + be freed. */ + break; + + case EXEC_FORALL: + gfc_free_forall_iterator (p->ext.forall_iterator); + break; + + default: + gfc_internal_error ("gfc_free_statement(): Bad statement"); + } +} + + +/* Free a code statement and all other code structures linked to it. */ + +void +gfc_free_statements (gfc_code * p) +{ + gfc_code *q; + + for (; p; p = q) + { + q = p->next; + + if (p->block) + gfc_free_statements (p->block); + gfc_free_statement (p); + gfc_free (p); + } +} + diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c new file mode 100644 index 00000000000..1bf32b241e7 --- /dev/null +++ b/gcc/fortran/symbol.c @@ -0,0 +1,2417 @@ +/* Maintain binary trees of symbols. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include +#include +#include + +#include "gfortran.h" +#include "parse.h" + +/* Strings for all symbol attributes. We use these for dumping the + parse tree, in error messages, and also when reading and writing + modules. */ + +const mstring flavors[] = +{ + minit ("UNKNOWN-FL", FL_UNKNOWN), minit ("PROGRAM", FL_PROGRAM), + minit ("BLOCK-DATA", FL_BLOCK_DATA), minit ("MODULE", FL_MODULE), + minit ("VARIABLE", FL_VARIABLE), minit ("PARAMETER", FL_PARAMETER), + minit ("LABEL", FL_LABEL), minit ("PROCEDURE", FL_PROCEDURE), + minit ("DERIVED", FL_DERIVED), minit ("NAMELIST", FL_NAMELIST), + minit (NULL, -1) +}; + +const mstring procedures[] = +{ + minit ("UNKNOWN-PROC", PROC_UNKNOWN), + minit ("MODULE-PROC", PROC_MODULE), + minit ("INTERNAL-PROC", PROC_INTERNAL), + minit ("DUMMY-PROC", PROC_DUMMY), + minit ("INTRINSIC-PROC", PROC_INTRINSIC), + minit ("EXTERNAL-PROC", PROC_EXTERNAL), + minit ("STATEMENT-PROC", PROC_ST_FUNCTION), + minit (NULL, -1) +}; + +const mstring intents[] = +{ + minit ("UNKNOWN-INTENT", INTENT_UNKNOWN), + minit ("IN", INTENT_IN), + minit ("OUT", INTENT_OUT), + minit ("INOUT", INTENT_INOUT), + minit (NULL, -1) +}; + +const mstring access_types[] = +{ + minit ("UNKNOWN-ACCESS", ACCESS_UNKNOWN), + minit ("PUBLIC", ACCESS_PUBLIC), + minit ("PRIVATE", ACCESS_PRIVATE), + minit (NULL, -1) +}; + +const mstring ifsrc_types[] = +{ + minit ("UNKNOWN", IFSRC_UNKNOWN), + minit ("DECL", IFSRC_DECL), + minit ("BODY", IFSRC_IFBODY), + minit ("USAGE", IFSRC_USAGE) +}; + + +/* This is to make sure the backend generates setup code in the correct + order. */ + +static int next_dummy_order = 1; + + +gfc_namespace *gfc_current_ns; + +static gfc_symbol *changed_syms = NULL; + + +/*********** IMPLICIT NONE and IMPLICIT statement handlers ***********/ + +/* The following static variables hold the default types set by + IMPLICIT statements. We have to store kind information because of + IMPLICIT DOUBLE PRECISION statements. IMPLICIT NONE stores a + BT_UNKNOWN into all elements. The arrays of flags indicate whether + a particular element has been explicitly set or not. */ + +static gfc_typespec new_ts[GFC_LETTERS]; +static int new_flag[GFC_LETTERS]; + + +/* Handle a correctly parsed IMPLICIT NONE. */ + +void +gfc_set_implicit_none (void) +{ + int i; + + for (i = 'a'; i <= 'z'; i++) + { + gfc_clear_ts (&gfc_current_ns->default_type[i - 'a']); + gfc_current_ns->set_flag[i - 'a'] = 1; + } +} + + +/* Sets the implicit types parsed by gfc_match_implicit(). */ + +void +gfc_set_implicit (void) +{ + int i; + + for (i = 0; i < GFC_LETTERS; i++) + if (new_flag[i]) + { + gfc_current_ns->default_type[i] = new_ts[i]; + gfc_current_ns->set_flag[i] = 1; + } +} + + +/* Wipe anything a previous IMPLICIT statement may have tried to do. */ +void gfc_clear_new_implicit (void) +{ + int i; + + for (i = 0; i < GFC_LETTERS; i++) + { + gfc_clear_ts (&new_ts[i]); + if (new_flag[i]) + new_flag[i] = 0; + } +} + + +/* Prepare for a new implicit range. Sets flags in new_flag[] and + copies the typespec to new_ts[]. */ + +try gfc_add_new_implicit_range (int c1, int c2, gfc_typespec * ts) +{ + int i; + + c1 -= 'a'; + c2 -= 'a'; + + for (i = c1; i <= c2; i++) + { + if (new_flag[i]) + { + gfc_error ("Letter '%c' already set in IMPLICIT statement at %C", + i + 'A'); + return FAILURE; + } + + new_ts[i] = *ts; + new_flag[i] = 1; + } + + return SUCCESS; +} + + +/* Add a matched implicit range for gfc_set_implicit(). An implicit + statement has been fully matched at this point. We now need to + check if merging the new implicit types back into the existing + types will work. */ + +try +gfc_merge_new_implicit (void) +{ + int i; + + for (i = 0; i < GFC_LETTERS; i++) + if (new_flag[i]) + { + if (gfc_current_ns->set_flag[i]) + { + gfc_error ("Letter %c already has an IMPLICIT type at %C", + i + 'A'); + return FAILURE; + } + } + + return SUCCESS; +} + + +/* Given a symbol, return a pointer to the typespec for it's default + type. */ + +gfc_typespec * +gfc_get_default_type (gfc_symbol * sym, gfc_namespace * ns) +{ + char letter; + + letter = sym->name[0]; + if (letter < 'a' || letter > 'z') + gfc_internal_error ("gfc_get_default_type(): Bad symbol"); + + if (ns == NULL) + ns = gfc_current_ns; + + return &ns->default_type[letter - 'a']; +} + + +/* Given a pointer to a symbol, set its type according to the first + letter of its name. Fails if the letter in question has no default + type. */ + +try +gfc_set_default_type (gfc_symbol * sym, int error_flag, gfc_namespace * ns) +{ + gfc_typespec *ts; + + if (sym->ts.type != BT_UNKNOWN) + gfc_internal_error ("gfc_set_default_type(): symbol already has a type"); + + ts = gfc_get_default_type (sym, ns); + + if (ts->type == BT_UNKNOWN) + { + if (error_flag) + gfc_error ("Symbol '%s' at %L has no IMPLICIT type", sym->name, + &sym->declared_at); + + return FAILURE; + } + + sym->ts = *ts; + sym->attr.implicit_type = 1; + + return SUCCESS; +} + + +/******************** Symbol attribute stuff *********************/ + +/* This is a generic conflict-checker. We do this to avoid having a + single conflict in two places. */ + +#define conf(a, b) if (attr->a && attr->b) { a1 = a; a2 = b; goto conflict; } +#define conf2(a) if (attr->a) { a2 = a; goto conflict; } + +static try +check_conflict (symbol_attribute * attr, locus * where) +{ + static const char *dummy = "DUMMY", *save = "SAVE", *pointer = "POINTER", + *target = "TARGET", *external = "EXTERNAL", *intent = "INTENT", + *intrinsic = "INTRINSIC", *allocatable = "ALLOCATABLE", + *elemental = "ELEMENTAL", *private = "PRIVATE", *recursive = "RECURSIVE", + *in_common = "COMMON", *result = "RESULT", *in_namelist = "NAMELIST", + *public = "PUBLIC", *optional = "OPTIONAL", *entry = "ENTRY", + *function = "FUNCTION", *subroutine = "SUBROUTINE", + *dimension = "DIMENSION"; + + const char *a1, *a2; + + if (where == NULL) + where = gfc_current_locus (); + + if (attr->pointer && attr->intent != INTENT_UNKNOWN) + { + a1 = pointer; + a2 = intent; + goto conflict; + } + + /* Check for attributes not allowed in a BLOCK DATA. */ + if (gfc_current_state () == COMP_BLOCK_DATA) + { + a1 = NULL; + + if (attr->allocatable) + a1 = allocatable; + if (attr->external) + a1 = external; + if (attr->optional) + a1 = optional; + if (attr->access == ACCESS_PRIVATE) + a1 = private; + if (attr->access == ACCESS_PUBLIC) + a1 = public; + if (attr->intent != INTENT_UNKNOWN) + a1 = intent; + + if (a1 != NULL) + { + gfc_error + ("%s attribute not allowed in BLOCK DATA program unit at %L", a1, + where); + return FAILURE; + } + } + + conf (dummy, save); + conf (pointer, target); + conf (pointer, external); + conf (pointer, intrinsic); + conf (target, external); + conf (target, intrinsic); + conf (external, dimension); /* See Fortran 95's R504. */ + + conf (external, intrinsic); + conf (allocatable, pointer); + conf (allocatable, dummy); /* TODO: Allowed in Fortran 200x. */ + conf (allocatable, function); /* TODO: Allowed in Fortran 200x. */ + conf (allocatable, result); /* TODO: Allowed in Fortran 200x. */ + conf (elemental, recursive); + + conf (in_common, dummy); + conf (in_common, allocatable); + conf (in_common, result); + conf (dummy, result); + + conf (in_namelist, pointer); + conf (in_namelist, allocatable); + + conf (entry, result); + + conf (function, subroutine); + + a1 = gfc_code2string (flavors, attr->flavor); + + if (attr->in_namelist + && attr->flavor != FL_VARIABLE + && attr->flavor != FL_UNKNOWN) + { + + a2 = in_namelist; + goto conflict; + } + + switch (attr->flavor) + { + case FL_PROGRAM: + case FL_BLOCK_DATA: + case FL_MODULE: + case FL_LABEL: + conf2 (dummy); + conf2 (save); + conf2 (pointer); + conf2 (target); + conf2 (external); + conf2 (intrinsic); + conf2 (allocatable); + conf2 (result); + conf2 (in_namelist); + conf2 (optional); + conf2 (function); + conf2 (subroutine); + break; + + case FL_VARIABLE: + case FL_NAMELIST: + break; + + case FL_PROCEDURE: + conf2 (intent); + + if (attr->subroutine) + { + conf2(save); + conf2(pointer); + conf2(target); + conf2(allocatable); + conf2(result); + conf2(in_namelist); + conf2(function); + } + + switch (attr->proc) + { + case PROC_ST_FUNCTION: + conf2 (in_common); + break; + + case PROC_MODULE: + conf2 (dummy); + break; + + case PROC_DUMMY: + conf2 (result); + conf2 (in_common); + conf2 (save); + break; + + default: + break; + } + + break; + + case FL_DERIVED: + conf2 (dummy); + conf2 (save); + conf2 (pointer); + conf2 (target); + conf2 (external); + conf2 (intrinsic); + conf2 (allocatable); + conf2 (optional); + conf2 (entry); + conf2 (function); + conf2 (subroutine); + + if (attr->intent != INTENT_UNKNOWN) + { + a2 = intent; + goto conflict; + } + break; + + case FL_PARAMETER: + conf2 (external); + conf2 (intrinsic); + conf2 (optional); + conf2 (allocatable); + conf2 (function); + conf2 (subroutine); + conf2 (entry); + conf2 (pointer); + conf2 (target); + conf2 (dummy); + conf2 (in_common); + break; + + default: + break; + } + + return SUCCESS; + +conflict: + gfc_error ("%s attribute conflicts with %s attribute at %L", a1, a2, where); + return FAILURE; +} + +#undef conf +#undef conf2 + + +/* Mark a symbol as referenced. */ + +void +gfc_set_sym_referenced (gfc_symbol * sym) +{ + if (sym->attr.referenced) + return; + + sym->attr.referenced = 1; + + /* Remember which order dummy variables are accessed in. */ + if (sym->attr.dummy) + sym->dummy_order = next_dummy_order++; +} + + +/* Common subroutine called by attribute changing subroutines in order + to prevent them from changing a symbol that has been + use-associated. Returns zero if it is OK to change the symbol, + nonzero if not. */ + +static int +check_used (symbol_attribute * attr, locus * where) +{ + + if (attr->use_assoc == 0) + return 0; + + if (where == NULL) + where = gfc_current_locus (); + + gfc_error ("Cannot change attributes of USE-associated symbol at %L", + where); + + return 1; +} + + +/* Used to prevent changing the attributes of a symbol after it has been + used. This check is only done from dummy variable as only these can be + used in specification expressions. Applying this to all symbols causes + error when we reach the body of a contained function. */ + +static int +check_done (symbol_attribute * attr, locus * where) +{ + + if (!(attr->dummy && attr->referenced)) + return 0; + + if (where == NULL) + where = gfc_current_locus (); + + gfc_error ("Cannot change attributes of symbol at %L" + " after it has been used", where); + + return 1; +} + + +/* Generate an error because of a duplicate attribute. */ + +static void +duplicate_attr (const char *attr, locus * where) +{ + + if (where == NULL) + where = gfc_current_locus (); + + gfc_error ("Duplicate %s attribute specified at %L", attr, where); +} + + +try +gfc_add_allocatable (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + if (attr->allocatable) + { + duplicate_attr ("ALLOCATABLE", where); + return FAILURE; + } + + attr->allocatable = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_dimension (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + if (attr->dimension) + { + duplicate_attr ("DIMENSION", where); + return FAILURE; + } + + attr->dimension = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_external (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + if (attr->external) + { + duplicate_attr ("EXTERNAL", where); + return FAILURE; + } + + attr->external = 1; + + return check_conflict (attr, where); +} + + +try +gfc_add_intrinsic (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + if (attr->intrinsic) + { + duplicate_attr ("INTRINSIC", where); + return FAILURE; + } + + attr->intrinsic = 1; + + return check_conflict (attr, where); +} + + +try +gfc_add_optional (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + if (attr->optional) + { + duplicate_attr ("OPTIONAL", where); + return FAILURE; + } + + attr->optional = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_pointer (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + attr->pointer = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_result (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + attr->result = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_save (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where)) + return FAILURE; + + if (gfc_pure (NULL)) + { + gfc_error + ("SAVE attribute at %L cannot be specified in a PURE procedure", + where); + return FAILURE; + } + + if (attr->save) + { + duplicate_attr ("SAVE", where); + return FAILURE; + } + + attr->save = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_saved_common (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where)) + return FAILURE; + + if (attr->saved_common) + { + duplicate_attr ("SAVE", where); + return FAILURE; + } + + attr->saved_common = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_target (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + if (attr->target) + { + duplicate_attr ("TARGET", where); + return FAILURE; + } + + attr->target = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_dummy (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where)) + return FAILURE; + + /* Duplicate dummy arguments are allow due to ENTRY statements. */ + attr->dummy = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_common (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + attr->common = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_in_common (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + /* Duplicate attribute already checked for. */ + attr->in_common = 1; + if (check_conflict (attr, where) == FAILURE) + return FAILURE; + + if (attr->flavor == FL_VARIABLE) + return SUCCESS; + + return gfc_add_flavor (attr, FL_VARIABLE, where); +} + + +try +gfc_add_in_namelist (symbol_attribute * attr, locus * where) +{ + + attr->in_namelist = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_sequence (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where)) + return FAILURE; + + attr->sequence = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_elemental (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + attr->elemental = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_pure (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + attr->pure = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_recursive (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + attr->recursive = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_entry (symbol_attribute * attr, locus * where) +{ + + if (check_used (attr, where)) + return FAILURE; + + if (attr->entry) + { + duplicate_attr ("ENTRY", where); + return FAILURE; + } + + attr->entry = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_function (symbol_attribute * attr, locus * where) +{ + + if (attr->flavor != FL_PROCEDURE + && gfc_add_flavor (attr, FL_PROCEDURE, where) == FAILURE) + return FAILURE; + + attr->function = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_subroutine (symbol_attribute * attr, locus * where) +{ + + if (attr->flavor != FL_PROCEDURE + && gfc_add_flavor (attr, FL_PROCEDURE, where) == FAILURE) + return FAILURE; + + attr->subroutine = 1; + return check_conflict (attr, where); +} + + +try +gfc_add_generic (symbol_attribute * attr, locus * where) +{ + + if (attr->flavor != FL_PROCEDURE + && gfc_add_flavor (attr, FL_PROCEDURE, where) == FAILURE) + return FAILURE; + + attr->generic = 1; + return check_conflict (attr, where); +} + + +/* Flavors are special because some flavors are not what fortran + considers attributes and can be reaffirmed multiple times. */ + +try +gfc_add_flavor (symbol_attribute * attr, sym_flavor f, locus * where) +{ + + if ((f == FL_PROGRAM || f == FL_BLOCK_DATA || f == FL_MODULE + || f == FL_PARAMETER || f == FL_LABEL || f == FL_DERIVED + || f == FL_NAMELIST) && check_used (attr, where)) + return FAILURE; + + if (attr->flavor == f && f == FL_VARIABLE) + return SUCCESS; + + if (attr->flavor != FL_UNKNOWN) + { + if (where == NULL) + where = gfc_current_locus (); + + gfc_error ("%s attribute conflicts with %s attribute at %L", + gfc_code2string (flavors, attr->flavor), + gfc_code2string (flavors, f), where); + + return FAILURE; + } + + attr->flavor = f; + + return check_conflict (attr, where); +} + + +try +gfc_add_procedure (symbol_attribute * attr, procedure_type t, locus * where) +{ + + if (check_used (attr, where) || check_done (attr, where)) + return FAILURE; + + if (attr->flavor != FL_PROCEDURE + && gfc_add_flavor (attr, FL_PROCEDURE, where) == FAILURE) + return FAILURE; + + if (where == NULL) + where = gfc_current_locus (); + + if (attr->proc != PROC_UNKNOWN) + { + gfc_error ("%s procedure at %L is already %s %s procedure", + gfc_code2string (procedures, t), where, + gfc_article (gfc_code2string (procedures, attr->proc)), + gfc_code2string (procedures, attr->proc)); + + return FAILURE; + } + + attr->proc = t; + + /* Statement functions are always scalar and functions. */ + if (t == PROC_ST_FUNCTION + && ((!attr->function && gfc_add_function (attr, where) == FAILURE) + || attr->dimension)) + return FAILURE; + + return check_conflict (attr, where); +} + + +try +gfc_add_intent (symbol_attribute * attr, sym_intent intent, locus * where) +{ + + if (check_used (attr, where)) + return FAILURE; + + if (attr->intent == INTENT_UNKNOWN) + { + attr->intent = intent; + return check_conflict (attr, where); + } + + if (where == NULL) + where = gfc_current_locus (); + + gfc_error ("INTENT (%s) conflicts with INTENT(%s) at %L", + gfc_intent_string (attr->intent), + gfc_intent_string (intent), where); + + return FAILURE; +} + + +/* No checks for use-association in public and private statements. */ + +try +gfc_add_access (symbol_attribute * attr, gfc_access access, locus * where) +{ + + if (attr->access == ACCESS_UNKNOWN) + { + attr->access = access; + return check_conflict (attr, where); + } + + if (where == NULL) + where = gfc_current_locus (); + gfc_error ("ACCESS specification at %L was already specified", where); + + return FAILURE; +} + + +try +gfc_add_explicit_interface (gfc_symbol * sym, ifsrc source, + gfc_formal_arglist * formal, locus * where) +{ + + if (check_used (&sym->attr, where)) + return FAILURE; + + if (where == NULL) + where = gfc_current_locus (); + + if (sym->attr.if_source != IFSRC_UNKNOWN + && sym->attr.if_source != IFSRC_DECL) + { + gfc_error ("Symbol '%s' at %L already has an explicit interface", + sym->name, where); + return FAILURE; + } + + sym->formal = formal; + sym->attr.if_source = source; + + return SUCCESS; +} + + +/* Add a type to a symbol. */ + +try +gfc_add_type (gfc_symbol * sym, gfc_typespec * ts, locus * where) +{ + sym_flavor flavor; + +/* TODO: This is legal if it is reaffirming an implicit type. + if (check_done (&sym->attr, where)) + return FAILURE;*/ + + if (where == NULL) + where = gfc_current_locus (); + + if (sym->ts.type != BT_UNKNOWN) + { + gfc_error ("Symbol '%s' at %L already has basic type of %s", sym->name, + where, gfc_basic_typename (sym->ts.type)); + return FAILURE; + } + + flavor = sym->attr.flavor; + + if (flavor == FL_PROGRAM || flavor == FL_BLOCK_DATA || flavor == FL_MODULE + || flavor == FL_LABEL || (flavor == FL_PROCEDURE + && sym->attr.subroutine) + || flavor == FL_DERIVED || flavor == FL_NAMELIST) + { + gfc_error ("Symbol '%s' at %L cannot have a type", sym->name, where); + return FAILURE; + } + + sym->ts = *ts; + return SUCCESS; +} + + +/* Clears all attributes. */ + +void +gfc_clear_attr (symbol_attribute * attr) +{ + + attr->allocatable = 0; + attr->dimension = 0; + attr->external = 0; + attr->intrinsic = 0; + attr->optional = 0; + attr->pointer = 0; + attr->save = 0; + attr->target = 0; + attr->dummy = 0; + attr->common = 0; + attr->result = 0; + attr->entry = 0; + attr->data = 0; + attr->use_assoc = 0; + attr->in_namelist = 0; + + attr->in_common = 0; + attr->saved_common = 0; + attr->function = 0; + attr->subroutine = 0; + attr->generic = 0; + attr->implicit_type = 0; + attr->sequence = 0; + attr->elemental = 0; + attr->pure = 0; + attr->recursive = 0; + + attr->access = ACCESS_UNKNOWN; + attr->intent = INTENT_UNKNOWN; + attr->flavor = FL_UNKNOWN; + attr->proc = PROC_UNKNOWN; + attr->if_source = IFSRC_UNKNOWN; +} + + +/* Check for missing attributes in the new symbol. Currently does + nothing, but it's not clear that it is unnecessary yet. */ + +try +gfc_missing_attr (symbol_attribute * attr ATTRIBUTE_UNUSED, + locus * where ATTRIBUTE_UNUSED) +{ + + return SUCCESS; +} + + +/* Copy an attribute to a symbol attribute, bit by bit. Some + attributes have a lot of side-effects but cannot be present given + where we are called from, so we ignore some bits. */ + +try +gfc_copy_attr (symbol_attribute * dest, symbol_attribute * src, locus * where) +{ + + if (src->allocatable && gfc_add_allocatable (dest, where) == FAILURE) + goto fail; + + if (src->dimension && gfc_add_dimension (dest, where) == FAILURE) + goto fail; + if (src->optional && gfc_add_optional (dest, where) == FAILURE) + goto fail; + if (src->pointer && gfc_add_pointer (dest, where) == FAILURE) + goto fail; + if (src->save && gfc_add_save (dest, where) == FAILURE) + goto fail; + if (src->target && gfc_add_target (dest, where) == FAILURE) + goto fail; + if (src->dummy && gfc_add_dummy (dest, where) == FAILURE) + goto fail; + if (src->common && gfc_add_common (dest, where) == FAILURE) + goto fail; + if (src->result && gfc_add_result (dest, where) == FAILURE) + goto fail; + if (src->entry) + dest->entry = 1; + + if (src->in_namelist && gfc_add_in_namelist (dest, where) == FAILURE) + goto fail; + + if (src->in_common && gfc_add_in_common (dest, where) == FAILURE) + goto fail; + if (src->saved_common && gfc_add_saved_common (dest, where) == FAILURE) + goto fail; + + if (src->generic && gfc_add_generic (dest, where) == FAILURE) + goto fail; + if (src->function && gfc_add_function (dest, where) == FAILURE) + goto fail; + if (src->subroutine && gfc_add_subroutine (dest, where) == FAILURE) + goto fail; + + if (src->sequence && gfc_add_sequence (dest, where) == FAILURE) + goto fail; + if (src->elemental && gfc_add_elemental (dest, where) == FAILURE) + goto fail; + if (src->pure && gfc_add_pure (dest, where) == FAILURE) + goto fail; + if (src->recursive && gfc_add_recursive (dest, where) == FAILURE) + goto fail; + + if (src->flavor != FL_UNKNOWN + && gfc_add_flavor (dest, src->flavor, where) == FAILURE) + goto fail; + + if (src->intent != INTENT_UNKNOWN + && gfc_add_intent (dest, src->intent, where) == FAILURE) + goto fail; + + if (src->access != ACCESS_UNKNOWN + && gfc_add_access (dest, src->access, where) == FAILURE) + goto fail; + + if (gfc_missing_attr (dest, where) == FAILURE) + goto fail; + + /* The subroutines that set these bits also cause flavors to be set, + and that has already happened in the original, so don't let to + happen again. */ + if (src->external) + dest->external = 1; + if (src->intrinsic) + dest->intrinsic = 1; + + return SUCCESS; + +fail: + return FAILURE; +} + + +/************** Component name management ************/ + +/* Component names of a derived type form their own little namespaces + that are separate from all other spaces. The space is composed of + a singly linked list of gfc_component structures whose head is + located in the parent symbol. */ + + +/* Add a component name to a symbol. The call fails if the name is + already present. On success, the component pointer is modified to + point to the additional component structure. */ + +try +gfc_add_component (gfc_symbol * sym, const char *name, gfc_component ** component) +{ + gfc_component *p, *tail; + + tail = NULL; + + for (p = sym->components; p; p = p->next) + { + if (strcmp (p->name, name) == 0) + { + gfc_error ("Component '%s' at %C already declared at %L", + name, &p->loc); + return FAILURE; + } + + tail = p; + } + + /* Allocate new component */ + p = gfc_get_component (); + + if (tail == NULL) + sym->components = p; + else + tail->next = p; + + strcpy (p->name, name); + p->loc = *gfc_current_locus (); + + *component = p; + return SUCCESS; +} + + +/* Recursive function to switch derived types of all symbol in a + namespace. */ + +static void +switch_types (gfc_symtree * st, gfc_symbol * from, gfc_symbol * to) +{ + gfc_symbol *sym; + + if (st == NULL) + return; + + sym = st->n.sym; + if (sym->ts.type == BT_DERIVED && sym->ts.derived == from) + sym->ts.derived = to; + + switch_types (st->left, from, to); + switch_types (st->right, from, to); +} + + +/* This subroutine is called when a derived type is used in order to + make the final determination about which version to use. The + standard requires that a type be defined before it is 'used', but + such types can appear in IMPLICIT statements before the actual + definition. 'Using' in this context means declaring a variable to + be that type or using the type constructor. + + If a type is used and the components haven't been defined, then we + have to have a derived type in a parent unit. We find the node in + the other namespace and point the symtree node in this namespace to + that node. Further reference to this name point to the correct + node. If we can't find the node in a parent namespace, then have + an error. + + This subroutine takes a pointer to a symbol node and returns a + pointer to the translated node or NULL for an error. Usually there + is no translation and we return the node we were passed. */ + +static gfc_symtree * +gfc_use_ha_derived (gfc_symbol * sym) +{ + gfc_symbol *s, *p; + gfc_typespec *t; + gfc_symtree *st; + int i; + + if (sym->ns->parent == NULL) + goto bad; + + if (gfc_find_symbol (sym->name, sym->ns->parent, 1, &s)) + { + gfc_error ("Symbol '%s' at %C is ambiguous", sym->name); + return NULL; + } + + if (s == NULL || s->attr.flavor != FL_DERIVED) + goto bad; + + /* Get rid of symbol sym, translating all references to s. */ + for (i = 0; i < GFC_LETTERS; i++) + { + t = &sym->ns->default_type[i]; + if (t->derived == sym) + t->derived = s; + } + + st = gfc_find_symtree (sym->ns->sym_root, sym->name); + st->n.sym = s; + + s->refs++; + + /* Unlink from list of modified symbols. */ + if (changed_syms == sym) + changed_syms = sym->tlink; + else + for (p = changed_syms; p; p = p->tlink) + if (p->tlink == sym) + { + p->tlink = sym->tlink; + break; + } + + switch_types (sym->ns->sym_root, sym, s); + + /* TODO: Also have to replace sym -> s in other lists like + namelists, common lists and interface lists. */ + gfc_free_symbol (sym); + + return st; + +bad: + gfc_error ("Derived type '%s' at %C is being used before it is defined", + sym->name); + return NULL; +} + + +gfc_symbol * +gfc_use_derived (gfc_symbol * sym) +{ + gfc_symtree *st; + + if (sym->components != NULL) + return sym; /* Already defined */ + + st = gfc_use_ha_derived (sym); + if (st) + return st->n.sym; + else + return NULL; +} + + +/* Given a derived type node and a component name, try to locate the + component structure. Returns the NULL pointer if the component is + not found or the components are private. */ + +gfc_component * +gfc_find_component (gfc_symbol * sym, const char *name) +{ + gfc_component *p; + + if (name == NULL) + return NULL; + + sym = gfc_use_derived (sym); + + if (sym == NULL) + return NULL; + + for (p = sym->components; p; p = p->next) + if (strcmp (p->name, name) == 0) + break; + + if (p == NULL) + gfc_error ("'%s' at %C is not a member of the '%s' structure", + name, sym->name); + else + { + if (sym->attr.use_assoc && sym->component_access == ACCESS_PRIVATE) + { + gfc_error ("Component '%s' at %C is a PRIVATE component of '%s'", + name, sym->name); + p = NULL; + } + } + + return p; +} + + +/* Given a symbol, free all of the component structures and everything + they point to. */ + +static void +free_components (gfc_component * p) +{ + gfc_component *q; + + for (; p; p = q) + { + q = p->next; + + gfc_free_array_spec (p->as); + gfc_free_expr (p->initializer); + + gfc_free (p); + } +} + + +/* Set component attributes from a standard symbol attribute + structure. */ + +void +gfc_set_component_attr (gfc_component * c, symbol_attribute * attr) +{ + + c->dimension = attr->dimension; + c->pointer = attr->pointer; +} + + +/* Get a standard symbol attribute structure given the component + structure. */ + +void +gfc_get_component_attr (symbol_attribute * attr, gfc_component * c) +{ + + gfc_clear_attr (attr); + attr->dimension = c->dimension; + attr->pointer = c->pointer; +} + + +/******************** Statement label management ********************/ + +/* Free a single gfc_st_label structure, making sure the list is not + messed up. This function is called only when some parse error + occurs. */ + +void +gfc_free_st_label (gfc_st_label * l) +{ + + if (l == NULL) + return; + + if (l->prev) + (l->prev->next = l->next); + + if (l->next) + (l->next->prev = l->prev); + + if (l->format != NULL) + gfc_free_expr (l->format); + gfc_free (l); +} + +/* Free a whole list of gfc_st_label structures. */ + +static void +free_st_labels (gfc_st_label * l1) +{ + gfc_st_label *l2; + + for (; l1; l1 = l2) + { + l2 = l1->next; + if (l1->format != NULL) + gfc_free_expr (l1->format); + gfc_free (l1); + } +} + + +/* Given a label number, search for and return a pointer to the label + structure, creating it if it does not exist. */ + +gfc_st_label * +gfc_get_st_label (int labelno) +{ + gfc_st_label *lp; + + /* First see if the label is already in this namespace. */ + for (lp = gfc_current_ns->st_labels; lp; lp = lp->next) + if (lp->value == labelno) + break; + if (lp != NULL) + return lp; + + lp = gfc_getmem (sizeof (gfc_st_label)); + + lp->value = labelno; + lp->defined = ST_LABEL_UNKNOWN; + lp->referenced = ST_LABEL_UNKNOWN; + + lp->prev = NULL; + lp->next = gfc_current_ns->st_labels; + if (gfc_current_ns->st_labels) + gfc_current_ns->st_labels->prev = lp; + gfc_current_ns->st_labels = lp; + + return lp; +} + + +/* Called when a statement with a statement label is about to be + accepted. We add the label to the list of the current namespace, + making sure it hasn't been defined previously and referenced + correctly. */ + +void +gfc_define_st_label (gfc_st_label * lp, gfc_sl_type type, locus * label_locus) +{ + int labelno; + + labelno = lp->value; + + if (lp->defined != ST_LABEL_UNKNOWN) + gfc_error ("Duplicate statement label %d at %L and %L", labelno, + &lp->where, label_locus); + else + { + lp->where = *label_locus; + + switch (type) + { + case ST_LABEL_FORMAT: + if (lp->referenced == ST_LABEL_TARGET) + gfc_error ("Label %d at %C already referenced as branch target", + labelno); + else + lp->defined = ST_LABEL_FORMAT; + + break; + + case ST_LABEL_TARGET: + if (lp->referenced == ST_LABEL_FORMAT) + gfc_error ("Label %d at %C already referenced as a format label", + labelno); + else + lp->defined = ST_LABEL_TARGET; + + break; + + default: + lp->defined = ST_LABEL_BAD_TARGET; + lp->referenced = ST_LABEL_BAD_TARGET; + } + } +} + + +/* Reference a label. Given a label and its type, see if that + reference is consistent with what is known about that label, + updating the unknown state. Returns FAILURE if something goes + wrong. */ + +try +gfc_reference_st_label (gfc_st_label * lp, gfc_sl_type type) +{ + gfc_sl_type label_type; + int labelno; + try rc; + + if (lp == NULL) + return SUCCESS; + + labelno = lp->value; + + if (lp->defined != ST_LABEL_UNKNOWN) + label_type = lp->defined; + else + { + label_type = lp->referenced; + lp->where = *gfc_current_locus (); + } + + if (label_type == ST_LABEL_FORMAT && type == ST_LABEL_TARGET) + { + gfc_error ("Label %d at %C previously used as a FORMAT label", labelno); + rc = FAILURE; + goto done; + } + + if ((label_type == ST_LABEL_TARGET || label_type == ST_LABEL_BAD_TARGET) + && type == ST_LABEL_FORMAT) + { + gfc_error ("Label %d at %C previously used as branch target", labelno); + rc = FAILURE; + goto done; + } + + lp->referenced = type; + rc = SUCCESS; + +done: + return rc; +} + + +/************** Symbol table management subroutines ****************/ + +/* Basic details: Fortran 95 requires a potentially unlimited number + of distinct namespaces when compiling a program unit. This case + occurs during a compilation of internal subprograms because all of + the internal subprograms must be read before we can start + generating code for the host. + + Given the tricky nature of the fortran grammar, we must be able to + undo changes made to a symbol table if the current interpretation + of a statement is found to be incorrect. Whenever a symbol is + looked up, we make a copy of it and link to it. All of these + symbols are kept in a singly linked list so that we can commit or + undo the changes at a later time. + + A symtree may point to a symbol node outside of it's namespace. In + this case, that symbol has been used as a host associated variable + at some previous time. */ + +/* Allocate a new namespace structure. */ + +gfc_namespace * +gfc_get_namespace (gfc_namespace * parent) +{ + gfc_namespace *ns; + gfc_typespec *ts; + gfc_intrinsic_op in; + int i; + + ns = gfc_getmem (sizeof (gfc_namespace)); + ns->sym_root = NULL; + ns->uop_root = NULL; + ns->default_access = ACCESS_UNKNOWN; + ns->parent = parent; + + for (in = GFC_INTRINSIC_BEGIN; in != GFC_INTRINSIC_END; in++) + ns->operator_access[in] = ACCESS_UNKNOWN; + + /* Initialize default implicit types. */ + for (i = 'a'; i <= 'z'; i++) + { + ns->set_flag[i - 'a'] = 0; + ts = &ns->default_type[i - 'a']; + + if (ns->parent != NULL) + { + /* Copy parent settings */ + *ts = ns->parent->default_type[i - 'a']; + continue; + } + + if (gfc_option.flag_implicit_none != 0) + { + gfc_clear_ts (ts); + continue; + } + + if ('i' <= i && i <= 'n') + { + ts->type = BT_INTEGER; + ts->kind = gfc_default_integer_kind (); + } + else + { + ts->type = BT_REAL; + ts->kind = gfc_default_real_kind (); + } + } + + return ns; +} + + +/* Comparison function for symtree nodes. */ + +static int +compare_symtree (void * _st1, void * _st2) +{ + gfc_symtree *st1, *st2; + + st1 = (gfc_symtree *) _st1; + st2 = (gfc_symtree *) _st2; + + return strcmp (st1->name, st2->name); +} + + +/* Allocate a new symtree node and associate it with the new symbol. */ + +gfc_symtree * +gfc_new_symtree (gfc_symtree ** root, const char *name) +{ + gfc_symtree *st; + + st = gfc_getmem (sizeof (gfc_symtree)); + strcpy (st->name, name); + + gfc_insert_bbt (root, st, compare_symtree); + return st; +} + + +/* Delete a symbol from the tree. Does not free the symbol itself! */ + +static void +delete_symtree (gfc_symtree ** root, const char *name) +{ + gfc_symtree st, *st0; + + st0 = gfc_find_symtree (*root, name); + + strcpy (st.name, name); + gfc_delete_bbt (root, &st, compare_symtree); + + gfc_free (st0); +} + + +/* Given a root symtree node and a name, try to find the symbol within + the namespace. Returns NULL if the symbol is not found. */ + +gfc_symtree * +gfc_find_symtree (gfc_symtree * st, const char *name) +{ + int c; + + while (st != NULL) + { + c = strcmp (name, st->name); + if (c == 0) + return st; + + st = (c < 0) ? st->left : st->right; + } + + return NULL; +} + + +/* Given a name find a user operator node, creating it if it doesn't + exist. These are much simpler than symbols because they can't be + ambiguous with one another. */ + +gfc_user_op * +gfc_get_uop (const char *name) +{ + gfc_user_op *uop; + gfc_symtree *st; + + st = gfc_find_symtree (gfc_current_ns->uop_root, name); + if (st != NULL) + return st->n.uop; + + st = gfc_new_symtree (&gfc_current_ns->uop_root, name); + + uop = st->n.uop = gfc_getmem (sizeof (gfc_user_op)); + strcpy (uop->name, name); + uop->access = ACCESS_UNKNOWN; + uop->ns = gfc_current_ns; + + return uop; +} + + +/* Given a name find the user operator node. Returns NULL if it does + not exist. */ + +gfc_user_op * +gfc_find_uop (const char *name, gfc_namespace * ns) +{ + gfc_symtree *st; + + if (ns == NULL) + ns = gfc_current_ns; + + st = gfc_find_symtree (ns->uop_root, name); + return (st == NULL) ? NULL : st->n.uop; +} + + +/* Remove a gfc_symbol structure and everything it points to. */ + +void +gfc_free_symbol (gfc_symbol * sym) +{ + + if (sym == NULL) + return; + + gfc_free_array_spec (sym->as); + + free_components (sym->components); + + gfc_free_expr (sym->value); + + gfc_free_namelist (sym->namelist); + + gfc_free_namespace (sym->formal_ns); + + gfc_free_interface (sym->generic); + + gfc_free_formal_arglist (sym->formal); + + gfc_free (sym); +} + + +/* Allocate and initialize a new symbol node. */ + +gfc_symbol * +gfc_new_symbol (const char *name, gfc_namespace * ns) +{ + gfc_symbol *p; + + p = gfc_getmem (sizeof (gfc_symbol)); + + gfc_clear_ts (&p->ts); + gfc_clear_attr (&p->attr); + p->ns = ns; + + p->declared_at = *gfc_current_locus (); + + if (strlen (name) > GFC_MAX_SYMBOL_LEN) + gfc_internal_error ("new_symbol(): Symbol name too long"); + + strcpy (p->name, name); + return p; +} + + +/* Generate an error if a symbol is ambiguous. */ + +static void +ambiguous_symbol (const char *name, gfc_symtree * st) +{ + + if (st->n.sym->module[0]) + gfc_error ("Name '%s' at %C is an ambiguous reference to '%s' " + "from module '%s'", name, st->n.sym->name, st->n.sym->module); + else + gfc_error ("Name '%s' at %C is an ambiguous reference to '%s' " + "from current program unit", name, st->n.sym->name); +} + + +/* Search for a symbol starting in the current namespace, resorting to + any parent namespaces if requested by a nonzero parent_flag. + Returns nonzero if the symbol is ambiguous. */ + +int +gfc_find_sym_tree (const char *name, gfc_namespace * ns, int parent_flag, + gfc_symtree ** result) +{ + gfc_symtree *st; + + if (ns == NULL) + ns = gfc_current_ns; + + do + { + st = gfc_find_symtree (ns->sym_root, name); + if (st != NULL) + { + *result = st; + if (st->ambiguous) + { + ambiguous_symbol (name, st); + return 1; + } + + return 0; + } + + if (!parent_flag) + break; + + ns = ns->parent; + } + while (ns != NULL); + + *result = NULL; + return 0; +} + + +int +gfc_find_symbol (const char *name, gfc_namespace * ns, int parent_flag, + gfc_symbol ** result) +{ + gfc_symtree *st; + int i; + + i = gfc_find_sym_tree (name, ns, parent_flag, &st); + + if (st == NULL) + *result = NULL; + else + *result = st->n.sym; + + return i; +} + + +/* Save symbol with the information necessary to back it out. */ + +static void +save_symbol_data (gfc_symbol * sym) +{ + + if (sym->new || sym->old_symbol != NULL) + return; + + sym->old_symbol = gfc_getmem (sizeof (gfc_symbol)); + *(sym->old_symbol) = *sym; + + sym->tlink = changed_syms; + changed_syms = sym; +} + + +/* Given a name, find a symbol, or create it if it does not exist yet + in the current namespace. If the symbol is found we make sure that + it's OK. + + The integer return code indicates + 0 All OK + 1 The symbol name was ambiguous + 2 The name meant to be established was already host associated. + + So if the return value is nonzero, then an error was issued. */ + +int +gfc_get_sym_tree (const char *name, gfc_namespace * ns, gfc_symtree ** result) +{ + gfc_symtree *st; + gfc_symbol *p; + + /* This doesn't usually happen during resolution. */ + if (ns == NULL) + ns = gfc_current_ns; + + /* Try to find the symbol in ns. */ + st = gfc_find_symtree (ns->sym_root, name); + + if (st == NULL) + { + /* If not there, create a new symbol. */ + p = gfc_new_symbol (name, ns); + + /* Add to the list of tentative symbols. */ + p->old_symbol = NULL; + p->tlink = changed_syms; + p->mark = 1; + p->new = 1; + changed_syms = p; + + st = gfc_new_symtree (&ns->sym_root, name); + st->n.sym = p; + p->refs++; + + } + else + { + /* Make sure the existing symbol is OK. */ + if (st->ambiguous) + { + ambiguous_symbol (name, st); + return 1; + } + + p = st->n.sym; + + if (p->ns != ns && (!p->attr.function || ns->proc_name != p)) + { + /* Symbol is from another namespace. */ + gfc_error ("Symbol '%s' at %C has already been host associated", + name); + return 2; + } + + p->mark = 1; + + /* Copy in case this symbol is changed. */ + save_symbol_data (p); + } + + *result = st; + return 0; +} + + +int +gfc_get_symbol (const char *name, gfc_namespace * ns, gfc_symbol ** result) +{ + gfc_symtree *st; + int i; + + + i = gfc_get_sym_tree (name, ns, &st); + if (i != 0) + return i; + + if (st) + *result = st->n.sym; + else + *result = NULL; + return i; +} + + +/* Subroutine that searches for a symbol, creating it if it doesn't + exist, but tries to host-associate the symbol if possible. */ + +int +gfc_get_ha_sym_tree (const char *name, gfc_symtree ** result) +{ + gfc_symtree *st; + int i; + + i = gfc_find_sym_tree (name, gfc_current_ns, 0, &st); + if (st != NULL) + { + save_symbol_data (st->n.sym); + + *result = st; + return i; + } + + if (gfc_current_ns->parent != NULL) + { + i = gfc_find_sym_tree (name, gfc_current_ns->parent, 1, &st); + if (i) + return i; + + if (st != NULL) + { + *result = st; + return 0; + } + } + + return gfc_get_sym_tree (name, gfc_current_ns, result); +} + + +int +gfc_get_ha_symbol (const char *name, gfc_symbol ** result) +{ + int i; + gfc_symtree *st; + + i = gfc_get_ha_sym_tree (name, &st); + + if (st) + *result = st->n.sym; + else + *result = NULL; + + return i; +} + +/* Return true if both symbols could refer to the same data object. Does + not take account of aliasing due to equivalence statements. */ + +int +gfc_symbols_could_alias (gfc_symbol * lsym, gfc_symbol * rsym) +{ + /* Aliasing isn't possible if the symbols have different base types. */ + if (gfc_compare_types (&lsym->ts, &rsym->ts) == 0) + return 0; + + /* Pointers can point to other pointers, target objects and allocatable + objects. Two allocatable objects cannot share the same storage. */ + if (lsym->attr.pointer + && (rsym->attr.pointer || rsym->attr.allocatable || rsym->attr.target)) + return 1; + if (lsym->attr.target && rsym->attr.pointer) + return 1; + if (lsym->attr.allocatable && rsym->attr.pointer) + return 1; + + return 0; +} + + +/* Undoes all the changes made to symbols in the current statement. + This subroutine is made simpler due to the fact that attributes are + never removed once added. */ + +void +gfc_undo_symbols (void) +{ + gfc_symbol *p, *q, *old; + + for (p = changed_syms; p; p = q) + { + q = p->tlink; + + if (p->new) + { + /* Symbol was new. */ + delete_symtree (&p->ns->sym_root, p->name); + + p->refs--; + if (p->refs < 0) + gfc_internal_error ("gfc_undo_symbols(): Negative refs"); + if (p->refs == 0) + gfc_free_symbol (p); + continue; + } + + /* Restore previous state of symbol. Just copy simple stuff. */ + p->mark = 0; + old = p->old_symbol; + + p->ts.type = old->ts.type; + p->ts.kind = old->ts.kind; + + p->attr = old->attr; + + if (p->value != old->value) + { + gfc_free_expr (old->value); + p->value = NULL; + } + + if (p->as != old->as) + { + if (p->as) + gfc_free_array_spec (p->as); + p->as = old->as; + } + + p->generic = old->generic; + p->component_access = old->component_access; + + if (p->namelist != NULL && old->namelist == NULL) + { + gfc_free_namelist (p->namelist); + p->namelist = NULL; + } + else + { + + if (p->namelist_tail != old->namelist_tail) + { + gfc_free_namelist (old->namelist_tail); + old->namelist_tail->next = NULL; + } + } + + p->namelist_tail = old->namelist_tail; + + if (p->formal != old->formal) + { + gfc_free_formal_arglist (p->formal); + p->formal = old->formal; + } + + gfc_free (p->old_symbol); + p->old_symbol = NULL; + p->tlink = NULL; + } + + changed_syms = NULL; +} + + +/* Makes the changes made in the current statement permanent-- gets + rid of undo information. */ + +void +gfc_commit_symbols (void) +{ + gfc_symbol *p, *q; + + for (p = changed_syms; p; p = q) + { + q = p->tlink; + p->tlink = NULL; + p->mark = 0; + p->new = 0; + + if (p->old_symbol != NULL) + { + gfc_free (p->old_symbol); + p->old_symbol = NULL; + } + } + + changed_syms = NULL; +} + + +/* Recursive function that deletes an entire tree and all the user + operator nodes that it contains. */ + +static void +free_uop_tree (gfc_symtree * uop_tree) +{ + + if (uop_tree == NULL) + return; + + free_uop_tree (uop_tree->left); + free_uop_tree (uop_tree->right); + + gfc_free_interface (uop_tree->n.uop->operator); + + gfc_free (uop_tree->n.uop); + gfc_free (uop_tree); +} + + +/* Recursive function that deletes an entire tree and all the symbols + that it contains. */ + +static void +free_sym_tree (gfc_symtree * sym_tree) +{ + gfc_namespace *ns; + gfc_symbol *sym; + + if (sym_tree == NULL) + return; + + free_sym_tree (sym_tree->left); + free_sym_tree (sym_tree->right); + + sym = sym_tree->n.sym; + + sym->refs--; + if (sym->refs < 0) + gfc_internal_error ("free_sym_tree(): Negative refs"); + + if (sym->formal_ns != NULL && sym->refs == 1) + { + /* As formal_ns contains a reference to sym, delete formal_ns just + before the deletion of sym. */ + ns = sym->formal_ns; + sym->formal_ns = NULL; + gfc_free_namespace (ns); + } + else if (sym->refs == 0) + { + /* Go ahead and delete the symbol. */ + gfc_free_symbol (sym); + } + + gfc_free (sym_tree); +} + + +/* Free a namespace structure and everything below it. Interface + lists associated with intrinsic operators are not freed. These are + taken care of when a specific name is freed. */ + +void +gfc_free_namespace (gfc_namespace * ns) +{ + gfc_charlen *cl, *cl2; + gfc_namespace *p, *q; + gfc_intrinsic_op i; + + if (ns == NULL) + return; + + gfc_free_statements (ns->code); + + free_sym_tree (ns->sym_root); + free_uop_tree (ns->uop_root); + + for (cl = ns->cl_list; cl; cl = cl2) + { + cl2 = cl->next; + gfc_free_expr (cl->length); + gfc_free (cl); + } + + free_st_labels (ns->st_labels); + + gfc_free_equiv (ns->equiv); + + for (i = GFC_INTRINSIC_BEGIN; i != GFC_INTRINSIC_END; i++) + gfc_free_interface (ns->operator[i]); + + gfc_free_data (ns->data); + p = ns->contained; + gfc_free (ns); + + /* Recursively free any contained namespaces. */ + while (p != NULL) + { + q = p; + p = p->sibling; + + gfc_free_namespace (q); + } +} + + +void +gfc_symbol_init_2 (void) +{ + + gfc_current_ns = gfc_get_namespace (NULL); +} + + +void +gfc_symbol_done_2 (void) +{ + + gfc_free_namespace (gfc_current_ns); + gfc_current_ns = NULL; +} + + +/* Clear mark bits from symbol nodes associated with a symtree node. */ + +static void +clear_sym_mark (gfc_symtree * st) +{ + + st->n.sym->mark = 0; +} + + +/* Recursively traverse the symtree nodes. */ + +static void +traverse_symtree (gfc_symtree * st, void (*func) (gfc_symtree *)) +{ + + if (st != NULL) + { + (*func) (st); + + traverse_symtree (st->left, func); + traverse_symtree (st->right, func); + } +} + + +void +gfc_traverse_symtree (gfc_namespace * ns, void (*func) (gfc_symtree *)) +{ + + traverse_symtree (ns->sym_root, func); +} + + +/* Recursive namespace traversal function. */ + +static void +traverse_ns (gfc_symtree * st, void (*func) (gfc_symbol *)) +{ + + if (st == NULL) + return; + + if (st->n.sym->mark == 0) + (*func) (st->n.sym); + st->n.sym->mark = 1; + + traverse_ns (st->left, func); + traverse_ns (st->right, func); +} + + +/* Call a given function for all symbols in the namespace. We take + care that each gfc_symbol node is called exactly once. */ + +void +gfc_traverse_ns (gfc_namespace * ns, void (*func) (gfc_symbol *)) +{ + + gfc_traverse_symtree (ns, clear_sym_mark); + + traverse_ns (ns->sym_root, func); +} + + +/* Given a symbol, mark it as SAVEd if it is allowed. */ + +static void +save_symbol (gfc_symbol * sym) +{ + + if (sym->attr.use_assoc) + return; + + if (sym->attr.common) + { + gfc_add_saved_common (&sym->attr, &sym->declared_at); + return; + } + + if (sym->attr.in_common + || sym->attr.dummy + || sym->attr.flavor != FL_VARIABLE) + return; + + gfc_add_save (&sym->attr, &sym->declared_at); +} + + +/* Mark those symbols which can be SAVEd as such. */ + +void +gfc_save_all (gfc_namespace * ns) +{ + + gfc_traverse_ns (ns, save_symbol); +} + + +#ifdef GFC_DEBUG +/* Make sure that no changes to symbols are pending. */ + +void +gfc_symbol_state(void) { + + if (changed_syms != NULL) + gfc_internal_error("Symbol changes still pending!"); +} +#endif + diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c new file mode 100644 index 00000000000..452b0fec81c --- /dev/null +++ b/gcc/fortran/trans-array.c @@ -0,0 +1,4158 @@ +/* Array translation routines + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + and Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* trans-array.c-- Various array related code, including scalarization, + allocation, initialization and other support routines. */ + +/* How the scalarizer works. + In gfortran, array expressions use the same core routines as scalar + expressions. + First, a Scalarization State (SS) chain is built. This is done by walking + the expression tree, and building a linear list of the terms in the + expression. As the tree is walked, scalar subexpressions are translated. + + The scalarization parameters are stored in a gfc_loopinfo structure. + First the start and stride of each term is calculated by + gfc_conv_ss_startstride. During this process the expressions for the array + descriptors and data pointers are also translated. + + If the expression is an assignment, we must then resolve any dependencies. + In fortran all the rhs values of an assignment must be evaluated before + any assignments take place. This can require a temporary array to store the + values. We also require a temporary when we are passing array expressions + or vector subecripts as procedure parameters. + + Array sections are passed without copying to a temporary. These use the + scalarizer to determine the shape of the section. The flag + loop->array_parameter tells the scalarizer that the actual values and loop + variables will not be required. + + The function gfc_conv_loop_setup generates the scalarization setup code. + It determines the range of the scalarizing loop variables. If a temporary + is required, this is created and initialized. Code for scalar expressions + taken outside the loop is also generated at this time. Next the offset and + scaling required to translate from loop variables to array indices for each + term is calculated. + + A call to gfc_start_scalarized_body marks the start of the scalarized + expression. This creates a scope and declares the loop variables. Before + calling this gfc_make_ss_chain_used must be used to indicate which terms + will be used inside this loop. + + The scalar gfc_conv_* functions are then used to build the main body of the + scalarization loop. Scalarization loop variables and precalculated scalar + values are automaticaly substituted. Note that gfc_advance_se_ss_chain + must be used, rather than changing the se->ss directly. + + For assignment expressions requiring a temporary two sub loops are + generated. The first stores the result of the expression in the temporary, + the second copies it to the result. A call to + gfc_trans_scalarized_loop_boundary marks the end of the main loop code and + the start of the copying loop. The temporary may be less than full rank. + + Finally gfc_trans_scalarizing_loops is called to generate the implicit do + loops. The loops are added to the pre chain of the loopinfo. The post + chain may still contain cleanup code. + + After the loop code has been added into its parent scope gfc_cleanup_loop + is called to free all the SS allocated by the scalarizer. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-simple.h" +#include +#include "ggc.h" +#include "toplev.h" +#include "real.h" +#include "flags.h" +#include +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-stmt.h" +#include "trans-types.h" +#include "trans-array.h" +#include "trans-const.h" +#include "dependency.h" + +static gfc_ss *gfc_walk_subexpr (gfc_ss *, gfc_expr *); + +/* The contents of this structure aren't actualy used, just the address. */ +static gfc_ss gfc_ss_terminator_var; +gfc_ss * const gfc_ss_terminator = &gfc_ss_terminator_var; + +unsigned HOST_WIDE_INT gfc_stack_space_left; + + +/* Returns true if a variable of specified size should go on the stack. */ + +int +gfc_can_put_var_on_stack (tree size) +{ + unsigned HOST_WIDE_INT low; + + if (!INTEGER_CST_P (size)) + return 0; + + if (gfc_option.flag_max_stack_var_size < 0) + return 1; + + if (TREE_INT_CST_HIGH (size) != 0) + return 0; + + low = TREE_INT_CST_LOW (size); + if (low > (unsigned HOST_WIDE_INT) gfc_option.flag_max_stack_var_size) + return 0; + +/* TODO: Set a per-function stack size limit. */ +#if 0 + /* We should be a bit more clever with array temps. */ + if (gfc_option.flag_max_function_vars_size >= 0) + { + if (low > gfc_stack_space_left) + return 0; + + gfc_stack_space_left -= low; + } +#endif + + return 1; +} + +static tree +gfc_array_dataptr_type (tree desc) +{ + return (GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (desc))); +} + + +/* Build expressions to access the members of an array descriptor. + It's surprisingly easy to mess up here, so never access + an array descriptor by "brute force", always use these + functions. This also avoids problems if we change the format + of an array descriptor. + + To understand these magic numbers, look at the comments + before gfc_build_array_type() in trans-types.c. + + The code within these defines should be the only code which knows the format + of an array descriptor. + + Any code just needing to read obtain the bounds of an array should use + gfc_conv_array_* rather than the following functions as these will return + know constant values, and work with arrays which do not have descriptors. + + Don't forget to #undef these! */ + +#define DATA_FIELD 0 +#define OFFSET_FIELD 1 +#define DTYPE_FIELD 2 +#define DIMENSION_FIELD 3 + +#define STRIDE_SUBFIELD 0 +#define LBOUND_SUBFIELD 1 +#define UBOUND_SUBFIELD 2 + +tree +gfc_conv_descriptor_data (tree desc) +{ + tree field; + tree type; + + type = TREE_TYPE (desc); + assert (GFC_DESCRIPTOR_TYPE_P (type)); + + field = TYPE_FIELDS (type); + assert (DATA_FIELD == 0); + assert (field != NULL_TREE + && TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == ARRAY_TYPE); + + return build (COMPONENT_REF, TREE_TYPE (field), desc, field); +} + +tree +gfc_conv_descriptor_offset (tree desc) +{ + tree type; + tree field; + + type = TREE_TYPE (desc); + assert (GFC_DESCRIPTOR_TYPE_P (type)); + + field = gfc_advance_chain (TYPE_FIELDS (type), OFFSET_FIELD); + assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type); + + return build (COMPONENT_REF, TREE_TYPE (field), desc, field); +} + +tree +gfc_conv_descriptor_dtype (tree desc) +{ + tree field; + tree type; + + type = TREE_TYPE (desc); + assert (GFC_DESCRIPTOR_TYPE_P (type)); + + field = gfc_advance_chain (TYPE_FIELDS (type), DTYPE_FIELD); + assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type); + + return build (COMPONENT_REF, TREE_TYPE (field), desc, field); +} + +static tree +gfc_conv_descriptor_dimension (tree desc, tree dim) +{ + tree field; + tree type; + tree tmp; + + type = TREE_TYPE (desc); + assert (GFC_DESCRIPTOR_TYPE_P (type)); + + field = gfc_advance_chain (TYPE_FIELDS (type), DIMENSION_FIELD); + assert (field != NULL_TREE + && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == RECORD_TYPE); + + tmp = build (COMPONENT_REF, TREE_TYPE (field), desc, field); + tmp = gfc_build_array_ref (tmp, dim); + return tmp; +} + +tree +gfc_conv_descriptor_stride (tree desc, tree dim) +{ + tree tmp; + tree field; + + tmp = gfc_conv_descriptor_dimension (desc, dim); + field = TYPE_FIELDS (TREE_TYPE (tmp)); + field = gfc_advance_chain (field, STRIDE_SUBFIELD); + assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type); + + tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field); + return tmp; +} + +tree +gfc_conv_descriptor_lbound (tree desc, tree dim) +{ + tree tmp; + tree field; + + tmp = gfc_conv_descriptor_dimension (desc, dim); + field = TYPE_FIELDS (TREE_TYPE (tmp)); + field = gfc_advance_chain (field, LBOUND_SUBFIELD); + assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type); + + tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field); + return tmp; +} + +tree +gfc_conv_descriptor_ubound (tree desc, tree dim) +{ + tree tmp; + tree field; + + tmp = gfc_conv_descriptor_dimension (desc, dim); + field = TYPE_FIELDS (TREE_TYPE (tmp)); + field = gfc_advance_chain (field, UBOUND_SUBFIELD); + assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type); + + tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field); + return tmp; +} + + +/* Generate an initializer for a static pointer or allocatable array. */ + +void +gfc_trans_static_array_pointer (gfc_symbol * sym) +{ + tree tmp; + tree field; + tree type; + + assert (TREE_STATIC (sym->backend_decl)); + /* Just zero the data member. */ + type = TREE_TYPE (sym->backend_decl); + assert (GFC_DESCRIPTOR_TYPE_P (type)); + assert (DATA_FIELD == 0); + field = TYPE_FIELDS (type); + + tmp = tree_cons (field, null_pointer_node, NULL_TREE); + tmp = build1 (CONSTRUCTOR, type, tmp); + TREE_CONSTANT (tmp) = 1; + TREE_INVARIANT (tmp) = 1; + DECL_INITIAL (sym->backend_decl) = tmp; +} + + +/* Cleanup those #defines. */ + +#undef DATA_FIELD +#undef OFFSET_FIELD +#undef DTYPE_FIELD +#undef DIMENSION_FIELD +#undef STRIDE_SUBFIELD +#undef LBOUND_SUBFIELD +#undef UBOUND_SUBFIELD + + +/* Mark a SS chain as used. Flags specifies in which loops the SS is used. + flags & 1 = Main loop body. + flags & 2 = temp copy loop. */ + +void +gfc_mark_ss_chain_used (gfc_ss * ss, unsigned flags) +{ + for (; ss != gfc_ss_terminator; ss = ss->next) + ss->useflags = flags; +} + +static void gfc_free_ss (gfc_ss *); + + +/* Free a gfc_ss chain. */ + +static void +gfc_free_ss_chain (gfc_ss * ss) +{ + gfc_ss *next; + + while (ss != gfc_ss_terminator) + { + assert (ss != NULL); + next = ss->next; + gfc_free_ss (ss); + ss = next; + } +} + + +/* Free a SS. */ + +static void +gfc_free_ss (gfc_ss * ss) +{ + int n; + + switch (ss->type) + { + case GFC_SS_SECTION: + case GFC_SS_VECTOR: + for (n = 0; n < GFC_MAX_DIMENSIONS; n++) + { + if (ss->data.info.subscript[n]) + gfc_free_ss_chain (ss->data.info.subscript[n]); + } + break; + + default: + break; + } + + gfc_free (ss); +} + + +/* Free all the SS associated with a loop. */ + +void +gfc_cleanup_loop (gfc_loopinfo * loop) +{ + gfc_ss *ss; + gfc_ss *next; + + ss = loop->ss; + while (ss != gfc_ss_terminator) + { + assert (ss != NULL); + next = ss->loop_chain; + gfc_free_ss (ss); + ss = next; + } +} + + +/* Associate a SS chain with a loop. */ + +void +gfc_add_ss_to_loop (gfc_loopinfo * loop, gfc_ss * head) +{ + gfc_ss *ss; + + if (head == gfc_ss_terminator) + return; + + ss = head; + for (; ss && ss != gfc_ss_terminator; ss = ss->next) + { + if (ss->next == gfc_ss_terminator) + ss->loop_chain = loop->ss; + else + ss->loop_chain = ss->next; + } + assert (ss == gfc_ss_terminator); + loop->ss = head; +} + + +/* Generate code to allocate an array temporary, or create a variable to + hold the data. */ + +static void +gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info, + tree size, tree nelem) +{ + tree tmp; + tree args; + tree desc; + tree data; + bool onstack; + + desc = info->descriptor; + data = gfc_conv_descriptor_data (desc); + onstack = gfc_can_put_var_on_stack (size); + if (onstack) + { + /* Make a temporary variable to hold the data. */ + tmp = fold (build (MINUS_EXPR, TREE_TYPE (nelem), nelem, + integer_one_node)); + tmp = build_range_type (gfc_array_index_type, integer_zero_node, tmp); + tmp = build_array_type (gfc_get_element_type (TREE_TYPE (desc)), tmp); + tmp = gfc_create_var (tmp, "A"); + tmp = gfc_build_addr_expr (TREE_TYPE (data), tmp); + gfc_add_modify_expr (&loop->pre, data, tmp); + info->data = data; + info->offset = gfc_index_zero_node; + + } + else + { + /* Allocate memory to hold the data. */ + args = gfc_chainon_list (NULL_TREE, size); + + if (gfc_index_integer_kind == 4) + tmp = gfor_fndecl_internal_malloc; + else if (gfc_index_integer_kind == 8) + tmp = gfor_fndecl_internal_malloc64; + else + abort (); + tmp = gfc_build_function_call (tmp, args); + tmp = convert (TREE_TYPE (data), tmp); + gfc_add_modify_expr (&loop->pre, data, tmp); + + info->data = data; + info->offset = gfc_index_zero_node; + } + + /* The offset is zero because we create temporaries with a zero + lower bound. */ + tmp = gfc_conv_descriptor_offset (desc); + gfc_add_modify_expr (&loop->pre, tmp, gfc_index_zero_node); + + if (!onstack) + { + /* Free the temporary. */ + tmp = convert (pvoid_type_node, info->data); + tmp = gfc_chainon_list (NULL_TREE, tmp); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp); + gfc_add_expr_to_block (&loop->post, tmp); + } +} + + +/* Generate code to allocate and initialize the descriptor for a temporary + array. Fills in the descriptor, data and offset fields of info. Also + adjusts the loop variables to be zero-based. Returns the size of the + array. */ + +tree +gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info, + tree eltype, tree string_length) +{ + tree type; + tree desc; + tree tmp; + tree size; + tree nelem; + int n; + int dim; + + assert (info->dimen > 0); + /* Set the lower bound to zero. */ + for (dim = 0; dim < info->dimen; dim++) + { + n = loop->order[dim]; + if (n < loop->temp_dim) + assert (integer_zerop (loop->from[n])); + else + { + loop->to[n] = fold (build (MINUS_EXPR, gfc_array_index_type, + loop->to[n], loop->from[n])); + loop->from[n] = integer_zero_node; + } + + info->delta[dim] = integer_zero_node; + info->start[dim] = integer_zero_node; + info->stride[dim] = integer_one_node; + info->dim[dim] = dim; + } + + /* Initialise the descriptor. */ + type = + gfc_get_array_type_bounds (eltype, info->dimen, loop->from, loop->to, 1); + desc = gfc_create_var (type, "atmp"); + GFC_DECL_PACKED_ARRAY (desc) = 1; + + info->descriptor = desc; + size = integer_one_node; + + /* Fill in the array dtype. */ + tmp = gfc_conv_descriptor_dtype (desc); + gfc_add_modify_expr (&loop->pre, tmp, + GFC_TYPE_ARRAY_DTYPE (TREE_TYPE (desc))); + + /* Fill in the bounds and stride. This is a packed array, so: + size = 1; + for (n = 0; n < rank; n++) + { + stride[n] = size + delta = ubound[n] + 1 - lbound[n]; + size = size * delta; + } + size = size * sizeof(element); */ + for (n = 0; n < info->dimen; n++) + { + /* Store the stride and bound components in the descriptor. */ + tmp = gfc_conv_descriptor_stride (desc, gfc_rank_cst[n]); + gfc_add_modify_expr (&loop->pre, tmp, size); + + tmp = gfc_conv_descriptor_lbound (desc, gfc_rank_cst[n]); + gfc_add_modify_expr (&loop->pre, tmp, integer_zero_node); + + tmp = gfc_conv_descriptor_ubound (desc, gfc_rank_cst[n]); + gfc_add_modify_expr (&loop->pre, tmp, loop->to[n]); + + tmp = fold (build (PLUS_EXPR, gfc_array_index_type, + loop->to[n], integer_one_node)); + + size = fold (build (MULT_EXPR, gfc_array_index_type, size, tmp)); + size = gfc_evaluate_now (size, &loop->pre); + } + + /* TODO: Where does the string length go? */ + if (string_length) + gfc_todo_error ("temporary arrays of strings"); + + /* Get the size of the array. */ + nelem = size; + size = fold (build (MULT_EXPR, gfc_array_index_type, size, + TYPE_SIZE_UNIT (gfc_get_element_type (type)))); + + gfc_trans_allocate_array_storage (loop, info, size, nelem); + + if (info->dimen > loop->temp_dim) + loop->temp_dim = info->dimen; + + return size; +} + + +/* Make sure offset is a variable. */ + +static void +gfc_put_offset_into_var (stmtblock_t * pblock, tree * poffset, + tree * offsetvar) +{ + /* We should have already created the offset variable. We cannot + create it here because we may be in an inner scopde. */ + assert (*offsetvar != NULL_TREE); + gfc_add_modify_expr (pblock, *offsetvar, *poffset); + *poffset = *offsetvar; + TREE_USED (*offsetvar) = 1; +} + + +/* Add the contents of an array to the constructor. */ + +static void +gfc_trans_array_constructor_subarray (stmtblock_t * pblock, + tree type ATTRIBUTE_UNUSED, + tree pointer, gfc_expr * expr, + tree * poffset, tree * offsetvar) +{ + gfc_se se; + gfc_ss *ss; + gfc_loopinfo loop; + stmtblock_t body; + tree tmp; + + /* We need this to be a variable so we can increment it. */ + gfc_put_offset_into_var (pblock, poffset, offsetvar); + + gfc_init_se (&se, NULL); + + /* Walk the array expression. */ + ss = gfc_walk_expr (expr); + assert (ss != gfc_ss_terminator); + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + gfc_add_ss_to_loop (&loop, ss); + + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + /* Make the loop body. */ + gfc_mark_ss_chain_used (ss, 1); + gfc_start_scalarized_body (&loop, &body); + gfc_copy_loopinfo_to_se (&se, &loop); + se.ss = ss; + + gfc_conv_expr (&se, expr); + gfc_add_block_to_block (&body, &se.pre); + + /* Store the value. */ + tmp = gfc_build_indirect_ref (pointer); + tmp = gfc_build_array_ref (tmp, *poffset); + gfc_add_modify_expr (&body, tmp, se.expr); + + /* Increment the offset. */ + tmp = build (PLUS_EXPR, gfc_array_index_type, *poffset, integer_one_node); + gfc_add_modify_expr (&body, *poffset, tmp); + + /* Finish the loop. */ + gfc_add_block_to_block (&body, &se.post); + assert (se.ss == gfc_ss_terminator); + gfc_trans_scalarizing_loops (&loop, &body); + gfc_add_block_to_block (&loop.pre, &loop.post); + tmp = gfc_finish_block (&loop.pre); + gfc_add_expr_to_block (pblock, tmp); + + gfc_cleanup_loop (&loop); +} + + +/* Assign the values to the elements of an array constructor. */ + +static void +gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type, + tree pointer, gfc_constructor * c, + tree * poffset, tree * offsetvar) +{ + tree tmp; + tree ref; + stmtblock_t body; + tree loopbody; + gfc_se se; + + for (; c; c = c->next) + { + /* If this is an iterator or an array, the offset must be a variable. */ + if ((c->iterator || c->expr->rank > 0) && INTEGER_CST_P (*poffset)) + gfc_put_offset_into_var (pblock, poffset, offsetvar); + + gfc_start_block (&body); + + if (c->expr->expr_type == EXPR_ARRAY) + { + /* Array constructors can be nested. */ + gfc_trans_array_constructor_value (&body, type, pointer, + c->expr->value.constructor, + poffset, offsetvar); + } + else if (c->expr->rank > 0) + { + gfc_trans_array_constructor_subarray (&body, type, pointer, + c->expr, poffset, offsetvar); + } + else + { + /* This code really upsets the gimplifier so don't bother for now. */ + gfc_constructor *p; + HOST_WIDE_INT n; + HOST_WIDE_INT size; + + p = c; + n = 0; + while (p && !(p->iterator || p->expr->expr_type != EXPR_CONSTANT)) + { + p = p->next; + n++; + } + if (n < 4) + { + /* Scalar values. */ + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, c->expr); + gfc_add_block_to_block (&body, &se.pre); + + ref = gfc_build_indirect_ref (pointer); + ref = gfc_build_array_ref (ref, *poffset); + gfc_add_modify_expr (&body, ref, se.expr); + gfc_add_block_to_block (&body, &se.post); + + *poffset = fold (build (PLUS_EXPR, gfc_array_index_type, + *poffset, integer_one_node)); + } + else + { + /* Collect multiple scalar constants into a constructor. */ + tree list; + tree init; + tree bound; + tree tmptype; + + p = c; + list = NULL_TREE; + /* Count the number of consecutive scalar constants. */ + while (p && !(p->iterator + || p->expr->expr_type != EXPR_CONSTANT)) + { + gfc_init_se (&se, NULL); + gfc_conv_constant (&se, p->expr); + list = tree_cons (NULL_TREE, se.expr, list); + c = p; + p = p->next; + } + + bound = build_int_2 (n - 1, 0); + /* Create an array type to hold them. */ + tmptype = build_range_type (gfc_array_index_type, + integer_zero_node, bound); + tmptype = build_array_type (type, tmptype); + + init = build1 (CONSTRUCTOR, tmptype, nreverse (list)); + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + TREE_STATIC (init) = 1; + /* Create a static variable to hold the data. */ + tmp = gfc_create_var (tmptype, "data"); + TREE_STATIC (tmp) = 1; + TREE_CONSTANT (tmp) = 1; + TREE_INVARIANT (tmp) = 1; + DECL_INITIAL (tmp) = init; + init = tmp; + + /* Use BUILTIN_MEMCPY to assign the values. */ + tmp = gfc_build_indirect_ref (pointer); + tmp = gfc_build_array_ref (tmp, *poffset); + tmp = gfc_build_addr_expr (NULL, tmp); + init = gfc_build_addr_expr (NULL, init); + + size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)); + bound = build_int_2 (n * size, 0); + tmp = gfc_chainon_list (NULL_TREE, tmp); + tmp = gfc_chainon_list (tmp, init); + tmp = gfc_chainon_list (tmp, bound); + tmp = gfc_build_function_call (built_in_decls[BUILT_IN_MEMCPY], + tmp); + gfc_add_expr_to_block (&body, tmp); + + *poffset = fold (build (PLUS_EXPR, gfc_array_index_type, + *poffset, bound)); + } + if (!INTEGER_CST_P (*poffset)) + { + gfc_add_modify_expr (&body, *offsetvar, *poffset); + *poffset = *offsetvar; + } + } + + /* The frontend should already have done any expansions. */ + if (c->iterator) + { + tree end; + tree step; + tree loopvar; + tree exit_label; + + loopbody = gfc_finish_block (&body); + + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, c->iterator->var); + gfc_add_block_to_block (pblock, &se.pre); + loopvar = se.expr; + + /* Initialize thie loop. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, c->iterator->start); + gfc_add_block_to_block (pblock, &se.pre); + gfc_add_modify_expr (pblock, loopvar, se.expr); + + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, c->iterator->end); + gfc_add_block_to_block (pblock, &se.pre); + end = gfc_evaluate_now (se.expr, pblock); + + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, c->iterator->step); + gfc_add_block_to_block (pblock, &se.pre); + step = gfc_evaluate_now (se.expr, pblock); + + /* Generate the loop body. */ + exit_label = gfc_build_label_decl (NULL_TREE); + gfc_start_block (&body); + + /* Generate the exit condition. */ + end = build (GT_EXPR, boolean_type_node, loopvar, end); + tmp = build1_v (GOTO_EXPR, exit_label); + TREE_USED (exit_label) = 1; + tmp = build_v (COND_EXPR, end, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&body, tmp); + + /* The main loop body. */ + gfc_add_expr_to_block (&body, loopbody); + + /* Increment the loop variable. */ + tmp = build (PLUS_EXPR, TREE_TYPE (loopvar), loopvar, step); + gfc_add_modify_expr (&body, loopvar, tmp); + + /* Finish the loop. */ + tmp = gfc_finish_block (&body); + tmp = build_v (LOOP_EXPR, tmp); + gfc_add_expr_to_block (pblock, tmp); + + /* Add the exit label. */ + tmp = build1_v (LABEL_EXPR, exit_label); + gfc_add_expr_to_block (pblock, tmp); + } + else + { + /* Pass the code as is. */ + tmp = gfc_finish_block (&body); + gfc_add_expr_to_block (pblock, tmp); + } + } +} + + +/* Get the size of an expression. Returns -1 if the size isn't constant. + Implied do loops with non-constant bounds are tricky because we must only + evaluate the bounds once. */ + +static void +gfc_get_array_cons_size (mpz_t * size, gfc_constructor * c) +{ + gfc_iterator *i; + mpz_t val; + mpz_t len; + + mpz_set_ui (*size, 0); + mpz_init (len); + mpz_init (val); + + for (; c; c = c->next) + { + if (c->expr->expr_type == EXPR_ARRAY) + { + /* A nested array constructor. */ + gfc_get_array_cons_size (&len, c->expr->value.constructor); + if (mpz_sgn (len) < 0) + { + mpz_set (*size, len); + mpz_clear (len); + mpz_clear (val); + return; + } + } + else + { + if (c->expr->rank > 0) + { + mpz_set_si (*size, -1); + mpz_clear (len); + mpz_clear (val); + return; + } + mpz_set_ui (len, 1); + } + + if (c->iterator) + { + i = c->iterator; + + if (i->start->expr_type != EXPR_CONSTANT + || i->end->expr_type != EXPR_CONSTANT + || i->step->expr_type != EXPR_CONSTANT) + { + mpz_set_si (*size, -1); + mpz_clear (len); + mpz_clear (val); + return; + } + + mpz_add (val, i->end->value.integer, i->start->value.integer); + mpz_tdiv_q (val, val, i->step->value.integer); + mpz_add_ui (val, val, 1); + mpz_mul (len, len, val); + } + mpz_add (*size, *size, len); + } + mpz_clear (len); + mpz_clear (val); +} + + +/* Array constructors are handled by constructing a temporary, then using that + within the scalarization loop. This is not optimal, but seems by far the + simplest method. */ + +static void +gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss) +{ + tree offset; + tree offsetvar; + tree desc; + tree size; + tree type; + + if (ss->expr->ts.type == BT_CHARACTER) + gfc_todo_error ("Character string array constructors"); + type = gfc_typenode_for_spec (&ss->expr->ts); + ss->data.info.dimen = loop->dimen; + size = + gfc_trans_allocate_temp_array (loop, &ss->data.info, type, NULL_TREE); + + desc = ss->data.info.descriptor; + offset = integer_zero_node; + offsetvar = gfc_create_var_np (gfc_array_index_type, "offset"); + TREE_USED (offsetvar) = 0; + gfc_trans_array_constructor_value (&loop->pre, type, + ss->data.info.data, + ss->expr->value.constructor, &offset, + &offsetvar); + + if (TREE_USED (offsetvar)) + pushdecl (offsetvar); + else + assert (INTEGER_CST_P (offset)); +#if 0 + /* Disable bound checking for now cos it's probably broken. */ + if (flag_bounds_check) + { + abort (); + } +#endif +} + + +/* Add the pre and post chains for all the scalar expressions in a SS chain + to loop. This is called after the loop parameters have been calculated, + but before the actual scalarizing loops. */ +/*GCC ARRAYS*/ + +static void +gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript) +{ + gfc_se se; + int n; + + assert (ss != NULL); + + for (; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + assert (ss); + + switch (ss->type) + { + case GFC_SS_SCALAR: + /* Scalar expression. Evaluate this now. This includes elemental + dimension indices, but not array section bounds. */ + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, ss->expr); + gfc_add_block_to_block (&loop->pre, &se.pre); + + if (ss->expr->ts.type != BT_CHARACTER) + { + /* Move the evaluation of scalar expressions outside the + scalarization loop. */ + if (subscript) + se.expr = convert(gfc_array_index_type, se.expr); + se.expr = gfc_evaluate_now (se.expr, &loop->pre); + gfc_add_block_to_block (&loop->pre, &se.post); + } + else + gfc_add_block_to_block (&loop->post, &se.post); + + ss->data.scalar.expr = se.expr; + ss->data.scalar.string_length = se.string_length; + break; + + case GFC_SS_REFERENCE: + /* Scalar reference. Evaluate this now. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_reference (&se, ss->expr); + gfc_add_block_to_block (&loop->pre, &se.pre); + gfc_add_block_to_block (&loop->post, &se.post); + + ss->data.scalar.expr = gfc_evaluate_now (se.expr, &loop->pre); + ss->data.scalar.string_length = se.string_length; + break; + + case GFC_SS_SECTION: + case GFC_SS_VECTOR: + /* Scalarized expression. Evaluate any scalar subscripts. */ + for (n = 0; n < GFC_MAX_DIMENSIONS; n++) + { + /* Add the expressions for scalar subscripts. */ + if (ss->data.info.subscript[n]) + gfc_add_loop_ss_code (loop, ss->data.info.subscript[n], true); + } + break; + + case GFC_SS_INTRINSIC: + gfc_add_intrinsic_ss_code (loop, ss); + break; + + case GFC_SS_FUNCTION: + /* Array function return value. We call the function and save its + result in a temporary for use inside the loop. */ + gfc_init_se (&se, NULL); + se.loop = loop; + se.ss = ss; + gfc_conv_expr (&se, ss->expr); + gfc_add_block_to_block (&loop->pre, &se.pre); + gfc_add_block_to_block (&loop->post, &se.post); + break; + + case GFC_SS_CONSTRUCTOR: + gfc_trans_array_constructor (loop, ss); + break; + + default: + abort (); + } + } +} + + +/* Translate expressions for the descriptor and data pointer of a SS. */ +/*GCC ARRAYS*/ + +static void +gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base) +{ + gfc_se se; + tree tmp; + + /* Get the descriptor for the array to be scalarized. */ + assert (ss->expr->expr_type == EXPR_VARIABLE); + gfc_init_se (&se, NULL); + se.descriptor_only = 1; + gfc_conv_expr_lhs (&se, ss->expr); + gfc_add_block_to_block (block, &se.pre); + ss->data.info.descriptor = se.expr; + + if (base) + { + /* Also the data pointer. */ + tmp = gfc_conv_array_data (se.expr); + /* If this is a variable or address of a variable we use it directly. + Otherwise we must evaluate it now to to avoid break dependency + analysis by pulling the expressions for elemental array indices + inside the loop. */ + if (!(DECL_P (tmp) + || (TREE_CODE (tmp) == ADDR_EXPR + && DECL_P (TREE_OPERAND (tmp, 0))))) + tmp = gfc_evaluate_now (tmp, block); + ss->data.info.data = tmp; + + tmp = gfc_conv_array_offset (se.expr); + ss->data.info.offset = gfc_evaluate_now (tmp, block); + } +} + + +/* Initialise a gfc_loopinfo structure. */ + +void +gfc_init_loopinfo (gfc_loopinfo * loop) +{ + int n; + + memset (loop, 0, sizeof (gfc_loopinfo)); + gfc_init_block (&loop->pre); + gfc_init_block (&loop->post); + + /* Initialy scalarize in order. */ + for (n = 0; n < GFC_MAX_DIMENSIONS; n++) + loop->order[n] = n; + + loop->ss = gfc_ss_terminator; +} + + +/* Copies the loop variable info to a gfc_se sructure. Does not copy the SS + chain. */ + +void +gfc_copy_loopinfo_to_se (gfc_se * se, gfc_loopinfo * loop) +{ + se->loop = loop; +} + + +/* Return an expression for the data pointer of an array. */ + +tree +gfc_conv_array_data (tree descriptor) +{ + tree type; + + type = TREE_TYPE (descriptor); + if (GFC_ARRAY_TYPE_P (type)) + { + if (TREE_CODE (type) == POINTER_TYPE) + return descriptor; + else + { + /* Descritporless arrays. */ + return gfc_build_addr_expr (NULL, descriptor); + } + } + else + return gfc_conv_descriptor_data (descriptor); +} + + +/* Return an expression for the base offset of an array. */ + +tree +gfc_conv_array_offset (tree descriptor) +{ + tree type; + + type = TREE_TYPE (descriptor); + if (GFC_ARRAY_TYPE_P (type)) + return GFC_TYPE_ARRAY_OFFSET (type); + else + return gfc_conv_descriptor_offset (descriptor); +} + + +/* Get an expression for the array stride. */ + +tree +gfc_conv_array_stride (tree descriptor, int dim) +{ + tree tmp; + tree type; + + type = TREE_TYPE (descriptor); + + /* For descriptorless arrays use the array size. */ + tmp = GFC_TYPE_ARRAY_STRIDE (type, dim); + if (tmp != NULL_TREE) + return tmp; + + tmp = gfc_conv_descriptor_stride (descriptor, gfc_rank_cst[dim]); + return tmp; +} + + +/* Like gfc_conv_array_stride, but for the lower bound. */ + +tree +gfc_conv_array_lbound (tree descriptor, int dim) +{ + tree tmp; + tree type; + + type = TREE_TYPE (descriptor); + + tmp = GFC_TYPE_ARRAY_LBOUND (type, dim); + if (tmp != NULL_TREE) + return tmp; + + tmp = gfc_conv_descriptor_lbound (descriptor, gfc_rank_cst[dim]); + return tmp; +} + + +/* Like gfc_conv_array_stride, but for the upper bound. */ + +tree +gfc_conv_array_ubound (tree descriptor, int dim) +{ + tree tmp; + tree type; + + type = TREE_TYPE (descriptor); + + tmp = GFC_TYPE_ARRAY_UBOUND (type, dim); + if (tmp != NULL_TREE) + return tmp; + + /* This should only ever happen when passing an assumed shape array + as an actual parameter. The value will never be used. */ + if (GFC_ARRAY_TYPE_P (TREE_TYPE (descriptor))) + return integer_zero_node; + + tmp = gfc_conv_descriptor_ubound (descriptor, gfc_rank_cst[dim]); + return tmp; +} + + +/* Translate an array reference. The descriptor should be in se->expr. + Do not use this function, it wil be removed soon. */ +/*GCC ARRAYS*/ + +static void +gfc_conv_array_index_ref (gfc_se * se, tree pointer, tree * indices, + tree offset, int dimen) +{ + tree array; + tree tmp; + tree index; + int n; + + array = gfc_build_indirect_ref (pointer); + + index = offset; + for (n = 0; n < dimen; n++) + { + /* index = index + stride[n]*indices[n] */ + tmp = gfc_conv_array_stride (se->expr, n); + tmp = fold (build (MULT_EXPR, gfc_array_index_type, indices[n], tmp)); + + index = fold (build (PLUS_EXPR, gfc_array_index_type, index, tmp)); + } + + /* Result = data[index]. */ + tmp = gfc_build_array_ref (array, index); + + /* Check we've used the correct number of dimensions. */ + assert (TREE_CODE (TREE_TYPE (tmp)) != ARRAY_TYPE); + + se->expr = tmp; +} + + +/* Generate code to perform an array index bound check. */ + +static tree +gfc_trans_array_bound_check (gfc_se * se, tree descriptor, tree index, int n) +{ + tree cond; + tree fault; + tree tmp; + + if (!flag_bounds_check) + return index; + + index = gfc_evaluate_now (index, &se->pre); + /* Check lower bound. */ + tmp = gfc_conv_array_lbound (descriptor, n); + fault = fold (build (LT_EXPR, boolean_type_node, index, tmp)); + /* Check upper bound. */ + tmp = gfc_conv_array_ubound (descriptor, n); + cond = fold (build (GT_EXPR, boolean_type_node, index, tmp)); + fault = fold (build (TRUTH_OR_EXPR, boolean_type_node, fault, cond)); + + gfc_trans_runtime_check (fault, gfc_strconst_fault, &se->pre); + + return index; +} + + +/* A reference to an array vector subscript. Uses recursion to handle nested + vector subscripts. */ + +static tree +gfc_conv_vector_array_index (gfc_se * se, tree index, gfc_ss * ss) +{ + tree descsave; + tree indices[GFC_MAX_DIMENSIONS]; + gfc_array_ref *ar; + gfc_ss_info *info; + int n; + + assert (ss && ss->type == GFC_SS_VECTOR); + + /* Save the descriptor. */ + descsave = se->expr; + info = &ss->data.info; + se->expr = info->descriptor; + + ar = &info->ref->u.ar; + for (n = 0; n < ar->dimen; n++) + { + switch (ar->dimen_type[n]) + { + case DIMEN_ELEMENT: + assert (info->subscript[n] != gfc_ss_terminator + && info->subscript[n]->type == GFC_SS_SCALAR); + indices[n] = info->subscript[n]->data.scalar.expr; + break; + + case DIMEN_RANGE: + indices[n] = index; + break; + + case DIMEN_VECTOR: + index = gfc_conv_vector_array_index (se, index, info->subscript[n]); + + indices[n] = + gfc_trans_array_bound_check (se, info->descriptor, index, n); + break; + + default: + abort (); + } + } + /* Get the index from the vector. */ + gfc_conv_array_index_ref (se, info->data, indices, info->offset, ar->dimen); + index = se->expr; + /* Put the descriptor back. */ + se->expr = descsave; + + return index; +} + + +/* Return the offset for an index. Performs bound checking for elemental + dimensions. Single element references are processed seperately. */ + +static tree +gfc_conv_array_index_offset (gfc_se * se, gfc_ss_info * info, int dim, int i, + gfc_array_ref * ar, tree stride) +{ + tree index; + + /* Get the index into the array for this dimension. */ + if (ar) + { + assert (ar->type != AR_ELEMENT); + if (ar->dimen_type[dim] == DIMEN_ELEMENT) + { + assert (i == -1); + /* Elemental dimension. */ + assert (info->subscript[dim] + && info->subscript[dim]->type == GFC_SS_SCALAR); + /* We've already translated this value outside the loop. */ + index = info->subscript[dim]->data.scalar.expr; + + index = + gfc_trans_array_bound_check (se, info->descriptor, index, dim); + } + else + { + /* Scalarized dimension. */ + assert (info && se->loop); + + /* Multiply the loop variable by the stride and dela. */ + index = se->loop->loopvar[i]; + index = fold (build (MULT_EXPR, gfc_array_index_type, index, + info->stride[i])); + index = fold (build (PLUS_EXPR, gfc_array_index_type, index, + info->delta[i])); + + if (ar->dimen_type[dim] == DIMEN_VECTOR) + { + /* Handle vector subscripts. */ + index = gfc_conv_vector_array_index (se, index, + info->subscript[dim]); + index = + gfc_trans_array_bound_check (se, info->descriptor, index, + dim); + } + else + assert (ar->dimen_type[dim] == DIMEN_RANGE); + } + } + else + { + /* Temporary array. */ + assert (se->loop); + index = se->loop->loopvar[se->loop->order[i]]; + } + + /* Multiply by the stride. */ + index = fold (build (MULT_EXPR, gfc_array_index_type, index, stride)); + + return index; +} + + +/* Build a scalarized reference to an array. */ + +static void +gfc_conv_scalarized_array_ref (gfc_se * se, gfc_array_ref * ar) +{ + gfc_ss_info *info; + tree index; + tree tmp; + int n; + + info = &se->ss->data.info; + if (ar) + n = se->loop->order[0]; + else + n = 0; + + index = gfc_conv_array_index_offset (se, info, info->dim[n], n, ar, + info->stride0); + /* Add the offset for this dimension to the stored offset for all other + dimensions. */ + index = fold (build (PLUS_EXPR, gfc_array_index_type, index, info->offset)); + + tmp = gfc_build_indirect_ref (info->data); + se->expr = gfc_build_array_ref (tmp, index); +} + + +/* Translate access of temporary array. */ + +void +gfc_conv_tmp_array_ref (gfc_se * se) +{ + tree desc; + + desc = se->ss->data.info.descriptor; + /* TODO: We need the string length for string variables. */ + + gfc_conv_scalarized_array_ref (se, NULL); +} + + +/* Build an array reference. se->expr already holds the array descriptor. + This should be either a variable, indirect variable reference or component + reference. For arrays which do not have a descriptor, se->expr will be + the data pointer. + a(i, j, k) = base[offset + i * stride[0] + j * stride[1] + k * stride[2]]*/ + +void +gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar) +{ + int n; + tree index; + tree tmp; + tree stride; + tree fault; + gfc_se indexse; + + /* Handle scalarized references seperately. */ + if (ar->type != AR_ELEMENT) + { + gfc_conv_scalarized_array_ref (se, ar); + return; + } + + index = integer_zero_node; + + fault = integer_zero_node; + + /* Calculate the offsets from all the dimensions. */ + for (n = 0; n < ar->dimen; n++) + { + /* Calculate the index for this demension. */ + gfc_init_se (&indexse, NULL); + gfc_conv_expr_type (&indexse, ar->start[n], gfc_array_index_type); + gfc_add_block_to_block (&se->pre, &indexse.pre); + + if (flag_bounds_check) + { + /* Check array bounds. */ + tree cond; + + indexse.expr = gfc_evaluate_now (indexse.expr, &se->pre); + + tmp = gfc_conv_array_lbound (se->expr, n); + cond = fold (build (LT_EXPR, boolean_type_node, indexse.expr, tmp)); + fault = + fold (build (TRUTH_OR_EXPR, boolean_type_node, fault, cond)); + + tmp = gfc_conv_array_ubound (se->expr, n); + cond = fold (build (GT_EXPR, boolean_type_node, indexse.expr, tmp)); + fault = + fold (build (TRUTH_OR_EXPR, boolean_type_node, fault, cond)); + } + + /* Multiply the index by the stride. */ + stride = gfc_conv_array_stride (se->expr, n); + tmp = fold (build (MULT_EXPR, gfc_array_index_type, indexse.expr, + stride)); + + /* And add it to the total. */ + index = fold (build (PLUS_EXPR, gfc_array_index_type, index, tmp)); + } + + if (flag_bounds_check) + gfc_trans_runtime_check (fault, gfc_strconst_fault, &se->pre); + + tmp = gfc_conv_array_offset (se->expr); + if (!integer_zerop (tmp)) + index = fold (build (PLUS_EXPR, gfc_array_index_type, index, tmp)); + + /* Access the calculated element. */ + tmp = gfc_conv_array_data (se->expr); + tmp = gfc_build_indirect_ref (tmp); + se->expr = gfc_build_array_ref (tmp, index); +} + + +/* Generate the code to be executed immediately before entering a + scalarization loop. */ + +static void +gfc_trans_preloop_setup (gfc_loopinfo * loop, int dim, int flag, + stmtblock_t * pblock) +{ + tree index; + tree stride; + gfc_ss_info *info; + gfc_ss *ss; + gfc_se se; + int i; + + /* This code will be executed before entering the scalarization loop + for this dimension. */ + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + if ((ss->useflags & flag) == 0) + continue; + + if (ss->type != GFC_SS_SECTION + && ss->type != GFC_SS_FUNCTION && ss->type != GFC_SS_CONSTRUCTOR) + continue; + + info = &ss->data.info; + + if (dim >= info->dimen) + continue; + + if (dim == info->dimen - 1) + { + /* For the outermost loop calculate the offset due to any + elemental dimensions. It will have been initialized with the + base offset of the array. */ + if (info->ref) + { + for (i = 0; i < info->ref->u.ar.dimen; i++) + { + if (info->ref->u.ar.dimen_type[i] != DIMEN_ELEMENT) + continue; + + gfc_init_se (&se, NULL); + se.loop = loop; + se.expr = info->descriptor; + stride = gfc_conv_array_stride (info->descriptor, i); + index = gfc_conv_array_index_offset (&se, info, i, -1, + &info->ref->u.ar, + stride); + gfc_add_block_to_block (pblock, &se.pre); + + info->offset = fold (build (PLUS_EXPR, gfc_array_index_type, + info->offset, index)); + info->offset = gfc_evaluate_now (info->offset, pblock); + } + + i = loop->order[0]; + stride = gfc_conv_array_stride (info->descriptor, info->dim[i]); + } + else + stride = gfc_conv_array_stride (info->descriptor, 0); + + /* Calculate the stride of the innermost loop. Hopefully this will + allow the backend optimizers to do their stuff more effectively. + */ + info->stride0 = gfc_evaluate_now (stride, pblock); + } + else + { + /* Add the offset for the previous loop dimension. */ + gfc_array_ref *ar; + + if (info->ref) + { + ar = &info->ref->u.ar; + i = loop->order[dim + 1]; + } + else + { + ar = NULL; + i = dim + 1; + } + + gfc_init_se (&se, NULL); + se.loop = loop; + se.expr = info->descriptor; + stride = gfc_conv_array_stride (info->descriptor, info->dim[i]); + index = gfc_conv_array_index_offset (&se, info, info->dim[i], i, + ar, stride); + gfc_add_block_to_block (pblock, &se.pre); + info->offset = fold (build (PLUS_EXPR, gfc_array_index_type, + info->offset, index)); + info->offset = gfc_evaluate_now (info->offset, pblock); + } + + /* Remeber this offset for the second loop. */ + if (dim == loop->temp_dim - 1) + info->saved_offset = info->offset; + } +} + + +/* Start a scalarized expression. Creates a scope and declares loop + variables. */ + +void +gfc_start_scalarized_body (gfc_loopinfo * loop, stmtblock_t * pbody) +{ + int dim; + int n; + int flags; + + assert (!loop->array_parameter); + + for (dim = loop->dimen - 1; dim >= 0; dim--) + { + n = loop->order[dim]; + + gfc_start_block (&loop->code[n]); + + /* Create the loop variable. */ + loop->loopvar[n] = gfc_create_var (gfc_array_index_type, "S"); + + if (dim < loop->temp_dim) + flags = 3; + else + flags = 1; + /* Calculate values that will be constant within this loop. */ + gfc_trans_preloop_setup (loop, dim, flags, &loop->code[n]); + } + gfc_start_block (pbody); +} + + +/* Generates the actual loop code for a scalarization loop. */ + +static void +gfc_trans_scalarized_loop_end (gfc_loopinfo * loop, int n, + stmtblock_t * pbody) +{ + stmtblock_t block; + tree cond; + tree tmp; + tree loopbody; + tree exit_label; + + loopbody = gfc_finish_block (pbody); + + /* Initialize the loopvar. */ + gfc_add_modify_expr (&loop->code[n], loop->loopvar[n], loop->from[n]); + + exit_label = gfc_build_label_decl (NULL_TREE); + + /* Generate the loop body. */ + gfc_init_block (&block); + + /* The exit condition. */ + cond = build (GT_EXPR, boolean_type_node, loop->loopvar[n], loop->to[n]); + tmp = build1_v (GOTO_EXPR, exit_label); + TREE_USED (exit_label) = 1; + tmp = build_v (COND_EXPR, cond, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&block, tmp); + + /* The main body. */ + gfc_add_expr_to_block (&block, loopbody); + + /* Increment the loopvar. */ + tmp = build (PLUS_EXPR, gfc_array_index_type, + loop->loopvar[n], integer_one_node); + gfc_add_modify_expr (&block, loop->loopvar[n], tmp); + + /* Build the loop. */ + tmp = gfc_finish_block (&block); + tmp = build_v (LOOP_EXPR, tmp); + gfc_add_expr_to_block (&loop->code[n], tmp); + + /* Add the exit label. */ + tmp = build1_v (LABEL_EXPR, exit_label); + gfc_add_expr_to_block (&loop->code[n], tmp); +} + + +/* Finishes and generates the loops for a scalarized expression. */ + +void +gfc_trans_scalarizing_loops (gfc_loopinfo * loop, stmtblock_t * body) +{ + int dim; + int n; + gfc_ss *ss; + stmtblock_t *pblock; + tree tmp; + + pblock = body; + /* Generate the loops. */ + for (dim = 0; dim < loop->dimen; dim++) + { + n = loop->order[dim]; + gfc_trans_scalarized_loop_end (loop, n, pblock); + loop->loopvar[n] = NULL_TREE; + pblock = &loop->code[n]; + } + + tmp = gfc_finish_block (pblock); + gfc_add_expr_to_block (&loop->pre, tmp); + + /* Clear all the used flags. */ + for (ss = loop->ss; ss; ss = ss->loop_chain) + ss->useflags = 0; +} + + +/* Finish the main body of a scalarized expression, and start the secondary + copying body. */ + +void +gfc_trans_scalarized_loop_boundary (gfc_loopinfo * loop, stmtblock_t * body) +{ + int dim; + int n; + stmtblock_t *pblock; + gfc_ss *ss; + + pblock = body; + /* We finish as many loops as are used by the temporary. */ + for (dim = 0; dim < loop->temp_dim - 1; dim++) + { + n = loop->order[dim]; + gfc_trans_scalarized_loop_end (loop, n, pblock); + loop->loopvar[n] = NULL_TREE; + pblock = &loop->code[n]; + } + + /* We don't want to finish the outermost loop entirely. */ + n = loop->order[loop->temp_dim - 1]; + gfc_trans_scalarized_loop_end (loop, n, pblock); + + /* Restore the initial offsets. */ + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + if ((ss->useflags & 2) == 0) + continue; + + if (ss->type != GFC_SS_SECTION + && ss->type != GFC_SS_FUNCTION && ss->type != GFC_SS_CONSTRUCTOR) + continue; + + ss->data.info.offset = ss->data.info.saved_offset; + } + + /* Restart all the inner loops we just finished. */ + for (dim = loop->temp_dim - 2; dim >= 0; dim--) + { + n = loop->order[dim]; + + gfc_start_block (&loop->code[n]); + + loop->loopvar[n] = gfc_create_var (gfc_array_index_type, "Q"); + + gfc_trans_preloop_setup (loop, dim, 2, &loop->code[n]); + } + + /* Start a block for the secondary copying code. */ + gfc_start_block (body); +} + + +/* Calculate the upper bound of an array section. */ + +static tree +gfc_conv_section_upper_bound (gfc_ss * ss, int n, stmtblock_t * pblock) +{ + int dim; + gfc_ss *vecss; + gfc_expr *end; + tree desc; + tree bound; + gfc_se se; + + assert (ss->type == GFC_SS_SECTION); + + /* For vector array subscripts we want the size of the vector. */ + dim = ss->data.info.dim[n]; + vecss = ss; + while (vecss->data.info.ref->u.ar.dimen_type[dim] == DIMEN_VECTOR) + { + vecss = vecss->data.info.subscript[dim]; + assert (vecss && vecss->type == GFC_SS_VECTOR); + dim = vecss->data.info.dim[0]; + } + + assert (vecss->data.info.ref->u.ar.dimen_type[dim] == DIMEN_RANGE); + end = vecss->data.info.ref->u.ar.end[dim]; + desc = vecss->data.info.descriptor; + + if (end) + { + /* The upper bound was specified. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, end, gfc_array_index_type); + gfc_add_block_to_block (pblock, &se.pre); + bound = se.expr; + } + else + { + /* No upper bound was specified, so use the bound of the array. */ + bound = gfc_conv_array_ubound (desc, dim); + } + + return bound; +} + + +/* Calculate the lower bound of an array section. */ + +static void +gfc_conv_section_startstride (gfc_loopinfo * loop, gfc_ss * ss, int n) +{ + gfc_expr *start; + gfc_expr *stride; + gfc_ss *vecss; + tree desc; + gfc_se se; + gfc_ss_info *info; + int dim; + + info = &ss->data.info; + + dim = info->dim[n]; + + /* For vector array subscripts we want the size of the vector. */ + vecss = ss; + while (vecss->data.info.ref->u.ar.dimen_type[dim] == DIMEN_VECTOR) + { + vecss = vecss->data.info.subscript[dim]; + assert (vecss && vecss->type == GFC_SS_VECTOR); + /* Get the descriptors for the vector subscripts as well. */ + if (!vecss->data.info.descriptor) + gfc_conv_ss_descriptor (&loop->pre, vecss, !loop->array_parameter); + dim = vecss->data.info.dim[0]; + } + + assert (vecss->data.info.ref->u.ar.dimen_type[dim] == DIMEN_RANGE); + start = vecss->data.info.ref->u.ar.start[dim]; + stride = vecss->data.info.ref->u.ar.stride[dim]; + desc = vecss->data.info.descriptor; + + /* Calculate the start of the range. For vector subscripts this will + be the range of the vector. */ + if (start) + { + /* Specified section start. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, start, gfc_array_index_type); + gfc_add_block_to_block (&loop->pre, &se.pre); + info->start[n] = se.expr; + } + else + { + /* No lower bound specified so use the bound of the array. */ + info->start[n] = gfc_conv_array_lbound (desc, dim); + } + info->start[n] = gfc_evaluate_now (info->start[n], &loop->pre); + + /* Calculate the stride. */ + if (stride == NULL) + info->stride[n] = integer_one_node; + else + { + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, stride, gfc_array_index_type); + gfc_add_block_to_block (&loop->pre, &se.pre); + info->stride[n] = gfc_evaluate_now (se.expr, &loop->pre); + } +} + + +/* Calculates the range start and stride for a SS chain. Also gets the + descriptor and data pointer. The range of vector subscripts is the size + of the vector. Array bounds are also checked. */ + +void +gfc_conv_ss_startstride (gfc_loopinfo * loop) +{ + int n; + tree tmp; + gfc_ss *ss; + gfc_ss *vecss; + tree desc; + + loop->dimen = 0; + /* Determine the rank of the loop. */ + for (ss = loop->ss; + ss != gfc_ss_terminator && loop->dimen == 0; ss = ss->loop_chain) + { + switch (ss->type) + { + case GFC_SS_SECTION: + case GFC_SS_CONSTRUCTOR: + case GFC_SS_FUNCTION: + loop->dimen = ss->data.info.dimen; + break; + + default: + break; + } + } + + if (loop->dimen == 0) + gfc_todo_error ("Unable to determine rank of expression"); + + + /* loop over all the SS in the chain. */ + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + switch (ss->type) + { + case GFC_SS_SECTION: + /* Get the descriptor for the array. */ + gfc_conv_ss_descriptor (&loop->pre, ss, !loop->array_parameter); + + for (n = 0; n < ss->data.info.dimen; n++) + gfc_conv_section_startstride (loop, ss, n); + break; + + case GFC_SS_CONSTRUCTOR: + case GFC_SS_FUNCTION: + for (n = 0; n < ss->data.info.dimen; n++) + { + ss->data.info.start[n] = integer_zero_node; + ss->data.info.stride[n] = integer_one_node; + } + break; + + default: + break; + } + } + + /* The rest is just runtime bound checking. */ + if (flag_bounds_check) + { + stmtblock_t block; + tree fault; + tree bound; + tree end; + tree size[GFC_MAX_DIMENSIONS]; + gfc_ss_info *info; + int dim; + + gfc_start_block (&block); + + fault = integer_zero_node; + for (n = 0; n < loop->dimen; n++) + size[n] = NULL_TREE; + + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + if (ss->type != GFC_SS_SECTION) + continue; + + /* TODO: range checking for mapped dimensions. */ + info = &ss->data.info; + + /* This only checks scalarized dimensions, elemental dimensions are + checked later. */ + for (n = 0; n < loop->dimen; n++) + { + dim = info->dim[n]; + vecss = ss; + while (vecss->data.info.ref->u.ar.dimen_type[dim] + == DIMEN_VECTOR) + { + vecss = vecss->data.info.subscript[dim]; + assert (vecss && vecss->type == GFC_SS_VECTOR); + dim = vecss->data.info.dim[0]; + } + assert (vecss->data.info.ref->u.ar.dimen_type[dim] + == DIMEN_RANGE); + desc = vecss->data.info.descriptor; + + /* Check lower bound. */ + bound = gfc_conv_array_lbound (desc, dim); + tmp = info->start[n]; + tmp = fold (build (LT_EXPR, boolean_type_node, tmp, bound)); + fault = fold (build (TRUTH_OR_EXPR, boolean_type_node, fault, + tmp)); + + /* Check the upper bound. */ + bound = gfc_conv_array_ubound (desc, dim); + end = gfc_conv_section_upper_bound (ss, n, &block); + tmp = fold (build (GT_EXPR, boolean_type_node, end, bound)); + fault = fold (build (TRUTH_OR_EXPR, boolean_type_node, fault, + tmp)); + + /* Check the section sizes match. */ + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, end, + info->start[n])); + tmp = fold (build (FLOOR_DIV_EXPR, gfc_array_index_type, tmp, + info->stride[n])); + /* We remember the size of the first section, and check all the + others against this. */ + if (size[n]) + { + tmp = + fold (build (NE_EXPR, boolean_type_node, tmp, size[n])); + fault = + build (TRUTH_OR_EXPR, boolean_type_node, fault, tmp); + } + else + size[n] = gfc_evaluate_now (tmp, &block); + } + } + gfc_trans_runtime_check (fault, gfc_strconst_bounds, &block); + + tmp = gfc_finish_block (&block); + gfc_add_expr_to_block (&loop->pre, tmp); + } +} + + +/* Return true if the two SS could be aliased, ie. both point to the same data + object. */ +/* TODO: resolve aliases based on frontend expressions. */ + +static int +gfc_could_be_alias (gfc_ss * lss, gfc_ss * rss) +{ + gfc_ref *lref; + gfc_ref *rref; + gfc_symbol *lsym; + gfc_symbol *rsym; + + lsym = lss->expr->symtree->n.sym; + rsym = rss->expr->symtree->n.sym; + if (gfc_symbols_could_alias (lsym, rsym)) + return 1; + + if (rsym->ts.type != BT_DERIVED + && lsym->ts.type != BT_DERIVED) + return 0; + + /* For Derived types we must check all the component types. We can ignore + array references as these will have the same base type as the previous + component ref. */ + for (lref = lss->expr->ref; lref != lss->data.info.ref; lref = lref->next) + { + if (lref->type != REF_COMPONENT) + continue; + + if (gfc_symbols_could_alias (lref->u.c.sym, rsym)) + return 1; + + for (rref = rss->expr->ref; rref != rss->data.info.ref; + rref = rref->next) + { + if (rref->type != REF_COMPONENT) + continue; + + if (gfc_symbols_could_alias (lref->u.c.sym, rref->u.c.sym)) + return 1; + } + } + + for (rref = rss->expr->ref; rref != rss->data.info.ref; rref = rref->next) + { + if (rref->type != REF_COMPONENT) + break; + + if (gfc_symbols_could_alias (rref->u.c.sym, lsym)) + return 1; + } + + return 0; +} + + +/* Resolve array data dependencies. Creates a temporary if required. */ +/* TODO: Calc dependencies with gfc_expr rather than gfc_ss, and move to + dependency.c. */ + +void +gfc_conv_resolve_dependencies (gfc_loopinfo * loop, gfc_ss * dest, + gfc_ss * rss) +{ + gfc_ss *ss; + gfc_ref *lref; + gfc_ref *rref; + gfc_ref *aref; + int nDepend = 0; + int temp_dim = 0; + + loop->temp_ss = NULL; + aref = dest->data.info.ref; + temp_dim = 0; + + for (ss = rss; ss != gfc_ss_terminator; ss = ss->next) + { + if (ss->type != GFC_SS_SECTION) + continue; + + if (gfc_could_be_alias (dest, ss)) + { + nDepend = 1; + break; + } + + if (dest->expr->symtree->n.sym == ss->expr->symtree->n.sym) + { + lref = dest->expr->ref; + rref = ss->expr->ref; + + nDepend = gfc_dep_resolver (lref, rref); +#if 0 + /* TODO : loop shifting. */ + if (nDepend == 1) + { + /* Mark the dimensions for LOOP SHIFTING */ + for (n = 0; n < loop->dimen; n++) + { + int dim = dest->data.info.dim[n]; + + if (lref->u.ar.dimen_type[dim] == DIMEN_VECTOR) + depends[n] = 2; + else if (! gfc_is_same_range (&lref->u.ar, + &rref->u.ar, dim, 0)) + depends[n] = 1; + } + + /* Put all the dimensions with dependancies in the + innermost loops. */ + dim = 0; + for (n = 0; n < loop->dimen; n++) + { + assert (loop->order[n] == n); + if (depends[n]) + loop->order[dim++] = n; + } + temp_dim = dim; + for (n = 0; n < loop->dimen; n++) + { + if (! depends[n]) + loop->order[dim++] = n; + } + + assert (dim == loop->dimen); + break; + } +#endif + } + } + + if (nDepend == 1) + { + loop->temp_ss = gfc_get_ss (); + loop->temp_ss->type = GFC_SS_TEMP; + loop->temp_ss->data.temp.type = + gfc_get_element_type (TREE_TYPE (dest->data.info.descriptor)); + loop->temp_ss->data.temp.string_length = NULL_TREE; + loop->temp_ss->data.temp.dimen = loop->dimen; + loop->temp_ss->next = gfc_ss_terminator; + gfc_add_ss_to_loop (loop, loop->temp_ss); + } + else + loop->temp_ss = NULL; +} + + +/* Initialise the scalarization loop. Creates the loop variables. Determines + the range of the loop variables. Creates a temporary if required. + Calculates how to transform from loop variables to array indices for each + expression. Also generates code for scalar expressions which have been + moved outside the loop. */ + +void +gfc_conv_loop_setup (gfc_loopinfo * loop) +{ + int n; + int dim; + gfc_ss_info *info; + gfc_ss_info *specinfo; + gfc_ss *ss; + tree tmp; + tree len; + gfc_ss *loopspec[GFC_MAX_DIMENSIONS]; + mpz_t *cshape; + mpz_t i; + + mpz_init (i); + for (n = 0; n < loop->dimen; n++) + { + loopspec[n] = NULL; + /* We use one SS term, and use that to determine the bounds of the + loop for this dimension. We try to pick the simplest term. */ + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + if (ss->expr && ss->expr->shape) + { + /* The frontend has worked out the size for us. */ + loopspec[n] = ss; + continue; + } + + if (ss->type == GFC_SS_CONSTRUCTOR) + { + /* Try to figure out the size of the constructior. */ + /* TODO: avoid this by making the prontend set the shape. */ + gfc_get_array_cons_size (&i, ss->expr->value.constructor); + /* A negative value meens we failed. */ + if (mpz_sgn (i) > 0) + { + mpz_sub_ui (i, i, 1); + loop->to[n] = + gfc_conv_mpz_to_tree (i, gfc_index_integer_kind); + loopspec[n] = ss; + } + continue; + } + + /* We don't know how to handle functions yet. + This may not be possible in all cases. */ + if (ss->type != GFC_SS_SECTION) + continue; + + info = &ss->data.info; + + if (loopspec[n]) + specinfo = &loopspec[n]->data.info; + else + specinfo = NULL; + info = &ss->data.info; + + /* Criteria for choosing a loop specifier (most important first): + stride of one + known stride + known lower bound + known upper bound + */ + if (!specinfo) + loopspec[n] = ss; + else if (loopspec[n]->type != GFC_SS_CONSTRUCTOR) + { + if (integer_onep (info->stride[n]) + && !integer_onep (specinfo->stride[n])) + loopspec[n] = ss; + else if (INTEGER_CST_P (info->stride[n]) + && !INTEGER_CST_P (specinfo->stride[n])) + loopspec[n] = ss; + else if (INTEGER_CST_P (info->start[n]) + && !INTEGER_CST_P (specinfo->start[n])) + loopspec[n] = ss; + /* We don't work out the upper bound. + else if (INTEGER_CST_P (info->finish[n]) + && ! INTEGER_CST_P (specinfo->finish[n])) + loopspec[n] = ss; */ + } + } + + if (!loopspec[n]) + gfc_todo_error ("Unable to find scalarization loop specifier"); + + info = &loopspec[n]->data.info; + + /* Set the extents of this range. */ + cshape = loopspec[n]->expr->shape; + if (cshape && INTEGER_CST_P (info->start[n]) + && INTEGER_CST_P (info->stride[n])) + { + loop->from[n] = info->start[n]; + mpz_set (i, cshape[n]); + mpz_sub_ui (i, i, 1); + /* To = from + (size - 1) * stride. */ + tmp = gfc_conv_mpz_to_tree (i, gfc_index_integer_kind); + if (!integer_onep (info->stride[n])) + { + tmp = fold (build (MULT_EXPR, gfc_array_index_type, + tmp, info->stride[n])); + } + loop->to[n] = fold (build (PLUS_EXPR, gfc_array_index_type, + loop->from[n], tmp)); + } + else + { + loop->from[n] = info->start[n]; + switch (loopspec[n]->type) + { + case GFC_SS_CONSTRUCTOR: + assert (info->dimen == 1); + assert (loop->to[n]); + break; + + case GFC_SS_SECTION: + loop->to[n] = gfc_conv_section_upper_bound (loopspec[n], n, + &loop->pre); + break; + + default: + abort (); + } + } + + /* Transform everything so we have a simple incrementing variable. */ + if (integer_onep (info->stride[n])) + info->delta[n] = integer_zero_node; + else + { + /* Set the delta for this section. */ + info->delta[n] = gfc_evaluate_now (loop->from[n], &loop->pre); + /* Number of iterations is (end - start + step) / step. + with start = 0, this simplifies to + last = end / step; + for (i = 0; i<=last; i++){...}; */ + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, loop->to[n], + loop->from[n])); + tmp = fold (build (TRUNC_DIV_EXPR, gfc_array_index_type, tmp, + info->stride[n])); + loop->to[n] = gfc_evaluate_now (tmp, &loop->pre); + /* Make the loop variable start at 0. */ + loop->from[n] = integer_zero_node; + } + } + + /* If we want a temporary then create it. */ + if (loop->temp_ss != NULL) + { + assert (loop->temp_ss->type == GFC_SS_TEMP); + tmp = loop->temp_ss->data.temp.type; + len = loop->temp_ss->data.temp.string_length; + n = loop->temp_ss->data.temp.dimen; + memset (&loop->temp_ss->data.info, 0, sizeof (gfc_ss_info)); + loop->temp_ss->type = GFC_SS_SECTION; + loop->temp_ss->data.info.dimen = n; + gfc_trans_allocate_temp_array (loop, &loop->temp_ss->data.info, + tmp, len); + } + + /* Add all the scalar code that can be taken out of the loops. */ + gfc_add_loop_ss_code (loop, loop->ss, false); + + for (n = 0; n < loop->temp_dim; n++) + loopspec[loop->order[n]] = NULL; + + mpz_clear (i); + + /* For array parameters we don't have loop variables, so don't calculate the + translations. */ + if (loop->array_parameter) + return; + + /* Calculate the translation from loop variables to array indices. */ + for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain) + { + if (ss->type != GFC_SS_SECTION) + continue; + + info = &ss->data.info; + + for (n = 0; n < info->dimen; n++) + { + dim = info->dim[n]; + + /* If we are specifying the range the delta may already be set. */ + if (loopspec[n] != ss) + { + /* Calculate the offset relative to the loop variable. + First multiply by the stride. */ + tmp = fold (build (MULT_EXPR, gfc_array_index_type, + loop->from[n], info->stride[n])); + + /* Then subtract this from our starting value. */ + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, + info->start[n], tmp)); + + info->delta[n] = gfc_evaluate_now (tmp, &loop->pre); + } + } + } +} + + +/* Fills in an array descriptor, and returns the size of the array. The size + will be a simple_val, ie a variable or a constant. Also calculates the + offset of the base. Returns the size of the arrary. + { + stride = 1; + offset = 0; + for (n = 0; n < rank; n++) + { + a.lbound[n] = specified_lower_bound; + offset = offset + a.lbond[n] * stride; + size = 1 - lbound; + a.ubound[n] = specified_upper_bound; + a.stride[n] = stride; + size = ubound + size; //size = ubound + 1 - lbound + stride = stride * size; + } + return (stride); + } */ +/*GCC ARRAYS*/ + +static tree +gfc_array_init_size (tree descriptor, int rank, tree * poffset, + gfc_expr ** lower, gfc_expr ** upper, + stmtblock_t * pblock) +{ + tree type; + tree tmp; + tree size; + tree offset; + tree stride; + gfc_expr *ubound; + gfc_se se; + int n; + + type = TREE_TYPE (descriptor); + + stride = integer_one_node; + offset = integer_zero_node; + + /* Set the dtype. */ + tmp = gfc_conv_descriptor_dtype (descriptor); + gfc_add_modify_expr (pblock, tmp, + GFC_TYPE_ARRAY_DTYPE (TREE_TYPE (descriptor))); + + for (n = 0; n < rank; n++) + { + /* We have 3 possibilities for determining the size of the array: + lower == NULL => lbound = 1, ubound = upper[n] + upper[n] = NULL => lbound = 1, ubound = lower[n] + upper[n] != NULL => lbound = lower[n], ubound = upper[n] */ + ubound = upper[n]; + + /* Set lower bound. */ + gfc_init_se (&se, NULL); + if (lower == NULL) + se.expr = integer_one_node; + else + { + assert (lower[n]); + if (ubound) + { + gfc_conv_expr_type (&se, lower[n], gfc_array_index_type); + gfc_add_block_to_block (pblock, &se.pre); + } + else + { + se.expr = integer_one_node; + ubound = lower[n]; + } + } + tmp = gfc_conv_descriptor_lbound (descriptor, gfc_rank_cst[n]); + gfc_add_modify_expr (pblock, tmp, se.expr); + + /* Work out the offset for this component. */ + tmp = fold (build (MULT_EXPR, gfc_array_index_type, se.expr, stride)); + offset = fold (build (MINUS_EXPR, gfc_array_index_type, offset, tmp)); + + /* Start the calculation for the size of this dimension. */ + size = build (MINUS_EXPR, gfc_array_index_type, + integer_one_node, se.expr); + + /* Set upper bound. */ + gfc_init_se (&se, NULL); + assert (ubound); + gfc_conv_expr_type (&se, ubound, gfc_array_index_type); + gfc_add_block_to_block (pblock, &se.pre); + + tmp = gfc_conv_descriptor_ubound (descriptor, gfc_rank_cst[n]); + gfc_add_modify_expr (pblock, tmp, se.expr); + + /* Store the stride. */ + tmp = gfc_conv_descriptor_stride (descriptor, gfc_rank_cst[n]); + gfc_add_modify_expr (pblock, tmp, stride); + + /* Calculate the size of this dimension. */ + size = fold (build (PLUS_EXPR, gfc_array_index_type, se.expr, size)); + + /* Multiply the stride by the number of elements in this dimension. */ + stride = fold (build (MULT_EXPR, gfc_array_index_type, stride, size)); + stride = gfc_evaluate_now (stride, pblock); + } + + /* The stride is the number of elements in the array, so multiply by the + size of an element to get the total size. */ + tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type)); + size = fold (build (MULT_EXPR, gfc_array_index_type, stride, tmp)); + + if (poffset != NULL) + { + offset = gfc_evaluate_now (offset, pblock); + *poffset = offset; + } + + size = gfc_evaluate_now (size, pblock); + return size; +} + + +/* Initialises the descriptor and generates a call to _gfor_allocate. Does + the work for an ALLOCATE statement. */ +/*GCC ARRAYS*/ + +void +gfc_array_allocate (gfc_se * se, gfc_ref * ref, tree pstat) +{ + tree tmp; + tree pointer; + tree allocate; + tree offset; + tree size; + gfc_expr **lower; + gfc_expr **upper; + + /* Figure out the size of the array. */ + switch (ref->u.ar.type) + { + case AR_ELEMENT: + lower = NULL; + upper = ref->u.ar.start; + break; + + case AR_FULL: + assert (ref->u.ar.as->type == AS_EXPLICIT); + + lower = ref->u.ar.as->lower; + upper = ref->u.ar.as->upper; + break; + + case AR_SECTION: + lower = ref->u.ar.start; + upper = ref->u.ar.end; + break; + + default: + abort (); + break; + } + + size = gfc_array_init_size (se->expr, ref->u.ar.as->rank, &offset, + lower, upper, &se->pre); + + /* Allocate memory to store the data. */ + tmp = gfc_conv_descriptor_data (se->expr); + pointer = gfc_build_addr_expr (NULL, tmp); + pointer = gfc_evaluate_now (pointer, &se->pre); + + if (gfc_array_index_type == gfc_int4_type_node) + allocate = gfor_fndecl_allocate; + else if (gfc_array_index_type == gfc_int8_type_node) + allocate = gfor_fndecl_allocate64; + else + abort (); + + tmp = gfc_chainon_list (NULL_TREE, pointer); + tmp = gfc_chainon_list (tmp, size); + tmp = gfc_chainon_list (tmp, pstat); + tmp = gfc_build_function_call (allocate, tmp); + gfc_add_expr_to_block (&se->pre, tmp); + + pointer = gfc_conv_descriptor_data (se->expr); + + tmp = gfc_conv_descriptor_offset (se->expr); + gfc_add_modify_expr (&se->pre, tmp, offset); +} + + +/* Deallocate an array variable. Also used when an allocated variable goes + out of scope. */ +/*GCC ARRAYS*/ + +tree +gfc_array_deallocate (tree descriptor) +{ + tree var; + tree tmp; + stmtblock_t block; + + gfc_start_block (&block); + /* Get a pointer to the data. */ + tmp = gfc_conv_descriptor_data (descriptor); + tmp = gfc_build_addr_expr (NULL, tmp); + var = gfc_create_var (TREE_TYPE (tmp), "ptr"); + gfc_add_modify_expr (&block, var, tmp); + + /* Parameter is the address of the data component. */ + tmp = gfc_chainon_list (NULL_TREE, var); + tmp = gfc_chainon_list (tmp, integer_zero_node); + tmp = gfc_build_function_call (gfor_fndecl_deallocate, tmp); + gfc_add_expr_to_block (&block, tmp); + + return gfc_finish_block (&block); +} + + +/* Create an array constructor from an initialization expression. + We assume the frontend already did any expansions and conversions. */ + +tree +gfc_conv_array_initializer (tree type, gfc_expr * expr) +{ + gfc_constructor *c; + tree list; + tree tmp; + mpz_t maxval; + gfc_se se; + HOST_WIDE_INT hi; + unsigned HOST_WIDE_INT lo; + tree index, range; + + list = NULL_TREE; + switch (expr->expr_type) + { + case EXPR_CONSTANT: + case EXPR_STRUCTURE: + /* A single scalar or derived type value. Create an array with all + elements equal to that value. */ + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, expr); + + tmp = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + assert (tmp && INTEGER_CST_P (tmp)); + hi = TREE_INT_CST_HIGH (tmp); + lo = TREE_INT_CST_LOW (tmp); + lo++; + if (lo == 0) + hi++; + /* This will probably eat buckets of memory for large arrays. */ + while (hi != 0 || lo != 0) + { + list = tree_cons (NULL_TREE, se.expr, list); + if (lo == 0) + hi--; + lo--; + } + break; + + case EXPR_ARRAY: + /* Create a list of all the elements. */ + for (c = expr->value.constructor; c; c = c->next) + { + if (c->iterator) + { + /* Problems occur when we get something like + integer :: a(lots) = (/(i, i=1,lots)/) */ + /* TODO: Unexpanded array initializers. */ + internal_error + ("Possible frontend bug: array constructor not expanded"); + } + if (mpz_cmp_si (c->n.offset, 0) != 0) + index = gfc_conv_mpz_to_tree (c->n.offset, gfc_index_integer_kind); + else + index = NULL_TREE; + mpz_init (maxval); + if (mpz_cmp_si (c->repeat, 0) != 0) + { + tree tmp1, tmp2; + + mpz_set (maxval, c->repeat); + mpz_add (maxval, c->n.offset, maxval); + mpz_sub_ui (maxval, maxval, 1); + tmp2 = gfc_conv_mpz_to_tree (maxval, gfc_index_integer_kind); + if (mpz_cmp_si (c->n.offset, 0) != 0) + { + mpz_add_ui (maxval, c->n.offset, 1); + tmp1 = gfc_conv_mpz_to_tree (maxval, gfc_index_integer_kind); + } + else + tmp1 = gfc_conv_mpz_to_tree (c->n.offset, gfc_index_integer_kind); + + range = build (RANGE_EXPR, integer_type_node, tmp1, tmp2); + } + else + range = NULL; + mpz_clear (maxval); + + gfc_init_se (&se, NULL); + switch (c->expr->expr_type) + { + case EXPR_CONSTANT: + gfc_conv_constant (&se, c->expr); + if (range == NULL_TREE) + list = tree_cons (index, se.expr, list); + else + { + if (index != NULL_TREE) + list = tree_cons (index, se.expr, list); + list = tree_cons (range, se.expr, list); + } + break; + + case EXPR_STRUCTURE: + gfc_conv_structure (&se, c->expr, 1); + list = tree_cons (index, se.expr, list); + break; + + default: + abort(); + } + } + /* We created the list in reverse order. */ + list = nreverse (list); + break; + + default: + abort(); + } + + /* Create a constructor from the list of elements. */ + tmp = build1 (CONSTRUCTOR, type, list); + TREE_CONSTANT (tmp) = 1; + TREE_INVARIANT (tmp) = 1; + return tmp; +} + + +/* Generate code to evaluate non-constant array bounds. Sets *poffset and + returns the size (in elements) of the array. */ + +static tree +gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset, + stmtblock_t * pblock) +{ + gfc_array_spec *as; + tree size; + tree stride; + tree offset; + tree ubound; + tree lbound; + tree tmp; + gfc_se se; + + int dim; + + as = sym->as; + + size = integer_one_node; + offset = integer_zero_node; + for (dim = 0; dim < as->rank; dim++) + { + /* Evaluate non-constant array bound expressions. */ + lbound = GFC_TYPE_ARRAY_LBOUND (type, dim); + if (as->lower[dim] && !INTEGER_CST_P (lbound)) + { + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, as->lower[dim], gfc_array_index_type); + gfc_add_block_to_block (pblock, &se.pre); + gfc_add_modify_expr (pblock, lbound, se.expr); + } + ubound = GFC_TYPE_ARRAY_UBOUND (type, dim); + if (as->upper[dim] && !INTEGER_CST_P (ubound)) + { + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, as->upper[dim], gfc_array_index_type); + gfc_add_block_to_block (pblock, &se.pre); + gfc_add_modify_expr (pblock, ubound, se.expr); + } + /* The offset of this dimension. offset = offset - lbound * stride. */ + tmp = fold (build (MULT_EXPR, gfc_array_index_type, lbound, size)); + offset = fold (build (MINUS_EXPR, gfc_array_index_type, offset, tmp)); + + /* The size of this dimension, and the stride of the next. */ + if (dim + 1 < as->rank) + stride = GFC_TYPE_ARRAY_STRIDE (type, dim + 1); + else + stride = NULL_TREE; + + if (ubound != NULL_TREE && !(stride && INTEGER_CST_P (stride))) + { + /* Calculate stride = size * (ubound + 1 - lbound). */ + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, + integer_one_node, lbound)); + tmp = fold (build (PLUS_EXPR, gfc_array_index_type, ubound, tmp)); + tmp = fold (build (MULT_EXPR, gfc_array_index_type, size, tmp)); + if (stride) + gfc_add_modify_expr (pblock, stride, tmp); + else + stride = gfc_evaluate_now (tmp, pblock); + } + + size = stride; + } + + *poffset = offset; + return size; +} + + +/* Generate code to initialize/allocate an array variable. */ + +tree +gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym, tree fnbody) +{ + stmtblock_t block; + tree type; + tree tmp; + tree fndecl; + tree size; + tree offset; + tree args; + bool onstack; + + assert (!(sym->attr.pointer || sym->attr.allocatable)); + + /* Do nothing for USEd variables. */ + if (sym->attr.use_assoc) + return fnbody; + + type = TREE_TYPE (decl); + assert (GFC_ARRAY_TYPE_P (type)); + onstack = TREE_CODE (type) != POINTER_TYPE; + + /* We never generate initialization code of module variables. */ + if (fnbody == NULL_TREE) + { + assert (onstack); + + /* Generate static initializer. */ + if (sym->value) + { + DECL_INITIAL (decl) = + gfc_conv_array_initializer (TREE_TYPE (decl), sym->value); + } + return fnbody; + } + + gfc_start_block (&block); + + /* Evaluate character string length. */ + if (sym->ts.type == BT_CHARACTER + && onstack && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + { + gfc_trans_init_string_length (sym->ts.cl, &block); + + DECL_DEFER_OUTPUT (decl) = 1; + + /* Generate code to allocate the automatic variable. It will be + freed automatically. */ + tmp = gfc_build_addr_expr (NULL, decl); + args = gfc_chainon_list (NULL_TREE, tmp); + args = gfc_chainon_list (args, sym->ts.cl->backend_decl); + tmp = gfc_build_function_call (built_in_decls[BUILT_IN_STACK_ALLOC], + args); + gfc_add_expr_to_block (&block, tmp); + } + + if (onstack) + { + if (sym->value) + { + DECL_INITIAL (decl) = + gfc_conv_array_initializer (TREE_TYPE (decl), sym->value); + } + + gfc_add_expr_to_block (&block, fnbody); + return gfc_finish_block (&block); + } + + type = TREE_TYPE (type); + + assert (!sym->attr.use_assoc); + assert (!TREE_STATIC (decl)); + assert (!sym->module[0]); + + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &block); + + size = gfc_trans_array_bounds (type, sym, &offset, &block); + + /* The size is the number of elements in the array, so multiply by the + size of an element to get the total size. */ + tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type)); + size = fold (build (MULT_EXPR, gfc_array_index_type, size, tmp)); + + /* Allocate memory to hold the data. */ + tmp = gfc_chainon_list (NULL_TREE, size); + + if (gfc_index_integer_kind == 4) + fndecl = gfor_fndecl_internal_malloc; + else if (gfc_index_integer_kind == 8) + fndecl = gfor_fndecl_internal_malloc64; + else + abort (); + tmp = gfc_build_function_call (fndecl, tmp); + tmp = fold (convert (TREE_TYPE (decl), tmp)); + gfc_add_modify_expr (&block, decl, tmp); + + /* Set offset of the array. */ + if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); + + + /* Automatic arrays should not have initializers. */ + assert (!sym->value); + + gfc_add_expr_to_block (&block, fnbody); + + /* Free the temporary. */ + tmp = convert (pvoid_type_node, decl); + tmp = gfc_chainon_list (NULL_TREE, tmp); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp); + gfc_add_expr_to_block (&block, tmp); + + return gfc_finish_block (&block); +} + + +/* Generate entry and exit code for g77 calling convention arrays. */ + +tree +gfc_trans_g77_array (gfc_symbol * sym, tree body) +{ + tree parm; + tree type; + locus loc; + tree offset; + tree tmp; + stmtblock_t block; + + gfc_get_backend_locus (&loc); + gfc_set_backend_locus (&sym->declared_at); + + /* Descriptor type. */ + parm = sym->backend_decl; + type = TREE_TYPE (parm); + assert (GFC_ARRAY_TYPE_P (type)); + + gfc_start_block (&block); + + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &block); + + /* Evaluate the bounds of the array. */ + gfc_trans_array_bounds (type, sym, &offset, &block); + + /* Set the offset. */ + if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); + + /* Set the pointer itself if we aren't using the parameter dirtectly. */ + if (TREE_CODE (parm) != PARM_DECL) + { + tmp = convert (TREE_TYPE (parm), GFC_DECL_SAVED_DESCRIPTOR (parm)); + gfc_add_modify_expr (&block, parm, tmp); + } + tmp = gfc_finish_block (&block); + + gfc_set_backend_locus (&loc); + + gfc_start_block (&block); + /* Add the initialization code to the start of the function. */ + gfc_add_expr_to_block (&block, tmp); + gfc_add_expr_to_block (&block, body); + + return gfc_finish_block (&block); +} + + +/* Modify the descriptor of an array parameter so that it has the + correct lower bound. Also move the upper bound accordingly. + If the array is not packed, it will be copied into a temporary. + For each dimension we set the new lower and upper bounds. Then we copy the + stride and calculate the offset for this dimension. We also work out + what the stride of a packed array would be, and see it the two match. + If the array need repacking, we set the stride to the values we just + calculated, recalculate the offset and copy the array data. + Code is also added to copy the data back at the end of the function. + */ + +tree +gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body) +{ + tree size; + tree type; + tree offset; + locus loc; + stmtblock_t block; + stmtblock_t cleanup; + tree lbound; + tree ubound; + tree dubound; + tree dlbound; + tree dumdesc; + tree tmp; + tree stmt; + tree stride; + tree stmt_packed; + tree stmt_unpacked; + tree partial; + gfc_se se; + int n; + int checkparm; + int no_repack; + + if (sym->attr.dummy && gfc_is_nodesc_array (sym)) + return gfc_trans_g77_array (sym, body); + + gfc_get_backend_locus (&loc); + gfc_set_backend_locus (&sym->declared_at); + + /* Descriptor type. */ + type = TREE_TYPE (tmpdesc); + assert (GFC_ARRAY_TYPE_P (type)); + dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); + dumdesc = gfc_build_indirect_ref (dumdesc); + gfc_start_block (&block); + + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &block); + + checkparm = (sym->as->type == AS_EXPLICIT && flag_bounds_check); + + no_repack = !(GFC_DECL_PACKED_ARRAY (tmpdesc) + || GFC_DECL_PARTIAL_PACKED_ARRAY (tmpdesc)); + + if (GFC_DECL_PARTIAL_PACKED_ARRAY (tmpdesc)) + { + /* For non-constant shape arrays we only check if the first dimension + is contiguous. Repacking higher dimensions wouldn't gain us + anything as we still don't know the array stride. */ + partial = gfc_create_var (boolean_type_node, "partial"); + TREE_USED (partial) = 1; + tmp = gfc_conv_descriptor_stride (dumdesc, gfc_rank_cst[0]); + tmp = fold (build (EQ_EXPR, boolean_type_node, tmp, integer_one_node)); + gfc_add_modify_expr (&block, partial, tmp); + } + else + { + partial = NULL_TREE; + } + + /* The naming of stmt_unpacked and stmt_packed may be counter-intuitive + here, however I think it does the right thing. */ + if (no_repack) + { + /* Set the first stride. */ + stride = gfc_conv_descriptor_stride (dumdesc, gfc_rank_cst[0]); + stride = gfc_evaluate_now (stride, &block); + + tmp = build (EQ_EXPR, boolean_type_node, stride, integer_zero_node); + tmp = build (COND_EXPR, gfc_array_index_type, tmp, + integer_one_node, stride); + stride = GFC_TYPE_ARRAY_STRIDE (type, 0); + gfc_add_modify_expr (&block, stride, tmp); + + /* Allow the user to disable array repacking. */ + stmt_unpacked = NULL_TREE; + } + else + { + assert (integer_onep (GFC_TYPE_ARRAY_STRIDE (type, 0))); + /* A library call to repack the array if neccessary. */ + tmp = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); + tmp = gfc_chainon_list (NULL_TREE, tmp); + stmt_unpacked = gfc_build_function_call (gfor_fndecl_in_pack, tmp); + + stride = integer_one_node; + } + + /* This is for the case where the array data is used directly without + calling the repack function. */ + if (no_repack || partial != NULL_TREE) + stmt_packed = gfc_conv_descriptor_data (dumdesc); + else + stmt_packed = NULL_TREE; + + /* Assign the data pointer. */ + if (stmt_packed != NULL_TREE && stmt_unpacked != NULL_TREE) + { + /* Don't repack unknown shape arrays when the first stride is 1. */ + tmp = build (COND_EXPR, TREE_TYPE (stmt_packed), partial, + stmt_packed, stmt_unpacked); + } + else + tmp = stmt_packed != NULL_TREE ? stmt_packed : stmt_unpacked; + gfc_add_modify_expr (&block, tmpdesc, tmp); + + offset = integer_zero_node; + size = integer_one_node; + + /* Evaluate the bounds of the array. */ + for (n = 0; n < sym->as->rank; n++) + { + if (checkparm || !sym->as->upper[n]) + { + /* Get the bounds of the actual parameter. */ + dubound = gfc_conv_descriptor_ubound (dumdesc, gfc_rank_cst[n]); + dlbound = gfc_conv_descriptor_lbound (dumdesc, gfc_rank_cst[n]); + } + else + { + dubound = NULL_TREE; + dlbound = NULL_TREE; + } + + lbound = GFC_TYPE_ARRAY_LBOUND (type, n); + if (!INTEGER_CST_P (lbound)) + { + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, sym->as->upper[n], + gfc_array_index_type); + gfc_add_block_to_block (&block, &se.pre); + gfc_add_modify_expr (&block, lbound, se.expr); + } + + ubound = GFC_TYPE_ARRAY_UBOUND (type, n); + /* Set the desired upper bound. */ + if (sym->as->upper[n]) + { + /* We know what we want the upper bound to be. */ + if (!INTEGER_CST_P (ubound)) + { + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, sym->as->upper[n], + gfc_array_index_type); + gfc_add_block_to_block (&block, &se.pre); + gfc_add_modify_expr (&block, ubound, se.expr); + } + + /* Check the sizes match. */ + if (checkparm) + { + /* Check (ubound(a) - lbound(a) == ubound(b) - lbound(b)). */ + + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, ubound, + lbound)); + stride = build (MINUS_EXPR, gfc_array_index_type, dubound, + dlbound); + tmp = fold (build (NE_EXPR, gfc_array_index_type, tmp, stride)); + gfc_trans_runtime_check (tmp, gfc_strconst_bounds, &block); + } + } + else + { + /* For assumed shape arrays move the upper bound by the same amount + as the lower bound. */ + tmp = build (MINUS_EXPR, gfc_array_index_type, dubound, dlbound); + tmp = fold (build (PLUS_EXPR, gfc_array_index_type, tmp, lbound)); + gfc_add_modify_expr (&block, ubound, tmp); + } + /* The offset of this dimension. offset = offset - lbound * stride. */ + tmp = fold (build (MULT_EXPR, gfc_array_index_type, lbound, stride)); + offset = fold (build (MINUS_EXPR, gfc_array_index_type, offset, tmp)); + + /* The size of this dimension, and the stride of the next. */ + if (n + 1 < sym->as->rank) + { + stride = GFC_TYPE_ARRAY_STRIDE (type, n + 1); + + if (no_repack || partial != NULL_TREE) + { + stmt_unpacked = + gfc_conv_descriptor_stride (dumdesc, gfc_rank_cst[n+1]); + } + + /* Figure out the stride if not a known constant. */ + if (!INTEGER_CST_P (stride)) + { + if (no_repack) + stmt_packed = NULL_TREE; + else + { + /* Calculate stride = size * (ubound + 1 - lbound). */ + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, + integer_one_node, lbound)); + tmp = fold (build (PLUS_EXPR, gfc_array_index_type, + ubound, tmp)); + size = fold (build (MULT_EXPR, gfc_array_index_type, + size, tmp)); + stmt_packed = size; + } + + /* Assign the stride. */ + if (stmt_packed != NULL_TREE && stmt_unpacked != NULL_TREE) + { + tmp = build (COND_EXPR, gfc_array_index_type, partial, + stmt_unpacked, stmt_packed); + } + else + tmp = (stmt_packed != NULL_TREE) ? stmt_packed : stmt_unpacked; + gfc_add_modify_expr (&block, stride, tmp); + } + } + } + + /* Set the offset. */ + if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + gfc_add_modify_expr (&block, GFC_TYPE_ARRAY_OFFSET (type), offset); + + stmt = gfc_finish_block (&block); + + gfc_start_block (&block); + + /* Only do the entry/initialization code if the arg is present. */ + dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); + if (sym->attr.optional) + { + tmp = gfc_conv_expr_present (sym); + stmt = build_v (COND_EXPR, tmp, stmt, build_empty_stmt ()); + } + gfc_add_expr_to_block (&block, stmt); + + /* Add the main function body. */ + gfc_add_expr_to_block (&block, body); + + /* Cleanup code. */ + if (!no_repack) + { + gfc_start_block (&cleanup); + + if (sym->attr.intent != INTENT_IN) + { + /* Copy the data back. */ + tmp = gfc_chainon_list (NULL_TREE, dumdesc); + tmp = gfc_chainon_list (tmp, tmpdesc); + tmp = gfc_build_function_call (gfor_fndecl_in_unpack, tmp); + gfc_add_expr_to_block (&cleanup, tmp); + } + + /* Free the temporary. */ + tmp = gfc_chainon_list (NULL_TREE, tmpdesc); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp); + gfc_add_expr_to_block (&cleanup, tmp); + + stmt = gfc_finish_block (&cleanup); + + /* Only do the cleanup if the array was repacked. */ + tmp = gfc_build_indirect_ref (dumdesc); + tmp = gfc_conv_descriptor_data (tmp); + tmp = build (NE_EXPR, boolean_type_node, tmp, tmpdesc); + stmt = build_v (COND_EXPR, tmp, stmt, build_empty_stmt ()); + + if (sym->attr.optional) + { + tmp = gfc_conv_expr_present (sym); + stmt = build_v (COND_EXPR, tmp, stmt, build_empty_stmt ()); + } + gfc_add_expr_to_block (&block, stmt); + } + /* We don't need to free any memory allocated by internal_pack as it will + be freed at the end of the function by pop_context. */ + return gfc_finish_block (&block); +} + + +/* Convert an array for passing as an actual parameter. Expressions + and vector subscripts are evaluated and stored in a teporary, which is then + passed. For whole arrays the descriptor is passed. For array sections + a modified copy of the descriptor is passed, but using the original data. + Also used for array pointer assignments by setting se->direct_byref. */ + +void +gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) +{ + gfc_loopinfo loop; + gfc_ss *secss; + gfc_ss_info *info; + int need_tmp; + int n; + tree tmp; + tree desc; + stmtblock_t block; + tree start; + tree offset; + int full; + + assert (ss != gfc_ss_terminator); + + /* TODO: Pass constant array constructors without a temporary. */ + /* If we have a linear array section, we can pass it directly. Otherwise + we need to copy it into a temporary. */ + if (expr->expr_type == EXPR_VARIABLE) + { + gfc_ss *vss; + + /* Find the SS for the array section. */ + secss = ss; + while (secss != gfc_ss_terminator && secss->type != GFC_SS_SECTION) + secss = secss->next; + + assert (secss != gfc_ss_terminator); + + need_tmp = 0; + for (n = 0; n < secss->data.info.dimen; n++) + { + vss = secss->data.info.subscript[secss->data.info.dim[n]]; + if (vss && vss->type == GFC_SS_VECTOR) + need_tmp = 1; + } + + info = &secss->data.info; + + /* Get the descriptor for the array. */ + gfc_conv_ss_descriptor (&se->pre, secss, 0); + desc = info->descriptor; + if (GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) + { + /* Create a new descriptor if the array doesn't have one. */ + full = 0; + } + else if (info->ref->u.ar.type == AR_FULL) + full = 1; + else if (se->direct_byref) + full = 0; + else + { + assert (info->ref->u.ar.type == AR_SECTION); + + full = 1; + for (n = 0; n < info->ref->u.ar.dimen; n++) + { + /* Detect passing the full array as a section. This could do + even more checking, but it doesn't seem worth it. */ + if (info->ref->u.ar.start[n] + || info->ref->u.ar.end[n] + || (info->ref->u.ar.stride[n] + && !gfc_expr_is_one (info->ref->u.ar.stride[n], 0))) + { + full = 0; + break; + } + } + } + if (full) + { + if (se->direct_byref) + { + /* Copy the descriptor for pointer assignments. */ + gfc_add_modify_expr (&se->pre, se->expr, desc); + } + else if (se->want_pointer) + { + /* We pass full arrays directly. This means that pointers and + allocatable arrays should also work. */ + se->expr = gfc_build_addr_expr (NULL, desc); + } + else + { + se->expr = desc; + } + return; + } + } + else + { + need_tmp = 1; + secss = NULL; + info = NULL; + } + + gfc_init_loopinfo (&loop); + + /* Associate the SS with the loop. */ + gfc_add_ss_to_loop (&loop, ss); + + /* Tell the scalarizer not to bother creating loop varliables, etc. */ + if (!need_tmp) + loop.array_parameter = 1; + else + assert (se->want_pointer && !se->direct_byref); + + /* Setup the scalarizing loops and bounds. */ + gfc_conv_ss_startstride (&loop); + + if (need_tmp) + { + /* Tell the scalarizer to make a temporary. */ + loop.temp_ss = gfc_get_ss (); + loop.temp_ss->type = GFC_SS_TEMP; + loop.temp_ss->next = gfc_ss_terminator; + loop.temp_ss->data.temp.type = gfc_typenode_for_spec (&expr->ts); + loop.temp_ss->data.temp.string_length = NULL; + loop.temp_ss->data.temp.dimen = loop.dimen; + gfc_add_ss_to_loop (&loop, loop.temp_ss); + } + + gfc_conv_loop_setup (&loop); + + if (need_tmp) + { + /* Copy into a temporary and pass that. We don't need to copy the data + back because expressions and vector subscripts must be INTENT_IN. */ + /* TODO: Optimize passing function return values. */ + gfc_se lse; + gfc_se rse; + + /* Start the copying loops. */ + gfc_mark_ss_chain_used (loop.temp_ss, 1); + gfc_mark_ss_chain_used (ss, 1); + gfc_start_scalarized_body (&loop, &block); + + /* Copy each data element. */ + gfc_init_se (&lse, NULL); + gfc_copy_loopinfo_to_se (&lse, &loop); + gfc_init_se (&rse, NULL); + gfc_copy_loopinfo_to_se (&rse, &loop); + + lse.ss = loop.temp_ss; + rse.ss = ss; + + gfc_conv_scalarized_array_ref (&lse, NULL); + gfc_conv_expr_val (&rse, expr); + + gfc_add_block_to_block (&block, &rse.pre); + gfc_add_block_to_block (&block, &lse.pre); + + gfc_add_modify_expr (&block, lse.expr, rse.expr); + + /* Finish the copying loops. */ + gfc_trans_scalarizing_loops (&loop, &block); + + /* Set the first stride component to zero to indicate a temporary. */ + desc = loop.temp_ss->data.info.descriptor; + tmp = gfc_conv_descriptor_stride (desc, gfc_rank_cst[0]); + gfc_add_modify_expr (&loop.pre, tmp, integer_zero_node); + + assert (is_gimple_lvalue (desc)); + se->expr = gfc_build_addr_expr (NULL, desc); + } + else + { + /* We pass sections without copying to a temporary. A function may + decide to repack the array to speed up access, but we're not + bothered about that here. */ + int dim; + tree parm; + tree parmtype; + tree stride; + tree from; + tree to; + tree base; + + /* Otherwise make a new descriptor and point it at the section we + want. The loop variable limits will be the limits of the section. + */ + desc = info->descriptor; + assert (secss && secss != gfc_ss_terminator); + if (se->direct_byref) + { + /* For pointer assignments we fill in the destination. */ + parm = se->expr; + parmtype = TREE_TYPE (parm); + } + else + { + /* Otherwise make a new one. */ + parmtype = gfc_get_element_type (TREE_TYPE (desc)); + parmtype = gfc_get_array_type_bounds (parmtype, loop.dimen, + loop.from, loop.to, 0); + parm = gfc_create_var (parmtype, "parm"); + } + + offset = integer_zero_node; + dim = 0; + + /* The following can be somewhat confusing. We have two + descriptors, a new one and the original array. + {parm, parmtype, dim} refer to the new one. + {desc, type, n, secss, loop} refer to the original, which maybe + a descriptorless array. + The bounds of the scaralization are the bounds of the section. + We don't have to worry about numeric overflows when calculating + the offsets because all elements are within the array data. */ + + /* Set the dtype. */ + tmp = gfc_conv_descriptor_dtype (parm); + gfc_add_modify_expr (&loop.pre, tmp, GFC_TYPE_ARRAY_DTYPE (parmtype)); + + if (se->direct_byref) + base = integer_zero_node; + else + base = NULL_TREE; + + for (n = 0; n < info->ref->u.ar.dimen; n++) + { + stride = gfc_conv_array_stride (desc, n); + + /* Work out the offset. */ + if (info->ref->u.ar.dimen_type[n] == DIMEN_ELEMENT) + { + assert (info->subscript[n] + && info->subscript[n]->type == GFC_SS_SCALAR); + start = info->subscript[n]->data.scalar.expr; + } + else + { + /* Check we haven't somehow got out of sync. */ + assert (info->dim[dim] == n); + + /* Evaluate and remember the start of the section. */ + start = info->start[dim]; + stride = gfc_evaluate_now (stride, &loop.pre); + } + + tmp = gfc_conv_array_lbound (desc, n); + tmp = fold (build (MINUS_EXPR, TREE_TYPE (tmp), start, tmp)); + + tmp = fold (build (MULT_EXPR, TREE_TYPE (tmp), tmp, stride)); + offset = fold (build (PLUS_EXPR, TREE_TYPE (tmp), offset, tmp)); + + if (info->ref->u.ar.dimen_type[n] == DIMEN_ELEMENT) + { + /* For elemental dimensions, we only need the offset. */ + continue; + } + + /* Vector subscripts need copying and are handled elsewhere. */ + assert (info->ref->u.ar.dimen_type[n] == DIMEN_RANGE); + + /* Set the new lower bound. */ + from = loop.from[dim]; + to = loop.to[dim]; + if (!integer_onep (from)) + { + /* Make sure the new section starts at 1. */ + tmp = fold (build (MINUS_EXPR, TREE_TYPE (from), + integer_one_node, from)); + to = fold (build (PLUS_EXPR, TREE_TYPE (to), to, tmp)); + from = integer_one_node; + } + tmp = gfc_conv_descriptor_lbound (parm, gfc_rank_cst[dim]); + gfc_add_modify_expr (&loop.pre, tmp, from); + + /* Set the new upper bound. */ + tmp = gfc_conv_descriptor_ubound (parm, gfc_rank_cst[dim]); + gfc_add_modify_expr (&loop.pre, tmp, to); + + /* Multiply the stride by the section stride to get the + total stride. */ + stride = fold (build (MULT_EXPR, gfc_array_index_type, stride, + info->stride[dim])); + + if (se->direct_byref) + { + base = fold (build (MINUS_EXPR, TREE_TYPE (base), + base, stride)); + } + + /* Store the new stride. */ + tmp = gfc_conv_descriptor_stride (parm, gfc_rank_cst[dim]); + gfc_add_modify_expr (&loop.pre, tmp, stride); + + dim++; + } + + /* Point the data pointer at the first element in the section. */ + tmp = gfc_conv_array_data (desc); + tmp = gfc_build_indirect_ref (tmp); + tmp = gfc_build_array_ref (tmp, offset); + offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp); + + tmp = gfc_conv_descriptor_data (parm); + gfc_add_modify_expr (&loop.pre, tmp, offset); + + if (se->direct_byref) + { + /* Set the offset. */ + tmp = gfc_conv_descriptor_offset (parm); + gfc_add_modify_expr (&loop.pre, tmp, base); + } + else + { + /* Only the callee knows what the correct offset it, so just set + it to zero here. */ + tmp = gfc_conv_descriptor_offset (parm); + gfc_add_modify_expr (&loop.pre, tmp, gfc_index_zero_node); + } + + if (!se->direct_byref) + { + /* Get a pointer to the new descriptor. */ + if (se->want_pointer) + se->expr = gfc_build_addr_expr (NULL, parm); + else + se->expr = parm; + } + } + + gfc_add_block_to_block (&se->pre, &loop.pre); + gfc_add_block_to_block (&se->post, &loop.post); + + /* Cleanup the scalarizer. */ + gfc_cleanup_loop (&loop); +} + + +/* Convert an array for passing as an actual parameter. */ +/* TODO: Optimize passing g77 arrays. */ + +void +gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77) +{ + tree ptr; + tree desc; + tree tmp; + tree stmt; + gfc_symbol *sym; + stmtblock_t block; + + /* Passing address of the array if it is not pointer or assumed-shape. */ + if (expr->expr_type == EXPR_VARIABLE + && expr->ref->u.ar.type == AR_FULL && g77) + { + sym = expr->symtree->n.sym; + tmp = gfc_get_symbol_decl (sym); + if (!sym->attr.pointer && sym->as->type != AS_ASSUMED_SHAPE + && !sym->attr.allocatable) + { + if (!sym->attr.dummy) + se->expr = gfc_build_addr_expr (NULL, tmp); + else + se->expr = tmp; + return; + } + if (sym->attr.allocatable) + { + se->expr = gfc_conv_array_data (tmp); + return; + } + } + + se->want_pointer = 1; + gfc_conv_expr_descriptor (se, expr, ss); + + if (g77) + { + desc = se->expr; + /* Repack the array. */ + tmp = gfc_chainon_list (NULL_TREE, desc); + ptr = gfc_build_function_call (gfor_fndecl_in_pack, tmp); + ptr = gfc_evaluate_now (ptr, &se->pre); + se->expr = ptr; + + gfc_start_block (&block); + + /* Copy the data back. */ + tmp = gfc_chainon_list (NULL_TREE, desc); + tmp = gfc_chainon_list (tmp, ptr); + tmp = gfc_build_function_call (gfor_fndecl_in_unpack, tmp); + gfc_add_expr_to_block (&block, tmp); + + /* Free the temporary. */ + tmp = convert (pvoid_type_node, ptr); + tmp = gfc_chainon_list (NULL_TREE, tmp); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp); + gfc_add_expr_to_block (&block, tmp); + + stmt = gfc_finish_block (&block); + + gfc_init_block (&block); + /* Only if it was repacked. This code needs to be executed before the + loop cleanup code. */ + tmp = gfc_build_indirect_ref (desc); + tmp = gfc_conv_array_data (tmp); + tmp = build (NE_EXPR, boolean_type_node, ptr, tmp); + tmp = build_v (COND_EXPR, tmp, stmt, build_empty_stmt ()); + + gfc_add_expr_to_block (&block, tmp); + gfc_add_block_to_block (&block, &se->post); + + gfc_init_block (&se->post); + gfc_add_block_to_block (&se->post, &block); + } +} + + +/* NULLIFY an allocated/pointer array on function entry, free it on exit. */ + +tree +gfc_trans_deferred_array (gfc_symbol * sym, tree body) +{ + tree type; + tree tmp; + tree descriptor; + tree deallocate; + stmtblock_t block; + stmtblock_t fnblock; + locus loc; + + /* Make sure the frontend gets these right. */ + if (!(sym->attr.pointer || sym->attr.allocatable)) + fatal_error + ("Possible frontend bug: Deferred array size without pointer or allocatable attribute."); + + gfc_init_block (&fnblock); + + assert (TREE_CODE (sym->backend_decl) == VAR_DECL); + if (sym->ts.type == BT_CHARACTER + && !INTEGER_CST_P (sym->ts.cl->backend_decl)) + gfc_trans_init_string_length (sym->ts.cl, &fnblock); + + /* Parameter variables don't need anything special. */ + if (sym->attr.dummy) + { + gfc_add_expr_to_block (&fnblock, body); + + return gfc_finish_block (&fnblock); + } + + gfc_get_backend_locus (&loc); + gfc_set_backend_locus (&sym->declared_at); + descriptor = sym->backend_decl; + + if (TREE_STATIC (descriptor)) + { + /* SAVEd variables are not freed on exit. */ + gfc_trans_static_array_pointer (sym); + return body; + } + + /* Get the descriptor type. */ + type = TREE_TYPE (sym->backend_decl); + assert (GFC_DESCRIPTOR_TYPE_P (type)); + + /* NULLIFY the data pointer. */ + tmp = gfc_conv_descriptor_data (descriptor); + gfc_add_modify_expr (&fnblock, tmp, integer_zero_node); + + gfc_add_expr_to_block (&fnblock, body); + + gfc_set_backend_locus (&loc); + /* Allocatable arrays need to be freed when they go out of scope. */ + if (sym->attr.allocatable) + { + gfc_start_block (&block); + + /* Deallocate if still allocated at the end of the procedure. */ + deallocate = gfc_array_deallocate (descriptor); + + tmp = gfc_conv_descriptor_data (descriptor); + tmp = build (NE_EXPR, boolean_type_node, tmp, integer_zero_node); + tmp = build_v (COND_EXPR, tmp, deallocate, build_empty_stmt ()); + gfc_add_expr_to_block (&block, tmp); + + tmp = gfc_finish_block (&block); + gfc_add_expr_to_block (&fnblock, tmp); + } + + return gfc_finish_block (&fnblock); +} + +/************ Expression Walking Functions ******************/ + +/* Walk a variable reference. + + Possible extension - multiple component subscripts. + x(:,:) = foo%a(:)%b(:) + Transforms to + forall (i=..., j=...) + x(i,j) = foo%a(j)%b(i) + end forall + This adds a fair amout of complexity because you need to deal with more + than one ref. Maybe handle in a similar manner to vector subscripts. + Maybe not worth the effort. */ + + +static gfc_ss * +gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr) +{ + gfc_ref *ref; + gfc_array_ref *ar; + gfc_ss *newss; + gfc_ss *head; + int n; + + for (ref = expr->ref; ref; ref = ref->next) + { + /* We're only interested in array sections. */ + if (ref->type != REF_ARRAY) + continue; + + ar = &ref->u.ar; + switch (ar->type) + { + case AR_ELEMENT: + /* TODO: Take elemental array references out of scalarization + loop. */ + break; + + case AR_FULL: + newss = gfc_get_ss (); + newss->type = GFC_SS_SECTION; + newss->expr = expr; + newss->next = ss; + newss->data.info.dimen = ar->as->rank; + newss->data.info.ref = ref; + + /* Make sure array is the same as array(:,:), this way + we don't need to special case all the time. */ + ar->dimen = ar->as->rank; + for (n = 0; n < ar->dimen; n++) + { + newss->data.info.dim[n] = n; + ar->dimen_type[n] = DIMEN_RANGE; + + assert (ar->start[n] == NULL); + assert (ar->end[n] == NULL); + assert (ar->stride[n] == NULL); + } + return newss; + + case AR_SECTION: + newss = gfc_get_ss (); + newss->type = GFC_SS_SECTION; + newss->expr = expr; + newss->next = ss; + newss->data.info.dimen = 0; + newss->data.info.ref = ref; + + head = newss; + + /* We add SS chains for all the subscripts in the section. */ + for (n = 0; n < ar->dimen; n++) + { + gfc_ss *indexss; + + switch (ar->dimen_type[n]) + { + case DIMEN_ELEMENT: + /* Add SS for elemental (scalar) subscripts. */ + assert (ar->start[n]); + indexss = gfc_get_ss (); + indexss->type = GFC_SS_SCALAR; + indexss->expr = ar->start[n]; + indexss->next = gfc_ss_terminator; + indexss->loop_chain = gfc_ss_terminator; + newss->data.info.subscript[n] = indexss; + break; + + case DIMEN_RANGE: + /* We don't add anything for sections, just remember this + dimension for later. */ + newss->data.info.dim[newss->data.info.dimen] = n; + newss->data.info.dimen++; + break; + + case DIMEN_VECTOR: + /* Get a SS for the vector. This will not be added to the + chain directly. */ + indexss = gfc_walk_expr (ar->start[n]); + if (indexss == gfc_ss_terminator) + internal_error ("scalar vector subscript???"); + + /* We currently only handle really simple vector + subscripts. */ + if (indexss->next != gfc_ss_terminator) + gfc_todo_error ("vector subscript expressions"); + indexss->loop_chain = gfc_ss_terminator; + + /* Mark this as a vector subscript. We don't add this + directly into the chain, but as a subscript of the + existing SS for this term. */ + indexss->type = GFC_SS_VECTOR; + newss->data.info.subscript[n] = indexss; + /* Also remember this dimension. */ + newss->data.info.dim[newss->data.info.dimen] = n; + newss->data.info.dimen++; + break; + + default: + /* We should know what sort of section it is by now. */ + abort (); + } + } + /* We should have at least one non-elemental dimension. */ + assert (newss->data.info.dimen > 0); + return head; + break; + + default: + /* We should know what sort of section it is by now. */ + abort (); + } + + } + return ss; +} + + +/* Walk an expression operator. If only one operand of a binary expression is + scalar, we must also add the scalar term to the SS chain. */ + +static gfc_ss * +gfc_walk_op_expr (gfc_ss * ss, gfc_expr * expr) +{ + gfc_ss *head; + gfc_ss *head2; + gfc_ss *newss; + + head = gfc_walk_subexpr (ss, expr->op1); + if (expr->op2 == NULL) + head2 = head; + else + head2 = gfc_walk_subexpr (head, expr->op2); + + /* All operands are scalar. Pass back and let the caller deal with it. */ + if (head2 == ss) + return head2; + + /* All operands require scalarization. */ + if (head != ss && (expr->op2 == NULL || head2 != head)) + return head2; + + /* One of the operands needs scalarization, the other is scalar. + Create a gfc_ss for the scalar expression. */ + newss = gfc_get_ss (); + newss->type = GFC_SS_SCALAR; + if (head == ss) + { + /* First operand is scalar. We build the chain in reverse order, so + add the scarar SS after the second operand. */ + head = head2; + while (head && head->next != ss) + head = head->next; + /* Check we haven't somehow broken the chain. */ + assert (head); + newss->next = ss; + head->next = newss; + newss->expr = expr->op1; + } + else /* head2 == head */ + { + assert (head2 == head); + /* Second operand is scalar. */ + newss->next = head2; + head2 = newss; + newss->expr = expr->op2; + } + + return head2; +} + + +/* Reverse a SS chain. */ + +static gfc_ss * +gfc_reverse_ss (gfc_ss * ss) +{ + gfc_ss *next; + gfc_ss *head; + + assert (ss != NULL); + + head = gfc_ss_terminator; + while (ss != gfc_ss_terminator) + { + next = ss->next; + assert (next != NULL); /* Check we didn't somehow break the chain. */ + ss->next = head; + head = ss; + ss = next; + } + + return (head); +} + + +/* Walk the arguments of an elemental function. */ + +gfc_ss * +gfc_walk_elemental_function_args (gfc_ss * ss, gfc_expr * expr, + gfc_ss_type type) +{ + gfc_actual_arglist *arg; + int scalar; + gfc_ss *head; + gfc_ss *tail; + gfc_ss *newss; + + head = gfc_ss_terminator; + tail = NULL; + scalar = 1; + for (arg = expr->value.function.actual; arg; arg = arg->next) + { + if (!arg->expr) + continue; + + newss = gfc_walk_subexpr (head, arg->expr); + if (newss == head) + { + /* Scalar argumet. */ + newss = gfc_get_ss (); + newss->type = type; + newss->expr = arg->expr; + newss->next = head; + } + else + scalar = 0; + + head = newss; + if (!tail) + { + tail = head; + while (tail->next != gfc_ss_terminator) + tail = tail->next; + } + } + + if (scalar) + { + /* If all the arguments are scalar we don't need the argument SS. */ + gfc_free_ss_chain (head); + /* Pass it back. */ + return ss; + } + + /* Add it onto the existing chain. */ + tail->next = ss; + return head; +} + + +/* Walk a function call. Scalar functions are passed back, and taken out of + scalarization loops. For elemental functions we walk their arguments. + The result of functions returning arrays is stored in a temporary outside + the loop, so that the function is only called once. Hence we do not need + to walk their arguments. */ + +static gfc_ss * +gfc_walk_function_expr (gfc_ss * ss, gfc_expr * expr) +{ + gfc_ss *newss; + gfc_intrinsic_sym *isym; + gfc_symbol *sym; + + isym = expr->value.function.isym; + + /* Handle intrinsic functions seperately. */ + if (isym) + return gfc_walk_intrinsic_function (ss, expr, isym); + + sym = expr->value.function.esym; + if (!sym) + sym = expr->symtree->n.sym; + + /* A function that returns arrays. */ + if (gfc_return_by_reference (sym) && sym->result->attr.dimension) + { + newss = gfc_get_ss (); + newss->type = GFC_SS_FUNCTION; + newss->expr = expr; + newss->next = ss; + newss->data.info.dimen = expr->rank; + return newss; + } + + /* Walk the parameters of an elemental function. For now we always pass + by reference. */ + if (sym->attr.elemental) + return gfc_walk_elemental_function_args (ss, expr, GFC_SS_REFERENCE); + + /* Scalar functions are OK as these are evaluated outside the scalarisation + loop. Pass back and let the caller deal with it. */ + return ss; +} + + +/* An array temporary is constructed for array constructors. */ + +static gfc_ss * +gfc_walk_array_constructor (gfc_ss * ss, gfc_expr * expr) +{ + gfc_ss *newss; + int n; + + newss = gfc_get_ss (); + newss->type = GFC_SS_CONSTRUCTOR; + newss->expr = expr; + newss->next = ss; + newss->data.info.dimen = expr->rank; + for (n = 0; n < expr->rank; n++) + newss->data.info.dim[n] = n; + + return newss; +} + + +/* Walk an expresson. Add walked expressions to the head of the SS chain. + A wholy scalar expression will not be added. */ + +static gfc_ss * +gfc_walk_subexpr (gfc_ss * ss, gfc_expr * expr) +{ + gfc_ss *head; + + switch (expr->expr_type) + { + case EXPR_VARIABLE: + head = gfc_walk_variable_expr (ss, expr); + return head; + + case EXPR_OP: + head = gfc_walk_op_expr (ss, expr); + return head; + + case EXPR_FUNCTION: + head = gfc_walk_function_expr (ss, expr); + return head; + + case EXPR_CONSTANT: + case EXPR_NULL: + case EXPR_STRUCTURE: + /* Pass back and let the caller deal with it. */ + break; + + case EXPR_ARRAY: + head = gfc_walk_array_constructor (ss, expr); + return head; + + case EXPR_SUBSTRING: + /* Pass back and let the caller deal with it. */ + break; + + default: + internal_error ("bad expression type during walk (%d)", + expr->expr_type); + } + return ss; +} + + +/* Entry point for expression walking. + A return value equal to the passed chain means this is + a scalar expression. It is up to the caller to take whatever action is + neccessary to translate these. */ + +gfc_ss * +gfc_walk_expr (gfc_expr * expr) +{ + gfc_ss *res; + + res = gfc_walk_subexpr (gfc_ss_terminator, expr); + return gfc_reverse_ss (res); +} + diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h new file mode 100644 index 00000000000..fe3f9ce707d --- /dev/null +++ b/gcc/fortran/trans-array.h @@ -0,0 +1,117 @@ +/* Header for array handling functions + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Generate code to free an array. */ +tree gfc_array_deallocate (tree); + +/* Generate code to initialise an allocate an array. Statements are added to + se, which should contain an expression for the array descriptor. */ +void gfc_array_allocate (gfc_se *, gfc_ref *, tree); + +/* Generate code to allocate a temporary array. */ +tree gfc_trans_allocate_temp_array (gfc_loopinfo *, gfc_ss_info *, tree, + tree); + +/* Generate function entry code for allocation of compiler allocated array + variables. */ +tree gfc_trans_auto_array_allocation (tree, gfc_symbol *, tree); +/* Generate entry and exit code for dummy array parameters. */ +tree gfc_trans_dummy_array_bias (gfc_symbol *, tree, tree); +/* Generate entry and exit code for g77 calling convention arrays. */ +tree gfc_trans_g77_array (gfc_symbol *, tree); +/* Add initialisation for deferred arrays. */ +tree gfc_trans_deferred_array (gfc_symbol *, tree); +/* Generate an initializer for a static pointer or allocatable array. */ +void gfc_trans_static_array_pointer (gfc_symbol *); + +/* Generate scalarization information for an expression. */ +gfc_ss *gfc_walk_expr (gfc_expr *); +/* Walk the arguments of an intrinsic function. */ +gfc_ss *gfc_walk_elemental_function_args (gfc_ss *, gfc_expr *, gfc_ss_type); +/* Walk an intrinsic function. */ +gfc_ss *gfc_walk_intrinsic_function (gfc_ss *, gfc_expr *, + gfc_intrinsic_sym *); + +/* Free the SS assocuated with a loop. */ +void gfc_cleanup_loop (gfc_loopinfo *); +/* Associate a SS chain with a loop. */ +void gfc_add_ss_to_loop (gfc_loopinfo *, gfc_ss *); +/* Mark a SS chain as used in this loop. */ +void gfc_mark_ss_chain_used (gfc_ss *, unsigned); + +/* Calculates the lower bound and stride of array sections. */ +void gfc_conv_ss_startstride (gfc_loopinfo *); + +void gfc_init_loopinfo (gfc_loopinfo *); +void gfc_copy_loopinfo_to_se (gfc_se *, gfc_loopinfo *); + +/* Marks the start of a scalarized expression, and declares loop variables. */ +void gfc_start_scalarized_body (gfc_loopinfo *, stmtblock_t *); +/* Generates the actual loops for a scalarized expression. */ +void gfc_trans_scalarizing_loops (gfc_loopinfo *, stmtblock_t *); +/* Mark the end of the main loop body and the start of the copying loop. */ +void gfc_trans_scalarized_loop_boundary (gfc_loopinfo *, stmtblock_t *); +/* Initialise the scalarization loop parameters. */ +void gfc_conv_loop_setup (gfc_loopinfo *); +/* Resolve array assignment dependencies. */ +void gfc_conv_resolve_dependencies (gfc_loopinfo *, gfc_ss *, gfc_ss *); + +/* Get a single array element. */ +void gfc_conv_array_ref (gfc_se *, gfc_array_ref *); +/* Translate a reference to a temporary array. */ +void gfc_conv_tmp_array_ref (gfc_se * se); +/* Translate a reference to an array temporary. */ +void gfc_conv_tmp_ref (gfc_se *); + +/* Evaluate an array expression. */ +void gfc_conv_expr_descriptor (gfc_se *, gfc_expr *, gfc_ss *); +/* Convert an array for passing as an actual function parameter. */ +void gfc_conv_array_parameter (gfc_se *, gfc_expr *, gfc_ss *, int); + +/* These work with both descriptors and descriptorless arrays. */ +tree gfc_conv_array_data (tree); +tree gfc_conv_array_offset (tree); +/* Return either an INT_CST or an expression for that part of the descriptor. */ +tree gfc_conv_array_stride (tree, int); +tree gfc_conv_array_lbound (tree, int); +tree gfc_conv_array_ubound (tree, int); + +/* The remaining space available for stack variables. */ +extern unsigned HOST_WIDE_INT gfc_stack_space_left; +/* Returns true if a variable of specified size should go on the stack. */ +int gfc_can_put_var_on_stack (tree); + +/* Build expressions for accessing components of an array descriptor. */ +tree gfc_conv_descriptor_data (tree); +tree gfc_conv_descriptor_offset (tree); +tree gfc_conv_descriptor_dtype (tree); +tree gfc_conv_descriptor_stride (tree, tree); +tree gfc_conv_descriptor_lbound (tree, tree); +tree gfc_conv_descriptor_ubound (tree, tree); + +/* Dependency checking for WHERE and FORALL. */ +int gfc_check_dependency (gfc_expr *, gfc_expr *, gfc_expr **, int); +/* Dependency checking for function calls. */ +int gfc_check_fncall_dependency (gfc_expr *, gfc_expr *); + +/* Add pre-loop scalarization code for intrinsic functions which require + special handling. */ +void gfc_add_intrinsic_ss_code (gfc_loopinfo *, gfc_ss *); diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c new file mode 100644 index 00000000000..0c954191818 --- /dev/null +++ b/gcc/fortran/trans-common.c @@ -0,0 +1,756 @@ +/* Common block and equivalence list handling + Copyright (C) 2000-2003 Free Software Foundation, Inc. + Contributed by Canqun Yang + +This file is part of GNU G95. + +G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* The core algorithm is based on Andy Vaught's g95 tree. Also the + way to build UNION_TYPE is borrowed from Richard Henderson. + + Transform common blocks. An integral part of this is processing + equvalence variables. Equivalenced variables that are not in a + common block end up in a private block of their own. + + Each common block or local equivalence list is declared as a union. + Variables within the block are represented as a field within the + block with the proper offset. + + So if two variables are equivalenced, they just point to a common + area in memory. + + Mathematically, laying out an equivalence block is equivalent to + solving a linear system of equations. The matrix is usually a + sparse matrix in which each row contains all zero elements except + for a +1 and a -1, a sort of a generalized Vandermonde matrix. The + matrix is usually block diagonal. The system can be + overdetermined, underdetermined or have a unique solution. If the + system is inconsistent, the program is not standard conforming. + The solution vector is integral, since all of the pivots are +1 or -1. + + How we lay out an equivalence block is a little less complicated. + In an equivalence list with n elements, there are n-1 conditions to + be satisfied. The conditions partition the variables into what we + will call segments. If A and B are equivalenced then A and B are + in the same segment. If B and C are equivalenced as well, then A, + B and C are in a segment and so on. Each segment is a block of + memory that has one or more variables equivalenced in some way. A + common block is made up of a series of segments that are joined one + after the other. In the linear system, a segment is a block + diagonal. + + To lay out a segment we first start with some variable and + determine its length. The first variable is assumed to start at + offset one and extends to however long it is. We then traverse the + list of equivalences to find an unused condition that involves at + least one of the variables currently in the segment. + + Each equivalence condition amounts to the condition B+b=C+c where B + and C are the offsets of the B and C variables, and b and c are + constants which are nonzero for array elements, substrings or + structure components. So for + + EQUIVALENCE(B(2), C(3)) + we have + B + 2*size of B's elements = C + 3*size of C's elements. + + If B and C are known we check to see if the condition already + holds. If B is known we can solve for C. Since we know the length + of C, we can see if the minimum and maximum extents of the segment + are affected. Eventually, we make a full pass through the + equivalence list without finding any new conditions and the segment + is fully specified. + + At this point, the segment is added to the current common block. + Since we know the minimum extent of the segment, everything in the + segment is translated to its position in the common block. The + usual case here is that there are no equivalence statements and the + common block is series of segments with one variable each, which is + a diagonal matrix in the matrix formulation. + + Once all common blocks have been created, the list of equivalences + is examined for still-unused equivalence conditions. We create a + block for each merged equivalence list. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "toplev.h" +#include "tm.h" +#include "gfortran.h" +#include "trans.h" +#include "trans-types.h" +#include "trans-const.h" + + +typedef struct segment_info +{ + gfc_symbol *sym; + int offset; + int length; + tree field; + struct segment_info *next; +} segment_info; + +static segment_info *current_segment, *current_common; +static int current_length, current_offset; +static gfc_namespace *gfc_common_ns = NULL; + +#define get_segment_info() gfc_getmem (sizeof (segment_info)) + +#define BLANK_COMMON_NAME "__BLNK__" + + +/* Construct mangled common block name from symbol name. */ + +static tree +gfc_sym_mangled_common_id (gfc_symbol *sym) +{ + int has_underscore; + char name[GFC_MAX_MANGLED_SYMBOL_LEN + 1]; + + if (strcmp (sym->name, BLANK_COMMON_NAME) == 0) + return get_identifier (sym->name); + if (gfc_option.flag_underscoring) + { + has_underscore = strchr (sym->name, '_') != 0; + if (gfc_option.flag_second_underscore && has_underscore) + snprintf (name, sizeof name, "%s__", sym->name); + else + snprintf (name, sizeof name, "%s_", sym->name); + return get_identifier (name); + } + else + return get_identifier (sym->name); +} + + +/* Build a filed declaration for a common variable or a local equivalence + object. */ + +static tree +build_field (segment_info *h, tree union_type, record_layout_info rli) +{ + tree type = gfc_sym_type (h->sym); + tree name = get_identifier (h->sym->name); + tree field = build_decl (FIELD_DECL, name, type); + HOST_WIDE_INT offset = h->offset; + unsigned int desired_align, known_align; + + known_align = (offset & -offset) * BITS_PER_UNIT; + if (known_align == 0 || known_align > BIGGEST_ALIGNMENT) + known_align = BIGGEST_ALIGNMENT; + + desired_align = update_alignment_for_field (rli, field, known_align); + if (desired_align > known_align) + DECL_PACKED (field) = 1; + + DECL_FIELD_CONTEXT (field) = union_type; + DECL_FIELD_OFFSET (field) = size_int (offset); + DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; + SET_DECL_OFFSET_ALIGN (field, known_align); + + rli->offset = size_binop (MAX_EXPR, rli->offset, + size_binop (PLUS_EXPR, + DECL_FIELD_OFFSET (field), + DECL_SIZE_UNIT (field))); + return field; +} + + +/* Get storage for local equivalence. */ + +static tree +build_equiv_decl (tree union_type, bool is_init) +{ + tree decl; + decl = build_decl (VAR_DECL, NULL, union_type); + DECL_ARTIFICIAL (decl) = 1; + + if (is_init) + DECL_COMMON (decl) = 0; + else + DECL_COMMON (decl) = 1; + + TREE_ADDRESSABLE (decl) = 1; + TREE_USED (decl) = 1; + gfc_add_decl_to_function (decl); + + return decl; +} + + +/* Get storage for common block. */ + +static tree +build_common_decl (gfc_symbol *sym, tree union_type, bool is_init) +{ + gfc_symbol *common_sym; + tree decl; + + /* Create a namespace to store symbols for common blocks. */ + if (gfc_common_ns == NULL) + gfc_common_ns = gfc_get_namespace (NULL); + + gfc_get_symbol (sym->name, gfc_common_ns, &common_sym); + decl = common_sym->backend_decl; + + /* Update the size of this common block as needed. */ + if (decl != NULL_TREE) + { + tree size = build_int_2 (current_length, 0); + if (tree_int_cst_lt (DECL_SIZE_UNIT (decl), size)) + { + /* Named common blocks of the same name shall be of the same size + in all scoping units of a program in which they appear, but + blank common blocks may be of different sizes. */ + if (strcmp (sym->name, BLANK_COMMON_NAME)) + gfc_warning ("named COMMON block '%s' at %L shall be of the " + "same size", sym->name, &sym->declared_at); + DECL_SIZE_UNIT (decl) = size; + } + } + + /* If this common block has been declared in a previous program unit, + and either it is already initialized or there is no new initialization + for it, just return. */ + if ((decl != NULL_TREE) && (!is_init || DECL_INITIAL (decl))) + return decl; + + /* If there is no backend_decl for the common block, build it. */ + if (decl == NULL_TREE) + { + decl = build_decl (VAR_DECL, get_identifier (sym->name), union_type); + SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_common_id (sym)); + TREE_PUBLIC (decl) = 1; + TREE_STATIC (decl) = 1; + DECL_ALIGN (decl) = BIGGEST_ALIGNMENT; + DECL_USER_ALIGN (decl) = 0; + } + + /* Has no initial values. */ + if (!is_init) + { + DECL_INITIAL (decl) = NULL_TREE; + DECL_COMMON (decl) = 1; + DECL_DEFER_OUTPUT (decl) = 1; + + /* Place the back end declaration for this common block in + GLOBAL_BINDING_LEVEL. */ + common_sym->backend_decl = pushdecl_top_level (decl); + } + else + { + DECL_INITIAL (decl) = error_mark_node; + DECL_COMMON (decl) = 0; + DECL_DEFER_OUTPUT (decl) = 0; + common_sym->backend_decl = decl; + } + return decl; +} + + +/* Declare memory for the common block or local equivalence, and create + backend declarations for all of the elements. */ + +static void +create_common (gfc_symbol *sym) +{ + segment_info *h, *next_s; + tree union_type; + tree *field_link; + record_layout_info rli; + tree decl; + bool is_init = false; + + /* Declare the variables inside the common block. */ + union_type = make_node (UNION_TYPE); + rli = start_record_layout (union_type); + field_link = &TYPE_FIELDS (union_type); + + for (h = current_common; h; h = next_s) + { + tree field; + field = build_field (h, union_type, rli); + + /* Link the field into the type. */ + *field_link = field; + field_link = &TREE_CHAIN (field); + h->field = field; + /* Has initial value. */ + if (h->sym->value) + is_init = true; + + next_s = h->next; + } + finish_record_layout (rli, true); + + if (is_init) + gfc_todo_error ("initial values for COMMON or EQUIVALENCE"); + + if (sym) + decl = build_common_decl (sym, union_type, is_init); + else + decl = build_equiv_decl (union_type, is_init); + + /* Build component reference for each variable. */ + for (h = current_common; h; h = next_s) + { + h->sym->backend_decl = build (COMPONENT_REF, TREE_TYPE (h->field), + decl, h->field); + + next_s = h->next; + gfc_free (h); + } +} + + +/* Given a symbol, find it in the current segment list. Returns NULL if + not found. */ + +static segment_info * +find_segment_info (gfc_symbol *symbol) +{ + segment_info *n; + + for (n = current_segment; n; n = n->next) + if (n->sym == symbol) return n; + + return NULL; +} + + +/* Given a variable symbol, calculate the total length in bytes of the + variable. */ + +static int +calculate_length (gfc_symbol *symbol) +{ + int j, element_size; + mpz_t elements; + + if (symbol->ts.type == BT_CHARACTER) + gfc_conv_const_charlen (symbol->ts.cl); + element_size = int_size_in_bytes (gfc_typenode_for_spec (&symbol->ts)); + if (symbol->as == NULL) + return element_size; + + /* Calculate the number of elements in the array */ + if (spec_size (symbol->as, &elements) == FAILURE) + gfc_internal_error ("calculate_length(): Unable to determine array size"); + j = mpz_get_ui (elements); + mpz_clear (elements); + + return j*element_size;; +} + + +/* Given an expression node, make sure it is a constant integer and return + the mpz_t value. */ + +static mpz_t * +get_mpz (gfc_expr *g) +{ + if (g->expr_type != EXPR_CONSTANT) + gfc_internal_error ("get_mpz(): Not an integer constant"); + + return &g->value.integer; +} + + +/* Given an array specification and an array reference, figure out the + array element number (zero based). Bounds and elements are guaranteed + to be constants. If something goes wrong we generate an error and + return zero. */ + +static int +element_number (gfc_array_ref *ar) +{ + mpz_t multiplier, offset, extent, l; + gfc_array_spec *as; + int b, rank; + + as = ar->as; + rank = as->rank; + mpz_init_set_ui (multiplier, 1); + mpz_init_set_ui (offset, 0); + mpz_init (extent); + mpz_init (l); + + for (b = 0; b < rank; b++) + { + if (ar->dimen_type[b] != DIMEN_ELEMENT) + gfc_internal_error ("element_number(): Bad dimension type"); + + mpz_sub (l, *get_mpz (ar->start[b]), *get_mpz (as->lower[b])); + + mpz_mul (l, l, multiplier); + mpz_add (offset, offset, l); + + mpz_sub (extent, *get_mpz (as->upper[b]), *get_mpz (as->lower[b])); + mpz_add_ui (extent, extent, 1); + + if (mpz_sgn (extent) < 0) + mpz_set_ui (extent, 0); + + mpz_mul (multiplier, multiplier, extent); + } + + b = mpz_get_ui (offset); + + mpz_clear (multiplier); + mpz_clear (offset); + mpz_clear (extent); + mpz_clear (l); + + return b; +} + + +/* Given a single element of an equivalence list, figure out the offset + from the base symbol. For simple variables or full arrays, this is + simply zero. For an array element we have to calculate the array + element number and multiply by the element size. For a substring we + have to calculate the further reference. */ + +static int +calculate_offset (gfc_expr *s) +{ + int a, element_size, offset; + gfc_typespec *element_type; + gfc_ref *reference; + + offset = 0; + element_type = &s->symtree->n.sym->ts; + + for (reference = s->ref; reference; reference = reference->next) + switch (reference->type) + { + case REF_ARRAY: + switch (reference->u.ar.type) + { + case AR_FULL: + break; + + case AR_ELEMENT: + a = element_number (&reference->u.ar); + if (element_type->type == BT_CHARACTER) + gfc_conv_const_charlen (element_type->cl); + element_size = + int_size_in_bytes (gfc_typenode_for_spec (element_type)); + offset += a * element_size; + break; + + default: + gfc_error ("bad array reference at %L", &s->where); + } + break; + case REF_SUBSTRING: + if (reference->u.ss.start != NULL) + offset += mpz_get_ui (*get_mpz (reference->u.ss.start)) - 1; + break; + default: + gfc_error ("illegal reference type at %L as EQUIVALENCE object", + &s->where); + } + return offset; +} + + +/* Add a new segment_info structure to the current eq1 is already in the + list at s1, eq2 is not. */ + +static void +new_condition (segment_info *v, gfc_equiv *eq1, gfc_equiv *eq2) +{ + int offset1, offset2; + segment_info *a; + + offset1 = calculate_offset (eq1->expr); + offset2 = calculate_offset (eq2->expr); + + a = get_segment_info (); + + a->sym = eq2->expr->symtree->n.sym; + a->offset = v->offset + offset1 - offset2; + a->length = calculate_length (eq2->expr->symtree->n.sym); + + a->next = current_segment; + current_segment = a; +} + + +/* Given two equivalence structures that are both already in the list, make + sure that this new condition is not violated, generating an error if it + is. */ + +static void +confirm_condition (segment_info *k, gfc_equiv *eq1, segment_info *e, + gfc_equiv *eq2) +{ + int offset1, offset2; + + offset1 = calculate_offset (eq1->expr); + offset2 = calculate_offset (eq2->expr); + + if (k->offset + offset1 != e->offset + offset2) + gfc_error ("inconsistent equivalence rules involving '%s' at %L and " + "'%s' at %L", k->sym->name, &k->sym->declared_at, + e->sym->name, &e->sym->declared_at); +} + + +/* At this point we have a new equivalence condition to process. If both + variables are already present, then we are confirming that the condition + holds. Otherwise we are adding a new variable to the segment list. */ + +static void +add_condition (gfc_equiv *eq1, gfc_equiv *eq2) +{ + segment_info *n, *t; + + eq1->expr->symtree->n.sym->mark = 1; + eq2->expr->symtree->n.sym->mark = 1; + + eq2->used = 1; + + n = find_segment_info (eq1->expr->symtree->n.sym); + t = find_segment_info (eq2->expr->symtree->n.sym); + + if (n == NULL && t == NULL) + abort (); + if (n != NULL && t == NULL) + new_condition (n, eq1, eq2); + if (n == NULL && t != NULL) + new_condition (t, eq2, eq1); + if (n != NULL && t != NULL) + confirm_condition (n, eq1, t, eq2); +} + + +/* Given a symbol, search through the equivalence lists for an unused + condition that involves the symbol. If a rule is found, we return + nonzero, the rule is marked as used and the eq1 and eq2 pointers point + to the rule. */ + +static int +find_equivalence (gfc_symbol *sym, gfc_equiv **eq1, gfc_equiv **eq2) +{ + gfc_equiv *c, *l; + + for (c = sym->ns->equiv; c; c = c->next) + for (l = c->eq; l; l = l->eq) + { + if (l->used) continue; + + if (c->expr->symtree->n.sym == sym || l->expr->symtree->n.sym == sym) + { + *eq1 = c; + *eq2 = l; + return 1; + } + } + return 0; +} + + +/* Function for adding symbols to current segment. Returns zero if the + segment was modified. Equivalence rules are considered to be between + the first expression in the list and each of the other expressions in + the list. Symbols are scanned multiple times because a symbol can be + equivalenced more than once. */ + +static int +add_equivalences (void) +{ + int segment_modified; + gfc_equiv *eq1, *eq2; + segment_info *f; + + segment_modified = 0; + + for (f = current_segment; f; f = f->next) + if (find_equivalence (f->sym, &eq1, &eq2)) break; + + if (f != NULL) + { + add_condition (eq1, eq2); + segment_modified = 1; + } + + return segment_modified; +} + + +/* Given a seed symbol, create a new segment consisting of that symbol + and all of the symbols equivalenced with that symbol. */ + +static void +new_segment (gfc_symbol *common_sym, gfc_symbol *sym) +{ + segment_info *v; + int length; + + current_segment = get_segment_info (); + current_segment->sym = sym; + current_segment->offset = current_offset; + length = calculate_length (sym); + current_segment->length = length; + + sym->mark = 1; + + /* Add all object directly or indirectly equivalenced with this common + variable. */ + while (add_equivalences ()); + + /* Calculate the storage size to hold the common block. */ + for (v = current_segment; v; v = v->next) + { + if (v->offset < 0) + gfc_error ("the equivalence set for '%s' cause an invalid extension " + "to COMMON '%s' at %L", + sym->name, common_sym->name, &common_sym->declared_at); + if (current_length < (v->offset + v->length)) + current_length = v->offset + v->length; + } + + /* The offset of the next common variable. */ + current_offset += length; + + /* Append the current segment to the current common. */ + v = current_segment; + while (v->next != NULL) + v = v->next; + + v->next = current_common; + current_common = current_segment; + current_segment = NULL; +} + + +/* Create a new block for each merged equivalence list. */ + +static void +finish_equivalences (gfc_namespace *ns) +{ + gfc_equiv *z, *y; + gfc_symbol *sym; + segment_info *v; + int min_offset; + + for (z = ns->equiv; z; z = z->next) + for (y= z->eq; y; y = y->eq) + { + if (y->used) continue; + sym = z->expr->symtree->n.sym; + current_length = 0; + current_segment = get_segment_info (); + current_segment->sym = sym; + current_segment->offset = 0; + current_segment->length = calculate_length (sym); + sym->mark = 1; + + /* All object directly or indrectly equivalenced with this symbol. */ + while (add_equivalences ()); + + /* Calculate the minimal offset. */ + min_offset = 0; + for (v = current_segment; v; v = v->next) + min_offset = (min_offset >= v->offset) ? v->offset : min_offset; + + /* Adjust the offset of each equivalence object, and calculate the + maximal storage size to hold them. */ + for (v = current_segment; v; v = v->next) + { + v->offset -= min_offset; + if (current_length < (v->offset + v->length)) + current_length = v->offset + v->length; + } + + current_common = current_segment; + create_common (NULL); + break; + } +} + + +/* Translate a single common block. */ + +static void +translate_common (gfc_symbol *common_sym, gfc_symbol *var_list) +{ + gfc_symbol *sym; + + current_common = NULL; + current_length = 0; + current_offset = 0; + + /* Mark bits indicate which symbols have already been placed in a + common area. */ + for (sym = var_list; sym; sym = sym->common_next) + sym->mark = 0; + + for (;;) + { + for (sym = var_list; sym; sym = sym->common_next) + if (!sym->mark) break; + + /* All symbols have been placed in a common. */ + if (sym == NULL) break; + new_segment (common_sym, sym); + } + + create_common (common_sym); +} + + +/* Work function for translating a named common block. */ + +static void +named_common (gfc_symbol *s) +{ + if (s->attr.common) + translate_common (s, s->common_head); +} + + +/* Translate the common blocks in a namespace. Unlike other variables, + these have to be created before code, because the backend_decl depends + on the rest of the common block. */ + +void +gfc_trans_common (gfc_namespace *ns) +{ + gfc_symbol *sym; + + /* Translate the blank common block. */ + if (ns->blank_common != NULL) + { + gfc_get_symbol (BLANK_COMMON_NAME, ns, &sym); + translate_common (sym, ns->blank_common); + } + + /* Translate all named common blocks. */ + gfc_traverse_ns (ns, named_common); + + /* Commit the newly created symbols for common blocks. */ + gfc_commit_symbols (); + + /* Translate local equivalence. */ + finish_equivalences (ns); +} diff --git a/gcc/fortran/trans-const.c b/gcc/fortran/trans-const.c new file mode 100644 index 00000000000..a0a72911834 --- /dev/null +++ b/gcc/fortran/trans-const.c @@ -0,0 +1,375 @@ +/* Translation of constants + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* trans-const.c -- convert constant values */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include +#include "ggc.h" +#include "toplev.h" +#include "real.h" +#include +#include +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-const.h" +#include "trans-types.h" + +/* String constants. */ +tree gfc_strconst_bounds; +tree gfc_strconst_fault; +tree gfc_strconst_wrong_return; +tree gfc_strconst_current_filename; + +tree gfc_rank_cst[GFC_MAX_DIMENSIONS + 1]; + +/* Build a constant with given type from an int_cst. */ +tree +gfc_build_const (tree type, tree intval) +{ + tree val; + tree zero; + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + val = convert (type, intval); + break; + + case REAL_TYPE: + val = build_real_from_int_cst (type, intval); + break; + + case COMPLEX_TYPE: + val = build_real_from_int_cst (TREE_TYPE (type), intval); + zero = build_real_from_int_cst (TREE_TYPE (type), integer_zero_node); + val = build_complex (type, val, zero); + break; + + default: + abort (); + } + return val; +} + +tree +gfc_build_string_const (int length, const char *s) +{ + tree str; + tree len; + + str = build_string (length, s); + len = build_int_2 (length, 0); + TREE_TYPE (str) = + build_array_type (gfc_character1_type_node, + build_range_type (gfc_strlen_type_node, + integer_one_node, len)); + return str; +} + +/* Return a string constant with the given length. Used for static + initializers. The constant will be padded to the full length. */ +tree +gfc_conv_string_init (tree length, gfc_expr * expr) +{ + char *s; + HOST_WIDE_INT len; + int slen; + tree str; + + assert (expr->expr_type == EXPR_CONSTANT); + assert (expr->ts.type == BT_CHARACTER && expr->ts.kind == 1); + assert (INTEGER_CST_P (length)); + assert (TREE_INT_CST_HIGH (length) == 0); + + len = TREE_INT_CST_LOW (length); + slen = expr->value.character.length; + assert (len >= slen); + if (len != slen) + { + s = gfc_getmem (len); + memcpy (s, expr->value.character.string, slen); + memset (&s[slen], ' ', len - slen); + str = gfc_build_string_const (len, s); + gfc_free (s); + } + else + str = gfc_build_string_const (len, expr->value.character.string); + + return str; +} + + +/* Create a tree node for the string length if it is constant. */ + +void +gfc_conv_const_charlen (gfc_charlen * cl) +{ + if (cl->backend_decl) + return; + + if (cl->length && cl->length->expr_type == EXPR_CONSTANT) + { + cl->backend_decl = gfc_conv_mpz_to_tree (cl->length->value.integer, + cl->length->ts.kind); + } +} + +void +gfc_init_constants (void) +{ + int n; + + for (n = 0; n <= GFC_MAX_DIMENSIONS; n++) + { + gfc_rank_cst[n] = build_int_2 (n, 0); + TREE_TYPE (gfc_rank_cst[n]) = gfc_array_index_type; + } + + gfc_strconst_bounds = gfc_build_string_const (21, "Array bound mismatch"); + + gfc_strconst_fault = + gfc_build_string_const (30, "Array reference out of bounds"); + + gfc_strconst_wrong_return = + gfc_build_string_const (32, "Incorrect function return value"); + + gfc_strconst_current_filename = + gfc_build_string_const (strlen (gfc_option.source) + 1, + gfc_option.source); +} + +#define BITS_PER_HOST_WIDE_INT (8 * sizeof (HOST_WIDE_INT)) +/* Converts a GMP integer into a backend tree node. */ +tree +gfc_conv_mpz_to_tree (mpz_t i, int kind) +{ + int val; + tree res; + HOST_WIDE_INT high; + unsigned HOST_WIDE_INT low; + int negate; + char buff[10]; + char *p; + char *q; + int n; + + /* TODO: could be wrong if sizeof(HOST_WIDE_INT) |= SIZEOF (int). */ + if (mpz_fits_slong_p (i)) + { + val = mpz_get_si (i); + res = build_int_2 (val, (val < 0) ? (HOST_WIDE_INT)-1 : 0); + TREE_TYPE (res) = gfc_get_int_type (kind); + return (res); + } + + n = mpz_sizeinbase (i, 16); + if (n > 8) + q = gfc_getmem (n + 2); + else + q = buff; + + low = 0; + high = 0; + p = mpz_get_str (q, 16, i); + if (p[0] == '-') + { + negate = 1; + p++; + } + else + negate = 0; + + while (*p) + { + n = *(p++); + if (n >= '0' && n <= '9') + n = n - '0'; + else if (n >= 'a' && n <= 'z') + n = n + 10 - 'a'; + else if (n >= 'A' && n <= 'Z') + n = n + 10 - 'A'; + else + abort (); + + assert (n >= 0 && n < 16); + high = (high << 4) + (low >> (BITS_PER_HOST_WIDE_INT - 4)); + low = (low << 4) + n; + } + res = build_int_2 (low, high); + TREE_TYPE (res) = gfc_get_int_type (kind); + if (negate) + res = fold (build1 (NEGATE_EXPR, TREE_TYPE (res), res)); + + if (q != buff) + gfc_free (q); + + return res; +} + +/* Converts a real constant into backend form. Uses an intermediate string + representation. */ +tree +gfc_conv_mpf_to_tree (mpf_t f, int kind) +{ + tree res; + tree type; + mp_exp_t exp; + char *p; + char *q; + int n; + int edigits; + + for (n = 0; gfc_real_kinds[n].kind != 0; n++) + { + if (gfc_real_kinds[n].kind == kind) + break; + } + assert (gfc_real_kinds[n].kind); + + assert (gfc_real_kinds[n].radix == 2); + + n = MAX (abs (gfc_real_kinds[n].min_exponent), + abs (gfc_real_kinds[n].min_exponent)); +#if 0 + edigits = 2 + (int) (log (n) / log (gfc_real_kinds[n].radix)); +#endif + edigits = 1; + while (n > 0) + { + n = n / 10; + edigits += 3; + } + + + p = mpf_get_str (NULL, &exp, 10, 0, f); + + /* We also have one minus sign, "e", "." and a null terminator. */ + q = (char *) gfc_getmem (strlen (p) + edigits + 4); + + if (p[0]) + { + if (p[0] == '-') + { + strcpy (&q[2], &p[1]); + q[0] = '-'; + q[1] = '.'; + } + else + { + strcpy (&q[1], p); + q[0] = '.'; + } + strcat (q, "e"); + sprintf (&q[strlen (q)], "%d", (int) exp); + } + else + { + strcpy (q, "0"); + } + + type = gfc_get_real_type (kind); + res = build_real (type, REAL_VALUE_ATOF (q, TYPE_MODE (type))); + gfc_free (q); + gfc_free (p); + + return res; +} + + +/* Translate any literal constant to a tree. Constants never have + pre or post chains. Character literal constants are special + special because they have a value and a length, so they cannot be + returned as a single tree. It is up to the caller to set the + length somewhere if necessary. + + Returns the translated constant, or aborts if it gets a type it + can't handle. */ + +tree +gfc_conv_constant_to_tree (gfc_expr * expr) +{ + assert (expr->expr_type == EXPR_CONSTANT); + + switch (expr->ts.type) + { + case BT_INTEGER: + return gfc_conv_mpz_to_tree (expr->value.integer, expr->ts.kind); + + case BT_REAL: + return gfc_conv_mpf_to_tree (expr->value.real, expr->ts.kind); + + case BT_LOGICAL: + return build_int_2 (expr->value.logical, 0); + + case BT_COMPLEX: + { + tree real = gfc_conv_mpf_to_tree (expr->value.complex.r, + expr->ts.kind); + tree imag = gfc_conv_mpf_to_tree (expr->value.complex.i, + expr->ts.kind); + + return build_complex (NULL_TREE, real, imag); + } + + case BT_CHARACTER: + return gfc_build_string_const (expr->value.character.length, + expr->value.character.string); + + default: + fatal_error ("gfc_conv_constant_to_tree(): invalid type: %s", + gfc_typename (&expr->ts)); + } +} + + +/* Like gfc_conv_contrant_to_tree, but for a simplified expression. + We can handle character literal constants here as well. */ + +void +gfc_conv_constant (gfc_se * se, gfc_expr * expr) +{ + assert (expr->expr_type == EXPR_CONSTANT); + + if (se->ss != NULL) + { + assert (se->ss != gfc_ss_terminator); + assert (se->ss->type == GFC_SS_SCALAR); + assert (se->ss->expr == expr); + + se->expr = se->ss->data.scalar.expr; + se->string_length = se->ss->data.scalar.string_length; + gfc_advance_se_ss_chain (se); + return; + } + + /* Translate the constant and put it in the simplifier structure. */ + se->expr = gfc_conv_constant_to_tree (expr); + + /* If this is a CHARACTER string, set it's length in the simplifier + structure, too. */ + if (expr->ts.type == BT_CHARACTER) + se->string_length = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (se->expr))); +} diff --git a/gcc/fortran/trans-const.h b/gcc/fortran/trans-const.h new file mode 100644 index 00000000000..a500ddf8f45 --- /dev/null +++ b/gcc/fortran/trans-const.h @@ -0,0 +1,59 @@ +/* Header for code constant translation functions + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Returns an INT_CST. */ +tree gfc_conv_mpz_to_tree (mpz_t, int); + +/* Returns a REAL_CST. */ +tree gfc_conv_mpf_to_tree (mpf_t, int); + +/* Build a tree for a constant. Must be an EXPR_CONSTANT gfc_expr. + For CHARACTER literal constants, the caller still has to set the + string length as a separate operation. */ +tree gfc_conv_constant_to_tree (gfc_expr *); + +/* Like gfc_conv_noncharacter_constant, but works on simplified expression + structures. Also sets the length of CHARACTER strings in the gfc_se. */ +void gfc_conv_constant (gfc_se *, gfc_expr *); + +tree gfc_build_string_const (int, const char *); + +/* Translate a string constant for a static initializer. */ +tree gfc_conv_string_init (tree, gfc_expr *); + +/* Create a tree node for the string length if it is constant. */ +void gfc_conv_const_charlen (gfc_charlen *); + +/* Initialise the nodes for constants. */ +void gfc_init_constants (void); + +/* Build a constant with given type from an int_cst. */ +tree gfc_build_const (tree, tree); + +/* String constants. */ +extern GTY(()) tree gfc_strconst_current_filename; +extern GTY(()) tree gfc_strconst_bounds; +extern GTY(()) tree gfc_strconst_fault; +extern GTY(()) tree gfc_strconst_wrong_return; + +/* Integer constants 0..GFC_MAX_DIMENSIONS. */ +extern GTY(()) tree gfc_rank_cst[GFC_MAX_DIMENSIONS + 1]; +#define gfc_index_zero_node gfc_rank_cst[0] diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c new file mode 100644 index 00000000000..79e8cf6927e --- /dev/null +++ b/gcc/fortran/trans-decl.c @@ -0,0 +1,2137 @@ +/* Backend function setup + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* trans-decl.c -- Handling of backend function and variable decls, etc */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-dump.h" +#include "tree-simple.h" +#include "ggc.h" +#include "toplev.h" +#include "tm.h" +#include "target.h" +#include "function.h" +#include "errors.h" +#include "flags.h" +#include "cgraph.h" +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-types.h" +#include "trans-array.h" +#include "trans-const.h" +/* Only for gfc_trans_code. Shouldn't need to include this. */ +#include "trans-stmt.h" + +#define MAX_LABEL_VALUE 99999 + + +/* Holds the result of the function if no result variable specified. */ + +static GTY(()) tree current_fake_result_decl; + +static GTY(()) tree current_function_return_label; + + +/* Holds the variable DECLs for the current function. */ + +static GTY(()) tree saved_function_decls = NULL_TREE; +static GTY(()) tree saved_parent_function_decls = NULL_TREE; + + +/* The namespace of the module we're currently generating. Only used while + outputting decls for module variables. Do not rely on this being set. */ + +static gfc_namespace *module_namespace; + + +/* List of static constructor functions. */ + +tree gfc_static_ctors; + + +/* Function declarations for builtin library functions. */ + +tree gfor_fndecl_internal_malloc; +tree gfor_fndecl_internal_malloc64; +tree gfor_fndecl_internal_free; +tree gfor_fndecl_allocate; +tree gfor_fndecl_allocate64; +tree gfor_fndecl_deallocate; +tree gfor_fndecl_pause_numeric; +tree gfor_fndecl_pause_string; +tree gfor_fndecl_stop_numeric; +tree gfor_fndecl_stop_string; +tree gfor_fndecl_select_string; +tree gfor_fndecl_runtime_error; +tree gfor_fndecl_in_pack; +tree gfor_fndecl_in_unpack; +tree gfor_fndecl_associated; + + +/* Math functions. Many other math functions are handled in + trans-intrinsic.c. */ + +tree gfor_fndecl_math_powf; +tree gfor_fndecl_math_pow; +tree gfor_fndecl_math_cpowf; +tree gfor_fndecl_math_cpow; +tree gfor_fndecl_math_cabsf; +tree gfor_fndecl_math_cabs; +tree gfor_fndecl_math_sign4; +tree gfor_fndecl_math_sign8; +tree gfor_fndecl_math_ishftc4; +tree gfor_fndecl_math_ishftc8; +tree gfor_fndecl_math_exponent4; +tree gfor_fndecl_math_exponent8; + + +/* String functions. */ + +tree gfor_fndecl_copy_string; +tree gfor_fndecl_compare_string; +tree gfor_fndecl_concat_string; +tree gfor_fndecl_string_len_trim; +tree gfor_fndecl_string_index; +tree gfor_fndecl_string_scan; +tree gfor_fndecl_string_verify; +tree gfor_fndecl_string_trim; +tree gfor_fndecl_string_repeat; +tree gfor_fndecl_adjustl; +tree gfor_fndecl_adjustr; + + +/* Other misc. runtime library functions. */ + +tree gfor_fndecl_size0; +tree gfor_fndecl_size1; + +/* Intrinsic functions implemented in FORTRAN. */ +tree gfor_fndecl_si_kind; +tree gfor_fndecl_sr_kind; + + +static void +gfc_add_decl_to_parent_function (tree decl) +{ + assert (decl); + DECL_CONTEXT (decl) = DECL_CONTEXT (current_function_decl); + DECL_NONLOCAL (decl) = 1; + TREE_CHAIN (decl) = saved_parent_function_decls; + saved_parent_function_decls = decl; +} + +void +gfc_add_decl_to_function (tree decl) +{ + assert (decl); + TREE_USED (decl) = 1; + DECL_CONTEXT (decl) = current_function_decl; + TREE_CHAIN (decl) = saved_function_decls; + saved_function_decls = decl; +} + + +/* Build a backend label declaration. + Set TREE_USED for named lables. For artificial labels it's up to the + caller to mark the label as used. */ + +tree +gfc_build_label_decl (tree label_id) +{ + /* 2^32 temporaries should be enough. */ + static unsigned int tmp_num = 1; + tree label_decl; + char *label_name; + + if (label_id == NULL_TREE) + { + /* Build an internal label name. */ + ASM_FORMAT_PRIVATE_NAME (label_name, "L", tmp_num++); + label_id = get_identifier (label_name); + } + else + label_name = NULL; + + /* Build the LABEL_DECL node. Labels have no type. */ + label_decl = build_decl (LABEL_DECL, label_id, void_type_node); + DECL_CONTEXT (label_decl) = current_function_decl; + DECL_MODE (label_decl) = VOIDmode; + + if (label_name) + { + DECL_ARTIFICIAL (label_decl) = 1; + } + else + { + /* We always define the label as used, even if the original source + file never references the label. We don't want all kinds of + spurious warnings for old-style Fortran code with too many + labels. */ + TREE_USED (label_decl) = 1; + } + + return label_decl; +} + + +/* Returns the return label for the current function. */ + +tree +gfc_get_return_label (void) +{ + char name[GFC_MAX_SYMBOL_LEN + 10]; + + if (current_function_return_label) + return current_function_return_label; + + sprintf (name, "__return_%s", + IDENTIFIER_POINTER (DECL_NAME (current_function_decl))); + + current_function_return_label = + gfc_build_label_decl (get_identifier (name)); + + DECL_ARTIFICIAL (current_function_return_label) = 1; + + return current_function_return_label; +} + + +/* Return the backend label declaration for a given label structure, + or create it if it doesn't exist yet. */ + +tree +gfc_get_label_decl (gfc_st_label * lp) +{ + + if (lp->backend_decl) + return lp->backend_decl; + else + { + char label_name[GFC_MAX_SYMBOL_LEN + 1]; + tree label_decl; + + /* Validate the label declaration from the front end. */ + assert (lp != NULL && lp->value <= MAX_LABEL_VALUE); + + /* Build a mangled name for the label. */ + sprintf (label_name, "__label_%.6d", lp->value); + + /* Build the LABEL_DECL node. */ + label_decl = gfc_build_label_decl (get_identifier (label_name)); + + /* Tell the debugger where the label came from. */ + if (lp->value <= MAX_LABEL_VALUE) /* An internal label */ + { + DECL_SOURCE_LINE (label_decl) = lp->where.line; + DECL_SOURCE_FILE (label_decl) = lp->where.file->filename; + } + else + DECL_ARTIFICIAL (label_decl) = 1; + + /* Store the label in the label list and return the LABEL_DECL. */ + lp->backend_decl = label_decl; + return label_decl; + } +} + + +/* Convert a gfc_symbol to an identifier of the same name. */ + +static tree +gfc_sym_identifier (gfc_symbol * sym) +{ + return (get_identifier (sym->name)); +} + + +/* Construct mangled name from symbol name. */ + +static tree +gfc_sym_mangled_identifier (gfc_symbol * sym) +{ + char name[GFC_MAX_MANGLED_SYMBOL_LEN + 1]; + + if (sym->module[0] == 0) + return gfc_sym_identifier (sym); + else + { + snprintf (name, sizeof name, "__%s__%s", sym->module, sym->name); + return get_identifier (name); + } +} + + +/* Construct mangled function name from symbol name. */ + +static tree +gfc_sym_mangled_function_id (gfc_symbol * sym) +{ + int has_underscore; + char name[GFC_MAX_MANGLED_SYMBOL_LEN + 1]; + + if (sym->module[0] == 0 || sym->attr.proc == PROC_EXTERNAL + || (sym->module[0] != 0 && sym->attr.if_source == IFSRC_IFBODY)) + { + if (strcmp (sym->name, "MAIN__") == 0 + || sym->attr.proc == PROC_INTRINSIC) + return get_identifier (sym->name); + + if (gfc_option.flag_underscoring) + { + has_underscore = strchr (sym->name, '_') != 0; + if (gfc_option.flag_second_underscore && has_underscore) + snprintf (name, sizeof name, "%s__", sym->name); + else + snprintf (name, sizeof name, "%s_", sym->name); + return get_identifier (name); + } + else + return get_identifier (sym->name); + } + else + { + snprintf (name, sizeof name, "__%s__%s", sym->module, sym->name); + return get_identifier (name); + } +} + + +/* Finish processing of a declaration and install its initial value. */ + +static void +gfc_finish_decl (tree decl, tree init) +{ + if (TREE_CODE (decl) == PARM_DECL) + assert (init == NULL_TREE); + /* Remember that PARM_DECL doesn't have a DECL_INITIAL field per se + -- it overlaps DECL_ARG_TYPE. */ + else if (init == NULL_TREE) + assert (DECL_INITIAL (decl) == NULL_TREE); + else + assert (DECL_INITIAL (decl) == error_mark_node); + + if (init != NULL_TREE) + { + if (TREE_CODE (decl) != TYPE_DECL) + DECL_INITIAL (decl) = init; + else + { + /* typedef foo = bar; store the type of bar as the type of foo. */ + TREE_TYPE (decl) = TREE_TYPE (init); + DECL_INITIAL (decl) = init = 0; + } + } + + if (TREE_CODE (decl) == VAR_DECL) + { + if (DECL_SIZE (decl) == NULL_TREE + && TYPE_SIZE (TREE_TYPE (decl)) != NULL_TREE) + layout_decl (decl, 0); + + /* A static variable with an incomplete type is an error if it is + initialized. Also if it is not file scope. Otherwise, let it + through, but if it is not `extern' then it may cause an error + message later. */ + /* An automatic variable with an incomplete type is an error. */ + if (DECL_SIZE (decl) == NULL_TREE + && (TREE_STATIC (decl) ? (DECL_INITIAL (decl) != 0 + || DECL_CONTEXT (decl) != 0) + : !DECL_EXTERNAL (decl))) + { + gfc_fatal_error ("storage size not known"); + } + + if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl)) + && (DECL_SIZE (decl) != 0) + && (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)) + { + gfc_fatal_error ("storage size not constant"); + } + } + +} + + +/* Apply symbol attributes to a variable, and add it to the function scope. */ + +static void +gfc_finish_var_decl (tree decl, gfc_symbol * sym) +{ + /* TREE_ADDRESSABLE means the address of this variable is acualy needed. + This is the equivalent of the TARGET variables. + We also need to set this if the variable is passed by reference in a + CALL statement. */ + if (sym->attr.target) + TREE_ADDRESSABLE (decl) = 1; + /* If it wasn't used we wouldn't be getting it. */ + TREE_USED (decl) = 1; + + /* Chain this decl to the pending declarations. Don't do pushdecl() + because this would add them to the current scope rather than the + function scope. */ + if (current_function_decl != NULL_TREE) + { + if (sym->ns->proc_name->backend_decl == current_function_decl) + gfc_add_decl_to_function (decl); + else + gfc_add_decl_to_parent_function (decl); + } + + /* If a variable is USE associated, it's always external. */ + if (sym->attr.use_assoc) + { + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + } + else if (sym->module[0] && !sym->attr.result) + { + /* TODO: Don't set sym->module for result variables. */ + assert (current_function_decl == NULL_TREE); + /* This is the declaration of a module variable. */ + TREE_PUBLIC (decl) = 1; + TREE_STATIC (decl) = 1; + } + + if ((sym->attr.save || sym->attr.data || sym->value) + && !sym->attr.use_assoc) + TREE_STATIC (decl) = 1; + + /* Keep variables larger than max-stack-var-size off stack. */ + if (!sym->ns->proc_name->attr.recursive + && INTEGER_CST_P (DECL_SIZE_UNIT (decl)) + && !gfc_can_put_var_on_stack (DECL_SIZE_UNIT (decl))) + TREE_STATIC (decl) = 1; +} + + +/* Allocate the lang-specific part of a decl. */ + +void +gfc_allocate_lang_decl (tree decl) +{ + DECL_LANG_SPECIFIC (decl) = (struct lang_decl *) + ggc_alloc_cleared (sizeof (struct lang_decl)); +} + +/* Remember a symbol to generate initialization/cleanup code at function + entry/exit. */ + +static void +gfc_defer_symbol_init (gfc_symbol * sym) +{ + gfc_symbol *p; + gfc_symbol *last; + gfc_symbol *head; + + /* Don't add a symbol twice. */ + if (sym->tlink) + return; + + last = head = sym->ns->proc_name; + p = last->tlink; + + /* Make sure that setup code for dummy variables which are used in the + setup of other variables is generated first. */ + if (sym->attr.dummy) + { + /* Find the first dummy arg seen after us, or the first non-dummy arg. + This is a circular list, so don't go past the head. */ + while (p != head + && (!p->attr.dummy || p->dummy_order > sym->dummy_order)) + { + last = p; + p = p->tlink; + } + } + /* Insert in between last and p. */ + last->tlink = sym; + sym->tlink = p; +} + + +/* Create an array index type variable with function scope. */ + +static tree +create_index_var (const char * pfx, int nest) +{ + tree decl; + + decl = gfc_create_var_np (gfc_array_index_type, pfx); + if (nest) + gfc_add_decl_to_parent_function (decl); + else + gfc_add_decl_to_function (decl); + return decl; +} + + +/* Create variables to hold all the non-constant bits of info for a + descriptorless array. Remember these in the lang-specific part of the + type. */ + +static void +gfc_build_qualified_array (tree decl, gfc_symbol * sym) +{ + tree type; + int dim; + int nest; + + type = TREE_TYPE (decl); + + /* We just use the descriptor, if there is one. */ + if (GFC_DESCRIPTOR_TYPE_P (type)) + return; + + assert (GFC_ARRAY_TYPE_P (type)); + nest = (sym->ns->proc_name->backend_decl != current_function_decl) + && !sym->attr.contained; + + for (dim = 0; dim < GFC_TYPE_ARRAY_RANK (type); dim++) + { + if (GFC_TYPE_ARRAY_LBOUND (type, dim) == NULL_TREE) + GFC_TYPE_ARRAY_LBOUND (type, dim) = create_index_var ("lbound", nest); + /* Don't try to use the unkown bound for assumed shape arrays. */ + if (GFC_TYPE_ARRAY_UBOUND (type, dim) == NULL_TREE + && (sym->as->type != AS_ASSUMED_SIZE + || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) + GFC_TYPE_ARRAY_UBOUND (type, dim) = create_index_var ("ubound", nest); + + if (GFC_TYPE_ARRAY_STRIDE (type, dim) == NULL_TREE) + GFC_TYPE_ARRAY_STRIDE (type, dim) = create_index_var ("stride", nest); + } + if (GFC_TYPE_ARRAY_OFFSET (type) == NULL_TREE) + { + GFC_TYPE_ARRAY_OFFSET (type) = gfc_create_var_np (gfc_array_index_type, + "offset"); + if (nest) + gfc_add_decl_to_parent_function (GFC_TYPE_ARRAY_OFFSET (type)); + else + gfc_add_decl_to_function (GFC_TYPE_ARRAY_OFFSET (type)); + } +} + + +/* For some dummy arguments we don't use the actual argument directly. + Instead we create a local decl and use that. This allows us to preform + initialization, and construct full type information. */ + +static tree +gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) +{ + tree decl; + tree type; + gfc_array_spec *as; + char *name; + int packed; + int n; + bool known_size; + + if (sym->attr.pointer || sym->attr.allocatable) + return dummy; + + /* Add to list of variables if not a fake result variable. */ + if (sym->attr.result || sym->attr.dummy) + gfc_defer_symbol_init (sym); + + type = TREE_TYPE (dummy); + assert (TREE_CODE (dummy) == PARM_DECL + && POINTER_TYPE_P (type)); + + /* Do we know the element size. */ + known_size = sym->ts.type != BT_CHARACTER + || INTEGER_CST_P (sym->ts.cl->backend_decl); + + if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))) + { + /* For descriptorless arrays with known element size the actual + argument is sufficient. */ + assert (GFC_ARRAY_TYPE_P (type)); + gfc_build_qualified_array (dummy, sym); + return dummy; + } + + type = TREE_TYPE (type); + if (GFC_DESCRIPTOR_TYPE_P (type)) + { + /* Create a decriptorless array pointer. */ + as = sym->as; + packed = 0; + if (!gfc_option.flag_repack_arrays) + { + if (as->type == AS_ASSUMED_SIZE) + packed = 2; + } + else + { + if (as->type == AS_EXPLICIT) + { + packed = 2; + for (n = 0; n < as->rank; n++) + { + if (!(as->upper[n] + && as->lower[n] + && as->upper[n]->expr_type == EXPR_CONSTANT + && as->lower[n]->expr_type == EXPR_CONSTANT)) + packed = 1; + } + } + else + packed = 1; + } + + type = gfc_typenode_for_spec (&sym->ts); + type = gfc_get_nodesc_array_type (type, sym->as, packed); + } + else + { + /* We now have an expression for the element size, so create a fully + qualified type. Reset sym->backend decl or this will just return the + old type. */ + sym->backend_decl = NULL_TREE; + type = gfc_sym_type (sym); + packed = 2; + } + + ASM_FORMAT_PRIVATE_NAME (name, IDENTIFIER_POINTER (DECL_NAME (dummy)), 0); + decl = build_decl (VAR_DECL, get_identifier (name), type); + + DECL_ARTIFICIAL (decl) = 1; + TREE_PUBLIC (decl) = 0; + TREE_STATIC (decl) = 0; + DECL_EXTERNAL (decl) = 0; + + /* We should never get deferred shape arrays here. We used to because of + frontend bugs. */ + assert (sym->as->type != AS_DEFERRED); + + switch (packed) + { + case 1: + GFC_DECL_PARTIAL_PACKED_ARRAY (decl) = 1; + break; + + case 2: + GFC_DECL_PACKED_ARRAY (decl) = 1; + break; + } + + gfc_build_qualified_array (decl, sym); + + if (DECL_LANG_SPECIFIC (dummy)) + DECL_LANG_SPECIFIC (decl) = DECL_LANG_SPECIFIC (dummy); + else + gfc_allocate_lang_decl (decl); + + GFC_DECL_SAVED_DESCRIPTOR (decl) = dummy; + + if (sym->ns->proc_name->backend_decl == current_function_decl + || sym->attr.contained) + gfc_add_decl_to_function (decl); + else + gfc_add_decl_to_parent_function (decl); + + return decl; +} + + +/* Return a constant or a variable to use as a string length. Does not + add the decl to the current scope. */ + +static tree +gfc_create_string_length (gfc_symbol * sym) +{ + tree length; + + assert (sym->ts.cl); + gfc_conv_const_charlen (sym->ts.cl); + + if (sym->ts.cl->backend_decl == NULL_TREE) + { + char name[GFC_MAX_MANGLED_SYMBOL_LEN + 2]; + + /* Also prefix the mangled name. */ + strcpy (&name[1], sym->name); + name[0] = '.'; + length = build_decl (VAR_DECL, get_identifier (name), + gfc_strlen_type_node); + DECL_ARTIFICIAL (length) = 1; + TREE_USED (length) = 1; + gfc_defer_symbol_init (sym); + sym->ts.cl->backend_decl = length; + } + + return sym->ts.cl->backend_decl; +} + + +/* Return the decl for a gfc_symbol, create it if it doesn't already + exist. */ + +tree +gfc_get_symbol_decl (gfc_symbol * sym) +{ + tree decl; + tree length = NULL_TREE; + gfc_se se; + int byref; + + assert (sym->attr.referenced); + + if (sym->ns && sym->ns->proc_name->attr.function) + byref = gfc_return_by_reference (sym->ns->proc_name); + else + byref = 0; + + if ((sym->attr.dummy && ! sym->attr.function) || (sym->attr.result && byref)) + { + /* Return via extra parameter. */ + if (sym->attr.result && byref + && !sym->backend_decl) + { + sym->backend_decl = + DECL_ARGUMENTS (sym->ns->proc_name->backend_decl); + } + + /* Dummy variables should already have been created. */ + assert (sym->backend_decl); + + /* Create a character length variable. */ + if (sym->ts.type == BT_CHARACTER) + { + if (sym->ts.cl->backend_decl == NULL_TREE) + { + length = gfc_create_string_length (sym); + if (TREE_CODE (length) != INTEGER_CST) + { + gfc_finish_var_decl (length, sym); + gfc_defer_symbol_init (sym); + } + } + } + + /* Use a copy of the descriptor for dummy arrays. */ + if (sym->attr.dimension && !TREE_USED (sym->backend_decl)) + { + sym->backend_decl = + gfc_build_dummy_array_decl (sym, sym->backend_decl); + } + + TREE_USED (sym->backend_decl) = 1; + return sym->backend_decl; + } + + if (sym->backend_decl) + return sym->backend_decl; + + if (sym->attr.entry) + gfc_todo_error ("alternate entry"); + + /* Catch function declarations. Only used for actual parameters. */ + if (sym->attr.flavor == FL_PROCEDURE) + { + decl = gfc_get_extern_function_decl (sym); + return decl; + } + + if (sym->attr.intrinsic) + internal_error ("intrinsic variable which isn't a procedure"); + + /* Create string length decl first so that they can be used in the + type declaration. */ + if (sym->ts.type == BT_CHARACTER) + length = gfc_create_string_length (sym); + + /* Create the decl for the variable. */ + decl = build_decl (VAR_DECL, gfc_sym_identifier (sym), gfc_sym_type (sym)); + + /* Symbols from modules have its assembler name should be mangled. + This is done here rather than in gfc_finish_var_decl because it + is different for string length variables. */ + if (sym->module[0]) + SET_DECL_ASSEMBLER_NAME (decl, gfc_sym_mangled_identifier (sym)); + + if (sym->attr.dimension) + { + /* Create variables to hold the non-constant bits of array info. */ + gfc_build_qualified_array (decl, sym); + + /* Remember this variable for allocation/cleanup. */ + gfc_defer_symbol_init (sym); + + if ((sym->attr.allocatable || !sym->attr.dummy) && !sym->attr.pointer) + GFC_DECL_PACKED_ARRAY (decl) = 1; + } + + gfc_finish_var_decl (decl, sym); + + if (sym->attr.assign) + { + gfc_allocate_lang_decl (decl); + GFC_DECL_ASSIGN (decl) = 1; + length = gfc_create_var (gfc_strlen_type_node, sym->name); + GFC_DECL_STRING_LEN (decl) = length; + GFC_DECL_ASSIGN_ADDR (decl) = gfc_create_var (pvoid_type_node, sym->name); + /* TODO: Need to check we don't change TREE_STATIC (decl) later. */ + TREE_STATIC (length) = TREE_STATIC (decl); + /* STRING_LENGTH is also used as flag. Less than -1 means that + ASSIGN_ADDR can not be used. Equal -1 means that ASSIGN_ADDR is the + target label's address. Other value is the length of format string + and ASSIGN_ADDR is the address of format string. */ + DECL_INITIAL (length) = build_int_2 (-2, -1); + } + + /* TODO: Initialization of pointer variables. */ + switch (sym->ts.type) + { + case BT_CHARACTER: + /* Character variables need special handling. */ + gfc_allocate_lang_decl (decl); + + if (TREE_CODE (length) == INTEGER_CST) + { + /* Static initializer for string scalars. + Initialization of string arrays is handled elsewhere. */ + if (sym->value && sym->attr.dimension == 0) + { + assert (TREE_STATIC (decl)); + if (sym->attr.pointer) + gfc_todo_error ("initialization of character pointers"); + DECL_INITIAL (decl) = gfc_conv_string_init (length, sym->value); + } + } + else + { + char name[GFC_MAX_MANGLED_SYMBOL_LEN + 2]; + + if (sym->module[0]) + { + /* Also prefix the mangled name for symbols from modules. */ + strcpy (&name[1], sym->name); + name[0] = '.'; + strcpy (&name[1], + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (length))); + SET_DECL_ASSEMBLER_NAME (decl, get_identifier (name)); + } + gfc_finish_var_decl (length, sym); + assert (!sym->value); + } + break; + + case BT_DERIVED: + if (sym->value && ! (sym->attr.use_assoc || sym->attr.dimension)) + { + gfc_init_se (&se, NULL); + gfc_conv_structure (&se, sym->value, 1); + DECL_INITIAL (decl) = se.expr; + } + break; + + default: + /* Static initializers for SAVEd variables. Arrays have already been + remembered. Module variables are initialized when the module is + loaded. */ + if (sym->value && ! (sym->attr.use_assoc || sym->attr.dimension)) + { + assert (TREE_STATIC (decl)); + gfc_init_se (&se, NULL); + gfc_conv_constant (&se, sym->value); + DECL_INITIAL (decl) = se.expr; + } + break; + } + sym->backend_decl = decl; + + return decl; +} + + +/* Get a basic decl for an external function. */ + +tree +gfc_get_extern_function_decl (gfc_symbol * sym) +{ + tree type; + tree fndecl; + gfc_expr e; + gfc_intrinsic_sym *isym; + gfc_expr argexpr; + char s[GFC_MAX_SYMBOL_LEN]; + tree name; + tree mangled_name; + + if (sym->backend_decl) + return sym->backend_decl; + + if (sym->attr.intrinsic) + { + /* Call the resolution function to get the actual name. This is + a nasty hack which relies on the resolution functions only looking + at the first argument. We pass NULL for the second argument + otherwise things like AINT get confused. */ + isym = gfc_find_function (sym->name); + assert (isym->resolve.f0 != NULL); + + memset (&e, 0, sizeof (e)); + e.expr_type = EXPR_FUNCTION; + + memset (&argexpr, 0, sizeof (argexpr)); + assert (isym->formal); + argexpr.ts = isym->formal->ts; + + if (isym->formal->next == NULL) + isym->resolve.f1 (&e, &argexpr); + else + { + /* All specific intrinsics take one or two arguments. */ + assert (isym->formal->next->next == NULL); + isym->resolve.f2 (&e, &argexpr, NULL); + } + sprintf (s, "specific%s", e.value.function.name); + name = get_identifier (s); + mangled_name = name; + } + else + { + name = gfc_sym_identifier (sym); + mangled_name = gfc_sym_mangled_function_id (sym); + } + + type = gfc_get_function_type (sym); + fndecl = build_decl (FUNCTION_DECL, name, type); + + SET_DECL_ASSEMBLER_NAME (fndecl, mangled_name); + /* If the return type is a pointer, avoid alias issues by setting + DECL_IS_MALLOC to nonzero. This means that the function should be + treated as if it were a malloc, meaning it returns a pointer that + is not an alias. */ + if (POINTER_TYPE_P (type)) + DECL_IS_MALLOC (fndecl) = 1; + + /* Set the context of this decl. */ + if (0 && sym->ns && sym->ns->proc_name) + { + /* TODO: Add external decls to the appropriate scope. */ + DECL_CONTEXT (fndecl) = sym->ns->proc_name->backend_decl; + } + else + { + /* Global declaration, eg. intrinsic subroutine. */ + DECL_CONTEXT (fndecl) = NULL_TREE; + } + + DECL_EXTERNAL (fndecl) = 1; + + /* This specifies if a function is globaly addressable, ie. it is + the opposite of declaring static in C. */ + TREE_PUBLIC (fndecl) = 1; + + /* Set attributes for PURE functions. A call to PURE function in the + Fortran 95 sense is both pure and without side effects in the C + sense. */ + if (sym->attr.pure || sym->attr.elemental) + { + DECL_IS_PURE (fndecl) = 1; +/* TODO: check if pure/elemental procedures can have INTENT(OUT) parameters. + TREE_SIDE_EFFECTS (fndecl) = 0;*/ + } + + sym->backend_decl = fndecl; + + if (DECL_CONTEXT (fndecl) == NULL_TREE) + pushdecl_top_level (fndecl); + + return fndecl; +} + + +/* Create a declaration for a procedure. For external functions (in the C + sense) use gfc_get_extern_function_decl. */ + +void +gfc_build_function_decl (gfc_symbol * sym) +{ + tree fndecl, type, result_decl, typelist, arglist; + tree length; + symbol_attribute attr; + gfc_formal_arglist *f; + + assert (!sym->backend_decl); + assert (!sym->attr.external); + + /* Allow only one nesting level. Allow public declarations. */ + assert (current_function_decl == NULL_TREE + || DECL_CONTEXT (current_function_decl) == NULL_TREE); + + type = gfc_get_function_type (sym); + fndecl = build_decl (FUNCTION_DECL, gfc_sym_identifier (sym), type); + + /* Perform name mangling if this is a top level or module procedure. */ + if (current_function_decl == NULL_TREE) + SET_DECL_ASSEMBLER_NAME (fndecl, gfc_sym_mangled_function_id (sym)); + + /* Figure out the return type of the declared function, and build a + RESULT_DECL for it. If this is subroutine with alternate + returns, build a RESULT_DECL for it. */ + attr = sym->attr; + + result_decl = NULL_TREE; + /* TODO: Shouldn't this just be TREE_TYPE (TREE_TYPE (fndecl)). */ + if (attr.function) + { + if (gfc_return_by_reference (sym)) + type = void_type_node; + else + { + if (sym->result != sym) + result_decl = gfc_sym_identifier (sym->result); + + type = TREE_TYPE (TREE_TYPE (fndecl)); + } + } + else + { + /* Look for alternate return placeholders. */ + int has_alternate_returns = 0; + for (f = sym->formal; f; f = f->next) + { + if (f->sym == NULL) + { + has_alternate_returns = 1; + break; + } + } + + if (has_alternate_returns) + type = integer_type_node; + else + type = void_type_node; + } + + result_decl = build_decl (RESULT_DECL, result_decl, type); + DECL_CONTEXT (result_decl) = fndecl; + DECL_RESULT (fndecl) = result_decl; + + /* Don't call layout_decl for a RESULT_DECL. + layout_decl (result_decl, 0); */ + + /* If the return type is a pointer, avoid alias issues by setting + DECL_IS_MALLOC to nonzero. This means that the function should be + treated as if it were a malloc, meaning it returns a pointer that + is not an alias. */ + if (POINTER_TYPE_P (type)) + DECL_IS_MALLOC (fndecl) = 1; + + /* Set up all attributes for the function. */ + DECL_CONTEXT (fndecl) = current_function_decl; + DECL_EXTERNAL (fndecl) = 0; + + /* This specifies if a function is globaly addressable, ie. it is + the opposite of decalring static in C. */ + if (DECL_CONTEXT (fndecl) == NULL_TREE || attr.external) + TREE_PUBLIC (fndecl) = 1; + + /* TREE_STATIC means the function body is defined here. */ + if (!attr.external) + TREE_STATIC (fndecl) = 1; + + /* Set attributes for PURE functions. A call to PURE function in the + Fortran 95 sense is both pure and without side effects in the C + sense. */ + if (attr.pure || attr.elemental) + { + DECL_IS_PURE (fndecl) = 1; + TREE_SIDE_EFFECTS (fndecl) = 0; + } + + /* Layout the function declaration and put it in the binding level + of the current function. */ + if (!attr.external) + { + tree parm; + + pushdecl (fndecl); + /* Build formal argument list. Make sure that their TREE_CONTEXT is + the new FUNCTION_DECL node. */ + current_function_decl = fndecl; + arglist = NULL_TREE; + typelist = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + if (gfc_return_by_reference (sym)) + { + type = TREE_VALUE (typelist); + parm = build_decl (PARM_DECL, get_identifier ("__result"), type); + + DECL_CONTEXT (parm) = fndecl; + DECL_ARG_TYPE (parm) = type; + TREE_READONLY (parm) = 1; + gfc_finish_decl (parm, NULL_TREE); + + arglist = chainon (arglist, parm); + typelist = TREE_CHAIN (typelist); + + if (sym->ts.type == BT_CHARACTER) + { + gfc_allocate_lang_decl (parm); + + /* Length of character result */ + type = TREE_VALUE (typelist); + assert (type == gfc_strlen_type_node); + + length = build_decl (PARM_DECL, + get_identifier (".__result"), + type); + if (!sym->ts.cl->length) + { + sym->ts.cl->backend_decl = length; + TREE_USED (length) = 1; + } + assert (TREE_CODE (length) == PARM_DECL); + arglist = chainon (arglist, length); + typelist = TREE_CHAIN (typelist); + DECL_CONTEXT (length) = fndecl; + DECL_ARG_TYPE (length) = type; + TREE_READONLY (length) = 1; + gfc_finish_decl (length, NULL_TREE); + } + } + + for (f = sym->formal; f; f = f->next) + { + if (f->sym != NULL) /* ignore alternate returns. */ + { + length = NULL_TREE; + + type = TREE_VALUE (typelist); + + /* Build a the argument declaration. */ + parm = build_decl (PARM_DECL, + gfc_sym_identifier (f->sym), type); + + /* Fill in arg stuff. */ + DECL_CONTEXT (parm) = fndecl; + DECL_ARG_TYPE (parm) = type; + DECL_ARG_TYPE_AS_WRITTEN (parm) = type; + /* All implementation args are read-only. */ + TREE_READONLY (parm) = 1; + + gfc_finish_decl (parm, NULL_TREE); + + f->sym->backend_decl = parm; + + arglist = chainon (arglist, parm); + typelist = TREE_CHAIN (typelist); + } + } + + /* Add the hidden string length parameters. */ + parm = arglist; + for (f = sym->formal; f; f = f->next) + { + char name[GFC_MAX_SYMBOL_LEN + 2]; + /* Ignore alternate returns. */ + if (f->sym == NULL) + continue; + + if (f->sym->ts.type != BT_CHARACTER) + continue; + + parm = f->sym->backend_decl; + type = TREE_VALUE (typelist); + assert (type == gfc_strlen_type_node); + + strcpy (&name[1], f->sym->name); + name[0] = '_'; + length = build_decl (PARM_DECL, get_identifier (name), type); + + arglist = chainon (arglist, length); + DECL_CONTEXT (length) = fndecl; + DECL_ARG_TYPE (length) = type; + TREE_READONLY (length) = 1; + gfc_finish_decl (length, NULL_TREE); + + /* TODO: Check string lengths when -fbounds-check. */ + + /* Use the passed value for assumed length variables. */ + if (!f->sym->ts.cl->length) + { + TREE_USED (length) = 1; + f->sym->ts.cl->backend_decl = length; + } + + parm = TREE_CHAIN (parm); + typelist = TREE_CHAIN (typelist); + } + + assert (TREE_VALUE (typelist) == void_type_node); + DECL_ARGUMENTS (fndecl) = arglist; + + /* Restore the old context. */ + current_function_decl = DECL_CONTEXT (fndecl); + } + sym->backend_decl = fndecl; +} + + +/* Return the decl used to hold the function return value. */ + +tree +gfc_get_fake_result_decl (gfc_symbol * sym) +{ + tree decl; + tree length; + + char name[GFC_MAX_SYMBOL_LEN + 10]; + + if (current_fake_result_decl != NULL_TREE) + return current_fake_result_decl; + + /* Only when gfc_get_fake_result_decl is called by gfc_trans_return, + sym is NULL. */ + if (!sym) + return NULL_TREE; + + if (sym->ts.type == BT_CHARACTER + && !sym->ts.cl->backend_decl) + { + length = gfc_create_string_length (sym); + gfc_finish_var_decl (length, sym); + } + + if (gfc_return_by_reference (sym)) + { + decl = DECL_ARGUMENTS (sym->backend_decl); + + TREE_USED (decl) = 1; + if (sym->as) + decl = gfc_build_dummy_array_decl (sym, decl); + } + else + { + sprintf (name, "__result_%.20s", + IDENTIFIER_POINTER (DECL_NAME (current_function_decl))); + + decl = build_decl (VAR_DECL, get_identifier (name), + TREE_TYPE (TREE_TYPE (current_function_decl))); + + DECL_ARTIFICIAL (decl) = 1; + DECL_EXTERNAL (decl) = 0; + TREE_PUBLIC (decl) = 0; + TREE_USED (decl) = 1; + + layout_decl (decl, 0); + + gfc_add_decl_to_function (decl); + } + + current_fake_result_decl = decl; + + return decl; +} + + +/* Builds a function decl. The remaining parameters are the types of the + function arguments. Negative nargs indicates a varargs function. */ + +tree +gfc_build_library_function_decl (tree name, tree rettype, int nargs, ...) +{ + tree arglist; + tree argtype; + tree fntype; + tree fndecl; + va_list p; + int n; + + /* Library functions must be declared with global scope. */ + assert (current_function_decl == NULL_TREE); + + va_start (p, nargs); + + + /* Create a list of the argument types. */ + for (arglist = NULL_TREE, n = abs (nargs); n > 0; n--) + { + argtype = va_arg (p, tree); + arglist = gfc_chainon_list (arglist, argtype); + } + + if (nargs >= 0) + { + /* Terminate the list. */ + arglist = gfc_chainon_list (arglist, void_type_node); + } + + /* Build the function type and decl. */ + fntype = build_function_type (rettype, arglist); + fndecl = build_decl (FUNCTION_DECL, name, fntype); + + /* Mark this decl as external. */ + DECL_EXTERNAL (fndecl) = 1; + TREE_PUBLIC (fndecl) = 1; + + va_end (p); + + pushdecl (fndecl); + + rest_of_decl_compilation (fndecl, NULL, 1, 0); + + return fndecl; +} + +static void +gfc_build_intrinsic_function_decls (void) +{ + /* String functions. */ + gfor_fndecl_copy_string = + gfc_build_library_function_decl (get_identifier (PREFIX("copy_string")), + void_type_node, + 4, + gfc_strlen_type_node, pchar_type_node, + gfc_strlen_type_node, pchar_type_node); + + gfor_fndecl_compare_string = + gfc_build_library_function_decl (get_identifier (PREFIX("compare_string")), + gfc_int4_type_node, + 4, + gfc_strlen_type_node, pchar_type_node, + gfc_strlen_type_node, pchar_type_node); + + gfor_fndecl_concat_string = + gfc_build_library_function_decl (get_identifier (PREFIX("concat_string")), + void_type_node, + 6, + gfc_strlen_type_node, pchar_type_node, + gfc_strlen_type_node, pchar_type_node, + gfc_strlen_type_node, pchar_type_node); + + gfor_fndecl_string_len_trim = + gfc_build_library_function_decl (get_identifier (PREFIX("string_len_trim")), + gfc_int4_type_node, + 2, gfc_strlen_type_node, + pchar_type_node); + + gfor_fndecl_string_index = + gfc_build_library_function_decl (get_identifier (PREFIX("string_index")), + gfc_int4_type_node, + 5, gfc_strlen_type_node, pchar_type_node, + gfc_strlen_type_node, pchar_type_node, + gfc_logical4_type_node); + + gfor_fndecl_string_scan = + gfc_build_library_function_decl (get_identifier (PREFIX("string_scan")), + gfc_int4_type_node, + 5, gfc_strlen_type_node, pchar_type_node, + gfc_strlen_type_node, pchar_type_node, + gfc_logical4_type_node); + + gfor_fndecl_string_verify = + gfc_build_library_function_decl (get_identifier (PREFIX("string_verify")), + gfc_int4_type_node, + 5, gfc_strlen_type_node, pchar_type_node, + gfc_strlen_type_node, pchar_type_node, + gfc_logical4_type_node); + + gfor_fndecl_string_trim = + gfc_build_library_function_decl (get_identifier (PREFIX("string_trim")), + void_type_node, + 4, + build_pointer_type (gfc_strlen_type_node), + ppvoid_type_node, + gfc_strlen_type_node, + pchar_type_node); + + gfor_fndecl_string_repeat = + gfc_build_library_function_decl (get_identifier (PREFIX("string_repeat")), + void_type_node, + 4, + pchar_type_node, + gfc_strlen_type_node, + pchar_type_node, + gfc_int4_type_node); + + gfor_fndecl_adjustl = + gfc_build_library_function_decl (get_identifier (PREFIX("adjustl")), + void_type_node, + 3, + pchar_type_node, + gfc_strlen_type_node, pchar_type_node); + + gfor_fndecl_adjustr = + gfc_build_library_function_decl (get_identifier (PREFIX("adjustr")), + void_type_node, + 3, + pchar_type_node, + gfc_strlen_type_node, pchar_type_node); + + gfor_fndecl_si_kind = + gfc_build_library_function_decl (get_identifier ("selected_int_kind"), + gfc_int4_type_node, + 1, + pvoid_type_node); + + gfor_fndecl_sr_kind = + gfc_build_library_function_decl (get_identifier ("selected_real_kind"), + gfc_int4_type_node, + 2, pvoid_type_node, + pvoid_type_node); + + + /* Power functions. */ + gfor_fndecl_math_powf = + gfc_build_library_function_decl (get_identifier ("powf"), + gfc_real4_type_node, + 1, gfc_real4_type_node); + gfor_fndecl_math_pow = + gfc_build_library_function_decl (get_identifier ("pow"), + gfc_real8_type_node, + 1, gfc_real8_type_node); + gfor_fndecl_math_cpowf = + gfc_build_library_function_decl (get_identifier ("cpowf"), + gfc_complex4_type_node, + 1, gfc_complex4_type_node); + gfor_fndecl_math_cpow = + gfc_build_library_function_decl (get_identifier ("cpow"), + gfc_complex8_type_node, + 1, gfc_complex8_type_node); + gfor_fndecl_math_cabsf = + gfc_build_library_function_decl (get_identifier ("cabsf"), + gfc_real4_type_node, + 1, gfc_complex4_type_node); + gfor_fndecl_math_cabs = + gfc_build_library_function_decl (get_identifier ("cabs"), + gfc_real8_type_node, + 1, gfc_complex8_type_node); + gfor_fndecl_math_sign4 = + gfc_build_library_function_decl (get_identifier ("copysignf"), + gfc_real4_type_node, + 1, gfc_real4_type_node); + gfor_fndecl_math_sign8 = + gfc_build_library_function_decl (get_identifier ("copysign"), + gfc_real8_type_node, + 1, gfc_real8_type_node); + gfor_fndecl_math_ishftc4 = + gfc_build_library_function_decl (get_identifier (PREFIX("ishftc4")), + gfc_int4_type_node, + 3, gfc_int4_type_node, + gfc_int4_type_node, gfc_int4_type_node); + gfor_fndecl_math_ishftc8 = + gfc_build_library_function_decl (get_identifier (PREFIX("ishftc8")), + gfc_int8_type_node, + 3, gfc_int8_type_node, + gfc_int8_type_node, gfc_int8_type_node); + gfor_fndecl_math_exponent4 = + gfc_build_library_function_decl (get_identifier (PREFIX("exponent_r4")), + gfc_int4_type_node, + 1, gfc_real4_type_node); + gfor_fndecl_math_exponent8 = + gfc_build_library_function_decl (get_identifier (PREFIX("exponent_r8")), + gfc_int4_type_node, + 1, gfc_real8_type_node); + + /* Other functions. */ + gfor_fndecl_size0 = + gfc_build_library_function_decl (get_identifier (PREFIX("size0")), + gfc_array_index_type, + 1, pvoid_type_node); + gfor_fndecl_size1 = + gfc_build_library_function_decl (get_identifier (PREFIX("size1")), + gfc_array_index_type, + 2, pvoid_type_node, + gfc_array_index_type); +} + + +/* Make prototypes for runtime library functions. */ + +void +gfc_build_builtin_function_decls (void) +{ + gfor_fndecl_internal_malloc = + gfc_build_library_function_decl (get_identifier (PREFIX("internal_malloc")), + pvoid_type_node, 1, gfc_int4_type_node); + + gfor_fndecl_internal_malloc64 = + gfc_build_library_function_decl (get_identifier + (PREFIX("internal_malloc64")), + pvoid_type_node, 1, gfc_int8_type_node); + + gfor_fndecl_internal_free = + gfc_build_library_function_decl (get_identifier (PREFIX("internal_free")), + void_type_node, 1, pvoid_type_node); + + gfor_fndecl_allocate = + gfc_build_library_function_decl (get_identifier (PREFIX("allocate")), + void_type_node, 2, ppvoid_type_node, + gfc_int4_type_node); + + gfor_fndecl_allocate64 = + gfc_build_library_function_decl (get_identifier (PREFIX("allocate64")), + void_type_node, 2, ppvoid_type_node, + gfc_int8_type_node); + + gfor_fndecl_deallocate = + gfc_build_library_function_decl (get_identifier (PREFIX("deallocate")), + void_type_node, 1, ppvoid_type_node); + + gfor_fndecl_stop_numeric = + gfc_build_library_function_decl (get_identifier (PREFIX("stop_numeric")), + void_type_node, 1, gfc_int4_type_node); + + gfor_fndecl_stop_string = + gfc_build_library_function_decl (get_identifier (PREFIX("stop_string")), + void_type_node, 2, pchar_type_node, + gfc_int4_type_node); + + gfor_fndecl_pause_numeric = + gfc_build_library_function_decl (get_identifier (PREFIX("pause_numeric")), + void_type_node, 1, gfc_int4_type_node); + + gfor_fndecl_pause_string = + gfc_build_library_function_decl (get_identifier (PREFIX("pause_string")), + void_type_node, 2, pchar_type_node, + gfc_int4_type_node); + + gfor_fndecl_select_string = + gfc_build_library_function_decl (get_identifier (PREFIX("select_string")), + pvoid_type_node, 0); + + gfor_fndecl_runtime_error = + gfc_build_library_function_decl (get_identifier (PREFIX("runtime_error")), + void_type_node, + 3, + pchar_type_node, pchar_type_node, + gfc_int4_type_node); + + gfor_fndecl_in_pack = gfc_build_library_function_decl ( + get_identifier (PREFIX("internal_pack")), + pvoid_type_node, 1, pvoid_type_node); + + gfor_fndecl_in_unpack = gfc_build_library_function_decl ( + get_identifier (PREFIX("internal_unpack")), + pvoid_type_node, 1, pvoid_type_node); + + gfor_fndecl_associated = + gfc_build_library_function_decl ( + get_identifier (PREFIX("associated")), + gfc_logical4_type_node, + 2, + ppvoid_type_node, + ppvoid_type_node); + + gfc_build_intrinsic_function_decls (); + gfc_build_intrinsic_lib_fndecls (); + gfc_build_io_library_fndecls (); +} + + +/* Exaluate the length of dummy character variables. */ + +static tree +gfc_trans_dummy_character (gfc_charlen * cl, tree fnbody) +{ + stmtblock_t body; + + gfc_finish_decl (cl->backend_decl, NULL_TREE); + + gfc_start_block (&body); + + /* Evaluate the string length expression. */ + gfc_trans_init_string_length (cl, &body); + + gfc_add_expr_to_block (&body, fnbody); + return gfc_finish_block (&body); +} + + +/* Allocate and cleanup an automatic character variable. */ + +static tree +gfc_trans_auto_character_variable (gfc_symbol * sym, tree fnbody) +{ + stmtblock_t body; + tree decl; + tree args; + tree tmp; + + assert (sym->backend_decl); + assert (sym->ts.cl && sym->ts.cl->length); + + gfc_start_block (&body); + + /* Evaluate the string length expression. */ + gfc_trans_init_string_length (sym->ts.cl, &body); + + decl = sym->backend_decl; + + DECL_DEFER_OUTPUT (decl) = 1; + + /* Generate code to allocate the automatic variable. It will be freed + automatically. */ + tmp = gfc_build_addr_expr (NULL, decl); + args = gfc_chainon_list (NULL_TREE, tmp); + args = gfc_chainon_list (args, sym->ts.cl->backend_decl); + tmp = gfc_build_function_call (built_in_decls[BUILT_IN_STACK_ALLOC], args); + gfc_add_expr_to_block (&body, tmp); + gfc_add_expr_to_block (&body, fnbody); + return gfc_finish_block (&body); +} + + +/* Generate function entry and exit code, and add it to the function body. + This includes: + Allocation and initialisation of array variables. + Allocation of character string variables. + Initialization and possibly repacking of dummy arrays. */ + +static tree +gfc_trans_deferred_vars (gfc_symbol * proc_sym, tree fnbody) +{ + locus loc; + gfc_symbol *sym; + + /* Deal with implicit return variables. Explicit return variables will + already have been added. */ + if (gfc_return_by_reference (proc_sym) && proc_sym->result == proc_sym) + { + if (!current_fake_result_decl) + { + warning ("Function does not return a value"); + return fnbody; + } + + if (proc_sym->as) + { + fnbody = gfc_trans_dummy_array_bias (proc_sym, + current_fake_result_decl, + fnbody); + } + else if (proc_sym->ts.type == BT_CHARACTER) + { + if (TREE_CODE (proc_sym->ts.cl->backend_decl) == VAR_DECL) + fnbody = gfc_trans_dummy_character (proc_sym->ts.cl, fnbody); + } + else + gfc_todo_error ("Deferred non-array return by reference"); + } + + for (sym = proc_sym->tlink; sym != proc_sym; sym = sym->tlink) + { + if (sym->attr.dimension) + { + switch (sym->as->type) + { + case AS_EXPLICIT: + if (sym->attr.dummy || sym->attr.result) + fnbody = + gfc_trans_dummy_array_bias (sym, sym->backend_decl, fnbody); + else if (sym->attr.pointer || sym->attr.allocatable) + { + if (TREE_STATIC (sym->backend_decl)) + gfc_trans_static_array_pointer (sym); + else + fnbody = gfc_trans_deferred_array (sym, fnbody); + } + else + { + gfc_get_backend_locus (&loc); + gfc_set_backend_locus (&sym->declared_at); + fnbody = gfc_trans_auto_array_allocation (sym->backend_decl, + sym, fnbody); + gfc_set_backend_locus (&loc); + } + break; + + case AS_ASSUMED_SIZE: + /* Must be a dummy parameter. */ + assert (sym->attr.dummy); + + /* We should always pass assumed size arrays the g77 way. */ + assert (TREE_CODE (sym->backend_decl) == PARM_DECL); + fnbody = gfc_trans_g77_array (sym, fnbody); + break; + + case AS_ASSUMED_SHAPE: + /* Must be a dummy parameter. */ + assert (sym->attr.dummy); + + fnbody = gfc_trans_dummy_array_bias (sym, sym->backend_decl, + fnbody); + break; + + case AS_DEFERRED: + fnbody = gfc_trans_deferred_array (sym, fnbody); + break; + + default: + abort (); + } + } + else if (sym->ts.type == BT_CHARACTER) + { + gfc_get_backend_locus (&loc); + gfc_set_backend_locus (&sym->declared_at); + if (sym->attr.dummy || sym->attr.result) + fnbody = gfc_trans_dummy_character (sym->ts.cl, fnbody); + else + fnbody = gfc_trans_auto_character_variable (sym, fnbody); + gfc_set_backend_locus (&loc); + } + else + abort (); + } + + return fnbody; +} + + +/* Output an initialized decl for a module variable. */ + +static void +gfc_create_module_variable (gfc_symbol * sym) +{ + tree decl; + gfc_se se; + + /* Only output symbols from this module. */ + if (sym->ns != module_namespace) + { + /* I don't think this should ever happen. */ + internal_error ("module symbol %s in wrong namespace", sym->name); + } + + /* Don't ouptut symbols from common blocks. */ + if (sym->attr.common) + return; + + /* Only output variables and array valued parametes. */ + if (sym->attr.flavor != FL_VARIABLE + && (sym->attr.flavor != FL_PARAMETER || sym->attr.dimension == 0)) + return; + + /* Don't generate variables from other modules. */ + if (sym->attr.use_assoc) + return; + + if (sym->backend_decl) + internal_error ("backend decl for module variable %s already exists", + sym->name); + + /* We always want module variables to be created. */ + sym->attr.referenced = 1; + /* Create the decl. */ + decl = gfc_get_symbol_decl (sym); + + /* We want to allocate storage for this variable. */ + TREE_STATIC (decl) = 1; + + if (sym->attr.dimension) + { + assert (sym->attr.pointer || sym->attr.allocatable + || GFC_ARRAY_TYPE_P (TREE_TYPE (sym->backend_decl))); + if (sym->attr.pointer || sym->attr.allocatable) + gfc_trans_static_array_pointer (sym); + else + gfc_trans_auto_array_allocation (sym->backend_decl, sym, NULL_TREE); + } + else if (sym->ts.type == BT_DERIVED) + { + if (sym->value) + gfc_todo_error ("Initialization of derived type module variables"); + } + else + { + if (sym->value) + { + gfc_init_se (&se, NULL); + gfc_conv_constant (&se, sym->value); + DECL_INITIAL (decl) = se.expr; + } + } + + /* Create the variable. */ + pushdecl (decl); + rest_of_decl_compilation (decl, NULL, 1, 0); + + /* Also add length of strings. */ + if (sym->ts.type == BT_CHARACTER) + { + tree length; + + length = sym->ts.cl->backend_decl; + if (!INTEGER_CST_P (length)) + { + pushdecl (length); + rest_of_decl_compilation (length, NULL, 1, 0); + } + } +} + + +/* Generate all the required code for module variables. */ + +void +gfc_generate_module_vars (gfc_namespace * ns) +{ + module_namespace = ns; + + /* Check the frontend left the namespace in a reasonable state. */ + assert (ns->proc_name && !ns->proc_name->tlink); + + /* Create decls for all the module varuiables. */ + gfc_traverse_ns (ns, gfc_create_module_variable); +} + +static void +gfc_generate_contained_functions (gfc_namespace * parent) +{ + gfc_namespace *ns; + + /* We create all the prototypes before generating any code. */ + for (ns = parent->contained; ns; ns = ns->sibling) + { + /* Skip namespaces from used modules. */ + if (ns->parent != parent) + continue; + + gfc_build_function_decl (ns->proc_name); + } + + for (ns = parent->contained; ns; ns = ns->sibling) + { + /* Skip namespaces from used modules. */ + if (ns->parent != parent) + continue; + + gfc_generate_function_code (ns); + } +} + + +/* Generate decls for all local variables. We do this to ensure correct + handling of expressions which only appear in the specification of + other functions. */ + +static void +generate_local_decl (gfc_symbol * sym) +{ + if (sym->attr.flavor == FL_VARIABLE) + { + /* TODO: The frontend sometimes creates symbols for things which don't + actually exist. E.g. common block names and the names of formal + arguments. The latter are created while attempting to parse + the argument list as a substring reference. + + The proper fix is to avoid adding these symbols in the first place. + For now we hack round it by ignoring anything with an unknown type. + */ + if (sym->ts.type == BT_UNKNOWN) + return; + + if (sym->attr.referenced) + gfc_get_symbol_decl (sym); + else if (sym->attr.dummy) + { + if (warn_unused_parameter) + warning ("unused parameter `%s'", sym->name); + } + else if (warn_unused_variable) + warning ("unused variable `%s'", sym->name); + } +} + +static void +generate_local_vars (gfc_namespace * ns) +{ + gfc_traverse_ns (ns, generate_local_decl); +} + + +/* Finalize DECL and all nested functions with cgraph. */ + +static void +gfc_finalize (tree decl) +{ + struct cgraph_node *cgn; + + cgn = cgraph_node (decl); + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + gfc_finalize (cgn->decl); + + cgraph_finalize_function (decl, false); +} + +/* Generate code for a function. */ + +void +gfc_generate_function_code (gfc_namespace * ns) +{ + tree fndecl; + tree old_context; + tree decl; + tree tmp; + stmtblock_t block; + stmtblock_t body; + tree result; + gfc_symbol *sym; + + sym = ns->proc_name; + /* Check that the frontend isn't still using this. */ + assert (sym->tlink == NULL); + + sym->tlink = sym; + + /* Create the declaration for functions with global scope. */ + if (!sym->backend_decl) + gfc_build_function_decl (ns->proc_name); + + fndecl = sym->backend_decl; + old_context = current_function_decl; + + if (old_context) + { + push_function_context (); + saved_parent_function_decls = saved_function_decls; + saved_function_decls = NULL_TREE; + } + + /* let GCC know the current scope is this function */ + current_function_decl = fndecl; + + /* print function name on the console at compile time + (unless this feature was switched of by command line option "-quiet" */ + announce_function (fndecl); + + if (DECL_CONTEXT (fndecl) == NULL_TREE) + { + /* create RTL for function declaration */ + rest_of_decl_compilation (fndecl, NULL, 1, 0); + } + + /* create RTL for function definition */ + make_decl_rtl (fndecl, NULL); + + /* Set the line and filename. sym->decalred_at seems to point to the last + statement for subroutines, but it'll do for now. */ + gfc_set_backend_locus (&sym->declared_at); + + /* line and file should not be 0 */ + init_function_start (fndecl); + + /* We're in function-at-a-time mode. */ + cfun->x_whole_function_mode_p = 1; + + /* Even though we're inside a function body, we still don't want to + call expand_expr to calculate the size of a variable-sized array. + We haven't necessarily assigned RTL to all variables yet, so it's + not safe to try to expand expressions involving them. */ + immediate_size_expand = 0; + cfun->x_dont_save_pending_sizes_p = 1; + + /* Will be created as needed. */ + current_fake_result_decl = NULL_TREE; + + /* function.c requires a push at the start of the function */ + pushlevel (0); + + gfc_start_block (&block); + + gfc_generate_contained_functions (ns); + + /* Translate COMMON blocks. */ + gfc_trans_common (ns); + + generate_local_vars (ns); + + current_function_return_label = NULL; + + /* Now generate the code for the body of this function. */ + gfc_init_block (&body); + + if (TREE_TYPE (DECL_RESULT (fndecl)) != void_type_node + && sym->attr.subroutine) + { + tree alternate_return; + alternate_return = gfc_get_fake_result_decl (sym); + gfc_add_modify_expr (&body, alternate_return, integer_zero_node); + } + + tmp = gfc_trans_code (ns->code); + gfc_add_expr_to_block (&body, tmp); + + /* Add a return label if needed. */ + if (current_function_return_label) + { + tmp = build1_v (LABEL_EXPR, current_function_return_label); + gfc_add_expr_to_block (&body, tmp); + } + + tmp = gfc_finish_block (&body); + /* Add code to create and cleanup arrays. */ + tmp = gfc_trans_deferred_vars (sym, tmp); + gfc_add_expr_to_block (&block, tmp); + + if (TREE_TYPE (DECL_RESULT (fndecl)) != void_type_node) + { + if (sym->attr.subroutine ||sym == sym->result) + { + result = current_fake_result_decl; + current_fake_result_decl = NULL_TREE; + } + else + result = sym->result->backend_decl; + + if (result == NULL_TREE) + warning ("Function return value not set"); + else + { + /* Set the return value to the the dummy result variable. */ + tmp = build (MODIFY_EXPR, TREE_TYPE (result), + DECL_RESULT (fndecl), result); + tmp = build_v (RETURN_EXPR, tmp); + gfc_add_expr_to_block (&block, tmp); + } + } + + /* Add all the decls we created during processing. */ + decl = saved_function_decls; + while (decl) + { + tree next; + + next = TREE_CHAIN (decl); + TREE_CHAIN (decl) = NULL_TREE; + pushdecl (decl); + decl = next; + } + saved_function_decls = NULL_TREE; + + DECL_SAVED_TREE (fndecl) = gfc_finish_block (&block); + + /* Finish off this function and send it for code generation. */ + poplevel (1, 0, 1); + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* Output the GENERIC tree. */ + dump_function (TDI_original, fndecl); + + /* Store the end of the function, so that we get good line number + info for the epilogue. */ + cfun->function_end_locus = input_location; + + /* We're leaving the context of this function, so zap cfun. + It's still in DECL_STRUCT_FUNCTION, and we'll restore it in + tree_rest_of_compilation. */ + cfun = NULL; + + if (old_context) + { + pop_function_context (); + saved_function_decls = saved_parent_function_decls; + } + current_function_decl = old_context; + + if (decl_function_context (fndecl)) + { + /* Register this function with cgraph just far enough to get it + added to our parent's nested function list. */ + (void) cgraph_node (fndecl); + + /* Lowering nested functions requires gimple input. */ + gimplify_function_tree (fndecl); + } + else + { + if (cgraph_node (fndecl)->nested) + { + gimplify_function_tree (fndecl); + lower_nested_functions (fndecl); + } + gfc_finalize (fndecl); + } +} + + +void +gfc_generate_constructors (void) +{ + if (gfc_static_ctors != NULL_TREE) + abort (); +#if 0 + tree fnname; + tree type; + tree fndecl; + tree decl; + tree tmp; + + if (gfc_static_ctors == NULL_TREE) + return; + + fnname = get_file_function_name ('I'); + type = build_function_type (void_type_node, + gfc_chainon_list (NULL_TREE, void_type_node)); + + fndecl = build_decl (FUNCTION_DECL, fnname, type); + TREE_PUBLIC (fndecl) = 1; + + decl = build_decl (RESULT_DECL, NULL_TREE, void_type_node); + DECL_CONTEXT (decl) = fndecl; + DECL_RESULT (fndecl) = decl; + + pushdecl (fndecl); + + current_function_decl = fndecl; + + rest_of_decl_compilation (fndecl, NULL, 1, 0); + + make_decl_rtl (fndecl, NULL); + + init_function_start (fndecl, input_filename, input_line); + + cfun->x_whole_function_mode_p = 1; + + immediate_size_expand = 0; + + pushlevel (0); + + for (; gfc_static_ctors; gfc_static_ctors = TREE_CHAIN (gfc_static_ctors)) + { + tmp = + gfc_build_function_call (TREE_VALUE (gfc_static_ctors), NULL_TREE); + DECL_SAVED_TREE (fndecl) = build_stmt (EXPR_STMT, tmp); + } + + poplevel (1, 0, 1); + + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + free_after_parsing (cfun); + free_after_compilation (cfun); + + tree_rest_of_compilation (fndecl, 0); + + current_function_decl = NULL_TREE; +#endif +} + +#include "gt-fortran-trans-decl.h" diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c new file mode 100644 index 00000000000..864b006c536 --- /dev/null +++ b/gcc/fortran/trans-expr.c @@ -0,0 +1,1835 @@ +/* Expression translation + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Paul Brook + and Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* trans-expr.c-- generate GENERIC trees for gfc_expr. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "convert.h" +#include +#include "ggc.h" +#include "toplev.h" +#include "real.h" +#include "tree-simple.h" +#include "flags.h" +#include +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-const.h" +#include "trans-types.h" +#include "trans-array.h" +/* Only for gfc_trans_assign and gfc_trans_pointer_assign. */ +#include "trans-stmt.h" + + +/* Copy the scalarization loop variables. */ + +static void +gfc_copy_se_loopvars (gfc_se * dest, gfc_se * src) +{ + dest->ss = src->ss; + dest->loop = src->loop; +} + + +/* Initialise a simple expression holder. + + Care must be taken when multiple se are created with the same parent. + The child se must be kept in sync. The easiest way is to delay creation + of a child se until after after the previous se has been translated. */ + +void +gfc_init_se (gfc_se * se, gfc_se * parent) +{ + memset (se, 0, sizeof (gfc_se)); + gfc_init_block (&se->pre); + gfc_init_block (&se->post); + + se->parent = parent; + + if (parent) + gfc_copy_se_loopvars (se, parent); +} + + +/* Advances to the next SS in the chain. Use this rather than setting + se->ss = se->ss->next because all the parent needs to be kept in sync. + See gfc_init_se. */ + +void +gfc_advance_se_ss_chain (gfc_se * se) +{ + gfc_se *p; + + assert (se != NULL && se->ss != NULL && se->ss != gfc_ss_terminator); + + p = se; + /* Walk down the parent chain. */ + while (p != NULL) + { + /* Simple consistancy check. */ + assert (p->parent == NULL || p->parent->ss == p->ss); + + p->ss = p->ss->next; + + p = p->parent; + } +} + + +/* Ensures the result of the expression as either a temporary variable + or a constant so that it can be used repeatedly. */ + +void +gfc_make_safe_expr (gfc_se * se) +{ + tree var; + + if (TREE_CODE_CLASS (TREE_CODE (se->expr)) == 'c') + return; + + /* we need a temporary for this result */ + var = gfc_create_var (TREE_TYPE (se->expr), NULL); + gfc_add_modify_expr (&se->pre, var, se->expr); + se->expr = var; +} + + +/* Return an expression which determines if a dummy parameter is present. */ + +tree +gfc_conv_expr_present (gfc_symbol * sym) +{ + tree decl; + + assert (sym->attr.dummy && sym->attr.optional); + + decl = gfc_get_symbol_decl (sym); + if (TREE_CODE (decl) != PARM_DECL) + { + /* Array parameters use a temporary descriptor, we want the real + parameter. */ + assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)) + || GFC_ARRAY_TYPE_P (TREE_TYPE (decl))); + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + } + return build (NE_EXPR, boolean_type_node, decl, null_pointer_node); +} + + +/* Generate code to initialize a string length variable. Returns the + value. */ + +void +gfc_trans_init_string_length (gfc_charlen * cl, stmtblock_t * pblock) +{ + gfc_se se; + tree tmp; + + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, cl->length, gfc_strlen_type_node); + gfc_add_block_to_block (pblock, &se.pre); + + tmp = cl->backend_decl; + gfc_add_modify_expr (pblock, tmp, se.expr); +} + +static void +gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind) +{ + tree tmp; + tree type; + tree var; + gfc_se start; + gfc_se end; + + type = gfc_get_character_type (kind, ref->u.ss.length); + type = build_pointer_type (type); + + var = NULL_TREE; + gfc_init_se (&start, se); + gfc_conv_expr_type (&start, ref->u.ss.start, gfc_strlen_type_node); + gfc_add_block_to_block (&se->pre, &start.pre); + + if (integer_onep (start.expr)) + { + gfc_conv_string_parameter (se); + } + else + { + /* Change the start of the string. */ + if (TYPE_STRING_FLAG (TREE_TYPE (se->expr))) + tmp = se->expr; + else + tmp = gfc_build_indirect_ref (se->expr); + tmp = gfc_build_array_ref (tmp, start.expr); + se->expr = gfc_build_addr_expr (type, tmp); + } + + /* Length = end + 1 - start. */ + gfc_init_se (&end, se); + if (ref->u.ss.end == NULL) + end.expr = se->string_length; + else + { + gfc_conv_expr_type (&end, ref->u.ss.end, gfc_strlen_type_node); + gfc_add_block_to_block (&se->pre, &end.pre); + } + tmp = + build (MINUS_EXPR, gfc_strlen_type_node, integer_one_node, start.expr); + tmp = build (PLUS_EXPR, gfc_strlen_type_node, end.expr, tmp); + se->string_length = fold (tmp); +} + + +/* Convert a derived type component reference. */ + +static void +gfc_conv_component_ref (gfc_se * se, gfc_ref * ref) +{ + gfc_component *c; + tree tmp; + tree decl; + tree field; + + c = ref->u.c.component; + + assert (c->backend_decl); + + field = c->backend_decl; + assert (TREE_CODE (field) == FIELD_DECL); + decl = se->expr; + tmp = build (COMPONENT_REF, TREE_TYPE (field), decl, field); + + se->expr = tmp; + + if (c->ts.type == BT_CHARACTER) + { + tmp = c->ts.cl->backend_decl; + assert (tmp); + if (!INTEGER_CST_P (tmp)) + gfc_todo_error ("Unknown length character component"); + se->string_length = tmp; + } + + if (c->pointer && c->dimension == 0) + se->expr = gfc_build_indirect_ref (se->expr); +} + + +/* Return the contents of a variable. Also handles reference/pointer + variables (all Fortran pointer references are implicit). */ + +static void +gfc_conv_variable (gfc_se * se, gfc_expr * expr) +{ + gfc_ref *ref; + gfc_symbol *sym; + + sym = expr->symtree->n.sym; + if (se->ss != NULL) + { + /* Check that something hasn't gone horribly wrong. */ + assert (se->ss != gfc_ss_terminator); + assert (se->ss->expr == expr); + + /* A scalarized term. We already know the descriptor. */ + se->expr = se->ss->data.info.descriptor; + ref = se->ss->data.info.ref; + } + else + { + se->expr = gfc_get_symbol_decl (sym); + + /* Procedure actual arguments. */ + if (sym->attr.flavor == FL_PROCEDURE + && se->expr != current_function_decl) + { + assert (se->want_pointer); + if (!sym->attr.dummy) + { + assert (TREE_CODE (se->expr) == FUNCTION_DECL); + se->expr = gfc_build_addr_expr (NULL, se->expr); + } + return; + } + + /* Special case for assigning the return value of a function. + Self recursive functions must have an explicit return value. */ + if (se->expr == current_function_decl && sym->attr.function + && (sym->result == sym)) + { + se->expr = gfc_get_fake_result_decl (sym); + } + + /* Dereference scalar dummy variables. */ + if (sym->attr.dummy + && sym->ts.type != BT_CHARACTER + && !sym->attr.dimension) + se->expr = gfc_build_indirect_ref (se->expr); + + /* Dereference pointer variables. */ + if ((sym->attr.pointer || sym->attr.allocatable) + && (sym->attr.dummy + || sym->attr.result + || sym->attr.function + || !sym->attr.dimension) + && sym->ts.type != BT_CHARACTER) + se->expr = gfc_build_indirect_ref (se->expr); + + ref = expr->ref; + } + + /* For character variables, also get the length. */ + if (sym->ts.type == BT_CHARACTER) + { + se->string_length = sym->ts.cl->backend_decl; + assert (se->string_length); + } + + while (ref) + { + switch (ref->type) + { + case REF_ARRAY: + /* Return the descriptor if that's what we want and this is an array + section reference. */ + if (se->descriptor_only && ref->u.ar.type != AR_ELEMENT) + return; +/* TODO: Pointers to single elements of array sections, eg elemental subs. */ + /* Return the descriptor for array pointers and allocations. */ + if (se->want_pointer + && ref->next == NULL && (se->descriptor_only)) + return; + + gfc_conv_array_ref (se, &ref->u.ar); + /* Return a pointer to an element. */ + break; + + case REF_COMPONENT: + gfc_conv_component_ref (se, ref); + break; + + case REF_SUBSTRING: + gfc_conv_substring (se, ref, expr->ts.kind); + break; + + default: + abort (); + break; + } + ref = ref->next; + } + /* Pointer assignment, allocation or pass by reference. Arrays are handled + seperately. */ + if (se->want_pointer) + { + if (expr->ts.type == BT_CHARACTER) + gfc_conv_string_parameter (se); + else + se->expr = gfc_build_addr_expr (NULL, se->expr); + } + if (se->ss != NULL) + gfc_advance_se_ss_chain (se); +} + + +/* Unary ops are easy... Or they would be if ! was a valid op. */ + +static void +gfc_conv_unary_op (enum tree_code code, gfc_se * se, gfc_expr * expr) +{ + gfc_se operand; + tree type; + + assert (expr->ts.type != BT_CHARACTER); + /* Initialize the operand. */ + gfc_init_se (&operand, se); + gfc_conv_expr_val (&operand, expr->op1); + gfc_add_block_to_block (&se->pre, &operand.pre); + + type = gfc_typenode_for_spec (&expr->ts); + + /* TRUTH_NOT_EXPR is not a "true" unary operator in GCC. + We must convert it to a compare to 0 (e.g. EQ_EXPR (op1, 0)). + All other unary operators have an equivalent SIMPLE unary operator */ + if (code == TRUTH_NOT_EXPR) + se->expr = build (EQ_EXPR, type, operand.expr, integer_zero_node); + else + se->expr = build1 (code, type, operand.expr); + +} + + +/* For power op (lhs ** rhs) We generate: + m = lhs + if (rhs > 0) + count = rhs + else if (rhs == 0) + { + count = 0 + m = 1 + } + else // (rhs < 0) + { + count = -rhs + m = 1 / m; + } + // for constant rhs we do the above at compile time + val = m; + for (n = 1; n < count; n++) + val = val * m; + */ + +static void +gfc_conv_integer_power (gfc_se * se, tree lhs, tree rhs) +{ + tree count; + tree result; + tree cond; + tree neg_stmt; + tree pos_stmt; + tree tmp; + tree var; + tree type; + stmtblock_t block; + tree exit_label; + + type = TREE_TYPE (lhs); + + if (INTEGER_CST_P (rhs)) + { + if (integer_zerop (rhs)) + { + se->expr = gfc_build_const (type, integer_one_node); + return; + } + /* Special cases for constant values. */ + if (TREE_INT_CST_HIGH (rhs) == -1) + { + /* x ** (-y) == 1 / (x ** y). */ + if (TREE_CODE (type) == INTEGER_TYPE) + { + se->expr = integer_zero_node; + return; + } + + tmp = gfc_build_const (type, integer_one_node); + lhs = fold (build (RDIV_EXPR, type, tmp, lhs)); + + rhs = fold (build1 (NEGATE_EXPR, TREE_TYPE (rhs), rhs)); + assert (INTEGER_CST_P (rhs)); + } + else + { + /* TODO: really big integer powers. */ + assert (TREE_INT_CST_HIGH (rhs) == 0); + } + + if (integer_onep (rhs)) + { + se->expr = lhs; + return; + } + if (TREE_INT_CST_LOW (rhs) == 2) + { + se->expr = build (MULT_EXPR, type, lhs, lhs); + return; + } + if (TREE_INT_CST_LOW (rhs) == 3) + { + tmp = build (MULT_EXPR, type, lhs, lhs); + se->expr = fold (build (MULT_EXPR, type, tmp, lhs)); + return; + } + + /* Create the loop count variable. */ + count = gfc_create_var (TREE_TYPE (rhs), "count"); + gfc_add_modify_expr (&se->pre, count, rhs); + } + else + { + /* Put the lhs into a temporary variable. */ + var = gfc_create_var (type, "val"); + count = gfc_create_var (TREE_TYPE (rhs), "count"); + gfc_add_modify_expr (&se->pre, var, lhs); + lhs = var; + + /* Generate code for negative rhs. */ + gfc_start_block (&block); + + if (TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE) + { + gfc_add_modify_expr (&block, lhs, integer_zero_node); + gfc_add_modify_expr (&block, count, integer_zero_node); + } + else + { + tmp = gfc_build_const (type, integer_one_node); + tmp = build (RDIV_EXPR, type, tmp, lhs); + gfc_add_modify_expr (&block, var, tmp); + + tmp = build1 (NEGATE_EXPR, TREE_TYPE (rhs), rhs); + gfc_add_modify_expr (&block, count, tmp); + } + neg_stmt = gfc_finish_block (&block); + + pos_stmt = build_v (MODIFY_EXPR, count, rhs); + + /* Code for rhs == 0. */ + gfc_start_block (&block); + + gfc_add_modify_expr (&block, count, integer_zero_node); + tmp = gfc_build_const (type, integer_one_node); + gfc_add_modify_expr (&block, lhs, tmp); + + tmp = gfc_finish_block (&block); + + /* Select the appropriate action. */ + cond = build (EQ_EXPR, boolean_type_node, rhs, integer_zero_node); + tmp = build_v (COND_EXPR, cond, tmp, neg_stmt); + + cond = build (GT_EXPR, boolean_type_node, rhs, integer_zero_node); + tmp = build_v (COND_EXPR, cond, pos_stmt, tmp); + gfc_add_expr_to_block (&se->pre, tmp); + } + + /* Create a variable for the result. */ + result = gfc_create_var (type, "pow"); + gfc_add_modify_expr (&se->pre, result, lhs); + + exit_label = gfc_build_label_decl (NULL_TREE); + TREE_USED (exit_label) = 1; + + /* Create the loop body. */ + gfc_start_block (&block); + + /* First the exit condition (until count <= 1). */ + tmp = build1_v (GOTO_EXPR, exit_label); + cond = build (LE_EXPR, TREE_TYPE (count), count, integer_one_node); + tmp = build_v (COND_EXPR, cond, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&block, tmp); + + /* Multiply by the lhs. */ + tmp = build (MULT_EXPR, type, result, lhs); + gfc_add_modify_expr (&block, result, tmp); + + /* Adjust the loop count. */ + tmp = build (MINUS_EXPR, TREE_TYPE (count), count, integer_one_node); + gfc_add_modify_expr (&block, count, tmp); + + tmp = gfc_finish_block (&block); + + /* Create the the loop. */ + tmp = build_v (LOOP_EXPR, tmp); + gfc_add_expr_to_block (&se->pre, tmp); + + /* Add the exit label. */ + tmp = build1_v (LABEL_EXPR, exit_label); + gfc_add_expr_to_block (&se->pre, tmp); + + se->expr = result; +} + + +/* Power op (**). Integer rhs has special handling. */ + +static void +gfc_conv_power_op (gfc_se * se, gfc_expr * expr) +{ + int kind; + gfc_se lse; + gfc_se rse; + tree fndecl; + tree tmp; + tree type; + + gfc_init_se (&lse, se); + gfc_conv_expr_val (&lse, expr->op1); + gfc_add_block_to_block (&se->pre, &lse.pre); + + gfc_init_se (&rse, se); + gfc_conv_expr_val (&rse, expr->op2); + gfc_add_block_to_block (&se->pre, &rse.pre); + + type = TREE_TYPE (lse.expr); + + kind = expr->op1->ts.kind; + switch (expr->op2->ts.type) + { + case BT_INTEGER: + /* Integer powers are expanded inline as multiplications. */ + gfc_conv_integer_power (se, lse.expr, rse.expr); + return; + + case BT_REAL: + switch (kind) + { + case 4: + fndecl = gfor_fndecl_math_powf; + break; + case 8: + fndecl = gfor_fndecl_math_pow; + break; + default: + abort (); + } + break; + + case BT_COMPLEX: + switch (kind) + { + case 4: + fndecl = gfor_fndecl_math_cpowf; + break; + case 8: + fndecl = gfor_fndecl_math_cpow; + break; + default: + abort (); + } + break; + + default: + abort (); + break; + } + + tmp = gfc_chainon_list (NULL_TREE, lse.expr); + tmp = gfc_chainon_list (tmp, rse.expr); + se->expr = gfc_build_function_call (fndecl, tmp); +} + + +/* Generate code to allocate a string temporary. */ + +tree +gfc_conv_string_tmp (gfc_se * se, tree type, tree len) +{ + tree var; + tree tmp; + tree args; + + if (gfc_can_put_var_on_stack (len)) + { + /* Create a temporary variable to hold the result. */ + tmp = fold (build (MINUS_EXPR, TREE_TYPE (len), len, integer_one_node)); + tmp = build_range_type (gfc_array_index_type, integer_zero_node, tmp); + tmp = build_array_type (gfc_character1_type_node, tmp); + var = gfc_create_var (tmp, "str"); + var = gfc_build_addr_expr (type, var); + } + else + { + /* Allocate a temporary to hold the result. */ + var = gfc_create_var (type, "pstr"); + args = gfc_chainon_list (NULL_TREE, len); + tmp = gfc_build_function_call (gfor_fndecl_internal_malloc, args); + tmp = convert (type, tmp); + gfc_add_modify_expr (&se->pre, var, tmp); + + /* Free the temporary afterwards. */ + tmp = convert (pvoid_type_node, var); + args = gfc_chainon_list (NULL_TREE, tmp); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, args); + gfc_add_expr_to_block (&se->post, tmp); + } + + return var; +} + + +/* Handle a string concatenation operation. A temporary will be allocated to + hold the result. */ + +static void +gfc_conv_concat_op (gfc_se * se, gfc_expr * expr) +{ + gfc_se lse; + gfc_se rse; + tree len; + tree type; + tree var; + tree args; + tree tmp; + + assert (expr->op1->ts.type == BT_CHARACTER + && expr->op2->ts.type == BT_CHARACTER); + + gfc_init_se (&lse, se); + gfc_conv_expr (&lse, expr->op1); + gfc_conv_string_parameter (&lse); + gfc_init_se (&rse, se); + gfc_conv_expr (&rse, expr->op2); + gfc_conv_string_parameter (&rse); + + gfc_add_block_to_block (&se->pre, &lse.pre); + gfc_add_block_to_block (&se->pre, &rse.pre); + + type = gfc_get_character_type (expr->ts.kind, expr->ts.cl); + len = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + if (len == NULL_TREE) + { + len = fold (build (PLUS_EXPR, TREE_TYPE (lse.string_length), + lse.string_length, rse.string_length)); + } + + type = build_pointer_type (type); + + var = gfc_conv_string_tmp (se, type, len); + + /* Do the actual concatenation. */ + args = NULL_TREE; + args = gfc_chainon_list (args, len); + args = gfc_chainon_list (args, var); + args = gfc_chainon_list (args, lse.string_length); + args = gfc_chainon_list (args, lse.expr); + args = gfc_chainon_list (args, rse.string_length); + args = gfc_chainon_list (args, rse.expr); + tmp = gfc_build_function_call (gfor_fndecl_concat_string, args); + gfc_add_expr_to_block (&se->pre, tmp); + + /* Add the cleanup for the operands. */ + gfc_add_block_to_block (&se->pre, &rse.post); + gfc_add_block_to_block (&se->pre, &lse.post); + + se->expr = var; + se->string_length = len; +} + + +/* Translates an op expression. Common (binary) cases are handled by this + function, others are passed on. Recursion is used in either case. + We use the fact that (op1.ts == op2.ts) (except for the power + operand **). + Operators need no special handling for scalarized expressions as long as + they call gfc_conv_siple_val to get their operands. + Character strings get special handling. */ + +static void +gfc_conv_expr_op (gfc_se * se, gfc_expr * expr) +{ + enum tree_code code; + gfc_se lse; + gfc_se rse; + tree type; + tree tmp; + int lop; + int checkstring; + + checkstring = 0; + lop = 0; + switch (expr->operator) + { + case INTRINSIC_UPLUS: + gfc_conv_expr (se, expr->op1); + return; + + case INTRINSIC_UMINUS: + gfc_conv_unary_op (NEGATE_EXPR, se, expr); + return; + + case INTRINSIC_NOT: + gfc_conv_unary_op (TRUTH_NOT_EXPR, se, expr); + return; + + case INTRINSIC_PLUS: + code = PLUS_EXPR; + break; + + case INTRINSIC_MINUS: + code = MINUS_EXPR; + break; + + case INTRINSIC_TIMES: + code = MULT_EXPR; + break; + + case INTRINSIC_DIVIDE: + /* If expr is a real or complex expr, use an RDIV_EXPR. If op1 is + an integer, we must round towards zero, so we use a + TRUNC_DIV_EXPR. */ + if (expr->ts.type == BT_INTEGER) + code = TRUNC_DIV_EXPR; + else + code = RDIV_EXPR; + break; + + case INTRINSIC_POWER: + gfc_conv_power_op (se, expr); + return; + + case INTRINSIC_CONCAT: + gfc_conv_concat_op (se, expr); + return; + + case INTRINSIC_AND: + code = TRUTH_ANDIF_EXPR; + lop = 1; + break; + + case INTRINSIC_OR: + code = TRUTH_ORIF_EXPR; + lop = 1; + break; + + /* EQV and NEQV only work on logicals, but since we represent them + as integers, we can use EQ_EXPR and NE_EXPR for them in SIMPLE. */ + case INTRINSIC_EQ: + case INTRINSIC_EQV: + code = EQ_EXPR; + checkstring = 1; + lop = 1; + break; + + case INTRINSIC_NE: + case INTRINSIC_NEQV: + code = NE_EXPR; + checkstring = 1; + lop = 1; + break; + + case INTRINSIC_GT: + code = GT_EXPR; + checkstring = 1; + lop = 1; + break; + + case INTRINSIC_GE: + code = GE_EXPR; + checkstring = 1; + lop = 1; + break; + + case INTRINSIC_LT: + code = LT_EXPR; + checkstring = 1; + lop = 1; + break; + + case INTRINSIC_LE: + code = LE_EXPR; + checkstring = 1; + lop = 1; + break; + + case INTRINSIC_USER: + case INTRINSIC_ASSIGN: + /* These should be converted into function calls by the frontend. */ + abort (); + return; + + default: + fatal_error ("Unknown intrinsic op"); + return; + } + + /* The only exception to this is **, which is handled seperately anyway. */ + assert (expr->op1->ts.type == expr->op2->ts.type); + + if (checkstring && expr->op1->ts.type != BT_CHARACTER) + checkstring = 0; + + /* lhs */ + gfc_init_se (&lse, se); + gfc_conv_expr (&lse, expr->op1); + gfc_add_block_to_block (&se->pre, &lse.pre); + + /* rhs */ + gfc_init_se (&rse, se); + gfc_conv_expr (&rse, expr->op2); + gfc_add_block_to_block (&se->pre, &rse.pre); + + /* For string comparisons we generate a library call, and compare the return + value with 0. */ + if (checkstring) + { + gfc_conv_string_parameter (&lse); + gfc_conv_string_parameter (&rse); + tmp = NULL_TREE; + tmp = gfc_chainon_list (tmp, lse.string_length); + tmp = gfc_chainon_list (tmp, lse.expr); + tmp = gfc_chainon_list (tmp, rse.string_length); + tmp = gfc_chainon_list (tmp, rse.expr); + + /* Build a call for the comparison. */ + lse.expr = gfc_build_function_call (gfor_fndecl_compare_string, tmp); + gfc_add_block_to_block (&lse.post, &rse.post); + + rse.expr = integer_zero_node; + } + + type = gfc_typenode_for_spec (&expr->ts); + + if (lop) + { + /* The result of logical ops is always boolean_type_node. */ + tmp = fold (build (code, type, lse.expr, rse.expr)); + se->expr = convert (type, tmp); + } + else + se->expr = fold (build (code, type, lse.expr, rse.expr)); + + + /* Add the post blocks. */ + gfc_add_block_to_block (&se->post, &rse.post); + gfc_add_block_to_block (&se->post, &lse.post); +} + +static void +gfc_conv_function_val (gfc_se * se, gfc_symbol * sym) +{ + tree tmp; + + if (sym->attr.dummy) + { + tmp = gfc_get_symbol_decl (sym); + assert (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (tmp))) == FUNCTION_TYPE); + + se->expr = tmp; + } + else + { + if (!sym->backend_decl) + sym->backend_decl = gfc_get_extern_function_decl (sym); + + tmp = sym->backend_decl; + assert (TREE_CODE (tmp) == FUNCTION_DECL); + se->expr = gfc_build_addr_expr (NULL, tmp); + } +} + + +/* Generate code for a procedure call. Note can return se->post != NULL. + If se->direct_byref is set then se->expr contains the return parameter. */ + +void +gfc_conv_function_call (gfc_se * se, gfc_symbol * sym, + gfc_actual_arglist * arg) +{ + tree arglist; + tree tmp; + tree fntype; + gfc_se parmse; + gfc_ss *argss; + gfc_ss_info *info; + int byref; + tree type; + tree var; + tree len; + tree stringargs; + gfc_formal_arglist *formal; + + arglist = NULL_TREE; + stringargs = NULL_TREE; + var = NULL_TREE; + len = NULL_TREE; + + if (se->ss != NULL) + { + if (!sym->attr.elemental) + { + assert (se->ss->type == GFC_SS_FUNCTION); + if (se->ss->useflags) + { + assert (gfc_return_by_reference (sym) + && sym->result->attr.dimension); + assert (se->loop != NULL); + + /* Access the previously obtained result. */ + gfc_conv_tmp_array_ref (se); + gfc_advance_se_ss_chain (se); + return; + } + } + info = &se->ss->data.info; + } + else + info = NULL; + + byref = gfc_return_by_reference (sym); + if (byref) + { + if (se->direct_byref) + arglist = gfc_chainon_list (arglist, se->expr); + else if (sym->result->attr.dimension) + { + assert (se->loop && se->ss); + /* Set the type of the array. */ + tmp = gfc_typenode_for_spec (&sym->ts); + info->dimen = se->loop->dimen; + /* Allocate a temporary to store the result. */ + gfc_trans_allocate_temp_array (se->loop, info, tmp, NULL_TREE); + + /* Zero the first stride to indicate a temporary. */ + tmp = + gfc_conv_descriptor_stride (info->descriptor, gfc_rank_cst[0]); + gfc_add_modify_expr (&se->pre, tmp, integer_zero_node); + /* Pass the temporary as the first argument. */ + tmp = info->descriptor; + tmp = gfc_build_addr_expr (NULL, tmp); + arglist = gfc_chainon_list (arglist, tmp); + } + else if (sym->ts.type == BT_CHARACTER) + { + assert (sym->ts.cl && sym->ts.cl->length + && sym->ts.cl->length->expr_type == EXPR_CONSTANT); + len = gfc_conv_mpz_to_tree + (sym->ts.cl->length->value.integer, sym->ts.cl->length->ts.kind); + sym->ts.cl->backend_decl = len; + type = gfc_get_character_type (sym->ts.kind, sym->ts.cl); + type = build_pointer_type (type); + + var = gfc_conv_string_tmp (se, type, len); + arglist = gfc_chainon_list (arglist, var); + arglist = gfc_chainon_list (arglist, convert (gfc_strlen_type_node, + len)); + } + else /* TODO: derived type function return values. */ + abort (); + } + + formal = sym->formal; + /* Evaluate the arguments. */ + for (; arg != NULL; arg = arg->next, formal = formal ? formal->next : NULL) + { + if (arg->expr == NULL) + { + + if (se->ignore_optional) + { + /* Some intrinsics have already been resolved to the correct + parameters. */ + continue; + } + else if (arg->label) + { + has_alternate_specifier = 1; + continue; + } + else + { + /* Pass a NULL pointer for an absent arg. */ + gfc_init_se (&parmse, NULL); + parmse.expr = null_pointer_node; + if (formal && formal->sym->ts.type == BT_CHARACTER) + { + stringargs = gfc_chainon_list (stringargs, + convert (gfc_strlen_type_node, integer_zero_node)); + } + } + } + else if (se->ss && se->ss->useflags) + { + /* An elemental function inside a scalarized loop. */ + gfc_init_se (&parmse, se); + gfc_conv_expr_reference (&parmse, arg->expr); + } + else + { + /* A scalar or transformational function. */ + gfc_init_se (&parmse, NULL); + argss = gfc_walk_expr (arg->expr); + + if (argss == gfc_ss_terminator) + { + gfc_conv_expr_reference (&parmse, arg->expr); + if (formal && formal->sym->attr.pointer) + { + /* Scalar pointer dummy args require an extra level of + indirection. */ + parmse.expr = gfc_build_addr_expr (NULL, parmse.expr); + } + } + else + { + /* If the procedure requires explicit interface, actual argument + is passed according to corresponing formal argument. We + do not use g77 method and the address of array descriptor + is passed if corresponing formal is pointer or + assumed-shape, Otherwise use g77 method. */ + int f; + f = (formal != NULL) + && !formal->sym->attr.pointer + && formal->sym->as->type != AS_ASSUMED_SHAPE; + f = f || !sym->attr.always_explicit; + gfc_conv_array_parameter (&parmse, arg->expr, argss, f); + } + } + + gfc_add_block_to_block (&se->pre, &parmse.pre); + gfc_add_block_to_block (&se->post, &parmse.post); + + /* Character strings are passed as two paramarers, a length and a + pointer. */ + if (parmse.string_length != NULL_TREE) + stringargs = gfc_chainon_list (stringargs, parmse.string_length); + + arglist = gfc_chainon_list (arglist, parmse.expr); + } + + /* Add the hidden string length parameters to the arguments. */ + arglist = chainon (arglist, stringargs); + + /* Generate the actual call. */ + gfc_conv_function_val (se, sym); + /* If there are alternate return labels, function type should be + integer. */ + if (has_alternate_specifier) + TREE_TYPE (TREE_TYPE (TREE_TYPE (se->expr))) = integer_type_node; + + fntype = TREE_TYPE (TREE_TYPE (se->expr)); + se->expr = build (CALL_EXPR, TREE_TYPE (fntype), se->expr, + arglist, NULL_TREE); + +/* A pure function may still have side-effects - it may modify its + parameters. */ + TREE_SIDE_EFFECTS (se->expr) = 1; +#if 0 + if (!sym->attr.pure) + TREE_SIDE_EFFECTS (se->expr) = 1; +#endif + + if (byref && !se->direct_byref) + { + gfc_add_expr_to_block (&se->pre, se->expr); + + if (sym->result->attr.dimension) + { + if (flag_bounds_check) + { + /* Check the data pointer hasn't been modified. This would happen + in a function returning a pointer. */ + tmp = gfc_conv_descriptor_data (info->descriptor); + tmp = build (NE_EXPR, boolean_type_node, tmp, info->data); + gfc_trans_runtime_check (tmp, gfc_strconst_fault, &se->pre); + } + se->expr = info->descriptor; + } + else if (sym->ts.type == BT_CHARACTER) + { + se->expr = var; + se->string_length = len; + } + else + abort (); + } +} + + +/* Translate a statement function. + The value of a statement function reference is obtained by evaluating the + expression using the values of the actual arguments for the values of the + corresponding dummy arguments. */ + +static void +gfc_conv_statement_function (gfc_se * se, gfc_expr * expr) +{ + gfc_symbol *sym; + gfc_symbol *fsym; + gfc_formal_arglist *fargs; + gfc_actual_arglist *args; + gfc_se lse; + gfc_se rse; + + sym = expr->symtree->n.sym; + args = expr->value.function.actual; + gfc_init_se (&lse, NULL); + gfc_init_se (&rse, NULL); + + for (fargs = sym->formal; fargs; fargs = fargs->next) + { + /* Each dummy shall be specified, explicitly or implicitly, to be + scalar. */ + assert (fargs->sym->attr.dimension == 0); + fsym = fargs->sym; + assert (fsym->backend_decl); + + /* Convert non-pointer string dummy. */ + if (fsym->ts.type == BT_CHARACTER && !fsym->attr.pointer) + { + tree len1; + tree len2; + tree arg; + tree tmp; + tree type; + tree var; + + assert (fsym->ts.cl && fsym->ts.cl->length + && fsym->ts.cl->length->expr_type == EXPR_CONSTANT); + + type = gfc_get_character_type (fsym->ts.kind, fsym->ts.cl); + len1 = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); + var = gfc_build_addr_expr (build_pointer_type (type), + fsym->backend_decl); + + gfc_conv_expr (&rse, args->expr); + gfc_conv_string_parameter (&rse); + len2 = rse.string_length; + gfc_add_block_to_block (&se->pre, &lse.pre); + gfc_add_block_to_block (&se->pre, &rse.pre); + + arg = NULL_TREE; + arg = gfc_chainon_list (arg, len1); + arg = gfc_chainon_list (arg, var); + arg = gfc_chainon_list (arg, len2); + arg = gfc_chainon_list (arg, rse.expr); + tmp = gfc_build_function_call (gfor_fndecl_copy_string, arg); + gfc_add_expr_to_block (&se->pre, tmp); + gfc_add_block_to_block (&se->pre, &lse.post); + gfc_add_block_to_block (&se->pre, &rse.post); + } + else + { + /* For everything else, just evaluate the expression. */ + if (fsym->attr.pointer == 1) + lse.want_pointer = 1; + + gfc_conv_expr (&lse, args->expr); + + gfc_add_block_to_block (&se->pre, &lse.pre); + gfc_add_modify_expr (&se->pre, fsym->backend_decl, lse.expr); + gfc_add_block_to_block (&se->pre, &lse.post); + } + args = args->next; + } + gfc_conv_expr (se, sym->value); +} + + +/* Translate a function expression. */ + +static void +gfc_conv_function_expr (gfc_se * se, gfc_expr * expr) +{ + gfc_symbol *sym; + + if (expr->value.function.isym) + { + gfc_conv_intrinsic_function (se, expr); + return; + } + + /* We distinguish the statement function from general function to improve + runtime performance. */ + if (expr->symtree->n.sym->attr.proc == PROC_ST_FUNCTION) + { + gfc_conv_statement_function (se, expr); + return; + } + + /* expr.value.function.esym is the resolved (specific) function symbol for + most functions. However this isn't set for dummy procedures. */ + sym = expr->value.function.esym; + if (!sym) + sym = expr->symtree->n.sym; + gfc_conv_function_call (se, sym, expr->value.function.actual); +} + +static void +gfc_conv_array_constructor_expr (gfc_se * se, gfc_expr * expr) +{ + assert (se->ss != NULL && se->ss != gfc_ss_terminator); + assert (se->ss->expr == expr && se->ss->type == GFC_SS_CONSTRUCTOR); + + gfc_conv_tmp_array_ref (se); + gfc_advance_se_ss_chain (se); +} + + + +/* Build an expression for a constructor. If init is nonzero then + this is part of a static variable initializer. */ + +void +gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init) +{ + gfc_constructor *c; + gfc_component *cm; + tree head; + tree tail; + tree val; + gfc_se cse; + tree type; + tree arraytype; + + assert (expr->expr_type == EXPR_STRUCTURE); + type = gfc_typenode_for_spec (&expr->ts); + head = build1 (CONSTRUCTOR, type, NULL_TREE); + tail = NULL_TREE; + + cm = expr->ts.derived->components; + for (c = expr->value.constructor; c; c = c->next, cm = cm->next) + { + /* Skip absent members in default initializers. */ + if (!c->expr) + continue; + + gfc_init_se (&cse, se); + /* Evaluate the expression for this component. */ + if (init) + { + switch (c->expr->expr_type) + { + case EXPR_ARRAY: + arraytype = TREE_TYPE (cm->backend_decl); + cse.expr = gfc_conv_array_initializer (arraytype, c->expr); + break; + + case EXPR_STRUCTURE: + gfc_conv_structure (&cse, c->expr, 1); + break; + + default: + gfc_conv_expr (&cse, c->expr); + } + } + else + { + gfc_conv_expr (&cse, c->expr); + gfc_add_block_to_block (&se->pre, &cse.pre); + gfc_add_block_to_block (&se->post, &cse.post); + } + + /* Build a TREE_CHAIN to hold it. */ + val = tree_cons (cm->backend_decl, cse.expr, NULL_TREE); + + /* Add it to the list. */ + if (tail == NULL_TREE) + TREE_OPERAND(head, 0) = tail = val; + else + { + TREE_CHAIN (tail) = val; + tail = val; + } + } + se->expr = head; +} + + +/*translate a substring expression */ + +static void +gfc_conv_substring_expr (gfc_se * se, gfc_expr * expr) +{ + gfc_ref *ref; + + ref = expr->ref; + + assert(ref->type == REF_SUBSTRING); + + se->expr = gfc_build_string_const(expr->value.character.length, + expr->value.character.string); + se->string_length = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (se->expr))); + TYPE_STRING_FLAG (TREE_TYPE (se->expr))=1; + + gfc_conv_substring(se,ref,expr->ts.kind); +} + + +/* Entry point for expression translation. */ + +void +gfc_conv_expr (gfc_se * se, gfc_expr * expr) +{ + if (se->ss && se->ss->expr == expr + && (se->ss->type == GFC_SS_SCALAR || se->ss->type == GFC_SS_REFERENCE)) + { + /* Substiture a scalar expression evaluated outside the scalarization + loop. */ + se->expr = se->ss->data.scalar.expr; + se->string_length = se->ss->data.scalar.string_length; + gfc_advance_se_ss_chain (se); + return; + } + + switch (expr->expr_type) + { + case EXPR_OP: + gfc_conv_expr_op (se, expr); + break; + + case EXPR_FUNCTION: + gfc_conv_function_expr (se, expr); + break; + + case EXPR_CONSTANT: + gfc_conv_constant (se, expr); + break; + + case EXPR_VARIABLE: + gfc_conv_variable (se, expr); + break; + + case EXPR_NULL: + se->expr = null_pointer_node; + break; + + case EXPR_SUBSTRING: + gfc_conv_substring_expr (se, expr); + break; + + case EXPR_STRUCTURE: + gfc_conv_structure (se, expr, 0); + break; + + case EXPR_ARRAY: + gfc_conv_array_constructor_expr (se, expr); + break; + + default: + abort (); + break; + } +} + +void +gfc_conv_expr_lhs (gfc_se * se, gfc_expr * expr) +{ + gfc_conv_expr (se, expr); + /* AFAICS all numeric lvalues have empty post chains. If not we need to + figure out a way of rewriting an lvalue so that it has no post chain. */ + assert (expr->ts.type != BT_CHARACTER || !se->post.head); +} + +void +gfc_conv_expr_val (gfc_se * se, gfc_expr * expr) +{ + tree val; + + assert (expr->ts.type != BT_CHARACTER); + gfc_conv_expr (se, expr); + if (se->post.head) + { + val = gfc_create_var (TREE_TYPE (se->expr), NULL); + gfc_add_modify_expr (&se->pre, val, se->expr); + } +} + +void +gfc_conv_expr_type (gfc_se * se, gfc_expr * expr, tree type) +{ + gfc_conv_expr_val (se, expr); + se->expr = convert (type, se->expr); +} + + +/* Converts an expression so that it can be passed by refernece. Scalar + values only. */ + +void +gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr) +{ + tree var; + + if (se->ss && se->ss->expr == expr + && se->ss->type == GFC_SS_REFERENCE) + { + se->expr = se->ss->data.scalar.expr; + se->string_length = se->ss->data.scalar.string_length; + gfc_advance_se_ss_chain (se); + return; + } + + if (expr->ts.type == BT_CHARACTER) + { + gfc_conv_expr (se, expr); + gfc_conv_string_parameter (se); + return; + } + + if (expr->expr_type == EXPR_VARIABLE) + { + se->want_pointer = 1; + gfc_conv_expr (se, expr); + if (se->post.head) + { + var = gfc_create_var (TREE_TYPE (se->expr), NULL); + gfc_add_modify_expr (&se->pre, var, se->expr); + gfc_add_block_to_block (&se->pre, &se->post); + se->expr = var; + } + return; + } + + gfc_conv_expr (se, expr); + + /* Create a temporary var to hold the value. */ + var = gfc_create_var (TREE_TYPE (se->expr), NULL); + gfc_add_modify_expr (&se->pre, var, se->expr); + gfc_add_block_to_block (&se->pre, &se->post); + + /* Take the address of that value. */ + se->expr = gfc_build_addr_expr (NULL, var); +} + + +tree +gfc_trans_pointer_assign (gfc_code * code) +{ + return gfc_trans_pointer_assignment (code->expr, code->expr2); +} + + +tree +gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) +{ + gfc_se lse; + gfc_se rse; + gfc_ss *lss; + gfc_ss *rss; + stmtblock_t block; + tree tmp; + + gfc_start_block (&block); + + gfc_init_se (&lse, NULL); + + lss = gfc_walk_expr (expr1); + rss = gfc_walk_expr (expr2); + if (lss == gfc_ss_terminator) + { + lse.want_pointer = 1; + gfc_conv_expr (&lse, expr1); + assert (rss == gfc_ss_terminator); + gfc_init_se (&rse, NULL); + rse.want_pointer = 1; + gfc_conv_expr (&rse, expr2); + gfc_add_block_to_block (&block, &lse.pre); + gfc_add_block_to_block (&block, &rse.pre); + gfc_add_modify_expr (&block, lse.expr, rse.expr); + gfc_add_block_to_block (&block, &rse.post); + gfc_add_block_to_block (&block, &lse.post); + } + else + { + gfc_conv_expr_descriptor (&lse, expr1, lss); + /* Implement Nullify. */ + if (expr2->expr_type == EXPR_NULL) + { + lse.expr = gfc_conv_descriptor_data (lse.expr); + rse.expr = null_pointer_node; + tmp = build_v (MODIFY_EXPR, lse.expr, rse.expr); + gfc_add_expr_to_block (&block, tmp); + } + else + { + lse.direct_byref = 1; + gfc_conv_expr_descriptor (&lse, expr2, rss); + } + gfc_add_block_to_block (&block, &lse.pre); + gfc_add_block_to_block (&block, &lse.post); + } + return gfc_finish_block (&block); +} + + +/* Makes sure se is suitable for passing as a function string parameter. */ +/* TODO: Need to check all callers fo this function. It may be abused. */ + +void +gfc_conv_string_parameter (gfc_se * se) +{ + tree type; + + if (TREE_CODE (se->expr) == STRING_CST) + { + se->expr = gfc_build_addr_expr (pchar_type_node, se->expr); + return; + } + + type = TREE_TYPE (se->expr); + if (TYPE_STRING_FLAG (type)) + { + assert (TREE_CODE (se->expr) != INDIRECT_REF); + se->expr = gfc_build_addr_expr (pchar_type_node, se->expr); + } + + assert (POINTER_TYPE_P (TREE_TYPE (se->expr))); + assert (se->string_length + && TREE_CODE (TREE_TYPE (se->string_length)) == INTEGER_TYPE); +} + + +/* Generate code for assignment of scalar variables. Includes character + strings. */ + +tree +gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, bt type) +{ + tree tmp; + tree args; + stmtblock_t block; + + gfc_init_block (&block); + + + if (type == BT_CHARACTER) + { + args = NULL_TREE; + + assert (lse->string_length != NULL_TREE + && rse->string_length != NULL_TREE); + + gfc_conv_string_parameter (lse); + gfc_conv_string_parameter (rse); + + gfc_add_block_to_block (&block, &lse->pre); + gfc_add_block_to_block (&block, &rse->pre); + + args = gfc_chainon_list (args, lse->string_length); + args = gfc_chainon_list (args, lse->expr); + args = gfc_chainon_list (args, rse->string_length); + args = gfc_chainon_list (args, rse->expr); + + tmp = gfc_build_function_call (gfor_fndecl_copy_string, args); + gfc_add_expr_to_block (&block, tmp); + } + else + { + gfc_add_block_to_block (&block, &lse->pre); + gfc_add_block_to_block (&block, &rse->pre); + + gfc_add_modify_expr (&block, lse->expr, rse->expr); + } + + gfc_add_block_to_block (&block, &lse->post); + gfc_add_block_to_block (&block, &rse->post); + + return gfc_finish_block (&block); +} + + +/* Try to translate array(:) = func (...), where func is a transformational + array function, without using a temporary. Returns NULL is this isn't the + case. */ + +static tree +gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2) +{ + gfc_se se; + gfc_ss *ss; + + /* The caller has already checked rank>0 and expr_type == EXPR_FUNCTION. */ + if (expr2->value.function.isym && !gfc_is_intrinsic_libcall (expr2)) + return NULL; + + /* Elemental functions don't need a temporary anyway. */ + if (expr2->symtree->n.sym->attr.elemental) + return NULL; + + /* Check for a dependency. */ + if (gfc_check_fncall_dependency (expr1, expr2)) + return NULL; + + /* The frontend doesn't seem to bother filling in expr->symtree for intrinsic + functions. */ + assert (expr2->value.function.isym + || (gfc_return_by_reference (expr2->symtree->n.sym) + && expr2->symtree->n.sym->result->attr.dimension)); + + ss = gfc_walk_expr (expr1); + assert (ss != gfc_ss_terminator); + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + se.want_pointer = 1; + + gfc_conv_array_parameter (&se, expr1, ss, 0); + + se.direct_byref = 1; + se.ss = gfc_walk_expr (expr2); + assert (se.ss != gfc_ss_terminator); + gfc_conv_function_expr (&se, expr2); + gfc_add_expr_to_block (&se.pre, se.expr); + gfc_add_block_to_block (&se.pre, &se.post); + + return gfc_finish_block (&se.pre); +} + + +/* Translate an assignment. Most of the code is concerned with + setting up the scalarizer. */ + +tree +gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2) +{ + gfc_se lse; + gfc_se rse; + gfc_ss *lss; + gfc_ss *lss_section; + gfc_ss *rss; + gfc_loopinfo loop; + tree tmp; + stmtblock_t block; + stmtblock_t body; + + /* Special case a single function returning an array. */ + if (expr2->expr_type == EXPR_FUNCTION && expr2->rank > 0) + { + tmp = gfc_trans_arrayfunc_assign (expr1, expr2); + if (tmp) + return tmp; + } + + /* Assignment of the form lhs = rhs. */ + gfc_start_block (&block); + + gfc_init_se (&lse, NULL); + gfc_init_se (&rse, NULL); + + /* Walk the lhs. */ + lss = gfc_walk_expr (expr1); + rss = NULL; + if (lss != gfc_ss_terminator) + { + /* The assignment needs scalarization. */ + lss_section = lss; + + /* Find a non-scalar SS from the lhs. */ + while (lss_section != gfc_ss_terminator + && lss_section->type != GFC_SS_SECTION) + lss_section = lss_section->next; + + assert (lss_section != gfc_ss_terminator); + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + + /* Walk the rhs. */ + rss = gfc_walk_expr (expr2); + if (rss == gfc_ss_terminator) + { + /* The rhs is scalar. Add a ss for the expression. */ + rss = gfc_get_ss (); + rss->next = gfc_ss_terminator; + rss->type = GFC_SS_SCALAR; + rss->expr = expr2; + } + /* Associate the SS with the loop. */ + gfc_add_ss_to_loop (&loop, lss); + gfc_add_ss_to_loop (&loop, rss); + + /* Calculate the bounds of the scalarization. */ + gfc_conv_ss_startstride (&loop); + /* Resolve any data dependencies in the statement. */ + gfc_conv_resolve_dependencies (&loop, lss_section, rss); + /* Setup the scalarizing loops. */ + gfc_conv_loop_setup (&loop); + + /* Setup the gfc_se structures. */ + gfc_copy_loopinfo_to_se (&lse, &loop); + gfc_copy_loopinfo_to_se (&rse, &loop); + + rse.ss = rss; + gfc_mark_ss_chain_used (rss, 1); + if (loop.temp_ss == NULL) + { + lse.ss = lss; + gfc_mark_ss_chain_used (lss, 1); + } + else + { + lse.ss = loop.temp_ss; + gfc_mark_ss_chain_used (lss, 3); + gfc_mark_ss_chain_used (loop.temp_ss, 3); + } + + /* Start the scalarized loop body. */ + gfc_start_scalarized_body (&loop, &body); + } + else + gfc_init_block (&body); + + /* Translate the expression. */ + gfc_conv_expr (&rse, expr2); + + if (lss != gfc_ss_terminator && loop.temp_ss != NULL) + { + gfc_conv_tmp_array_ref (&lse); + gfc_advance_se_ss_chain (&lse); + } + else + gfc_conv_expr (&lse, expr1); + + tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts.type); + gfc_add_expr_to_block (&body, tmp); + + if (lss == gfc_ss_terminator) + { + /* Use the scalar assignment as is. */ + gfc_add_block_to_block (&block, &body); + } + else + { + if (lse.ss != gfc_ss_terminator) + abort (); + if (rse.ss != gfc_ss_terminator) + abort (); + + if (loop.temp_ss != NULL) + { + gfc_trans_scalarized_loop_boundary (&loop, &body); + + /* We need to copy the temporary to the actual lhs. */ + gfc_init_se (&lse, NULL); + gfc_init_se (&rse, NULL); + gfc_copy_loopinfo_to_se (&lse, &loop); + gfc_copy_loopinfo_to_se (&rse, &loop); + + rse.ss = loop.temp_ss; + lse.ss = lss; + + gfc_conv_tmp_array_ref (&rse); + gfc_advance_se_ss_chain (&rse); + gfc_conv_expr (&lse, expr1); + + if (lse.ss != gfc_ss_terminator) + abort (); + + if (rse.ss != gfc_ss_terminator) + abort (); + + tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts.type); + gfc_add_expr_to_block (&body, tmp); + } + /* Generate the copying loops. */ + gfc_trans_scalarizing_loops (&loop, &body); + + /* Wrap the whole thing up. */ + gfc_add_block_to_block (&block, &loop.pre); + gfc_add_block_to_block (&block, &loop.post); + + gfc_cleanup_loop (&loop); + } + + return gfc_finish_block (&block); +} + +tree +gfc_trans_assign (gfc_code * code) +{ + return gfc_trans_assignment (code->expr, code->expr2); +} diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c new file mode 100644 index 00000000000..fb3ceb2f6b1 --- /dev/null +++ b/gcc/fortran/trans-intrinsic.c @@ -0,0 +1,3003 @@ +/* Intrinsic translation + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Paul Brook + and Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* trans-intrinsic.c-- generate GENERIC trees for calls to intrinsics. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include +#include +#include "ggc.h" +#include "toplev.h" +#include "real.h" +#include "tree-simple.h" +#include "flags.h" +#include +#include +#include "gfortran.h" +#include "intrinsic.h" +#include "trans.h" +#include "trans-const.h" +#include "trans-types.h" +#include "trans-array.h" +#include "defaults.h" +/* Only for gfc_trans_assign and gfc_trans_pointer_assign. */ +#include "trans-stmt.h" + +/* This maps fortran intrinsic math functions to external library or GCC + builtin functions. */ +typedef struct gfc_intrinsic_map_t GTY(()) +{ + /* The explicit enum is required to work around inadequacies in the + garbage collection/gengtype parsing mechanism. */ + enum gfc_generic_isym_id id; + + /* Enum value from the "language-independent", aka C-centric, part + of gcc, or END_BUILTINS of no such value set. */ + /* ??? There are now complex variants in builtins.def, though we + don't currently do anything with them. */ + enum built_in_function code4; + enum built_in_function code8; + + /* True if the naming pattern is to prepend "c" for complex and + append "f" for kind=4. False if the naming pattern is to + prepend "_gfortran_" and append "[rc][48]". */ + bool libm_name; + + /* True if a complex version of the function exists. */ + bool complex_available; + + /* True if the function should be marked const. */ + bool is_constant; + + /* The base library name of this function. */ + const char *name; + + /* Cache decls created for the various operand types. */ + tree real4_decl; + tree real8_decl; + tree complex4_decl; + tree complex8_decl; +} +gfc_intrinsic_map_t; + +/* ??? The NARGS==1 hack here is based on the fact that (c99 at least) + defines complex variants of all of the entries in mathbuiltins.def + except for atan2. */ +#define DEFINE_MATH_BUILTIN(ID, NAME, NARGS) \ + { GFC_ISYM_ ## ID, BUILT_IN_ ## ID ## F, BUILT_IN_ ## ID, true, \ + NARGS == 1, true, NAME, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE}, + +#define LIBM_FUNCTION(ID, NAME, HAVE_COMPLEX) \ + { GFC_ISYM_ ## ID, END_BUILTINS, END_BUILTINS, true, HAVE_COMPLEX, true, \ + NAME, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE } + +#define LIBF_FUNCTION(ID, NAME, HAVE_COMPLEX) \ + { GFC_ISYM_ ## ID, END_BUILTINS, END_BUILTINS, false, HAVE_COMPLEX, true, \ + NAME, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE } + +static GTY(()) gfc_intrinsic_map_t gfc_intrinsic_map[] = +{ + /* Functions built into gcc itself. */ +#include "mathbuiltins.def" + + /* Functions in libm. */ + /* ??? This does exist as BUILT_IN_SCALBN, but doesn't quite fit the + pattern for other mathbuiltins.def entries. At present we have no + optimizations for this in the common sources. */ + LIBM_FUNCTION (SCALE, "scalbn", false), + + /* Functions in libgfortran. */ + LIBF_FUNCTION (FRACTION, "fraction", false), + LIBF_FUNCTION (NEAREST, "nearest", false), + LIBF_FUNCTION (SET_EXPONENT, "set_exponent", false), + + /* End the list. */ + LIBF_FUNCTION (NONE, NULL, false) +}; +#undef DEFINE_MATH_BUILTIN +#undef LIBM_FUNCTION +#undef LIBF_FUNCTION + +/* Structure for storing components of a floating number to be used by + elemental functions to manipulate reals. */ +typedef struct +{ + tree arg; /* Variable tree to view convert to integer. */ + tree expn; /* Variable tree to save exponent. */ + tree frac; /* Variable tree to save fraction. */ + tree smask; /* Constant tree of sign's mask. */ + tree emask; /* Constant tree of exponent's mask. */ + tree fmask; /* Constant tree of fraction's mask. */ + tree edigits; /* Constant tree of bit numbers of exponent. */ + tree fdigits; /* Constant tree of bit numbers of fraction. */ + tree f1; /* Constant tree of the f1 defined in the real model. */ + tree bias; /* Constant tree of the bias of exponent in the memory. */ + tree type; /* Type tree of arg1. */ + tree mtype; /* Type tree of integer type. Kind is that of arg1. */ +} +real_compnt_info; + + +/* Evaluate the arguments to an intrinsic function. */ + +static tree +gfc_conv_intrinsic_function_args (gfc_se * se, gfc_expr * expr) +{ + gfc_actual_arglist *actual; + tree args; + gfc_se argse; + + args = NULL_TREE; + for (actual = expr->value.function.actual; actual; actual = actual->next) + { + /* Skip ommitted optional arguments. */ + if (!actual->expr) + continue; + + /* Evaluate the parameter. This will substitute scalarized + references automatically. */ + gfc_init_se (&argse, se); + + if (actual->expr->ts.type == BT_CHARACTER) + { + gfc_conv_expr (&argse, actual->expr); + gfc_conv_string_parameter (&argse); + args = gfc_chainon_list (args, argse.string_length); + } + else + gfc_conv_expr_val (&argse, actual->expr); + + gfc_add_block_to_block (&se->pre, &argse.pre); + gfc_add_block_to_block (&se->post, &argse.post); + args = gfc_chainon_list (args, argse.expr); + } + return args; +} + + +/* Conversions between different types are output by the frontend as + intrinsic functions. We implement these directly with inline code. */ + +static void +gfc_conv_intrinsic_conversion (gfc_se * se, gfc_expr * expr) +{ + tree type; + tree arg; + + /* Evaluate the argument. */ + type = gfc_typenode_for_spec (&expr->ts); + assert (expr->value.function.actual->expr); + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (arg); + + /* Conversion from complex to non-complex involves taking the real + component of the value. */ + if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE + && expr->ts.type != BT_COMPLEX) + { + tree artype; + + artype = TREE_TYPE (TREE_TYPE (arg)); + arg = build1 (REALPART_EXPR, artype, arg); + } + + se->expr = convert (type, arg); +} + + +/* This is needed because the gcc backend only implements FIX_TRUNC_EXPR + TRUNC(x) = INT(x) <= x ? INT(x) : INT(x) - 1 + Similarly for CEILING. */ + +static tree +build_fixbound_expr (stmtblock_t * pblock, tree arg, tree type, int up) +{ + tree tmp; + tree cond; + tree argtype; + tree intval; + + argtype = TREE_TYPE (arg); + arg = gfc_evaluate_now (arg, pblock); + + intval = convert (type, arg); + intval = gfc_evaluate_now (intval, pblock); + + tmp = convert (argtype, intval); + cond = build (up ? GE_EXPR : LE_EXPR, boolean_type_node, tmp, arg); + + tmp = build (up ? PLUS_EXPR : MINUS_EXPR, type, intval, integer_one_node); + tmp = build (COND_EXPR, type, cond, intval, tmp); + return tmp; +} + + +/* This is needed because the gcc backend only implements FIX_TRUNC_EXPR + NINT(x) = INT(x + ((x > 0) ? 0.5 : -0.5)). */ + +static tree +build_round_expr (stmtblock_t * pblock, tree arg, tree type) +{ + tree tmp; + tree cond; + tree neg; + tree pos; + tree argtype; + REAL_VALUE_TYPE r; + + argtype = TREE_TYPE (arg); + arg = gfc_evaluate_now (arg, pblock); + + real_from_string (&r, "0.5"); + pos = build_real (argtype, r); + + real_from_string (&r, "-0.5"); + neg = build_real (argtype, r); + + tmp = gfc_build_const (argtype, integer_zero_node); + cond = fold (build (GT_EXPR, boolean_type_node, arg, tmp)); + + tmp = fold (build (COND_EXPR, argtype, cond, pos, neg)); + tmp = fold (build (PLUS_EXPR, argtype, arg, tmp)); + return fold (build1 (FIX_TRUNC_EXPR, type, tmp)); +} + + +/* Convert a real to an integer using a specific rounding mode. + Ideally we would just build the corresponding GENERIC node, + however the RTL expander only actually supports FIX_TRUNC_EXPR. */ + +static tree +build_fix_expr (stmtblock_t * pblock, tree arg, tree type, int op) +{ + switch (op) + { + case FIX_FLOOR_EXPR: + return build_fixbound_expr (pblock, arg, type, 0); + break; + + case FIX_CEIL_EXPR: + return build_fixbound_expr (pblock, arg, type, 1); + break; + + case FIX_ROUND_EXPR: + return build_round_expr (pblock, arg, type); + + default: + return build1 (op, type, arg); + } +} + + +/* Round a real value using the specified rounding mode. + We use a temporary integer of that same kind size as the result. + Values larger than can be represented by this kind are unchanged, as + will not be accurate enough to represent the rounding. + huge = HUGE (KIND (a)) + aint (a) = ((a > huge) || (a < -huge)) ? a : (real)(int)a + */ + +static void +gfc_conv_intrinsic_aint (gfc_se * se, gfc_expr * expr, int op) +{ + tree type; + tree itype; + tree arg; + tree tmp; + tree cond; + mpf_t huge; + int n; + int kind; + + kind = expr->ts.kind; + + n = END_BUILTINS; + /* We have builtin functions for some cases. */ + switch (op) + { + case FIX_ROUND_EXPR: + switch (kind) + { + case 4: + n = BUILT_IN_ROUNDF; + break; + + case 8: + n = BUILT_IN_ROUND; + break; + } + break; + + case FIX_FLOOR_EXPR: + switch (kind) + { + case 4: + n = BUILT_IN_FLOORF; + break; + + case 8: + n = BUILT_IN_FLOOR; + break; + } + } + + /* Evaluate the argument. */ + assert (expr->value.function.actual->expr); + arg = gfc_conv_intrinsic_function_args (se, expr); + + /* Use a builtin function if one exists. */ + if (n != END_BUILTINS) + { + tmp = built_in_decls[n]; + se->expr = gfc_build_function_call (tmp, arg); + return; + } + + /* This code is probably redundant, but we'll keep it lying around just + in case. */ + type = gfc_typenode_for_spec (&expr->ts); + arg = TREE_VALUE (arg); + arg = gfc_evaluate_now (arg, &se->pre); + + /* Test if the value is too large to handle sensibly. */ + mpf_init (huge); + n = gfc_validate_kind (BT_INTEGER, kind); + mpf_set_z (huge, gfc_integer_kinds[n].huge); + tmp = gfc_conv_mpf_to_tree (huge, kind); + cond = build (LT_EXPR, boolean_type_node, arg, tmp); + + mpf_neg (huge, huge); + tmp = gfc_conv_mpf_to_tree (huge, kind); + tmp = build (GT_EXPR, boolean_type_node, arg, tmp); + cond = build (TRUTH_AND_EXPR, boolean_type_node, cond, tmp); + itype = gfc_get_int_type (kind); + + tmp = build_fix_expr (&se->pre, arg, itype, op); + tmp = convert (type, tmp); + se->expr = build (COND_EXPR, type, cond, tmp, arg); +} + + +/* Convert to an integer using the specified rounding mode. */ + +static void +gfc_conv_intrinsic_int (gfc_se * se, gfc_expr * expr, int op) +{ + tree type; + tree arg; + + /* Evaluate the argument. */ + type = gfc_typenode_for_spec (&expr->ts); + assert (expr->value.function.actual->expr); + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (arg); + + if (TREE_CODE (TREE_TYPE (arg)) == INTEGER_TYPE) + { + /* Conversion to a different integer kind. */ + se->expr = convert (type, arg); + } + else + { + /* Conversion from complex to non-complex involves taking the real + component of the value. */ + if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE + && expr->ts.type != BT_COMPLEX) + { + tree artype; + + artype = TREE_TYPE (TREE_TYPE (arg)); + arg = build1 (REALPART_EXPR, artype, arg); + } + + se->expr = build_fix_expr (&se->pre, arg, type, op); + } +} + + +/* Get the imaginary component of a value. */ + +static void +gfc_conv_intrinsic_imagpart (gfc_se * se, gfc_expr * expr) +{ + tree arg; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (arg); + se->expr = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg); +} + + +/* Get the complex conjugate of a value. */ + +static void +gfc_conv_intrinsic_conjg (gfc_se * se, gfc_expr * expr) +{ + tree arg; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (arg); + se->expr = build1 (CONJ_EXPR, TREE_TYPE (arg), arg); +} + + +/* Initialize function decls for library functions. The external functions + are created as required. Builtin functions are added here. */ + +void +gfc_build_intrinsic_lib_fndecls (void) +{ + gfc_intrinsic_map_t *m; + + /* Add GCC builtin functions. */ + for (m = gfc_intrinsic_map; m->id != GFC_ISYM_NONE; m++) + { + if (m->code4 != END_BUILTINS) + m->real4_decl = built_in_decls[m->code4]; + if (m->code8 != END_BUILTINS) + m->real8_decl = built_in_decls[m->code8]; + } +} + + +/* Create a fndecl for a simple intrinsic library function. */ + +static tree +gfc_get_intrinsic_lib_fndecl (gfc_intrinsic_map_t * m, gfc_expr * expr) +{ + tree type; + tree argtypes; + tree fndecl; + gfc_actual_arglist *actual; + tree *pdecl; + gfc_typespec *ts; + char name[GFC_MAX_SYMBOL_LEN + 3]; + + ts = &expr->ts; + if (ts->type == BT_REAL) + { + switch (ts->kind) + { + case 4: + pdecl = &m->real4_decl; + break; + case 8: + pdecl = &m->real8_decl; + break; + default: + abort (); + } + } + else if (ts->type == BT_COMPLEX) + { + if (!m->complex_available) + abort (); + + switch (ts->kind) + { + case 4: + pdecl = &m->complex4_decl; + break; + case 8: + pdecl = &m->complex8_decl; + break; + default: + abort (); + } + } + else + abort (); + + if (*pdecl) + return *pdecl; + + if (m->libm_name) + { + if (ts->kind != 4 && ts->kind != 8) + abort (); + snprintf (name, sizeof (name), "%s%s%s", + ts->type == BT_COMPLEX ? "c" : "", + m->name, + ts->kind == 4 ? "f" : ""); + } + else + { + snprintf (name, sizeof (name), PREFIX ("%s_%c%d"), m->name, + ts->type == BT_COMPLEX ? 'c' : 'r', + ts->kind); + } + + argtypes = NULL_TREE; + for (actual = expr->value.function.actual; actual; actual = actual->next) + { + type = gfc_typenode_for_spec (&actual->expr->ts); + argtypes = gfc_chainon_list (argtypes, type); + } + argtypes = gfc_chainon_list (argtypes, void_type_node); + type = build_function_type (gfc_typenode_for_spec (ts), argtypes); + fndecl = build_decl (FUNCTION_DECL, get_identifier (name), type); + + /* Mark the decl as external. */ + DECL_EXTERNAL (fndecl) = 1; + TREE_PUBLIC (fndecl) = 1; + + /* Mark it __attribute__((const)), if possible. */ + TREE_READONLY (fndecl) = m->is_constant; + + rest_of_decl_compilation (fndecl, NULL, 1, 0); + + (*pdecl) = fndecl; + return fndecl; +} + + +/* Convert an intrinsic function into an external or builtin call. */ + +static void +gfc_conv_intrinsic_lib_function (gfc_se * se, gfc_expr * expr) +{ + gfc_intrinsic_map_t *m; + tree args; + tree fndecl; + gfc_generic_isym_id id; + + id = expr->value.function.isym->generic_id; + /* Find the entry for this function. */ + for (m = gfc_intrinsic_map; m->id != GFC_ISYM_NONE; m++) + { + if (id == m->id) + break; + } + + if (m->id == GFC_ISYM_NONE) + { + internal_error ("Intrinsic function %s(%d) not recognized", + expr->value.function.name, id); + } + + /* Get the decl and generate the call. */ + args = gfc_conv_intrinsic_function_args (se, expr); + fndecl = gfc_get_intrinsic_lib_fndecl (m, expr); + se->expr = gfc_build_function_call (fndecl, args); +} + +/* Generate code for EXPONENT(X) intrinsic function. */ + +static void +gfc_conv_intrinsic_exponent (gfc_se * se, gfc_expr * expr) +{ + tree args, fndecl; + gfc_expr *a1; + + args = gfc_conv_intrinsic_function_args (se, expr); + + a1 = expr->value.function.actual->expr; + switch (a1->ts.kind) + { + case 4: + fndecl = gfor_fndecl_math_exponent4; + break; + case 8: + fndecl = gfor_fndecl_math_exponent8; + break; + default: + abort (); + } + + se->expr = gfc_build_function_call (fndecl, args); +} + +/* Evaluate a single upper or lower bound. */ +/* TODO: bound intrinsic generates way too much unneccessary code. */ + +static void +gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper) +{ + gfc_actual_arglist *arg; + gfc_actual_arglist *arg2; + tree desc; + tree type; + tree bound; + tree tmp; + tree cond; + gfc_se argse; + gfc_ss *ss; + int i; + + gfc_init_se (&argse, NULL); + arg = expr->value.function.actual; + arg2 = arg->next; + + if (se->ss) + { + /* Create an implicit second parameter from the loop variable. */ + assert (!arg2->expr); + assert (se->loop->dimen == 1); + assert (se->ss->expr == expr); + gfc_advance_se_ss_chain (se); + bound = se->loop->loopvar[0]; + bound = fold (build (MINUS_EXPR, gfc_array_index_type, bound, + se->loop->from[0])); + } + else + { + /* use the passed argument. */ + assert (arg->next->expr); + gfc_init_se (&argse, NULL); + gfc_conv_expr_type (&argse, arg->next->expr, gfc_array_index_type); + gfc_add_block_to_block (&se->pre, &argse.pre); + bound = argse.expr; + /* Convert from one based to zero based. */ + bound = fold (build (MINUS_EXPR, gfc_array_index_type, bound, + integer_one_node)); + } + + /* TODO: don't re-evaluate the descriptor on each iteration. */ + /* Get a descriptor for the first parameter. */ + ss = gfc_walk_expr (arg->expr); + assert (ss != gfc_ss_terminator); + argse.want_pointer = 0; + gfc_conv_expr_descriptor (&argse, arg->expr, ss); + gfc_add_block_to_block (&se->pre, &argse.pre); + gfc_add_block_to_block (&se->post, &argse.post); + + desc = argse.expr; + + if (INTEGER_CST_P (bound)) + { + assert (TREE_INT_CST_HIGH (bound) == 0); + i = TREE_INT_CST_LOW (bound); + assert (i >= 0 && i < GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc))); + } + else + { + if (flag_bounds_check) + { + bound = gfc_evaluate_now (bound, &se->pre); + cond = fold (build (LT_EXPR, boolean_type_node, bound, + integer_zero_node)); + tmp = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc))]; + tmp = fold (build (GE_EXPR, boolean_type_node, bound, tmp)); + cond = fold(build (TRUTH_ORIF_EXPR, boolean_type_node, cond, tmp)); + gfc_trans_runtime_check (cond, gfc_strconst_fault, &se->pre); + } + } + + if (upper) + se->expr = gfc_conv_descriptor_ubound(desc, bound); + else + se->expr = gfc_conv_descriptor_lbound(desc, bound); + + type = gfc_typenode_for_spec (&expr->ts); + se->expr = convert (type, se->expr); +} + + +static void +gfc_conv_intrinsic_abs (gfc_se * se, gfc_expr * expr) +{ + tree args; + tree val; + tree fndecl; + + args = gfc_conv_intrinsic_function_args (se, expr); + assert (args && TREE_CHAIN (args) == NULL_TREE); + val = TREE_VALUE (args); + + switch (expr->value.function.actual->expr->ts.type) + { + case BT_INTEGER: + case BT_REAL: + se->expr = build1 (ABS_EXPR, TREE_TYPE (val), val); + break; + + case BT_COMPLEX: + switch (expr->ts.kind) + { + case 4: + fndecl = gfor_fndecl_math_cabsf; + break; + case 8: + fndecl = gfor_fndecl_math_cabs; + break; + default: + abort (); + } + se->expr = gfc_build_function_call (fndecl, args); + break; + + default: + abort (); + } +} + + +/* Create a complex value from one or two real components. */ + +static void +gfc_conv_intrinsic_cmplx (gfc_se * se, gfc_expr * expr, int both) +{ + tree arg; + tree real; + tree imag; + tree type; + + type = gfc_typenode_for_spec (&expr->ts); + arg = gfc_conv_intrinsic_function_args (se, expr); + real = convert (TREE_TYPE (type), TREE_VALUE (arg)); + if (both) + imag = convert (TREE_TYPE (type), TREE_VALUE (TREE_CHAIN (arg))); + else if (TREE_CODE (TREE_TYPE (TREE_VALUE (arg))) == COMPLEX_TYPE) + { + arg = TREE_VALUE (arg); + imag = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg); + imag = convert (TREE_TYPE (type), imag); + } + else + imag = build_real_from_int_cst (TREE_TYPE (type), integer_zero_node); + + se->expr = fold (build (COMPLEX_EXPR, type, real, imag)); +} + +/* Remainder function MOD(A, P) = A - INT(A / P) * P. + MODULO(A, P) = (A==0 .or. !(A>0 .xor. P>0))? MOD(A,P):MOD(A,P)+P. */ +/* TODO: MOD(x, 0) */ + +static void +gfc_conv_intrinsic_mod (gfc_se * se, gfc_expr * expr, int modulo) +{ + tree arg; + tree arg2; + tree type; + tree itype; + tree tmp; + tree zero; + tree test; + tree test2; + mpf_t huge; + int n; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + type = TREE_TYPE (arg); + + switch (expr->ts.type) + { + case BT_INTEGER: + /* Integer case is easy, we've got a builtin op. */ + se->expr = build (TRUNC_MOD_EXPR, type, arg, arg2); + break; + + case BT_REAL: + /* Real values we have to do the hard way. */ + arg = gfc_evaluate_now (arg, &se->pre); + arg2 = gfc_evaluate_now (arg2, &se->pre); + + tmp = build (RDIV_EXPR, type, arg, arg2); + /* Test if the value is too large to handle sensibly. */ + mpf_init (huge); + n = gfc_validate_kind (BT_INTEGER, expr->ts.kind); + mpf_set_z (huge, gfc_integer_kinds[n].huge); + test = gfc_conv_mpf_to_tree (huge, expr->ts.kind); + test2 = build (LT_EXPR, boolean_type_node, tmp, test); + + mpf_neg (huge, huge); + test = gfc_conv_mpf_to_tree (huge, expr->ts.kind); + test = build (GT_EXPR, boolean_type_node, tmp, test); + test2 = build (TRUTH_AND_EXPR, boolean_type_node, test, test2); + + itype = gfc_get_int_type (expr->ts.kind); + tmp = build_fix_expr (&se->pre, tmp, itype, FIX_TRUNC_EXPR); + tmp = convert (type, tmp); + tmp = build (COND_EXPR, type, test2, tmp, arg); + tmp = build (MULT_EXPR, type, tmp, arg2); + se->expr = build (MINUS_EXPR, type, arg, tmp); + break; + + default: + abort (); + } + + if (modulo) + { + zero = gfc_build_const (type, integer_zero_node); + /* Build !(A > 0 .xor. P > 0). */ + test = build (GT_EXPR, boolean_type_node, arg, zero); + test2 = build (GT_EXPR, boolean_type_node, arg2, zero); + test = build (TRUTH_XOR_EXPR, boolean_type_node, test, test2); + test = build1 (TRUTH_NOT_EXPR, boolean_type_node, test); + /* Build (A == 0) .or. !(A > 0 .xor. P > 0). */ + test2 = build (EQ_EXPR, boolean_type_node, arg, zero); + test = build (TRUTH_OR_EXPR, boolean_type_node, test, test2); + + se->expr = build (COND_EXPR, type, test, se->expr, + build (PLUS_EXPR, type, se->expr, arg2)); + } +} + +/* Positive difference DIM (x, y) = ((x - y) < 0) ? 0 : x - y. */ + +static void +gfc_conv_intrinsic_dim (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree arg2; + tree val; + tree tmp; + tree type; + tree zero; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + type = TREE_TYPE (arg); + + val = build (MINUS_EXPR, type, arg, arg2); + val = gfc_evaluate_now (val, &se->pre); + + zero = gfc_build_const (type, integer_zero_node); + tmp = build (LE_EXPR, boolean_type_node, val, zero); + se->expr = build (COND_EXPR, type, tmp, zero, val); +} + + +/* SIGN(A, B) is absolute value of A times sign of B. + The real value versions use library functions to ensure the correct + handling of negative zero. Integer case implemented as: + SIGN(A, B) = ((a >= 0) .xor. (b >= 0)) ? a : -a + */ + +static void +gfc_conv_intrinsic_sign (gfc_se * se, gfc_expr * expr) +{ + tree tmp; + tree arg; + tree arg2; + tree type; + tree zero; + tree testa; + tree testb; + + + arg = gfc_conv_intrinsic_function_args (se, expr); + if (expr->ts.type == BT_REAL) + { + switch (expr->ts.kind) + { + case 4: + tmp = gfor_fndecl_math_sign4; + break; + case 8: + tmp = gfor_fndecl_math_sign8; + break; + default: + abort (); + } + se->expr = gfc_build_function_call (tmp, arg); + return; + } + + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + type = TREE_TYPE (arg); + zero = gfc_build_const (type, integer_zero_node); + + testa = fold (build (GE_EXPR, boolean_type_node, arg, zero)); + testb = fold (build (GE_EXPR, boolean_type_node, arg2, zero)); + tmp = fold (build (TRUTH_XOR_EXPR, boolean_type_node, testa, testb)); + se->expr = fold (build (COND_EXPR, type, tmp, + build1 (NEGATE_EXPR, type, arg), arg)); +} + + +/* Test for the presence of an optional argument. */ + +static void +gfc_conv_intrinsic_present (gfc_se * se, gfc_expr * expr) +{ + gfc_expr *arg; + + arg = expr->value.function.actual->expr; + assert (arg->expr_type == EXPR_VARIABLE); + se->expr = gfc_conv_expr_present (arg->symtree->n.sym); + se->expr = convert (gfc_typenode_for_spec (&expr->ts), se->expr); +} + + +/* Calculate the double precision product of two single precision values. */ + +static void +gfc_conv_intrinsic_dprod (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree arg2; + tree type; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + + /* Convert the args to double precision before multiplying. */ + type = gfc_typenode_for_spec (&expr->ts); + arg = convert (type, arg); + arg2 = convert (type, arg2); + se->expr = build (MULT_EXPR, type, arg, arg2); +} + + +/* Return a length one character string containing an ascii character. */ + +static void +gfc_conv_intrinsic_char (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree var; + tree type; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (arg); + + /* We currently don't support character types != 1. */ + assert (expr->ts.kind == 1); + type = gfc_character1_type_node; + var = gfc_create_var (type, "char"); + + arg = convert (type, arg); + gfc_add_modify_expr (&se->pre, var, arg); + se->expr = gfc_build_addr_expr (build_pointer_type (type), var); + se->string_length = integer_one_node; +} + + +/* Get the minimum/maximum value of all the parameters. + minmax (a1, a2, a3, ...) + { + if (a2 .op. a1) + mvar = a2; + else + mvar = a1; + if (a3 .op. mvar) + mvar = a3; + ... + return mvar + } + */ + +/* TODO: Mismatching types can occur when specific names are used. + These should be handled during resolution. */ +static void +gfc_conv_intrinsic_minmax (gfc_se * se, gfc_expr * expr, int op) +{ + tree limit; + tree tmp; + tree mvar; + tree val; + tree thencase; + tree elsecase; + tree arg; + tree type; + + arg = gfc_conv_intrinsic_function_args (se, expr); + type = gfc_typenode_for_spec (&expr->ts); + + limit = TREE_VALUE (arg); + if (TREE_TYPE (limit) != type) + limit = convert (type, limit); + /* Only evaluate the argument once. */ + if (TREE_CODE (limit) != VAR_DECL && !TREE_CONSTANT (limit)) + limit = gfc_evaluate_now(limit, &se->pre); + + mvar = gfc_create_var (type, "M"); + elsecase = build_v (MODIFY_EXPR, mvar, limit); + for (arg = TREE_CHAIN (arg); arg != NULL_TREE; arg = TREE_CHAIN (arg)) + { + val = TREE_VALUE (arg); + if (TREE_TYPE (val) != type) + val = convert (type, val); + + /* Only evaluate the argument once. */ + if (TREE_CODE (val) != VAR_DECL && !TREE_CONSTANT (val)) + val = gfc_evaluate_now(val, &se->pre); + + thencase = build_v (MODIFY_EXPR, mvar, convert (type, val)); + + tmp = build (op, boolean_type_node, val, limit); + tmp = build_v (COND_EXPR, tmp, thencase, elsecase); + gfc_add_expr_to_block (&se->pre, tmp); + elsecase = build_empty_stmt (); + limit = mvar; + } + se->expr = mvar; +} + + +/* Create a symbol node for this intrinsic. The symbol form the frontend + is for the generic name. */ + +static gfc_symbol * +gfc_get_symbol_for_expr (gfc_expr * expr) +{ + gfc_symbol *sym; + + /* TODO: Add symbols for intrinsic function to the global namespace. */ + assert (strlen (expr->value.function.name) <= GFC_MAX_SYMBOL_LEN - 5); + sym = gfc_new_symbol (expr->value.function.name, NULL); + + sym->ts = expr->ts; + sym->attr.external = 1; + sym->attr.function = 1; + sym->attr.always_explicit = 1; + sym->attr.proc = PROC_INTRINSIC; + sym->attr.flavor = FL_PROCEDURE; + sym->result = sym; + if (expr->rank > 0) + { + sym->attr.dimension = 1; + sym->as = gfc_get_array_spec (); + sym->as->type = AS_ASSUMED_SHAPE; + sym->as->rank = expr->rank; + } + + /* TODO: proper argument lists for external intrinsics. */ + return sym; +} + +/* Generate a call to an external intrinsic function. */ +static void +gfc_conv_intrinsic_funcall (gfc_se * se, gfc_expr * expr) +{ + gfc_symbol *sym; + + assert (!se->ss || se->ss->expr == expr); + + if (se->ss) + assert (expr->rank > 0); + else + assert (expr->rank == 0); + + sym = gfc_get_symbol_for_expr (expr); + gfc_conv_function_call (se, sym, expr->value.function.actual); + gfc_free (sym); +} + +/* ANY and ALL intrinsics. ANY->op == NE_EXPR, ALL->op == EQ_EXPR. + Implemented as + any(a) + { + forall (i=...) + if (a[i] != 0) + return 1 + end forall + return 0 + } + all(a) + { + forall (i=...) + if (a[i] == 0) + return 0 + end forall + return 1 + } + */ +static void +gfc_conv_intrinsic_anyall (gfc_se * se, gfc_expr * expr, int op) +{ + tree resvar; + stmtblock_t block; + stmtblock_t body; + tree type; + tree tmp; + tree found; + gfc_loopinfo loop; + gfc_actual_arglist *actual; + gfc_ss *arrayss; + gfc_se arrayse; + tree exit_label; + + if (se->ss) + { + gfc_conv_intrinsic_funcall (se, expr); + return; + } + + actual = expr->value.function.actual; + type = gfc_typenode_for_spec (&expr->ts); + /* Initialize the result. */ + resvar = gfc_create_var (type, "test"); + if (op == EQ_EXPR) + tmp = convert (type, boolean_true_node); + else + tmp = convert (type, boolean_false_node); + gfc_add_modify_expr (&se->pre, resvar, tmp); + + /* Walk the arguments. */ + arrayss = gfc_walk_expr (actual->expr); + assert (arrayss != gfc_ss_terminator); + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + exit_label = gfc_build_label_decl (NULL_TREE); + TREE_USED (exit_label) = 1; + gfc_add_ss_to_loop (&loop, arrayss); + + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + gfc_mark_ss_chain_used (arrayss, 1); + /* Generate the loop body. */ + gfc_start_scalarized_body (&loop, &body); + + /* If the condition matches then set the return value. */ + gfc_start_block (&block); + if (op == EQ_EXPR) + tmp = convert (type, boolean_false_node); + else + tmp = convert (type, boolean_true_node); + gfc_add_modify_expr (&block, resvar, tmp); + + /* And break out of the loop. */ + tmp = build1_v (GOTO_EXPR, exit_label); + gfc_add_expr_to_block (&block, tmp); + + found = gfc_finish_block (&block); + + /* Check this element. */ + gfc_init_se (&arrayse, NULL); + gfc_copy_loopinfo_to_se (&arrayse, &loop); + arrayse.ss = arrayss; + gfc_conv_expr_val (&arrayse, actual->expr); + + gfc_add_block_to_block (&body, &arrayse.pre); + tmp = build (op, boolean_type_node, arrayse.expr, integer_zero_node); + tmp = build_v (COND_EXPR, tmp, found, build_empty_stmt ()); + gfc_add_expr_to_block (&body, tmp); + gfc_add_block_to_block (&body, &arrayse.post); + + gfc_trans_scalarizing_loops (&loop, &body); + + /* Add the exit label. */ + tmp = build1_v (LABEL_EXPR, exit_label); + gfc_add_expr_to_block (&loop.pre, tmp); + + gfc_add_block_to_block (&se->pre, &loop.pre); + gfc_add_block_to_block (&se->pre, &loop.post); + gfc_cleanup_loop (&loop); + + se->expr = resvar; +} + +/* COUNT(A) = Number of true elements in A. */ +static void +gfc_conv_intrinsic_count (gfc_se * se, gfc_expr * expr) +{ + tree resvar; + tree type; + stmtblock_t body; + tree tmp; + gfc_loopinfo loop; + gfc_actual_arglist *actual; + gfc_ss *arrayss; + gfc_se arrayse; + + if (se->ss) + { + gfc_conv_intrinsic_funcall (se, expr); + return; + } + + actual = expr->value.function.actual; + + type = gfc_typenode_for_spec (&expr->ts); + /* Initialize the result. */ + resvar = gfc_create_var (type, "count"); + gfc_add_modify_expr (&se->pre, resvar, integer_zero_node); + + /* Walk the arguments. */ + arrayss = gfc_walk_expr (actual->expr); + assert (arrayss != gfc_ss_terminator); + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + gfc_add_ss_to_loop (&loop, arrayss); + + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + gfc_mark_ss_chain_used (arrayss, 1); + /* Generate the loop body. */ + gfc_start_scalarized_body (&loop, &body); + + tmp = build (PLUS_EXPR, TREE_TYPE (resvar), resvar, integer_one_node); + tmp = build_v (MODIFY_EXPR, resvar, tmp); + + gfc_init_se (&arrayse, NULL); + gfc_copy_loopinfo_to_se (&arrayse, &loop); + arrayse.ss = arrayss; + gfc_conv_expr_val (&arrayse, actual->expr); + tmp = build_v (COND_EXPR, arrayse.expr, tmp, build_empty_stmt ()); + + gfc_add_block_to_block (&body, &arrayse.pre); + gfc_add_expr_to_block (&body, tmp); + gfc_add_block_to_block (&body, &arrayse.post); + + gfc_trans_scalarizing_loops (&loop, &body); + + gfc_add_block_to_block (&se->pre, &loop.pre); + gfc_add_block_to_block (&se->pre, &loop.post); + gfc_cleanup_loop (&loop); + + se->expr = resvar; +} + +/* Inline implementation of the sum and product intrinsics. */ +static void +gfc_conv_intrinsic_arith (gfc_se * se, gfc_expr * expr, int op) +{ + tree resvar; + tree type; + stmtblock_t body; + stmtblock_t block; + tree tmp; + gfc_loopinfo loop; + gfc_actual_arglist *actual; + gfc_ss *arrayss; + gfc_ss *maskss; + gfc_se arrayse; + gfc_se maskse; + gfc_expr *arrayexpr; + gfc_expr *maskexpr; + + if (se->ss) + { + gfc_conv_intrinsic_funcall (se, expr); + return; + } + + type = gfc_typenode_for_spec (&expr->ts); + /* Initialize the result. */ + resvar = gfc_create_var (type, "val"); + if (op == PLUS_EXPR) + tmp = gfc_build_const (type, integer_zero_node); + else + tmp = gfc_build_const (type, integer_one_node); + + gfc_add_modify_expr (&se->pre, resvar, tmp); + + /* Walk the arguments. */ + actual = expr->value.function.actual; + arrayexpr = actual->expr; + arrayss = gfc_walk_expr (arrayexpr); + assert (arrayss != gfc_ss_terminator); + + actual = actual->next->next; + assert (actual); + maskexpr = actual->expr; + if (maskexpr) + { + maskss = gfc_walk_expr (maskexpr); + assert (maskss != gfc_ss_terminator); + } + else + maskss = NULL; + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + gfc_add_ss_to_loop (&loop, arrayss); + if (maskss) + gfc_add_ss_to_loop (&loop, maskss); + + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + gfc_mark_ss_chain_used (arrayss, 1); + if (maskss) + gfc_mark_ss_chain_used (maskss, 1); + /* Generate the loop body. */ + gfc_start_scalarized_body (&loop, &body); + + /* If we have a mask, only add this element if the mask is set. */ + if (maskss) + { + gfc_init_se (&maskse, NULL); + gfc_copy_loopinfo_to_se (&maskse, &loop); + maskse.ss = maskss; + gfc_conv_expr_val (&maskse, maskexpr); + gfc_add_block_to_block (&body, &maskse.pre); + + gfc_start_block (&block); + } + else + gfc_init_block (&block); + + /* Do the actual summation/product. */ + gfc_init_se (&arrayse, NULL); + gfc_copy_loopinfo_to_se (&arrayse, &loop); + arrayse.ss = arrayss; + gfc_conv_expr_val (&arrayse, arrayexpr); + gfc_add_block_to_block (&block, &arrayse.pre); + + tmp = build (op, type, resvar, arrayse.expr); + gfc_add_modify_expr (&block, resvar, tmp); + gfc_add_block_to_block (&block, &arrayse.post); + + if (maskss) + { + /* We enclose the above in if (mask) {...} . */ + tmp = gfc_finish_block (&block); + + tmp = build_v (COND_EXPR, maskse.expr, tmp, build_empty_stmt ()); + } + else + tmp = gfc_finish_block (&block); + gfc_add_expr_to_block (&body, tmp); + + gfc_trans_scalarizing_loops (&loop, &body); + gfc_add_block_to_block (&se->pre, &loop.pre); + gfc_add_block_to_block (&se->pre, &loop.post); + gfc_cleanup_loop (&loop); + + se->expr = resvar; +} + +static void +gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, int op) +{ + stmtblock_t body; + stmtblock_t block; + stmtblock_t ifblock; + tree limit; + tree type; + tree tmp; + tree ifbody; + tree cond; + gfc_loopinfo loop; + gfc_actual_arglist *actual; + gfc_ss *arrayss; + gfc_ss *maskss; + gfc_se arrayse; + gfc_se maskse; + gfc_expr *arrayexpr; + gfc_expr *maskexpr; + tree pos; + int n; + + if (se->ss) + { + gfc_conv_intrinsic_funcall (se, expr); + return; + } + + /* Initialize the result. */ + pos = gfc_create_var (gfc_array_index_type, "pos"); + type = gfc_typenode_for_spec (&expr->ts); + + /* Walk the arguments. */ + actual = expr->value.function.actual; + arrayexpr = actual->expr; + arrayss = gfc_walk_expr (arrayexpr); + assert (arrayss != gfc_ss_terminator); + + actual = actual->next->next; + assert (actual); + maskexpr = actual->expr; + if (maskexpr) + { + maskss = gfc_walk_expr (maskexpr); + assert (maskss != gfc_ss_terminator); + } + else + maskss = NULL; + + limit = gfc_create_var (gfc_typenode_for_spec (&arrayexpr->ts), "limit"); + n = gfc_validate_kind (arrayexpr->ts.type, arrayexpr->ts.kind); + switch (arrayexpr->ts.type) + { + case BT_REAL: + tmp = gfc_conv_mpf_to_tree (gfc_real_kinds[n].huge, arrayexpr->ts.kind); + break; + + case BT_INTEGER: + tmp = gfc_conv_mpz_to_tree (gfc_integer_kinds[n].huge, + arrayexpr->ts.kind); + break; + + default: + abort (); + } + + /* Most negative(+HUGE) for maxval, most negative (-HUGE) for minval. */ + if (op == GT_EXPR) + tmp = fold (build1 (NEGATE_EXPR, TREE_TYPE (tmp), tmp)); + gfc_add_modify_expr (&se->pre, limit, tmp); + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + gfc_add_ss_to_loop (&loop, arrayss); + if (maskss) + gfc_add_ss_to_loop (&loop, maskss); + + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + assert (loop.dimen == 1); + + /* Initialize the position to the first element. If the array has zero + size we need to return zero. Otherwise use the first element of the + array, in case all elements are equal to the limit. + ie. pos = (ubound >= lbound) ? lbound, lbound - 1; */ + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, + loop.from[0], integer_one_node)); + cond = fold (build (GE_EXPR, boolean_type_node, + loop.to[0], loop.from[0])); + tmp = fold (build (COND_EXPR, gfc_array_index_type, cond, + loop.from[0], tmp)); + gfc_add_modify_expr (&loop.pre, pos, tmp); + + gfc_mark_ss_chain_used (arrayss, 1); + if (maskss) + gfc_mark_ss_chain_used (maskss, 1); + /* Generate the loop body. */ + gfc_start_scalarized_body (&loop, &body); + + /* If we have a mask, only check this element if the mask is set. */ + if (maskss) + { + gfc_init_se (&maskse, NULL); + gfc_copy_loopinfo_to_se (&maskse, &loop); + maskse.ss = maskss; + gfc_conv_expr_val (&maskse, maskexpr); + gfc_add_block_to_block (&body, &maskse.pre); + + gfc_start_block (&block); + } + else + gfc_init_block (&block); + + /* Compare with the current limit. */ + gfc_init_se (&arrayse, NULL); + gfc_copy_loopinfo_to_se (&arrayse, &loop); + arrayse.ss = arrayss; + gfc_conv_expr_val (&arrayse, arrayexpr); + gfc_add_block_to_block (&block, &arrayse.pre); + + /* We do the following if this is a more extreme value. */ + gfc_start_block (&ifblock); + + /* Assign the value to the limit... */ + gfc_add_modify_expr (&ifblock, limit, arrayse.expr); + + /* Remember where we are. */ + gfc_add_modify_expr (&ifblock, pos, loop.loopvar[0]); + + ifbody = gfc_finish_block (&ifblock); + + /* If it is a more extreme value. */ + tmp = build (op, boolean_type_node, arrayse.expr, limit); + tmp = build_v (COND_EXPR, tmp, ifbody, build_empty_stmt ()); + gfc_add_expr_to_block (&block, tmp); + + if (maskss) + { + /* We enclose the above in if (mask) {...}. */ + tmp = gfc_finish_block (&block); + + tmp = build_v (COND_EXPR, maskse.expr, tmp, build_empty_stmt ()); + } + else + tmp = gfc_finish_block (&block); + gfc_add_expr_to_block (&body, tmp); + + gfc_trans_scalarizing_loops (&loop, &body); + + gfc_add_block_to_block (&se->pre, &loop.pre); + gfc_add_block_to_block (&se->pre, &loop.post); + gfc_cleanup_loop (&loop); + + /* Return a value in the range 1..SIZE(array). */ + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, loop.from[0], + integer_one_node)); + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, pos, tmp)); + /* And convert to the required type. */ + se->expr = convert (type, tmp); +} + +static void +gfc_conv_intrinsic_minmaxval (gfc_se * se, gfc_expr * expr, int op) +{ + tree limit; + tree type; + tree tmp; + tree ifbody; + stmtblock_t body; + stmtblock_t block; + gfc_loopinfo loop; + gfc_actual_arglist *actual; + gfc_ss *arrayss; + gfc_ss *maskss; + gfc_se arrayse; + gfc_se maskse; + gfc_expr *arrayexpr; + gfc_expr *maskexpr; + int n; + + if (se->ss) + { + gfc_conv_intrinsic_funcall (se, expr); + return; + } + + type = gfc_typenode_for_spec (&expr->ts); + /* Initialize the result. */ + limit = gfc_create_var (type, "limit"); + n = gfc_validate_kind (expr->ts.type, expr->ts.kind); + switch (expr->ts.type) + { + case BT_REAL: + tmp = gfc_conv_mpf_to_tree (gfc_real_kinds[n].huge, expr->ts.kind); + break; + + case BT_INTEGER: + tmp = gfc_conv_mpz_to_tree (gfc_integer_kinds[n].huge, expr->ts.kind); + break; + + default: + abort (); + } + + /* Most negative(-HUGE) for maxval, most positive (-HUGE) for minval. */ + if (op == GT_EXPR) + tmp = fold (build1 (NEGATE_EXPR, TREE_TYPE (tmp), tmp)); + gfc_add_modify_expr (&se->pre, limit, tmp); + + /* Walk the arguments. */ + actual = expr->value.function.actual; + arrayexpr = actual->expr; + arrayss = gfc_walk_expr (arrayexpr); + assert (arrayss != gfc_ss_terminator); + + actual = actual->next->next; + assert (actual); + maskexpr = actual->expr; + if (maskexpr) + { + maskss = gfc_walk_expr (maskexpr); + assert (maskss != gfc_ss_terminator); + } + else + maskss = NULL; + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + gfc_add_ss_to_loop (&loop, arrayss); + if (maskss) + gfc_add_ss_to_loop (&loop, maskss); + + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + gfc_mark_ss_chain_used (arrayss, 1); + if (maskss) + gfc_mark_ss_chain_used (maskss, 1); + /* Generate the loop body. */ + gfc_start_scalarized_body (&loop, &body); + + /* If we have a mask, only add this element if the mask is set. */ + if (maskss) + { + gfc_init_se (&maskse, NULL); + gfc_copy_loopinfo_to_se (&maskse, &loop); + maskse.ss = maskss; + gfc_conv_expr_val (&maskse, maskexpr); + gfc_add_block_to_block (&body, &maskse.pre); + + gfc_start_block (&block); + } + else + gfc_init_block (&block); + + /* Compare with the current limit. */ + gfc_init_se (&arrayse, NULL); + gfc_copy_loopinfo_to_se (&arrayse, &loop); + arrayse.ss = arrayss; + gfc_conv_expr_val (&arrayse, arrayexpr); + gfc_add_block_to_block (&block, &arrayse.pre); + + /* Assign the value to the limit... */ + ifbody = build_v (MODIFY_EXPR, limit, arrayse.expr); + + /* If it is a more extreme value. */ + tmp = build (op, boolean_type_node, arrayse.expr, limit); + tmp = build_v (COND_EXPR, tmp, ifbody, build_empty_stmt ()); + gfc_add_expr_to_block (&block, tmp); + gfc_add_block_to_block (&block, &arrayse.post); + + tmp = gfc_finish_block (&block); + if (maskss) + { + /* We enclose the above in if (mask) {...}. */ + tmp = build_v (COND_EXPR, maskse.expr, tmp, build_empty_stmt ()); + } + gfc_add_expr_to_block (&body, tmp); + + gfc_trans_scalarizing_loops (&loop, &body); + + gfc_add_block_to_block (&se->pre, &loop.pre); + gfc_add_block_to_block (&se->pre, &loop.post); + gfc_cleanup_loop (&loop); + + se->expr = limit; +} + +/* BTEST (i, pos) = (i & (1 << pos)) != 0. */ +static void +gfc_conv_intrinsic_btest (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree arg2; + tree type; + tree tmp; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + type = TREE_TYPE (arg); + + tmp = build (LSHIFT_EXPR, type, integer_one_node, arg2); + tmp = build (BIT_AND_EXPR, type, arg, tmp); + tmp = fold (build (NE_EXPR, boolean_type_node, tmp, integer_zero_node)); + type = gfc_typenode_for_spec (&expr->ts); + se->expr = convert (type, tmp); +} + +/* Generate code to perform the specified operation. */ +static void +gfc_conv_intrinsic_bitop (gfc_se * se, gfc_expr * expr, int op) +{ + tree arg; + tree arg2; + tree type; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + type = TREE_TYPE (arg); + + se->expr = fold (build (op, type, arg, arg2)); +} + +/* Bitwise not. */ +static void +gfc_conv_intrinsic_not (gfc_se * se, gfc_expr * expr) +{ + tree arg; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (arg); + + se->expr = build1 (BIT_NOT_EXPR, TREE_TYPE (arg), arg); +} + +/* Set or clear a single bit. */ +static void +gfc_conv_intrinsic_singlebitop (gfc_se * se, gfc_expr * expr, int set) +{ + tree arg; + tree arg2; + tree type; + tree tmp; + int op; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + type = TREE_TYPE (arg); + + tmp = fold (build (LSHIFT_EXPR, type, integer_one_node, arg2)); + if (set) + op = BIT_IOR_EXPR; + else + { + op = BIT_AND_EXPR; + tmp = fold (build1 (BIT_NOT_EXPR, type, tmp)); + } + se->expr = fold (build (op, type, arg, tmp)); +} + +/* Extract a sequence of bits. + IBITS(I, POS, LEN) = (I >> POS) & ~((~0) << LEN). */ +static void +gfc_conv_intrinsic_ibits (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree arg2; + tree arg3; + tree type; + tree tmp; + tree mask; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_CHAIN (arg); + arg3 = TREE_VALUE (TREE_CHAIN (arg2)); + arg = TREE_VALUE (arg); + arg2 = TREE_VALUE (arg2); + type = TREE_TYPE (arg); + + mask = build_int_2 (-1, ~(unsigned HOST_WIDE_INT) 0); + mask = build (LSHIFT_EXPR, type, mask, arg3); + mask = build1 (BIT_NOT_EXPR, type, mask); + + tmp = build (RSHIFT_EXPR, type, arg, arg2); + + se->expr = fold (build (BIT_AND_EXPR, type, tmp, mask)); +} + +/* ISHFT (I, SHIFT) = (shift >= 0) ? i << shift : i >> -shift. */ +static void +gfc_conv_intrinsic_ishft (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree arg2; + tree type; + tree tmp; + tree lshift; + tree rshift; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_VALUE (TREE_CHAIN (arg)); + arg = TREE_VALUE (arg); + type = TREE_TYPE (arg); + + /* Left shift if positive. */ + lshift = build (LSHIFT_EXPR, type, arg, arg2); + + /* Right shift if negative. This will perform an arithmetic shift as + we are dealing with signed integers. Section 13.5.7 allows this. */ + tmp = build1 (NEGATE_EXPR, TREE_TYPE (arg2), arg2); + rshift = build (RSHIFT_EXPR, type, arg, tmp); + + tmp = build (GT_EXPR, boolean_type_node, arg2, integer_zero_node); + rshift = build (COND_EXPR, type, tmp, lshift, rshift); + + /* Do nothing if shift == 0. */ + tmp = build (EQ_EXPR, boolean_type_node, arg2, integer_zero_node); + se->expr = build (COND_EXPR, type, tmp, arg, rshift); +} + +/* Circular shift. AKA rotate or barrel shift. */ +static void +gfc_conv_intrinsic_ishftc (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree arg2; + tree arg3; + tree type; + tree tmp; + tree lrot; + tree rrot; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg2 = TREE_CHAIN (arg); + arg3 = TREE_CHAIN (arg2); + if (arg3) + { + /* Use a library function for the 3 parameter version. */ + type = TREE_TYPE (TREE_VALUE (arg)); + /* Convert all args to the same type otherwise we need loads of library + functions. SIZE and SHIFT cannot have values > BIT_SIZE (I) so the + conversion is safe. */ + tmp = convert (type, TREE_VALUE (arg2)); + TREE_VALUE (arg2) = tmp; + tmp = convert (type, TREE_VALUE (arg3)); + TREE_VALUE (arg3) = tmp; + + switch (expr->ts.kind) + { + case 4: + tmp = gfor_fndecl_math_ishftc4; + break; + case 8: + tmp = gfor_fndecl_math_ishftc8; + break; + default: + abort (); + } + se->expr = gfc_build_function_call (tmp, arg); + return; + } + arg = TREE_VALUE (arg); + arg2 = TREE_VALUE (arg2); + type = TREE_TYPE (arg); + + /* Rotate left if positive. */ + lrot = build (LROTATE_EXPR, type, arg, arg2); + + /* Rotate right if negative. */ + tmp = build1 (NEGATE_EXPR, TREE_TYPE (arg2), arg2); + rrot = build (RROTATE_EXPR, type, arg, tmp); + + tmp = build (GT_EXPR, boolean_type_node, arg2, integer_zero_node); + rrot = build (COND_EXPR, type, tmp, lrot, rrot); + + /* Do nothing if shift == 0. */ + tmp = build (EQ_EXPR, boolean_type_node, arg2, integer_zero_node); + se->expr = build (COND_EXPR, type, tmp, arg, rrot); +} + +/* The length of a character string. */ +static void +gfc_conv_intrinsic_len (gfc_se * se, gfc_expr * expr) +{ + tree len; + tree type; + tree decl; + gfc_symbol *sym; + gfc_se argse; + gfc_expr *arg; + + assert (!se->ss); + + arg = expr->value.function.actual->expr; + + type = gfc_typenode_for_spec (&expr->ts); + switch (arg->expr_type) + { + case EXPR_CONSTANT: + len = build_int_2 (arg->value.character.length, 0); + break; + + default: + if (arg->expr_type == EXPR_VARIABLE && arg->ref == NULL) + { + sym = arg->symtree->n.sym; + decl = gfc_get_symbol_decl (sym); + if (decl == current_function_decl && sym->attr.function + && (sym->result == sym)) + decl = gfc_get_fake_result_decl (sym); + + len = sym->ts.cl->backend_decl; + assert (len); + } + else + { + /* Anybody stupid enough to do this deserves inefficient code. */ + gfc_init_se (&argse, se); + gfc_conv_expr (&argse, arg); + gfc_add_block_to_block (&se->pre, &argse.pre); + gfc_add_block_to_block (&se->post, &argse.post); + len = argse.string_length; + } + break; + } + se->expr = convert (type, len); +} + +/* The length of a character string not including trailing blanks. */ +static void +gfc_conv_intrinsic_len_trim (gfc_se * se, gfc_expr * expr) +{ + tree args; + tree type; + + args = gfc_conv_intrinsic_function_args (se, expr); + type = gfc_typenode_for_spec (&expr->ts); + se->expr = gfc_build_function_call (gfor_fndecl_string_len_trim, args); + se->expr = convert (type, se->expr); +} + + +/* Returns the starting position of a substring within a string. */ + +static void +gfc_conv_intrinsic_index (gfc_se * se, gfc_expr * expr) +{ + tree args; + tree back; + tree type; + tree tmp; + + args = gfc_conv_intrinsic_function_args (se, expr); + type = gfc_typenode_for_spec (&expr->ts); + tmp = gfc_advance_chain (args, 3); + if (TREE_CHAIN (tmp) == NULL_TREE) + { + back = convert (gfc_logical4_type_node, integer_one_node); + back = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); + TREE_CHAIN (tmp) = back; + } + else + { + back = TREE_CHAIN (tmp); + TREE_VALUE (back) = convert (gfc_logical4_type_node, TREE_VALUE (back)); + } + + se->expr = gfc_build_function_call (gfor_fndecl_string_index, args); + se->expr = convert (type, se->expr); +} + +/* The ascii value for a single character. */ +static void +gfc_conv_intrinsic_ichar (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree type; + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (TREE_CHAIN (arg)); + assert (POINTER_TYPE_P (TREE_TYPE (arg))); + arg = build1 (NOP_EXPR, pchar_type_node, arg); + type = gfc_typenode_for_spec (&expr->ts); + + se->expr = gfc_build_indirect_ref (arg); + se->expr = convert (type, se->expr); +} + + +/* MERGE (tsource, fsource, mask) = mask ? tsource : fsource. */ + +static void +gfc_conv_intrinsic_merge (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree tsource; + tree fsource; + tree mask; + tree type; + + arg = gfc_conv_intrinsic_function_args (se, expr); + tsource = TREE_VALUE (arg); + arg = TREE_CHAIN (arg); + fsource = TREE_VALUE (arg); + arg = TREE_CHAIN (arg); + mask = TREE_VALUE (arg); + + type = TREE_TYPE (tsource); + se->expr = fold (build (COND_EXPR, type, mask, tsource, fsource)); +} + + +static void +gfc_conv_intrinsic_size (gfc_se * se, gfc_expr * expr) +{ + gfc_actual_arglist *actual; + tree args; + tree type; + tree fndecl; + gfc_se argse; + gfc_ss *ss; + + gfc_init_se (&argse, NULL); + actual = expr->value.function.actual; + + ss = gfc_walk_expr (actual->expr); + assert (ss != gfc_ss_terminator); + argse.want_pointer = 1; + gfc_conv_expr_descriptor (&argse, actual->expr, ss); + gfc_add_block_to_block (&se->pre, &argse.pre); + gfc_add_block_to_block (&se->post, &argse.post); + args = gfc_chainon_list (NULL_TREE, argse.expr); + + actual = actual->next; + if (actual->expr) + { + gfc_init_se (&argse, NULL); + gfc_conv_expr_type (&argse, actual->expr, gfc_array_index_type); + gfc_add_block_to_block (&se->pre, &argse.pre); + args = gfc_chainon_list (args, argse.expr); + fndecl = gfor_fndecl_size1; + } + else + fndecl = gfor_fndecl_size0; + + se->expr = gfc_build_function_call (fndecl, args); + type = gfc_typenode_for_spec (&expr->ts); + se->expr = convert (type, se->expr); +} + + +/* Intrinsic string comparison functions. */ + + static void +gfc_conv_intrinsic_strcmp (gfc_se * se, gfc_expr * expr, int op) +{ + tree type; + tree args; + + args = gfc_conv_intrinsic_function_args (se, expr); + /* Build a call for the comparison. */ + se->expr = gfc_build_function_call (gfor_fndecl_compare_string, args); + + type = gfc_typenode_for_spec (&expr->ts); + se->expr = build (op, type, se->expr, integer_zero_node); +} + +/* Generate a call to the adjustl/adjustr library function. */ +static void +gfc_conv_intrinsic_adjust (gfc_se * se, gfc_expr * expr, tree fndecl) +{ + tree args; + tree len; + tree type; + tree var; + tree tmp; + + args = gfc_conv_intrinsic_function_args (se, expr); + len = TREE_VALUE (args); + + type = TREE_TYPE (TREE_VALUE (TREE_CHAIN (args))); + var = gfc_conv_string_tmp (se, type, len); + args = tree_cons (NULL_TREE, var, args); + + tmp = gfc_build_function_call (fndecl, args); + gfc_add_expr_to_block (&se->pre, tmp); + se->expr = var; + se->string_length = len; +} + + +/* Scalar transfer statement. + TRANSFER (source, mold) = *(typeof *)&source */ + +static void +gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr) +{ + gfc_actual_arglist *arg; + gfc_se argse; + tree type; + tree ptr; + gfc_ss *ss; + + assert (!se->ss); + + /* Get a pointer to the source. */ + arg = expr->value.function.actual; + ss = gfc_walk_expr (arg->expr); + gfc_init_se (&argse, NULL); + if (ss == gfc_ss_terminator) + gfc_conv_expr_reference (&argse, arg->expr); + else + gfc_conv_array_parameter (&argse, arg->expr, ss, 1); + gfc_add_block_to_block (&se->pre, &argse.pre); + gfc_add_block_to_block (&se->post, &argse.post); + ptr = argse.expr; + + arg = arg->next; + type = gfc_typenode_for_spec (&expr->ts); + ptr = convert (build_pointer_type (type), ptr); + if (expr->ts.type == BT_CHARACTER) + { + gfc_init_se (&argse, NULL); + gfc_conv_expr (&argse, arg->expr); + gfc_add_block_to_block (&se->pre, &argse.pre); + gfc_add_block_to_block (&se->post, &argse.post); + se->expr = ptr; + se->string_length = argse.string_length; + } + else + { + se->expr = gfc_build_indirect_ref (ptr); + } +} + + +/* Generate code for the ALLOCATED intrinsic. + Generate inline code that directly check the address of the argument. */ + +static void +gfc_conv_allocated (gfc_se *se, gfc_expr *expr) +{ + gfc_actual_arglist *arg1; + gfc_se arg1se; + gfc_ss *ss1; + tree tmp; + + gfc_init_se (&arg1se, NULL); + arg1 = expr->value.function.actual; + ss1 = gfc_walk_expr (arg1->expr); + arg1se.descriptor_only = 1; + gfc_conv_expr_descriptor (&arg1se, arg1->expr, ss1); + + tmp = gfc_conv_descriptor_data (arg1se.expr); + tmp = build (NE_EXPR, boolean_type_node, tmp, null_pointer_node); + se->expr = convert (gfc_typenode_for_spec (&expr->ts), tmp); +} + + +/* Generate code for the ASSOCIATED intrinsic. + If both POINTER and TARGET are arrays, generate a call to library function + _gfor_associated, and pass descriptors of POINTER and TARGET to it. + In other cases, generate inline code that directly compare the address of + POINTER with the address of TARGET. */ + +static void +gfc_conv_associated (gfc_se *se, gfc_expr *expr) +{ + gfc_actual_arglist *arg1; + gfc_actual_arglist *arg2; + gfc_se arg1se; + gfc_se arg2se; + tree tmp2; + tree tmp; + tree args, fndecl; + gfc_ss *ss1, *ss2; + + gfc_init_se (&arg1se, NULL); + gfc_init_se (&arg2se, NULL); + arg1 = expr->value.function.actual; + arg2 = arg1->next; + ss1 = gfc_walk_expr (arg1->expr); + + if (!arg2->expr) + { + /* No optional target. */ + if (ss1 == gfc_ss_terminator) + { + /* A pointer to a scalar. */ + arg1se.want_pointer = 1; + gfc_conv_expr (&arg1se, arg1->expr); + tmp2 = arg1se.expr; + } + else + { + /* A pointer to an array. */ + arg1se.descriptor_only = 1; + gfc_conv_expr_lhs (&arg1se, arg1->expr); + tmp2 = gfc_conv_descriptor_data (arg1se.expr); + } + tmp = build (NE_EXPR, boolean_type_node, tmp2, null_pointer_node); + se->expr = tmp; + } + else + { + /* An optional target. */ + ss2 = gfc_walk_expr (arg2->expr); + if (ss1 == gfc_ss_terminator) + { + /* A pointer to a scalar. */ + assert (ss2 == gfc_ss_terminator); + arg1se.want_pointer = 1; + gfc_conv_expr (&arg1se, arg1->expr); + arg2se.want_pointer = 1; + gfc_conv_expr (&arg2se, arg2->expr); + tmp = build (EQ_EXPR, boolean_type_node, arg1se.expr, arg2se.expr); + se->expr = tmp; + } + else + { + /* A pointer to an array, call library function _gfor_associated. */ + assert (ss2 != gfc_ss_terminator); + args = NULL_TREE; + arg1se.want_pointer = 1; + gfc_conv_expr_descriptor (&arg1se, arg1->expr, ss1); + args = gfc_chainon_list (args, arg1se.expr); + arg2se.want_pointer = 1; + gfc_conv_expr_descriptor (&arg2se, arg2->expr, ss2); + gfc_add_block_to_block (&se->pre, &arg2se.pre); + gfc_add_block_to_block (&se->post, &arg2se.post); + args = gfc_chainon_list (args, arg2se.expr); + fndecl = gfor_fndecl_associated; + se->expr = gfc_build_function_call (fndecl, args); + } + } + se->expr = convert (gfc_typenode_for_spec (&expr->ts), se->expr); +} + + +/* Scan a string for any one of the characters in a set of characters. */ + +static void +gfc_conv_intrinsic_scan (gfc_se * se, gfc_expr * expr) +{ + tree args; + tree back; + tree type; + tree tmp; + + args = gfc_conv_intrinsic_function_args (se, expr); + type = gfc_typenode_for_spec (&expr->ts); + tmp = gfc_advance_chain (args, 3); + if (TREE_CHAIN (tmp) == NULL_TREE) + { + back = convert (gfc_logical4_type_node, integer_one_node); + back = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); + TREE_CHAIN (tmp) = back; + } + else + { + back = TREE_CHAIN (tmp); + TREE_VALUE (back) = convert (gfc_logical4_type_node, TREE_VALUE (back)); + } + + se->expr = gfc_build_function_call (gfor_fndecl_string_scan, args); + se->expr = convert (type, se->expr); +} + + +/* Verify that a set of characters contains all the characters in a string + by indentifying the position of the first character in a string of + characters that does not appear in a given set of characters. */ + +static void +gfc_conv_intrinsic_verify (gfc_se * se, gfc_expr * expr) +{ + tree args; + tree back; + tree type; + tree tmp; + + args = gfc_conv_intrinsic_function_args (se, expr); + type = gfc_typenode_for_spec (&expr->ts); + tmp = gfc_advance_chain (args, 3); + if (TREE_CHAIN (tmp) == NULL_TREE) + { + back = convert (gfc_logical4_type_node, integer_one_node); + back = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); + TREE_CHAIN (tmp) = back; + } + else + { + back = TREE_CHAIN (tmp); + TREE_VALUE (back) = convert (gfc_logical4_type_node, TREE_VALUE (back)); + } + + se->expr = gfc_build_function_call (gfor_fndecl_string_verify, args); + se->expr = convert (type, se->expr); +} + +/* Prepare components and related information of a real number which is + the first argument of a elemental functions to manipulate reals. */ + +static +void prepare_arg_info (gfc_se * se, gfc_expr * expr, + real_compnt_info * rcs, int all) +{ + tree arg; + tree masktype; + tree tmp; + tree wbits; + tree one; + tree exponent, fraction; + int n; + gfc_expr *a1; + + if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT) + gfc_todo_error ("Non-IEEE floating format"); + + assert (expr->expr_type == EXPR_FUNCTION); + + arg = gfc_conv_intrinsic_function_args (se, expr); + arg = TREE_VALUE (arg); + rcs->type = TREE_TYPE (arg); + + /* Force arg'type to integer by unaffected convert */ + a1 = expr->value.function.actual->expr; + masktype = gfc_get_int_type (a1->ts.kind); + rcs->mtype = masktype; + tmp = build1 (VIEW_CONVERT_EXPR, masktype, arg); + arg = gfc_create_var (masktype, "arg"); + gfc_add_modify_expr(&se->pre, arg, tmp); + rcs->arg = arg; + + /* Caculate the numbers of bits of exponent, fraction and word */ + n = gfc_validate_kind (a1->ts.type, a1->ts.kind); + tmp = build_int_2 (gfc_real_kinds[n].digits - 1, 0); + rcs->fdigits = convert (masktype, tmp); + wbits = build_int_2 (TYPE_PRECISION (rcs->type) - 1, 0); + wbits = convert (masktype, wbits); + rcs->edigits = fold (build (MINUS_EXPR, masktype, wbits, tmp)); + + /* Form masks for exponent/fraction/sign */ + one = gfc_build_const (masktype, integer_one_node); + rcs->smask = fold (build (LSHIFT_EXPR, masktype, one, wbits)); + rcs->f1 = fold (build (LSHIFT_EXPR, masktype, one, rcs->fdigits)); + rcs->emask = fold (build (MINUS_EXPR, masktype, rcs->smask, rcs->f1)); + rcs->fmask = fold (build (MINUS_EXPR, masktype, rcs->f1, one)); + /* Form bias. */ + tmp = fold (build (MINUS_EXPR, masktype, rcs->edigits, one)); + tmp = fold (build (LSHIFT_EXPR, masktype, one, tmp)); + rcs->bias = fold (build (MINUS_EXPR, masktype, tmp ,one)); + + if (all) + { + /* exponent, and fraction */ + tmp = build (BIT_AND_EXPR, masktype, arg, rcs->emask); + tmp = build (RSHIFT_EXPR, masktype, tmp, rcs->fdigits); + exponent = gfc_create_var (masktype, "exponent"); + gfc_add_modify_expr(&se->pre, exponent, tmp); + rcs->expn = exponent; + + tmp = build (BIT_AND_EXPR, masktype, arg, rcs->fmask); + fraction = gfc_create_var (masktype, "fraction"); + gfc_add_modify_expr(&se->pre, fraction, tmp); + rcs->frac = fraction; + } +} + +/* Build a call to __builtin_clz. */ + +static tree +call_builtin_clz (tree result_type, tree op0) +{ + tree fn, parms, call; + enum machine_mode op0_mode = TYPE_MODE (TREE_TYPE (op0)); + + if (op0_mode == TYPE_MODE (integer_type_node)) + fn = built_in_decls[BUILT_IN_CLZ]; + else if (op0_mode == TYPE_MODE (long_integer_type_node)) + fn = built_in_decls[BUILT_IN_CLZL]; + else if (op0_mode == TYPE_MODE (long_long_integer_type_node)) + fn = built_in_decls[BUILT_IN_CLZLL]; + else + abort (); + + parms = tree_cons (NULL, op0, NULL); + call = gfc_build_function_call (fn, parms); + + return convert (result_type, call); +} + +/* Generate code for SPACING (X) intrinsic function. We generate: + + t = expn - (BITS_OF_FRACTION) + res = t << (BITS_OF_FRACTION) + if (t < 0) + res = tiny(X) +*/ + +static void +gfc_conv_intrinsic_spacing (gfc_se * se, gfc_expr * expr) +{ + tree arg; + tree masktype; + tree tmp, t1, cond; + tree tiny, zero; + tree fdigits; + real_compnt_info rcs; + + prepare_arg_info (se, expr, &rcs, 0); + arg = rcs.arg; + masktype = rcs.mtype; + fdigits = rcs.fdigits; + tiny = rcs.f1; + zero = gfc_build_const (masktype, integer_zero_node); + tmp = build (BIT_AND_EXPR, masktype, rcs.emask, arg); + tmp = build (RSHIFT_EXPR, masktype, tmp, fdigits); + tmp = build (MINUS_EXPR, masktype, tmp, fdigits); + cond = build (LE_EXPR, boolean_type_node, tmp, zero); + t1 = build (LSHIFT_EXPR, masktype, tmp, fdigits); + tmp = build (COND_EXPR, masktype, cond, tiny, t1); + tmp = build1 (VIEW_CONVERT_EXPR, rcs.type, tmp); + + se->expr = tmp; +} + +/* Generate code for RRSPACING (X) intrinsic function. We generate: + sedigits = edigits + 1; + if (expn == 0) + { + t1 = leadzero (frac); + frac = frac << (t1 + sedigits); + frac = frac >> (sedigits); + } + t = bias + BITS_OF_FRACTION_OF; + res = (t << BITS_OF_FRACTION_OF) | frac; +*/ + +static void +gfc_conv_intrinsic_rrspacing (gfc_se * se, gfc_expr * expr) +{ + tree masktype; + tree tmp, t1, t2, cond; + tree one, zero; + tree fdigits, fraction; + real_compnt_info rcs; + + prepare_arg_info (se, expr, &rcs, 1); + masktype = rcs.mtype; + fdigits = rcs.fdigits; + fraction = rcs.frac; + one = gfc_build_const (masktype, integer_one_node); + zero = gfc_build_const (masktype, integer_zero_node); + t2 = build (PLUS_EXPR, masktype, rcs.edigits, one); + + t1 = call_builtin_clz (masktype, fraction); + tmp = build (PLUS_EXPR, masktype, t1, one); + tmp = build (LSHIFT_EXPR, masktype, fraction, tmp); + tmp = build (RSHIFT_EXPR, masktype, tmp, t2); + cond = build (EQ_EXPR, boolean_type_node, rcs.expn, zero); + fraction = build (COND_EXPR, masktype, cond, tmp, fraction); + + tmp = build (PLUS_EXPR, masktype, rcs.bias, fdigits); + tmp = build (LSHIFT_EXPR, masktype, tmp, fdigits); + tmp = build (BIT_IOR_EXPR, masktype, tmp, fraction); + + tmp = build1 (VIEW_CONVERT_EXPR, rcs.type, tmp); + se->expr = tmp; +} + +/* Generate code for SELECTED_INT_KIND (R) intrinsic function. */ + +static void +gfc_conv_intrinsic_si_kind (gfc_se * se, gfc_expr * expr) +{ + tree args; + + args = gfc_conv_intrinsic_function_args (se, expr); + args = TREE_VALUE (args); + args = gfc_build_addr_expr (NULL, args); + args = tree_cons (NULL_TREE, args, NULL_TREE); + se->expr = gfc_build_function_call (gfor_fndecl_si_kind, args); +} + +/* Generate code for SELECTED_REAL_KIND (P, R) intrinsic function. */ + +static void +gfc_conv_intrinsic_sr_kind (gfc_se * se, gfc_expr * expr) +{ + gfc_actual_arglist *actual; + tree args; + gfc_se argse; + + args = NULL_TREE; + for (actual = expr->value.function.actual; actual; actual = actual->next) + { + gfc_init_se (&argse, se); + + /* Pass a NULL pointer for an absent arg. */ + if (actual->expr == NULL) + argse.expr = null_pointer_node; + else + gfc_conv_expr_reference (&argse, actual->expr); + + gfc_add_block_to_block (&se->pre, &argse.pre); + gfc_add_block_to_block (&se->post, &argse.post); + args = gfc_chainon_list (args, argse.expr); + } + se->expr = gfc_build_function_call (gfor_fndecl_sr_kind, args); +} + + +/* Generate code for TRIM (A) intrinsic function. */ + +static void +gfc_conv_intrinsic_trim (gfc_se * se, gfc_expr * expr) +{ + tree var; + tree len; + tree addr; + tree tmp; + tree arglist; + tree type; + tree cond; + + arglist = NULL_TREE; + + type = build_pointer_type (gfc_character1_type_node); + var = gfc_create_var (type, "pstr"); + addr = gfc_build_addr_expr (ppvoid_type_node, var); + len = gfc_create_var (gfc_int4_type_node, "len"); + + tmp = gfc_conv_intrinsic_function_args (se, expr); + arglist = gfc_chainon_list (arglist, gfc_build_addr_expr (NULL, len)); + arglist = gfc_chainon_list (arglist, addr); + arglist = chainon (arglist, tmp); + + tmp = gfc_build_function_call (gfor_fndecl_string_trim, arglist); + gfc_add_expr_to_block (&se->pre, tmp); + + /* Free the temporary afterwards, if necessary. */ + cond = build (GT_EXPR, boolean_type_node, len, integer_zero_node); + arglist = gfc_chainon_list (NULL_TREE, var); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, arglist); + tmp = build_v (COND_EXPR, cond, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&se->post, tmp); + + se->expr = var; + se->string_length = len; +} + + +/* Generate code for REPEAT (STRING, NCOPIES) intrinsic function. */ + +static void +gfc_conv_intrinsic_repeat (gfc_se * se, gfc_expr * expr) +{ + tree tmp; + tree len; + tree args; + tree arglist; + tree ncopies; + tree var; + tree type; + + args = gfc_conv_intrinsic_function_args (se, expr); + len = TREE_VALUE (args); + tmp = gfc_advance_chain (args, 2); + ncopies = TREE_VALUE (tmp); + len = fold (build (MULT_EXPR, gfc_int4_type_node, len, ncopies)); + type = gfc_get_character_type (expr->ts.kind, expr->ts.cl); + var = gfc_conv_string_tmp (se, build_pointer_type (type), len); + + arglist = NULL_TREE; + arglist = gfc_chainon_list (arglist, var); + arglist = chainon (arglist, args); + tmp = gfc_build_function_call (gfor_fndecl_string_repeat, arglist); + gfc_add_expr_to_block (&se->pre, tmp); + + se->expr = var; + se->string_length = len; +} + + +/* Generate code for an intrinsic function. Some map directly to library + calls, others get special handling. In some cases the name of the function + used depends on the type specifiers. */ + +void +gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr) +{ + gfc_intrinsic_sym *isym; + char *name; + int lib; + + isym = expr->value.function.isym; + + name = &expr->value.function.name[2]; + + if (expr->rank > 0) + { + lib = gfc_is_intrinsic_libcall (expr); + if (lib != 0) + { + if (lib == 1) + se->ignore_optional = 1; + gfc_conv_intrinsic_funcall (se, expr); + return; + } + } + + switch (expr->value.function.isym->generic_id) + { + case GFC_ISYM_NONE: + abort (); + + case GFC_ISYM_REPEAT: + gfc_conv_intrinsic_repeat (se, expr); + break; + + case GFC_ISYM_TRIM: + gfc_conv_intrinsic_trim (se, expr); + break; + + case GFC_ISYM_SI_KIND: + gfc_conv_intrinsic_si_kind (se, expr); + break; + + case GFC_ISYM_SR_KIND: + gfc_conv_intrinsic_sr_kind (se, expr); + break; + + case GFC_ISYM_EXPONENT: + gfc_conv_intrinsic_exponent (se, expr); + break; + + case GFC_ISYM_SPACING: + gfc_conv_intrinsic_spacing (se, expr); + break; + + case GFC_ISYM_RRSPACING: + gfc_conv_intrinsic_rrspacing (se, expr); + break; + + case GFC_ISYM_SCAN: + gfc_conv_intrinsic_scan (se, expr); + break; + + case GFC_ISYM_VERIFY: + gfc_conv_intrinsic_verify (se, expr); + break; + + case GFC_ISYM_ALLOCATED: + gfc_conv_allocated (se, expr); + break; + + case GFC_ISYM_ASSOCIATED: + gfc_conv_associated(se, expr); + break; + + case GFC_ISYM_ABS: + gfc_conv_intrinsic_abs (se, expr); + break; + + case GFC_ISYM_ADJUSTL: + gfc_conv_intrinsic_adjust (se, expr, gfor_fndecl_adjustl); + break; + + case GFC_ISYM_ADJUSTR: + gfc_conv_intrinsic_adjust (se, expr, gfor_fndecl_adjustr); + break; + + case GFC_ISYM_AIMAG: + gfc_conv_intrinsic_imagpart (se, expr); + break; + + case GFC_ISYM_AINT: + gfc_conv_intrinsic_aint (se, expr, FIX_TRUNC_EXPR); + break; + + case GFC_ISYM_ALL: + gfc_conv_intrinsic_anyall (se, expr, EQ_EXPR); + break; + + case GFC_ISYM_ANINT: + gfc_conv_intrinsic_aint (se, expr, FIX_ROUND_EXPR); + break; + + case GFC_ISYM_ANY: + gfc_conv_intrinsic_anyall (se, expr, NE_EXPR); + break; + + case GFC_ISYM_BTEST: + gfc_conv_intrinsic_btest (se, expr); + break; + + case GFC_ISYM_ACHAR: + case GFC_ISYM_CHAR: + gfc_conv_intrinsic_char (se, expr); + break; + + case GFC_ISYM_CONVERSION: + case GFC_ISYM_REAL: + case GFC_ISYM_LOGICAL: + case GFC_ISYM_DBLE: + gfc_conv_intrinsic_conversion (se, expr); + break; + + /* Integer conversions are handled seperately to make sure we get the + correct rounding mode. */ + case GFC_ISYM_INT: + gfc_conv_intrinsic_int (se, expr, FIX_TRUNC_EXPR); + break; + + case GFC_ISYM_NINT: + gfc_conv_intrinsic_int (se, expr, FIX_ROUND_EXPR); + break; + + case GFC_ISYM_CEILING: + gfc_conv_intrinsic_int (se, expr, FIX_CEIL_EXPR); + break; + + case GFC_ISYM_FLOOR: + gfc_conv_intrinsic_int (se, expr, FIX_FLOOR_EXPR); + break; + + case GFC_ISYM_MOD: + gfc_conv_intrinsic_mod (se, expr, 0); + break; + + case GFC_ISYM_MODULO: + gfc_conv_intrinsic_mod (se, expr, 1); + break; + + case GFC_ISYM_CMPLX: + gfc_conv_intrinsic_cmplx (se, expr, name[5] == '1'); + break; + + case GFC_ISYM_CONJG: + gfc_conv_intrinsic_conjg (se, expr); + break; + + case GFC_ISYM_COUNT: + gfc_conv_intrinsic_count (se, expr); + break; + + case GFC_ISYM_DIM: + gfc_conv_intrinsic_dim (se, expr); + break; + + case GFC_ISYM_DPROD: + gfc_conv_intrinsic_dprod (se, expr); + break; + + case GFC_ISYM_IAND: + gfc_conv_intrinsic_bitop (se, expr, BIT_AND_EXPR); + break; + + case GFC_ISYM_IBCLR: + gfc_conv_intrinsic_singlebitop (se, expr, 0); + break; + + case GFC_ISYM_IBITS: + gfc_conv_intrinsic_ibits (se, expr); + break; + + case GFC_ISYM_IBSET: + gfc_conv_intrinsic_singlebitop (se, expr, 1); + break; + + case GFC_ISYM_IACHAR: + case GFC_ISYM_ICHAR: + /* We assume ASCII character sequence. */ + gfc_conv_intrinsic_ichar (se, expr); + break; + + case GFC_ISYM_IEOR: + gfc_conv_intrinsic_bitop (se, expr, BIT_XOR_EXPR); + break; + + case GFC_ISYM_INDEX: + gfc_conv_intrinsic_index (se, expr); + break; + + case GFC_ISYM_IOR: + gfc_conv_intrinsic_bitop (se, expr, BIT_IOR_EXPR); + break; + + case GFC_ISYM_ISHFT: + gfc_conv_intrinsic_ishft (se, expr); + break; + + case GFC_ISYM_ISHFTC: + gfc_conv_intrinsic_ishftc (se, expr); + break; + + case GFC_ISYM_LBOUND: + gfc_conv_intrinsic_bound (se, expr, 0); + break; + + case GFC_ISYM_LEN: + gfc_conv_intrinsic_len (se, expr); + break; + + case GFC_ISYM_LEN_TRIM: + gfc_conv_intrinsic_len_trim (se, expr); + break; + + case GFC_ISYM_LGE: + gfc_conv_intrinsic_strcmp (se, expr, GE_EXPR); + break; + + case GFC_ISYM_LGT: + gfc_conv_intrinsic_strcmp (se, expr, GT_EXPR); + break; + + case GFC_ISYM_LLE: + gfc_conv_intrinsic_strcmp (se, expr, LE_EXPR); + break; + + case GFC_ISYM_LLT: + gfc_conv_intrinsic_strcmp (se, expr, LT_EXPR); + break; + + case GFC_ISYM_MAX: + gfc_conv_intrinsic_minmax (se, expr, GT_EXPR); + break; + + case GFC_ISYM_MAXLOC: + gfc_conv_intrinsic_minmaxloc (se, expr, GT_EXPR); + break; + + case GFC_ISYM_MAXVAL: + gfc_conv_intrinsic_minmaxval (se, expr, GT_EXPR); + break; + + case GFC_ISYM_MERGE: + gfc_conv_intrinsic_merge (se, expr); + break; + + case GFC_ISYM_MIN: + gfc_conv_intrinsic_minmax (se, expr, LT_EXPR); + break; + + case GFC_ISYM_MINLOC: + gfc_conv_intrinsic_minmaxloc (se, expr, LT_EXPR); + break; + + case GFC_ISYM_MINVAL: + gfc_conv_intrinsic_minmaxval (se, expr, LT_EXPR); + break; + + case GFC_ISYM_NOT: + gfc_conv_intrinsic_not (se, expr); + break; + + case GFC_ISYM_PRESENT: + gfc_conv_intrinsic_present (se, expr); + break; + + case GFC_ISYM_PRODUCT: + gfc_conv_intrinsic_arith (se, expr, MULT_EXPR); + break; + + case GFC_ISYM_SIGN: + gfc_conv_intrinsic_sign (se, expr); + break; + + case GFC_ISYM_SIZE: + gfc_conv_intrinsic_size (se, expr); + break; + + case GFC_ISYM_SUM: + gfc_conv_intrinsic_arith (se, expr, PLUS_EXPR); + break; + + case GFC_ISYM_TRANSFER: + gfc_conv_intrinsic_transfer (se, expr); + break; + + case GFC_ISYM_UBOUND: + gfc_conv_intrinsic_bound (se, expr, 1); + break; + + case GFC_ISYM_DOT_PRODUCT: + case GFC_ISYM_MATMUL: + gfc_conv_intrinsic_funcall (se, expr); + break; + + default: + gfc_conv_intrinsic_lib_function (se, expr); + break; + } +} + + +/* This generates code to execute before entering the scalarization loop. + Currently does nothing. */ + +void +gfc_add_intrinsic_ss_code (gfc_loopinfo * loop ATTRIBUTE_UNUSED, gfc_ss * ss) +{ + switch (ss->expr->value.function.isym->generic_id) + { + case GFC_ISYM_UBOUND: + case GFC_ISYM_LBOUND: + break; + + default: + abort (); + break; + } +} + + +/* UBOUND and LBOUND intrinsics with one parameter are expanded into code + inside the scalarization loop. */ + +static gfc_ss * +gfc_walk_intrinsic_bound (gfc_ss * ss, gfc_expr * expr) +{ + gfc_ss *newss; + + /* The two argument version returns a scalar. */ + if (expr->value.function.actual->next->expr) + return ss; + + newss = gfc_get_ss (); + newss->type = GFC_SS_INTRINSIC; + newss->expr = expr; + newss->next = ss; + + return newss; +} + + +/* Walk an intrinsic array libcall. */ + +static gfc_ss * +gfc_walk_intrinsic_libfunc (gfc_ss * ss, gfc_expr * expr) +{ + gfc_ss *newss; + + assert (expr->rank > 0); + + newss = gfc_get_ss (); + newss->type = GFC_SS_FUNCTION; + newss->expr = expr; + newss->next = ss; + newss->data.info.dimen = expr->rank; + + return newss; +} + + +/* Returns nonzero if the specified intrinsic function call maps directly to a + an external library call. Should only be used for functions that return + arrays. */ + +int +gfc_is_intrinsic_libcall (gfc_expr * expr) +{ + assert (expr->expr_type == EXPR_FUNCTION && expr->value.function.isym); + assert (expr->rank > 0); + + switch (expr->value.function.isym->generic_id) + { + case GFC_ISYM_ALL: + case GFC_ISYM_ANY: + case GFC_ISYM_COUNT: + case GFC_ISYM_MATMUL: + case GFC_ISYM_MAXLOC: + case GFC_ISYM_MAXVAL: + case GFC_ISYM_MINLOC: + case GFC_ISYM_MINVAL: + case GFC_ISYM_PRODUCT: + case GFC_ISYM_SUM: + case GFC_ISYM_SHAPE: + case GFC_ISYM_SPREAD: + case GFC_ISYM_TRANSPOSE: + /* Ignore absent optional parameters. */ + return 1; + + case GFC_ISYM_RESHAPE: + case GFC_ISYM_CSHIFT: + case GFC_ISYM_EOSHIFT: + case GFC_ISYM_PACK: + case GFC_ISYM_UNPACK: + /* Pass absent optional parameters. */ + return 2; + + default: + return 0; + } +} + +/* Walk an intrinsic function. */ +gfc_ss * +gfc_walk_intrinsic_function (gfc_ss * ss, gfc_expr * expr, + gfc_intrinsic_sym * isym) +{ + assert (isym); + + if (isym->elemental) + return gfc_walk_elemental_function_args (ss, expr, GFC_SS_SCALAR); + + if (expr->rank == 0) + return ss; + + if (gfc_is_intrinsic_libcall (expr)) + return gfc_walk_intrinsic_libfunc (ss, expr); + + /* Special cases. */ + switch (isym->generic_id) + { + case GFC_ISYM_LBOUND: + case GFC_ISYM_UBOUND: + return gfc_walk_intrinsic_bound (ss, expr); + + default: + /* This probably meant someone forgot to add an intrinsic to the above + list(s) when they implemented it, or something's gone horribly wrong. + */ + gfc_todo_error ("Scalarization of non-elemental intrinsic: %s", + expr->value.function.name); + } +} + +#include "gt-fortran-trans-intrinsic.h" diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c new file mode 100644 index 00000000000..d18bb794195 --- /dev/null +++ b/gcc/fortran/trans-io.c @@ -0,0 +1,1157 @@ +/* IO Code translation/library interface + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-simple.h" +#include +#include "ggc.h" +#include "toplev.h" +#include "real.h" +#include +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-stmt.h" +#include "trans-array.h" +#include "trans-types.h" +#include "trans-const.h" + + +static GTY(()) tree gfc_pint4_type_node; + +/* Members of the ioparm structure. */ + +static GTY(()) tree ioparm_unit; +static GTY(()) tree ioparm_err; +static GTY(()) tree ioparm_end; +static GTY(()) tree ioparm_eor; +static GTY(()) tree ioparm_list_format; +static GTY(()) tree ioparm_library_return; +static GTY(()) tree ioparm_iostat; +static GTY(()) tree ioparm_exist; +static GTY(()) tree ioparm_opened; +static GTY(()) tree ioparm_number; +static GTY(()) tree ioparm_named; +static GTY(()) tree ioparm_rec; +static GTY(()) tree ioparm_nextrec; +static GTY(()) tree ioparm_size; +static GTY(()) tree ioparm_recl_in; +static GTY(()) tree ioparm_recl_out; +static GTY(()) tree ioparm_file; +static GTY(()) tree ioparm_file_len; +static GTY(()) tree ioparm_status; +static GTY(()) tree ioparm_status_len; +static GTY(()) tree ioparm_access; +static GTY(()) tree ioparm_access_len; +static GTY(()) tree ioparm_form; +static GTY(()) tree ioparm_form_len; +static GTY(()) tree ioparm_blank; +static GTY(()) tree ioparm_blank_len; +static GTY(()) tree ioparm_position; +static GTY(()) tree ioparm_position_len; +static GTY(()) tree ioparm_action; +static GTY(()) tree ioparm_action_len; +static GTY(()) tree ioparm_delim; +static GTY(()) tree ioparm_delim_len; +static GTY(()) tree ioparm_pad; +static GTY(()) tree ioparm_pad_len; +static GTY(()) tree ioparm_format; +static GTY(()) tree ioparm_format_len; +static GTY(()) tree ioparm_advance; +static GTY(()) tree ioparm_advance_len; +static GTY(()) tree ioparm_name; +static GTY(()) tree ioparm_name_len; +static GTY(()) tree ioparm_internal_unit; +static GTY(()) tree ioparm_internal_unit_len; +static GTY(()) tree ioparm_sequential; +static GTY(()) tree ioparm_sequential_len; +static GTY(()) tree ioparm_direct; +static GTY(()) tree ioparm_direct_len; +static GTY(()) tree ioparm_formatted; +static GTY(()) tree ioparm_formatted_len; +static GTY(()) tree ioparm_unformatted; +static GTY(()) tree ioparm_unformatted_len; +static GTY(()) tree ioparm_read; +static GTY(()) tree ioparm_read_len; +static GTY(()) tree ioparm_write; +static GTY(()) tree ioparm_write_len; +static GTY(()) tree ioparm_readwrite; +static GTY(()) tree ioparm_readwrite_len; +static GTY(()) tree ioparm_namelist_name; +static GTY(()) tree ioparm_namelist_name_len; +static GTY(()) tree ioparm_namelist_read_mode; + +/* The global I/O variables */ + +static GTY(()) tree ioparm_var; +static GTY(()) tree locus_file; +static GTY(()) tree locus_line; + + +/* Library I/O subroutines */ + +static GTY(()) tree iocall_read; +static GTY(()) tree iocall_read_done; +static GTY(()) tree iocall_write; +static GTY(()) tree iocall_write_done; +static GTY(()) tree iocall_x_integer; +static GTY(()) tree iocall_x_logical; +static GTY(()) tree iocall_x_character; +static GTY(()) tree iocall_x_real; +static GTY(()) tree iocall_x_complex; +static GTY(()) tree iocall_open; +static GTY(()) tree iocall_close; +static GTY(()) tree iocall_inquire; +static GTY(()) tree iocall_rewind; +static GTY(()) tree iocall_backspace; +static GTY(()) tree iocall_endfile; +static GTY(()) tree iocall_set_nml_val_int; +static GTY(()) tree iocall_set_nml_val_float; +static GTY(()) tree iocall_set_nml_val_char; +static GTY(()) tree iocall_set_nml_val_complex; +static GTY(()) tree iocall_set_nml_val_log; + +/* Variable for keeping track of what the last data transfer statement + was. Used for deciding which subroutine to call when the data + transfer is complete. */ +static enum { READ, WRITE } last_dt; + +#define ADD_FIELD(name, type) \ + ioparm_ ## name = gfc_add_field_to_struct \ + (&(TYPE_FIELDS (ioparm_type)), ioparm_type, \ + get_identifier (stringize(name)), type) + +#define ADD_STRING(name) \ + ioparm_ ## name = gfc_add_field_to_struct \ + (&(TYPE_FIELDS (ioparm_type)), ioparm_type, \ + get_identifier (stringize(name)), pchar_type_node); \ + ioparm_ ## name ## _len = gfc_add_field_to_struct \ + (&(TYPE_FIELDS (ioparm_type)), ioparm_type, \ + get_identifier (stringize(name) "_len"), gfc_int4_type_node) + + +/* Create function decls for IO library functions. */ + +void +gfc_build_io_library_fndecls (void) +{ + tree ioparm_type; + + gfc_pint4_type_node = build_pointer_type (gfc_int4_type_node); + +/* Build the st_parameter structure. Information associated with I/O + calls are transferred here. This must match the one defined in the + library exactly. */ + + ioparm_type = make_node (RECORD_TYPE); + TYPE_NAME (ioparm_type) = get_identifier ("_gfc_ioparm"); + + ADD_FIELD (unit, gfc_int4_type_node); + ADD_FIELD (err, gfc_int4_type_node); + ADD_FIELD (end, gfc_int4_type_node); + ADD_FIELD (eor, gfc_int4_type_node); + ADD_FIELD (list_format, gfc_int4_type_node); + ADD_FIELD (library_return, gfc_int4_type_node); + + ADD_FIELD (iostat, gfc_pint4_type_node); + ADD_FIELD (exist, gfc_pint4_type_node); + ADD_FIELD (opened, gfc_pint4_type_node); + ADD_FIELD (number, gfc_pint4_type_node); + ADD_FIELD (named, gfc_pint4_type_node); + ADD_FIELD (rec, gfc_pint4_type_node); + ADD_FIELD (nextrec, gfc_pint4_type_node); + ADD_FIELD (size, gfc_pint4_type_node); + + ADD_FIELD (recl_in, gfc_pint4_type_node); + ADD_FIELD (recl_out, gfc_pint4_type_node); + + ADD_STRING (file); + ADD_STRING (status); + + ADD_STRING (access); + ADD_STRING (form); + ADD_STRING (blank); + ADD_STRING (position); + ADD_STRING (action); + ADD_STRING (delim); + ADD_STRING (pad); + ADD_STRING (format); + ADD_STRING (advance); + ADD_STRING (name); + ADD_STRING (internal_unit); + ADD_STRING (sequential); + + ADD_STRING (direct); + ADD_STRING (formatted); + ADD_STRING (unformatted); + ADD_STRING (read); + ADD_STRING (write); + ADD_STRING (readwrite); + + ADD_STRING (namelist_name); + ADD_FIELD (namelist_read_mode, gfc_int4_type_node); + + gfc_finish_type (ioparm_type); + + ioparm_var = build_decl (VAR_DECL, get_identifier (PREFIX("ioparm")), + ioparm_type); + DECL_EXTERNAL (ioparm_var) = 1; + TREE_PUBLIC (ioparm_var) = 1; + + locus_line = build_decl (VAR_DECL, get_identifier (PREFIX("line")), + gfc_int4_type_node); + DECL_EXTERNAL (locus_line) = 1; + TREE_PUBLIC (locus_line) = 1; + + locus_file = build_decl (VAR_DECL, get_identifier (PREFIX("filename")), + pchar_type_node); + DECL_EXTERNAL (locus_file) = 1; + TREE_PUBLIC (locus_file) = 1; + + /* Define the transfer functions. */ + + iocall_x_integer = + gfc_build_library_function_decl (get_identifier + (PREFIX("transfer_integer")), + void_type_node, 2, pvoid_type_node, + gfc_int4_type_node); + + iocall_x_logical = + gfc_build_library_function_decl (get_identifier + (PREFIX("transfer_logical")), + void_type_node, 2, pvoid_type_node, + gfc_int4_type_node); + + iocall_x_character = + gfc_build_library_function_decl (get_identifier + (PREFIX("transfer_character")), + void_type_node, 2, pvoid_type_node, + gfc_int4_type_node); + + iocall_x_real = + gfc_build_library_function_decl (get_identifier (PREFIX("transfer_real")), + void_type_node, 2, + pvoid_type_node, gfc_int4_type_node); + + iocall_x_complex = + gfc_build_library_function_decl (get_identifier + (PREFIX("transfer_complex")), + void_type_node, 2, pvoid_type_node, + gfc_int4_type_node); + + /* Library entry points */ + + iocall_read = + gfc_build_library_function_decl (get_identifier (PREFIX("st_read")), + void_type_node, 0); + + iocall_write = + gfc_build_library_function_decl (get_identifier (PREFIX("st_write")), + void_type_node, 0); + iocall_open = + gfc_build_library_function_decl (get_identifier (PREFIX("st_open")), + void_type_node, 0); + + iocall_close = + gfc_build_library_function_decl (get_identifier (PREFIX("st_close")), + void_type_node, 0); + + iocall_inquire = + gfc_build_library_function_decl (get_identifier (PREFIX("st_inquire")), + gfc_int4_type_node, 0); + + iocall_rewind = + gfc_build_library_function_decl (get_identifier (PREFIX("st_rewind")), + gfc_int4_type_node, 0); + + iocall_backspace = + gfc_build_library_function_decl (get_identifier (PREFIX("st_backspace")), + gfc_int4_type_node, 0); + + iocall_endfile = + gfc_build_library_function_decl (get_identifier (PREFIX("st_endfile")), + gfc_int4_type_node, 0); + /* Library helpers */ + + iocall_read_done = + gfc_build_library_function_decl (get_identifier (PREFIX("st_read_done")), + gfc_int4_type_node, 0); + + iocall_write_done = + gfc_build_library_function_decl (get_identifier (PREFIX("st_write_done")), + gfc_int4_type_node, 0); + iocall_set_nml_val_int = + gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var_int")), + void_type_node, 4, + pvoid_type_node, pvoid_type_node, + gfc_int4_type_node,gfc_int4_type_node); + + iocall_set_nml_val_float = + gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var_float")), + void_type_node, 4, + pvoid_type_node, pvoid_type_node, + gfc_int4_type_node,gfc_int4_type_node); + iocall_set_nml_val_char = + gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var_char")), + void_type_node, 4, + pvoid_type_node, pvoid_type_node, + gfc_int4_type_node,gfc_int4_type_node); + iocall_set_nml_val_complex = + gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var_complex")), + void_type_node, 4, + pvoid_type_node, pvoid_type_node, + gfc_int4_type_node,gfc_int4_type_node); + iocall_set_nml_val_log = + gfc_build_library_function_decl (get_identifier (PREFIX("st_set_nml_var_log")), + void_type_node, 4, + pvoid_type_node, pvoid_type_node, + gfc_int4_type_node,gfc_int4_type_node); + +} + + +/* Generate code to store an non-string I/O parameter into the + ioparm structure. This is a pass by value. */ + +static void +set_parameter_value (stmtblock_t * block, tree var, gfc_expr * e) +{ + gfc_se se; + tree tmp; + + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, e, TREE_TYPE (var)); + gfc_add_block_to_block (block, &se.pre); + + tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var); + gfc_add_modify_expr (block, tmp, se.expr); +} + + +/* Generate code to store an non-string I/O parameter into the + ioparm structure. This is pass by reference. */ + +static void +set_parameter_ref (stmtblock_t * block, tree var, gfc_expr * e) +{ + gfc_se se; + tree tmp; + + gfc_init_se (&se, NULL); + se.want_pointer = 1; + + gfc_conv_expr_type (&se, e, TREE_TYPE (var)); + gfc_add_block_to_block (block, &se.pre); + + tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var); + gfc_add_modify_expr (block, tmp, se.expr); +} + + +/* Generate code to store a string and its length into the + ioparm structure. */ + +static void +set_string (stmtblock_t * block, stmtblock_t * postblock, tree var, + tree var_len, gfc_expr * e) +{ + gfc_se se; + tree tmp; + tree msg; + tree io; + tree len; + + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, e); + + io = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var); + len = build (COMPONENT_REF, TREE_TYPE (var_len), ioparm_var, var_len); + + /* Integer variable assigned a format label. */ + if (e->ts.type == BT_INTEGER && e->symtree->n.sym->attr.assign == 1) + { + msg = + gfc_build_string_const (37, "Assigned label is not a format label"); + tmp = GFC_DECL_STRING_LEN (se.expr); + tmp = build (LE_EXPR, boolean_type_node, tmp, integer_minus_one_node); + gfc_trans_runtime_check (tmp, msg, &se.pre); + gfc_add_modify_expr (&se.pre, io, GFC_DECL_ASSIGN_ADDR (se.expr)); + gfc_add_modify_expr (&se.pre, len, GFC_DECL_STRING_LEN (se.expr)); + } + else + { + gfc_conv_string_parameter (&se); + gfc_add_modify_expr (&se.pre, io, se.expr); + gfc_add_modify_expr (&se.pre, len, se.string_length); + } + + gfc_add_block_to_block (block, &se.pre); + gfc_add_block_to_block (postblock, &se.post); + +} + + +/* Set a member of the ioparm structure to one. */ +static void +set_flag (stmtblock_t *block, tree var) +{ + tree tmp; + + tmp = build (COMPONENT_REF, TREE_TYPE(var), ioparm_var, var); + gfc_add_modify_expr (block, tmp, integer_one_node); +} + + +/* Add a case to a IO-result switch. */ + +static void +add_case (int label_value, gfc_st_label * label, stmtblock_t * body) +{ + tree tmp, value; + + if (label == NULL) + return; /* No label, no case */ + + value = build_int_2 (label_value, 0); + + /* Make a backend label for this case. */ + tmp = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (tmp) = current_function_decl; + + /* And the case itself. */ + tmp = build_v (CASE_LABEL_EXPR, value, NULL_TREE, tmp); + gfc_add_expr_to_block (body, tmp); + + /* Jump to the label. */ + tmp = build1_v (GOTO_EXPR, gfc_get_label_decl (label)); + gfc_add_expr_to_block (body, tmp); +} + + +/* Generate a switch statement that branches to the correct I/O + result label. The last statement of an I/O call stores the + result into a variable because there is often cleanup that + must be done before the switch, so a temporary would have to + be created anyway. */ + +static void +io_result (stmtblock_t * block, gfc_st_label * err_label, + gfc_st_label * end_label, gfc_st_label * eor_label) +{ + stmtblock_t body; + tree tmp, rc; + + /* If no labels are specified, ignore the result instead + of building an empty switch. */ + if (err_label == NULL + && end_label == NULL + && eor_label == NULL) + return; + + /* Build a switch statement. */ + gfc_start_block (&body); + + /* The label values here must be the same as the values + in the library_return enum in the runtime library */ + add_case (1, err_label, &body); + add_case (2, end_label, &body); + add_case (3, eor_label, &body); + + tmp = gfc_finish_block (&body); + + rc = build (COMPONENT_REF, TREE_TYPE (ioparm_library_return), ioparm_var, + ioparm_library_return); + + tmp = build_v (SWITCH_EXPR, rc, tmp, NULL_TREE); + + gfc_add_expr_to_block (block, tmp); +} + + +/* Store the current file and line number to variables so that if a + library call goes awry, we can tell the user where the problem is. */ + +static void +set_error_locus (stmtblock_t * block, locus * where) +{ + gfc_file *f; + tree tmp; + int line; + + f = where->file; + tmp = gfc_build_string_const (strlen (f->filename) + 1, f->filename); + + tmp = gfc_build_addr_expr (pchar_type_node, tmp); + gfc_add_modify_expr (block, locus_file, tmp); + + line = where->lp->start_line + where->line; + gfc_add_modify_expr (block, locus_line, build_int_2 (line, 0)); +} + + +/* Translate an OPEN statement. */ + +tree +gfc_trans_open (gfc_code * code) +{ + stmtblock_t block, post_block; + gfc_open *p; + tree tmp; + + gfc_init_block (&block); + gfc_init_block (&post_block); + + set_error_locus (&block, &code->loc); + p = code->ext.open; + + if (p->unit) + set_parameter_value (&block, ioparm_unit, p->unit); + + if (p->file) + set_string (&block, &post_block, ioparm_file, ioparm_file_len, p->file); + + if (p->status) + set_string (&block, &post_block, ioparm_status, + ioparm_status_len, p->status); + + if (p->access) + set_string (&block, &post_block, ioparm_access, + ioparm_access_len, p->access); + + if (p->form) + set_string (&block, &post_block, ioparm_form, ioparm_form_len, p->form); + + if (p->recl) + set_parameter_value (&block, ioparm_recl_in, p->recl); + + if (p->blank) + set_string (&block, &post_block, ioparm_blank, ioparm_blank_len, + p->blank); + + if (p->position) + set_string (&block, &post_block, ioparm_position, + ioparm_position_len, p->position); + + if (p->action) + set_string (&block, &post_block, ioparm_action, + ioparm_action_len, p->action); + + if (p->delim) + set_string (&block, &post_block, ioparm_delim, ioparm_delim_len, + p->delim); + + if (p->pad) + set_string (&block, &post_block, ioparm_pad, ioparm_pad_len, p->pad); + + if (p->iostat) + set_parameter_ref (&block, ioparm_iostat, p->iostat); + + if (p->err) + set_flag (&block, ioparm_err); + + tmp = gfc_build_function_call (iocall_open, NULL_TREE); + gfc_add_expr_to_block (&block, tmp); + + gfc_add_block_to_block (&block, &post_block); + + io_result (&block, p->err, NULL, NULL); + + return gfc_finish_block (&block); +} + + +/* Translate a CLOSE statement. */ + +tree +gfc_trans_close (gfc_code * code) +{ + stmtblock_t block, post_block; + gfc_close *p; + tree tmp; + + gfc_init_block (&block); + gfc_init_block (&post_block); + + set_error_locus (&block, &code->loc); + p = code->ext.close; + + if (p->unit) + set_parameter_value (&block, ioparm_unit, p->unit); + + if (p->status) + set_string (&block, &post_block, ioparm_status, + ioparm_status_len, p->status); + + if (p->iostat) + set_parameter_ref (&block, ioparm_iostat, p->iostat); + + if (p->err) + set_flag (&block, ioparm_err); + + tmp = gfc_build_function_call (iocall_close, NULL_TREE); + gfc_add_expr_to_block (&block, tmp); + + gfc_add_block_to_block (&block, &post_block); + + io_result (&block, p->err, NULL, NULL); + + return gfc_finish_block (&block); +} + + +/* Common subroutine for building a file positioning statement. */ + +static tree +build_filepos (tree function, gfc_code * code) +{ + stmtblock_t block; + gfc_filepos *p; + tree tmp; + + p = code->ext.filepos; + + gfc_init_block (&block); + + set_error_locus (&block, &code->loc); + + if (p->unit) + set_parameter_value (&block, ioparm_unit, p->unit); + + if (p->iostat) + set_parameter_ref (&block, ioparm_iostat, p->iostat); + + if (p->err) + set_flag (&block, ioparm_err); + + tmp = gfc_build_function_call (function, NULL); + gfc_add_expr_to_block (&block, tmp); + + io_result (&block, p->err, NULL, NULL); + + return gfc_finish_block (&block); +} + + +/* Translate a BACKSPACE statement. */ + +tree +gfc_trans_backspace (gfc_code * code) +{ + + return build_filepos (iocall_backspace, code); +} + + +/* Translate an ENDFILE statement. */ + +tree +gfc_trans_endfile (gfc_code * code) +{ + + return build_filepos (iocall_endfile, code); +} + + +/* Translate a REWIND statement. */ + +tree +gfc_trans_rewind (gfc_code * code) +{ + + return build_filepos (iocall_rewind, code); +} + + +/* Translate the non-IOLENGTH form of an INQUIRE statement. */ + +tree +gfc_trans_inquire (gfc_code * code) +{ + stmtblock_t block, post_block; + gfc_inquire *p; + tree tmp; + + gfc_init_block (&block); + gfc_init_block (&post_block); + + set_error_locus (&block, &code->loc); + p = code->ext.inquire; + + if (p->unit) + set_parameter_value (&block, ioparm_unit, p->unit); + + if (p->file) + set_string (&block, &post_block, ioparm_file, ioparm_file_len, p->file); + + if (p->iostat) + set_parameter_ref (&block, ioparm_iostat, p->iostat); + + if (p->exist) + set_parameter_ref (&block, ioparm_exist, p->exist); + + if (p->opened) + set_parameter_ref (&block, ioparm_opened, p->opened); + + if (p->number) + set_parameter_ref (&block, ioparm_number, p->number); + + if (p->named) + set_parameter_ref (&block, ioparm_named, p->named); + + if (p->name) + set_string (&block, &post_block, ioparm_name, ioparm_name_len, p->name); + + if (p->access) + set_string (&block, &post_block, ioparm_access, + ioparm_access_len, p->access); + + if (p->sequential) + set_string (&block, &post_block, ioparm_sequential, + ioparm_sequential_len, p->sequential); + + if (p->direct) + set_string (&block, &post_block, ioparm_direct, + ioparm_direct_len, p->direct); + + if (p->form) + set_string (&block, &post_block, ioparm_form, ioparm_form_len, p->form); + + if (p->formatted) + set_string (&block, &post_block, ioparm_formatted, + ioparm_formatted_len, p->formatted); + + if (p->unformatted) + set_string (&block, &post_block, ioparm_unformatted, + ioparm_unformatted_len, p->unformatted); + + if (p->recl) + set_parameter_ref (&block, ioparm_recl_out, p->recl); + + if (p->nextrec) + set_parameter_ref (&block, ioparm_nextrec, p->nextrec); + + if (p->blank) + set_string (&block, &post_block, ioparm_blank, ioparm_blank_len, + p->blank); + + if (p->position) + set_string (&block, &post_block, ioparm_position, + ioparm_position_len, p->position); + + if (p->action) + set_string (&block, &post_block, ioparm_action, + ioparm_action_len, p->action); + + if (p->read) + set_string (&block, &post_block, ioparm_read, ioparm_read_len, p->read); + + if (p->write) + set_string (&block, &post_block, ioparm_write, + ioparm_write_len, p->write); + + if (p->readwrite) + set_string (&block, &post_block, ioparm_readwrite, + ioparm_readwrite_len, p->readwrite); + + if (p->delim) + set_string (&block, &post_block, ioparm_delim, ioparm_delim_len, + p->delim); + + if (p->err) + set_flag (&block, ioparm_err); + + tmp = gfc_build_function_call (iocall_inquire, NULL); + gfc_add_expr_to_block (&block, tmp); + + gfc_add_block_to_block (&block, &post_block); + + io_result (&block, p->err, NULL, NULL); + + return gfc_finish_block (&block); +} + + +/* Translate the IOLENGTH form of an INQUIRE statement. We treat + this as a third sort of data transfer statement, except that + lengths are summed instead of actually transfering any data. */ + +tree +gfc_trans_iolength (gfc_code * c ATTRIBUTE_UNUSED) +{ + gfc_todo_error ("IOLENGTH statement"); +} + +static gfc_expr * +gfc_new_nml_name_expr (char * name) +{ + gfc_expr * nml_name; + nml_name = gfc_get_expr(); + nml_name->ref = NULL; + nml_name->expr_type = EXPR_CONSTANT; + nml_name->ts.kind = gfc_default_character_kind (); + nml_name->ts.type = BT_CHARACTER; + nml_name->value.character.length = strlen(name); + nml_name->value.character.string = name; + + return nml_name; +} + +static gfc_expr * +get_new_var_expr(gfc_symbol * sym) +{ + gfc_expr * nml_var; + + nml_var = gfc_get_expr(); + nml_var->expr_type = EXPR_VARIABLE; + nml_var->ts = sym->ts; + if (sym->as) + nml_var->rank = sym->as->rank; + nml_var->symtree = (gfc_symtree *)gfc_getmem (sizeof (gfc_symtree)); + nml_var->symtree->n.sym = sym; + nml_var->where = sym->declared_at; + sym->attr.referenced = 1; + + return nml_var; +} + + +/* Create a data transfer statement. Not all of the fields are valid + for both reading and writing, but improper use has been filtered + out by now. */ + +static tree +build_dt (tree * function, gfc_code * code) +{ + stmtblock_t block, post_block; + gfc_dt *dt; + tree tmp, args, arg2; + gfc_expr *nmlname, *nmlvar; + gfc_namelist *nml, *nml_tail; + gfc_se se,se2; + int ts_kind, ts_type, name_len; + + gfc_init_block (&block); + gfc_init_block (&post_block); + + set_error_locus (&block, &code->loc); + dt = code->ext.dt; + + if (dt->io_unit) + { + if (dt->io_unit->ts.type == BT_CHARACTER) + { + set_string (&block, &post_block, ioparm_internal_unit, + ioparm_internal_unit_len, dt->io_unit); + } + else + set_parameter_value (&block, ioparm_unit, dt->io_unit); + } + + if (dt->rec) + set_parameter_value (&block, ioparm_rec, dt->rec); + + if (dt->advance) + set_string (&block, &post_block, ioparm_advance, ioparm_advance_len, + dt->advance); + + if (dt->format_expr) + set_string (&block, &post_block, ioparm_format, ioparm_format_len, + dt->format_expr); + + if (dt->format_label) + { + if (dt->format_label == &format_asterisk) + set_flag (&block, ioparm_list_format); + else + set_string (&block, &post_block, ioparm_format, + ioparm_format_len, dt->format_label->format); + } + + if (dt->iostat) + set_parameter_ref (&block, ioparm_iostat, dt->iostat); + + if (dt->size) + set_parameter_ref (&block, ioparm_size, dt->size); + + if (dt->err) + set_flag (&block, ioparm_err); + + if (dt->eor) + set_flag(&block, ioparm_eor); + + if (dt->end) + set_flag(&block, ioparm_end); + + if (dt->namelist) + { + if (dt->format_expr || dt->format_label) + fatal_error("A format cannot be specified with a namelist"); + + nmlname = gfc_new_nml_name_expr(dt->namelist->name); + + set_string (&block, &post_block, ioparm_namelist_name, + ioparm_namelist_name_len, nmlname); + + if (last_dt == READ) + set_flag (&block, ioparm_namelist_read_mode); + + nml = dt->namelist->namelist; + nml_tail = dt->namelist->namelist_tail; + + while(nml != NULL) + { + gfc_init_se (&se, NULL); + gfc_init_se (&se2, NULL); + nmlvar = get_new_var_expr(nml->sym); + nmlname = gfc_new_nml_name_expr(nml->sym->name); + name_len = strlen(nml->sym->name); + ts_kind = nml->sym->ts.kind; + ts_type = nml->sym->ts.type; + + gfc_conv_expr_reference (&se2, nmlname); + gfc_conv_expr_reference (&se, nmlvar); + args = gfc_chainon_list (NULL_TREE, se.expr); + args = gfc_chainon_list (args, se2.expr); + args = gfc_chainon_list (args, se2.string_length); + arg2 = build_int_2 (ts_kind, 0); + args = gfc_chainon_list (args,arg2); + switch (ts_type) + { + case BT_INTEGER: + tmp = gfc_build_function_call (iocall_set_nml_val_int, args); + break; + case BT_CHARACTER: + tmp = gfc_build_function_call (iocall_set_nml_val_char, args); + break; + case BT_REAL: + tmp = gfc_build_function_call (iocall_set_nml_val_float, args); + break; + case BT_LOGICAL: + tmp = gfc_build_function_call (iocall_set_nml_val_log, args); + break; + case BT_COMPLEX: + tmp = gfc_build_function_call (iocall_set_nml_val_complex, args); + break; + default : + internal_error ("Bad namelist IO basetype (%d)", ts_type); + } + + gfc_add_expr_to_block (&block, tmp); + + nml = nml->next; + } + } + + tmp = gfc_build_function_call (*function, NULL_TREE); + gfc_add_expr_to_block (&block, tmp); + + gfc_add_block_to_block (&block, &post_block); + + return gfc_finish_block (&block); +} + + +/* Translate a READ statement. */ + +tree +gfc_trans_read (gfc_code * code) +{ + + last_dt = READ; + return build_dt (&iocall_read, code); +} + + +/* Translate a WRITE statement */ + +tree +gfc_trans_write (gfc_code * code) +{ + + last_dt = WRITE; + return build_dt (&iocall_write, code); +} + + +/* Finish a data transfer statement. */ + +tree +gfc_trans_dt_end (gfc_code * code) +{ + tree function, tmp; + stmtblock_t block; + + gfc_init_block (&block); + + function = (last_dt == READ) ? iocall_read_done : iocall_write_done; + + tmp = gfc_build_function_call (function, NULL); + gfc_add_expr_to_block (&block, tmp); + + io_result (&block, code->ext.dt->err, code->ext.dt->end, code->ext.dt->eor); + + return gfc_finish_block (&block); +} + + +/* Generate the call for a scalar transfer node. */ + +static void +transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr) +{ + tree args, tmp, function, arg2, field, expr; + gfc_component *c; + int kind; + + kind = ts->kind; + function = NULL; + arg2 = NULL; + + switch (ts->type) + { + case BT_INTEGER: + arg2 = build_int_2 (kind, 0); + function = iocall_x_integer; + break; + + case BT_REAL: + arg2 = build_int_2 (kind, 0); + function = iocall_x_real; + break; + + case BT_COMPLEX: + arg2 = build_int_2 (kind, 0); + function = iocall_x_complex; + break; + + case BT_LOGICAL: + arg2 = build_int_2 (kind, 0); + function = iocall_x_logical; + break; + + case BT_CHARACTER: + arg2 = se->string_length; + function = iocall_x_character; + break; + + case BT_DERIVED: + expr = gfc_evaluate_now (addr_expr, &se->pre); + expr = gfc_build_indirect_ref (expr); + + for (c = ts->derived->components; c; c = c->next) + { + field = c->backend_decl; + assert (field && TREE_CODE (field) == FIELD_DECL); + + tmp = build (COMPONENT_REF, TREE_TYPE (field), expr, field); + + if (c->ts.type == BT_CHARACTER) + { + assert (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE); + se->string_length = + TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tmp))); + } + transfer_expr (se, &c->ts, gfc_build_addr_expr (NULL, tmp)); + } + return; + + default: + internal_error ("Bad IO basetype (%d)", ts->type); + } + + args = gfc_chainon_list (NULL_TREE, addr_expr); + args = gfc_chainon_list (args, arg2); + + tmp = gfc_build_function_call (function, args); + gfc_add_expr_to_block (&se->pre, tmp); + gfc_add_block_to_block (&se->pre, &se->post); +} + + +/* gfc_trans_transfer()-- Translate a TRANSFER code node */ + +tree +gfc_trans_transfer (gfc_code * code) +{ + stmtblock_t block, body; + gfc_loopinfo loop; + gfc_expr *expr; + gfc_ss *ss; + gfc_se se; + tree tmp; + + gfc_start_block (&block); + + expr = code->expr; + ss = gfc_walk_expr (expr); + + gfc_init_se (&se, NULL); + + if (ss == gfc_ss_terminator) + gfc_init_block (&body); + else + { + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + gfc_add_ss_to_loop (&loop, ss); + + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + /* The main loop body. */ + gfc_mark_ss_chain_used (ss, 1); + gfc_start_scalarized_body (&loop, &body); + + gfc_copy_loopinfo_to_se (&se, &loop); + se.ss = ss; + } + + gfc_conv_expr_reference (&se, expr); + + transfer_expr (&se, &expr->ts, se.expr); + + gfc_add_block_to_block (&body, &se.pre); + gfc_add_block_to_block (&body, &se.post); + + if (se.ss == NULL) + tmp = gfc_finish_block (&body); + else + { + assert (se.ss == gfc_ss_terminator); + gfc_trans_scalarizing_loops (&loop, &body); + + gfc_add_block_to_block (&loop.pre, &loop.post); + tmp = gfc_finish_block (&loop.pre); + gfc_cleanup_loop (&loop); + } + + gfc_add_expr_to_block (&block, tmp); + + return gfc_finish_block (&block);; +} + +#include "gt-fortran-trans-io.h" + diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c new file mode 100644 index 00000000000..0de62a5367c --- /dev/null +++ b/gcc/fortran/trans-stmt.c @@ -0,0 +1,3159 @@ +/* Statement translation -- generate GCC trees from gfc_code. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + and Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-simple.h" +#include +#include "ggc.h" +#include "toplev.h" +#include "real.h" +#include +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-stmt.h" +#include "trans-types.h" +#include "trans-array.h" +#include "trans-const.h" +#include "arith.h" + +int has_alternate_specifier; + +typedef struct iter_info +{ + tree var; + tree start; + tree end; + tree step; + struct iter_info *next; +} +iter_info; + +typedef struct temporary_list +{ + tree temporary; + struct temporary_list *next; +} +temporary_list; + +typedef struct forall_info +{ + iter_info *this_loop; + tree mask; + tree pmask; + tree maskindex; + int nvar; + tree size; + struct forall_info *outer; + struct forall_info *next_nest; +} +forall_info; + +static void gfc_trans_where_2 (gfc_code *, tree, tree, forall_info *, + stmtblock_t *, temporary_list **temp); + +/* Translate a F95 label number to a LABEL_EXPR. */ + +tree +gfc_trans_label_here (gfc_code * code) +{ + return build1_v (LABEL_EXPR, gfc_get_label_decl (code->here)); +} + +/* Translate a label assignment statement. */ +tree +gfc_trans_label_assign (gfc_code * code) +{ + tree label_tree; + gfc_se se; + tree len; + tree addr; + tree len_tree; + char *label_str; + int label_len; + + /* Start a new block. */ + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + gfc_conv_expr (&se, code->expr); + len = GFC_DECL_STRING_LEN (se.expr); + addr = GFC_DECL_ASSIGN_ADDR (se.expr); + + label_tree = gfc_get_label_decl (code->label); + + if (code->label->defined == ST_LABEL_TARGET) + { + label_tree = gfc_build_addr_expr (pvoid_type_node, label_tree); + len_tree = integer_minus_one_node; + } + else + { + label_str = code->label->format->value.character.string; + label_len = code->label->format->value.character.length; + len_tree = build_int_2 (label_len, 0); + label_tree = gfc_build_string_const (label_len + 1, label_str); + label_tree = gfc_build_addr_expr (pchar_type_node, label_tree); + } + + gfc_add_modify_expr (&se.pre, len, len_tree); + gfc_add_modify_expr (&se.pre, addr, label_tree); + + return gfc_finish_block (&se.pre); +} + +/* Translate a GOTO statement. */ + +tree +gfc_trans_goto (gfc_code * code) +{ + tree assigned_goto; + tree target; + tree tmp; + tree assign_error; + tree range_error; + gfc_se se; + + + if (code->label != NULL) + return build1_v (GOTO_EXPR, gfc_get_label_decl (code->label)); + + /* ASSIGNED GOTO. */ + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + gfc_conv_expr (&se, code->expr); + assign_error = + gfc_build_string_const (37, "Assigned label is not a target label"); + tmp = GFC_DECL_STRING_LEN (se.expr); + tmp = build (NE_EXPR, boolean_type_node, tmp, integer_minus_one_node); + gfc_trans_runtime_check (tmp, assign_error, &se.pre); + + assigned_goto = GFC_DECL_ASSIGN_ADDR (se.expr); + target = build1 (GOTO_EXPR, void_type_node, assigned_goto); + + code = code->block; + if (code == NULL) + { + gfc_add_expr_to_block (&se.pre, target); + return gfc_finish_block (&se.pre); + } + + /* Check the label list. */ + range_error = + gfc_build_string_const (34, "Assigned label is not in the list"); + + do + { + tmp = gfc_get_label_decl (code->label); + tmp = gfc_build_addr_expr (pvoid_type_node, tmp); + tmp = build (EQ_EXPR, boolean_type_node, tmp, assigned_goto); + tmp = build_v (COND_EXPR, tmp, target, build_empty_stmt ()); + gfc_add_expr_to_block (&se.pre, tmp); + code = code->block; + } + while (code != NULL); + gfc_trans_runtime_check (boolean_true_node, range_error, &se.pre); + return gfc_finish_block (&se.pre); +} + + +/* Translate the CALL statement. Builds a call to an F95 subroutine. */ + +tree +gfc_trans_call (gfc_code * code) +{ + gfc_se se; + + /* A CALL starts a new block because the actual arguments may have to + be evaluated first. */ + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + assert (code->resolved_sym); + has_alternate_specifier = 0; + + /* Translate the call. */ + gfc_conv_function_call (&se, code->resolved_sym, code->ext.actual); + + /* A subroutine without side-effect, by definition, does nothing! */ + TREE_SIDE_EFFECTS (se.expr) = 1; + + /* Chain the pieces together and return the block. */ + if (has_alternate_specifier) + { + gfc_code *select_code; + gfc_symbol *sym; + select_code = code->next; + assert(select_code->op == EXEC_SELECT); + sym = select_code->expr->symtree->n.sym; + se.expr = convert (gfc_typenode_for_spec (&sym->ts), se.expr); + gfc_add_modify_expr (&se.pre, sym->backend_decl, se.expr); + } + else + gfc_add_expr_to_block (&se.pre, se.expr); + + gfc_add_block_to_block (&se.pre, &se.post); + return gfc_finish_block (&se.pre); +} + + +/* Translate the RETURN statement. */ + +tree +gfc_trans_return (gfc_code * code ATTRIBUTE_UNUSED) +{ + if (code->expr) + { + gfc_se se; + tree tmp; + tree result; + + /* if code->expr is not NULL, this return statement must appear + in a subroutine and current_fake_result_decl has already + been generated. */ + + result = gfc_get_fake_result_decl (NULL); + if (!result) + { + gfc_warning ("An alternate return at %L without a * dummy argument", + &code->expr->where); + return build1_v (GOTO_EXPR, gfc_get_return_label ()); + } + + /* Start a new block for this statement. */ + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + gfc_conv_expr (&se, code->expr); + + tmp = build (MODIFY_EXPR, TREE_TYPE (result), result, se.expr); + gfc_add_expr_to_block (&se.pre, tmp); + + tmp = build1_v (GOTO_EXPR, gfc_get_return_label ()); + gfc_add_expr_to_block (&se.pre, tmp); + gfc_add_block_to_block (&se.pre, &se.post); + return gfc_finish_block (&se.pre); + } + else + return build1_v (GOTO_EXPR, gfc_get_return_label ()); +} + + +/* Translate the PAUSE statement. We have to translate this statement + to a runtime library call. */ + +tree +gfc_trans_pause (gfc_code * code) +{ + gfc_se se; + tree args; + tree tmp; + tree fndecl; + + /* Start a new block for this statement. */ + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + + if (code->expr == NULL) + { + tmp = build_int_2 (code->ext.stop_code, 0); + TREE_TYPE (tmp) = gfc_int4_type_node; + args = gfc_chainon_list (NULL_TREE, tmp); + fndecl = gfor_fndecl_pause_numeric; + } + else + { + gfc_conv_expr_reference (&se, code->expr); + args = gfc_chainon_list (NULL_TREE, se.expr); + args = gfc_chainon_list (args, se.string_length); + fndecl = gfor_fndecl_pause_string; + } + + tmp = gfc_build_function_call (fndecl, args); + gfc_add_expr_to_block (&se.pre, tmp); + + gfc_add_block_to_block (&se.pre, &se.post); + + return gfc_finish_block (&se.pre); +} + + +/* Translate the STOP statement. We have to translate this statement + to a runtime library call. */ + +tree +gfc_trans_stop (gfc_code * code) +{ + gfc_se se; + tree args; + tree tmp; + tree fndecl; + + /* Start a new block for this statement. */ + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + + if (code->expr == NULL) + { + tmp = build_int_2 (code->ext.stop_code, 0); + TREE_TYPE (tmp) = gfc_int4_type_node; + args = gfc_chainon_list (NULL_TREE, tmp); + fndecl = gfor_fndecl_stop_numeric; + } + else + { + gfc_conv_expr_reference (&se, code->expr); + args = gfc_chainon_list (NULL_TREE, se.expr); + args = gfc_chainon_list (args, se.string_length); + fndecl = gfor_fndecl_stop_string; + } + + tmp = gfc_build_function_call (fndecl, args); + gfc_add_expr_to_block (&se.pre, tmp); + + gfc_add_block_to_block (&se.pre, &se.post); + + return gfc_finish_block (&se.pre); +} + + +/* Generate GENERIC for the IF construct. This function also deals with + the simple IF statement, because the front end translates the IF + statement into an IF construct. + + We translate: + + IF (cond) THEN + then_clause + ELSEIF (cond2) + elseif_clause + ELSE + else_clause + ENDIF + + into: + + pre_cond_s; + if (cond_s) + { + then_clause; + } + else + { + pre_cond_s + if (cond_s) + { + elseif_clause + } + else + { + else_clause; + } + } + + where COND_S is the simplified version of the predicate. PRE_COND_S + are the pre side-effects produced by the translation of the + conditional. + We need to build the chain recursively otherwise we run into + problems with folding incomplete statements. */ + +static tree +gfc_trans_if_1 (gfc_code * code) +{ + gfc_se if_se; + tree stmt, elsestmt; + + /* Check for an unconditional ELSE clause. */ + if (!code->expr) + return gfc_trans_code (code->next); + + /* Initialize a statement builder for each block. Puts in NULL_TREEs. */ + gfc_init_se (&if_se, NULL); + gfc_start_block (&if_se.pre); + + /* Calculate the IF condition expression. */ + gfc_conv_expr_val (&if_se, code->expr); + + /* Translate the THEN clause. */ + stmt = gfc_trans_code (code->next); + + /* Translate the ELSE clause. */ + if (code->block) + elsestmt = gfc_trans_if_1 (code->block); + else + elsestmt = build_empty_stmt (); + + /* Build the condition expression and add it to the condition block. */ + stmt = build_v (COND_EXPR, if_se.expr, stmt, elsestmt); + + gfc_add_expr_to_block (&if_se.pre, stmt); + + /* Finish off this statement. */ + return gfc_finish_block (&if_se.pre); +} + +tree +gfc_trans_if (gfc_code * code) +{ + /* Ignore the top EXEC_IF, it only announces an IF construct. The + actual code we must translate is in code->block. */ + + return gfc_trans_if_1 (code->block); +} + + +/* Translage an arithmetic IF expression. + + IF (cond) label1, label2, label3 translates to + + if (cond <= 0) + { + if (cond < 0) + goto label1; + else // cond == 0 + goto label2; + } + else // cond > 0 + goto label3; +*/ + +tree +gfc_trans_arithmetic_if (gfc_code * code) +{ + gfc_se se; + tree tmp; + tree branch1; + tree branch2; + tree zero; + + /* Start a new block. */ + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + /* Pre-evaluate COND. */ + gfc_conv_expr_val (&se, code->expr); + + /* Build something to compare with. */ + zero = gfc_build_const (TREE_TYPE (se.expr), integer_zero_node); + + /* If (cond < 0) take branch1 else take branch2. + First build jumps to the COND .LT. 0 and the COND .EQ. 0 cases. */ + branch1 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label)); + branch2 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label2)); + + tmp = build (LT_EXPR, boolean_type_node, se.expr, zero); + branch1 = build_v (COND_EXPR, tmp, branch1, branch2); + + /* if (cond <= 0) take branch1 else take branch2. */ + branch2 = build1_v (GOTO_EXPR, gfc_get_label_decl (code->label3)); + tmp = build (LE_EXPR, boolean_type_node, se.expr, zero); + branch1 = build_v (COND_EXPR, tmp, branch1, branch2); + + /* Append the COND_EXPR to the evaluation of COND, and return. */ + gfc_add_expr_to_block (&se.pre, branch1); + return gfc_finish_block (&se.pre); +} + + +/* Translate the DO construct. This obviously is one of the most + important ones to get right with any compiler, but especially + so for Fortran. + + Currently we calculate the loop count before entering the loop, but + it may be possible to optimize if step is a constant. The main + advantage is that the loop test is a single GENERIC node + + We translate a do loop from: + + DO dovar = from, to, step + body + END DO + + to: + + pre_dovar; + pre_from; + pre_to; + pre_step; + temp1=to_expr-from_expr; + step_temp=step_expr; + range_temp=step_tmp/range_temp; + for ( ; range_temp > 0 ; range_temp = range_temp - 1) + { + body; +cycle_label: + dovar_temp = dovar + dovar=dovar_temp + step_temp; + } +exit_label: + + Some optimization is done for empty do loops. We can't just let + dovar=to because it's possible for from+range*loopcount!=to. Anyone + who writes empty DO deserves sub-optimal (but correct) code anyway. + + TODO: Large loop counts + Does not work loop counts which do not fit into a signed integer kind, + ie. Does not work for loop counts > 2^31 for integer(kind=4) variables + We must support the full range. */ + +tree +gfc_trans_do (gfc_code * code) +{ + gfc_se se; + tree dovar; + tree from; + tree to; + tree step; + tree count; + tree type; + tree cond; + tree cycle_label; + tree exit_label; + tree tmp; + stmtblock_t block; + stmtblock_t body; + + gfc_start_block (&block); + + /* Create GIMPLE versions of all expressions in the iterator. */ + + gfc_init_se (&se, NULL); + gfc_conv_expr_lhs (&se, code->ext.iterator->var); + gfc_add_block_to_block (&block, &se.pre); + dovar = se.expr; + type = TREE_TYPE (dovar); + + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, code->ext.iterator->start, type); + gfc_add_block_to_block (&block, &se.pre); + from = se.expr; + + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, code->ext.iterator->end, type); + gfc_add_block_to_block (&block, &se.pre); + to = se.expr; + + gfc_init_se (&se, NULL); + gfc_conv_expr_type (&se, code->ext.iterator->step, type); + + /* We don't want this changing part way through. */ + gfc_make_safe_expr (&se); + gfc_add_block_to_block (&block, &se.pre); + step = se.expr; + + /* Initialise loop count. This code is executed before we enter the + loop body. We generate: count = (to + step - from) / step. */ + + tmp = fold (build (MINUS_EXPR, type, step, from)); + tmp = fold (build (PLUS_EXPR, type, to, tmp)); + tmp = fold (build (TRUNC_DIV_EXPR, type, tmp, step)); + + count = gfc_create_var (type, "count"); + gfc_add_modify_expr (&block, count, tmp); + + /* Initialise the DO variable: dovar = from. */ + gfc_add_modify_expr (&block, dovar, from); + + /* Loop body. */ + gfc_start_block (&body); + + /* Cycle and exit statements are implemented with gotos. */ + cycle_label = gfc_build_label_decl (NULL_TREE); + exit_label = gfc_build_label_decl (NULL_TREE); + + /* Start with the loop condition. Loop until count <= 0. */ + cond = build (LE_EXPR, boolean_type_node, count, integer_zero_node); + tmp = build1_v (GOTO_EXPR, exit_label); + TREE_USED (exit_label) = 1; + tmp = build_v (COND_EXPR, cond, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&body, tmp); + + /* Put these labels where they can be found later. We put the + labels in a TREE_LIST node (because TREE_CHAIN is already + used). cycle_label goes in TREE_PURPOSE (backend_decl), exit + label in TREE_VALUE (backend_decl). */ + + code->block->backend_decl = tree_cons (cycle_label, exit_label, NULL); + + /* Main loop body. */ + tmp = gfc_trans_code (code->block->next); + gfc_add_expr_to_block (&body, tmp); + + /* Label for cycle statements (if needed). */ + if (TREE_USED (cycle_label)) + { + tmp = build1_v (LABEL_EXPR, cycle_label); + gfc_add_expr_to_block (&body, tmp); + } + + /* Increment the loop variable. */ + tmp = build (PLUS_EXPR, type, dovar, step); + gfc_add_modify_expr (&body, dovar, tmp); + + /* Decrement the loop count. */ + tmp = build (MINUS_EXPR, type, count, integer_one_node); + gfc_add_modify_expr (&body, count, tmp); + + /* End of loop body. */ + tmp = gfc_finish_block (&body); + + /* The for loop itself. */ + tmp = build_v (LOOP_EXPR, tmp); + gfc_add_expr_to_block (&block, tmp); + + /* Add the exit label. */ + tmp = build1_v (LABEL_EXPR, exit_label); + gfc_add_expr_to_block (&block, tmp); + + return gfc_finish_block (&block); +} + + +/* Translate the DO WHILE construct. + + We translate + + DO WHILE (cond) + body + END DO + + to: + + for ( ; ; ) + { + pre_cond; + if (! cond) goto exit_label; + body; +cycle_label: + } +exit_label: + + Because the evaluation of the exit condition `cond' may have side + effects, we can't do much for empty loop bodies. The backend optimizers + should be smart enough to eliminate any dead loops. */ + +tree +gfc_trans_do_while (gfc_code * code) +{ + gfc_se cond; + tree tmp; + tree cycle_label; + tree exit_label; + stmtblock_t block; + + /* Everything we build here is part of the loop body. */ + gfc_start_block (&block); + + /* Cycle and exit statements are implemented with gotos. */ + cycle_label = gfc_build_label_decl (NULL_TREE); + exit_label = gfc_build_label_decl (NULL_TREE); + + /* Put the labels where they can be found later. See gfc_trans_do(). */ + code->block->backend_decl = tree_cons (cycle_label, exit_label, NULL); + + /* Create a GIMPLE version of the exit condition. */ + gfc_init_se (&cond, NULL); + gfc_conv_expr_val (&cond, code->expr); + gfc_add_block_to_block (&block, &cond.pre); + cond.expr = fold (build1 (TRUTH_NOT_EXPR, boolean_type_node, cond.expr)); + + /* Build "IF (! cond) GOTO exit_label". */ + tmp = build1_v (GOTO_EXPR, exit_label); + TREE_USED (exit_label) = 1; + tmp = build_v (COND_EXPR, cond.expr, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&block, tmp); + + /* The main body of the loop. */ + tmp = gfc_trans_code (code->block->next); + gfc_add_expr_to_block (&block, tmp); + + /* Label for cycle statements (if needed). */ + if (TREE_USED (cycle_label)) + { + tmp = build1_v (LABEL_EXPR, cycle_label); + gfc_add_expr_to_block (&block, tmp); + } + + /* End of loop body. */ + tmp = gfc_finish_block (&block); + + gfc_init_block (&block); + /* Build the loop. */ + tmp = build_v (LOOP_EXPR, tmp); + gfc_add_expr_to_block (&block, tmp); + + /* Add the exit label. */ + tmp = build1_v (LABEL_EXPR, exit_label); + gfc_add_expr_to_block (&block, tmp); + + return gfc_finish_block (&block); +} + + +/* Translate the SELECT CASE construct for INTEGER case expressions, + without killing all potential optimizations. The problem is that + Fortran allows unbounded cases, but the back-end does not, so we + need to intercept those before we enter the equivalent SWITCH_EXPR + we can build. + + For example, we translate this, + + SELECT CASE (expr) + CASE (:100,101,105:115) + block_1 + CASE (190:199,200:) + block_2 + CASE (300) + block_3 + CASE DEFAULT + block_4 + END SELECT + + to the GENERIC equivalent, + + switch (expr) + { + case (minimum value for typeof(expr) ... 100: + case 101: + case 105 ... 114: + block1: + goto end_label; + + case 200 ... (maximum value for typeof(expr): + case 190 ... 199: + block2; + goto end_label; + + case 300: + block_3; + goto end_label; + + default: + block_4; + goto end_label; + } + + end_label: */ + +static tree +gfc_trans_integer_select (gfc_code * code) +{ + gfc_code *c; + gfc_case *cp; + tree end_label; + tree tmp; + gfc_se se; + stmtblock_t block; + stmtblock_t body; + + gfc_start_block (&block); + + /* Calculate the switch expression. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, code->expr); + gfc_add_block_to_block (&block, &se.pre); + + end_label = gfc_build_label_decl (NULL_TREE); + + gfc_init_block (&body); + + for (c = code->block; c; c = c->block) + { + for (cp = c->ext.case_list; cp; cp = cp->next) + { + tree low, high; + tree label; + + /* Assume it's the default case. */ + low = high = NULL_TREE; + + if (cp->low) + { + low = gfc_conv_constant_to_tree (cp->low); + + /* If there's only a lower bound, set the high bound to the + maximum value of the case expression. */ + if (!cp->high) + high = TYPE_MAX_VALUE (TREE_TYPE (se.expr)); + } + + if (cp->high) + { + /* Three cases are possible here: + + 1) There is no lower bound, e.g. CASE (:N). + 2) There is a lower bound .NE. high bound, that is + a case range, e.g. CASE (N:M) where M>N (we make + sure that M>N during type resolution). + 3) There is a lower bound, and it has the same value + as the high bound, e.g. CASE (N:N). This is our + internal representation of CASE(N). + + In the first and second case, we need to set a value for + high. In the thirth case, we don't because the GCC middle + end represents a single case value by just letting high be + a NULL_TREE. We can't do that because we need to be able + to represent unbounded cases. */ + + if (!cp->low + || (cp->low + && mpz_cmp (cp->low->value.integer, + cp->high->value.integer) != 0)) + high = gfc_conv_constant_to_tree (cp->high); + + /* Unbounded case. */ + if (!cp->low) + low = TYPE_MIN_VALUE (TREE_TYPE (se.expr)); + } + + /* Build a label. */ + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_CONTEXT (label) = current_function_decl; + + /* Add this case label. + Add parameter 'label', make it match GCC backend. */ + tmp = build (CASE_LABEL_EXPR, void_type_node, low, high, label); + gfc_add_expr_to_block (&body, tmp); + } + + /* Add the statements for this case. */ + tmp = gfc_trans_code (c->next); + gfc_add_expr_to_block (&body, tmp); + + /* Break to the end of the construct. */ + tmp = build1_v (GOTO_EXPR, end_label); + gfc_add_expr_to_block (&body, tmp); + } + + tmp = gfc_finish_block (&body); + tmp = build_v (SWITCH_EXPR, se.expr, tmp, NULL_TREE); + gfc_add_expr_to_block (&block, tmp); + + tmp = build1_v (LABEL_EXPR, end_label); + gfc_add_expr_to_block (&block, tmp); + + return gfc_finish_block (&block); +} + + +/* Translate the SELECT CASE construct for LOGICAL case expressions. + + There are only two cases possible here, even though the standard + does allow three cases in a LOGICAL SELECT CASE construct: .TRUE., + .FALSE., and DEFAULT. + + We never generate more than two blocks here. Instead, we always + try to eliminate the DEFAULT case. This way, we can translate this + kind of SELECT construct to a simple + + if {} else {}; + + expression in GENERIC. */ + +static tree +gfc_trans_logical_select (gfc_code * code) +{ + gfc_code *c; + gfc_code *t, *f, *d; + gfc_case *cp; + gfc_se se; + stmtblock_t block; + + /* Assume we don't have any cases at all. */ + t = f = d = NULL; + + /* Now see which ones we actually do have. We can have at most two + cases in a single case list: one for .TRUE. and one for .FALSE. + The default case is always separate. If the cases for .TRUE. and + .FALSE. are in the same case list, the block for that case list + always executed, and we don't generate code a COND_EXPR. */ + for (c = code->block; c; c = c->block) + { + for (cp = c->ext.case_list; cp; cp = cp->next) + { + if (cp->low) + { + if (cp->low->value.logical == 0) /* .FALSE. */ + f = c; + else /* if (cp->value.logical != 0), thus .TRUE. */ + t = c; + } + else + d = c; + } + } + + /* Start a new block. */ + gfc_start_block (&block); + + /* Calculate the switch expression. We always need to do this + because it may have side effects. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, code->expr); + gfc_add_block_to_block (&block, &se.pre); + + if (t == f && t != NULL) + { + /* Cases for .TRUE. and .FALSE. are in the same block. Just + translate the code for these cases, append it to the current + block. */ + gfc_add_expr_to_block (&block, gfc_trans_code (t->next)); + } + else + { + tree true_tree, false_tree; + + true_tree = build_empty_stmt (); + false_tree = build_empty_stmt (); + + /* If we have a case for .TRUE. and for .FALSE., discard the default case. + Otherwise, if .TRUE. or .FALSE. is missing and there is a default case, + make the missing case the default case. */ + if (t != NULL && f != NULL) + d = NULL; + else if (d != NULL) + { + if (t == NULL) + t = d; + else + f = d; + } + + /* Translate the code for each of these blocks, and append it to + the current block. */ + if (t != NULL) + true_tree = gfc_trans_code (t->next); + + if (f != NULL) + false_tree = gfc_trans_code (f->next); + + gfc_add_expr_to_block (&block, build_v (COND_EXPR, se.expr, + true_tree, false_tree)); + } + + return gfc_finish_block (&block); +} + + +/* Translate the SELECT CASE construct for CHARACTER case expressions. + Instead of generating compares and jumps, it is far simpler to + generate a data structure describing the cases in order and call a + library subroutine that locates the right case. + This is particularly true because this is the only case where we + might have to dispose of a temporary. + The library subroutine returns a pointer to jump to or NULL if no + branches are to be taken. */ + +static tree +gfc_trans_character_select (gfc_code *code) +{ + tree init, node, end_label, tmp, type, args, *labels; + stmtblock_t block, body; + gfc_case *cp, *d; + gfc_code *c; + gfc_se se; + int i, n; + + static tree select_struct; + static tree ss_string1, ss_string1_len; + static tree ss_string2, ss_string2_len; + static tree ss_target; + + if (select_struct == NULL) + { + select_struct = make_node (RECORD_TYPE); + TYPE_NAME (select_struct) = get_identifier ("_jump_struct"); + +#undef ADD_FIELD +#define ADD_FIELD(NAME, TYPE) \ + ss_##NAME = gfc_add_field_to_struct \ + (&(TYPE_FIELDS (select_struct)), select_struct, \ + get_identifier (stringize(NAME)), TYPE) + + ADD_FIELD (string1, pchar_type_node); + ADD_FIELD (string1_len, gfc_int4_type_node); + + ADD_FIELD (string2, pchar_type_node); + ADD_FIELD (string2_len, gfc_int4_type_node); + + ADD_FIELD (target, pvoid_type_node); +#undef ADD_FIELD + + gfc_finish_type (select_struct); + } + + cp = code->block->ext.case_list; + while (cp->left != NULL) + cp = cp->left; + + n = 0; + for (d = cp; d; d = d->right) + d->n = n++; + + if (n != 0) + labels = gfc_getmem (n * sizeof (tree)); + else + labels = NULL; + + for(i = 0; i < n; i++) + { + labels[i] = gfc_build_label_decl (NULL_TREE); + TREE_USED (labels[i]) = 1; + /* TODO: The gimplifier should do this for us, but it has + inadequacies when dealing with static initializers. */ + FORCED_LABEL (labels[i]) = 1; + } + + end_label = gfc_build_label_decl (NULL_TREE); + + /* Generate the body */ + gfc_start_block (&block); + gfc_init_block (&body); + + for (c = code->block; c; c = c->block) + { + for (d = c->ext.case_list; d; d = d->next) + { + tmp = build_v (LABEL_EXPR, labels[d->n]); + gfc_add_expr_to_block (&body, tmp); + } + + tmp = gfc_trans_code (c->next); + gfc_add_expr_to_block (&body, tmp); + + tmp = build_v (GOTO_EXPR, end_label); + gfc_add_expr_to_block (&body, tmp); + } + + /* Generate the structure describing the branches */ + init = NULL_TREE; + i = 0; + + for(d = cp; d; d = d->right, i++) + { + node = NULL_TREE; + + gfc_init_se (&se, NULL); + + if (d->low == NULL) + { + node = tree_cons (ss_string1, null_pointer_node, node); + node = tree_cons (ss_string1_len, integer_zero_node, node); + } + else + { + gfc_conv_expr_reference (&se, d->low); + + node = tree_cons (ss_string1, se.expr, node); + node = tree_cons (ss_string1_len, se.string_length, node); + } + + if (d->high == NULL) + { + node = tree_cons (ss_string2, null_pointer_node, node); + node = tree_cons (ss_string2_len, integer_zero_node, node); + } + else + { + gfc_init_se (&se, NULL); + gfc_conv_expr_reference (&se, d->high); + + node = tree_cons (ss_string2, se.expr, node); + node = tree_cons (ss_string2_len, se.string_length, node); + } + + tmp = gfc_build_addr_expr (pvoid_type_node, labels[i]); + node = tree_cons (ss_target, tmp, node); + + tmp = build1 (CONSTRUCTOR, select_struct, nreverse (node)); + init = tree_cons (NULL_TREE, tmp, init); + } + + type = build_array_type (select_struct, + build_index_type (build_int_2(n - 1, 0))); + + init = build1 (CONSTRUCTOR, type, nreverse(init)); + TREE_CONSTANT (init) = 1; + TREE_INVARIANT (init) = 1; + TREE_STATIC (init) = 1; + /* Create a static variable to hold the jump table. */ + tmp = gfc_create_var (type, "jumptable"); + TREE_CONSTANT (tmp) = 1; + TREE_INVARIANT (tmp) = 1; + TREE_STATIC (tmp) = 1; + DECL_INITIAL (tmp) = init; + init = tmp; + + /* Build an argument list for the library call */ + init = gfc_build_addr_expr (pvoid_type_node, init); + args = gfc_chainon_list (NULL_TREE, init); + + tmp = build_int_2 (n, 0); + args = gfc_chainon_list (args, tmp); + + tmp = gfc_build_addr_expr (pvoid_type_node, end_label); + args = gfc_chainon_list (args, tmp); + + gfc_init_se (&se, NULL); + gfc_conv_expr_reference (&se, code->expr); + + args = gfc_chainon_list (args, se.expr); + args = gfc_chainon_list (args, se.string_length); + + gfc_add_block_to_block (&block, &se.pre); + + tmp = gfc_build_function_call (gfor_fndecl_select_string, args); + tmp = build1 (GOTO_EXPR, void_type_node, tmp); + gfc_add_expr_to_block (&block, tmp); + + tmp = gfc_finish_block (&body); + gfc_add_expr_to_block (&block, tmp); + tmp = build_v (LABEL_EXPR, end_label); + gfc_add_expr_to_block (&block, tmp); + + if (n != 0) + gfc_free (labels); + + return gfc_finish_block (&block); +} + + +/* Translate the three variants of the SELECT CASE construct. + + SELECT CASEs with INTEGER case expressions can be translated to an + equivalent GENERIC switch statement, and for LOGICAL case + expressions we build one or two if-else compares. + + SELECT CASEs with CHARACTER case expressions are a whole different + story, because they don't exist in GENERIC. So we sort them and + do a binary search at runtime. + + Fortran has no BREAK statement, and it does not allow jumps from + one case block to another. That makes things a lot easier for + the optimizers. */ + +tree +gfc_trans_select (gfc_code * code) +{ + assert (code && code->expr); + + /* Empty SELECT constructs are legal. */ + if (code->block == NULL) + return build_empty_stmt (); + + /* Select the correct translation function. */ + switch (code->expr->ts.type) + { + case BT_LOGICAL: return gfc_trans_logical_select (code); + case BT_INTEGER: return gfc_trans_integer_select (code); + case BT_CHARACTER: return gfc_trans_character_select (code); + default: + gfc_internal_error ("gfc_trans_select(): Bad type for case expr."); + /* Not reached */ + } +} + + +/* Generate the loops for a FORALL block. The normal loop format: + count = (end - start + step) / step + loopvar = start + while (1) + { + if (count <=0 ) + goto end_of_loop + + loopvar += step + count -- + } + end_of_loop: */ + +static tree +gfc_trans_forall_loop (forall_info *forall_tmp, int nvar, tree body, int mask_flag) +{ + int n; + tree tmp; + tree cond; + stmtblock_t block; + tree exit_label; + tree count; + tree var, start, end, step, mask, maskindex; + iter_info *iter; + + iter = forall_tmp->this_loop; + for (n = 0; n < nvar; n++) + { + var = iter->var; + start = iter->start; + end = iter->end; + step = iter->step; + + exit_label = gfc_build_label_decl (NULL_TREE); + TREE_USED (exit_label) = 1; + + /* The loop counter. */ + count = gfc_create_var (TREE_TYPE (var), "count"); + + /* The body of the loop. */ + gfc_init_block (&block); + + /* The exit condition. */ + cond = build (LE_EXPR, boolean_type_node, count, integer_zero_node); + tmp = build1_v (GOTO_EXPR, exit_label); + tmp = build_v (COND_EXPR, cond, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&block, tmp); + + /* The main loop body. */ + gfc_add_expr_to_block (&block, body); + + /* Increment the loop variable. */ + tmp = build (PLUS_EXPR, TREE_TYPE (var), var, step); + gfc_add_modify_expr (&block, var, tmp); + + /* Advance to the next mask element. */ + if (mask_flag) + { + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + if (mask) + { + tmp = build (PLUS_EXPR, gfc_array_index_type, maskindex, + integer_one_node); + gfc_add_modify_expr (&block, maskindex, tmp); + } + } + /* Decrement the loop counter. */ + tmp = build (MINUS_EXPR, TREE_TYPE (var), count, integer_one_node); + gfc_add_modify_expr (&block, count, tmp); + + body = gfc_finish_block (&block); + + /* Loop var initialization. */ + gfc_init_block (&block); + gfc_add_modify_expr (&block, var, start); + + /* Initialize the loop counter. */ + tmp = fold (build (MINUS_EXPR, TREE_TYPE (var), step, start)); + tmp = fold (build (PLUS_EXPR, TREE_TYPE (var), end, tmp)); + tmp = fold (build (TRUNC_DIV_EXPR, TREE_TYPE (var), tmp, step)); + gfc_add_modify_expr (&block, count, tmp); + + /* The loop expression. */ + tmp = build_v (LOOP_EXPR, body); + gfc_add_expr_to_block (&block, tmp); + + /* The exit label. */ + tmp = build1_v (LABEL_EXPR, exit_label); + gfc_add_expr_to_block (&block, tmp); + + body = gfc_finish_block (&block); + iter = iter->next; + } + return body; +} + + +/* Generate the body and loops according to MASK_FLAG and NEST_FLAG. + if MASK_FLAG is non-zero, the body is controlled by maskes in forall + nest, otherwise, the body is not controlled by maskes. + if NEST_FLAG is non-zero, generate loops for nested forall, otherwise, + only generate loops for the current forall level. */ + +static tree +gfc_trans_nested_forall_loop (forall_info * nested_forall_info, tree body, + int mask_flag, int nest_flag) +{ + tree tmp; + int nvar; + forall_info *forall_tmp; + tree pmask, mask, maskindex; + + forall_tmp = nested_forall_info; + /* Generate loops for nested forall. */ + if (nest_flag) + { + while (forall_tmp->next_nest != NULL) + forall_tmp = forall_tmp->next_nest; + while (forall_tmp != NULL) + { + /* Generate body with masks' control. */ + if (mask_flag) + { + pmask = forall_tmp->pmask; + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + + if (mask) + { + /* If a mask was specified make the assignment contitional. */ + if (pmask) + tmp = gfc_build_indirect_ref (mask); + else + tmp = mask; + tmp = gfc_build_array_ref (tmp, maskindex); + + body = build_v (COND_EXPR, tmp, body, build_empty_stmt ()); + } + } + nvar = forall_tmp->nvar; + body = gfc_trans_forall_loop (forall_tmp, nvar, body, mask_flag); + forall_tmp = forall_tmp->outer; + } + } + else + { + nvar = forall_tmp->nvar; + body = gfc_trans_forall_loop (forall_tmp, nvar, body, mask_flag); + } + + return body; +} + + +/* Allocate data for holding a temporary array. Returns either a local + temporary array or a pointer variable. */ + +static tree +gfc_do_allocate (tree bytesize, tree size, tree * pdata, stmtblock_t * pblock, + tree elem_type) +{ + tree tmpvar; + tree type; + tree tmp; + tree args; + + if (INTEGER_CST_P (size)) + { + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, size, + integer_one_node)); + } + else + tmp = NULL_TREE; + + type = build_range_type (gfc_array_index_type, integer_zero_node, tmp); + type = build_array_type (elem_type, type); + if (gfc_can_put_var_on_stack (bytesize)) + { + assert (INTEGER_CST_P (size)); + tmpvar = gfc_create_var (type, "temp"); + *pdata = NULL_TREE; + } + else + { + tmpvar = gfc_create_var (build_pointer_type (type), "temp"); + *pdata = convert (pvoid_type_node, tmpvar); + + args = gfc_chainon_list (NULL_TREE, bytesize); + if (gfc_index_integer_kind == 4) + tmp = gfor_fndecl_internal_malloc; + else if (gfc_index_integer_kind == 8) + tmp = gfor_fndecl_internal_malloc64; + else + abort (); + tmp = gfc_build_function_call (tmp, args); + tmp = convert (TREE_TYPE (tmpvar), tmp); + gfc_add_modify_expr (pblock, tmpvar, tmp); + } + return tmpvar; +} + + +/* Generate codes to copy the temporary to the actual lhs. */ + +static tree +generate_loop_for_temp_to_lhs (gfc_expr *expr, tree tmp1, tree size, + tree count3, tree count1, tree count2, tree wheremask) +{ + gfc_ss *lss; + gfc_se lse, rse; + stmtblock_t block, body; + gfc_loopinfo loop1; + tree tmp, tmp2; + tree index; + tree wheremaskexpr; + + /* Walk the lhs. */ + lss = gfc_walk_expr (expr); + + if (lss == gfc_ss_terminator) + { + gfc_start_block (&block); + + gfc_init_se (&lse, NULL); + + /* Translate the expression. */ + gfc_conv_expr (&lse, expr); + + /* Form the expression for the temporary. */ + tmp = gfc_build_array_ref (tmp1, count1); + + /* Use the scalar assignment as is. */ + gfc_add_block_to_block (&block, &lse.pre); + gfc_add_modify_expr (&block, lse.expr, tmp); + gfc_add_block_to_block (&block, &lse.post); + + /* Increment the count1. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count1), count1, size)); + gfc_add_modify_expr (&block, count1, tmp); + tmp = gfc_finish_block (&block); + } + else + { + gfc_start_block (&block); + + gfc_init_loopinfo (&loop1); + gfc_init_se (&rse, NULL); + gfc_init_se (&lse, NULL); + + /* Associate the lss with the loop. */ + gfc_add_ss_to_loop (&loop1, lss); + + /* Calculate the bounds of the scalarization. */ + gfc_conv_ss_startstride (&loop1); + /* Setup the scalarizing loops. */ + gfc_conv_loop_setup (&loop1); + + gfc_mark_ss_chain_used (lss, 1); + /* Initialize count2. */ + gfc_add_modify_expr (&block, count2, integer_zero_node); + + /* Start the scalarized loop body. */ + gfc_start_scalarized_body (&loop1, &body); + + /* Setup the gfc_se structures. */ + gfc_copy_loopinfo_to_se (&lse, &loop1); + lse.ss = lss; + + /* Form the expression of the temporary. */ + if (lss != gfc_ss_terminator) + { + index = fold (build (PLUS_EXPR, gfc_array_index_type, + count1, count2)); + rse.expr = gfc_build_array_ref (tmp1, index); + } + /* Translate expr. */ + gfc_conv_expr (&lse, expr); + + /* Use the scalar assignment. */ + tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts.type); + + /* Form the mask expression according to the mask tree list. */ + if (wheremask) + { + tmp2 = wheremask; + if (tmp2 != NULL) + wheremaskexpr = gfc_build_array_ref (tmp2, count3); + tmp2 = TREE_CHAIN (tmp2); + while (tmp2) + { + tmp1 = gfc_build_array_ref (tmp2, count3); + wheremaskexpr = build (TRUTH_AND_EXPR, TREE_TYPE (tmp1), + wheremaskexpr, tmp1); + tmp2 = TREE_CHAIN (tmp2); + } + tmp = build_v (COND_EXPR, wheremaskexpr, tmp, build_empty_stmt ()); + } + + gfc_add_expr_to_block (&body, tmp); + + /* Increment count2. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count2), count2, + integer_one_node)); + gfc_add_modify_expr (&body, count2, tmp); + + /* Increment count3. */ + if (count3) + { + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count3), count3, + integer_one_node)); + gfc_add_modify_expr (&body, count3, tmp); + } + + /* Generate the copying loops. */ + gfc_trans_scalarizing_loops (&loop1, &body); + gfc_add_block_to_block (&block, &loop1.pre); + gfc_add_block_to_block (&block, &loop1.post); + gfc_cleanup_loop (&loop1); + + /* Increment count1. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count1), count1, size)); + gfc_add_modify_expr (&block, count1, tmp); + tmp = gfc_finish_block (&block); + } + return tmp; +} + + +/* Generate codes to copy rhs to the temporary. TMP1 is the address of temporary + LSS and RSS are formed in function compute_inner_temp_size(), and should + not be freed. */ + +static tree +generate_loop_for_rhs_to_temp (gfc_expr *expr2, tree tmp1, tree size, + tree count3, tree count1, tree count2, + gfc_ss *lss, gfc_ss *rss, tree wheremask) +{ + stmtblock_t block, body1; + gfc_loopinfo loop; + gfc_se lse; + gfc_se rse; + tree tmp, tmp2, index; + tree wheremaskexpr; + + gfc_start_block (&block); + + gfc_init_se (&rse, NULL); + gfc_init_se (&lse, NULL); + + if (lss == gfc_ss_terminator) + { + gfc_init_block (&body1); + gfc_conv_expr (&rse, expr2); + lse.expr = gfc_build_array_ref (tmp1, count1); + } + else + { + /* Initilize count2. */ + gfc_add_modify_expr (&block, count2, integer_zero_node); + + /* Initiliaze the loop. */ + gfc_init_loopinfo (&loop); + + /* We may need LSS to determine the shape of the expression. */ + gfc_add_ss_to_loop (&loop, lss); + gfc_add_ss_to_loop (&loop, rss); + + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + gfc_mark_ss_chain_used (rss, 1); + /* Start the loop body. */ + gfc_start_scalarized_body (&loop, &body1); + + /* Translate the expression. */ + gfc_copy_loopinfo_to_se (&rse, &loop); + rse.ss = rss; + gfc_conv_expr (&rse, expr2); + + /* Form the expression of the temporary. */ + index = fold (build (PLUS_EXPR, gfc_array_index_type, count1, count2)); + lse.expr = gfc_build_array_ref (tmp1, index); + } + + /* Use the scalar assignment. */ + tmp = gfc_trans_scalar_assign (&lse, &rse, expr2->ts.type); + + /* Form the mask expression according to the mask tree list. */ + if (wheremask) + { + tmp2 = wheremask; + if (tmp2 != NULL) + wheremaskexpr = gfc_build_array_ref (tmp2, count3); + tmp2 = TREE_CHAIN (tmp2); + while (tmp2) + { + tmp1 = gfc_build_array_ref (tmp2, count3); + wheremaskexpr = build (TRUTH_AND_EXPR, TREE_TYPE (tmp1), + wheremaskexpr, tmp1); + tmp2 = TREE_CHAIN (tmp2); + } + tmp = build_v (COND_EXPR, wheremaskexpr, tmp, build_empty_stmt ()); + } + + gfc_add_expr_to_block (&body1, tmp); + + if (lss == gfc_ss_terminator) + { + gfc_add_block_to_block (&block, &body1); + } + else + { + /* Increment count2. */ + tmp = fold (build (PLUS_EXPR, gfc_array_index_type, count2, + integer_one_node)); + gfc_add_modify_expr (&body1, count2, tmp); + + /* Increment count3. */ + if (count3) + { + tmp = fold (build (PLUS_EXPR, gfc_array_index_type, count3, + integer_one_node)); + gfc_add_modify_expr (&body1, count3, tmp); + } + + /* Generate the copying loops. */ + gfc_trans_scalarizing_loops (&loop, &body1); + + gfc_add_block_to_block (&block, &loop.pre); + gfc_add_block_to_block (&block, &loop.post); + + gfc_cleanup_loop (&loop); + /* TODO: Reuse lss and rss when copying temp->lhs. Need to be careful + as tree nodes in SS may not be valid in different scope. */ + } + /* Increment count1. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count1), count1, size)); + gfc_add_modify_expr (&block, count1, tmp); + + tmp = gfc_finish_block (&block); + return tmp; +} + + +/* Calculate the size of temporary needed in the assignment inside forall. + LSS and RSS are filled in this function. */ + +static tree +compute_inner_temp_size (gfc_expr *expr1, gfc_expr *expr2, + stmtblock_t * pblock, + gfc_ss **lss, gfc_ss **rss) +{ + gfc_loopinfo loop; + tree size; + int i; + tree tmp; + + *lss = gfc_walk_expr (expr1); + *rss = NULL; + + size = integer_one_node; + if (*lss != gfc_ss_terminator) + { + gfc_init_loopinfo (&loop); + + /* Walk the RHS of the expression. */ + *rss = gfc_walk_expr (expr2); + if (*rss == gfc_ss_terminator) + { + /* The rhs is scalar. Add a ss for the expression. */ + *rss = gfc_get_ss (); + (*rss)->next = gfc_ss_terminator; + (*rss)->type = GFC_SS_SCALAR; + (*rss)->expr = expr2; + } + + /* Associate the SS with the loop. */ + gfc_add_ss_to_loop (&loop, *lss); + /* We don't actually need to add the rhs at this point, but it might + make guessing the loop bounds a bit easier. */ + gfc_add_ss_to_loop (&loop, *rss); + + /* We only want the shape of the expression, not rest of the junk + generated by the scalarizer. */ + loop.array_parameter = 1; + + /* Calculate the bounds of the scalarization. */ + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + /* Figure out how many elements we need. */ + for (i = 0; i < loop.dimen; i++) + { + tmp = fold (build (MINUS_EXPR, TREE_TYPE (loop.from[i]), + integer_one_node, loop.from[i])); + tmp = fold (build (PLUS_EXPR, TREE_TYPE (tmp), tmp, loop.to[i])); + size = fold (build (MULT_EXPR, TREE_TYPE (size), size, tmp)); + } + gfc_add_block_to_block (pblock, &loop.pre); + size = gfc_evaluate_now (size, pblock); + gfc_add_block_to_block (pblock, &loop.post); + + /* TODO: write a function that cleans up a loopinfo without freeing + the SS chains. Currently a NOP. */ + } + + return size; +} + + +/* Calculate the overall iterator number of the nested forall construct. */ + +static tree +compute_overall_iter_number (forall_info *nested_forall_info, tree inner_size, + stmtblock_t *block) +{ + tree tmp, number; + stmtblock_t body; + + /* TODO: optimizing the computing process. */ + number = gfc_create_var (gfc_array_index_type, "num"); + gfc_add_modify_expr (block, number, integer_zero_node); + + gfc_start_block (&body); + if (nested_forall_info) + tmp = build (PLUS_EXPR, gfc_array_index_type, number, + inner_size); + else + tmp = inner_size; + gfc_add_modify_expr (&body, number, tmp); + tmp = gfc_finish_block (&body); + + /* Generate loops. */ + if (nested_forall_info != NULL) + tmp = gfc_trans_nested_forall_loop (nested_forall_info, tmp, 0, 1); + + gfc_add_expr_to_block (block, tmp); + + return number; +} + + +/* Allocate temporary for forall construct according to the information in + nested_forall_info. INNER_SIZE is the size of temporary needed in the + assignment inside forall. PTEMP1 is returned for space free. */ + +static tree +allocate_temp_for_forall_nest (forall_info * nested_forall_info, tree type, + tree inner_size, stmtblock_t * block, + tree * ptemp1) +{ + tree unit; + tree temp1; + tree tmp; + tree bytesize, size; + + /* Calculate the total size of temporary needed in forall construct. */ + size = compute_overall_iter_number (nested_forall_info, inner_size, block); + + unit = TYPE_SIZE_UNIT (type); + bytesize = fold (build (MULT_EXPR, gfc_array_index_type, size, unit)); + + *ptemp1 = NULL; + temp1 = gfc_do_allocate (bytesize, size, ptemp1, block, type); + + if (*ptemp1) + tmp = gfc_build_indirect_ref (temp1); + else + tmp = temp1; + + return tmp; +} + + +/* Handle assignments inside forall which need temporary. */ +static void +gfc_trans_assign_need_temp (gfc_expr * expr1, gfc_expr * expr2, tree wheremask, + forall_info * nested_forall_info, + stmtblock_t * block) +{ + tree type; + tree inner_size; + gfc_ss *lss, *rss; + tree count, count1, count2; + tree tmp, tmp1; + tree ptemp1; + tree mask, maskindex; + forall_info *forall_tmp; + + /* Create vars. count1 is the current iterator number of the nested forall. + count2 is the current iterator number of the inner loops needed in the + assignment. */ + count1 = gfc_create_var (gfc_array_index_type, "count1"); + count2 = gfc_create_var (gfc_array_index_type, "count2"); + + /* Count is the wheremask index. */ + if (wheremask) + { + count = gfc_create_var (gfc_array_index_type, "count"); + gfc_add_modify_expr (block, count, integer_zero_node); + } + else + count = NULL; + + /* Initialize count1. */ + gfc_add_modify_expr (block, count1, integer_zero_node); + + /* Calculate the size of temporary needed in the assignment. Return loop, lss + and rss which are used in function generate_loop_for_rhs_to_temp(). */ + inner_size = compute_inner_temp_size (expr1, expr2, block, &lss, &rss); + + /* The type of LHS. Used in function allocate_temp_for_forall_nest */ + type = gfc_typenode_for_spec (&expr1->ts); + + /* Allocate temporary for nested forall construct according to the + information in nested_forall_info and inner_size. */ + tmp1 = allocate_temp_for_forall_nest (nested_forall_info, type, + inner_size, block, &ptemp1); + + /* Initialize the maskindexes. */ + forall_tmp = nested_forall_info; + while (forall_tmp != NULL) + { + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + if (mask) + gfc_add_modify_expr (block, maskindex, integer_zero_node); + forall_tmp = forall_tmp->next_nest; + } + + /* Generate codes to copy rhs to the temporary . */ + tmp = generate_loop_for_rhs_to_temp (expr2, tmp1, inner_size, count, + count1, count2, lss, rss, wheremask); + + /* Generate body and loops according to the inforamtion in + nested_forall_info. */ + tmp = gfc_trans_nested_forall_loop (nested_forall_info, tmp, 1, 1); + gfc_add_expr_to_block (block, tmp); + + /* Reset count1. */ + gfc_add_modify_expr (block, count1, integer_zero_node); + + /* Reset maskindexed. */ + forall_tmp = nested_forall_info; + while (forall_tmp != NULL) + { + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + if (mask) + gfc_add_modify_expr (block, maskindex, integer_zero_node); + forall_tmp = forall_tmp->next_nest; + } + + /* Reset count. */ + if (wheremask) + gfc_add_modify_expr (block, count, integer_zero_node); + + /* Generate codes to copy the temporary to lhs. */ + tmp = generate_loop_for_temp_to_lhs (expr1, tmp1, inner_size, count, + count1, count2, wheremask); + + /* Generate body and loops according to the inforamtion in + nested_forall_info. */ + tmp = gfc_trans_nested_forall_loop (nested_forall_info, tmp, 1, 1); + gfc_add_expr_to_block (block, tmp); + + if (ptemp1) + { + /* Free the temporary. */ + tmp = gfc_chainon_list (NULL_TREE, ptemp1); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp); + gfc_add_expr_to_block (block, tmp); + } +} + + +/* Translate pointer assignment inside FORALL which need temporary. */ + +static void +gfc_trans_pointer_assign_need_temp (gfc_expr * expr1, gfc_expr * expr2, + forall_info * nested_forall_info, + stmtblock_t * block) +{ + tree type; + tree inner_size; + gfc_ss *lss, *rss; + gfc_se lse; + gfc_se rse; + gfc_ss_info *info; + gfc_loopinfo loop; + tree desc; + tree parm; + tree parmtype; + stmtblock_t body; + tree count; + tree tmp, tmp1, ptemp1; + tree mask, maskindex; + forall_info *forall_tmp; + + count = gfc_create_var (gfc_array_index_type, "count"); + gfc_add_modify_expr (block, count, integer_zero_node); + + inner_size = integer_one_node; + lss = gfc_walk_expr (expr1); + rss = gfc_walk_expr (expr2); + if (lss == gfc_ss_terminator) + { + type = gfc_typenode_for_spec (&expr1->ts); + type = build_pointer_type (type); + + /* Allocate temporary for nested forall construct according to the + information in nested_forall_info and inner_size. */ + tmp1 = allocate_temp_for_forall_nest (nested_forall_info, + type, inner_size, block, &ptemp1); + gfc_start_block (&body); + gfc_init_se (&lse, NULL); + lse.expr = gfc_build_array_ref (tmp1, count); + gfc_init_se (&rse, NULL); + rse.want_pointer = 1; + gfc_conv_expr (&rse, expr2); + gfc_add_block_to_block (&body, &rse.pre); + gfc_add_modify_expr (&body, lse.expr, rse.expr); + gfc_add_block_to_block (&body, &rse.post); + + /* Increment count. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count), count, + integer_one_node)); + gfc_add_modify_expr (&body, count, tmp); + + tmp = gfc_finish_block (&body); + + /* Initialize the maskindexes. */ + forall_tmp = nested_forall_info; + while (forall_tmp != NULL) + { + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + if (mask) + gfc_add_modify_expr (block, maskindex, integer_zero_node); + forall_tmp = forall_tmp->next_nest; + } + + /* Generate body and loops according to the inforamtion in + nested_forall_info. */ + tmp = gfc_trans_nested_forall_loop (nested_forall_info, tmp, 1, 1); + gfc_add_expr_to_block (block, tmp); + + /* Reset count. */ + gfc_add_modify_expr (block, count, integer_zero_node); + + /* Reset maskindexes. */ + forall_tmp = nested_forall_info; + while (forall_tmp != NULL) + { + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + if (mask) + gfc_add_modify_expr (block, maskindex, integer_zero_node); + forall_tmp = forall_tmp->next_nest; + } + gfc_start_block (&body); + gfc_init_se (&lse, NULL); + gfc_init_se (&rse, NULL); + rse.expr = gfc_build_array_ref (tmp1, count); + lse.want_pointer = 1; + gfc_conv_expr (&lse, expr1); + gfc_add_block_to_block (&body, &lse.pre); + gfc_add_modify_expr (&body, lse.expr, rse.expr); + gfc_add_block_to_block (&body, &lse.post); + /* Increment count. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count), count, + integer_one_node)); + gfc_add_modify_expr (&body, count, tmp); + tmp = gfc_finish_block (&body); + + /* Generate body and loops according to the inforamtion in + nested_forall_info. */ + tmp = gfc_trans_nested_forall_loop (nested_forall_info, tmp, 1, 1); + gfc_add_expr_to_block (block, tmp); + } + else + { + gfc_init_loopinfo (&loop); + + /* Associate the SS with the loop. */ + gfc_add_ss_to_loop (&loop, rss); + + /* Setup the scalarizing loops and bounds. */ + gfc_conv_ss_startstride (&loop); + + gfc_conv_loop_setup (&loop); + + info = &rss->data.info; + desc = info->descriptor; + + /* Make a new descriptor. */ + parmtype = gfc_get_element_type (TREE_TYPE (desc)); + parmtype = gfc_get_array_type_bounds (parmtype, loop.dimen, + loop.from, loop.to, 1); + + /* Allocate temporary for nested forall construct. */ + tmp1 = allocate_temp_for_forall_nest (nested_forall_info, parmtype, + inner_size, block, &ptemp1); + gfc_start_block (&body); + gfc_init_se (&lse, NULL); + lse.expr = gfc_build_array_ref (tmp1, count); + lse.direct_byref = 1; + rss = gfc_walk_expr (expr2); + gfc_conv_expr_descriptor (&lse, expr2, rss); + + gfc_add_block_to_block (&body, &lse.pre); + gfc_add_block_to_block (&body, &lse.post); + + /* Increment count. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count), count, + integer_one_node)); + gfc_add_modify_expr (&body, count, tmp); + + tmp = gfc_finish_block (&body); + + /* Initialize the maskindexes. */ + forall_tmp = nested_forall_info; + while (forall_tmp != NULL) + { + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + if (mask) + gfc_add_modify_expr (block, maskindex, integer_zero_node); + forall_tmp = forall_tmp->next_nest; + } + + /* Generate body and loops according to the inforamtion in + nested_forall_info. */ + tmp = gfc_trans_nested_forall_loop (nested_forall_info, tmp, 1, 1); + gfc_add_expr_to_block (block, tmp); + + /* Reset count. */ + gfc_add_modify_expr (block, count, integer_zero_node); + + /* Reset maskindexes. */ + forall_tmp = nested_forall_info; + while (forall_tmp != NULL) + { + mask = forall_tmp->mask; + maskindex = forall_tmp->maskindex; + if (mask) + gfc_add_modify_expr (block, maskindex, integer_zero_node); + forall_tmp = forall_tmp->next_nest; + } + parm = gfc_build_array_ref (tmp1, count); + lss = gfc_walk_expr (expr1); + gfc_init_se (&lse, NULL); + gfc_conv_expr_descriptor (&lse, expr1, lss); + gfc_add_modify_expr (&lse.pre, lse.expr, parm); + gfc_start_block (&body); + gfc_add_block_to_block (&body, &lse.pre); + gfc_add_block_to_block (&body, &lse.post); + + /* Increment count. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count), count, + integer_one_node)); + gfc_add_modify_expr (&body, count, tmp); + + tmp = gfc_finish_block (&body); + + tmp = gfc_trans_nested_forall_loop (nested_forall_info, tmp, 1, 1); + gfc_add_expr_to_block (block, tmp); + } + /* Free the temporary. */ + if (ptemp1) + { + tmp = gfc_chainon_list (NULL_TREE, ptemp1); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp); + gfc_add_expr_to_block (block, tmp); + } +} + + +/* FORALL and WHERE statements are really nasty, especially when you nest + them. All the rhs of a forall assignment must be evaluated before the + actual assignments are performed. Presumably this also applies to all the + assignments in an inner where statement. */ + +/* Generate code for a FORALL statement. Any temporaries are allocated as a + linear array, relying on the fact that we process in the same order in all + loops. + + forall (i=start:end:stride; maskexpr) + e = f + g = h + end forall + (where e,f,g,h are arbitary expressions possibly involving i) + Translates to: + count = ((end + 1 - start) / staride) + masktmp(:) = maskexpr(:) + + maskindex = 0; + for (i = start; i <= end; i += stride) + { + if (masktmp[maskindex++]) + e = f + } + maskindex = 0; + for (i = start; i <= end; i += stride) + { + if (masktmp[maskindex++]) + e = f + } + + Note that this code only works when there are no dependencies. + Forall loop with array assignments and data dependencies are a real pain, + because the size of the temporary cannot always be determined before the + loop is executed. This problem is compouded by the presence of nested + FORALL constructs. + */ + +static tree +gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) +{ + stmtblock_t block; + stmtblock_t body; + tree *var; + tree *start; + tree *end; + tree *step; + gfc_expr **varexpr; + tree tmp; + tree assign; + tree size; + tree bytesize; + tree tmpvar; + tree sizevar; + tree lenvar; + tree maskindex; + tree mask; + tree pmask; + int n; + int nvar; + int need_temp; + gfc_forall_iterator *fa; + gfc_se se; + gfc_code *c; + tree *saved_var_decl; + symbol_attribute *saved_var_attr; + iter_info *this_forall, *iter_tmp; + forall_info *info, *forall_tmp; + temporary_list *temp; + + gfc_start_block (&block); + + n = 0; + /* Count the FORALL index number. */ + for (fa = code->ext.forall_iterator; fa; fa = fa->next) + n++; + nvar = n; + + /* Allocate the space for var, start, end, step, varexpr. */ + var = (tree *) gfc_getmem (nvar * sizeof (tree)); + start = (tree *) gfc_getmem (nvar * sizeof (tree)); + end = (tree *) gfc_getmem (nvar * sizeof (tree)); + step = (tree *) gfc_getmem (nvar * sizeof (tree)); + varexpr = (gfc_expr **) gfc_getmem (nvar * sizeof (gfc_expr *)); + saved_var_decl = (tree *) gfc_getmem (nvar * sizeof (tree)); + saved_var_attr = (symbol_attribute *) + gfc_getmem (nvar * sizeof (symbol_attribute)); + + /* Allocate the space for info. */ + info = (forall_info *) gfc_getmem (sizeof (forall_info)); + n = 0; + for (fa = code->ext.forall_iterator; fa; fa = fa->next) + { + gfc_symbol *sym = fa->var->symtree->n.sym; + + /* allocate space for this_forall. */ + this_forall = (iter_info *) gfc_getmem (sizeof (iter_info)); + + /* Save the FORALL index's backend_decl. */ + saved_var_decl[n] = sym->backend_decl; + + /* Save the attribute. */ + saved_var_attr[n] = sym->attr; + + /* Set the proper attributes. */ + gfc_clear_attr (&sym->attr); + sym->attr.referenced = 1; + sym->attr.flavor = FL_VARIABLE; + + /* Create a temporary variable for the FORALL index. */ + tmp = gfc_typenode_for_spec (&sym->ts); + var[n] = gfc_create_var (tmp, sym->name); + /* Record it in this_forall. */ + this_forall->var = var[n]; + + /* Replace the index symbol's backend_decl with the temporary decl. */ + sym->backend_decl = var[n]; + + /* Work out the start, end and stride for the loop. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, fa->start); + /* Record it in this_forall. */ + this_forall->start = se.expr; + gfc_add_block_to_block (&block, &se.pre); + start[n] = se.expr; + + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, fa->end); + /* Record it in this_forall. */ + this_forall->end = se.expr; + gfc_make_safe_expr (&se); + gfc_add_block_to_block (&block, &se.pre); + end[n] = se.expr; + + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, fa->stride); + /* Record it in this_forall. */ + this_forall->step = se.expr; + gfc_make_safe_expr (&se); + gfc_add_block_to_block (&block, &se.pre); + step[n] = se.expr; + + /* Set the NEXT field of this_forall to NULL. */ + this_forall->next = NULL; + /* Link this_forall to the info construct. */ + if (info->this_loop == NULL) + info->this_loop = this_forall; + else + { + iter_tmp = info->this_loop; + while (iter_tmp->next != NULL) + iter_tmp = iter_tmp->next; + iter_tmp->next = this_forall; + } + + n++; + } + nvar = n; + + /* Work out the number of elements in the mask array. */ + tmpvar = NULL_TREE; + lenvar = NULL_TREE; + size = integer_one_node; + sizevar = NULL_TREE; + + for (n = 0; n < nvar; n++) + { + if (lenvar && TREE_TYPE (lenvar) != TREE_TYPE (start[n])) + lenvar = NULL_TREE; + + /* size = (end + step - start) / step. */ + tmp = fold (build (MINUS_EXPR, TREE_TYPE (start[n]), step[n], start[n])); + tmp = fold (build (PLUS_EXPR, TREE_TYPE (end[n]), end[n], tmp)); + + tmp = fold (build (FLOOR_DIV_EXPR, TREE_TYPE (tmp), tmp, step[n])); + tmp = convert (gfc_array_index_type, tmp); + + size = fold (build (MULT_EXPR, gfc_array_index_type, size, tmp)); + } + + /* Record the nvar and size of current forall level. */ + info->nvar = nvar; + info->size = size; + + /* Link the current forall level to nested_forall_info. */ + forall_tmp = nested_forall_info; + if (forall_tmp == NULL) + nested_forall_info = info; + else + { + while (forall_tmp->next_nest != NULL) + forall_tmp = forall_tmp->next_nest; + info->outer = forall_tmp; + forall_tmp->next_nest = info; + } + + /* Copy the mask into a temporary variable if required. + For now we assume a mask temporary is needed. */ + if (code->expr) + { + /* Allocate the mask temporary. */ + bytesize = fold (build (MULT_EXPR, gfc_array_index_type, size, + TYPE_SIZE_UNIT (boolean_type_node))); + + mask = gfc_do_allocate (bytesize, size, &pmask, &block, boolean_type_node); + + maskindex = gfc_create_var_np (gfc_array_index_type, "mi"); + /* Record them in the info structure. */ + info->pmask = pmask; + info->mask = mask; + info->maskindex = maskindex; + + gfc_add_modify_expr (&block, maskindex, integer_zero_node); + + /* Start of mask assignment loop body. */ + gfc_start_block (&body); + + /* Evaluate the mask expression. */ + gfc_init_se (&se, NULL); + gfc_conv_expr_val (&se, code->expr); + gfc_add_block_to_block (&body, &se.pre); + + /* Store the mask. */ + se.expr = convert (boolean_type_node, se.expr); + + if (pmask) + tmp = gfc_build_indirect_ref (mask); + else + tmp = mask; + tmp = gfc_build_array_ref (tmp, maskindex); + gfc_add_modify_expr (&body, tmp, se.expr); + + /* Advance to the next mask element. */ + tmp = build (PLUS_EXPR, gfc_array_index_type, maskindex, + integer_one_node); + gfc_add_modify_expr (&body, maskindex, tmp); + + /* Generate the loops. */ + tmp = gfc_finish_block (&body); + tmp = gfc_trans_nested_forall_loop (info, tmp, 0, 0); + gfc_add_expr_to_block (&block, tmp); + } + else + { + /* No mask was specified. */ + maskindex = NULL_TREE; + mask = pmask = NULL_TREE; + } + + c = code->block->next; + + /* TODO: loop merging in FORALL statements. */ + /* Now that we've got a copy of the mask, generate the assignment loops. */ + while (c) + { + switch (c->op) + { + case EXEC_ASSIGN: + /* A scalar or array assingment. */ + need_temp = gfc_check_dependency (c->expr, c->expr2, varexpr, nvar); + /* Teporaries due to array assignment data dependencies introduce + no end of problems. */ + if (need_temp) + gfc_trans_assign_need_temp (c->expr, c->expr2, NULL, + nested_forall_info, &block); + else + { + /* Use the normal assignment copying routines. */ + assign = gfc_trans_assignment (c->expr, c->expr2); + + /* Reset the mask index. */ + if (mask) + gfc_add_modify_expr (&block, maskindex, integer_zero_node); + + /* Generate body and loops. */ + tmp = gfc_trans_nested_forall_loop (nested_forall_info, assign, 1, 1); + gfc_add_expr_to_block (&block, tmp); + } + + break; + + case EXEC_WHERE: + + /* Translate WHERE or WHERE construct nested in FORALL. */ + temp = NULL; + gfc_trans_where_2 (c, NULL, NULL, nested_forall_info, &block, &temp); + + while (temp) + { + tree args; + temporary_list *p; + + /* Free the temporary. */ + args = gfc_chainon_list (NULL_TREE, temp->temporary); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, args); + gfc_add_expr_to_block (&block, tmp); + + p = temp; + temp = temp->next; + gfc_free (p); + } + + break; + + /* Pointer assignment inside FORALL. */ + case EXEC_POINTER_ASSIGN: + need_temp = gfc_check_dependency (c->expr, c->expr2, varexpr, nvar); + if (need_temp) + gfc_trans_pointer_assign_need_temp (c->expr, c->expr2, + nested_forall_info, &block); + else + { + /* Use the normal assignment copying routines. */ + assign = gfc_trans_pointer_assignment (c->expr, c->expr2); + + /* Reset the mask index. */ + if (mask) + gfc_add_modify_expr (&block, maskindex, integer_zero_node); + + /* Generate body and loops. */ + tmp = gfc_trans_nested_forall_loop (nested_forall_info, assign, + 1, 1); + gfc_add_expr_to_block (&block, tmp); + } + break; + + case EXEC_FORALL: + tmp = gfc_trans_forall_1 (c, nested_forall_info); + gfc_add_expr_to_block (&block, tmp); + break; + + default: + abort (); + break; + } + + c = c->next; + } + + /* Restore the index original backend_decl and the attribute. */ + for (fa = code->ext.forall_iterator, n=0; fa; fa = fa->next, n++) + { + gfc_symbol *sym = fa->var->symtree->n.sym; + sym->backend_decl = saved_var_decl[n]; + sym->attr = saved_var_attr[n]; + } + + /* Free the space for var, start, end, step, varexpr. */ + gfc_free (var); + gfc_free (start); + gfc_free (end); + gfc_free (step); + gfc_free (varexpr); + gfc_free (saved_var_decl); + gfc_free (saved_var_attr); + + if (pmask) + { + /* Free the temporary for the mask. */ + tmp = gfc_chainon_list (NULL_TREE, pmask); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp); + gfc_add_expr_to_block (&block, tmp); + } + if (maskindex) + pushdecl (maskindex); + + return gfc_finish_block (&block); +} + + +/* Translate the FORALL statement or construct. */ + +tree gfc_trans_forall (gfc_code * code) +{ + return gfc_trans_forall_1 (code, NULL); +} + + +/* Evaluate the WHERE mask expression, copy its value to a temporary. + If the WHERE construct is nested in FORALL, compute the overall temporary + needed by the WHERE mask expression multiplied by the iterator number of + the nested forall. + ME is the WHERE mask expression. + MASK is the temporary which value is mask's value. + NMASK is another temporary which value is !mask. + TEMP records the temporary's address allocated in this function in order to + free them outside this function. + MASK, NMASK and TEMP are all OUT arguments. */ + +static tree +gfc_evaluate_where_mask (gfc_expr * me, forall_info * nested_forall_info, + tree * mask, tree * nmask, temporary_list ** temp, + stmtblock_t * block) +{ + tree tmp, tmp1; + gfc_ss *lss, *rss; + gfc_loopinfo loop; + tree ptemp1, ntmp, ptemp2; + tree inner_size; + stmtblock_t body, body1; + gfc_se lse, rse; + tree count; + tree tmpexpr; + + gfc_init_loopinfo (&loop); + + /* Calculate the size of temporary needed by the mask-expr. */ + inner_size = compute_inner_temp_size (me, me, block, &lss, &rss); + + /* Allocate temporary for where mask. */ + tmp = allocate_temp_for_forall_nest (nested_forall_info, boolean_type_node, + inner_size, block, &ptemp1); + /* Record the temporary address in order to free it later. */ + if (ptemp1) + { + temporary_list *tempo; + tempo = (temporary_list *) gfc_getmem (sizeof (temporary_list)); + tempo->temporary = ptemp1; + tempo->next = *temp; + *temp = tempo; + } + + /* Allocate temporary for !mask. */ + ntmp = allocate_temp_for_forall_nest (nested_forall_info, boolean_type_node, + inner_size, block, &ptemp2); + /* Record the temporary in order to free it later. */ + if (ptemp2) + { + temporary_list *tempo; + tempo = (temporary_list *) gfc_getmem (sizeof (temporary_list)); + tempo->temporary = ptemp2; + tempo->next = *temp; + *temp = tempo; + } + + /* Variable to index the temporary. */ + count = gfc_create_var (gfc_array_index_type, "count"); + /* Initilize count. */ + gfc_add_modify_expr (block, count, integer_zero_node); + + gfc_start_block (&body); + + gfc_init_se (&rse, NULL); + gfc_init_se (&lse, NULL); + + if (lss == gfc_ss_terminator) + { + gfc_init_block (&body1); + } + else + { + /* Initiliaze the loop. */ + gfc_init_loopinfo (&loop); + + /* We may need LSS to determine the shape of the expression. */ + gfc_add_ss_to_loop (&loop, lss); + gfc_add_ss_to_loop (&loop, rss); + + gfc_conv_ss_startstride (&loop); + gfc_conv_loop_setup (&loop); + + gfc_mark_ss_chain_used (rss, 1); + /* Start the loop body. */ + gfc_start_scalarized_body (&loop, &body1); + + /* Translate the expression. */ + gfc_copy_loopinfo_to_se (&rse, &loop); + rse.ss = rss; + gfc_conv_expr (&rse, me); + } + /* Form the expression of the temporary. */ + lse.expr = gfc_build_array_ref (tmp, count); + tmpexpr = gfc_build_array_ref (ntmp, count); + + /* Use the scalar assignment to fill temporary TMP. */ + tmp1 = gfc_trans_scalar_assign (&lse, &rse, me->ts.type); + gfc_add_expr_to_block (&body1, tmp1); + + /* Fill temporary NTMP. */ + tmp1 = build1 (TRUTH_NOT_EXPR, TREE_TYPE (lse.expr), lse.expr); + gfc_add_modify_expr (&body1, tmpexpr, tmp1); + + if (lss == gfc_ss_terminator) + { + gfc_add_block_to_block (&body, &body1); + } + else + { + /* Increment count. */ + tmp1 = fold (build (PLUS_EXPR, gfc_array_index_type, count, + integer_one_node)); + gfc_add_modify_expr (&body1, count, tmp1); + + /* Generate the copying loops. */ + gfc_trans_scalarizing_loops (&loop, &body1); + + gfc_add_block_to_block (&body, &loop.pre); + gfc_add_block_to_block (&body, &loop.post); + + gfc_cleanup_loop (&loop); + /* TODO: Reuse lss and rss when copying temp->lhs. Need to be careful + as tree nodes in SS may not be valid in different scope. */ + } + + tmp1 = gfc_finish_block (&body); + /* If the WHERE construct is inside FORALL, fill the full temporary. */ + if (nested_forall_info != NULL) + tmp1 = gfc_trans_nested_forall_loop (nested_forall_info, tmp1, 1, 1); + + + gfc_add_expr_to_block (block, tmp1); + + *mask = tmp; + *nmask = ntmp; + + return tmp1; +} + + +/* Translate an assignment statement in a WHERE statement or construct + statement. The MASK expression is used to control which elements + of EXPR1 shall be assigned. */ + +static tree +gfc_trans_where_assign (gfc_expr *expr1, gfc_expr *expr2, tree mask, + tree count1, tree count2) +{ + gfc_se lse; + gfc_se rse; + gfc_ss *lss; + gfc_ss *lss_section; + gfc_ss *rss; + + gfc_loopinfo loop; + tree tmp; + stmtblock_t block; + stmtblock_t body; + tree index, maskexpr, tmp1; + +#if 0 + /* TODO: handle this special case. + Special case a single function returning an array. */ + if (expr2->expr_type == EXPR_FUNCTION && expr2->rank > 0) + { + tmp = gfc_trans_arrayfunc_assign (expr1, expr2); + if (tmp) + return tmp; + } +#endif + + /* Assignment of the form lhs = rhs. */ + gfc_start_block (&block); + + gfc_init_se (&lse, NULL); + gfc_init_se (&rse, NULL); + + /* Walk the lhs. */ + lss = gfc_walk_expr (expr1); + rss = NULL; + + /* In each where-assign-stmt, the mask-expr and the variable being + defined shall be arrays of the same shape. */ + assert (lss != gfc_ss_terminator); + + /* The assignment needs scalarization. */ + lss_section = lss; + + /* Find a non-scalar SS from the lhs. */ + while (lss_section != gfc_ss_terminator + && lss_section->type != GFC_SS_SECTION) + lss_section = lss_section->next; + + assert (lss_section != gfc_ss_terminator); + + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); + + /* Walk the rhs. */ + rss = gfc_walk_expr (expr2); + if (rss == gfc_ss_terminator) + { + /* The rhs is scalar. Add a ss for the expression. */ + rss = gfc_get_ss (); + rss->next = gfc_ss_terminator; + rss->type = GFC_SS_SCALAR; + rss->expr = expr2; + } + + /* Associate the SS with the loop. */ + gfc_add_ss_to_loop (&loop, lss); + gfc_add_ss_to_loop (&loop, rss); + + /* Calculate the bounds of the scalarization. */ + gfc_conv_ss_startstride (&loop); + + /* Resolve any data dependencies in the statement. */ + gfc_conv_resolve_dependencies (&loop, lss_section, rss); + + /* Setup the scalarizing loops. */ + gfc_conv_loop_setup (&loop); + + /* Setup the gfc_se structures. */ + gfc_copy_loopinfo_to_se (&lse, &loop); + gfc_copy_loopinfo_to_se (&rse, &loop); + + rse.ss = rss; + gfc_mark_ss_chain_used (rss, 1); + if (loop.temp_ss == NULL) + { + lse.ss = lss; + gfc_mark_ss_chain_used (lss, 1); + } + else + { + lse.ss = loop.temp_ss; + gfc_mark_ss_chain_used (lss, 3); + gfc_mark_ss_chain_used (loop.temp_ss, 3); + } + + /* Start the scalarized loop body. */ + gfc_start_scalarized_body (&loop, &body); + + /* Translate the expression. */ + gfc_conv_expr (&rse, expr2); + if (lss != gfc_ss_terminator && loop.temp_ss != NULL) + { + gfc_conv_tmp_array_ref (&lse); + gfc_advance_se_ss_chain (&lse); + } + else + gfc_conv_expr (&lse, expr1); + + /* Form the mask expression according to the mask tree list. */ + index = count1; + tmp = mask; + if (tmp != NULL) + maskexpr = gfc_build_array_ref (tmp, index); + else + maskexpr = NULL; + + tmp = TREE_CHAIN (tmp); + while (tmp) + { + tmp1 = gfc_build_array_ref (tmp, index); + maskexpr = build (TRUTH_AND_EXPR, TREE_TYPE (tmp1), maskexpr, tmp1); + tmp = TREE_CHAIN (tmp); + } + /* Use the scalar assignment as is. */ + tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts.type); + tmp = build_v (COND_EXPR, maskexpr, tmp, build_empty_stmt ()); + + gfc_add_expr_to_block (&body, tmp); + + if (lss == gfc_ss_terminator) + { + /* Increment count1. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count1), count1, + integer_one_node)); + gfc_add_modify_expr (&body, count1, tmp); + + /* Use the scalar assignment as is. */ + gfc_add_block_to_block (&block, &body); + } + else + { + if (lse.ss != gfc_ss_terminator) + abort (); + if (rse.ss != gfc_ss_terminator) + abort (); + + if (loop.temp_ss != NULL) + { + /* Increment count1 before finish the main body of a scalarized + expression. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count1), count1, + integer_one_node)); + gfc_add_modify_expr (&body, count1, tmp); + gfc_trans_scalarized_loop_boundary (&loop, &body); + + /* We need to copy the temporary to the actual lhs. */ + gfc_init_se (&lse, NULL); + gfc_init_se (&rse, NULL); + gfc_copy_loopinfo_to_se (&lse, &loop); + gfc_copy_loopinfo_to_se (&rse, &loop); + + rse.ss = loop.temp_ss; + lse.ss = lss; + + gfc_conv_tmp_array_ref (&rse); + gfc_advance_se_ss_chain (&rse); + gfc_conv_expr (&lse, expr1); + + if (lse.ss != gfc_ss_terminator) + abort (); + + if (rse.ss != gfc_ss_terminator) + abort (); + + /* Form the mask expression according to the mask tree list. */ + index = count2; + tmp = mask; + if (tmp != NULL) + maskexpr = gfc_build_array_ref (tmp, index); + else + maskexpr = NULL; + + tmp = TREE_CHAIN (tmp); + while (tmp) + { + tmp1 = gfc_build_array_ref (tmp, index); + maskexpr = build (TRUTH_AND_EXPR, TREE_TYPE (tmp1), maskexpr, + tmp1); + tmp = TREE_CHAIN (tmp); + } + /* Use the scalar assignment as is. */ + tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts.type); + tmp = build_v (COND_EXPR, maskexpr, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&body, tmp); + /* Increment count2. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count2), count2, + integer_one_node)); + gfc_add_modify_expr (&body, count2, tmp); + } + else + { + /* Increment count1. */ + tmp = fold (build (PLUS_EXPR, TREE_TYPE (count1), count1, + integer_one_node)); + gfc_add_modify_expr (&body, count1, tmp); + } + + /* Generate the copying loops. */ + gfc_trans_scalarizing_loops (&loop, &body); + + /* Wrap the whole thing up. */ + gfc_add_block_to_block (&block, &loop.pre); + gfc_add_block_to_block (&block, &loop.post); + gfc_cleanup_loop (&loop); + } + + return gfc_finish_block (&block); +} + + +/* Translate the WHERE construct or statement. + This fuction can be called iteratelly to translate the nested WHERE + construct or statement. + MASK is the control mask, and PMASK is the pending control mask. + TEMP records the temporary address which must be freed later. */ + +static void +gfc_trans_where_2 (gfc_code * code, tree mask, tree pmask, + forall_info * nested_forall_info, stmtblock_t * block, + temporary_list ** temp) +{ + gfc_expr *expr1; + gfc_expr *expr2; + gfc_code *cblock; + gfc_code *cnext; + tree tmp, tmp1, tmp2; + tree count1, count2; + tree mask_copy; + int need_temp; + + /* the WHERE statement or the WHERE construct statement. */ + cblock = code->block; + while (cblock) + { + /* Has mask-expr. */ + if (cblock->expr) + { + /* Ensure that the WHERE mask be evaluated only once. */ + tmp2 = gfc_evaluate_where_mask (cblock->expr, nested_forall_info, + &tmp, &tmp1, temp, block); + + /* Set the control mask and the pending control mask. */ + /* It's a where-stmt. */ + if (mask == NULL) + { + mask = tmp; + pmask = tmp1; + } + /* It's a nested where-stmt. */ + else if (mask && pmask == NULL) + { + tree tmp2; + /* Use the TREE_CHAIN to list the masks. */ + tmp2 = copy_list (mask); + pmask = chainon (mask, tmp1); + mask = chainon (tmp2, tmp); + } + /* It's a masked-elsewhere-stmt. */ + else if (mask && cblock->expr) + { + tree tmp2; + tmp2 = copy_list (pmask); + + mask = pmask; + tmp2 = chainon (tmp2, tmp); + pmask = chainon (mask, tmp1); + mask = tmp2; + } + } + /* It's a elsewhere-stmt. No mask-expr is present. */ + else + mask = pmask; + + /* Get the assignment statement of a WHERE statement, or the first + statement in where-body-construct of a WHERE construct. */ + cnext = cblock->next; + while (cnext) + { + switch (cnext->op) + { + /* WHERE assignment statement. */ + case EXEC_ASSIGN: + expr1 = cnext->expr; + expr2 = cnext->expr2; + if (nested_forall_info != NULL) + { + int nvar; + gfc_expr **varexpr; + + nvar = nested_forall_info->nvar; + varexpr = (gfc_expr **) + gfc_getmem (nvar * sizeof (gfc_expr *)); + need_temp = gfc_check_dependency (expr1, expr2, varexpr, + nvar); + if (need_temp) + gfc_trans_assign_need_temp (expr1, expr2, mask, + nested_forall_info, block); + else + { + /* Variables to control maskexpr. */ + count1 = gfc_create_var (gfc_array_index_type, "count1"); + count2 = gfc_create_var (gfc_array_index_type, "count2"); + gfc_add_modify_expr (block, count1, integer_zero_node); + gfc_add_modify_expr (block, count2, integer_zero_node); + + tmp = gfc_trans_where_assign (expr1, expr2, mask, count1, + count2); + tmp = gfc_trans_nested_forall_loop (nested_forall_info, + tmp, 1, 1); + gfc_add_expr_to_block (block, tmp); + } + } + else + { + /* Variables to control maskexpr. */ + count1 = gfc_create_var (gfc_array_index_type, "count1"); + count2 = gfc_create_var (gfc_array_index_type, "count2"); + gfc_add_modify_expr (block, count1, integer_zero_node); + gfc_add_modify_expr (block, count2, integer_zero_node); + + tmp = gfc_trans_where_assign (expr1, expr2, mask, count1, + count2); + gfc_add_expr_to_block (block, tmp); + + } + break; + + /* WHERE or WHERE construct is part of a where-body-construct. */ + case EXEC_WHERE: + /* Ensure that MASK is not modified by next gfc_trans_where_2. */ + mask_copy = copy_list (mask); + gfc_trans_where_2 (cnext, mask_copy, NULL, nested_forall_info, + block, temp); + break; + + default: + abort (); + } + + /* The next statement within the same where-body-construct. */ + cnext = cnext->next; + } + /* The next masked-elsewhere-stmt, elsewhere-stmt, or end-where-stmt. */ + cblock = cblock->block; + } +} + + +/* As the WHERE or WHERE construct statement can be nested, we call + gfc_trans_where_2 to do the translation, and pass the initial + NULL values for both the control mask and the pending control mask. */ + +tree +gfc_trans_where (gfc_code * code) +{ + stmtblock_t block; + temporary_list *temp, *p; + tree args; + tree tmp; + + gfc_start_block (&block); + temp = NULL; + + gfc_trans_where_2 (code, NULL, NULL, NULL, &block, &temp); + + /* Add calls to free temporaries which were dynamically allocated. */ + while (temp) + { + args = gfc_chainon_list (NULL_TREE, temp->temporary); + tmp = gfc_build_function_call (gfor_fndecl_internal_free, args); + gfc_add_expr_to_block (&block, tmp); + + p = temp; + temp = temp->next; + gfc_free (p); + } + return gfc_finish_block (&block); +} + + +/* CYCLE a DO loop. The label decl has already been created by + gfc_trans_do(), it's in TREE_PURPOSE (backend_decl) of the gfc_code + node at the head of the loop. We must mark the label as used. */ + +tree +gfc_trans_cycle (gfc_code * code) +{ + tree cycle_label; + + cycle_label = TREE_PURPOSE (code->ext.whichloop->backend_decl); + TREE_USED (cycle_label) = 1; + return build1_v (GOTO_EXPR, cycle_label); +} + + +/* EXIT a DO loop. Similair to CYCLE, but now the label is in + TREE_VALUE (backend_decl) of the gfc_code node at the head of the + loop. */ + +tree +gfc_trans_exit (gfc_code * code) +{ + tree exit_label; + + exit_label = TREE_VALUE (code->ext.whichloop->backend_decl); + TREE_USED (exit_label) = 1; + return build1_v (GOTO_EXPR, exit_label); +} + + +/* Translate the ALLOCATE statement. */ + +tree +gfc_trans_allocate (gfc_code * code) +{ + gfc_alloc *al; + gfc_expr *expr; + gfc_se se; + tree tmp; + tree parm; + gfc_ref *ref; + tree stat; + tree pstat; + tree error_label; + stmtblock_t block; + + if (!code->ext.alloc_list) + return NULL_TREE; + + gfc_start_block (&block); + + if (code->expr) + { + stat = gfc_create_var (gfc_int4_type_node, "stat"); + pstat = gfc_build_addr_expr (NULL, stat); + + error_label = gfc_build_label_decl (NULL_TREE); + TREE_USED (error_label) = 1; + } + else + { + pstat = integer_zero_node; + stat = error_label = NULL_TREE; + } + + + for (al = code->ext.alloc_list; al != NULL; al = al->next) + { + expr = al->expr; + + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + se.want_pointer = 1; + se.descriptor_only = 1; + gfc_conv_expr (&se, expr); + + ref = expr->ref; + + /* Find the last reference in the chain. */ + while (ref && ref->next != NULL) + { + assert (ref->type != REF_ARRAY || ref->u.ar.type == AR_ELEMENT); + ref = ref->next; + } + + if (ref != NULL && ref->type == REF_ARRAY) + { + /* An array. */ + gfc_array_allocate (&se, ref, pstat); + } + else + { + /* A scalar or derived type. */ + tree val; + + val = gfc_create_var (ppvoid_type_node, "ptr"); + tmp = gfc_build_addr_expr (ppvoid_type_node, se.expr); + gfc_add_modify_expr (&se.pre, val, tmp); + + tmp = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (se.expr))); + parm = gfc_chainon_list (NULL_TREE, val); + parm = gfc_chainon_list (parm, tmp); + parm = gfc_chainon_list (parm, pstat); + tmp = gfc_build_function_call (gfor_fndecl_allocate, parm); + gfc_add_expr_to_block (&se.pre, tmp); + + if (code->expr) + { + tmp = build1_v (GOTO_EXPR, error_label); + parm = + build (NE_EXPR, boolean_type_node, stat, integer_zero_node); + tmp = build_v (COND_EXPR, parm, tmp, build_empty_stmt ()); + gfc_add_expr_to_block (&se.pre, tmp); + } + } + + tmp = gfc_finish_block (&se.pre); + gfc_add_expr_to_block (&block, tmp); + } + + /* Assign the value to the status variable. */ + if (code->expr) + { + tmp = build1_v (LABEL_EXPR, error_label); + gfc_add_expr_to_block (&block, tmp); + + gfc_init_se (&se, NULL); + gfc_conv_expr_lhs (&se, code->expr); + tmp = convert (TREE_TYPE (se.expr), stat); + gfc_add_modify_expr (&block, se.expr, tmp); + } + + return gfc_finish_block (&block); +} + + +tree +gfc_trans_deallocate (gfc_code * code) +{ + gfc_se se; + gfc_alloc *al; + gfc_expr *expr; + tree var; + tree tmp; + tree type; + stmtblock_t block; + + gfc_start_block (&block); + + for (al = code->ext.alloc_list; al != NULL; al = al->next) + { + expr = al->expr; + assert (expr->expr_type == EXPR_VARIABLE); + + gfc_init_se (&se, NULL); + gfc_start_block (&se.pre); + + se.want_pointer = 1; + se.descriptor_only = 1; + gfc_conv_expr (&se, expr); + + if (expr->symtree->n.sym->attr.dimension) + { + tmp = gfc_array_deallocate (se.expr); + gfc_add_expr_to_block (&se.pre, tmp); + } + else + { + type = build_pointer_type (TREE_TYPE (se.expr)); + var = gfc_create_var (type, "ptr"); + tmp = gfc_build_addr_expr (type, se.expr); + gfc_add_modify_expr (&se.pre, var, tmp); + + tmp = gfc_chainon_list (NULL_TREE, var); + tmp = gfc_chainon_list (tmp, integer_zero_node); + tmp = gfc_build_function_call (gfor_fndecl_deallocate, tmp); + gfc_add_expr_to_block (&se.pre, tmp); + } + tmp = gfc_finish_block (&se.pre); + gfc_add_expr_to_block (&block, tmp); + } + + return gfc_finish_block (&block); +} + diff --git a/gcc/fortran/trans-stmt.h b/gcc/fortran/trans-stmt.h new file mode 100644 index 00000000000..ff62dd5b017 --- /dev/null +++ b/gcc/fortran/trans-stmt.h @@ -0,0 +1,65 @@ +/* Header for statement translation functions + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Statement translators (gfc_trans_*) return a fully translated tree. + Calls gfc_trans_*. */ +tree gfc_trans_code (gfc_code *); + +/* All other gfc_trans_* should only need be called by gfc_trans_code */ + +/* trans-expr.c */ +tree gfc_trans_assign (gfc_code *); +tree gfc_trans_pointer_assign (gfc_code *); + +/* trans-stmt.c */ +tree gfc_trans_cycle (gfc_code *); +tree gfc_trans_exit (gfc_code *); +tree gfc_trans_label_assign (gfc_code *); +tree gfc_trans_label_here (gfc_code *); +tree gfc_trans_goto (gfc_code *); +tree gfc_trans_pause (gfc_code *); +tree gfc_trans_stop (gfc_code *); +tree gfc_trans_call (gfc_code *); +tree gfc_trans_return (gfc_code *); +tree gfc_trans_if (gfc_code *); +tree gfc_trans_arithmetic_if (gfc_code *); +tree gfc_trans_do (gfc_code *); +tree gfc_trans_do_while (gfc_code *); +tree gfc_trans_select (gfc_code *); +tree gfc_trans_forall (gfc_code *); +tree gfc_trans_where (gfc_code *); +tree gfc_trans_allocate (gfc_code *); +tree gfc_trans_deallocate (gfc_code *); +tree gfc_trans_deallocate_array (tree); + +/* trans-io.c */ +tree gfc_trans_open (gfc_code *); +tree gfc_trans_close (gfc_code *); +tree gfc_trans_read (gfc_code *); +tree gfc_trans_write (gfc_code *); +tree gfc_trans_iolength (gfc_code *); +tree gfc_trans_backspace (gfc_code *); +tree gfc_trans_endfile (gfc_code *); +tree gfc_trans_inquire (gfc_code *); +tree gfc_trans_rewind (gfc_code *); + +tree gfc_trans_transfer (gfc_code *); +tree gfc_trans_dt_end (gfc_code *); diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c new file mode 100644 index 00000000000..12943891582 --- /dev/null +++ b/gcc/fortran/trans-types.c @@ -0,0 +1,1485 @@ +/* Backend support for Fortran 95 basic types and derived types. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + and Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* trans-types.c -- gfortran backend types */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include +#include "ggc.h" +#include "toplev.h" +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-types.h" +#include "trans-const.h" + + +#if (GFC_MAX_DIMENSIONS < 10) +#define GFC_RANK_DIGITS 1 +#define GFC_RANK_PRINTF_FORMAT "%01d" +#elif (GFC_MAX_DIMENSIONS < 100) +#define GFC_RANK_DIGITS 2 +#define GFC_RANK_PRINTF_FORMAT "%02d" +#else +#error If you really need >99 dimensions, continue the sequence above... +#endif + +static tree gfc_get_derived_type (gfc_symbol * derived); + +tree gfc_type_nodes[NUM_F95_TYPES]; + +tree gfc_array_index_type; +tree pvoid_type_node; +tree ppvoid_type_node; +tree pchar_type_node; + +static GTY(()) tree gfc_desc_dim_type = NULL; + +static GTY(()) tree gfc_max_array_element_size; + +/* Create the backend type nodes. We map them to their + equivalent C type, at least for now. We also give + names to the types here, and we push them in the + global binding level context.*/ +void +gfc_init_types (void) +{ + unsigned n; + unsigned HOST_WIDE_INT hi; + unsigned HOST_WIDE_INT lo; + + /* Name the types. */ +#define PUSH_TYPE(name, node) \ + pushdecl (build_decl (TYPE_DECL, get_identifier (name), node)) + + gfc_int1_type_node = signed_char_type_node; + PUSH_TYPE ("int1", gfc_int1_type_node); + gfc_int2_type_node = short_integer_type_node; + PUSH_TYPE ("int2", gfc_int2_type_node); + gfc_int4_type_node = gfc_type_for_size (32, 0 /*unsigned */ ); + PUSH_TYPE ("int4", gfc_int4_type_node); + gfc_int8_type_node = gfc_type_for_size (64, 0 /*unsigned */ ); + PUSH_TYPE ("int8", gfc_int8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + gfc_int16_type_node = gfc_type_for_size (128, 0 /*unsigned */ ); + PUSH_TYPE ("int16", gfc_int16_type_node); +#endif + + gfc_real4_type_node = float_type_node; + PUSH_TYPE ("real4", gfc_real4_type_node); + gfc_real8_type_node = double_type_node; + PUSH_TYPE ("real8", gfc_real8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + /* Hmm, this will not work. Ref. g77 */ + gfc_real16_type_node = long_double_type_node; + PUSH_TYPE ("real16", gfc_real16_type_node); +#endif + + gfc_complex4_type_node = complex_float_type_node; + PUSH_TYPE ("complex4", gfc_complex4_type_node); + gfc_complex8_type_node = complex_double_type_node; + PUSH_TYPE ("complex8", gfc_complex8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + /* Hmm, this will not work. Ref. g77 */ + gfc_complex16_type_node = complex_long_double_type_node; + PUSH_TYPE ("complex16", gfc_complex16_type_node); +#endif + + gfc_logical1_type_node = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (gfc_logical1_type_node) = 8; + fixup_unsigned_type (gfc_logical1_type_node); + PUSH_TYPE ("logical1", gfc_logical1_type_node); + gfc_logical2_type_node = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (gfc_logical2_type_node) = 16; + fixup_unsigned_type (gfc_logical2_type_node); + PUSH_TYPE ("logical2", gfc_logical2_type_node); + gfc_logical4_type_node = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (gfc_logical4_type_node) = 32; + fixup_unsigned_type (gfc_logical4_type_node); + PUSH_TYPE ("logical4", gfc_logical4_type_node); + gfc_logical8_type_node = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (gfc_logical8_type_node) = 64; + fixup_unsigned_type (gfc_logical8_type_node); + PUSH_TYPE ("logical8", gfc_logical8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + gfc_logical16_type_node = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (gfc_logical16_type_node) = 128; + fixup_unsigned_type (gfc_logical16_type_node); + PUSH_TYPE ("logical16", gfc_logical16_type_node); +#endif + + gfc_character1_type_node = build_type_variant (signed_char_type_node, 0, 0); + PUSH_TYPE ("char", gfc_character1_type_node); + + PUSH_TYPE ("byte", unsigned_char_type_node); + PUSH_TYPE ("void", void_type_node); + + /* DBX debugging output gets upset if these aren't set. */ + if (!TYPE_NAME (integer_type_node)) + PUSH_TYPE ("c_integer", integer_type_node); + if (!TYPE_NAME (char_type_node)) + PUSH_TYPE ("c_char", char_type_node); +#undef PUSH_TYPE + + pvoid_type_node = build_pointer_type (void_type_node); + ppvoid_type_node = build_pointer_type (pvoid_type_node); + pchar_type_node = build_pointer_type (gfc_character1_type_node); + + gfc_index_integer_kind = TYPE_PRECISION (long_unsigned_type_node) / 8; + gfc_array_index_type = gfc_get_int_type (gfc_index_integer_kind); + + /* The maximum array element size that can be handled is determined + by the number of bits available to store this field in the array + descriptor. */ + + n = TREE_INT_CST_LOW (TYPE_SIZE (gfc_array_index_type)) + - GFC_DTYPE_SIZE_SHIFT; + + if (n > sizeof (HOST_WIDE_INT) * 8) + { + lo = ~(unsigned HOST_WIDE_INT) 0; + hi = lo >> (sizeof (HOST_WIDE_INT) * 16 - n); + } + else + { + hi = 0; + lo = (~(unsigned HOST_WIDE_INT) 0) >> (sizeof (HOST_WIDE_INT) * 8 - n); + } + gfc_max_array_element_size = build_int_2 (lo, hi); + TREE_TYPE (gfc_max_array_element_size) = long_unsigned_type_node; + + size_type_node = gfc_array_index_type; + boolean_type_node = gfc_get_logical_type (gfc_default_logical_kind ()); + + boolean_true_node = build_int_2 (1, 0); + TREE_TYPE (boolean_true_node) = boolean_type_node; + boolean_false_node = build_int_2 (0, 0); + TREE_TYPE (boolean_false_node) = boolean_type_node; +} + +/* Get a type node for an integer kind */ +tree +gfc_get_int_type (int kind) +{ + switch (kind) + { + case 1: + return (gfc_int1_type_node); + case 2: + return (gfc_int2_type_node); + case 4: + return (gfc_int4_type_node); + case 8: + return (gfc_int8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + case 16: + return (95 _int16_type_node); +#endif + default: + fatal_error ("integer kind=%d not available", kind); + } +} + +/* Get a type node for a real kind */ +tree +gfc_get_real_type (int kind) +{ + switch (kind) + { + case 4: + return (gfc_real4_type_node); + case 8: + return (gfc_real8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + case 16: + return (gfc_real16_type_node); +#endif + default: + fatal_error ("real kind=%d not available", kind); + } +} + +/* Get a type node for a complex kind */ +tree +gfc_get_complex_type (int kind) +{ + switch (kind) + { + case 4: + return (gfc_complex4_type_node); + case 8: + return (gfc_complex8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + case 16: + return (gfc_complex16_type_node); +#endif + default: + fatal_error ("complex kind=%d not available", kind); + } +} + +/* Get a type node for a logical kind */ +tree +gfc_get_logical_type (int kind) +{ + switch (kind) + { + case 1: + return (gfc_logical1_type_node); + case 2: + return (gfc_logical2_type_node); + case 4: + return (gfc_logical4_type_node); + case 8: + return (gfc_logical8_type_node); +#if (GFC_USE_TYPES16 && (HOST_BITS_PER_WIDE_INT >= 64)) + case 16: + return (gfc_logical16_type_node); +#endif + default: + fatal_error ("logical kind=%d not available", kind); + } +} + +/* Get a type node for a character kind. */ +tree +gfc_get_character_type (int kind, gfc_charlen * cl) +{ + tree base; + tree type; + tree len; + tree bounds; + + switch (kind) + { + case 1: + base = gfc_character1_type_node; + break; + + default: + fatal_error ("character kind=%d not available", kind); + } + + len = (cl == 0) ? NULL_TREE : cl->backend_decl; + + bounds = build_range_type (gfc_array_index_type, integer_one_node, len); + type = build_array_type (base, bounds); + TYPE_STRING_FLAG (type) = 1; + + return type; +} + +/* Covert a basic type. This will be an array for character types. */ +tree +gfc_typenode_for_spec (gfc_typespec * spec) +{ + tree basetype; + + switch (spec->type) + { + case BT_UNKNOWN: + abort (); + break; + + case BT_INTEGER: + basetype = gfc_get_int_type (spec->kind); + break; + + case BT_REAL: + basetype = gfc_get_real_type (spec->kind); + break; + + case BT_COMPLEX: + basetype = gfc_get_complex_type (spec->kind); + break; + + case BT_LOGICAL: + basetype = gfc_get_logical_type (spec->kind); + break; + + case BT_CHARACTER: + basetype = gfc_get_character_type (spec->kind, spec->cl); + break; + + case BT_DERIVED: + basetype = gfc_get_derived_type (spec->derived); + break; + + default: + abort (); + break; + } + return basetype; +} + +/* Build an INT_CST for constant expressions, otherwise return NULL_TREE. */ +static tree +gfc_conv_array_bound (gfc_expr * expr) +{ + /* If expr is an integer constant, return that. */ + if (expr != NULL && expr->expr_type == EXPR_CONSTANT) + return gfc_conv_mpz_to_tree (expr->value.integer, gfc_index_integer_kind); + + /* Otherwise return NULL. */ + return NULL_TREE; +} + +tree +gfc_get_element_type (tree type) +{ + tree element; + + if (GFC_ARRAY_TYPE_P (type)) + { + if (TREE_CODE (type) == POINTER_TYPE) + type = TREE_TYPE (type); + assert (TREE_CODE (type) == ARRAY_TYPE); + element = TREE_TYPE (type); + } + else + { + assert (GFC_DESCRIPTOR_TYPE_P (type)); + element = TREE_TYPE (TYPE_FIELDS (type)); + + assert (TREE_CODE (element) == POINTER_TYPE); + element = TREE_TYPE (element); + + assert (TREE_CODE (element) == ARRAY_TYPE); + element = TREE_TYPE (element); + } + + return element; +} + +/* Build an array. This function is called from gfc_sym_type(). + Actualy returns array descriptor type. + + Format of array descriptors is as follows: + + struct gfc_array_descriptor + { + array *data + index offset; + index dtype; + struct descriptor_dimension dimension[N_DIM]; + } + + struct descriptor_dimension + { + index stride; + index lbound; + index ubound; + } + + Translation code should use gfc_conv_descriptor_* rather than accessing + the descriptor directly. Any changes to the array descriptor type will + require changes in gfc_conv_descriptor_* and gfc_build_array_initializer. + + This is represented internaly as a RECORD_TYPE. The index nodes are + gfc_array_index_type and the data node is a pointer to the data. See below + for the handling of character types. + + The dtype member is formatted as follows: + rank = dtype & GFC_DTYPE_RANK_MASK // 3 bits + type = (dtype & GFC_DTYPE_TYPE_MASK) >> GFC_DTYPE_TYPE_SHIFT // 3 bits + size = dtype >> GFC_DTYPE_SIZE_SHIFT + + I originaly used nested ARRAY_TYPE nodes to represent arrays, but this + generated poor code for assumed/deferred size arrays. These require + use of PLACEHOLDER_EXPR/WITH_RECORD_EXPR, which isn't part of GIMPLE + grammar. Also, there is no way to explicitly set the array stride, so + all data must be packed(1). I've tried to mark all the functions which + would require modification with a GCC ARRAYS comment. + + The data component points to the first element in the array. + The offset field is the position of the origin of the array + (ie element (0, 0 ...)). This may be outsite the bounds of the array. + + An element is accessed by + data[offset + index0*stride0 + index1*stride1 + index2*stride2] + This gives good performance as it computation does not involve the + bounds of the array. For packed arrays, this is optimized further by + substituting the known strides. + + This system has one problem: all array bounds must be withing 2^31 elements + of the origin (2^63 on 64-bit machines). For example + integer, dimension (80000:90000, 80000:90000, 2) :: array + may not work properly on 32-bit machines because 80000*80000 > 2^31, so + the calculation for stride02 would overflow. This may still work, but + I haven't checked, and it relies on the overflow doing the right thing. + + The way to fix this problem is to access alements as follows: + data[(index0-lbound0)*stride0 + (index1-lbound1)*stride1] + Obviously this is much slower. I will make this a compile time option, + something like -fsmall-array-offsets. Mixing code compiled with and without + this switch will work. + + (1) This can be worked around by modifying the upper bound of the previous + dimension. This requires extra fields in the descriptor (both real_ubound + and fake_ubound). In tree.def there is mention of TYPE_SEP, which + may allow us to do this. However I can't find mention of this anywhere + else. + */ + + +/* Returns true if the array sym does not require a descriptor. */ + +int +gfc_is_nodesc_array (gfc_symbol * sym) +{ + assert (sym->attr.dimension); + + /* We only want local arrays. */ + if (sym->attr.pointer || sym->attr.allocatable) + return 0; + + if (sym->attr.dummy) + { + if (sym->as->type != AS_ASSUMED_SHAPE) + return 1; + else + return 0; + } + + if (sym->attr.result || sym->attr.function) + return 0; + + if (sym->attr.pointer || sym->attr.allocatable) + return 0; + + assert (sym->as->type == AS_EXPLICIT); + + return 1; +} + +static tree +gfc_build_array_type (tree type, gfc_array_spec * as) +{ + tree lbound[GFC_MAX_DIMENSIONS]; + tree ubound[GFC_MAX_DIMENSIONS]; + int n; + + for (n = 0; n < as->rank; n++) + { + /* Create expressions for the known bounds of the array. */ + if (as->type == AS_ASSUMED_SHAPE && as->lower[n] == NULL) + lbound[n] = integer_one_node; + else + lbound[n] = gfc_conv_array_bound (as->lower[n]); + ubound[n] = gfc_conv_array_bound (as->upper[n]); + } + + return gfc_get_array_type_bounds (type, as->rank, lbound, ubound, 0); +} + +/* Returns the struct descriptor_dimension type. */ +static tree +gfc_get_desc_dim_type (void) +{ + tree type; + tree decl; + tree fieldlist; + + if (gfc_desc_dim_type) + return gfc_desc_dim_type; + + /* Build the type node. */ + type = make_node (RECORD_TYPE); + + TYPE_NAME (type) = get_identifier ("descriptor_dimension"); + TYPE_PACKED (type) = 1; + + /* Consists of the stride, lbound and ubound members. */ + decl = build_decl (FIELD_DECL, + get_identifier ("stride"), gfc_array_index_type); + DECL_CONTEXT (decl) = type; + fieldlist = decl; + + decl = build_decl (FIELD_DECL, + get_identifier ("lbound"), gfc_array_index_type); + DECL_CONTEXT (decl) = type; + fieldlist = chainon (fieldlist, decl); + + decl = build_decl (FIELD_DECL, + get_identifier ("ubound"), gfc_array_index_type); + DECL_CONTEXT (decl) = type; + fieldlist = chainon (fieldlist, decl); + + /* Finish off the type. */ + TYPE_FIELDS (type) = fieldlist; + + gfc_finish_type (type); + + gfc_desc_dim_type = type; + return type; +} + +static tree +gfc_get_dtype (tree type, int rank) +{ + tree size; + int n; + HOST_WIDE_INT i; + tree tmp; + tree dtype; + + if (GFC_DESCRIPTOR_TYPE_P (type) || GFC_ARRAY_TYPE_P (type)) + return (GFC_TYPE_ARRAY_DTYPE (type)); + + /* TODO: Correctly identify LOGICAL types. */ + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + n = GFC_DTYPE_INTEGER; + break; + + case BOOLEAN_TYPE: + n = GFC_DTYPE_LOGICAL; + break; + + case REAL_TYPE: + n = GFC_DTYPE_REAL; + break; + + case COMPLEX_TYPE: + n = GFC_DTYPE_COMPLEX; + break; + + /* Arrays have already been dealt with. */ + case RECORD_TYPE: + n = GFC_DTYPE_DERIVED; + break; + + case ARRAY_TYPE: + n = GFC_DTYPE_CHARACTER; + break; + + default: + abort (); + } + + assert (rank <= GFC_DTYPE_RANK_MASK); + size = TYPE_SIZE_UNIT (type); + + i = rank | (n << GFC_DTYPE_TYPE_SHIFT); + if (size && INTEGER_CST_P (size)) + { + if (tree_int_cst_lt (gfc_max_array_element_size, size)) + internal_error ("Array element size too big"); + + i += TREE_INT_CST_LOW (size) << GFC_DTYPE_SIZE_SHIFT; + } + dtype = build_int_2 (i, 0); + TREE_TYPE (dtype) = gfc_array_index_type; + + if (size && !INTEGER_CST_P (size)) + { + tmp = build_int_2 (GFC_DTYPE_SIZE_SHIFT, 0); + TREE_TYPE (tmp) = gfc_array_index_type; + tmp = fold (build (LSHIFT_EXPR, gfc_array_index_type, size, tmp)); + dtype = fold (build (PLUS_EXPR, gfc_array_index_type, tmp, dtype)); + } + /* If we don't know the size we leave it as zero. This should never happen + for anything that is actually used. */ + /* TODO: Check this is actually true, particularly when repacking + assumed size parameters. */ + + return dtype; +} + + +/* Build an array type for use without a descriptor. Valid values of packed + are 0=no, 1=partial, 2=full, 3=static. */ + +tree +gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, int packed) +{ + tree range; + tree type; + tree tmp; + int n; + int known_stride; + int known_offset; + mpz_t offset; + mpz_t stride; + mpz_t delta; + gfc_expr *expr; + + mpz_init_set_ui (offset, 0); + mpz_init_set_ui (stride, 1); + mpz_init (delta); + + /* We don't use build_array_type because this does not include include + lang-specific information (ie. the bounds of the array) when checking + for duplicates. */ + type = make_node (ARRAY_TYPE); + + GFC_ARRAY_TYPE_P (type) = 1; + TYPE_LANG_SPECIFIC (type) = (struct lang_type *) + ggc_alloc_cleared (sizeof (struct lang_type)); + + known_stride = (packed != 0); + known_offset = 1; + for (n = 0; n < as->rank; n++) + { + /* Fill in the stride and bound components of the type. */ + if (known_stride) + tmp = gfc_conv_mpz_to_tree (stride, gfc_index_integer_kind); + else + tmp = NULL_TREE; + GFC_TYPE_ARRAY_STRIDE (type, n) = tmp; + + expr = as->lower[n]; + if (expr->expr_type == EXPR_CONSTANT) + { + tmp = gfc_conv_mpz_to_tree (expr->value.integer, + gfc_index_integer_kind); + } + else + { + known_stride = 0; + tmp = NULL_TREE; + } + GFC_TYPE_ARRAY_LBOUND (type, n) = tmp; + + if (known_stride) + { + /* Calculate the offset. */ + mpz_mul (delta, stride, as->lower[n]->value.integer); + mpz_sub (offset, offset, delta); + } + else + known_offset = 0; + + expr = as->upper[n]; + if (expr && expr->expr_type == EXPR_CONSTANT) + { + tmp = gfc_conv_mpz_to_tree (expr->value.integer, + gfc_index_integer_kind); + } + else + { + tmp = NULL_TREE; + known_stride = 0; + } + GFC_TYPE_ARRAY_UBOUND (type, n) = tmp; + + if (known_stride) + { + /* Calculate the stride. */ + mpz_sub (delta, as->upper[n]->value.integer, + as->lower[n]->value.integer); + mpz_add_ui (delta, delta, 1); + mpz_mul (stride, stride, delta); + } + + /* Only the first stride is known for partial packed arrays. */ + if (packed < 2) + known_stride = 0; + } + + if (known_offset) + { + GFC_TYPE_ARRAY_OFFSET (type) = + gfc_conv_mpz_to_tree (offset, gfc_index_integer_kind); + } + else + GFC_TYPE_ARRAY_OFFSET (type) = NULL_TREE; + + if (known_stride) + { + GFC_TYPE_ARRAY_SIZE (type) = + gfc_conv_mpz_to_tree (stride, gfc_index_integer_kind); + } + else + GFC_TYPE_ARRAY_SIZE (type) = NULL_TREE; + + GFC_TYPE_ARRAY_DTYPE (type) = gfc_get_dtype (etype, as->rank); + GFC_TYPE_ARRAY_RANK (type) = as->rank; + range = build_range_type (gfc_array_index_type, integer_zero_node, + NULL_TREE); + /* TODO: use main type if it is unbounded. */ + GFC_TYPE_ARRAY_DATAPTR_TYPE (type) = + build_pointer_type (build_array_type (etype, range)); + + if (known_stride) + { + mpz_sub_ui (stride, stride, 1); + range = gfc_conv_mpz_to_tree (stride, gfc_index_integer_kind); + } + else + range = NULL_TREE; + + range = build_range_type (gfc_array_index_type, integer_zero_node, range); + TYPE_DOMAIN (type) = range; + + build_pointer_type (etype); + TREE_TYPE (type) = etype; + + layout_type (type); + + mpz_clear (offset); + mpz_clear (stride); + mpz_clear (delta); + + if (packed < 3 || !known_stride) + { + type = build_pointer_type (type); + GFC_ARRAY_TYPE_P (type) = 1; + TYPE_LANG_SPECIFIC (type) = TYPE_LANG_SPECIFIC (TREE_TYPE (type)); + } + return type; +} + + +/* Build an array (descriptor) type with given bounds. */ + +tree +gfc_get_array_type_bounds (tree etype, int dimen, tree * lbound, + tree * ubound, int packed) +{ + tree fat_type, fat_pointer_type; + tree fieldlist; + tree arraytype; + tree decl; + int n; + char name[8 + GFC_RANK_DIGITS + GFC_MAX_SYMBOL_LEN]; + const char *typename; + tree lower; + tree upper; + tree stride; + tree tmp; + + /* Build the type node. */ + fat_type = make_node (RECORD_TYPE); + GFC_DESCRIPTOR_TYPE_P (fat_type) = 1; + TYPE_LANG_SPECIFIC (fat_type) = (struct lang_type *) + ggc_alloc_cleared (sizeof (struct lang_type)); + GFC_TYPE_ARRAY_RANK (fat_type) = dimen; + GFC_TYPE_ARRAY_DTYPE (fat_type) = gfc_get_dtype (etype, dimen); + + tmp = TYPE_NAME (etype); + if (tmp && TREE_CODE (tmp) == TYPE_DECL) + tmp = DECL_NAME (tmp); + if (tmp) + typename = IDENTIFIER_POINTER (tmp); + else + typename = "unknown"; + + sprintf (name, "array" GFC_RANK_PRINTF_FORMAT "_%.*s", dimen, + GFC_MAX_SYMBOL_LEN, typename); + TYPE_NAME (fat_type) = get_identifier (name); + TYPE_PACKED (fat_type) = 0; + + fat_pointer_type = build_pointer_type (fat_type); + + /* Build an array descriptor record type. */ + if (packed != 0) + stride = integer_one_node; + else + stride = NULL_TREE; + + for (n = 0; n < dimen; n++) + { + GFC_TYPE_ARRAY_STRIDE (fat_type, n) = stride; + + if (lbound) + lower = lbound[n]; + else + lower = NULL_TREE; + + if (lower != NULL_TREE) + { + if (INTEGER_CST_P (lower)) + GFC_TYPE_ARRAY_LBOUND (fat_type, n) = lower; + else + lower = NULL_TREE; + } + + upper = ubound[n]; + if (upper != NULL_TREE) + { + if (INTEGER_CST_P (upper)) + GFC_TYPE_ARRAY_UBOUND (fat_type, n) = upper; + else + upper = NULL_TREE; + } + + if (upper != NULL_TREE && lower != NULL_TREE && stride != NULL_TREE) + { + tmp = fold (build (MINUS_EXPR, gfc_array_index_type, upper, lower)); + tmp = fold (build (PLUS_EXPR, gfc_array_index_type, tmp, + integer_one_node)); + stride = + fold (build (MULT_EXPR, gfc_array_index_type, tmp, stride)); + /* Check the folding worked. */ + assert (INTEGER_CST_P (stride)); + } + else + stride = NULL_TREE; + } + GFC_TYPE_ARRAY_SIZE (fat_type) = stride; + /* TODO: known offsets for descriptors. */ + GFC_TYPE_ARRAY_OFFSET (fat_type) = NULL_TREE; + + /* We define data as an unknown size array. Much better than doing + pointer arithmetic. */ + arraytype = + build_array_type (etype, + build_range_type (gfc_array_index_type, + integer_zero_node, NULL_TREE)); + arraytype = build_pointer_type (arraytype); + GFC_TYPE_ARRAY_DATAPTR_TYPE (fat_type) = arraytype; + + /* The pointer to the array data. */ + decl = build_decl (FIELD_DECL, get_identifier ("data"), arraytype); + + DECL_CONTEXT (decl) = fat_type; + /* Add the data member as the first element of the descriptor. */ + fieldlist = decl; + + /* Add the base component. */ + decl = build_decl (FIELD_DECL, get_identifier ("offset"), + gfc_array_index_type); + DECL_CONTEXT (decl) = fat_type; + fieldlist = chainon (fieldlist, decl); + + /* Add the dtype component. */ + decl = build_decl (FIELD_DECL, get_identifier ("dtype"), + gfc_array_index_type); + DECL_CONTEXT (decl) = fat_type; + fieldlist = chainon (fieldlist, decl); + + /* Build the array type for the stride and bound components. */ + arraytype = + build_array_type (gfc_get_desc_dim_type (), + build_range_type (gfc_array_index_type, + integer_zero_node, + gfc_rank_cst[dimen - 1])); + + decl = build_decl (FIELD_DECL, get_identifier ("dim"), arraytype); + DECL_CONTEXT (decl) = fat_type; + DECL_INITIAL (decl) = NULL_TREE; + fieldlist = chainon (fieldlist, decl); + + /* Finish off the type. */ + TYPE_FIELDS (fat_type) = fieldlist; + + gfc_finish_type (fat_type); + + return fat_type; +} + +/* Build a pointer type. This function is called from gfc_sym_type(). */ +static tree +gfc_build_pointer_type (gfc_symbol * sym, tree type) +{ + /* Array pointer types aren't actualy pointers. */ + if (sym->attr.dimension) + return type; + else + return build_pointer_type (type); +} + +/* Return the type for a symbol. Special handling is required for character + types to get the correct level of indirection. + For functions return the return type. + For subroutines return void_type_node. + */ +tree +gfc_sym_type (gfc_symbol * sym) +{ + tree type; + int byref; + + if (sym->attr.flavor == FL_PROCEDURE && !sym->attr.function) + return void_type_node; + + if (sym->backend_decl) + { + if (sym->attr.function) + return TREE_TYPE (TREE_TYPE (sym->backend_decl)); + else + return TREE_TYPE (sym->backend_decl); + } + + /* The frontend doesn't set all the attributes for a function with an + explicit result value, so we use that instead when present. */ + if (sym->attr.function && sym->result) + sym = sym->result; + + type = gfc_typenode_for_spec (&sym->ts); + + if (sym->attr.dummy && !sym->attr.function) + byref = 1; + else + byref = 0; + + if (sym->attr.dimension) + { + if (gfc_is_nodesc_array (sym)) + { + /* If this is a character argument of unknown length, just use the + base type. */ + if (sym->ts.type != BT_CHARACTER + || !(sym->attr.dummy || sym->attr.function || sym->attr.result) + || sym->ts.cl->backend_decl) + { + type = gfc_get_nodesc_array_type (type, sym->as, + byref ? 2 : 3); + byref = 0; + } + } + else + type = gfc_build_array_type (type, sym->as); + } + else + { + if (sym->attr.allocatable || sym->attr.pointer) + type = gfc_build_pointer_type (sym, type); + } + + /* We currently pass all parameters by reference. + See f95_get_function_decl. For dummy function parameters return the + function type. */ + if (byref) + type = build_reference_type (type); + + return (type); +} + +/* Layout and output debug info for a record type. */ +void +gfc_finish_type (tree type) +{ + tree decl; + + decl = build_decl (TYPE_DECL, NULL_TREE, type); + TYPE_STUB_DECL (type) = decl; + layout_type (type); + rest_of_type_compilation (type, 1); + rest_of_decl_compilation (decl, NULL, 1, 0); +} + +/* Add a field of given NAME and TYPE to the context of a UNION_TYPE + or RECORD_TYPE pointed to by STYPE. The new field is chained + to the fieldlist pointed to by FIELDLIST. + + Returns a pointer to the new field. */ +tree +gfc_add_field_to_struct (tree *fieldlist, tree context, + tree name, tree type) +{ + tree decl; + + decl = build_decl (FIELD_DECL, name, type); + + DECL_CONTEXT (decl) = context; + DECL_INITIAL (decl) = 0; + DECL_ALIGN (decl) = 0; + DECL_USER_ALIGN (decl) = 0; + TREE_CHAIN (decl) = NULL_TREE; + *fieldlist = chainon (*fieldlist, decl); + + return decl; +} + + +/* Build a tree node for a derived type. */ +static tree +gfc_get_derived_type (gfc_symbol * derived) +{ + tree typenode, field, field_type, fieldlist; + gfc_component *c; + + assert (derived && derived->attr.flavor == FL_DERIVED); + + /* derived->backend_decl != 0 means we saw it before, but its + component's backend_decl may have not been built. */ + if (derived->backend_decl) + { + /* Its component's backend_decl has been built. */ + if (TYPE_FIELDS (derived->backend_decl)) + return derived->backend_decl; + else + typenode = derived->backend_decl; + } + else + { + /* We see this derived type first time, so build the type node. */ + typenode = make_node (RECORD_TYPE); + TYPE_NAME (typenode) = get_identifier (derived->name); + TYPE_PACKED (typenode) = gfc_option.flag_pack_derived; + derived->backend_decl = typenode; + } + + /* Build the type member list. Install the newly created RECORD_TYPE + node as DECL_CONTEXT of each FIELD_DECL. */ + fieldlist = NULL_TREE; + for (c = derived->components; c; c = c->next) + { + if (c->ts.type == BT_DERIVED && c->pointer) + { + if (c->ts.derived->backend_decl) + field_type = c->ts.derived->backend_decl; + else + { + /* Build the type node. */ + field_type = make_node (RECORD_TYPE); + TYPE_NAME (field_type) = get_identifier (c->ts.derived->name); + TYPE_PACKED (field_type) = gfc_option.flag_pack_derived; + c->ts.derived->backend_decl = field_type; + } + } + else + { + if (c->ts.type == BT_CHARACTER) + { + /* Evaluate the string length. */ + gfc_conv_const_charlen (c->ts.cl); + assert (c->ts.cl->backend_decl); + } + + field_type = gfc_typenode_for_spec (&c->ts); + } + + /* This returns an array descriptor type. Initialisation may be + required. */ + if (c->dimension) + { + if (c->pointer) + { + /* Pointers to arrays aren't actualy pointer types. The + descriptors are seperate, but the data is common. */ + field_type = gfc_build_array_type (field_type, c->as); + } + else + field_type = gfc_get_nodesc_array_type (field_type, c->as, 3); + } + else if (c->pointer) + field_type = build_pointer_type (field_type); + + field = gfc_add_field_to_struct (&fieldlist, typenode, + get_identifier (c->name), + field_type); + + DECL_PACKED (field) |= TYPE_PACKED (typenode); + + assert (!c->backend_decl); + c->backend_decl = field; + } + + /* Now we have the final fieldlist. Record it, then lay out the + derived type, including the fields. */ + TYPE_FIELDS (typenode) = fieldlist; + + gfc_finish_type (typenode); + + derived->backend_decl = typenode; + + return typenode; +} + +int +gfc_return_by_reference (gfc_symbol * sym) +{ + if (!sym->attr.function) + return 0; + + assert (sym->attr.function); + + if (sym->result) + sym = sym->result; + + if (sym->attr.dimension) + return 1; + + if (sym->ts.type == BT_CHARACTER) + return 1; + + if (sym->ts.type == BT_DERIVED) + gfc_todo_error ("Returning derived types"); + /* Possibly return derived types by reference. */ + return 0; +} + +tree +gfc_get_function_type (gfc_symbol * sym) +{ + tree type; + tree typelist; + gfc_formal_arglist *f; + gfc_symbol *arg; + int nstr; + int alternate_return; + + /* Make sure this symbol is a function or a subroutine. */ + assert (sym->attr.flavor == FL_PROCEDURE); + + if (sym->backend_decl) + return TREE_TYPE (sym->backend_decl); + + nstr = 0; + alternate_return = 0; + typelist = NULL_TREE; + /* Some functions we use an extra parameter for the return value. */ + if (gfc_return_by_reference (sym)) + { + if (sym->result) + arg = sym->result; + else + arg = sym; + + if (arg->ts.type == BT_CHARACTER) + gfc_conv_const_charlen (arg->ts.cl); + + type = gfc_sym_type (arg); + if (arg->ts.type == BT_DERIVED + || arg->attr.dimension + || arg->ts.type == BT_CHARACTER) + type = build_reference_type (type); + + typelist = gfc_chainon_list (typelist, type); + if (arg->ts.type == BT_CHARACTER) + typelist = gfc_chainon_list (typelist, gfc_strlen_type_node); + } + + /* Build the argument types for the function */ + for (f = sym->formal; f; f = f->next) + { + arg = f->sym; + if (arg) + { + /* Evaluate constant character lengths here so that they can be + included in the type. */ + if (arg->ts.type == BT_CHARACTER) + gfc_conv_const_charlen (arg->ts.cl); + + if (arg->attr.flavor == FL_PROCEDURE) + { + type = gfc_get_function_type (arg); + type = build_pointer_type (type); + } + else + type = gfc_sym_type (arg); + + /* Parameter Passing Convention + + We currently pass all parameters by reference. + Parameters with INTENT(IN) could be passed by value. + The problem arises if a function is called via an implicit + prototype. In this situation the INTENT is not known. + For this reason all parameters to global functions must be + passed by reference. Passing by value would potentialy + generate bad code. Worse there would be no way of telling that + this code wad bad, except that it would give incorrect results. + + Contained procedures could pass by value as these are never + used without an explicit interface, and connot be passed as + actual parameters for a dummy procedure. + */ + if (arg->ts.type == BT_CHARACTER) + nstr++; + typelist = gfc_chainon_list (typelist, type); + } + else + { + if (sym->attr.subroutine) + alternate_return = 1; + } + } + + /* Add hidden string length parameters. */ + while (nstr--) + typelist = gfc_chainon_list (typelist, gfc_strlen_type_node); + + typelist = gfc_chainon_list (typelist, void_type_node); + + if (alternate_return) + type = integer_type_node; + else if (!sym->attr.function || gfc_return_by_reference (sym)) + type = void_type_node; + else + type = gfc_sym_type (sym); + + type = build_function_type (type, typelist); + + return type; +} + +/* Routines for getting integer type nodes */ + + +/* Return an integer type with BITS bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +tree +gfc_type_for_size (unsigned bits, int unsignedp) +{ + if (bits == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (bits == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (bits == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (bits == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (bits == TYPE_PRECISION (long_long_integer_type_node)) + return (unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node); +/*TODO: We currently don't initialise this... + if (bits == TYPE_PRECISION (widest_integer_literal_type_node)) + return (unsignedp ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node);*/ + + if (bits <= TYPE_PRECISION (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (bits <= TYPE_PRECISION (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (bits <= TYPE_PRECISION (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (bits <= TYPE_PRECISION (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + + return 0; +} + +/* Return a data type that has machine mode MODE. + If the mode is an integer, + then UNSIGNEDP selects between signed and unsigned types. */ + +tree +gfc_type_for_mode (enum machine_mode mode, int unsignedp) +{ + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (mode == TYPE_MODE (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsignedp ? long_long_unsigned_type_node : + long_long_integer_type_node; + +/*TODO: see above + if (mode == TYPE_MODE (widest_integer_literal_type_node)) + return unsignedp ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node; +*/ + + if (mode == QImode) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (mode == HImode) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (mode == SImode) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (mode == DImode) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (mode == TYPE_MODE (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + + 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; + + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) + return build_pointer_type (char_type_node); + + if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) + return build_pointer_type (integer_type_node); + +#ifdef VECTOR_MODE_SUPPORTED_P + if (VECTOR_MODE_SUPPORTED_P (mode)) + { + switch (mode) + { + case V16QImode: + return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node; + case V8HImode: + return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node; + case V4SImode: + return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node; + case V2DImode: + return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node; + case V2SImode: + return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node; + case V4HImode: + return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node; + case V8QImode: + return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node; + case V16SFmode: + return V16SF_type_node; + case V4SFmode: + return V4SF_type_node; + case V2SFmode: + return V2SF_type_node; + case V2DFmode: + return V2DF_type_node; + default: + break; + } + } +#endif + + return 0; +} + +/* Return an unsigned type the same as TYPE in other respects. */ +tree +gfc_unsigned_type (tree type) +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == signed_char_type_node || type1 == char_type_node) + return unsigned_char_type_node; + if (type1 == integer_type_node) + return unsigned_type_node; + if (type1 == short_integer_type_node) + return short_unsigned_type_node; + if (type1 == long_integer_type_node) + return long_unsigned_type_node; + if (type1 == long_long_integer_type_node) + return long_long_unsigned_type_node; +/*TODO :see others + if (type1 == widest_integer_literal_type_node) + return widest_unsigned_literal_type_node; +*/ +#if HOST_BITS_PER_WIDE_INT >= 64 + if (type1 == intTI_type_node) + return unsigned_intTI_type_node; +#endif + if (type1 == intDI_type_node) + return unsigned_intDI_type_node; + if (type1 == intSI_type_node) + return unsigned_intSI_type_node; + if (type1 == intHI_type_node) + return unsigned_intHI_type_node; + if (type1 == intQI_type_node) + return unsigned_intQI_type_node; + + return gfc_signed_or_unsigned_type (1, type); +} + +/* Return a signed type the same as TYPE in other respects. */ + +tree +gfc_signed_type (tree type) +{ + tree type1 = TYPE_MAIN_VARIANT (type); + if (type1 == unsigned_char_type_node || type1 == char_type_node) + return signed_char_type_node; + if (type1 == unsigned_type_node) + return integer_type_node; + if (type1 == short_unsigned_type_node) + return short_integer_type_node; + if (type1 == long_unsigned_type_node) + return long_integer_type_node; + if (type1 == long_long_unsigned_type_node) + return long_long_integer_type_node; +/*TODO: see others + if (type1 == widest_unsigned_literal_type_node) + return widest_integer_literal_type_node; +*/ +#if HOST_BITS_PER_WIDE_INT >= 64 + if (type1 == unsigned_intTI_type_node) + return intTI_type_node; +#endif + if (type1 == unsigned_intDI_type_node) + return intDI_type_node; + if (type1 == unsigned_intSI_type_node) + return intSI_type_node; + if (type1 == unsigned_intHI_type_node) + return intHI_type_node; + if (type1 == unsigned_intQI_type_node) + return intQI_type_node; + + return gfc_signed_or_unsigned_type (0, type); +} + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ + +tree +gfc_signed_or_unsigned_type (int unsignedp, tree type) +{ + if (!INTEGRAL_TYPE_P (type) || TYPE_UNSIGNED (type) == unsignedp) + return type; + + if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) + 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); +/*TODO: see others + if (TYPE_PRECISION (type) == TYPE_PRECISION (widest_integer_literal_type_node)) + return (unsignedp ? widest_unsigned_literal_type_node + : widest_integer_literal_type_node); +*/ +#if HOST_BITS_PER_WIDE_INT >= 64 + if (TYPE_PRECISION (type) == TYPE_PRECISION (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + if (TYPE_PRECISION (type) == TYPE_PRECISION (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + return type; +} + +#include "gt-fortran-trans-types.h" diff --git a/gcc/fortran/trans-types.h b/gcc/fortran/trans-types.h new file mode 100644 index 00000000000..b401499deb8 --- /dev/null +++ b/gcc/fortran/trans-types.h @@ -0,0 +1,143 @@ +/* Header for Fortran 95 types backend support. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + and Steven Bosscher + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef GFC_BACKEND_H +#define GFC_BACKEND_H + +enum +{ + F95_INT1_TYPE, + F95_INT2_TYPE, + F95_INT4_TYPE, + F95_INT8_TYPE, + F95_INT16_TYPE, + F95_REAL4_TYPE, + F95_REAL8_TYPE, + F95_REAl16_TYPE, + F95_COMPLEX4_TYPE, + F95_COMPLEX8_TYPE, + F95_COMPLEX16_TYPE, + F95_LOGICAL1_TYPE, + F95_LOGICAL2_TYPE, + F95_LOGICAL4_TYPE, + F95_LOGICAL8_TYPE, + F95_LOGICAL16_TYPE, + F95_CHARACTER1_TYPE, + NUM_F95_TYPES +}; + +#define GFC_DTYPE_RANK_MASK 0x07 +#define GFC_DTYPE_TYPE_SHIFT 3 +#define GFC_DTYPE_TYPE_MASK 0x38 +#define GFC_DTYPE_SIZE_SHIFT 6 + +enum +{ + GFC_DTYPE_UNKNOWN = 0, + GFC_DTYPE_INTEGER, + GFC_DTYPE_LOGICAL, + GFC_DTYPE_REAL, + GFC_DTYPE_COMPLEX, + GFC_DTYPE_DERIVED, + GFC_DTYPE_CHARACTER +}; + +extern GTY(()) tree gfc_type_nodes[NUM_F95_TYPES]; + +extern GTY(()) tree gfc_array_index_type; +extern GTY(()) tree ppvoid_type_node; +extern GTY(()) tree pvoid_type_node; +extern GTY(()) tree pchar_type_node; + +#define gfc_int1_type_node gfc_type_nodes[F95_INT1_TYPE] +#define gfc_int2_type_node gfc_type_nodes[F95_INT2_TYPE] +#define gfc_int4_type_node gfc_type_nodes[F95_INT4_TYPE] +#define gfc_int8_type_node gfc_type_nodes[F95_INT8_TYPE] +#define gfc_int16_type_node gfc_type_nodes[F95_INT16_TYPE] + +#define gfc_real4_type_node gfc_type_nodes[F95_REAL4_TYPE] +#define gfc_real8_type_node gfc_type_nodes[F95_REAL8_TYPE] +#define gfc_real16_type_node gfc_type_nodes[F95_REAL16_TYPE] + +#define gfc_complex4_type_node gfc_type_nodes[F95_COMPLEX4_TYPE] +#define gfc_complex8_type_node gfc_type_nodes[F95_COMPLEX8_TYPE] +#define gfc_complex16_type_node gfc_type_nodes[F95_COMPLEX16_TYPE] + +#define gfc_logical1_type_node gfc_type_nodes[F95_LOGICAL1_TYPE] +#define gfc_logical2_type_node gfc_type_nodes[F95_LOGICAL2_TYPE] +#define gfc_logical4_type_node gfc_type_nodes[F95_LOGICAL4_TYPE] +#define gfc_logical8_type_node gfc_type_nodes[F95_LOGICAL8_TYPE] +#define gfc_logical16_type_node gfc_type_nodes[F95_LOGICAL16_TYPE] + +#define gfc_character1_type_node gfc_type_nodes[F95_CHARACTER1_TYPE] + +#define gfc_strlen_kind 4 +#define gfc_strlen_type_node gfc_int4_type_node + +/* These C-specific types are used while building builtin function decls. + For now it doesn't really matter what these are defined to as we don't + need any of the builtins that use them. */ +#define intmax_type_node gfc_int8_type_node +#define string_type_node pchar_type_node +#define const_string_type_node pchar_type_node + +/* be-function.c */ +void gfc_convert_function_code (gfc_namespace *); + +/* trans-types.c */ +void gfc_init_types (void); + +tree gfc_get_int_type (int); +tree gfc_get_real_type (int); +tree gfc_get_complex_type (int); +tree gfc_get_logical_type (int); +tree gfc_get_character_type (int, gfc_charlen *); + +tree gfc_sym_type (gfc_symbol *); +tree gfc_typenode_for_spec (gfc_typespec *); + +tree gfc_get_function_type (gfc_symbol *); + +tree gfc_type_for_size (unsigned, int); +tree gfc_type_for_mode (enum machine_mode, int); +tree gfc_unsigned_type (tree); +tree gfc_signed_type (tree); +tree gfc_signed_or_unsigned_type (int, tree); + +tree gfc_get_element_type (tree); +tree gfc_get_array_type_bounds (tree, int, tree *, tree *, int); +tree gfc_get_nodesc_array_type (tree, gfc_array_spec *, int); + +/* Add a field of given name and type to a UNION_TYPE or RECORD_TYPE. */ +tree gfc_add_field_to_struct (tree *, tree, tree, tree); + +/* Layout and output debugging info for a type. */ +void gfc_finish_type (tree); + +/* Some functions have an extra parameter for the return value. */ +int gfc_return_by_reference (gfc_symbol *); + +/* Returns true if the array sym does not require a descriptor. */ +int gfc_is_nodesc_array (gfc_symbol *); + +#endif diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c new file mode 100644 index 00000000000..aed764d0a36 --- /dev/null +++ b/gcc/fortran/trans.c @@ -0,0 +1,662 @@ +/* Code translation -- generate GCC trees from gfc_code. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-simple.h" +#include +#include "ggc.h" +#include "toplev.h" +#include "defaults.h" +#include "real.h" +#include +#include +#include "gfortran.h" +#include "trans.h" +#include "trans-stmt.h" +#include "trans-array.h" +#include "trans-types.h" +#include "trans-const.h" + +/* Naming convention for backend interface code: + + gfc_trans_* translate gfc_code into STMT trees. + + gfc_conv_* expression conversion + + gfc_get_* get a backend tree representation of a decl or type */ + +static gfc_file *gfc_current_backend_file; + + +/* Advance along TREE_CHAIN n times. */ + +tree +gfc_advance_chain (tree t, int n) +{ + for (; n > 0; n--) + { + assert (t != NULL_TREE); + t = TREE_CHAIN (t); + } + return t; +} + + +/* Wrap a node in a TREE_LIST node and add it to the end of a list. */ + +tree +gfc_chainon_list (tree list, tree add) +{ + tree l; + + l = tree_cons (NULL_TREE, add, NULL_TREE); + + return chainon (list, l); +} + + +/* Strip off a legitimate source ending from the input + string NAME of length LEN. */ + +static inline void +remove_suffix (char *name, int len) +{ + int i; + + for (i = 2; i < 8 && len > i; i++) + { + if (name[len - i] == '.') + { + name[len - i] = '\0'; + break; + } + } +} + + +/* Creates a variable declaration with a given TYPE. */ + +tree +gfc_create_var_np (tree type, const char *prefix) +{ + return create_tmp_var_raw (type, prefix); +} + + +/* Like above, but also adds it to the current scope. */ + +tree +gfc_create_var (tree type, const char *prefix) +{ + tree tmp; + + tmp = gfc_create_var_np (type, prefix); + + pushdecl (tmp); + + return tmp; +} + + +/* If the an expression is not constant, evaluate it now. We assign the + result of the expression to an artificially created variable VAR, and + return a pointer to the VAR_DECL node for this variable. */ + +tree +gfc_evaluate_now (tree expr, stmtblock_t * pblock) +{ + tree var; + + if (TREE_CODE_CLASS (TREE_CODE (expr)) == 'c') + return expr; + + var = gfc_create_var (TREE_TYPE (expr), NULL); + gfc_add_modify_expr (pblock, var, expr); + + return var; +} + + +/* Build a MODIFY_EXPR node and add it to a given statement block PBLOCK. + A MODIFY_EXPR is an assignment: LHS <- RHS. */ + +void +gfc_add_modify_expr (stmtblock_t * pblock, tree lhs, tree rhs) +{ + tree tmp; + + tmp = fold (build_v (MODIFY_EXPR, lhs, rhs)); + gfc_add_expr_to_block (pblock, tmp); +} + + +/* Create a new scope/binding level and initialize a block. Care must be + taken when translating expessions as any temporaries will be placed in + the innermost scope. */ + +void +gfc_start_block (stmtblock_t * block) +{ + /* Start a new binding level. */ + pushlevel (0); + block->has_scope = 1; + + /* The block is empty. */ + block->head = NULL_TREE; +} + + +/* Initialize a block without creating a new scope. */ + +void +gfc_init_block (stmtblock_t * block) +{ + block->head = NULL_TREE; + block->has_scope = 0; +} + + +/* Sometimes we create a scope but it turns out that we don't actually + need it. This function merges the scope of BLOCK with its parent. + Only variable decls will be merged, you still need to add the code. */ + +void +gfc_merge_block_scope (stmtblock_t * block) +{ + tree decl; + tree next; + + assert (block->has_scope); + block->has_scope = 0; + + /* Remember the decls in this scope. */ + decl = getdecls (); + poplevel (0, 0, 0); + + /* Add them to the parent scope. */ + while (decl != NULL_TREE) + { + next = TREE_CHAIN (decl); + TREE_CHAIN (decl) = NULL_TREE; + + pushdecl (decl); + decl = next; + } +} + + +/* Finish a scope containing a block of statements. */ + +tree +gfc_finish_block (stmtblock_t * stmtblock) +{ + tree decl; + tree expr; + tree block; + + expr = rationalize_compound_expr (stmtblock->head); + stmtblock->head = NULL_TREE; + + if (stmtblock->has_scope) + { + decl = getdecls (); + + if (decl) + { + block = poplevel (1, 0, 0); + expr = build_v (BIND_EXPR, decl, expr, block); + } + else + poplevel (0, 0, 0); + } + + return expr; +} + + +/* Build an ADDR_EXPR and cast the result to TYPE. If TYPE is NULL, the + natural type is used. */ + +tree +gfc_build_addr_expr (tree type, tree t) +{ + tree base_type = TREE_TYPE (t); + tree natural_type; + + if (type && POINTER_TYPE_P (type) + && TREE_CODE (base_type) == ARRAY_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (type)) + == TYPE_MAIN_VARIANT (TREE_TYPE (base_type))) + natural_type = type; + else + natural_type = build_pointer_type (base_type); + + if (TREE_CODE (t) == INDIRECT_REF) + { + if (!type) + type = natural_type; + t = TREE_OPERAND (t, 0); + natural_type = TREE_TYPE (t); + } + else + { + if (DECL_P (t)) + TREE_ADDRESSABLE (t) = 1; + t = build1 (ADDR_EXPR, natural_type, t); + } + + if (type && natural_type != type) + t = convert (type, t); + + return t; +} + + +/* Build an INDIRECT_REF with its natural type. */ + +tree +gfc_build_indirect_ref (tree t) +{ + tree type = TREE_TYPE (t); + if (!POINTER_TYPE_P (type)) + abort (); + type = TREE_TYPE (type); + + if (TREE_CODE (t) == ADDR_EXPR) + return TREE_OPERAND (t, 0); + else + return build1 (INDIRECT_REF, type, t); +} + + +/* Build an ARRAY_REF with its natural type. */ + +tree +gfc_build_array_ref (tree base, tree offset) +{ + tree type = TREE_TYPE (base); + if (TREE_CODE (type) != ARRAY_TYPE) + abort (); + type = TREE_TYPE (type); + + if (DECL_P (base)) + TREE_ADDRESSABLE (base) = 1; + + return build (ARRAY_REF, type, base, offset); +} + + +/* Given a funcion declaration FNDECL and an argument list ARGLIST, + build a CALL_EXPR. */ + +tree +gfc_build_function_call (tree fndecl, tree arglist) +{ + tree fn; + tree call; + + fn = gfc_build_addr_expr (NULL, fndecl); + call = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fndecl)), fn, arglist, NULL); + TREE_SIDE_EFFECTS (call) = 1; + + return call; +} + + +/* Generate a runtime error if COND is true. */ + +void +gfc_trans_runtime_check (tree cond, tree msg, stmtblock_t * pblock) +{ + stmtblock_t block; + tree body; + tree tmp; + tree args; + + cond = fold (cond); + + if (integer_zerop (cond)) + return; + + /* The code to generate the error. */ + gfc_start_block (&block); + + assert (TREE_CODE (msg) == STRING_CST); + + TREE_USED (msg) = 1; + + tmp = gfc_build_addr_expr (pchar_type_node, msg); + args = gfc_chainon_list (NULL_TREE, tmp); + + tmp = gfc_build_addr_expr (pchar_type_node, gfc_strconst_current_filename); + args = gfc_chainon_list (args, tmp); + + tmp = build_int_2 (input_line, 0); + args = gfc_chainon_list (args, tmp); + + tmp = gfc_build_function_call (gfor_fndecl_runtime_error, args); + gfc_add_expr_to_block (&block, tmp); + + body = gfc_finish_block (&block); + + if (integer_onep (cond)) + { + gfc_add_expr_to_block (pblock, body); + } + else + { + /* Tell the compiler that this isn't likley. */ + tmp = gfc_chainon_list (NULL_TREE, cond); + tmp = gfc_chainon_list (tmp, integer_zero_node); + cond = gfc_build_function_call (built_in_decls[BUILT_IN_EXPECT], tmp); + + tmp = build_v (COND_EXPR, cond, body, build_empty_stmt ()); + gfc_add_expr_to_block (pblock, tmp); + } +} + + +/* Add a statement to a bock. */ + +void +gfc_add_expr_to_block (stmtblock_t * block, tree expr) +{ + assert (block); + + if (expr == NULL_TREE || IS_EMPTY_STMT (expr)) + return; + + expr = fold (expr); + if (block->head) + block->head = build_v (COMPOUND_EXPR, block->head, expr); + else + block->head = expr; +} + + +/* Add a block the end of a block. */ + +void +gfc_add_block_to_block (stmtblock_t * block, stmtblock_t * append) +{ + assert (append); + assert (!append->has_scope); + + gfc_add_expr_to_block (block, append->head); + append->head = NULL_TREE; +} + + +/* Get the current locus. The structure may not be complete, and should + only be used with gfc_set_current_locus. */ + +void +gfc_get_backend_locus (locus * loc) +{ + loc->line = input_line - 1; + loc->file = gfc_current_backend_file; +} + + +/* Set the current locus. */ + +void +gfc_set_backend_locus (locus * loc) +{ + input_line = loc->line + 1; + gfc_current_backend_file = loc->file; + input_filename = loc->file->filename; +} + + +/* Translate an executable statement. */ + +tree +gfc_trans_code (gfc_code * code) +{ + stmtblock_t block; + tree res; + + if (!code) + return build_empty_stmt (); + + gfc_start_block (&block); + + /* Translate statements one by one to SIMPLE trees until we reach + the end of this gfc_code branch. */ + for (; code; code = code->next) + { + gfc_set_backend_locus (&code->loc); + + if (code->here != 0) + { + res = gfc_trans_label_here (code); + gfc_add_expr_to_block (&block, res); + } + + switch (code->op) + { + case EXEC_NOP: + res = NULL_TREE; + break; + + case EXEC_ASSIGN: + res = gfc_trans_assign (code); + break; + + case EXEC_LABEL_ASSIGN: + res = gfc_trans_label_assign (code); + break; + + case EXEC_POINTER_ASSIGN: + res = gfc_trans_pointer_assign (code); + break; + + case EXEC_CONTINUE: + res = NULL_TREE; + break; + + case EXEC_CYCLE: + res = gfc_trans_cycle (code); + break; + + case EXEC_EXIT: + res = gfc_trans_exit (code); + break; + + case EXEC_GOTO: + res = gfc_trans_goto (code); + break; + + case EXEC_PAUSE: + res = gfc_trans_pause (code); + break; + + case EXEC_STOP: + res = gfc_trans_stop (code); + break; + + case EXEC_CALL: + res = gfc_trans_call (code); + break; + + case EXEC_RETURN: + res = gfc_trans_return (code); + break; + + case EXEC_IF: + res = gfc_trans_if (code); + break; + + case EXEC_ARITHMETIC_IF: + res = gfc_trans_arithmetic_if (code); + break; + + case EXEC_DO: + res = gfc_trans_do (code); + break; + + case EXEC_DO_WHILE: + res = gfc_trans_do_while (code); + break; + + case EXEC_SELECT: + res = gfc_trans_select (code); + break; + + case EXEC_FORALL: + res = gfc_trans_forall (code); + break; + + case EXEC_WHERE: + res = gfc_trans_where (code); + break; + + case EXEC_ALLOCATE: + res = gfc_trans_allocate (code); + break; + + case EXEC_DEALLOCATE: + res = gfc_trans_deallocate (code); + break; + + case EXEC_OPEN: + res = gfc_trans_open (code); + break; + + case EXEC_CLOSE: + res = gfc_trans_close (code); + break; + + case EXEC_READ: + res = gfc_trans_read (code); + break; + + case EXEC_WRITE: + res = gfc_trans_write (code); + break; + + case EXEC_IOLENGTH: + res = gfc_trans_iolength (code); + break; + + case EXEC_BACKSPACE: + res = gfc_trans_backspace (code); + break; + + case EXEC_ENDFILE: + res = gfc_trans_endfile (code); + break; + + case EXEC_INQUIRE: + res = gfc_trans_inquire (code); + break; + + case EXEC_REWIND: + res = gfc_trans_rewind (code); + break; + + case EXEC_TRANSFER: + res = gfc_trans_transfer (code); + break; + + case EXEC_DT_END: + res = gfc_trans_dt_end (code); + break; + + default: + internal_error ("gfc_trans_code(): Bad statement code"); + } + + if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) + { + annotate_with_locus (res, input_location); + /* Add the new statemment to the block. */ + gfc_add_expr_to_block (&block, res); + } + } + + /* Return the finished block. */ + return gfc_finish_block (&block); +} + + +/* This function is called after a complete program unit has been parsed + and resolved. */ + +void +gfc_generate_code (gfc_namespace * ns) +{ + gfc_symbol *main_program = NULL; + symbol_attribute attr; + + /* Main program subroutine. */ + if (!ns->proc_name) + { + /* Lots of things get upset if a subroutine doesn't have a symbol, so we + make one now. Hopefully we've set all the required fields. */ + gfc_get_symbol ("MAIN__", ns, &main_program); + gfc_clear_attr (&attr); + attr.flavor = FL_PROCEDURE; + attr.proc = PROC_UNKNOWN; + attr.subroutine = 1; + attr.access = ACCESS_PUBLIC; + main_program->attr = attr; + ns->proc_name = main_program; + gfc_commit_symbols (); + } + + gfc_generate_function_code (ns); +} + + +/* This function is called after a complete module has been parsed + and resolved. */ + +void +gfc_generate_module_code (gfc_namespace * ns) +{ + gfc_namespace *n; + + gfc_generate_module_vars (ns); + + /* We need to generate all module function prototypes first, to allow + sibling calls. */ + for (n = ns->contained; n; n = n->sibling) + { + if (!n->proc_name) + continue; + + gfc_build_function_decl (n->proc_name); + } + + for (n = ns->contained; n; n = n->sibling) + { + if (!n->proc_name) + continue; + + gfc_generate_function_code (n); + } +} + diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h new file mode 100644 index 00000000000..d5b31376e81 --- /dev/null +++ b/gcc/fortran/trans.h @@ -0,0 +1,534 @@ +/* Header for code translation functions + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of GNU G95. + +GNU G95 is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU G95 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU G95; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef GFC_TRANS_H +#define GFC_TRANS_H + +/* Mangled symbols take the form __module__name. */ +#define GFC_MAX_MANGLED_SYMBOL_LEN (GFC_MAX_SYMBOL_LEN*2+4) + +/* Struct for holding a block of statements. It should be treated as an + opaque entity and not modified directly. This allows us to change the + underlying representation of statement lists. */ +typedef struct +{ + tree head; + int has_scope:1; +} +stmtblock_t; + +/* a simplified expresson */ +typedef struct gfc_se +{ + /* Code blocks to be executed before and after using the value. */ + stmtblock_t pre; + stmtblock_t post; + + /* the result of the expression */ + tree expr; + + /* The length of a character string value. */ + tree string_length; + + /* If set gfc_conv_variable will return an expression for the array + descriptor. When set, want_pointer should also be set. + If not set scalarizing variables will be substituted. */ + unsigned descriptor_only:1; + + /* When this is set gfc_conv_expr returns the address of a variable. Only + applies to EXPR_VARIABLE nodes. + Also used by gfc_conv_array_parameter. When set this indicates a pointer + to the descriptor should be returned, rather than the descriptor itself. + */ + unsigned want_pointer:1; + + /* An array function call returning without a temporary. Also used for array + pointer assignments. */ + unsigned direct_byref:1; + + /* Ignore absent optional arguments. Used for some intrinsics. */ + unsigned ignore_optional:1; + + /* Scalarization parameters. */ + struct gfc_se *parent; + struct gfc_ss *ss; + struct gfc_loopinfo *loop; +} +gfc_se; + + +/* Scalarisation State chain. Created by walking an expression tree before + creating the scalarization loops. Then passed as part of a gfc_se structure + to translate the expression inside the loop. Note that these chains are + terminated by gfc_se_terminator, not NULL. A NULL pointer in a gfc_se + indicates to gfc_conv_* that this is a scalar expression. + Note that some member arrays correspond to scalarizer rank and others + are the variable rank. */ + +typedef struct gfc_ss_info +{ + int dimen; + /* The ref that holds information on this section. */ + gfc_ref *ref; + /* The descriptor of this array. */ + tree descriptor; + /* holds the pointer to the data array. */ + tree data; + /* To move some of the array index calculation out of the innermost loop. */ + tree offset; + tree saved_offset; + tree stride0; + /* Holds the SS for a subscript. Indexed by actual dimension. */ + struct gfc_ss *subscript[GFC_MAX_DIMENSIONS]; + + /* stride and delta are used to access this inside a scalarization loop. + start is used in the calculation of these. Indexed by scalarizer + dimension. */ + tree start[GFC_MAX_DIMENSIONS]; + tree stride[GFC_MAX_DIMENSIONS]; + tree delta[GFC_MAX_DIMENSIONS]; + + /* Translation from scalariser dimensions to actual dimensions. + actual = dim[scalarizer] */ + int dim[GFC_MAX_DIMENSIONS]; +} +gfc_ss_info; + +typedef enum +{ + /* A scalar value. This will be evaluated before entering the + scalarization loop. */ + GFC_SS_SCALAR, + + /* Like GFC_SS_SCALAR except it evaluates a pointer the the expression. + Used for elemental function parameters. */ + GFC_SS_REFERENCE, + + /* An array section. Scalarization indices will be substituted during + expression translation. */ + GFC_SS_SECTION, + + /* A non-elemental function call returning an array. The call is executed + before entering the scalarization loop, storing the result in a + temporary. This temporary is then used inside the scalarization loop. + Simple assignments, eg. a(:) = fn() are handles without a temporary + as a special case. */ + GFC_SS_FUNCTION, + + /* An array constructor. The current implementation is sub-optimal in + many cases. It allocated a temporary, assigns the values to it, then + uses this temporary inside the scalarization loop. */ + GFC_SS_CONSTRUCTOR, + + /* A vector subscript. Only used as the SS chain for a subscript. + Similar int format to a GFC_SS_SECTION. */ + GFC_SS_VECTOR, + + /* A temporary array allocated by the scalarizer. Its rank can be less + than that of the assignment expression. */ + GFC_SS_TEMP, + + /* An intrinsic function call. Many intrinsic functions which map directly + to library calls are created as GFC_SS_FUNCTION nodes. */ + GFC_SS_INTRINSIC +} +gfc_ss_type; + +/* SS structures can only belong to a single loopinfo. They must be added + otherwise they will not get freed. */ +typedef struct gfc_ss +{ + gfc_ss_type type; + gfc_expr *expr; + union + { + /* If type is GFC_SS_SCALAR or GFC_SS_REFERENCE. */ + struct + { + tree expr; + tree string_length; + } + scalar; + + /* GFC_SS_TEMP. */ + struct + { + /* The rank of the temporary. May be less than the rank of the + assigned expression. */ + int dimen; + tree type; + tree string_length; + } + temp; + /* All other types. */ + gfc_ss_info info; + } + data; + + /* All the SS in a loop and linked through loop_chain. The SS for an + expression are linked by the next pointer. */ + struct gfc_ss *loop_chain; + struct gfc_ss *next; + + /* This is used by assignments requiring teporaries. The bits specify which + loops the terms appear in. This will be 1 for the RHS expressions, + 2 for the LHS expressions, and 3(=1|2) for the temporary. */ + unsigned useflags:2; +} +gfc_ss; +#define gfc_get_ss() gfc_getmem(sizeof(gfc_ss)) + +/* The contents of this aren't actualy used. A NULL SS chain indicates a + scalar expression, so this pointer is used to terminate SS chains. */ +extern gfc_ss * const gfc_ss_terminator; + +/* Holds information about an expression while it is being scalarized. */ +typedef struct gfc_loopinfo +{ + stmtblock_t pre; + stmtblock_t post; + + int dimen; + + /* All the SS involved with this loop. */ + gfc_ss *ss; + /* The SS describing the teporary used in an assignment. */ + gfc_ss *temp_ss; + + /* The scalarization loop index variables. */ + tree loopvar[GFC_MAX_DIMENSIONS]; + + /* The bounds of the scalarization loops. */ + tree from[GFC_MAX_DIMENSIONS]; + tree to[GFC_MAX_DIMENSIONS]; + gfc_ss *specloop[GFC_MAX_DIMENSIONS]; + + /* The code member contains the code for the body of the next outer loop. */ + stmtblock_t code[GFC_MAX_DIMENSIONS]; + + /* Order in which the dimensions should be looped, innermost first. */ + int order[GFC_MAX_DIMENSIONS]; + + /* The number of dimensions for which a temporary is used. */ + int temp_dim; + + /* If set we don't need the loop variables. */ + unsigned array_parameter:1; +} +gfc_loopinfo; + +/* Advance the SS chain to the next term. */ +void gfc_advance_se_ss_chain (gfc_se *); + +/* Call this to initialise a gfc_se structure before use + first parameter is structure to initialise, second is + parent to get scalarization data from, or NULL. */ +void gfc_init_se (gfc_se *, gfc_se *); + +/* Create an artificial variable decl and add it to the current scope. */ +tree gfc_create_var (tree, const char *); +/* Like above but doesn't add it to the current scope. */ +tree gfc_create_var_np (tree, const char *); + +/* Store the result of an expression in a temp variable so it can be used + repeatedly even if the original changes */ +void gfc_make_safe_expr (gfc_se * se); + +/* Makes sure se is suitable for passing as a function string parameter. */ +void gfc_conv_string_parameter (gfc_se * se); + +/* Add an item to the end of TREE_LIST. */ +tree gfc_chainon_list (tree, tree); + +/* When using the gfc_conv_* make sure you understand what they do, ie. + when a POST chain may be created, and what the retured expression may be + used for. Note that character strings have special handling. This + should not be a problem as most statements/operations only deal with + numeric/logical types. */ + +/* Entry point for expression translation. */ +void gfc_conv_expr (gfc_se * se, gfc_expr * expr); +/* Like gfc_conv_expr, but the POST block is guaranteed to be empty for + numeric expressions. */ +void gfc_conv_expr_val (gfc_se * se, gfc_expr * expr); +/* Like gfc_conv_expr_val, but the value is also suitable for use in the lhs of + an assignment. */ +void gfc_conv_expr_lhs (gfc_se * se, gfc_expr * expr); +/* Converts an expression so that it can be passed be reference. */ +void gfc_conv_expr_reference (gfc_se * se, gfc_expr *); +/* Equivalent to convert(type, gfc_conv_expr_val(se, expr)). */ +void gfc_conv_expr_type (gfc_se * se, gfc_expr *, tree); +/* If the value is not constant, Create a temporary and copy the value. */ +tree gfc_evaluate_now (tree, stmtblock_t *); + +/* Intrinsic function handling. */ +void gfc_conv_intrinsic_function (gfc_se *, gfc_expr *); + +/* Does an intrinsic map directly to an external library call. */ +int gfc_is_intrinsic_libcall (gfc_expr *); + +/* Also used to CALL subroutines. */ +void gfc_conv_function_call (gfc_se *, gfc_symbol *, gfc_actual_arglist *); +/* gfc_trans_* shouldn't call push/poplevel, use gfc_push/pop_scope */ + +/* Generate code for a scalar assignment. */ +tree gfc_trans_scalar_assign (gfc_se *, gfc_se *, bt); + +/* Translate COMMON blocks. */ +void gfc_trans_common (gfc_namespace *); + +/* Translate a derived type constructor. */ +void gfc_conv_structure (gfc_se *, gfc_expr *, int); + +/* Return an expression which determines if a dummy parameter is present. */ +tree gfc_conv_expr_present (gfc_symbol *); + +/* Generate code to allocate a string temporary. */ +tree gfc_conv_string_tmp (gfc_se *, tree, tree); +/* Initialize a string length variable. */ +void gfc_trans_init_string_length (gfc_charlen *, stmtblock_t *); + +/* Add an expression to the end of a block. */ +void gfc_add_expr_to_block (stmtblock_t *, tree); +/* Add a block to the end of a block. */ +void gfc_add_block_to_block (stmtblock_t *, stmtblock_t *); +/* Add a MODIFY_EXPR to a block. */ +void gfc_add_modify_expr (stmtblock_t *, tree, tree); + +/* Initialize a statement block. */ +void gfc_init_block (stmtblock_t *); +/* Start a new satement block. Like gfc_init_block but also starts a new + variable scope. */ +void gfc_start_block (stmtblock_t *); +/* Finish a statement block. Also closes the scope if the block was created + with gfc_start_block. */ +tree gfc_finish_block (stmtblock_t *); +/* Merge the scope of a block with its parent. */ +void gfc_merge_block_scope (stmtblock_t * block); + +/* Return the backend label decl. */ +tree gfc_get_label_decl (gfc_st_label *); + +/* Return the decl for an external function. */ +tree gfc_get_extern_function_decl (gfc_symbol *); + +/* Return the decl for a function. */ +tree gfc_get_function_decl (gfc_symbol *); + +/* Build a CALL_EXPR. */ +tree gfc_build_function_call (tree, tree); + +/* Build an ADDR_EXPR. */ +tree gfc_build_addr_expr (tree, tree); + +/* Build an INDIRECT_REF. */ +tree gfc_build_indirect_ref (tree); + +/* Build an ARRAY_REF. */ +tree gfc_build_array_ref (tree, tree); + +/* Creates an label. Decl is artificial if label_id == NULL_TREE. */ +tree gfc_build_label_decl (tree); + +/* Return the decl used to hold the function return value. + Do not use if the function has an explicit result variable. */ +tree gfc_get_fake_result_decl (gfc_symbol *); + +/* Get the return label for the current function. */ +tree gfc_get_return_label (void); + +/* Add a decl to the binding level for the current function. */ +void gfc_add_decl_to_function (tree); + +/* Make prototypes for runtime library functions. */ +void gfc_build_builtin_function_decls (void); + +/* Return the variable decl for a symbol. */ +tree gfc_get_symbol_decl (gfc_symbol *); + +/* Allocate the lang-spcific part of a decl node. */ +void gfc_allocate_lang_decl (tree); + +/* Advance along a TREE_CHAIN. */ +tree gfc_advance_chain (tree, int); + +/* Create a decl for a function. */ +void gfc_build_function_decl (gfc_symbol *); +/* Generate the code for a function. */ +void gfc_generate_function_code (gfc_namespace *); +/* Output a decl for a module variable. */ +void gfc_generate_module_vars (gfc_namespace *); + +/* Get and set the current location. */ +void gfc_set_backend_locus (locus *); +void gfc_get_backend_locus (locus *); + +/* Handle static constructor functions. */ +extern GTY(()) tree gfc_static_ctors; +void gfc_generate_constructors (void); + +/* Generate a runtime error check. */ +void gfc_trans_runtime_check (tree, tree, stmtblock_t *); + +/* Generate code for an assigment, includes scalarization. */ +tree gfc_trans_assignment (gfc_expr *, gfc_expr *); + +/* Generate code for an pointer assignment. */ +tree gfc_trans_pointer_assignment (gfc_expr *, gfc_expr *); + +/* Initialize function decls for library functions. */ +void gfc_build_intrinsic_lib_fndecls (void); +/* Create function decls for IO library functions. */ +void gfc_build_io_library_fndecls (void); +/* Build a function decl for a library function. */ +tree gfc_build_library_function_decl (tree, tree, int, ...); + +/* somewhere! */ +tree pushdecl (tree); +tree pushdecl_top_level (tree); +void pushlevel (int); +tree poplevel (int, int, int); +tree getdecls (void); +tree gfc_truthvalue_conversion (tree); + +/* Runtime library function decls. */ +extern GTY(()) tree gfor_fndecl_internal_malloc; +extern GTY(()) tree gfor_fndecl_internal_malloc64; +extern GTY(()) tree gfor_fndecl_internal_free; +extern GTY(()) tree gfor_fndecl_allocate; +extern GTY(()) tree gfor_fndecl_allocate64; +extern GTY(()) tree gfor_fndecl_deallocate; +extern GTY(()) tree gfor_fndecl_pause_numeric; +extern GTY(()) tree gfor_fndecl_pause_string; +extern GTY(()) tree gfor_fndecl_stop_numeric; +extern GTY(()) tree gfor_fndecl_stop_string; +extern GTY(()) tree gfor_fndecl_select_string; +extern GTY(()) tree gfor_fndecl_runtime_error; +extern GTY(()) tree gfor_fndecl_in_pack; +extern GTY(()) tree gfor_fndecl_in_unpack; +extern GTY(()) tree gfor_fndecl_associated; + +/* Math functions. Many other math functions are handled in + trans-intrinsic.c. */ +extern GTY(()) tree gfor_fndecl_math_powf; +extern GTY(()) tree gfor_fndecl_math_pow; +extern GTY(()) tree gfor_fndecl_math_cpowf; +extern GTY(()) tree gfor_fndecl_math_cpow; +extern GTY(()) tree gfor_fndecl_math_cabsf; +extern GTY(()) tree gfor_fndecl_math_cabs; +extern GTY(()) tree gfor_fndecl_math_sign4; +extern GTY(()) tree gfor_fndecl_math_sign8; +extern GTY(()) tree gfor_fndecl_math_ishftc4; +extern GTY(()) tree gfor_fndecl_math_ishftc8; +extern GTY(()) tree gfor_fndecl_math_exponent4; +extern GTY(()) tree gfor_fndecl_math_exponent8; + +/* String functions. */ +extern GTY(()) tree gfor_fndecl_copy_string; +extern GTY(()) tree gfor_fndecl_compare_string; +extern GTY(()) tree gfor_fndecl_concat_string; +extern GTY(()) tree gfor_fndecl_string_len_trim; +extern GTY(()) tree gfor_fndecl_string_index; +extern GTY(()) tree gfor_fndecl_string_scan; +extern GTY(()) tree gfor_fndecl_string_verify; +extern GTY(()) tree gfor_fndecl_string_trim; +extern GTY(()) tree gfor_fndecl_string_repeat; +extern GTY(()) tree gfor_fndecl_adjustl; +extern GTY(()) tree gfor_fndecl_adjustr; + +/* Other misc. runtime library functions. */ +extern GTY(()) tree gfor_fndecl_size0; +extern GTY(()) tree gfor_fndecl_size1; + +/* Implemented in FORTRAN. */ +extern GTY(()) tree gfor_fndecl_si_kind; +extern GTY(()) tree gfor_fndecl_sr_kind; + + +/* True if node is an integer constant. */ +#define INTEGER_CST_P(node) (TREE_CODE(node) == INTEGER_CST) + +/* G95-specific declaration information. */ + +/* Array types only. */ +struct lang_type GTY(()) +{ + int rank; + tree lbound[GFC_MAX_DIMENSIONS]; + tree ubound[GFC_MAX_DIMENSIONS]; + tree stride[GFC_MAX_DIMENSIONS]; + tree size; + tree offset; + tree dtype; + tree dataptr_type; +}; + +struct lang_decl GTY(()) +{ + /* Dummy variables. */ + tree saved_descriptor; + /* Assigned integer nodes. Stringlength is the IO format string's length. + Addr is the address of the string or the target label. Stringlength is + initialized to -2 and assiged to -1 when addr is assigned to the + address of target label. */ + tree stringlen; + tree addr; +}; + + +#define GFC_DECL_ASSIGN_ADDR(node) DECL_LANG_SPECIFIC(node)->addr +#define GFC_DECL_STRING_LEN(node) DECL_LANG_SPECIFIC(node)->stringlen +#define GFC_DECL_SAVED_DESCRIPTOR(node) \ + (DECL_LANG_SPECIFIC(node)->saved_descriptor) +#define GFC_DECL_PACKED_ARRAY(node) DECL_LANG_FLAG_0(node) +#define GFC_DECL_PARTIAL_PACKED_ARRAY(node) DECL_LANG_FLAG_1(node) +#define GFC_DECL_ASSIGN(node) DECL_LANG_FLAG_2(node) + +/* An array descriptor. */ +#define GFC_DESCRIPTOR_TYPE_P(node) TYPE_LANG_FLAG_1(node) +/* An array without a descriptor. */ +#define GFC_ARRAY_TYPE_P(node) TYPE_LANG_FLAG_2(node) +/* The GFC_TYPE_ARRAY_* members are present in both descriptor and + descriptorless array types. */ +#define GFC_TYPE_ARRAY_LBOUND(node, dim) \ + (TYPE_LANG_SPECIFIC(node)->lbound[dim]) +#define GFC_TYPE_ARRAY_UBOUND(node, dim) \ + (TYPE_LANG_SPECIFIC(node)->ubound[dim]) +#define GFC_TYPE_ARRAY_STRIDE(node, dim) \ + (TYPE_LANG_SPECIFIC(node)->stride[dim]) +#define GFC_TYPE_ARRAY_RANK(node) (TYPE_LANG_SPECIFIC(node)->rank) +#define GFC_TYPE_ARRAY_SIZE(node) (TYPE_LANG_SPECIFIC(node)->size) +#define GFC_TYPE_ARRAY_OFFSET(node) (TYPE_LANG_SPECIFIC(node)->offset) +#define GFC_TYPE_ARRAY_DTYPE(node) (TYPE_LANG_SPECIFIC(node)->dtype) +#define GFC_TYPE_ARRAY_DATAPTR_TYPE(node) \ + (TYPE_LANG_SPECIFIC(node)->dataptr_type) + +/* I changed this from sorry(...) because it should not return. */ +/* TODO: Remove gfc_todo_error before releasing version 1.0. */ +#define gfc_todo_error(args...) fatal_error("gfc_todo: Not Implemented: " args) + +/* Build an expression with void type. */ +#define build1_v(code, arg) build(code, void_type_node, arg) +#define build_v(code, args...) build(code, void_type_node, args) + +/* flag for alternative return labels. */ +extern int has_alternate_specifier; /* for caller */ +#endif /* GFC_TRANS_H */ diff --git a/gcc/function.c b/gcc/function.c index 8ce5ef5ef79..322227bc495 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -64,10 +64,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "target.h" -#ifndef TRAMPOLINE_ALIGNMENT -#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY -#endif - #ifndef LOCAL_ALIGNMENT #define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT #endif @@ -132,9 +128,6 @@ int current_function_uses_only_leaf_regs; post-instantiation libcalls. */ int virtuals_instantiated; -/* Nonzero if at least one trampoline has been created. */ -int trampolines_created; - /* Assign unique numbers to labels generated for profiling, debugging, etc. */ static GTY(()) int funcdef_no; @@ -142,9 +135,6 @@ static GTY(()) int funcdef_no; target specific, per-function data structures. */ struct machine_function * (*init_machine_status) (void); -/* The FUNCTION_DECL for an inline function currently being expanded. */ -tree inline_function_decl; - /* The currently compiled function. */ struct function *cfun = 0; @@ -256,16 +246,11 @@ static void instantiate_decls_1 (tree, int); static void instantiate_decl (rtx, HOST_WIDE_INT, int); static rtx instantiate_new_reg (rtx, HOST_WIDE_INT *); static int instantiate_virtual_regs_1 (rtx *, rtx, int); -static void delete_handlers (void); static void pad_to_arg_alignment (struct args_size *, int, struct args_size *); static void pad_below (struct args_size *, enum machine_mode, tree); -static rtx round_trampoline_addr (rtx); -static rtx adjust_trampoline_addr (rtx); static tree *identify_blocks_1 (rtx, tree *, tree *, tree *); -static void reorder_blocks_0 (tree); static void reorder_blocks_1 (rtx, tree, varray_type *); static void reorder_fix_fragments (tree); -static tree blocks_nreverse (tree); static int all_blocks (tree, tree *); static tree *get_block_vector (tree, int *); extern tree debug_find_var_in_block_tree (tree, tree); @@ -446,10 +431,7 @@ free_after_compilation (struct function *f) f->arg_offset_rtx = NULL; f->return_rtx = NULL; f->internal_arg_pointer = NULL; - f->x_nonlocal_labels = NULL; - f->x_nonlocal_goto_handler_slots = NULL; f->x_nonlocal_goto_handler_labels = NULL; - f->x_nonlocal_goto_stack_level = NULL; f->x_cleanup_label = NULL; f->x_return_label = NULL; f->x_naked_return_label = NULL; @@ -461,9 +443,6 @@ free_after_compilation (struct function *f) f->x_tail_recursion_label = NULL; f->x_tail_recursion_reentry = NULL; f->x_arg_pointer_save_area = NULL; - f->x_clobber_return_insn = NULL; - f->x_context_display = NULL; - f->x_trampoline_list = NULL; f->x_parm_birth_insn = NULL; f->x_last_parm_insn = NULL; f->x_parm_reg_stack_loc = NULL; @@ -1323,7 +1302,7 @@ put_var_into_stack (tree decl, int rescan) because it might not be in any active function. FIXME: Is that really supposed to happen? It does in ObjC at least. */ - if (context != current_function_decl && context != inline_function_decl) + if (context != current_function_decl) for (function = outer_function_chain; function; function = function->outer) if (function->decl == context) break; @@ -4168,59 +4147,6 @@ instantiate_virtual_regs_1 (rtx *loc, rtx object, int extra_insns) return 1; } -/* Optimization: assuming this function does not receive nonlocal gotos, - delete the handlers for such, as well as the insns to establish - and disestablish them. */ - -static void -delete_handlers (void) -{ - rtx insn; - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - /* Delete the handler by turning off the flag that would - prevent jump_optimize from deleting it. - Also permit deletion of the nonlocal labels themselves - if nothing local refers to them. */ - if (GET_CODE (insn) == CODE_LABEL) - { - tree t, last_t; - - LABEL_PRESERVE_P (insn) = 0; - - /* Remove it from the nonlocal_label list, to avoid confusing - flow. */ - for (t = nonlocal_labels, last_t = 0; t; - last_t = t, t = TREE_CHAIN (t)) - if (DECL_RTL (TREE_VALUE (t)) == insn) - break; - if (t) - { - if (! last_t) - nonlocal_labels = TREE_CHAIN (nonlocal_labels); - else - TREE_CHAIN (last_t) = TREE_CHAIN (t); - } - } - if (GET_CODE (insn) == INSN) - { - int can_delete = 0; - rtx t; - for (t = nonlocal_goto_handler_slots; t != 0; t = XEXP (t, 1)) - if (reg_mentioned_p (t, PATTERN (insn))) - { - can_delete = 1; - break; - } - if (can_delete - || (nonlocal_goto_stack_level != 0 - && reg_mentioned_p (nonlocal_goto_stack_level, - PATTERN (insn)))) - delete_related_insns (insn); - } - } -} - /* Return the first insn following those generated by `assign_parms'. */ rtx @@ -4319,12 +4245,7 @@ assign_parms (tree fndecl) /* Nonzero if function takes extra anonymous args. This means the last named arg must be on the stack right before the anonymous ones. */ - int stdarg - = (TYPE_ARG_TYPES (fntype) != 0 - && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) - != void_type_node)); - - current_function_stdarg = stdarg; + int stdarg = current_function_stdarg; /* If the reg that the virtual arg pointer will be translated into is not a fixed reg or is the stack pointer, make a copy of the virtual @@ -5714,49 +5635,30 @@ pad_below (struct args_size *offset_ptr, enum machine_mode passed_mode, tree siz } /* Walk the tree of blocks describing the binding levels within a function - and warn about uninitialized variables. + and warn about variables the might be killed by setjmp or vfork. This is done after calling flow_analysis and before global_alloc clobbers the pseudo-regs to hard regs. */ void -uninitialized_vars_warning (tree block) +setjmp_vars_warning (tree block) { tree decl, sub; + for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) { - if (warn_uninitialized - && TREE_CODE (decl) == VAR_DECL - /* These warnings are unreliable for and aggregates - because assigning the fields one by one can fail to convince - flow.c that the entire aggregate was initialized. - Unions are troublesome because members may be shorter. */ - && ! AGGREGATE_TYPE_P (TREE_TYPE (decl)) - && DECL_RTL_SET_P (decl) - && GET_CODE (DECL_RTL (decl)) == REG - /* Global optimizations can make it difficult to determine if a - particular variable has been initialized. However, a VAR_DECL - with a nonzero DECL_INITIAL had an initializer, so do not - claim it is potentially uninitialized. - - When the DECL_INITIAL is NULL call the language hook to tell us - if we want to warn. */ - && (DECL_INITIAL (decl) == NULL_TREE || lang_hooks.decl_uninit (decl)) - && regno_uninitialized (REGNO (DECL_RTL (decl)))) - warning ("%J'%D' might be used uninitialized in this function", - decl, decl); - if (extra_warnings - && TREE_CODE (decl) == VAR_DECL + if (TREE_CODE (decl) == VAR_DECL && DECL_RTL_SET_P (decl) && GET_CODE (DECL_RTL (decl)) == REG && regno_clobbered_at_setjmp (REGNO (DECL_RTL (decl)))) warning ("%Jvariable '%D' might be clobbered by `longjmp' or `vfork'", decl, decl); } + for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) - uninitialized_vars_warning (sub); + setjmp_vars_warning (sub); } -/* Do the appropriate part of uninitialized_vars_warning +/* Do the appropriate part of setjmp_vars_warning but for arguments instead of local variables. */ void @@ -5830,33 +5732,6 @@ setjmp_protect_args (void) put_var_into_stack (decl, /*rescan=*/true); } -/* Return the context-pointer register corresponding to DECL, - or 0 if it does not need one. */ - -rtx -lookup_static_chain (tree decl) -{ - tree context = decl_function_context (decl); - tree link; - - if (context == 0 - || (TREE_CODE (decl) == FUNCTION_DECL && DECL_NO_STATIC_CHAIN (decl))) - return 0; - - /* We treat inline_function_decl as an alias for the current function - because that is the inline function whose vars, types, etc. - are being merged into the current function. - See expand_inline_function. */ - if (context == current_function_decl || context == inline_function_decl) - return virtual_stack_vars_rtx; - - for (link = context_display; link; link = TREE_CHAIN (link)) - if (TREE_PURPOSE (link) == context) - return RTL_EXPR_RTL (TREE_VALUE (link)); - - abort (); -} - /* Convert a stack slot address ADDR for variable VAR (from a containing function) into an address valid in this function (using a static chain). */ @@ -5871,7 +5746,7 @@ fix_lexical_addr (rtx addr, tree var) rtx base = 0; /* If this is the present function, we need not do anything. */ - if (context == current_function_decl || context == inline_function_decl) + if (context == current_function_decl) return addr; fp = find_function_data (context); @@ -5887,49 +5762,6 @@ fix_lexical_addr (rtx addr, tree var) else abort (); - /* We accept vars reached via the containing function's - incoming arg pointer and via its stack variables pointer. */ - if (basereg == fp->internal_arg_pointer) - { - /* If reached via arg pointer, get the arg pointer value - out of that function's stack frame. - - There are two cases: If a separate ap is needed, allocate a - slot in the outer function for it and dereference it that way. - This is correct even if the real ap is actually a pseudo. - Otherwise, just adjust the offset from the frame pointer to - compensate. */ - -#ifdef NEED_SEPARATE_AP - rtx addr; - - addr = get_arg_pointer_save_area (fp); - addr = fix_lexical_addr (XEXP (addr, 0), var); - addr = memory_address (Pmode, addr); - - base = gen_rtx_MEM (Pmode, addr); - set_mem_alias_set (base, get_frame_alias_set ()); - base = copy_to_reg (base); -#else - displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET); - base = lookup_static_chain (var); -#endif - } - - else if (basereg == virtual_stack_vars_rtx) - { - /* This is the same code as lookup_static_chain, duplicated here to - avoid an extra call to decl_function_context. */ - tree link; - - for (link = context_display; link; link = TREE_CHAIN (link)) - if (TREE_PURPOSE (link) == context) - { - base = RTL_EXPR_RTL (TREE_VALUE (link)); - break; - } - } - if (base == 0) abort (); @@ -5938,106 +5770,6 @@ fix_lexical_addr (rtx addr, tree var) return plus_constant (base, displacement); } -/* Return the address of the trampoline for entering nested fn FUNCTION. - If necessary, allocate a trampoline (in the stack frame) - and emit rtl to initialize its contents (at entry to this function). */ - -rtx -trampoline_address (tree function) -{ - tree link; - tree rtlexp; - rtx tramp; - struct function *fp; - tree fn_context; - - /* Find an existing trampoline and return it. */ - for (link = trampoline_list; link; link = TREE_CHAIN (link)) - if (TREE_PURPOSE (link) == function) - return - adjust_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0)); - - for (fp = outer_function_chain; fp; fp = fp->outer) - for (link = fp->x_trampoline_list; link; link = TREE_CHAIN (link)) - if (TREE_PURPOSE (link) == function) - { - tramp = fix_lexical_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0), - function); - return adjust_trampoline_addr (tramp); - } - - /* None exists; we must make one. */ - - /* Find the `struct function' for the function containing FUNCTION. */ - fp = 0; - fn_context = decl_function_context (function); - if (fn_context != current_function_decl - && fn_context != inline_function_decl) - fp = find_function_data (fn_context); - - /* Allocate run-time space for this trampoline. */ - /* If rounding needed, allocate extra space - to ensure we have TRAMPOLINE_SIZE bytes left after rounding up. */ -#define TRAMPOLINE_REAL_SIZE \ - (TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1) - tramp = assign_stack_local_1 (BLKmode, TRAMPOLINE_REAL_SIZE, 0, - fp ? fp : cfun); - /* Record the trampoline for reuse and note it for later initialization - by expand_function_end. */ - if (fp != 0) - { - rtlexp = make_node (RTL_EXPR); - RTL_EXPR_RTL (rtlexp) = tramp; - fp->x_trampoline_list = tree_cons (function, rtlexp, - fp->x_trampoline_list); - } - else - { - /* Make the RTL_EXPR node temporary, not momentary, so that the - trampoline_list doesn't become garbage. */ - rtlexp = make_node (RTL_EXPR); - - RTL_EXPR_RTL (rtlexp) = tramp; - trampoline_list = tree_cons (function, rtlexp, trampoline_list); - } - - tramp = fix_lexical_addr (XEXP (tramp, 0), function); - return adjust_trampoline_addr (tramp); -} - -/* Given a trampoline address, - round it to multiple of TRAMPOLINE_ALIGNMENT. */ - -static rtx -round_trampoline_addr (rtx tramp) -{ - /* Round address up to desired boundary. */ - rtx temp = gen_reg_rtx (Pmode); - rtx addend = GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1); - rtx mask = GEN_INT (-TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT); - - temp = expand_simple_binop (Pmode, PLUS, tramp, addend, - temp, 0, OPTAB_LIB_WIDEN); - tramp = expand_simple_binop (Pmode, AND, temp, mask, - temp, 0, OPTAB_LIB_WIDEN); - - return tramp; -} - -/* Given a trampoline address, round it then apply any - platform-specific adjustments so that the result can be used for a - function call . */ - -static rtx -adjust_trampoline_addr (rtx tramp) -{ - tramp = round_trampoline_addr (tramp); -#ifdef TRAMPOLINE_ADJUST_ADDRESS - TRAMPOLINE_ADJUST_ADDRESS (tramp); -#endif - return tramp; -} - /* Put all this function's BLOCK nodes including those that are chained onto the first block into a vector, and return it. Also store in each NOTE for the beginning or end of a block @@ -6157,7 +5889,7 @@ reorder_blocks (void) VARRAY_TREE_INIT (block_stack, 10, "block_stack"); /* Reset the TREE_ASM_WRITTEN bit for all blocks. */ - reorder_blocks_0 (block); + clear_block_marks (block); /* Prune the old trees away, so that they don't get in the way. */ BLOCK_SUBBLOCKS (block) = NULL_TREE; @@ -6173,13 +5905,13 @@ reorder_blocks (void) /* Helper function for reorder_blocks. Reset TREE_ASM_WRITTEN. */ -static void -reorder_blocks_0 (tree block) +void +clear_block_marks (tree block) { while (block) { TREE_ASM_WRITTEN (block) = 0; - reorder_blocks_0 (BLOCK_SUBBLOCKS (block)); + clear_block_marks (BLOCK_SUBBLOCKS (block)); block = BLOCK_CHAIN (block); } } @@ -6310,7 +6042,7 @@ reorder_fix_fragments (tree block) /* Reverse the order of elements in the chain T of blocks, and return the new head of the chain (old last element). */ -static tree +tree blocks_nreverse (tree t) { tree prev = 0, decl, next; @@ -6428,6 +6160,7 @@ void allocate_struct_function (tree fndecl) { tree result; + tree fntype = fndecl ? TREE_TYPE (fndecl) : NULL_TREE; cfun = ggc_alloc_cleared (sizeof (struct function)); @@ -6464,9 +6197,11 @@ allocate_struct_function (tree fndecl) current_function_returns_pointer = POINTER_TYPE_P (TREE_TYPE (result)); - current_function_needs_context - = (decl_function_context (current_function_decl) != 0 - && ! DECL_NO_STATIC_CHAIN (current_function_decl)); + current_function_stdarg + = (fntype + && TYPE_ARG_TYPES (fntype) != 0 + && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) + != void_type_node)); } /* Reset cfun, and other non-struct-function variables to defaults as @@ -6639,17 +6374,10 @@ expand_pending_sizes (tree pending_sizes) void expand_function_start (tree subr, int parms_have_cleanups) { - tree tem; - rtx last_ptr = NULL_RTX; - /* Make sure volatile mem refs aren't considered valid operands of arithmetic insns. */ init_recog_no_volatile (); - current_function_instrument_entry_exit - = (flag_instrument_function_entry_exit - && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr)); - current_function_profile = (profile_flag && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr)); @@ -6657,19 +6385,6 @@ expand_function_start (tree subr, int parms_have_cleanups) current_function_limit_stack = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr)); - /* If function gets a static chain arg, store it in the stack frame. - Do this first, so it gets the first stack slot offset. */ - if (current_function_needs_context) - { - last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); - - /* Delay copying static chain if it is not a register to avoid - conflicts with regs used for parameters. */ - if (! SMALL_REGISTER_CLASSES - || GET_CODE (static_chain_incoming_rtx) == REG) - emit_move_insn (last_ptr, static_chain_incoming_rtx); - } - /* If the parameters of this function need cleaning up, get a label for the beginning of the code which executes those cleanups. This must be done before doing anything with return_label. */ @@ -6750,15 +6465,37 @@ expand_function_start (tree subr, int parms_have_cleanups) /* Initialize rtx for parameters and local variables. In some cases this requires emitting insns. */ - assign_parms (subr); - /* Copy the static chain now if it wasn't a register. The delay is to - avoid conflicts with the parameter passing registers. */ + /* If function gets a static chain arg, store it. */ + if (cfun->static_chain_decl) + { + rtx x; + + expand_var (cfun->static_chain_decl); + x = expand_expr (cfun->static_chain_decl, NULL_RTX, + VOIDmode, EXPAND_WRITE); + emit_move_insn (x, static_chain_incoming_rtx); + } + + /* If the function receives a non-local goto, then store the + bits we need to restore the frame pointer. */ + if (cfun->nonlocal_goto_save_area) + { + tree t_save; + rtx r_save; + + /* ??? We need to do this save early. Unfortunately here is + before the frame variable gets declared. Help out... */ + expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0)); + + t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area, + integer_zero_node); + r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE); - if (SMALL_REGISTER_CLASSES && current_function_needs_context) - if (GET_CODE (static_chain_incoming_rtx) != REG) - emit_move_insn (last_ptr, static_chain_incoming_rtx); + emit_move_insn (r_save, virtual_stack_vars_rtx); + update_nonlocal_goto_save_area (); + } /* The following was moved from init_function_start. The move is supposed to make sdb output more accurate. */ @@ -6770,67 +6507,6 @@ expand_function_start (tree subr, int parms_have_cleanups) emit_note (NOTE_INSN_DELETED); parm_birth_insn = get_last_insn (); - context_display = 0; - if (current_function_needs_context) - { - /* Fetch static chain values for containing functions. */ - tem = decl_function_context (current_function_decl); - /* Copy the static chain pointer into a pseudo. If we have - small register classes, copy the value from memory if - static_chain_incoming_rtx is a REG. */ - if (tem) - { - /* If the static chain originally came in a register, put it back - there, then move it out in the next insn. The reason for - this peculiar code is to satisfy function integration. */ - if (SMALL_REGISTER_CLASSES - && GET_CODE (static_chain_incoming_rtx) == REG) - emit_move_insn (static_chain_incoming_rtx, last_ptr); - last_ptr = copy_to_reg (static_chain_incoming_rtx); - } - - while (tem) - { - tree rtlexp = make_node (RTL_EXPR); - - RTL_EXPR_RTL (rtlexp) = last_ptr; - context_display = tree_cons (tem, rtlexp, context_display); - tem = decl_function_context (tem); - if (tem == 0) - break; - /* Chain through stack frames, assuming pointer to next lexical frame - is found at the place we always store it. */ -#ifdef FRAME_GROWS_DOWNWARD - last_ptr = plus_constant (last_ptr, - -(HOST_WIDE_INT) GET_MODE_SIZE (Pmode)); -#endif - last_ptr = gen_rtx_MEM (Pmode, memory_address (Pmode, last_ptr)); - set_mem_alias_set (last_ptr, get_frame_alias_set ()); - last_ptr = copy_to_reg (last_ptr); - - /* If we are not optimizing, ensure that we know that this - piece of context is live over the entire function. */ - if (! optimize) - save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, last_ptr, - save_expr_regs); - } - } - - if (current_function_instrument_entry_exit) - { - rtx fun = DECL_RTL (current_function_decl); - if (GET_CODE (fun) == MEM) - fun = XEXP (fun, 0); - else - abort (); - emit_library_call (profile_function_entry_libfunc, LCT_NORMAL, VOIDmode, - 2, fun, Pmode, - expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, - 0, - hard_frame_pointer_rtx), - Pmode); - } - if (current_function_profile) { #ifdef PROFILE_HOOK @@ -6948,7 +6624,6 @@ static GTY(()) rtx initial_trampoline; void expand_function_end (void) { - tree link; rtx clobber_after; finish_expr_for_function (); @@ -6970,45 +6645,6 @@ expand_function_end (void) } #endif - /* Initialize any trampolines required by this function. */ - for (link = trampoline_list; link; link = TREE_CHAIN (link)) - { - tree function = TREE_PURPOSE (link); - rtx context ATTRIBUTE_UNUSED = lookup_static_chain (function); - rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link)); -#ifdef TRAMPOLINE_TEMPLATE - rtx blktramp; -#endif - rtx seq; - -#ifdef TRAMPOLINE_TEMPLATE - /* First make sure this compilation has a template for - initializing trampolines. */ - if (initial_trampoline == 0) - { - initial_trampoline - = gen_rtx_MEM (BLKmode, assemble_trampoline_template ()); - set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT); - } -#endif - - /* Generate insns to initialize the trampoline. */ - start_sequence (); - tramp = round_trampoline_addr (XEXP (tramp, 0)); -#ifdef TRAMPOLINE_TEMPLATE - blktramp = replace_equiv_address (initial_trampoline, tramp); - emit_block_move (blktramp, initial_trampoline, - GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); -#endif - trampolines_created = 1; - INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context); - seq = get_insns (); - end_sequence (); - - /* Put those insns at entry to the containing function (this one). */ - emit_insn_before (seq, tail_recursion_reentry); - } - /* If we are doing stack checking and this function makes calls, do a stack probe at the start of the function to ensure we have enough space for another stack frame. */ @@ -7036,11 +6672,6 @@ expand_function_end (void) && !lang_hooks.callgraph.expand_function) do_warn_unused_parameter (current_function_decl); - /* Delete handlers for nonlocal gotos if nothing uses them. */ - if (nonlocal_goto_handler_slots != 0 - && ! current_function_has_nonlocal_label) - delete_handlers (); - /* End any sequences that failed to be closed due to syntax errors. */ while (in_sequence_p ()) end_sequence (); @@ -7096,21 +6727,6 @@ expand_function_end (void) if (return_label) emit_label (return_label); - if (current_function_instrument_entry_exit) - { - rtx fun = DECL_RTL (current_function_decl); - if (GET_CODE (fun) == MEM) - fun = XEXP (fun, 0); - else - abort (); - emit_library_call (profile_function_exit_libfunc, LCT_NORMAL, VOIDmode, - 2, fun, Pmode, - expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS, - 0, - hard_frame_pointer_rtx), - Pmode); - } - /* Let except.c know where it should emit the call to unregister the function context for sjlj exceptions. */ if (flag_exceptions && USING_SJLJ_EXCEPTIONS) @@ -7233,9 +6849,6 @@ expand_function_end (void) end_sequence (); after = emit_insn_after (seq, clobber_after); - - if (clobber_after != after) - cfun->x_clobber_return_insn = after; } /* Output the label for the naked return from the function, if one is @@ -8161,6 +7774,59 @@ init_function_once (void) VARRAY_INT_INIT (sibcall_epilogue, 0, "sibcall_epilogue"); } +/* Resets insn_block_boundaries array. */ + +void +reset_block_changes (void) +{ + VARRAY_TREE_INIT (cfun->ib_boundaries_block, 100, "ib_boundaries_block"); + VARRAY_PUSH_TREE (cfun->ib_boundaries_block, NULL_TREE); +} + +/* Record the boundary for BLOCK. */ +void +record_block_change (tree block) +{ + int i, n; + tree last_block; + + if (!block) + return; + + last_block = VARRAY_TOP_TREE (cfun->ib_boundaries_block); + VARRAY_POP (cfun->ib_boundaries_block); + n = get_max_uid (); + for (i = VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block); i < n; i++) + VARRAY_PUSH_TREE (cfun->ib_boundaries_block, last_block); + + VARRAY_PUSH_TREE (cfun->ib_boundaries_block, block); +} + +/* Finishes record of boundaries. */ +void finalize_block_changes (void) +{ + record_block_change (DECL_INITIAL (current_function_decl)); +} + +/* For INSN return the BLOCK it belongs to. */ +void +check_block_change (rtx insn, tree *block) +{ + unsigned uid = INSN_UID (insn); + + if (uid >= VARRAY_ACTIVE_SIZE (cfun->ib_boundaries_block)) + return; + + *block = VARRAY_TREE (cfun->ib_boundaries_block, uid); +} + +/* Releases the ib_boundaries_block records. */ +void +free_block_changes (void) +{ + cfun->ib_boundaries_block = NULL; +} + /* Returns the name of the current function. */ const char * current_function_name (void) diff --git a/gcc/function.h b/gcc/function.h index 7e34633d848..4c7537eba6d 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -243,26 +243,10 @@ struct function GTY(()) /* Number of function calls seen so far in current function. */ int x_function_call_count; - /* List (chain of TREE_LIST) of LABEL_DECLs for all nonlocal labels - (labels to which there can be nonlocal gotos from nested functions) - in this function. */ - tree x_nonlocal_labels; - - /* List (chain of EXPR_LIST) of stack slots that hold the current handlers - for nonlocal gotos. There is one for every nonlocal label in the - function; this list matches the one in nonlocal_labels. - Zero when function does not have nonlocal labels. */ - rtx x_nonlocal_goto_handler_slots; - /* List (chain of EXPR_LIST) of labels heading the current handlers for nonlocal gotos. */ rtx x_nonlocal_goto_handler_labels; - /* RTX for stack slot that holds the stack pointer value to restore - for a nonlocal goto. - Zero when function does not have nonlocal labels. */ - rtx x_nonlocal_goto_stack_level; - /* Label that will go on parm cleanup code, if any. Jumping to this label runs cleanup code for parameters, if such code must be run. Following this code is the logical return @@ -307,29 +291,19 @@ struct function GTY(()) needed by inner routines. */ rtx x_arg_pointer_save_area; - /* If the function returns non-void, we will emit a clobber of the - return registers just in case the user fell off the end without - returning a proper value. This is that insn. */ - rtx x_clobber_return_insn; - /* Offset to end of allocated area of stack frame. If stack grows down, this is the address of the last stack slot allocated. If stack grows up, this is the address for the next slot. */ HOST_WIDE_INT x_frame_offset; - /* List (chain of TREE_LISTs) of static chains for containing functions. - Each link has a FUNCTION_DECL in the TREE_PURPOSE and a reg rtx - in an RTL_EXPR in the TREE_VALUE. */ - tree x_context_display; + /* A VAR_DECL that should contain the static chain for this function. + It will be initialized at the beginning of the function. */ + tree static_chain_decl; - /* List (chain of TREE_LISTs) of trampolines for nested functions. - The trampoline sets up the static chain and jumps to the function. - We supply the trampoline's address when the function's address is - requested. - - Each link has a FUNCTION_DECL in the TREE_PURPOSE and a reg rtx - in an RTL_EXPR in the TREE_VALUE. */ - tree x_trampoline_list; + /* An expression that contains the non-local goto save area. The first + word is the saved frame pointer and the second is the saved stack + pointer. */ + tree nonlocal_goto_save_area; /* Insn after which register parms and SAVE_EXPRs are born, if nonopt. */ rtx x_parm_birth_insn; @@ -391,6 +365,8 @@ struct function GTY(()) int preferred_stack_boundary; /* Set when the call to function itself has been emit. */ bool recursive_call_emit; + /* Set when the tail call has been produced. */ + bool tail_call_emit; /* Language-specific code can use this to store whatever it likes. */ struct language_function * language; @@ -401,6 +377,10 @@ struct function GTY(()) delay list for them is recorded here. */ rtx epilogue_delay_list; + /* Nonzero if NOTE_INSN_BLOCK_BEG / NOTE_INSN_BLOCK_END notes should not + be emitted. */ + unsigned int dont_emit_block_notes : 1; + /* How commonly executed the function is. Initialized during branch probabilities pass. */ enum function_frequency { @@ -418,6 +398,18 @@ struct function GTY(()) final flowgraph size. */ int max_jumptable_ents; + /* UIDs for LABEL_DECLs. */ + int last_label_uid; + + /* Line number of the end of the function. */ + location_t function_end_locus; + + /* Array mapping insn uids to blocks. */ + struct varray_head_tag *ib_boundaries_block; + + /* The variables unexpanded so far. */ + tree unexpanded_var_list; + /* Collected bit flags. */ /* Nonzero if function being compiled needs to be given an address @@ -431,9 +423,6 @@ struct function GTY(()) /* Nonzero if the current function returns a pointer type. */ unsigned int returns_pointer : 1; - /* Nonzero if function being compiled needs to be passed a static chain. */ - unsigned int needs_context : 1; - /* Nonzero if function being compiled can call setjmp. */ unsigned int calls_setjmp : 1; @@ -447,9 +436,6 @@ struct function GTY(()) /* Nonzero if the function calls __builtin_eh_return. */ unsigned int calls_eh_return : 1; - /* Nonzero if the function calls __builtin_constant_p. */ - unsigned int calls_constant_p : 1; - /* Nonzero if function being compiled receives nonlocal gotos from nested functions. */ unsigned int has_nonlocal_label : 1; @@ -517,13 +503,6 @@ struct function GTY(()) /* Nonzero if code to initialize arg_pointer_save_area has been emitted. */ unsigned int arg_pointer_save_area_init : 1; - - /* Flag for use by ther rtl inliner, to tell if the function has been - processed at least once. */ - unsigned int rtl_inline_init : 1; - - /* Nonzero if the rtl inliner has saved the function for inlining. */ - unsigned int saved_for_inline : 1; }; /* The function currently being compiled. */ @@ -543,12 +522,10 @@ extern int trampolines_created; #define current_function_returns_struct (cfun->returns_struct) #define current_function_returns_pcc_struct (cfun->returns_pcc_struct) #define current_function_returns_pointer (cfun->returns_pointer) -#define current_function_needs_context (cfun->needs_context) #define current_function_calls_setjmp (cfun->calls_setjmp) #define current_function_calls_alloca (cfun->calls_alloca) #define current_function_calls_longjmp (cfun->calls_longjmp) #define current_function_calls_eh_return (cfun->calls_eh_return) -#define current_function_calls_constant_p (cfun->calls_constant_p) #define current_function_has_computed_jump (cfun->has_computed_jump) #define current_function_contains_functions (cfun->contains_functions) #define current_function_is_thunk (cfun->is_thunk) @@ -585,20 +562,13 @@ extern int trampolines_created; #define arg_pointer_save_area (cfun->x_arg_pointer_save_area) #define rtl_expr_chain (cfun->x_rtl_expr_chain) #define last_parm_insn (cfun->x_last_parm_insn) -#define context_display (cfun->x_context_display) -#define trampoline_list (cfun->x_trampoline_list) #define function_call_count (cfun->x_function_call_count) #define temp_slots (cfun->x_temp_slots) #define temp_slot_level (cfun->x_temp_slot_level) #define target_temp_slot_level (cfun->x_target_temp_slot_level) #define var_temp_slot_level (cfun->x_var_temp_slot_level) #define nonlocal_labels (cfun->x_nonlocal_labels) -#define nonlocal_goto_handler_slots (cfun->x_nonlocal_goto_handler_slots) #define nonlocal_goto_handler_labels (cfun->x_nonlocal_goto_handler_labels) -#define nonlocal_goto_stack_level (cfun->x_nonlocal_goto_stack_level) - -/* The FUNCTION_DECL for an inline function currently being expanded. */ -extern tree inline_function_decl; /* Given a function decl for a containing function, return the `struct function' for it. */ @@ -614,6 +584,14 @@ extern void reorder_blocks (void); /* Set BLOCK_NUMBER for all the blocks in FN. */ extern void number_blocks (tree); +extern void clear_block_marks (tree); +extern tree blocks_nreverse (tree); +extern void reset_block_changes (void); +extern void record_block_change (tree); +extern void finalize_block_changes (void); +extern void check_block_change (rtx, tree *); +extern void free_block_changes (void); + /* Return size needed for stack frame based on slots so far allocated. This size counts from zero. It is not rounded to STACK_BOUNDARY; the caller may have to do that. */ diff --git a/gcc/gcc.c b/gcc/gcc.c index 4434e791aa0..0c61555e00c 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -599,6 +599,20 @@ proper position among the other output files. */ #define LIB_SPEC "%{!shared:%{g*:-lg} %{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}}" #endif +/* mudflap specs */ +#ifndef MFWRAP_SPEC +/* XXX: valid only for GNU ld */ +/* XXX: should exactly match hooks provided by libmudflap.a */ +#define MFWRAP_SPEC " %{static: %{fmudflap|fmudflapth: \ + --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc\ + --wrap=mmap --wrap=munmap --wrap=alloca\ +} %{fmudflapth: --wrap=pthread_create --wrap=pthread_join --wrap=pthread_exit\ +}} %{fmudflap|fmudflapth: --wrap=main}" +#endif +#ifndef MFLIB_SPEC +#define MFLIB_SPEC " %{fmudflap: -export-dynamic -lmudflap %{static:%(link_gcc_c_sequence) -lmudflap}} %{fmudflapth: -export-dynamic -lmudflapth -lpthread %{static:%(link_gcc_c_sequence) -lmudflapth}} " +#endif + /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is included. */ #ifndef LIBGCC_SPEC @@ -683,7 +697,8 @@ proper position among the other output files. */ %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\ %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\ %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ - %{static:} %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate:-lgcov}\ + %{static:} %{L*} %(mfwrap) %(link_libgcc) %o %(mflib)\ + %{fprofile-arcs|fprofile-generate:-lgcov}\ %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}}\ %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}" #endif @@ -719,6 +734,8 @@ static const char *asm_spec = ASM_SPEC; static const char *asm_final_spec = ASM_FINAL_SPEC; static const char *link_spec = LINK_SPEC; static const char *lib_spec = LIB_SPEC; +static const char *mfwrap_spec = MFWRAP_SPEC; +static const char *mflib_spec = MFLIB_SPEC; static const char *libgcc_spec = LIBGCC_SPEC; static const char *endfile_spec = ENDFILE_SPEC; static const char *startfile_spec = STARTFILE_SPEC; @@ -753,6 +770,8 @@ static const char *cpp_unique_options = %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\ %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}}\ %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\ + %{fmudflap:-D_MUDFLAP -include mf-runtime.h}\ + %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h}\ %{E|M|MM:%W{o*}}"; /* This contains cpp options which are common with cc1_options and are passed @@ -778,7 +797,8 @@ static const char *cc1_options = %{Qn:-fno-ident} %{--help:--help}\ %{--target-help:--target-help}\ %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\ - %{fsyntax-only:-o %j} %{-param*}"; + %{fsyntax-only:-o %j} %{-param*}\ + %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants}"; static const char *asm_options = "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}"; @@ -901,6 +921,8 @@ static const struct compiler default_compilers[] = {".CPP", "#C++", 0, 0, 0}, {".ii", "#C++", 0, 0, 0}, {".ads", "#Ada", 0, 0, 0}, {".adb", "#Ada", 0, 0, 0}, {".f", "#Fortran", 0, 0, 0}, {".for", "#Fortran", 0, 0, 0}, + {".F", "#Fortran", 0}, {".FOR", "#Fortran", 0}, {".FPP", "#Fortran", 0}, + {".f90", "#Fortran 95", 0}, {".f95", "#Fortran 95", 0}, {".fpp", "#Fortran", 0, 0, 0}, {".F", "#Fortran", 0, 0, 0}, {".FOR", "#Fortran", 0, 0, 0}, {".FPP", "#Fortran", 0, 0, 0}, {".r", "#Ratfor", 0, 0, 0}, @@ -1490,6 +1512,8 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("endfile", &endfile_spec), INIT_STATIC_SPEC ("link", &link_spec), INIT_STATIC_SPEC ("lib", &lib_spec), + INIT_STATIC_SPEC ("mfwrap", &mfwrap_spec), + INIT_STATIC_SPEC ("mflib", &mflib_spec), INIT_STATIC_SPEC ("libgcc", &libgcc_spec), INIT_STATIC_SPEC ("startfile", &startfile_spec), INIT_STATIC_SPEC ("switches_need_spaces", &switches_need_spaces), diff --git a/gcc/gcse.c b/gcc/gcse.c index 19710d200fe..9e6ced54dd1 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -1281,7 +1281,6 @@ want_to_gcse_p (rtx x) case CONST_DOUBLE: case CONST_VECTOR: case CALL: - case CONSTANT_P_RTX: return 0; default: @@ -2141,9 +2140,6 @@ gcse_constant_p (rtx x) && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 1)))) return true; - if (GET_CODE (x) == CONSTANT_P_RTX) - return false; - return CONSTANT_P (x); } @@ -4773,7 +4769,7 @@ reg_killed_on_edge (rtx reg, edge e) { rtx insn; - for (insn = e->insns; insn; insn = NEXT_INSN (insn)) + for (insn = e->insns.r; insn; insn = NEXT_INSN (insn)) if (INSN_P (insn) && reg_set_p (reg, insn)) return true; @@ -4850,7 +4846,7 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) continue; /* Check the data flow is valid after edge insertions. */ - if (e->insns && reg_killed_on_edge (reg_used->reg_rtx, e)) + if (e->insns.r && reg_killed_on_edge (reg_used->reg_rtx, e)) continue; src = SET_SRC (pc_set (jump)); @@ -4871,14 +4867,14 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) if (new == pc_rtx) { edest = FALLTHRU_EDGE (bb); - dest = edest->insns ? NULL : edest->dest; + dest = edest->insns.r ? NULL : edest->dest; } else if (GET_CODE (new) == LABEL_REF) { dest = BLOCK_FOR_INSN (XEXP (new, 0)); /* Don't bypass edges containing instructions. */ for (edest = bb->succ; edest; edest = edest->succ_next) - if (edest->dest == dest && edest->insns) + if (edest->dest == dest && edest->insns.r) { dest = NULL; break; @@ -8150,7 +8146,7 @@ reg_used_on_edge (rtx reg, edge e) { rtx insn; - for (insn = e->insns; insn; insn = NEXT_INSN (insn)) + for (insn = e->insns.r; insn; insn = NEXT_INSN (insn)) if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn))) return true; diff --git a/gcc/gdbinit.in b/gcc/gdbinit.in index ccc6504dda7..753cd9e73bc 100644 --- a/gcc/gdbinit.in +++ b/gcc/gdbinit.in @@ -40,6 +40,24 @@ Print the tree that is $ in C syntax. Works only when an inferior is executing. end +define pgs +set debug_generic_stmt ($) +end + +document pgs +Print the statement that is $ in C syntax. +Works only when an inferior is executing. +end + +define pge +set debug_generic_expr ($) +end + +document pge +Print the expression that is $ in C syntax. +Works only when an inferior is executing. +end + define ptc output (enum tree_code) $.common.code echo \n diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index a3c035f4ef7..245c65599b1 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -90,14 +90,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA independent of the insn code. `in_struct' (ATTR_CURR_SIMPLIFIED_P): This rtx is fully simplified for the insn code currently being processed (see optimize_attrs). - `integrated' (ATTR_PERMANENT_P): This rtx is permanent and unique + `return_val' (ATTR_PERMANENT_P): This rtx is permanent and unique (see attr_rtx). `volatil' (ATTR_EQ_ATTR_P): During simplify_by_exploding the value of an EQ_ATTR rtx is true if !volatil and false if volatil. */ #define ATTR_IND_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), unchanging)) #define ATTR_CURR_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), in_struct)) -#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), integrated)) +#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), return_val)) #define ATTR_EQ_ATTR_P(RTX) (RTX_FLAG((RTX), volatil)) #if 0 diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l index 2d0462beba5..19d7691f35e 100644 --- a/gcc/gengtype-lex.l +++ b/gcc/gengtype-lex.l @@ -47,7 +47,7 @@ update_lineno (const char *l, size_t len) ID [[:alpha:]_][[:alnum:]_]* WS [[:space:]]+ -IWORD short|long|(un)?signed|char|int|HOST_WIDE_INT|bool|size_t|BOOL_BITFIELD +IWORD short|long|(un)?signed|char|int|HOST_WIDE_INT|HOST_WIDEST_INT|bool|size_t|BOOL_BITFIELD ITYPE {IWORD}({WS}{IWORD})* %x in_struct in_struct_comment in_comment in_yacc_escape diff --git a/gcc/gengtype-yacc.y b/gcc/gengtype-yacc.y index f6a9bac2e2e..02136dc0d29 100644 --- a/gcc/gengtype-yacc.y +++ b/gcc/gengtype-yacc.y @@ -212,11 +212,16 @@ struct_fields: { $$ = NULL; } p->line = lexer_line; $$ = p; } + | type ':' bitfieldlen ';' struct_fields + { $$ = $5; } ; bitfieldopt: /* empty */ - | ':' NUM - | ':' ID + | ':' bitfieldlen + ; + +bitfieldlen: NUM | ID + { } ; type: SCALAR diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 1bad8e4e706..1b56a839fcc 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1095,11 +1095,12 @@ open_base_files (void) { /* The order of files here matters very much. */ static const char *const ifiles [] = { - "config.h", "system.h", "coretypes.h", "tm.h", "varray.h", + "config.h", "system.h", "coretypes.h", "tm.h", "varray.h", "hashtab.h", "splay-tree.h", "bitmap.h", "tree.h", "rtl.h", "function.h", "insn-config.h", "expr.h", "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h", "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h", + "tree-alias-type.h", "tree-flow.h", NULL }; const char *const *ifp; diff --git a/gcc/genrecog.c b/gcc/genrecog.c index 2d4c0911cd9..c727fec97c5 100644 --- a/gcc/genrecog.c +++ b/gcc/genrecog.c @@ -513,8 +513,7 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code) && c != CONST_INT && c != CONST_DOUBLE && c != CONST - && c != HIGH - && c != CONSTANT_P_RTX) + && c != HIGH) allows_non_const = 1; if (c != REG diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c new file mode 100644 index 00000000000..af2760279bc --- /dev/null +++ b/gcc/gimple-low.c @@ -0,0 +1,472 @@ +/* Tree lowering pass. Lowers GIMPLE into unstructured form. + + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "errors.h" +#include "varray.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "tree-flow.h" +#include "timevar.h" +#include "except.h" +#include "hashtab.h" +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "toplev.h" +#include "tree-pass.h" + +struct lower_data +{ + /* Block the current statement belongs to. */ + tree block; +}; + +static void lower_stmt (tree_stmt_iterator *, struct lower_data *); +static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *); +static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *); +static bool expand_var_p (tree); + +/* Lowers the body of current_function_decl. */ + +static void +lower_function_body (void) +{ + struct lower_data data; + tree *body_p = &DECL_SAVED_TREE (current_function_decl); + tree bind = *body_p; + tree_stmt_iterator i; + + if (TREE_CODE (bind) != BIND_EXPR) + abort (); + + data.block = DECL_INITIAL (current_function_decl); + BLOCK_SUBBLOCKS (data.block) = NULL_TREE; + BLOCK_CHAIN (data.block) = NULL_TREE; + TREE_ASM_WRITTEN (data.block) = 1; + + *body_p = alloc_stmt_list (); + i = tsi_start (*body_p); + tsi_link_after (&i, bind, TSI_NEW_STMT); + lower_bind_expr (&i, &data); + + if (data.block != DECL_INITIAL (current_function_decl)) + abort (); + BLOCK_SUBBLOCKS (data.block) + = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); + + clear_block_marks (data.block); + + /* Avoid producing notes for blocks. */ + cfun->dont_emit_block_notes = 1; + reset_block_changes (); +} + +struct tree_opt_pass pass_lower_cf = +{ + "lower", /* name */ + NULL, /* gate */ + lower_function_body, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_gimple_any, /* properties_required */ + PROP_gimple_lcf, /* properties_provided */ + PROP_gimple_any, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ +}; + + +/* Lowers the EXPR. Unlike gimplification the statements are not relowered + when they are changed -- if this has to be done, the lowering routine must + do it explicitly. DATA is passed through the recursion. */ + +void +lower_stmt_body (tree expr, struct lower_data *data) +{ + tree_stmt_iterator tsi; + + for (tsi = tsi_start (expr); !tsi_end_p (tsi); ) + lower_stmt (&tsi, data); +} + +/* Lowers statement TSI. DATA is passed through the recursion. */ + +static void +lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree stmt = tsi_stmt (*tsi); + + if (EXPR_HAS_LOCATION (stmt) && data) + TREE_BLOCK (stmt) = data->block; + + switch (TREE_CODE (stmt)) + { + case BIND_EXPR: + lower_bind_expr (tsi, data); + return; + case COND_EXPR: + lower_cond_expr (tsi, data); + return; + + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + lower_stmt_body (TREE_OPERAND (stmt, 0), data); + lower_stmt_body (TREE_OPERAND (stmt, 1), data); + break; + case CATCH_EXPR: + lower_stmt_body (CATCH_BODY (stmt), data); + break; + case EH_FILTER_EXPR: + lower_stmt_body (EH_FILTER_FAILURE (stmt), data); + break; + + case NOP_EXPR: + case ASM_EXPR: + case RETURN_EXPR: + case MODIFY_EXPR: + case CALL_EXPR: + case GOTO_EXPR: + case LABEL_EXPR: + case VA_ARG_EXPR: + case SWITCH_EXPR: + break; + + default: + print_node_brief (stderr, "", stmt, 0); + case COMPOUND_EXPR: + abort (); + } + + tsi_next (tsi); +} + +/* Lowers a bind_expr TSI. DATA is passed through the recursion. */ + +static void +lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree old_block = data->block; + tree stmt = tsi_stmt (*tsi); + tree new_block = BIND_EXPR_BLOCK (stmt); + + if (new_block) + { + if (new_block == old_block) + { + /* The outermost block of the original function may not be the + outermost statement chain of the gimplified function. So we + may see the outermost block just inside the function. */ + if (new_block != DECL_INITIAL (current_function_decl)) + abort (); + new_block = NULL; + } + else + { + /* We do not expect to handle duplicate blocks. */ + if (TREE_ASM_WRITTEN (new_block)) + abort (); + TREE_ASM_WRITTEN (new_block) = 1; + + /* Block tree may get clobbered by inlining. Normally this would + be fixed in rest_of_decl_compilation using block notes, but + since we are not going to emit them, it is up to us. */ + BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block); + BLOCK_SUBBLOCKS (old_block) = new_block; + BLOCK_SUBBLOCKS (new_block) = NULL_TREE; + BLOCK_SUPERCONTEXT (new_block) = old_block; + + data->block = new_block; + } + } + + record_vars (BIND_EXPR_VARS (stmt)); + lower_stmt_body (BIND_EXPR_BODY (stmt), data); + + if (new_block) + { + if (data->block != new_block) + abort (); + + BLOCK_SUBBLOCKS (new_block) + = blocks_nreverse (BLOCK_SUBBLOCKS (new_block)); + data->block = old_block; + } + + /* The BIND_EXPR no longer carries any useful information -- kill it. */ + tsi_link_before (tsi, BIND_EXPR_BODY (stmt), TSI_SAME_STMT); + tsi_delink (tsi); +} + +/* Try to determine if we can fall out of the bottom of BLOCK. This guess + need not be 100% accurate; simply be conservative and return true if we + don't know. This is used only to avoid stupidly generating extra code. + If we're wrong, we'll just delete the extra code later. */ + +bool +block_may_fallthru (tree block) +{ + tree stmt = expr_last (block); + + switch (stmt ? TREE_CODE (stmt) : ERROR_MARK) + { + case GOTO_EXPR: + case RETURN_EXPR: + case RESX_EXPR: + case SWITCH_EXPR: + /* Easy cases. If the last statement of the block implies + control transfer, then we can't fall through. */ + return false; + + case COND_EXPR: + if (block_may_fallthru (COND_EXPR_THEN (stmt))) + return true; + return block_may_fallthru (COND_EXPR_ELSE (stmt)); + + case BIND_EXPR: + return block_may_fallthru (BIND_EXPR_BODY (stmt)); + + case TRY_FINALLY_EXPR: + return block_may_fallthru (TREE_OPERAND (stmt, 1)); + + case MODIFY_EXPR: + if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) + stmt = TREE_OPERAND (stmt, 1); + else + return true; + /* FALLTHRU */ + + case CALL_EXPR: + /* Functions that do not return do not fall through. */ + return (call_expr_flags (stmt) & ECF_NORETURN) == 0; + + default: + return true; + } +} + +/* Lowers a cond_expr TSI. DATA is passed through the recursion. */ + +static void +lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree stmt = tsi_stmt (*tsi); + bool then_is_goto, else_is_goto; + tree then_branch, else_branch; + tree then_goto, else_goto; + + then_branch = COND_EXPR_THEN (stmt); + else_branch = COND_EXPR_ELSE (stmt); + + lower_stmt_body (then_branch, data); + lower_stmt_body (else_branch, data); + + then_goto = expr_only (then_branch); + then_is_goto = then_goto && simple_goto_p (then_goto); + + else_goto = expr_only (else_branch); + else_is_goto = else_goto && simple_goto_p (else_goto); + + if (!then_is_goto || !else_is_goto) + { + tree then_label, else_label, end_label, t; + + then_label = NULL_TREE; + else_label = NULL_TREE; + end_label = NULL_TREE; + + /* Replace the cond_expr with explicit gotos. */ + if (!then_is_goto) + { + t = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + if (TREE_SIDE_EFFECTS (then_branch)) + then_label = t; + else + end_label = t; + then_goto = build_and_jump (&LABEL_EXPR_LABEL (t)); + } + + if (!else_is_goto) + { + t = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + if (TREE_SIDE_EFFECTS (else_branch)) + else_label = t; + else + { + /* Both THEN and ELSE can be no-ops if one or both contained an + empty BIND_EXPR that was associated with the toplevel block + of an inlined function. In that case remove_useless_stmts + can't have cleaned things up for us; kill the whole + conditional now. */ + if (end_label) + { + tsi_delink (tsi); + return; + } + else + end_label = t; + } + else_goto = build_and_jump (&LABEL_EXPR_LABEL (t)); + } + + if (then_label) + { + bool may_fallthru = block_may_fallthru (then_branch); + + tsi_link_after (tsi, then_label, TSI_CONTINUE_LINKING); + tsi_link_after (tsi, then_branch, TSI_CONTINUE_LINKING); + + if (else_label && may_fallthru) + { + end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + t = build_and_jump (&LABEL_EXPR_LABEL (end_label)); + tsi_link_after (tsi, t, TSI_CONTINUE_LINKING); + } + } + + if (else_label) + { + tsi_link_after (tsi, else_label, TSI_CONTINUE_LINKING); + tsi_link_after (tsi, else_branch, TSI_CONTINUE_LINKING); + } + + if (end_label) + tsi_link_after (tsi, end_label, TSI_CONTINUE_LINKING); + } + + COND_EXPR_THEN (stmt) = then_goto; + COND_EXPR_ELSE (stmt) = else_goto; + + tsi_next (tsi); +} + + +/* Record the variables in VARS. */ + +void +record_vars (tree vars) +{ + for (; vars; vars = TREE_CHAIN (vars)) + { + tree var = vars; + + /* Nothing to do in this case. */ + if (DECL_EXTERNAL (var)) + continue; + if (TREE_CODE (var) == FUNCTION_DECL) + continue; + + /* Record the variable. */ + cfun->unexpanded_var_list = tree_cons (NULL_TREE, var, + cfun->unexpanded_var_list); + } +} + +/* Check whether to expand a variable VAR. */ + +static bool +expand_var_p (tree var) +{ + struct var_ann_d *ann; + + if (TREE_CODE (var) != VAR_DECL) + return true; + + ann = var_ann (var); + + /* Remove all unused, unaliased temporaries. Also remove unused, unaliased + local variables during highly optimizing compilations. */ + ann = var_ann (var); + if (ann + && ! ann->may_aliases + && ! ann->used + && ! ann->has_hidden_use + && ! TREE_ADDRESSABLE (var) + && ! TREE_THIS_VOLATILE (var) + && (DECL_ARTIFICIAL (var) || optimize >= 2)) + return false; + + return true; +} + +/* Throw away variables that are unused. */ + +static void +remove_useless_vars (void) +{ + tree var, *cell; + + for (cell = &cfun->unexpanded_var_list; *cell; ) + { + var = TREE_VALUE (*cell); + + if (!expand_var_p (var)) + { + *cell = TREE_CHAIN (*cell); + continue; + } + + cell = &TREE_CHAIN (*cell); + } +} + +/* Expand variables in the unexpanded_var_list. */ + +void +expand_used_vars (void) +{ + tree cell; + + cfun->unexpanded_var_list = nreverse (cfun->unexpanded_var_list); + + for (cell = cfun->unexpanded_var_list; cell; cell = TREE_CHAIN (cell)) + expand_var (TREE_VALUE (cell)); + + cfun->unexpanded_var_list = NULL_TREE; +} + +struct tree_opt_pass pass_remove_useless_vars = +{ + "vars", /* name */ + NULL, /* gate */ + remove_useless_vars, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ +}; + + diff --git a/gcc/gimplify.c b/gcc/gimplify.c new file mode 100644 index 00000000000..dda218beab4 --- /dev/null +++ b/gcc/gimplify.c @@ -0,0 +1,3754 @@ +/* Tree lowering pass. This pass converts the GENERIC functions-as-trees + tree representation into the GIMPLE form. + + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Major work done by Sebastian Pop , + Diego Novillo and Jason Merrill . + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "errors.h" +#include "varray.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "tree-flow.h" +#include "timevar.h" +#include "except.h" +#include "hashtab.h" +#include "flags.h" +#include "real.h" +#include "function.h" +#include "output.h" +#include "expr.h" +#include "ggc.h" + +static struct gimplify_ctx +{ + tree current_bind_expr; + bool save_stack; + tree temps; + tree conditional_cleanups; + int conditions; + tree exit_label; + varray_type case_labels; + /* The formal temporary table. Should this be persistent? */ + htab_t temp_htab; +} *gimplify_ctxp; + + +/* Formal (expression) temporary table handling: Multiple occurrences of + the same scalar expression are evaluated into the same temporary. */ + +typedef struct gimple_temp_hash_elt +{ + tree val; /* Key */ + tree temp; /* Value */ +} elt_t; + +/* Return a hash value for a formal temporary table entry. */ + +static hashval_t +gimple_tree_hash (const void *p) +{ + tree t = ((const elt_t *)p)->val; + return iterative_hash_expr (t, 0); +} + +/* Compare two formal temporary table entries. */ + +static int +gimple_tree_eq (const void *p1, const void *p2) +{ + tree t1 = ((const elt_t *)p1)->val; + tree t2 = ((const elt_t *)p2)->val; + enum tree_code code = TREE_CODE (t1); + + if (TREE_CODE (t2) != code + || TREE_TYPE (t1) != TREE_TYPE (t2)) + return 0; + + if (!operand_equal_p (t1, t2, 0)) + return 0; + + /* Only allow them to compare equal if they also hash equal; otherwise + results are nondeterminate, and we fail bootstrap comparison. */ + if (gimple_tree_hash (p1) != gimple_tree_hash (p2)) + abort (); + + return 1; +} + +/* Set up a context for the gimplifier. */ + +void +push_gimplify_context (void) +{ + if (gimplify_ctxp) + abort (); + gimplify_ctxp + = (struct gimplify_ctx *) xcalloc (1, sizeof (struct gimplify_ctx)); + gimplify_ctxp->temp_htab + = htab_create (1000, gimple_tree_hash, gimple_tree_eq, free); +} + +/* Tear down a context for the gimplifier. If BODY is non-null, then + put the temporaries into the outer BIND_EXPR. Otherwise, put them + in the unexpanded_var_list. */ + +void +pop_gimplify_context (tree body) +{ + if (!gimplify_ctxp || gimplify_ctxp->current_bind_expr) + abort (); + + if (body) + declare_tmp_vars (gimplify_ctxp->temps, body); + else + record_vars (gimplify_ctxp->temps); + +#if 0 + if (!quiet_flag) + fprintf (stderr, " collisions: %f ", + htab_collisions (gimplify_ctxp->temp_htab)); +#endif + + htab_delete (gimplify_ctxp->temp_htab); + free (gimplify_ctxp); + gimplify_ctxp = NULL; +} + +void +gimple_push_bind_expr (tree bind) +{ + TREE_CHAIN (bind) = gimplify_ctxp->current_bind_expr; + gimplify_ctxp->current_bind_expr = bind; +} + +void +gimple_pop_bind_expr (void) +{ + gimplify_ctxp->current_bind_expr + = TREE_CHAIN (gimplify_ctxp->current_bind_expr); +} + +tree +gimple_current_bind_expr (void) +{ + return gimplify_ctxp->current_bind_expr; +} + +/* Returns true iff there is a COND_EXPR between us and the innermost + CLEANUP_POINT_EXPR. This info is used by gimple_push_cleanup. */ + +static bool +gimple_conditional_context (void) +{ + return gimplify_ctxp->conditions > 0; +} + +/* Note that we've entered a COND_EXPR. */ + +static void +gimple_push_condition (void) +{ + ++(gimplify_ctxp->conditions); +} + +/* Note that we've left a COND_EXPR. If we're back at unconditional scope + now, add any conditional cleanups we've seen to the prequeue. */ + +static void +gimple_pop_condition (tree *pre_p) +{ + int conds = --(gimplify_ctxp->conditions); + if (conds == 0) + { + append_to_statement_list (gimplify_ctxp->conditional_cleanups, pre_p); + gimplify_ctxp->conditional_cleanups = NULL_TREE; + } + else if (conds < 0) + abort (); +} + +/* A subroutine of append_to_statement_list{,_force}. */ + +static void +append_to_statement_list_1 (tree t, tree *list_p, bool side_effects) +{ + tree list = *list_p; + tree_stmt_iterator i; + + if (!list) + { + if (t && TREE_CODE (t) == STATEMENT_LIST) + { + *list_p = t; + return; + } + *list_p = list = alloc_stmt_list (); + } + + if (!side_effects) + return; + + i = tsi_last (list); + tsi_link_after (&i, t, TSI_CONTINUE_LINKING); +} + +/* Add T to the end of the list container pointed by LIST_P. + If T is an expression with no effects, it is ignored. */ + +void +append_to_statement_list (tree t, tree *list_p) +{ + append_to_statement_list_1 (t, list_p, t ? TREE_SIDE_EFFECTS (t) : false); +} + +/* Similar, but the statement is always added, regardless of side effects. */ + +void +append_to_statement_list_force (tree t, tree *list_p) +{ + append_to_statement_list_1 (t, list_p, t != NULL); +} + +/* Add T to the end of a COMPOUND_EXPR pointed by LIST_P. The type + of the result is the type of T. */ + +void +append_to_compound_expr (tree t, tree *list_p) +{ + if (!t) + return; + if (!*list_p) + *list_p = t; + else + *list_p = build (COMPOUND_EXPR, TREE_TYPE (t), *list_p, t); +} + +/* Strip off a legitimate source ending from the input string NAME of + length LEN. Rather than having to know the names used by all of + our front ends, we strip off an ending of a period followed by + up to five characters. (Java uses ".class".) */ + +static inline void +remove_suffix (char *name, int len) +{ + int i; + + for (i = 2; i < 8 && len > i; i++) + { + if (name[len - i] == '.') + { + name[len - i] = '\0'; + break; + } + } +} + +/* Create a nameless artificial label and put it in the current function + context. Returns the newly created label. */ + +tree +create_artificial_label (void) +{ + tree lab = build_decl (LABEL_DECL, NULL_TREE, void_type_node); + DECL_ARTIFICIAL (lab) = 1; + DECL_CONTEXT (lab) = current_function_decl; + return lab; +} + +/* Create a new temporary name with PREFIX. Returns an indentifier. */ + +static GTY(()) unsigned int tmp_var_id_num; + +static tree +create_tmp_var_name (const char *prefix) +{ + char *tmp_name; + + if (prefix) + { + char *preftmp = ASTRDUP (prefix); + remove_suffix (preftmp, strlen (preftmp)); + prefix = preftmp; + } + + ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix ? prefix : "T", tmp_var_id_num++); + return get_identifier (tmp_name); +} + + +/* Create a new temporary variable declaration of type TYPE. + Does NOT push it into the current binding. */ + +tree +create_tmp_var_raw (tree type, const char *prefix) +{ + tree tmp_var; + tree new_type; + + /* Make the type of the variable writable. */ + new_type = build_type_variant (type, 0, 0); + TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type); + + tmp_var = build_decl (VAR_DECL, create_tmp_var_name (prefix), type); + + /* The variable was declared by the compiler. */ + DECL_ARTIFICIAL (tmp_var) = 1; + /* And we don't want debug info for it. */ + DECL_IGNORED_P (tmp_var) = 1; + + /* Make the variable writable. */ + TREE_READONLY (tmp_var) = 0; + + DECL_EXTERNAL (tmp_var) = 0; + TREE_STATIC (tmp_var) = 0; + TREE_USED (tmp_var) = 1; + + return tmp_var; +} + +/* Create a new temporary variable declaration of type TYPE. DOES push the + variable into the current binding. Further, assume that this is called + only from gimplification or optimization, at which point the creation of + certain types are bugs. */ + +tree +create_tmp_var (tree type, const char *prefix) +{ + tree tmp_var; + +#if defined ENABLE_CHECKING + /* If the type is an array or a type which must be created by the + frontend, something is wrong. */ + if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type)) + abort (); + if (!COMPLETE_TYPE_P (type)) + abort (); + /* Variable sized types require lots of machinery to create; the + optimizers shouldn't be doing anything of the sort. */ + if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) + abort (); +#endif + + tmp_var = create_tmp_var_raw (type, prefix); + gimple_add_tmp_var (tmp_var); + return tmp_var; +} + +/* Given a tree, try to return a useful variable name that we can use + to prefix a temporary that is being assigned the value of the tree. + I.E. given = &A, return A. */ + +const char * +get_name (tree t) +{ + tree stripped_decl; + + stripped_decl = t; + STRIP_NOPS (stripped_decl); + if (DECL_P (stripped_decl) && DECL_NAME (stripped_decl)) + return IDENTIFIER_POINTER (DECL_NAME (stripped_decl)); + else + { + switch (TREE_CODE (stripped_decl)) + { + case ADDR_EXPR: + return get_name (TREE_OPERAND (stripped_decl, 0)); + break; + default: + return NULL; + } + } +} + +/* Create a temporary with a name derived from VAL. Subroutine of + lookup_tmp_var; nobody else should call this function. */ + +static inline tree +create_tmp_from_val (tree val) +{ + return create_tmp_var (TREE_TYPE (val), get_name (val)); +} + +/* Create a temporary to hold the value of VAL. If IS_FORMAL, try to reuse + an existing expression temporary. */ + +static tree +lookup_tmp_var (tree val, bool is_formal) +{ + if (!is_formal || TREE_SIDE_EFFECTS (val)) + return create_tmp_from_val (val); + else + { + elt_t elt, *elt_p; + void **slot; + + elt.val = val; + slot = htab_find_slot (gimplify_ctxp->temp_htab, (void *)&elt, INSERT); + if (*slot == NULL) + { + elt_p = xmalloc (sizeof (*elt_p)); + elt_p->val = val; + elt_p->temp = create_tmp_from_val (val); + *slot = (void *)elt_p; + } + else + elt_p = (elt_t *) *slot; + + return elt_p->temp; + } +} + +/* Returns a formal temporary variable initialized with VAL. PRE_P is as + in gimplify_expr. Only use this function if: + + 1) The value of the unfactored expression represented by VAL will not + change between the initialization and use of the temporary, and + 2) The temporary will not be otherwise modified. + + For instance, #1 means that this is inappropriate for SAVE_EXPR temps, + and #2 means it is inappropriate for && temps. + + For other cases, use get_initialized_tmp_var instead. */ + +static tree +internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal) +{ + tree t, mod; + char class; + + gimplify_expr (&val, pre_p, post_p, is_gimple_rhs, fb_rvalue); + + t = lookup_tmp_var (val, is_formal); + + mod = build (MODIFY_EXPR, TREE_TYPE (t), t, val); + + class = TREE_CODE_CLASS (TREE_CODE (val)); + if (EXPR_LOCUS (val)) + SET_EXPR_LOCUS (mod, EXPR_LOCUS (val)); + else + annotate_with_locus (mod, input_location); + /* gimplify_modify_expr might want to reduce this further. */ + gimplify_stmt (&mod); + append_to_statement_list (mod, pre_p); + + return t; +} + +tree +get_formal_tmp_var (tree val, tree *pre_p) +{ + return internal_get_tmp_var (val, pre_p, NULL, true); +} + +/* Returns a temporary variable initialized with VAL. PRE_P and POST_P + are as in gimplify_expr. */ + +tree +get_initialized_tmp_var (tree val, tree *pre_p, tree *post_p) +{ + return internal_get_tmp_var (val, pre_p, post_p, false); +} + +/* Returns true if T is a GIMPLE temporary variable, false otherwise. */ + +bool +is_gimple_tmp_var (tree t) +{ + /* FIXME this could trigger for other local artificials, too. */ + return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t) + && !TREE_STATIC (t) && !DECL_EXTERNAL (t)); +} + +/* Declares all the variables in VARS in SCOPE. Returns the last + DECL_STMT emitted. */ + +void +declare_tmp_vars (tree vars, tree scope) +{ + tree last = vars; + if (last) + { + tree temps; + + /* C99 mode puts the default 'return 0;' for main() outside the outer + braces. So drill down until we find an actual scope. */ + while (TREE_CODE (scope) == COMPOUND_EXPR) + scope = TREE_OPERAND (scope, 0); + + if (TREE_CODE (scope) != BIND_EXPR) + abort (); + + temps = nreverse (last); + TREE_CHAIN (last) = BIND_EXPR_VARS (scope); + BIND_EXPR_VARS (scope) = temps; + + /* We don't add the temps to the block for this BIND_EXPR, as we're + not interested in debugging info for them. */ + } +} + +void +gimple_add_tmp_var (tree tmp) +{ + if (TREE_CHAIN (tmp) || tmp->decl.seen_in_bind_expr) + abort (); + + DECL_CONTEXT (tmp) = current_function_decl; + tmp->decl.seen_in_bind_expr = 1; + + if (gimplify_ctxp) + { + TREE_CHAIN (tmp) = gimplify_ctxp->temps; + gimplify_ctxp->temps = tmp; + } + else if (cfun) + record_vars (tmp); + else + declare_tmp_vars (tmp, DECL_SAVED_TREE (current_function_decl)); +} + +/* Determines whether to assign a locus to the statement STMT. */ + +static bool +should_carry_locus_p (tree stmt) +{ + /* Don't emit a line note for a label. We particularly don't want to + emit one for the break label, since it doesn't actually correspond + to the beginning of the loop/switch. */ + if (TREE_CODE (stmt) == LABEL_EXPR) + return false; + + /* Do not annotate empty statements, since it confuses gcov. */ + if (!TREE_SIDE_EFFECTS (stmt)) + return false; + + return true; +} + +void +annotate_all_with_locus (tree *stmt_p, location_t locus) +{ + tree_stmt_iterator i; + + if (!*stmt_p) + return; + + for (i = tsi_start (*stmt_p); !tsi_end_p (i); tsi_next (&i)) + { + tree t = tsi_stmt (i); + +#ifdef ENABLE_CHECKING + /* Assuming we've already been gimplified, we shouldn't + see nested chaining constructs anymore. */ + if (TREE_CODE (t) == STATEMENT_LIST + || TREE_CODE (t) == COMPOUND_EXPR) + abort (); +#endif + + if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t))) + && ! EXPR_HAS_LOCATION (t) + && should_carry_locus_p (t)) + annotate_with_locus (t, locus); + } +} + +/* Similar to copy_tree_r() but do not copy SAVE_EXPR or TARGET_EXPR nodes. + These nodes model computations that should only be done once. If we + were to unshare something like SAVE_EXPR(i++), the gimplification + process would create wrong code. */ + +static tree +mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data) +{ + enum tree_code code = TREE_CODE (*tp); + /* Don't unshare types, constants and SAVE_EXPR nodes. */ + if (TREE_CODE_CLASS (code) == 't' + || TREE_CODE_CLASS (code) == 'c' + || code == SAVE_EXPR || code == TARGET_EXPR + /* We can't do anything sensible with a BLOCK used as an expression, + but we also can't abort when we see it because of non-expression + uses. So just avert our eyes and cross our fingers. Silly Java. */ + || code == BLOCK) + *walk_subtrees = 0; + else if (code == BIND_EXPR) + abort (); + else + copy_tree_r (tp, walk_subtrees, data); + + return NULL_TREE; +} + +/* Mark all the _DECL nodes under *TP as volatile. FIXME: This must die + after VA_ARG_EXPRs are properly lowered. */ + +static tree +mark_decls_volatile_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + if (SSA_VAR_P (*tp)) + TREE_THIS_VOLATILE (*tp) = 1; + + return NULL_TREE; +} + + +/* Callback for walk_tree to unshare most of the shared trees rooted at + *TP. If *TP has been visited already (i.e., TREE_VISITED (*TP) == 1), + then *TP is deep copied by calling copy_tree_r. + + This unshares the same trees as copy_tree_r with the exception of + SAVE_EXPR nodes. These nodes model computations that should only be + done once. If we were to unshare something like SAVE_EXPR(i++), the + gimplification process would create wrong code. */ + +static tree +copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + /* If this node has been visited already, unshare it and don't look + any deeper. */ + if (TREE_VISITED (*tp)) + { + walk_tree (tp, mostly_copy_tree_r, NULL, NULL); + *walk_subtrees = 0; + } + else + { + /* Otherwise, mark the tree as visited and keep looking. */ + TREE_VISITED (*tp) = 1; + if (TREE_CODE (*tp) == VA_ARG_EXPR) + { + /* Mark any _DECL inside the operand as volatile to avoid the + optimizers messing around with it. FIXME: Remove this once + VA_ARG_EXPRs are properly lowered. */ + walk_tree (&TREE_OPERAND (*tp, 0), mark_decls_volatile_r, + NULL, NULL); + } + } + return NULL_TREE; +} + +static tree +unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + if (TREE_VISITED (*tp)) + TREE_VISITED (*tp) = 0; + else + *walk_subtrees = 0; + + return NULL_TREE; +} + +/* Unshare T and all the trees reached from T via TREE_CHAIN. */ + +void +unshare_all_trees (tree t) +{ + walk_tree (&t, copy_if_shared_r, NULL, NULL); + walk_tree (&t, unmark_visited_r, NULL, NULL); +} + +/* Unconditionally make an unshared copy of EXPR. This is used when using + stored expressions which span multiple functions, such as BINFO_VTABLE, + as the normal unsharing process can't tell that they're shared. */ + +tree +unshare_expr (tree expr) +{ + walk_tree (&expr, mostly_copy_tree_r, NULL, NULL); + return expr; +} + +/* A terser interface for building a representation of a exception + specification. */ + +tree +gimple_build_eh_filter (tree body, tree allowed, tree failure) +{ + tree t; + + /* FIXME should the allowed types go in TREE_TYPE? */ + t = build (EH_FILTER_EXPR, void_type_node, allowed, NULL_TREE); + append_to_statement_list (failure, &EH_FILTER_FAILURE (t)); + + t = build (TRY_CATCH_EXPR, void_type_node, NULL_TREE, t); + append_to_statement_list (body, &TREE_OPERAND (t, 0)); + + return t; +} + + +/* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both + contain statements and have a value. Assign its value to a temporary + and give it void_type_node. Returns the temporary, or NULL_TREE if + WRAPPER was already void. */ + +tree +voidify_wrapper_expr (tree wrapper) +{ + if (!VOID_TYPE_P (TREE_TYPE (wrapper))) + { + tree *p; + tree temp; + + /* Set p to point to the body of the wrapper. */ + switch (TREE_CODE (wrapper)) + { + case BIND_EXPR: + /* For a BIND_EXPR, the body is operand 1. */ + p = &BIND_EXPR_BODY (wrapper); + break; + + default: + p = &TREE_OPERAND (wrapper, 0); + break; + } + + /* Advance to the last statement. Set all container types to void. */ + if (TREE_CODE (*p) == STATEMENT_LIST) + { + tree_stmt_iterator i = tsi_last (*p); + p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i); + } + else + { + for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1)) + { + TREE_SIDE_EFFECTS (*p) = 1; + TREE_TYPE (*p) = void_type_node; + } + } + + if (p && TREE_CODE (*p) == INIT_EXPR) + { + /* The C++ frontend already did this for us. */; + temp = TREE_OPERAND (*p, 0); + } + else if (p && TREE_CODE (*p) == INDIRECT_REF) + { + /* If we're returning a dereference, move the dereference outside + the wrapper. */ + tree ptr = TREE_OPERAND (*p, 0); + temp = create_tmp_var (TREE_TYPE (ptr), "retval"); + *p = build (MODIFY_EXPR, TREE_TYPE (ptr), temp, ptr); + temp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (temp)), temp); + /* If this is a BIND_EXPR for a const inline function, it might not + have TREE_SIDE_EFFECTS set. That is no longer accurate. */ + TREE_SIDE_EFFECTS (wrapper) = 1; + } + else + { + temp = create_tmp_var (TREE_TYPE (wrapper), "retval"); + if (p && !IS_EMPTY_STMT (*p)) + { + *p = build (MODIFY_EXPR, TREE_TYPE (temp), temp, *p); + TREE_SIDE_EFFECTS (wrapper) = 1; + } + } + + TREE_TYPE (wrapper) = void_type_node; + return temp; + } + + return NULL_TREE; +} + +/* Prepare calls to builtins to SAVE and RESTORE the stack as well as + temporary through that they comunicate. */ + +static void +build_stack_save_restore (tree *save, tree *restore) +{ + tree save_call, tmp_var; + + save_call = + build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_SAVE], + NULL_TREE); + tmp_var = create_tmp_var (ptr_type_node, "saved_stack"); + + *save = build (MODIFY_EXPR, ptr_type_node, tmp_var, save_call); + *restore = + build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_RESTORE], + tree_cons (NULL_TREE, tmp_var, NULL_TREE)); +} + +/* Gimplify a BIND_EXPR. Just voidify and recurse. */ + +static enum gimplify_status +gimplify_bind_expr (tree *expr_p, tree *pre_p) +{ + tree bind_expr = *expr_p; + tree temp = voidify_wrapper_expr (bind_expr); + bool old_save_stack = gimplify_ctxp->save_stack; + tree t; + + /* Mark variables seen in this bind expr. */ + for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t)) + t->decl.seen_in_bind_expr = 1; + + gimple_push_bind_expr (bind_expr); + gimplify_ctxp->save_stack = false; + + gimplify_to_stmt_list (&BIND_EXPR_BODY (bind_expr)); + + if (gimplify_ctxp->save_stack) + { + tree stack_save, stack_restore; + + /* Save stack on entry and restore it on exit. Add a try_finally + block to achieve this. Note that mudflap depends on the + format of the emitted code: see mx_register_decls(). */ + build_stack_save_restore (&stack_save, &stack_restore); + + t = build (TRY_FINALLY_EXPR, void_type_node, + BIND_EXPR_BODY (bind_expr), NULL_TREE); + append_to_statement_list (stack_restore, &TREE_OPERAND (t, 1)); + + BIND_EXPR_BODY (bind_expr) = NULL_TREE; + append_to_statement_list (stack_save, &BIND_EXPR_BODY (bind_expr)); + append_to_statement_list (t, &BIND_EXPR_BODY (bind_expr)); + } + + gimplify_ctxp->save_stack = old_save_stack; + gimple_pop_bind_expr (); + + if (temp) + { + *expr_p = temp; + append_to_statement_list (bind_expr, pre_p); + return GS_OK; + } + else + return GS_ALL_DONE; +} + +/* Gimplify a RETURN_EXPR. If the expression to be returned is not a + GIMPLE value, it is assigned to a new temporary and the statement is + re-written to return the temporary. + + PRE_P points to the list where side effects that must happen before + STMT should be stored. */ + +static enum gimplify_status +gimplify_return_expr (tree stmt, tree *pre_p) +{ + tree ret_expr = TREE_OPERAND (stmt, 0); + tree result; + + if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL) + return GS_ALL_DONE; + + if (ret_expr == error_mark_node) + return GS_ERROR; + + if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) + result = NULL_TREE; + else + { + result = TREE_OPERAND (ret_expr, 0); +#ifdef ENABLE_CHECKING + if ((TREE_CODE (ret_expr) != MODIFY_EXPR + && TREE_CODE (ret_expr) != INIT_EXPR) + || TREE_CODE (result) != RESULT_DECL) + abort (); +#endif + } + + /* We need to pass the full MODIFY_EXPR down so that special handling + can replace it with something else. */ + gimplify_stmt (&ret_expr); + + if (result == NULL_TREE) + TREE_OPERAND (stmt, 0) = NULL_TREE; + else if (ret_expr == TREE_OPERAND (stmt, 0)) + /* It was already GIMPLE. */ + return GS_ALL_DONE; + else + { + /* If there's still a MODIFY_EXPR of the RESULT_DECL after + gimplification, find it so we can put it in the RETURN_EXPR. */ + tree ret = NULL_TREE; + + if (TREE_CODE (ret_expr) == STATEMENT_LIST) + { + tree_stmt_iterator si; + for (si = tsi_start (ret_expr); !tsi_end_p (si); tsi_next (&si)) + { + tree sub = tsi_stmt (si); + if (TREE_CODE (sub) == MODIFY_EXPR + && TREE_OPERAND (sub, 0) == result) + { + ret = sub; + if (tsi_one_before_end_p (si)) + tsi_delink (&si); + else + { + /* If there were posteffects after the MODIFY_EXPR, + we need a temporary. */ + tree tmp = create_tmp_var (TREE_TYPE (result), "retval"); + TREE_OPERAND (ret, 0) = tmp; + ret = build (MODIFY_EXPR, TREE_TYPE (result), + result, tmp); + } + break; + } + } + } + + if (ret) + TREE_OPERAND (stmt, 0) = ret; + else + /* The return value must be set up some other way. Just tell + expand_return that we're returning the RESULT_DECL. */ + TREE_OPERAND (stmt, 0) = result; + } + + append_to_statement_list (ret_expr, pre_p); + return GS_ALL_DONE; +} + +/* Gimplify a LOOP_EXPR. Normally this just involves gimplifying the body + and replacing the LOOP_EXPR with goto, but if the loop contains an + EXIT_EXPR, we need to append a label for it to jump to. */ + +static enum gimplify_status +gimplify_loop_expr (tree *expr_p, tree *pre_p) +{ + tree saved_label = gimplify_ctxp->exit_label; + tree start_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + tree jump_stmt = build_and_jump (&LABEL_EXPR_LABEL (start_label)); + + append_to_statement_list (start_label, pre_p); + + gimplify_ctxp->exit_label = NULL_TREE; + + gimplify_stmt (&LOOP_EXPR_BODY (*expr_p)); + append_to_statement_list (LOOP_EXPR_BODY (*expr_p), pre_p); + + if (gimplify_ctxp->exit_label) + { + append_to_statement_list (jump_stmt, pre_p); + *expr_p = build1 (LABEL_EXPR, void_type_node, gimplify_ctxp->exit_label); + } + else + *expr_p = jump_stmt; + + gimplify_ctxp->exit_label = saved_label; + + return GS_ALL_DONE; +} + +/* Gimplify a SWITCH_EXPR, and collect a TREE_VEC of the labels it can + branch to. */ + +static enum gimplify_status +gimplify_switch_expr (tree *expr_p, tree *pre_p) +{ + tree switch_expr = *expr_p; + enum gimplify_status ret; + + ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL, + is_gimple_val, fb_rvalue); + + if (SWITCH_BODY (switch_expr)) + { + varray_type labels, saved_labels; + bool saw_default; + tree label_vec, t; + size_t i, len; + + /* If someone can be bothered to fill in the labels, they can + be bothered to null out the body too. */ + if (SWITCH_LABELS (switch_expr)) + abort (); + + saved_labels = gimplify_ctxp->case_labels; + VARRAY_TREE_INIT (gimplify_ctxp->case_labels, 8, "case_labels"); + + gimplify_to_stmt_list (&SWITCH_BODY (switch_expr)); + + labels = gimplify_ctxp->case_labels; + gimplify_ctxp->case_labels = saved_labels; + + len = VARRAY_ACTIVE_SIZE (labels); + saw_default = false; + + for (i = 0; i < len; ++i) + { + t = VARRAY_TREE (labels, i); + if (!CASE_LOW (t)) + { + saw_default = true; + break; + } + } + + label_vec = make_tree_vec (len + !saw_default); + SWITCH_LABELS (*expr_p) = label_vec; + + for (i = 0; i < len; ++i) + TREE_VEC_ELT (label_vec, i) = VARRAY_TREE (labels, i); + + append_to_statement_list (switch_expr, pre_p); + + /* If the switch has no default label, add one, so that we jump + around the switch body. */ + if (!saw_default) + { + t = build (CASE_LABEL_EXPR, void_type_node, NULL_TREE, + NULL_TREE, create_artificial_label ()); + TREE_VEC_ELT (label_vec, len) = t; + append_to_statement_list (SWITCH_BODY (switch_expr), pre_p); + *expr_p = build (LABEL_EXPR, void_type_node, CASE_LABEL (t)); + } + else + *expr_p = SWITCH_BODY (switch_expr); + + SWITCH_BODY (switch_expr) = NULL; + } + else if (!SWITCH_LABELS (switch_expr)) + abort (); + + return ret; +} + +static enum gimplify_status +gimplify_case_label_expr (tree *expr_p) +{ + tree expr = *expr_p; + if (gimplify_ctxp->case_labels) + VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, expr); + else + abort (); + *expr_p = build (LABEL_EXPR, void_type_node, CASE_LABEL (expr)); + return GS_ALL_DONE; +} + +/* Gimplify a LABELED_BLOCK_EXPR into a LABEL_EXPR following + a (possibly empty) body. */ + +static enum gimplify_status +gimplify_labeled_block_expr (tree *expr_p) +{ + tree body = LABELED_BLOCK_BODY (*expr_p); + tree label = LABELED_BLOCK_LABEL (*expr_p); + tree t; + + DECL_CONTEXT (label) = current_function_decl; + t = build (LABEL_EXPR, void_type_node, label); + if (body != NULL_TREE) + t = build (COMPOUND_EXPR, void_type_node, body, t); + *expr_p = t; + + return GS_OK; +} + +/* Gimplify a EXIT_BLOCK_EXPR into a GOTO_EXPR. */ + +static enum gimplify_status +gimplify_exit_block_expr (tree *expr_p) +{ + tree labeled_block = TREE_OPERAND (*expr_p, 0); + tree label; + + /* First operand must be a LABELED_BLOCK_EXPR, which should + already be lowered (or partially lowered) when we get here. */ +#if defined ENABLE_CHECKING + if (TREE_CODE (labeled_block) != LABELED_BLOCK_EXPR) + abort (); +#endif + + label = LABELED_BLOCK_LABEL (labeled_block); + *expr_p = build1 (GOTO_EXPR, void_type_node, label); + + return GS_OK; +} + +/* Build a GOTO to the LABEL_DECL pointed to by LABEL_P, building it first + if necessary. */ + +tree +build_and_jump (tree *label_p) +{ + if (label_p == NULL) + /* If there's nowhere to jump, just fall through. */ + return build_empty_stmt (); + + if (*label_p == NULL_TREE) + { + tree label = create_artificial_label (); + *label_p = label; + } + + return build1 (GOTO_EXPR, void_type_node, *label_p); +} + +/* Gimplify an EXIT_EXPR by converting to a GOTO_EXPR inside a COND_EXPR. + This also involves building a label to jump to and communicating it to + gimplify_loop_expr through gimplify_ctxp->exit_label. */ + +static enum gimplify_status +gimplify_exit_expr (tree *expr_p) +{ + tree cond = TREE_OPERAND (*expr_p, 0); + tree expr; + + expr = build_and_jump (&gimplify_ctxp->exit_label); + expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ()); + *expr_p = expr; + + return GS_OK; +} + +/* A helper function to be called via walk_tree. Mark all labels under *TP + as being forced. To be called for DECL_INITIAL of static variables. */ + +tree +force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +{ + if (TYPE_P (*tp)) + *walk_subtrees = 0; + if (TREE_CODE (*tp) == LABEL_DECL) + FORCED_LABEL (*tp) = 1; + + return NULL_TREE; +} + +/* Break out elements of a constructor used as an initializer into separate + MODIFY_EXPRs. + + Note that we still need to clear any elements that don't have explicit + initializers, so if not all elements are initialized we keep the + original MODIFY_EXPR, we just remove all of the constructor elements. */ + +static enum gimplify_status +gimplify_init_constructor (tree *expr_p, tree *pre_p, + tree *post_p, int want_value) +{ + tree object = TREE_OPERAND (*expr_p, 0); + tree ctor = TREE_OPERAND (*expr_p, 1); + tree type = TREE_TYPE (ctor); + enum gimplify_status ret; + tree elt_list; + + if (TREE_CODE (ctor) != CONSTRUCTOR) + return GS_UNHANDLED; + + elt_list = CONSTRUCTOR_ELTS (ctor); + + ret = GS_ALL_DONE; + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + case ARRAY_TYPE: + { + HOST_WIDE_INT i, num_elements, num_nonzero_elements; + HOST_WIDE_INT num_nonconstant_elements; + bool cleared; + + /* Aggregate types must lower constructors to initialization of + individual elements. The exception is that a CONSTRUCTOR node + with no elements indicates zero-initialization of the whole. */ + if (elt_list == NULL) + { + if (want_value) + { + *expr_p = object; + return GS_OK; + } + else + return GS_ALL_DONE; + } + + categorize_ctor_elements (ctor, &num_nonzero_elements, + &num_nonconstant_elements); + num_elements = count_type_elements (TREE_TYPE (ctor)); + + /* If a const aggregate variable is being initialized, then it + should never be a lose to promote the variable to be static. */ + if (num_nonconstant_elements == 0 + && TREE_READONLY (object) + && TREE_CODE (object) == VAR_DECL) + { + DECL_INITIAL (object) = ctor; + TREE_STATIC (object) = 1; + if (!DECL_NAME (object)) + DECL_NAME (object) = create_tmp_var_name ("C"); + walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL); + + /* ??? C++ doesn't automatically append a . to the + assembler name, and even when it does, it looks a FE private + data structures to figure out what that number should be, + which are not set for this variable. I suppose this is + important for local statics for inline functions, which aren't + "local" in the object file sense. So in order to get a unique + TU-local symbol, we must invoke the lhd version now. */ + lhd_set_decl_assembler_name (object); + + *expr_p = build_empty_stmt (); + break; + } + + /* If there are "lots" of initialized elements, and all of them + are valid address constants, then the entire initializer can + be dropped to memory, and then memcpy'd out. */ + if (num_nonconstant_elements == 0) + { + HOST_WIDE_INT size = int_size_in_bytes (type); + unsigned int align; + + /* ??? We can still get unbounded array types, at least + from the C++ front end. This seems wrong, but attempt + to work around it for now. */ + if (size < 0) + { + size = int_size_in_bytes (TREE_TYPE (object)); + if (size >= 0) + TREE_TYPE (ctor) = type = TREE_TYPE (object); + } + + /* Find the maximum alignment we can assume for the object. */ + /* ??? Make use of DECL_OFFSET_ALIGN. */ + if (DECL_P (object)) + align = DECL_ALIGN (object); + else + align = TYPE_ALIGN (type); + + if (size > 0 && !can_move_by_pieces (size, align)) + { + tree new = create_tmp_var_raw (type, "C"); + gimple_add_tmp_var (new); + TREE_STATIC (new) = 1; + TREE_READONLY (new) = 1; + DECL_INITIAL (new) = ctor; + if (align > DECL_ALIGN (new)) + { + DECL_ALIGN (new) = align; + DECL_USER_ALIGN (new) = 1; + } + walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL); + + TREE_OPERAND (*expr_p, 1) = new; + break; + } + } + + /* If there are "lots" of initialized elements, even discounting + those that are not address constants (and thus *must* be + computed at runtime), then partition the constructor into + constant and non-constant parts. Block copy the constant + parts in, then generate code for the non-constant parts. */ + /* TODO. There's code in cp/typeck.c to do this. */ + + /* If there are "lots" of zeros, then block clear the object first. */ + cleared = false; + if (num_elements - num_nonzero_elements > CLEAR_RATIO + && num_nonzero_elements < num_elements/4) + cleared = true; + + /* ??? This bit ought not be needed. For any element not present + in the initializer, we should simply set them to zero. Except + we'd need to *find* the elements that are not present, and that + requires trickery to avoid quadratic compile-time behaviour in + large cases or excessive memory use in small cases. */ + else + { + HOST_WIDE_INT len = list_length (elt_list); + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree nelts = array_type_nelts (type); + if (!host_integerp (nelts, 1) + || tree_low_cst (nelts, 1) != len) + cleared = 1;; + } + else if (len != fields_length (type)) + cleared = 1; + } + + if (cleared) + { + CONSTRUCTOR_ELTS (ctor) = NULL_TREE; + append_to_statement_list (*expr_p, pre_p); + } + + for (i = 0; elt_list; i++, elt_list = TREE_CHAIN (elt_list)) + { + tree purpose, value, cref, init; + + purpose = TREE_PURPOSE (elt_list); + value = TREE_VALUE (elt_list); + + if (cleared && initializer_zerop (value)) + continue; + + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object))); + + /* ??? Here's to hoping the front end fills in all of the + indicies, so we don't have to figure out what's missing + ourselves. */ + if (!purpose) + abort (); + /* ??? Need to handle this. */ + if (TREE_CODE (purpose) == RANGE_EXPR) + abort (); + + cref = build (ARRAY_REF, t, object, purpose); + } + else + { + cref = build (COMPONENT_REF, TREE_TYPE (purpose), + object, purpose); + } + + init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value); + /* Each member initialization is a full-expression. */ + gimplify_stmt (&init); + append_to_statement_list (init, pre_p); + } + + *expr_p = build_empty_stmt (); + } + break; + + case COMPLEX_TYPE: + { + tree r, i; + + /* Extract the real and imaginary parts out of the ctor. */ + r = i = NULL_TREE; + if (elt_list) + { + r = TREE_VALUE (elt_list); + elt_list = TREE_CHAIN (elt_list); + if (elt_list) + { + i = TREE_VALUE (elt_list); + if (TREE_CHAIN (elt_list)) + abort (); + } + } + if (r == NULL || i == NULL) + { + tree zero = convert (TREE_TYPE (type), integer_zero_node); + if (r == NULL) + r = zero; + if (i == NULL) + i = zero; + } + + /* Complex types have either COMPLEX_CST or COMPLEX_EXPR to + represent creation of a complex value. */ + if (TREE_CONSTANT (r) && TREE_CONSTANT (i)) + { + ctor = build_complex (type, r, i); + TREE_OPERAND (*expr_p, 1) = ctor; + } + else + { + ctor = build (COMPLEX_EXPR, type, r, i); + TREE_OPERAND (*expr_p, 1) = ctor; + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, + is_gimple_rhs, fb_rvalue); + } + } + break; + + case VECTOR_TYPE: + /* Go ahead and simplify constant constructors to VECTOR_CST. */ + if (TREE_CONSTANT (ctor)) + TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list); + else + { + /* Vector types use CONSTRUCTOR all the way through gimple + compilation as a general initializer. */ + for (; elt_list; elt_list = TREE_CHAIN (elt_list)) + { + enum gimplify_status tret; + tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p, + is_gimple_constructor_elt, fb_rvalue); + if (tret == GS_ERROR) + ret = GS_ERROR; + } + } + break; + + default: + /* So how did we get a CONSTRUCTOR for a scalar type? */ + abort (); + } + + if (ret == GS_ERROR) + return GS_ERROR; + else if (want_value) + { + append_to_statement_list (*expr_p, pre_p); + *expr_p = object; + return GS_OK; + } + else + return GS_ALL_DONE; +} + +/* *EXPR_P is a COMPONENT_REF being used as an rvalue. If its type is + different from its canonical type, wrap the whole thing inside a + NOP_EXPR and force the type of the COMPONENT_REF to be the canonical + type. + + The canonical type of a COMPONENT_REF is the type of the field being + referenced--unless the field is a bit-field which can be read directly + in a smaller mode, in which case the canonical type is the + sign-appropriate type corresponding to that mode. */ + +static void +canonicalize_component_ref (tree *expr_p) +{ + tree expr = *expr_p; + tree type; + + if (TREE_CODE (expr) != COMPONENT_REF) + abort (); + + if (INTEGRAL_TYPE_P (TREE_TYPE (expr))) + type = TREE_TYPE (get_unwidened (expr, NULL_TREE)); + else + type = TREE_TYPE (TREE_OPERAND (expr, 1)); + + if (TREE_TYPE (expr) != type) + { + tree old_type = TREE_TYPE (expr); + + /* Set the type of the COMPONENT_REF to the underlying type. */ + TREE_TYPE (expr) = type; + + /* And wrap the whole thing inside a NOP_EXPR. */ + expr = build1 (NOP_EXPR, old_type, expr); + + *expr_p = expr; + } +} + +/* If a NOP conversion is changing a pointer to array of foo to a pointer + to foo, embed that change in the ADDR_EXPR. Lest we perturb the type + system too badly, we must take extra steps to ensure that the ADDR_EXPR + and the addressed object continue to agree on types. */ +/* ??? We might could do better if we recognize + T array[N][M]; + (T *)&array + ==> + &array[0][0]; +*/ + +static void +canonicalize_addr_expr (tree* expr_p) +{ + tree expr = *expr_p; + tree ctype = TREE_TYPE (expr); + tree addr_expr = TREE_OPERAND (expr, 0); + tree atype = TREE_TYPE (addr_expr); + tree dctype, datype, ddatype, otype, obj_expr; + + /* Both cast and addr_expr types should be pointers. */ + if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype)) + return; + + /* The addr_expr type should be a pointer to an array. */ + datype = TREE_TYPE (atype); + if (TREE_CODE (datype) != ARRAY_TYPE) + return; + + /* Both cast and addr_expr types should address the same object type. */ + dctype = TREE_TYPE (ctype); + ddatype = TREE_TYPE (datype); + if (!lang_hooks.types_compatible_p (ddatype, dctype)) + return; + + /* The addr_expr and the object type should match. */ + obj_expr = TREE_OPERAND (addr_expr, 0); + otype = TREE_TYPE (obj_expr); + if (!lang_hooks.types_compatible_p (otype, datype)) + return; + + /* All checks succeeded. Build a new node to merge the cast. */ + *expr_p = build1 (ADDR_EXPR, ctype, obj_expr); +} + +/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions + underneath as appropriate. */ + +static enum gimplify_status +gimplify_conversion (tree *expr_p) +{ + /* Strip away as many useless type conversions as possible + at the toplevel. */ + STRIP_USELESS_TYPE_CONVERSION (*expr_p); + + /* If we still have a conversion at the toplevel, then strip + away all but the outermost conversion. */ + if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR) + { + STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0)); + + /* And remove the outermost conversion if it's useless. */ + if (tree_ssa_useless_type_conversion (*expr_p)) + *expr_p = TREE_OPERAND (*expr_p, 0); + } + + /* If we still have a conversion at the toplevel, + then canonicalize some constructs. */ + if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR) + { + tree sub = TREE_OPERAND (*expr_p, 0); + + /* If a NOP conversion is changing the type of a COMPONENT_REF + expression, then canonicalize its type now in order to expose more + redundant conversions. */ + if (TREE_CODE (sub) == COMPONENT_REF) + canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0)); + + /* If a NOP conversion is changing a pointer to array of foo + to a pointer to foo, embed that change in the ADDR_EXPR. */ + else if (TREE_CODE (sub) == ADDR_EXPR) + canonicalize_addr_expr (expr_p); + } + + return GS_OK; +} + +/* Reduce MIN/MAX_EXPR to a COND_EXPR for further gimplification. */ + +static enum gimplify_status +gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree op1 = TREE_OPERAND (*expr_p, 0); + tree op2 = TREE_OPERAND (*expr_p, 1); + enum tree_code code; + enum gimplify_status r0, r1; + + if (TREE_CODE (*expr_p) == MIN_EXPR) + code = LE_EXPR; + else + code = GE_EXPR; + + r0 = gimplify_expr (&op1, pre_p, post_p, is_gimple_val, fb_rvalue); + r1 = gimplify_expr (&op2, pre_p, post_p, is_gimple_val, fb_rvalue); + + *expr_p = build (COND_EXPR, TREE_TYPE (*expr_p), + build (code, boolean_type_node, op1, op2), + op1, op2); + + if (r0 == GS_ERROR || r1 == GS_ERROR) + return GS_ERROR; + else + return GS_OK; +} + +/* Build an expression for the address of T. Folds away INDIRECT_REF to + avoid confusing the gimplify process. */ + +static tree +build_addr_expr_with_type (tree t, tree ptrtype) +{ + if (TREE_CODE (t) == INDIRECT_REF) + { + t = TREE_OPERAND (t, 0); + if (TREE_TYPE (t) != ptrtype) + t = build1 (NOP_EXPR, ptrtype, t); + } + else + { + tree base = t; + while (TREE_CODE (base) == COMPONENT_REF + || TREE_CODE (base) == ARRAY_REF) + base = TREE_OPERAND (base, 0); + if (DECL_P (base)) + TREE_ADDRESSABLE (base) = 1; + + t = build1 (ADDR_EXPR, ptrtype, t); + } + + return t; +} + +static tree +build_addr_expr (tree t) +{ + return build_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t))); +} + +/* Subroutine of gimplify_compound_lval and gimplify_array_ref. + Converts an ARRAY_REF to the equivalent *(&array + offset) form. */ + +static enum gimplify_status +gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree array = TREE_OPERAND (*expr_p, 0); + tree arrtype = TREE_TYPE (array); + tree elttype = TREE_TYPE (arrtype); + tree size = size_in_bytes (elttype); + tree ptrtype = build_pointer_type (elttype); + enum tree_code add_code = PLUS_EXPR; + tree idx = TREE_OPERAND (*expr_p, 1); + tree minidx, offset, addr, result; + enum gimplify_status ret; + + /* If the array domain does not start at zero, apply the offset. */ + minidx = TYPE_DOMAIN (arrtype); + if (minidx) + { + minidx = TYPE_MIN_VALUE (minidx); + if (minidx && !integer_zerop (minidx)) + { + idx = convert (TREE_TYPE (minidx), idx); + idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx)); + } + } + + /* If the index is negative -- a technically invalid situation now + that we've biased the index back to zero -- then casting it to + unsigned has ill effects. In particular, -1*4U/4U != -1. + Represent this as a subtraction of a positive rather than addition + of a negative. This will prevent any conversion back to ARRAY_REF + from getting the wrong results from the division. */ + if (TREE_CODE (idx) == INTEGER_CST && tree_int_cst_sgn (idx) < 0) + { + idx = fold (build1 (NEGATE_EXPR, TREE_TYPE (idx), idx)); + add_code = MINUS_EXPR; + } + + /* Pointer arithmetic must be done in sizetype. */ + idx = convert (sizetype, idx); + + /* Convert the index to a byte offset. */ + offset = size_binop (MULT_EXPR, size, idx); + + ret = gimplify_expr (&array, pre_p, post_p, is_gimple_min_lval, fb_lvalue); + if (ret == GS_ERROR) + return ret; + + addr = build_addr_expr_with_type (array, ptrtype); + result = fold (build (add_code, ptrtype, addr, offset)); + *expr_p = build1 (INDIRECT_REF, elttype, result); + + return GS_OK; +} + +/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR + node pointed by EXPR_P. + + compound_lval + : min_lval '[' val ']' + | min_lval '.' ID + | compound_lval '[' val ']' + | compound_lval '.' ID + + This is not part of the original SIMPLE definition, which separates + array and member references, but it seems reasonable to handle them + together. Also, this way we don't run into problems with union + aliasing; gcc requires that for accesses through a union to alias, the + union reference must be explicit, which was not always the case when we + were splitting up array and member refs. + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. + + POST_P points to the list where side effects that must happen after + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_compound_lval (tree *expr_p, tree *pre_p, + tree *post_p, int want_lvalue) +{ + tree *p; + enum tree_code code; + varray_type stack; + enum gimplify_status ret; + +#if defined ENABLE_CHECKING + if (TREE_CODE (*expr_p) != ARRAY_REF + && TREE_CODE (*expr_p) != COMPONENT_REF + && TREE_CODE (*expr_p) != REALPART_EXPR + && TREE_CODE (*expr_p) != IMAGPART_EXPR) + abort (); +#endif + + code = ERROR_MARK; /* [GIMPLE] Avoid uninitialized use warning. */ + + /* Create a stack of the subexpressions so later we can walk them in + order from inner to outer. */ + VARRAY_TREE_INIT (stack, 10, "stack"); + + for (p = expr_p; + TREE_CODE (*p) == ARRAY_REF + || TREE_CODE (*p) == COMPONENT_REF + || TREE_CODE (*p) == REALPART_EXPR + || TREE_CODE (*p) == IMAGPART_EXPR; + p = &TREE_OPERAND (*p, 0)) + { + code = TREE_CODE (*p); + if (code == ARRAY_REF) + { + tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*p, 0))); + if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype))) + /* If the size of the array elements is not constant, + computing the offset is non-trivial, so expose it. */ + break; + } + VARRAY_PUSH_TREE (stack, *p); + } + + /* Now 'p' points to the first bit that isn't a ref, 'code' is the + TREE_CODE of the last bit that was, and 'stack' is a stack of pointers + to all the refs we've walked through. + + Gimplify the base, and then process each of the outer nodes from left + to right. */ + ret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, + code != ARRAY_REF ? fb_either : fb_lvalue); + + for (; VARRAY_ACTIVE_SIZE (stack) > 0; ) + { + tree t = VARRAY_TOP_TREE (stack); + if (TREE_CODE (t) == ARRAY_REF) + { + /* Gimplify the dimension. */ + enum gimplify_status tret; + /* Temporary fix for gcc.c-torture/execute/20040313-1.c. + Gimplify non-constant array indices into a temporary + variable. + FIXME - The real fix is to gimplify post-modify + expressions into a minimal gimple lvalue. However, that + exposes bugs in alias analysis. The alias analyzer does + not handle &PTR->FIELD very well. Will fix after the + branch is merged into mainline (dnovillo 2004-05-03). */ + if (!is_gimple_min_invariant (TREE_OPERAND (t, 1))) + { + tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p, + is_gimple_tmp_var, fb_rvalue); + if (tret == GS_ERROR) + ret = GS_ERROR; + } + } + recalculate_side_effects (t); + VARRAY_POP (stack); + } + + /* If the outermost expression is a COMPONENT_REF, canonicalize its type. */ + if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF) + { + canonicalize_component_ref (expr_p); + ret = MIN (ret, GS_OK); + } + + return ret; +} + +/* Re-write the ARRAY_REF node pointed by EXPR_P. + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. + + POST_P points to the list where side effects that must happen after + *EXPR_P should be stored. + + FIXME: ARRAY_REF currently doesn't accept a pointer as the array + argument, so this gimplification uses an INDIRECT_REF of ARRAY_TYPE. + ARRAY_REF should be extended. */ + +static enum gimplify_status +gimplify_array_ref (tree *expr_p, tree *pre_p, + tree *post_p, int want_lvalue) +{ + tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*expr_p, 0))); + if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype))) + /* If the size of the array elements is not constant, + computing the offset is non-trivial, so expose it. */ + return gimplify_array_ref_to_plus (expr_p, pre_p, post_p); + else + /* Handle array and member refs together for now. When alias analysis + improves, we may want to go back to handling them separately. */ + return gimplify_compound_lval (expr_p, pre_p, post_p, want_lvalue); +} + +/* Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=). + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. + + POST_P points to the list where side effects that must happen after + *EXPR_P should be stored. + + WANT_VALUE is nonzero iff we want to use the value of this expression + in another expression. */ + +static enum gimplify_status +gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p, + int want_value) +{ + enum tree_code code; + tree lhs, lvalue, rhs, t1; + bool postfix; + enum tree_code arith_code; + enum gimplify_status ret; + + code = TREE_CODE (*expr_p); + +#if defined ENABLE_CHECKING + if (code != POSTINCREMENT_EXPR + && code != POSTDECREMENT_EXPR + && code != PREINCREMENT_EXPR + && code != PREDECREMENT_EXPR) + abort (); +#endif + + /* Prefix or postfix? */ + if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR) + /* Faster to treat as prefix if result is not used. */ + postfix = want_value; + else + postfix = false; + + /* Add or subtract? */ + if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) + arith_code = PLUS_EXPR; + else + arith_code = MINUS_EXPR; + + /* Gimplify the LHS into a GIMPLE lvalue. */ + lvalue = TREE_OPERAND (*expr_p, 0); + ret = gimplify_expr (&lvalue, pre_p, post_p, is_gimple_lvalue, fb_lvalue); + if (ret == GS_ERROR) + return ret; + + /* Extract the operands to the arithmetic operation. */ + lhs = lvalue; + rhs = TREE_OPERAND (*expr_p, 1); + + /* For postfix operator, we evaluate the LHS to an rvalue and then use + that as the result value and in the postqueue operation. */ + if (postfix) + { + ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue); + if (ret == GS_ERROR) + return ret; + } + + t1 = build (arith_code, TREE_TYPE (*expr_p), lhs, rhs); + t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1); + + if (postfix) + { + gimplify_stmt (&t1); + append_to_statement_list (t1, post_p); + *expr_p = lhs; + return GS_ALL_DONE; + } + else + { + *expr_p = t1; + return GS_OK; + } +} + +/* Gimplify the CALL_EXPR node pointed by EXPR_P. + + call_expr + : ID '(' arglist ')' + + arglist + : arglist ',' val + | val + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree)) +{ + tree decl; + tree arglist; + enum gimplify_status ret; + +#if defined ENABLE_CHECKING + if (TREE_CODE (*expr_p) != CALL_EXPR) + abort (); +#endif + + /* For reliable diagnostics during inlining, it is necessary that + every call_expr be annotated with file and line. */ + if (!EXPR_LOCUS (*expr_p)) + annotate_with_locus (*expr_p, input_location); + + /* This may be a call to a builtin function. + + Builtin function calls may be transformed into different + (and more efficient) builtin function calls under certain + circumstances. Unfortunately, gimplification can muck things + up enough that the builtin expanders are not aware that certain + transformations are still valid. + + So we attempt transformation/gimplification of the call before + we gimplify the CALL_EXPR. At this time we do not manage to + transform all calls in the same manner as the expanders do, but + we do transform most of them. */ + decl = get_callee_fndecl (*expr_p); + if (decl && DECL_BUILT_IN (decl)) + { + tree new; + + /* If it is allocation of stack, record the need to restore the memory + when the enclosing bind_expr is exited. */ + if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_ALLOC) + gimplify_ctxp->save_stack = true; + + /* If it is restore of the stack, reset it, since it means we are + regimplifying the bind_expr. Note that we use the fact that + for try_finally_expr, try part is processed first. */ + if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_RESTORE) + gimplify_ctxp->save_stack = false; + + new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt); + + if (new && new != *expr_p) + { + /* There was a transformation of this call which computes the + same value, but in a more efficient way. Return and try + again. */ + *expr_p = new; + return GS_OK; + } + } + + /* There is a sequence point before the call, so any side effects in + the calling expression must occur before the actual call. Force + gimplify_expr to use an internal post queue. */ + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL, + is_gimple_val, fb_rvalue); + + if (PUSH_ARGS_REVERSED) + TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1)); + for (arglist = TREE_OPERAND (*expr_p, 1); arglist; + arglist = TREE_CHAIN (arglist)) + { + enum gimplify_status t; + + /* There is a sequence point before a function call. Side effects in + the argument list must occur before the actual call. So, when + gimplifying arguments, force gimplify_expr to use an internal + post queue which is then appended to the end of PRE_P. */ + t = gimplify_expr (&TREE_VALUE (arglist), pre_p, NULL, is_gimple_val, + fb_rvalue); + + if (t == GS_ERROR) + ret = GS_ERROR; + } + if (PUSH_ARGS_REVERSED) + TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1)); + + /* Try this again in case gimplification exposed something. */ + if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl)) + { + tree new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt); + + if (new && new != *expr_p) + { + /* There was a transformation of this call which computes the + same value, but in a more efficient way. Return and try + again. */ + *expr_p = new; + return GS_OK; + } + } + + /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its + decl. This allows us to eliminate redundant or useless + calls to "const" functions. */ + if (TREE_CODE (*expr_p) == CALL_EXPR + && (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE))) + TREE_SIDE_EFFECTS (*expr_p) = 0; + + return ret; +} + +/* Handle shortcut semantics in the predicate operand of a COND_EXPR by + rewriting it into multiple COND_EXPRs, and possibly GOTO_EXPRs. + + TRUE_LABEL_P and FALSE_LABEL_P point to the labels to jump to if the + condition is true or false, respectively. If null, we should generate + our own to skip over the evaluation of this specific expression. + + This function is the tree equivalent of do_jump. + + shortcut_cond_r should only be called by shortcut_cond_expr. */ + +static tree +shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p) +{ + tree local_label = NULL_TREE; + tree t, expr = NULL; + + /* OK, it's not a simple case; we need to pull apart the COND_EXPR to + retain the shortcut semantics. Just insert the gotos here; + shortcut_cond_expr will append the real blocks later. */ + if (TREE_CODE (pred) == TRUTH_ANDIF_EXPR) + { + /* Turn if (a && b) into + + if (a); else goto no; + if (b) goto yes; else goto no; + (no:) */ + + if (false_label_p == NULL) + false_label_p = &local_label; + + t = shortcut_cond_r (TREE_OPERAND (pred, 0), NULL, false_label_p); + append_to_statement_list (t, &expr); + + t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, + false_label_p); + append_to_statement_list (t, &expr); + } + else if (TREE_CODE (pred) == TRUTH_ORIF_EXPR) + { + /* Turn if (a || b) into + + if (a) goto yes; + if (b) goto yes; else goto no; + (yes:) */ + + if (true_label_p == NULL) + true_label_p = &local_label; + + t = shortcut_cond_r (TREE_OPERAND (pred, 0), true_label_p, NULL); + append_to_statement_list (t, &expr); + + t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, + false_label_p); + append_to_statement_list (t, &expr); + } + else if (TREE_CODE (pred) == COND_EXPR) + { + /* As long as we're messing with gotos, turn if (a ? b : c) into + if (a) + if (b) goto yes; else goto no; + else + if (c) goto yes; else goto no; */ + expr = build (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0), + shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p, + false_label_p), + shortcut_cond_r (TREE_OPERAND (pred, 2), true_label_p, + false_label_p)); + } + else + { + expr = build (COND_EXPR, void_type_node, pred, + build_and_jump (true_label_p), + build_and_jump (false_label_p)); + } + + if (local_label) + { + t = build1 (LABEL_EXPR, void_type_node, local_label); + append_to_statement_list (t, &expr); + } + + return expr; +} + +static tree +shortcut_cond_expr (tree expr) +{ + tree pred = TREE_OPERAND (expr, 0); + tree then_ = TREE_OPERAND (expr, 1); + tree else_ = TREE_OPERAND (expr, 2); + tree true_label, false_label, end_label, t; + tree *true_label_p; + tree *false_label_p; + bool emit_end, emit_false; + + /* First do simple transformations. */ + if (!TREE_SIDE_EFFECTS (else_)) + { + /* If there is no 'else', turn (a && b) into if (a) if (b). */ + while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR) + { + TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); + then_ = shortcut_cond_expr (expr); + pred = TREE_OPERAND (pred, 0); + expr = build (COND_EXPR, void_type_node, pred, then_, + build_empty_stmt ()); + } + } + if (!TREE_SIDE_EFFECTS (then_)) + { + /* If there is no 'then', turn + if (a || b); else d + into + if (a); else if (b); else d. */ + while (TREE_CODE (pred) == TRUTH_ORIF_EXPR) + { + TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1); + else_ = shortcut_cond_expr (expr); + pred = TREE_OPERAND (pred, 0); + expr = build (COND_EXPR, void_type_node, pred, + build_empty_stmt (), else_); + } + } + + /* If we're done, great. */ + if (TREE_CODE (pred) != TRUTH_ANDIF_EXPR + && TREE_CODE (pred) != TRUTH_ORIF_EXPR) + return expr; + + /* Otherwise we need to mess with gotos. Change + if (a) c; else d; + to + if (a); else goto no; + c; goto end; + no: d; end: + and recursively gimplify the condition. */ + + true_label = false_label = end_label = NULL_TREE; + + /* If our arms just jump somewhere, hijack those labels so we don't + generate jumps to jumps. */ + + if (TREE_CODE (then_) == GOTO_EXPR + && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL) + { + true_label = GOTO_DESTINATION (then_); + then_ = build_empty_stmt (); + } + + if (TREE_CODE (else_) == GOTO_EXPR + && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL) + { + false_label = GOTO_DESTINATION (else_); + else_ = build_empty_stmt (); + } + + /* If we aren't hijacking a label for the 'then' branch, it falls through. */ + if (true_label) + true_label_p = &true_label; + else + true_label_p = NULL; + + /* The 'else' branch also needs a label if it contains interesting code. */ + if (false_label || TREE_SIDE_EFFECTS (else_)) + false_label_p = &false_label; + else + false_label_p = NULL; + + /* If there was nothing else in our arms, just forward the label(s). */ + if (!TREE_SIDE_EFFECTS (then_) && !TREE_SIDE_EFFECTS (else_)) + return shortcut_cond_r (pred, true_label_p, false_label_p); + + /* If our last subexpression already has a terminal label, reuse it. */ + if (TREE_SIDE_EFFECTS (else_)) + expr = expr_last (else_); + else + expr = expr_last (then_); + if (TREE_CODE (expr) == LABEL_EXPR) + end_label = LABEL_EXPR_LABEL (expr); + + /* If we don't care about jumping to the 'else' branch, jump to the end + if the condition is false. */ + if (!false_label_p) + false_label_p = &end_label; + + /* We only want to emit these labels if we aren't hijacking them. */ + emit_end = (end_label == NULL_TREE); + emit_false = (false_label == NULL_TREE); + + pred = shortcut_cond_r (pred, true_label_p, false_label_p); + + expr = NULL; + append_to_statement_list (pred, &expr); + + append_to_statement_list (then_, &expr); + if (TREE_SIDE_EFFECTS (else_)) + { + t = build_and_jump (&end_label); + append_to_statement_list (t, &expr); + if (emit_false) + { + t = build1 (LABEL_EXPR, void_type_node, false_label); + append_to_statement_list (t, &expr); + } + append_to_statement_list (else_, &expr); + } + if (emit_end && end_label) + { + t = build1 (LABEL_EXPR, void_type_node, end_label); + append_to_statement_list (t, &expr); + } + + return expr; +} + +/* EXPR is used in a boolean context; make sure it has BOOLEAN_TYPE. */ + +static tree +gimple_boolify (tree expr) +{ + tree type = TREE_TYPE (expr); + + if (TREE_CODE (type) == BOOLEAN_TYPE) + return expr; + + /* If this is the predicate of a COND_EXPR, it might not even be a + truthvalue yet. */ + expr = (*lang_hooks.truthvalue_conversion) (expr); + + switch (TREE_CODE (expr)) + { + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + /* Also boolify the arguments of truth exprs. */ + TREE_OPERAND (expr, 1) = gimple_boolify (TREE_OPERAND (expr, 1)); + /* FALLTHRU */ + + case TRUTH_NOT_EXPR: + TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); + /* FALLTHRU */ + + case EQ_EXPR: case NE_EXPR: + case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: + /* These expressions always produce boolean results. */ + TREE_TYPE (expr) = boolean_type_node; + return expr; + + default: + /* Other expressions that get here must have boolean values, but + might need to be converted to the appropriate mode. */ + return convert (boolean_type_node, expr); + } +} + +/* Convert the conditional expression pointed by EXPR_P '(p) ? a : b;' + into + + if (p) if (p) + t1 = a; a; + else or else + t1 = b; b; + t1; + + The second form is used when *EXPR_P is of type void. + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target) +{ + tree expr = *expr_p; + tree tmp; + enum gimplify_status ret; + + /* If this COND_EXPR has a value, copy the values into a temporary within + the arms. */ + if (! VOID_TYPE_P (TREE_TYPE (expr))) + { + if (target) + { + tmp = target; + ret = GS_OK; + } + else + { + tmp = create_tmp_var (TREE_TYPE (expr), "iftmp"); + ret = GS_ALL_DONE; + } + + /* Build the then clause, 't1 = a;'. But don't build an assignment + if this branch is void; in C++ it can be, if it's a throw. */ + if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node) + TREE_OPERAND (expr, 1) + = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1)); + + /* Build the else clause, 't1 = b;'. */ + if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node) + TREE_OPERAND (expr, 2) + = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2)); + + TREE_TYPE (expr) = void_type_node; + recalculate_side_effects (expr); + + /* Move the COND_EXPR to the prequeue and use the temp in its place. */ + gimplify_stmt (&expr); + append_to_statement_list (expr, pre_p); + *expr_p = tmp; + + return ret; + } + + /* Make sure the condition has BOOLEAN_TYPE. */ + TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); + + /* Break apart && and || conditions. */ + if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR + || TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR) + { + expr = shortcut_cond_expr (expr); + + if (expr != *expr_p) + { + *expr_p = expr; + + /* We can't rely on gimplify_expr to re-gimplify the expanded + form properly, as cleanups might cause the target labels to be + wrapped in a TRY_FINALLY_EXPR. To prevent that, we need to + set up a conditional context. */ + gimple_push_condition (); + gimplify_stmt (expr_p); + gimple_pop_condition (pre_p); + + return GS_ALL_DONE; + } + } + + /* Now do the normal gimplification. */ + ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, + is_gimple_condexpr, fb_rvalue); + + gimple_push_condition (); + + gimplify_to_stmt_list (&TREE_OPERAND (expr, 1)); + gimplify_to_stmt_list (&TREE_OPERAND (expr, 2)); + recalculate_side_effects (expr); + + gimple_pop_condition (pre_p); + + if (ret == GS_ERROR) + ; + else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) + ret = GS_ALL_DONE; + else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2))) + /* Rewrite "if (a); else b" to "if (!a) b" */ + { + TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0)); + ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, + is_gimple_condexpr, fb_rvalue); + + tmp = TREE_OPERAND (expr, 1); + TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2); + TREE_OPERAND (expr, 2) = tmp; + } + else + /* Both arms are empty; replace the COND_EXPR with its predicate. */ + expr = TREE_OPERAND (expr, 0); + + *expr_p = expr; + return ret; +} + +/* Gimplify the MODIFY_EXPR node pointed by EXPR_P. + + modify_expr + : varname '=' rhs + | '*' ID '=' rhs + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. + + POST_P points to the list where side effects that must happen after + *EXPR_P should be stored. + + WANT_VALUE is nonzero iff we want to use the value of this expression + in another expression. */ + +static enum gimplify_status +gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) +{ + tree *from_p = &TREE_OPERAND (*expr_p, 1); + tree *to_p = &TREE_OPERAND (*expr_p, 0); + enum gimplify_status ret; + +#if defined ENABLE_CHECKING + if (TREE_CODE (*expr_p) != MODIFY_EXPR && TREE_CODE (*expr_p) != INIT_EXPR) + abort (); +#endif + + /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful. */ + if (TREE_CODE (*expr_p) == INIT_EXPR) + TREE_SET_CODE (*expr_p, MODIFY_EXPR); + + ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue); + if (ret == GS_ERROR) + return ret; + + /* If we are initializing something from a TARGET_EXPR, strip the + TARGET_EXPR and initialize it directly. */ + /* What about code that pulls out the temp and uses it elsewhere? I + think that such code never uses the TARGET_EXPR as an initializer. If + I'm wrong, we'll abort because the temp won't have any RTL. In that + case, I guess we'll need to replace references somehow. */ + if (TREE_CODE (*from_p) == TARGET_EXPR) + *from_p = TARGET_EXPR_INITIAL (*from_p); + + /* If we're assigning from a ?: expression with ADDRESSABLE type, push + the assignment down into the branches, since we can't generate a + temporary of such a type. */ + if (TREE_CODE (*from_p) == COND_EXPR + && TREE_ADDRESSABLE (TREE_TYPE (*from_p))) + { + *expr_p = *from_p; + return gimplify_cond_expr (expr_p, pre_p, *to_p); + } + + ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_rhs, fb_rvalue); + if (ret == GS_ERROR) + return ret; + + ret = gimplify_init_constructor (expr_p, pre_p, post_p, want_value); + if (ret != GS_UNHANDLED) + return ret; + + /* If the destination is already simple, nothing else needed. */ + if (is_gimple_tmp_var (*to_p)) + ret = GS_ALL_DONE; + else + { + /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto and + the LHS is a user variable, then we need to introduce a temporary. + ie temp = RHS; LHS = temp. + + This way the optimizers can determine that the user variable is + only modified if evaluation of the RHS does not throw. + + FIXME this should be handled by the is_gimple_rhs predicate. */ + + if (TREE_CODE (*from_p) == CALL_EXPR + || (flag_non_call_exceptions && tree_could_trap_p (*from_p)) + /* If we're dealing with a renamable type, either source or dest + must be a renamed variable. */ + || (is_gimple_reg_type (TREE_TYPE (*from_p)) + && !is_gimple_reg (*to_p))) + gimplify_expr (from_p, pre_p, post_p, is_gimple_val, fb_rvalue); + + /* If the value being copied is of variable width, expose the length + if the copy by converting the whole thing to a memcpy. */ + /* ??? Except that we can't manage this with VA_ARG_EXPR. Yes, this + does leave us with an edge condition that doesn't work. The only + way out is to rearrange how VA_ARG_EXPR works. */ + if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST + && TREE_CODE (*from_p) != VA_ARG_EXPR) + { + tree args, t, dest; + + t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p)); + args = tree_cons (NULL, t, NULL); + t = build_addr_expr (*from_p); + args = tree_cons (NULL, t, args); + dest = build_addr_expr (*to_p); + args = tree_cons (NULL, dest, args); + t = implicit_built_in_decls[BUILT_IN_MEMCPY]; + t = build_function_call_expr (t, args); + if (want_value) + { + t = build1 (NOP_EXPR, TREE_TYPE (dest), t); + t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t); + } + *expr_p = t; + + return GS_OK; + } + + ret = want_value ? GS_OK : GS_ALL_DONE; + } + + if (want_value) + { + append_to_statement_list (*expr_p, pre_p); + *expr_p = *to_p; + } + + return ret; +} + +/* Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions. EXPR_P + points to the expression to gimplify. + + Expressions of the form 'a && b' are gimplified to: + + a && b ? true : false + + gimplify_cond_expr will do the rest. + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_boolean_expr (tree *expr_p) +{ + /* Preserve the original type of the expression. */ + tree type = TREE_TYPE (*expr_p); + + *expr_p = build (COND_EXPR, type, *expr_p, + convert (type, boolean_true_node), + convert (type, boolean_false_node)); + + return GS_OK; +} + +/* Gimplifies an expression sequence. This function gimplifies each + expression and re-writes the original expression with the last + expression of the sequence in GIMPLE form. + + PRE_P points to the list where the side effects for all the + expressions in the sequence will be emitted. + + WANT_VALUE is true when the result of the last COMPOUND_EXPR is used. */ +/* ??? Should rearrange to share the pre-queue with all the indirect + invocations of gimplify_expr. Would probably save on creations + of statement_list nodes. */ + +static enum gimplify_status +gimplify_compound_expr (tree *expr_p, tree *pre_p, bool want_value) +{ + tree t = *expr_p; + + do + { + tree *sub_p = &TREE_OPERAND (t, 0); + + if (TREE_CODE (*sub_p) == COMPOUND_EXPR) + gimplify_compound_expr (sub_p, pre_p, false); + else + gimplify_stmt (sub_p); + append_to_statement_list (*sub_p, pre_p); + + t = TREE_OPERAND (t, 1); + } + while (TREE_CODE (t) == COMPOUND_EXPR); + + *expr_p = t; + if (want_value) + return GS_OK; + else + { + gimplify_stmt (expr_p); + return GS_ALL_DONE; + } +} + +/* Gimplifies a statement list. These may be created either by an + enlightend front-end, or by shortcut_cond_expr. */ + +static enum gimplify_status +gimplify_statement_list (tree *expr_p) +{ + tree_stmt_iterator i = tsi_start (*expr_p); + + while (!tsi_end_p (i)) + { + tree t; + + gimplify_stmt (tsi_stmt_ptr (i)); + + t = tsi_stmt (i); + if (TREE_CODE (t) == STATEMENT_LIST) + { + tsi_link_before (&i, t, TSI_SAME_STMT); + tsi_delink (&i); + } + else + tsi_next (&i); + } + + return GS_ALL_DONE; +} + +/* Gimplify a SAVE_EXPR node. EXPR_P points to the expression to + gimplify. After gimplification, EXPR_P will point to a new temporary + that holds the original value of the SAVE_EXPR node. + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + enum gimplify_status ret = GS_ALL_DONE; + tree val; + +#if defined ENABLE_CHECKING + if (TREE_CODE (*expr_p) != SAVE_EXPR) + abort (); +#endif + + val = TREE_OPERAND (*expr_p, 0); + + /* If the operand is already a GIMPLE temporary, just re-write the + SAVE_EXPR node. */ + if (is_gimple_tmp_var (val)) + *expr_p = val; + /* The operand may be a void-valued expression such as SAVE_EXPRs + generated by the Java frontend for class initialization. It is + being executed only for its side-effects. */ + else if (TREE_TYPE (val) == void_type_node) + { + tree body = TREE_OPERAND (*expr_p, 0); + ret = gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none); + append_to_statement_list (body, pre_p); + *expr_p = build_empty_stmt (); + } + else + *expr_p = TREE_OPERAND (*expr_p, 0) + = get_initialized_tmp_var (val, pre_p, post_p); + + return ret; +} + +/* Re-write the ADDR_EXPR node pointed by EXPR_P + + unary_expr + : ... + | '&' varname + ... + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. + + POST_P points to the list where side effects that must happen after + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree expr = *expr_p; + tree op0 = TREE_OPERAND (expr, 0); + enum gimplify_status ret; + + switch (TREE_CODE (op0)) + { + case INDIRECT_REF: + /* Check if we are dealing with an expression of the form '&*ptr'. + While the front end folds away '&*ptr' into 'ptr', these + expressions may be generated internally by the compiler (e.g., + builtins like __builtin_va_end). */ + *expr_p = TREE_OPERAND (op0, 0); + ret = GS_OK; + break; + + case ARRAY_REF: + /* Fold &a[6] to (&a + 6). */ + ret = gimplify_array_ref_to_plus (&TREE_OPERAND (expr, 0), + pre_p, post_p); + + /* This added an INDIRECT_REF. Fold it away. */ + op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0); + + *expr_p = op0; + break; + + default: + /* We use fb_either here because the C frontend sometimes takes + the address of a call that returns a struct. */ + ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p, + is_gimple_addr_expr_arg, fb_either); + if (ret != GS_ERROR) + { + /* At this point, the argument of the ADDR_EXPR should be + sufficiently simple that there are never side effects. */ + /* ??? Could split out the decision code from build1 to verify. */ + TREE_SIDE_EFFECTS (expr) = 0; + + /* Make sure TREE_INVARIANT/TREE_CONSTANT is set properly. */ + recompute_tree_invarant_for_addr_expr (expr); + + /* Mark the RHS addressable. */ + (*lang_hooks.mark_addressable) (TREE_OPERAND (expr, 0)); + } + break; + } + + /* If the operand is gimplified into a _DECL, mark the address expression + as TREE_INVARIANT. */ + if (DECL_P (TREE_OPERAND (expr, 0))) + TREE_INVARIANT (expr) = 1; + + return ret; +} + +/* Gimplify the operands of an ASM_EXPR. Input operands should be a gimple + value; output operands should be a gimple lvalue. */ + +static enum gimplify_status +gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree expr = *expr_p; + int noutputs = list_length (ASM_OUTPUTS (expr)); + const char **oconstraints + = (const char **) alloca ((noutputs) * sizeof (const char *)); + int i; + tree link; + const char *constraint; + bool allows_mem, allows_reg, is_inout; + enum gimplify_status ret, tret; + + ASM_STRING (expr) + = resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr), + ASM_INPUTS (expr)); + + ret = GS_ALL_DONE; + for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = TREE_CHAIN (link)) + { + oconstraints[i] = constraint + = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); + + parse_output_constraint (&constraint, i, 0, 0, + &allows_mem, &allows_reg, &is_inout); + + if (!allows_reg && allows_mem) + (*lang_hooks.mark_addressable) (TREE_VALUE (link)); + + tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, + is_inout ? is_gimple_min_lval : is_gimple_lvalue, + fb_lvalue | fb_mayfail); + if (tret == GS_ERROR) + { + error ("invalid lvalue in asm output %d", i); + ret = tret; + } + + if (is_inout) + { + /* An input/output operand. To give the optimizers more + flexibility, split it into separate input and output + operands. */ + tree input; + char buf[10]; + size_t constraint_len = strlen (constraint); + + /* Turn the in/out constraint into an output constraint. */ + char *p = xstrdup (constraint); + p[0] = '='; + TREE_VALUE (TREE_PURPOSE (link)) = build_string (constraint_len, p); + free (p); + + /* And add a matching input constraint. */ + if (allows_reg) + { + sprintf (buf, "%d", i); + input = build_string (strlen (buf), buf); + } + else + input = build_string (constraint_len - 1, constraint + 1); + input = build_tree_list (build_tree_list (NULL_TREE, input), + unshare_expr (TREE_VALUE (link))); + ASM_INPUTS (expr) = chainon (ASM_INPUTS (expr), input); + } + } + + for (link = ASM_INPUTS (expr); link; ++i, link = TREE_CHAIN (link)) + { + constraint + = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); + parse_input_constraint (&constraint, 0, 0, noutputs, 0, + oconstraints, &allows_mem, &allows_reg); + + /* If the operand is a memory input, it should be an lvalue. */ + if (!allows_reg && allows_mem) + { + (*lang_hooks.mark_addressable) (TREE_VALUE (link)); + tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, + is_gimple_lvalue, fb_lvalue | fb_mayfail); + if (tret == GS_ERROR) + { + error ("memory input %d is not directly addressable", i); + ret = tret; + } + } + else + { + tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p, + is_gimple_val, fb_rvalue); + if (tret == GS_ERROR) + ret = tret; + } + } + + return ret; +} + +/* Gimplify a CLEANUP_POINT_EXPR. Currently this works by adding + WITH_CLEANUP_EXPRs to the prequeue as we encounter cleanups while + gimplifying the body, and converting them to TRY_FINALLY_EXPRs when we + return to this function. + + FIXME should we complexify the prequeue handling instead? Or use flags + for all the cleanups and let the optimizer tighten them up? The current + code seems pretty fragile; it will break on a cleanup within any + non-conditional nesting. But any such nesting would be broken, anyway; + we can't write a TRY_FINALLY_EXPR that starts inside a nesting construct + and continues out of it. We can do that at the RTL level, though, so + having an optimizer to tighten up try/finally regions would be a Good + Thing. */ + +static enum gimplify_status +gimplify_cleanup_point_expr (tree *expr_p, tree *pre_p) +{ + tree_stmt_iterator iter; + tree body; + + tree temp = voidify_wrapper_expr (*expr_p); + + /* We only care about the number of conditions between the innermost + CLEANUP_POINT_EXPR and the cleanup. So save and reset the count. */ + int old_conds = gimplify_ctxp->conditions; + gimplify_ctxp->conditions = 0; + + body = TREE_OPERAND (*expr_p, 0); + gimplify_to_stmt_list (&body); + + gimplify_ctxp->conditions = old_conds; + + for (iter = tsi_start (body); !tsi_end_p (iter); ) + { + tree *wce_p = tsi_stmt_ptr (iter); + tree wce = *wce_p; + + if (TREE_CODE (wce) == WITH_CLEANUP_EXPR) + { + if (tsi_one_before_end_p (iter)) + { + tsi_link_before (&iter, TREE_OPERAND (wce, 1), TSI_SAME_STMT); + tsi_delink (&iter); + break; + } + else + { + tree sl, tfe; + + sl = tsi_split_statement_list_after (&iter); + tfe = build (TRY_FINALLY_EXPR, void_type_node, sl, NULL_TREE); + append_to_statement_list (TREE_OPERAND (wce, 1), + &TREE_OPERAND (tfe, 1)); + *wce_p = tfe; + iter = tsi_start (sl); + } + } + else + tsi_next (&iter); + } + + if (temp) + { + *expr_p = temp; + append_to_statement_list (body, pre_p); + return GS_OK; + } + else + { + *expr_p = body; + return GS_ALL_DONE; + } +} + +/* Insert a cleanup marker for gimplify_cleanup_point_expr. CLEANUP + is the cleanup action required. */ + +static void +gimple_push_cleanup (tree var, tree cleanup, tree *pre_p) +{ + tree wce; + + /* Errors can result in improperly nested cleanups. Which results in + confusion when trying to resolve the WITH_CLEANUP_EXPR. */ + if (errorcount || sorrycount) + return; + + if (gimple_conditional_context ()) + { + /* If we're in a conditional context, this is more complex. We only + want to run the cleanup if we actually ran the initialization that + necessitates it, but we want to run it after the end of the + conditional context. So we wrap the try/finally around the + condition and use a flag to determine whether or not to actually + run the destructor. Thus + + test ? f(A()) : 0 + + becomes (approximately) + + flag = 0; + try { + if (test) { A::A(temp); flag = 1; val = f(temp); } + else { val = 0; } + } finally { + if (flag) A::~A(temp); + } + val + */ + + tree flag = create_tmp_var (boolean_type_node, "cleanup"); + tree ffalse = build (MODIFY_EXPR, void_type_node, flag, + boolean_false_node); + tree ftrue = build (MODIFY_EXPR, void_type_node, flag, + boolean_true_node); + cleanup = build (COND_EXPR, void_type_node, flag, cleanup, + build_empty_stmt ()); + wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE, + cleanup, NULL_TREE); + append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups); + append_to_statement_list (wce, &gimplify_ctxp->conditional_cleanups); + append_to_statement_list (ftrue, pre_p); + + /* Because of this manipulation, and the EH edges that jump + threading cannot redirect, the temporary (VAR) will appear + to be used uninitialized. Don't warn. */ + TREE_NO_WARNING (var) = 1; + } + else + { + wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE, + cleanup, NULL_TREE); + append_to_statement_list (wce, pre_p); + } + + gimplify_stmt (&TREE_OPERAND (wce, 1)); +} + +/* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR. */ + +static enum gimplify_status +gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree targ = *expr_p; + tree temp = TARGET_EXPR_SLOT (targ); + tree init = TARGET_EXPR_INITIAL (targ); + enum gimplify_status ret; + + if (init) + { + /* TARGET_EXPR temps aren't part of the enclosing block, so add it to the + temps list. */ + gimple_add_tmp_var (temp); + + /* Build up the initialization and add it to pre_p. */ + init = build (MODIFY_EXPR, void_type_node, temp, init); + ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none); + if (ret == GS_ERROR) + return GS_ERROR; + + append_to_statement_list (init, pre_p); + + /* If needed, push the cleanup for the temp. */ + if (TARGET_EXPR_CLEANUP (targ)) + { + gimplify_stmt (&TARGET_EXPR_CLEANUP (targ)); + gimple_push_cleanup (temp, TARGET_EXPR_CLEANUP (targ), pre_p); + } + + /* Only expand this once. */ + TREE_OPERAND (targ, 3) = init; + TARGET_EXPR_INITIAL (targ) = NULL_TREE; + } + else if (!temp->decl.seen_in_bind_expr) + /* We should have expanded this before. */ + abort (); + + *expr_p = temp; + return GS_OK; +} + +/* Gimplification of expression trees. */ + +/* Gimplify an expression which appears at statement context; usually, this + means replacing it with a suitably gimple COMPOUND_EXPR. */ + +void +gimplify_stmt (tree *stmt_p) +{ + gimplify_expr (stmt_p, NULL, NULL, is_gimple_stmt, fb_none); + if (!*stmt_p) + *stmt_p = alloc_stmt_list (); +} + +/* Similarly, but force the result to be a STATEMENT_LIST. */ + +void +gimplify_to_stmt_list (tree *stmt_p) +{ + gimplify_stmt (stmt_p); + if (TREE_CODE (*stmt_p) != STATEMENT_LIST) + { + tree t = *stmt_p; + *stmt_p = NULL; + append_to_statement_list (t, stmt_p); + } +} + + +/* Gimplifies the expression tree pointed by EXPR_P. Return 0 if + gimplification failed. + + PRE_P points to the list where side effects that must happen before + EXPR should be stored. + + POST_P points to the list where side effects that must happen after + EXPR should be stored, or NULL if there is no suitable list. In + that case, we copy the result to a temporary, emit the + post-effects, and then return the temporary. + + GIMPLE_TEST_F points to a function that takes a tree T and + returns nonzero if T is in the GIMPLE form requested by the + caller. The GIMPLE predicates are in tree-simple.c. + + This test is used twice. Before gimplification, the test is + invoked to determine whether *EXPR_P is already gimple enough. If + that fails, *EXPR_P is gimplified according to its code and + GIMPLE_TEST_F is called again. If the test still fails, then a new + temporary variable is created and assigned the value of the + gimplified expression. + + FALLBACK tells the function what sort of a temporary we want. If the 1 + bit is set, an rvalue is OK. If the 2 bit is set, an lvalue is OK. + If both are set, either is OK, but an lvalue is preferable. + + The return value is either GS_ERROR or GS_ALL_DONE, since this function + iterates until solution. */ + +enum gimplify_status +gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, + bool (* gimple_test_f) (tree), fallback_t fallback) +{ + tree tmp; + tree internal_pre = NULL_TREE; + tree internal_post = NULL_TREE; + tree save_expr; + int is_statement = (pre_p == NULL); + location_t *locus; + location_t saved_location; + enum gimplify_status ret; + + save_expr = *expr_p; + if (save_expr == NULL_TREE) + return GS_ALL_DONE; + + /* We used to check the predicate here and return immediately if it + succeeds. This is wrong; the design is for gimplification to be + idempotent, and for the predicates to only test for valid forms, not + whether they are fully simplified. */ + + /* Set up our internal queues if needed. */ + if (pre_p == NULL) + pre_p = &internal_pre; + if (post_p == NULL) + post_p = &internal_post; + + saved_location = input_location; + if (save_expr == error_mark_node) + locus = NULL; + else + locus = EXPR_LOCUS (save_expr); + if (locus) + input_location = *locus; + + /* Loop over the specific gimplifiers until the toplevel node + remains the same. */ + do + { + /* Strip any uselessness. */ + STRIP_MAIN_TYPE_NOPS (*expr_p); + + /* Remember the expr. */ + save_expr = *expr_p; + + /* Die, die, die, my darling. */ + if (save_expr == error_mark_node + || TREE_TYPE (save_expr) == error_mark_node) + { + ret = GS_ERROR; + break; + } + + /* Do any language-specific gimplification. */ + ret = (*lang_hooks.gimplify_expr) (expr_p, pre_p, post_p); + if (ret == GS_OK) + { + if (*expr_p == NULL_TREE) + break; + if (*expr_p != save_expr) + continue; + } + else if (ret != GS_UNHANDLED) + break; + + ret = GS_OK; + switch (TREE_CODE (*expr_p)) + { + /* First deal with the special cases. */ + + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + ret = gimplify_self_mod_expr (expr_p, pre_p, post_p, + fallback != fb_none); + break; + + case ARRAY_REF: + ret = gimplify_array_ref (expr_p, pre_p, post_p, + fallback & fb_lvalue); + break; + + case COMPONENT_REF: + ret = gimplify_compound_lval (expr_p, pre_p, post_p, + fallback & fb_lvalue); + break; + + case COND_EXPR: + ret = gimplify_cond_expr (expr_p, pre_p, NULL_TREE); + break; + + case CALL_EXPR: + ret = gimplify_call_expr (expr_p, pre_p, gimple_test_f); + break; + + case TREE_LIST: + abort (); + + case COMPOUND_EXPR: + ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none); + break; + + case REALPART_EXPR: + case IMAGPART_EXPR: + ret = gimplify_compound_lval (expr_p, pre_p, post_p, + fallback & fb_lvalue); + break; + + case MODIFY_EXPR: + case INIT_EXPR: + ret = gimplify_modify_expr (expr_p, pre_p, post_p, + fallback != fb_none); + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + ret = gimplify_boolean_expr (expr_p); + break; + + case TRUTH_NOT_EXPR: + TREE_OPERAND (*expr_p, 0) + = gimple_boolify (TREE_OPERAND (*expr_p, 0)); + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_val, fb_rvalue); + recalculate_side_effects (*expr_p); + break; + + case ADDR_EXPR: + ret = gimplify_addr_expr (expr_p, pre_p, post_p); + break; + + case VA_ARG_EXPR: + /* Mark any _DECL inside the operand as volatile to avoid the + optimizers messing around with it. FIXME: Remove this once + VA_ARG_EXPRs are properly lowered. */ + walk_tree (&TREE_OPERAND (*expr_p, 0), mark_decls_volatile_r, + NULL, NULL); + + /* va_arg expressions are in GIMPLE form already. */ + ret = GS_ALL_DONE; + break; + + case CONVERT_EXPR: + case NOP_EXPR: + if (IS_EMPTY_STMT (*expr_p)) + { + ret = GS_ALL_DONE; + break; + } + + if (VOID_TYPE_P (TREE_TYPE (*expr_p)) + || fallback == fb_none) + { + /* Just strip a conversion to void (or in void context) and + try again. */ + *expr_p = TREE_OPERAND (*expr_p, 0); + break; + } + + ret = gimplify_conversion (expr_p); + if (ret == GS_ERROR) + break; + if (*expr_p != save_expr) + break; + /* FALLTHRU */ + + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + /* unary_expr: ... | '(' cast ')' val | ... */ + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_val, fb_rvalue); + recalculate_side_effects (*expr_p); + break; + + case INDIRECT_REF: + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_reg, fb_rvalue); + recalculate_side_effects (*expr_p); + break; + + /* Constants need not be gimplified. */ + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + ret = GS_ALL_DONE; + break; + + case CONST_DECL: + *expr_p = DECL_INITIAL (*expr_p); + break; + + case EXC_PTR_EXPR: + /* FIXME make this a decl. */ + ret = GS_ALL_DONE; + break; + + case BIND_EXPR: + ret = gimplify_bind_expr (expr_p, pre_p); + break; + + case LOOP_EXPR: + ret = gimplify_loop_expr (expr_p, pre_p); + break; + + case SWITCH_EXPR: + ret = gimplify_switch_expr (expr_p, pre_p); + break; + + case LABELED_BLOCK_EXPR: + ret = gimplify_labeled_block_expr (expr_p); + break; + + case EXIT_BLOCK_EXPR: + ret = gimplify_exit_block_expr (expr_p); + break; + + case EXIT_EXPR: + ret = gimplify_exit_expr (expr_p); + break; + + case GOTO_EXPR: + /* If the target is not LABEL, then it is a computed jump + and the target needs to be gimplified. */ + if (TREE_CODE (GOTO_DESTINATION (*expr_p)) != LABEL_DECL) + ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p, + NULL, is_gimple_val, fb_rvalue); + break; + + case LABEL_EXPR: + ret = GS_ALL_DONE; +#ifdef ENABLE_CHECKING + if (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) != current_function_decl) + abort (); +#endif + break; + + case CASE_LABEL_EXPR: + ret = gimplify_case_label_expr (expr_p); + break; + + case RETURN_EXPR: + ret = gimplify_return_expr (*expr_p, pre_p); + break; + + case CONSTRUCTOR: + /* Don't reduce this in place; let gimplify_init_constructor work + its magic. */ + ret = GS_ALL_DONE; + break; + + /* The following are special cases that are not handled by the + original GIMPLE grammar. */ + + /* SAVE_EXPR nodes are converted into a GIMPLE identifier and + eliminated. */ + case SAVE_EXPR: + ret = gimplify_save_expr (expr_p, pre_p, post_p); + break; + + case BIT_FIELD_REF: + { + enum gimplify_status r0, r1, r2; + + r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_min_lval, fb_either); + r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, + is_gimple_val, fb_rvalue); + r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p, + is_gimple_val, fb_rvalue); + recalculate_side_effects (*expr_p); + + ret = MIN (r0, MIN (r1, r2)); + } + break; + + case NON_LVALUE_EXPR: + /* This should have been stripped above. */ + abort (); + break; + + case ASM_EXPR: + ret = gimplify_asm_expr (expr_p, pre_p, post_p); + break; + + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 0)); + gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 1)); + ret = GS_ALL_DONE; + break; + + case CLEANUP_POINT_EXPR: + ret = gimplify_cleanup_point_expr (expr_p, pre_p); + break; + + case TARGET_EXPR: + ret = gimplify_target_expr (expr_p, pre_p, post_p); + break; + + case CATCH_EXPR: + gimplify_to_stmt_list (&CATCH_BODY (*expr_p)); + ret = GS_ALL_DONE; + break; + + case EH_FILTER_EXPR: + gimplify_to_stmt_list (&EH_FILTER_FAILURE (*expr_p)); + ret = GS_ALL_DONE; + break; + + case VTABLE_REF: + /* This moves much of the actual computation out of the + VTABLE_REF. Perhaps this should be revisited once we want to + do clever things with VTABLE_REFs. */ + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_min_lval, fb_lvalue); + break; + + case MIN_EXPR: + case MAX_EXPR: + ret = gimplify_minimax_expr (expr_p, pre_p, post_p); + break; + + case LABEL_DECL: + /* We get here when taking the address of a label. We mark + the label as "forced"; meaning it can never be removed and + it is a potential target for any computed goto. */ + FORCED_LABEL (*expr_p) = 1; + ret = GS_ALL_DONE; + break; + + case STATEMENT_LIST: + ret = gimplify_statement_list (expr_p); + break; + + case VAR_DECL: + /* ??? If this is a local variable, and it has not been seen in any + outer BIND_EXPR, then it's probably the result of a duplicate + declaration, for which we've already issued an error. It would + be really nice if the front end wouldn't leak these at all. + Currently the only known culprit is C++ destructors, as seen + in g++.old-deja/g++.jason/binding.C. */ + tmp = *expr_p; + if (!TREE_STATIC (tmp) && !DECL_EXTERNAL (tmp) + && decl_function_context (tmp) == current_function_decl + && !tmp->decl.seen_in_bind_expr) + { +#ifdef ENABLE_CHECKING + if (!errorcount && !sorrycount) + abort (); +#endif + ret = GS_ERROR; + } + else + ret = GS_ALL_DONE; + break; + + default: + /* If *EXPR_P does not need to be special-cased, handle it + according to its class. */ + if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1') + ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, + post_p, is_gimple_val, fb_rvalue); + else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2' + || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<' + || TREE_CODE (*expr_p) == TRUTH_AND_EXPR + || TREE_CODE (*expr_p) == TRUTH_OR_EXPR + || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR) + { + enum gimplify_status r0, r1; + + r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, + post_p, is_gimple_val, fb_rvalue); + r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, + post_p, is_gimple_val, fb_rvalue); + + ret = MIN (r0, r1); + } + else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'd' + || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'c') + { + ret = GS_ALL_DONE; + break; + } + else + /* Fail if we don't know how to handle this tree code. */ + abort (); + + recalculate_side_effects (*expr_p); + break; + } + + /* If we replaced *expr_p, gimplify again. */ + if (ret == GS_OK && (*expr_p == NULL || *expr_p == save_expr)) + ret = GS_ALL_DONE; + } + while (ret == GS_OK); + + /* If we encountered an error_mark somewhere nested inside, either + stub out the statement or propagate the error back out. */ + if (ret == GS_ERROR) + { + if (is_statement) + *expr_p = build_empty_stmt (); + goto out; + } + +#ifdef ENABLE_CHECKING + /* This was only valid as a return value from the langhook, which + we handled. Make sure it doesn't escape from any other context. */ + if (ret == GS_UNHANDLED) + abort (); +#endif + + if (!*expr_p) + *expr_p = build_empty_stmt (); + if (fallback == fb_none && !is_gimple_stmt (*expr_p)) + { + /* We aren't looking for a value, and we don't have a valid + statement. If it doesn't have side-effects, throw it away. */ + if (!TREE_SIDE_EFFECTS (*expr_p)) + *expr_p = build_empty_stmt (); + else if (!TREE_THIS_VOLATILE (*expr_p)) + /* We only handle volatiles here; anything else with side-effects + must be converted to a valid statement before we get here. */ + abort (); + else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p))) + { + /* Historically, the compiler has treated a bare + reference to a volatile lvalue as forcing a load. */ + tree tmp = create_tmp_var (TREE_TYPE (*expr_p), "vol"); + *expr_p = build (MODIFY_EXPR, TREE_TYPE (tmp), tmp, *expr_p); + } + else + /* We can't do anything useful with a volatile reference to + incomplete type, so just throw it away. */ + *expr_p = build_empty_stmt (); + } + + /* If we are gimplifying at the statement level, we're done. Tack + everything together and replace the original statement with the + gimplified form. */ + if (is_statement) + { + append_to_statement_list (*expr_p, &internal_pre); + append_to_statement_list (internal_post, &internal_pre); + annotate_all_with_locus (&internal_pre, input_location); + *expr_p = internal_pre; + goto out; + } + + /* Otherwise we're gimplifying a subexpression, so the resulting value is + interesting. */ + + /* If it's sufficiently simple already, we're done. Unless we are + handling some post-effects internally; if that's the case, we need to + copy into a temp before adding the post-effects to the tree. */ + if (!internal_post && (*gimple_test_f) (*expr_p)) + goto out; + + /* Otherwise, we need to create a new temporary for the gimplified + expression. */ + + /* We can't return an lvalue if we have an internal postqueue. The + object the lvalue refers to would (probably) be modified by the + postqueue; we need to copy the value out first, which means an + rvalue. */ + if ((fallback & fb_lvalue) && !internal_post + && is_gimple_addr_expr_arg (*expr_p)) + { + /* An lvalue will do. Take the address of the expression, store it + in a temporary, and replace the expression with an INDIRECT_REF of + that temporary. */ + tmp = build_addr_expr (*expr_p); + gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue); + *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp); + } + else if ((fallback & fb_rvalue) && is_gimple_rhs (*expr_p)) + { +#if defined ENABLE_CHECKING + if (VOID_TYPE_P (TREE_TYPE (*expr_p))) + abort (); +#endif + + /* An rvalue will do. Assign the gimplified expression into a new + temporary TMP and replace the original expression with TMP. */ + + if (internal_post || (fallback & fb_lvalue)) + /* The postqueue might change the value of the expression between + the initialization and use of the temporary, so we can't use a + formal temp. FIXME do we care? */ + *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p); + else + *expr_p = get_formal_tmp_var (*expr_p, pre_p); + } + else if (fallback & fb_mayfail) + { + /* If this is an asm statement, and the user asked for the impossible, + don't abort. Fail and let gimplify_asm_expr issue an error. */ + ret = GS_ERROR; + goto out; + } + else + { + fprintf (stderr, "gimplification failed:\n"); + print_generic_expr (stderr, *expr_p, 0); + debug_tree (*expr_p); + abort (); + } + +#if defined ENABLE_CHECKING + /* Make sure the temporary matches our predicate. */ + if (!(*gimple_test_f) (*expr_p)) + abort (); +#endif + + if (internal_post) + { + annotate_all_with_locus (&internal_post, input_location); + append_to_statement_list (internal_post, pre_p); + } + + out: + input_location = saved_location; + return ret; +} + +#ifdef ENABLE_CHECKING +/* Compare types A and B for a "close enough" match. */ + +static bool +cpt_same_type (tree a, tree b) +{ + if (lang_hooks.types_compatible_p (a, b)) + return true; + + /* ??? The C++ FE decomposes METHOD_TYPES to FUNCTION_TYPES and doesn't + link them together. This routine is intended to catch type errors + that will affect the optimizers, and the optimizers don't add new + dereferences of function pointers, so ignore it. */ + if ((TREE_CODE (a) == FUNCTION_TYPE || TREE_CODE (a) == METHOD_TYPE) + && (TREE_CODE (b) == FUNCTION_TYPE || TREE_CODE (b) == METHOD_TYPE)) + return true; + + /* ??? The C FE pushes type qualifiers after the fact into the type of + the element from the type of the array. See build_unary_op's handling + of ADDR_EXPR. This seems wrong -- if we were going to do this, we + should have done it when creating the variable in the first place. + Alternately, why aren't the two array types made variants? */ + if (TREE_CODE (a) == ARRAY_TYPE && TREE_CODE (b) == ARRAY_TYPE) + return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b)); + + /* And because of those, we have to recurse down through pointers. */ + if (POINTER_TYPE_P (a) && POINTER_TYPE_P (b)) + return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b)); + + return false; +} + +/* Check for some cases of the front end missing cast expressions. + The type of a dereference should correspond to the pointer type; + similarly the type of an address should match its object. */ + +static tree +check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + tree t = *tp; + tree ptype, otype, dtype; + + switch (TREE_CODE (t)) + { + case INDIRECT_REF: + case ARRAY_REF: + otype = TREE_TYPE (t); + ptype = TREE_TYPE (TREE_OPERAND (t, 0)); + dtype = TREE_TYPE (ptype); + if (!cpt_same_type (otype, dtype)) + abort (); + break; + + case ADDR_EXPR: + ptype = TREE_TYPE (t); + otype = TREE_TYPE (TREE_OPERAND (t, 0)); + dtype = TREE_TYPE (ptype); + if (!cpt_same_type (otype, dtype)) + { + /* &array is allowed to produce a pointer to the element, + rather than a pointer to the array type. */ + if (TREE_CODE (otype) == ARRAY_TYPE + && POINTER_TYPE_P (ptype) + && cpt_same_type (TREE_TYPE (otype), dtype)) + break; + abort (); + } + break; + + default: + return NULL_TREE; + } + + + return NULL_TREE; +} +#endif + +/* Gimplify the body of statements pointed by BODY_P. FNDECL is the + function decl containing BODY. */ + +void +gimplify_body (tree *body_p, tree fndecl) +{ + location_t saved_location = input_location; + tree body; + + timevar_push (TV_TREE_GIMPLIFY); + push_gimplify_context (); + + /* Unshare most shared trees in the body. */ + unshare_all_trees (*body_p); + + /* Make sure input_location isn't set to something wierd. */ + input_location = DECL_SOURCE_LOCATION (fndecl); + + /* Gimplify the function's body. */ + gimplify_stmt (body_p); + body = *body_p; + + /* Unshare again, in case gimplification was sloppy. */ + unshare_all_trees (body); + + /* If there isn't an outer BIND_EXPR, add one. */ + if (TREE_CODE (body) == STATEMENT_LIST) + { + tree t = expr_only (*body_p); + if (t) + body = t; + } + if (TREE_CODE (body) != BIND_EXPR) + { + tree b = build (BIND_EXPR, void_type_node, NULL_TREE, + NULL_TREE, NULL_TREE); + TREE_SIDE_EFFECTS (b) = 1; + append_to_statement_list (body, &BIND_EXPR_BODY (b)); + body = b; + } + *body_p = body; + + pop_gimplify_context (body); + +#ifdef ENABLE_CHECKING + walk_tree (body_p, check_pointer_types_r, NULL, NULL); +#endif + + timevar_pop (TV_TREE_GIMPLIFY); + input_location = saved_location; +} + +/* Entry point to the gimplification pass. FNDECL is the FUNCTION_DECL + node for the function we want to gimplify. */ + +void +gimplify_function_tree (tree fndecl) +{ + tree oldfn; + + oldfn = current_function_decl; + current_function_decl = fndecl; + + gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl); + + /* If we're instrumenting function entry/exit, then prepend the call to + the entry hook and wrap the whole function in a TRY_FINALLY_EXPR to + catch the exit hook. */ + /* ??? Add some way to ignore exceptions for this TFE. */ + if (flag_instrument_function_entry_exit + && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)) + { + tree tf, x, bind; + + tf = build (TRY_FINALLY_EXPR, void_type_node, NULL, NULL); + TREE_SIDE_EFFECTS (tf) = 1; + x = DECL_SAVED_TREE (fndecl); + append_to_statement_list (x, &TREE_OPERAND (tf, 0)); + x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT]; + x = build_function_call_expr (x, NULL); + append_to_statement_list (x, &TREE_OPERAND (tf, 1)); + + bind = build (BIND_EXPR, void_type_node, NULL, NULL, NULL); + TREE_SIDE_EFFECTS (bind) = 1; + x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER]; + x = build_function_call_expr (x, NULL); + append_to_statement_list (x, &BIND_EXPR_BODY (bind)); + append_to_statement_list (tf, &BIND_EXPR_BODY (bind)); + + DECL_SAVED_TREE (fndecl) = bind; + } + + current_function_decl = oldfn; +} + +#include "gt-gimplify.h" diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index a87d7ad2097..6a212f1ccc2 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -950,9 +950,6 @@ priority (rtx insn) rtx next; int next_priority; - if (RTX_INTEGRATED_P (link)) - continue; - next = XEXP (link, 0); /* Critical path is meaningful in block boundaries only. */ @@ -1581,7 +1578,6 @@ restore_line_notes (rtx head, rtx tail) added_notes++; new = emit_note_after (NOTE_LINE_NUMBER (note), prev); NOTE_SOURCE_FILE (new) = NOTE_SOURCE_FILE (note); - RTX_INTEGRATED_P (new) = RTX_INTEGRATED_P (note); } } if (sched_verbose && added_notes) diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 7968b2b764b..a6066da2151 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -3023,7 +3023,7 @@ static int dead_or_predicable (basic_block test_bb, basic_block merge_bb, basic_block other_bb, basic_block new_dest, int reversep) { - rtx head, end, jump, earliest, old_dest, new_label = NULL_RTX; + rtx head, end, jump, earliest = NULL_RTX, old_dest, new_label = NULL_RTX; jump = BB_END (test_bb); diff --git a/gcc/input.h b/gcc/input.h index 45fee91d040..6e11023a900 100644 --- a/gcc/input.h +++ b/gcc/input.h @@ -53,9 +53,6 @@ extern location_t input_location; The line member is not accurate for the innermost file on the stack. */ extern struct file_stack *input_file_stack; -/* Stack of EXPR_WITH_FILE_LOCATION nested expressions. */ -extern struct file_stack *expr_wfl_stack; - /* Incremented on each change to input_file_stack. */ extern int input_file_stack_tick; diff --git a/gcc/integrate.c b/gcc/integrate.c index 3a58f2cda04..de897176ea0 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -41,26 +41,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "function.h" #include "toplev.h" #include "intl.h" -#include "loop.h" #include "params.h" #include "ggc.h" #include "target.h" #include "langhooks.h" -/* Similar, but round to the next highest integer that meets the - alignment. */ +/* Round to the next highest integer that meets the alignment. */ #define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1)) - -/* Default max number of insns a function can have and still be inline. - This is overridden on RISC machines. */ -#ifndef INTEGRATE_THRESHOLD -/* Inlining small functions might save more space then not inlining at - all. Assume 1 instruction for the call and 1.5 insns per argument. */ -#define INTEGRATE_THRESHOLD(DECL) \ - (optimize_size \ - ? (1 + (3 * list_length (DECL_ARGUMENTS (DECL))) / 2) \ - : (8 * (8 + list_length (DECL_ARGUMENTS (DECL))))) -#endif /* Private type used by {get/has}_func_hard_reg_initial_val. */ @@ -74,29 +61,10 @@ typedef struct initial_value_struct GTY(()) { initial_value_pair * GTY ((length ("%h.num_entries"))) entries; } initial_value_struct; -static void setup_initial_hard_reg_value_integration (struct function *, - struct inline_remap *); - -static rtvec initialize_for_inline (tree); -static void note_modified_parmregs (rtx, rtx, void *); -static void integrate_parm_decls (tree, struct inline_remap *, rtvec); -static tree integrate_decl_tree (tree, struct inline_remap *); static void subst_constants (rtx *, rtx, struct inline_remap *, int); static void set_block_origin_self (tree); static void set_block_abstract_flags (tree, int); -static void process_reg_param (struct inline_remap *, rtx, rtx); static void mark_stores (rtx, rtx, void *); -static void save_parm_insns (rtx, rtx); -static void copy_insn_list (rtx, struct inline_remap *, rtx); -static void copy_insn_notes (rtx, struct inline_remap *, int); -static int compare_blocks (const void *, const void *); -static int find_block (const void *, const void *); - -/* Used by copy_rtx_and_substitute; this indicates whether the function is - called for the purpose of inlining or some other purpose (i.e. loop - unrolling). This affects how constant pool references are handled. - This variable contains the FUNCTION_DECL for the inlined function. */ -static struct function *inlining = 0; /* Returns the Ith entry in the label_map contained in MAP. If the Ith entry has not yet been set, return a fresh label. This function @@ -136,195 +104,7 @@ function_attribute_inlinable_p (tree fndecl) return true; } - -/* Zero if the current function (whose FUNCTION_DECL is FNDECL) - is safe and reasonable to integrate into other functions. - Nonzero means value is a warning msgid with a single %s - for the function's name. */ - -const char * -function_cannot_inline_p (tree fndecl) -{ - rtx insn; - tree last = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); - - /* For functions marked as inline increase the maximum size to - MAX_INLINE_INSNS_RTL (--param max-inline-insn-rtl=). For - regular functions use the limit given by INTEGRATE_THRESHOLD. - Note that the RTL inliner is not used by the languages that use - the tree inliner (C, C++). */ - - int max_insns = (DECL_INLINE (fndecl)) - ? (MAX_INLINE_INSNS_RTL - + 8 * list_length (DECL_ARGUMENTS (fndecl))) - : INTEGRATE_THRESHOLD (fndecl); - - int ninsns = 0; - tree parms; - - if (DECL_UNINLINABLE (fndecl)) - return N_("function cannot be inline"); - - /* No inlines with varargs. */ - if (last && TREE_VALUE (last) != void_type_node) - return N_("varargs function cannot be inline"); - - if (current_function_calls_alloca) - return N_("function using alloca cannot be inline"); - - if (current_function_calls_longjmp) - return N_("function using longjmp cannot be inline"); - - if (current_function_calls_setjmp) - return N_("function using setjmp cannot be inline"); - - if (current_function_calls_eh_return) - return N_("function uses __builtin_eh_return"); - - if (current_function_contains_functions) - return N_("function with nested functions cannot be inline"); - - if (forced_labels) - return - N_("function with label addresses used in initializers cannot inline"); - - if (current_function_cannot_inline) - return current_function_cannot_inline; - - /* If it's not even close, don't even look. */ - if (get_max_uid () > 3 * max_insns) - return N_("function too large to be inline"); - -#if 0 - /* Don't inline functions which do not specify a function prototype and - have BLKmode argument or take the address of a parameter. */ - for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) - { - if (TYPE_MODE (TREE_TYPE (parms)) == BLKmode) - TREE_ADDRESSABLE (parms) = 1; - if (last == NULL_TREE && TREE_ADDRESSABLE (parms)) - return N_("no prototype, and parameter address used; cannot be inline"); - } -#endif - - /* We can't inline functions that return structures - the old-fashioned PCC way, copying into a static block. */ - if (current_function_returns_pcc_struct) - return N_("inline functions not supported for this return value type"); - - /* We can't inline functions that return structures of varying size. */ - if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE - && int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0) - return N_("function with varying-size return value cannot be inline"); - - /* Cannot inline a function with a varying size argument or one that - receives a transparent union. */ - for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms)) - { - if (int_size_in_bytes (TREE_TYPE (parms)) < 0) - return N_("function with varying-size parameter cannot be inline"); - else if (TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE - && TYPE_TRANSPARENT_UNION (TREE_TYPE (parms))) - return N_("function with transparent unit parameter cannot be inline"); - } - - if (get_max_uid () > max_insns) - { - for (ninsns = 0, insn = get_first_nonparm_insn (); - insn && ninsns < max_insns; - insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - ninsns++; - - if (ninsns >= max_insns) - return N_("function too large to be inline"); - } - - /* We will not inline a function which uses computed goto. The addresses of - its local labels, which may be tucked into global storage, are of course - not constant across instantiations, which causes unexpected behavior. */ - if (current_function_has_computed_jump) - return N_("function with computed jump cannot inline"); - - /* We cannot inline a nested function that jumps to a nonlocal label. */ - if (current_function_has_nonlocal_goto) - return N_("function with nonlocal goto cannot be inline"); - - /* We can't inline functions that return a PARALLEL rtx. */ - if (DECL_RTL_SET_P (DECL_RESULT (fndecl))) - { - rtx result = DECL_RTL (DECL_RESULT (fndecl)); - if (GET_CODE (result) == PARALLEL) - return N_("inline functions not supported for this return value type"); - } - - /* If the function has a target specific attribute attached to it, - then we assume that we should not inline it. This can be overridden - by the target if it defines TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. */ - if (!function_attribute_inlinable_p (fndecl)) - return N_("function with target specific attribute(s) cannot be inlined"); - - return NULL; -} -/* Map pseudo reg number into the PARM_DECL for the parm living in the reg. - Zero for a reg that isn't a parm's home. - Only reg numbers less than max_parm_reg are mapped here. */ -static tree *parmdecl_map; - -/* In save_for_inline, nonzero if past the parm-initialization insns. */ -static int in_nonparm_insns; - -/* Subroutine for `save_for_inline'. Performs initialization - needed to save FNDECL's insns and info for future inline expansion. */ - -static rtvec -initialize_for_inline (tree fndecl) -{ - int i; - rtvec arg_vector; - tree parms; - - /* Clear out PARMDECL_MAP. It was allocated in the caller's frame. */ - memset (parmdecl_map, 0, max_parm_reg * sizeof (tree)); - arg_vector = rtvec_alloc (list_length (DECL_ARGUMENTS (fndecl))); - - for (parms = DECL_ARGUMENTS (fndecl), i = 0; - parms; - parms = TREE_CHAIN (parms), i++) - { - rtx p = DECL_RTL (parms); - - /* If we have (mem (addressof (mem ...))), use the inner MEM since - otherwise the copy_rtx call below will not unshare the MEM since - it shares ADDRESSOF. */ - if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF - && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM) - p = XEXP (XEXP (p, 0), 0); - - RTVEC_ELT (arg_vector, i) = p; - - if (GET_CODE (p) == REG) - parmdecl_map[REGNO (p)] = parms; - else if (GET_CODE (p) == CONCAT) - { - rtx preal = gen_realpart (GET_MODE (XEXP (p, 0)), p); - rtx pimag = gen_imagpart (GET_MODE (preal), p); - - if (GET_CODE (preal) == REG) - parmdecl_map[REGNO (preal)] = parms; - if (GET_CODE (pimag) == REG) - parmdecl_map[REGNO (pimag)] = parms; - } - - /* This flag is cleared later - if the function ever modifies the value of the parm. */ - TREE_READONLY (parms) = 1; - } - - return arg_vector; -} - /* Copy NODE (which must be a DECL, but not a PARM_DECL). The DECL originally was in the FROM_FN, but now it will be in the TO_FN. */ @@ -379,7 +159,10 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn) address has been taken; it's for internal bookkeeping in expand_goto_internal. */ if (TREE_CODE (copy) == LABEL_DECL) - TREE_ADDRESSABLE (copy) = 0; + { + TREE_ADDRESSABLE (copy) = 0; + DECL_TOO_LATE (copy) = 0; + } } /* Set the DECL_ABSTRACT_ORIGIN so the debugging routines know what @@ -412,1439 +195,13 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn) return copy; } - -/* Make the insns and PARM_DECLs of the current function permanent - and record other information in DECL_STRUCT_FUNCTION to allow - inlining of this function in subsequent calls. - - This routine need not copy any insns because we are not going - to immediately compile the insns in the insn chain. There - are two cases when we would compile the insns for FNDECL: - (1) when FNDECL is expanded inline, and (2) when FNDECL needs to - be output at the end of other compilation, because somebody took - its address. In the first case, the insns of FNDECL are copied - as it is expanded inline, so FNDECL's saved insns are not - modified. In the second case, FNDECL is used for the last time, - so modifying the rtl is not a problem. - - We don't have to worry about FNDECL being inline expanded by - other functions which are written at the end of compilation - because flag_no_inline is turned on when we begin writing - functions at the end of compilation. */ - -void -save_for_inline (tree fndecl) -{ - rtx insn; - rtvec argvec; - rtx first_nonparm_insn; - - /* Set up PARMDECL_MAP which maps pseudo-reg number to its PARM_DECL. - Later we set TREE_READONLY to 0 if the parm is modified inside the fn. - Also set up ARG_VECTOR, which holds the unmodified DECL_RTX values - for the parms, prior to elimination of virtual registers. - These values are needed for substituting parms properly. */ - if (! flag_no_inline) - parmdecl_map = xmalloc (max_parm_reg * sizeof (tree)); - - /* Make and emit a return-label if we have not already done so. */ - - if (return_label == 0) - { - return_label = gen_label_rtx (); - emit_label (return_label); - } - - if (! flag_no_inline) - argvec = initialize_for_inline (fndecl); - else - argvec = NULL; - - /* Delete basic block notes created by early run of find_basic_block. - The notes would be later used by find_basic_blocks to reuse the memory - for basic_block structures on already freed obstack. */ - for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK) - delete_related_insns (insn); - - /* If there are insns that copy parms from the stack into pseudo registers, - those insns are not copied. `expand_inline_function' must - emit the correct code to handle such things. */ - - insn = get_insns (); - if (GET_CODE (insn) != NOTE) - abort (); - - if (! flag_no_inline) - { - /* Get the insn which signals the end of parameter setup code. */ - first_nonparm_insn = get_first_nonparm_insn (); - - /* Now just scan the chain of insns to see what happens to our - PARM_DECLs. If a PARM_DECL is used but never modified, we - can substitute its rtl directly when expanding inline (and - perform constant folding when its incoming value is - constant). Otherwise, we have to copy its value into a new - register and track the new register's life. */ - in_nonparm_insns = 0; - save_parm_insns (insn, first_nonparm_insn); - - cfun->inl_max_label_num = max_label_num (); - cfun->inl_last_parm_insn = cfun->x_last_parm_insn; - cfun->original_arg_vector = argvec; - } - cfun->original_decl_initial = DECL_INITIAL (fndecl); - cfun->no_debugging_symbols = (write_symbols == NO_DEBUG); - cfun->saved_for_inline = 1; - - /* Clean up. */ - if (! flag_no_inline) - free (parmdecl_map); -} - -/* Scan the chain of insns to see what happens to our PARM_DECLs. If a - PARM_DECL is used but never modified, we can substitute its rtl directly - when expanding inline (and perform constant folding when its incoming - value is constant). Otherwise, we have to copy its value into a new - register and track the new register's life. */ - -static void -save_parm_insns (rtx insn, rtx first_nonparm_insn) -{ - if (insn == NULL_RTX) - return; - - for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn)) - { - if (insn == first_nonparm_insn) - in_nonparm_insns = 1; - - if (INSN_P (insn)) - { - /* Record what interesting things happen to our parameters. */ - note_stores (PATTERN (insn), note_modified_parmregs, NULL); - - /* If this is a CALL_PLACEHOLDER insn then we need to look into the - three attached sequences: normal call, sibling call and tail - recursion. */ - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - { - int i; - - for (i = 0; i < 3; i++) - save_parm_insns (XEXP (PATTERN (insn), i), - first_nonparm_insn); - } - } - } -} -/* Note whether a parameter is modified or not. */ - -static void -note_modified_parmregs (rtx reg, rtx x ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED) -{ - if (GET_CODE (reg) == REG && in_nonparm_insns - && REGNO (reg) < max_parm_reg - && REGNO (reg) >= FIRST_PSEUDO_REGISTER - && parmdecl_map[REGNO (reg)] != 0) - TREE_READONLY (parmdecl_map[REGNO (reg)]) = 0; -} - /* Unfortunately, we need a global copy of const_equiv map for communication with a function called from note_stores. Be *very* careful that this is used properly in the presence of recursion. */ varray_type global_const_equiv_varray; - -#define FIXED_BASE_PLUS_P(X) \ - (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \ - && GET_CODE (XEXP (X, 0)) == REG \ - && REGNO (XEXP (X, 0)) >= FIRST_VIRTUAL_REGISTER \ - && REGNO (XEXP (X, 0)) <= LAST_VIRTUAL_REGISTER) -/* Called to set up a mapping for the case where a parameter is in a - register. If it is read-only and our argument is a constant, set up the - constant equivalence. - - If LOC is REG_USERVAR_P, the usual case, COPY must also have that flag set - if it is a register. - - Also, don't allow hard registers here; they might not be valid when - substituted into insns. */ -static void -process_reg_param (struct inline_remap *map, rtx loc, rtx copy) -{ - if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG) - || (GET_CODE (copy) == REG && REG_USERVAR_P (loc) - && ! REG_USERVAR_P (copy)) - || (GET_CODE (copy) == REG - && REGNO (copy) < FIRST_PSEUDO_REGISTER)) - { - rtx temp = copy_to_mode_reg (GET_MODE (loc), copy); - REG_USERVAR_P (temp) = REG_USERVAR_P (loc); - if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy)) - SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM); - copy = temp; - } - map->reg_map[REGNO (loc)] = copy; -} - -/* Compare two BLOCKs for qsort. The key we sort on is the - BLOCK_ABSTRACT_ORIGIN of the blocks. We cannot just subtract the - two pointers, because it may overflow sizeof(int). */ - -static int -compare_blocks (const void *v1, const void *v2) -{ - tree b1 = *((const tree *) v1); - tree b2 = *((const tree *) v2); - char *p1 = (char *) BLOCK_ABSTRACT_ORIGIN (b1); - char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2); - - if (p1 == p2) - return 0; - return p1 < p2 ? -1 : 1; -} - -/* Compare two BLOCKs for bsearch. The first pointer corresponds to - an original block; the second to a remapped equivalent. */ - -static int -find_block (const void *v1, const void *v2) -{ - const union tree_node *b1 = (const union tree_node *) v1; - tree b2 = *((const tree *) v2); - char *p1 = (char *) b1; - char *p2 = (char *) BLOCK_ABSTRACT_ORIGIN (b2); - - if (p1 == p2) - return 0; - return p1 < p2 ? -1 : 1; -} - -/* Integrate the procedure defined by FNDECL. Note that this function - may wind up calling itself. Since the static variables are not - reentrant, we do not assign them until after the possibility - of recursion is eliminated. - - If IGNORE is nonzero, do not produce a value. - Otherwise store the value in TARGET if it is nonzero and that is convenient. - - Value is: - (rtx)-1 if we could not substitute the function - 0 if we substituted it and it does not produce a value - else an rtx for where the value is stored. */ - -rtx -expand_inline_function (tree fndecl, tree parms, rtx target, int ignore, - tree type, rtx structure_value_addr) -{ - struct function *inlining_previous; - struct function *inl_f = DECL_STRUCT_FUNCTION (fndecl); - tree formal, actual, block; - rtx parm_insns = inl_f->emit->x_first_insn; - rtx insns = (inl_f->inl_last_parm_insn - ? NEXT_INSN (inl_f->inl_last_parm_insn) - : parm_insns); - tree *arg_trees; - rtx *arg_vals; - int max_regno; - int i; - int min_labelno = inl_f->emit->x_first_label_num; - int max_labelno = inl_f->inl_max_label_num; - int nargs; - rtx loc; - rtx stack_save = 0; - rtx temp; - struct inline_remap *map = 0; - rtvec arg_vector = inl_f->original_arg_vector; - rtx static_chain_value = 0; - int inl_max_uid; - int eh_region_offset; - - /* The pointer used to track the true location of the memory used - for MAP->LABEL_MAP. */ - rtx *real_label_map = 0; - - /* Allow for equivalences of the pseudos we make for virtual fp and ap. */ - max_regno = inl_f->emit->x_reg_rtx_no + 3; - if (max_regno < FIRST_PSEUDO_REGISTER) - abort (); - - /* Pull out the decl for the function definition; fndecl may be a - local declaration, which would break DECL_ABSTRACT_ORIGIN. */ - fndecl = inl_f->decl; - - nargs = list_length (DECL_ARGUMENTS (fndecl)); - - if (cfun->preferred_stack_boundary < inl_f->preferred_stack_boundary) - cfun->preferred_stack_boundary = inl_f->preferred_stack_boundary; - - /* Check that the parms type match and that sufficient arguments were - passed. Since the appropriate conversions or default promotions have - already been applied, the machine modes should match exactly. */ - - for (formal = DECL_ARGUMENTS (fndecl), actual = parms; - formal; - formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual)) - { - tree arg; - enum machine_mode mode; - - if (actual == 0) - return (rtx) (size_t) -1; - - arg = TREE_VALUE (actual); - mode = TYPE_MODE (DECL_ARG_TYPE (formal)); - - if (arg == error_mark_node - || mode != TYPE_MODE (TREE_TYPE (arg)) - /* If they are block mode, the types should match exactly. - They don't match exactly if TREE_TYPE (FORMAL) == ERROR_MARK_NODE, - which could happen if the parameter has incomplete type. */ - || (mode == BLKmode - && (TYPE_MAIN_VARIANT (TREE_TYPE (arg)) - != TYPE_MAIN_VARIANT (TREE_TYPE (formal))))) - return (rtx) (size_t) -1; - } - - /* If there is a TARGET which is a readonly BLKmode MEM and DECL_RESULT - is also a mem, we are going to lose the readonly on the stores, so don't - inline. */ - if (target != 0 && GET_CODE (target) == MEM && GET_MODE (target) == BLKmode - && RTX_UNCHANGING_P (target) && DECL_RTL_SET_P (DECL_RESULT (fndecl)) - && GET_CODE (DECL_RTL (DECL_RESULT (fndecl))) == MEM) - return (rtx) (size_t) -1; - - /* Extra arguments are valid, but will be ignored below, so we must - evaluate them here for side-effects. */ - for (; actual; actual = TREE_CHAIN (actual)) - expand_expr (TREE_VALUE (actual), const0_rtx, - TYPE_MODE (TREE_TYPE (TREE_VALUE (actual))), 0); - - /* Expand the function arguments. Do this first so that any - new registers get created before we allocate the maps. */ - - arg_vals = xmalloc (nargs * sizeof (rtx)); - arg_trees = xmalloc (nargs * sizeof (tree)); - - for (formal = DECL_ARGUMENTS (fndecl), actual = parms, i = 0; - formal; - formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual), i++) - { - /* Actual parameter, converted to the type of the argument within the - function. */ - tree arg = convert (TREE_TYPE (formal), TREE_VALUE (actual)); - /* Mode of the variable used within the function. */ - enum machine_mode mode = TYPE_MODE (TREE_TYPE (formal)); - int invisiref = 0; - - arg_trees[i] = arg; - loc = RTVEC_ELT (arg_vector, i); - - /* If this is an object passed by invisible reference, we copy the - object into a stack slot and save its address. If this will go - into memory, we do nothing now. Otherwise, we just expand the - argument. */ - if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG - && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER) - { - rtx stack_slot = assign_temp (TREE_TYPE (arg), 1, 1, 1); - - store_expr (arg, stack_slot, 0); - arg_vals[i] = XEXP (stack_slot, 0); - invisiref = 1; - } - else if (GET_CODE (loc) != MEM) - { - if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg))) - { - int unsignedp = TYPE_UNSIGNED (TREE_TYPE (formal)); - enum machine_mode pmode = TYPE_MODE (TREE_TYPE (formal)); - - pmode = promote_mode (TREE_TYPE (formal), pmode, - &unsignedp, 0); - - if (GET_MODE (loc) != pmode) - abort (); - - /* The mode if LOC and ARG can differ if LOC was a variable - that had its mode promoted. */ - arg_vals[i] = convert_modes (pmode, - TYPE_MODE (TREE_TYPE (arg)), - expand_expr (arg, NULL_RTX, mode, - EXPAND_SUM), - unsignedp); - } - else - arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM); - } - else - arg_vals[i] = 0; - - /* If the formal type was const but the actual was not, we might - end up here with an rtx wrongly tagged unchanging in the caller's - context. Fix that. */ - if (arg_vals[i] != 0 - && (GET_CODE (arg_vals[i]) == REG || GET_CODE (arg_vals[i]) == MEM) - && ! TREE_READONLY (TREE_VALUE (actual))) - RTX_UNCHANGING_P (arg_vals[i]) = 0; - - if (arg_vals[i] != 0 - && (! TREE_READONLY (formal) - /* If the parameter is not read-only, copy our argument through - a register. Also, we cannot use ARG_VALS[I] if it overlaps - TARGET in any way. In the inline function, they will likely - be two different pseudos, and `safe_from_p' will make all - sorts of smart assumptions about their not conflicting. - But if ARG_VALS[I] overlaps TARGET, these assumptions are - wrong, so put ARG_VALS[I] into a fresh register. - Don't worry about invisible references, since their stack - temps will never overlap the target. */ - || (target != 0 - && ! invisiref - && (GET_CODE (arg_vals[i]) == REG - || GET_CODE (arg_vals[i]) == SUBREG - || GET_CODE (arg_vals[i]) == MEM) - && reg_overlap_mentioned_p (arg_vals[i], target)) - /* ??? We must always copy a SUBREG into a REG, because it might - get substituted into an address, and not all ports correctly - handle SUBREGs in addresses. */ - || (GET_CODE (arg_vals[i]) == SUBREG))) - arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]); - - if (arg_vals[i] != 0 && GET_CODE (arg_vals[i]) == REG - && POINTER_TYPE_P (TREE_TYPE (formal))) - mark_reg_pointer (arg_vals[i], - TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal)))); - } - - /* Allocate the structures we use to remap things. */ - - map = xcalloc (1, sizeof (struct inline_remap)); - map->fndecl = fndecl; - - VARRAY_TREE_INIT (map->block_map, 10, "block_map"); - map->reg_map = xcalloc (max_regno, sizeof (rtx)); - - /* We used to use alloca here, but the size of what it would try to - allocate would occasionally cause it to exceed the stack limit and - cause unpredictable core dumps. */ - real_label_map = xmalloc ((max_labelno) * sizeof (rtx)); - map->label_map = real_label_map; - map->local_return_label = NULL_RTX; - - inl_max_uid = (inl_f->emit->x_cur_insn_uid + 1); - map->insn_map = xcalloc (inl_max_uid, sizeof (rtx)); - map->min_insnno = 0; - map->max_insnno = inl_max_uid; - - map->integrating = 1; - map->compare_src = NULL_RTX; - map->compare_mode = VOIDmode; - - /* const_equiv_varray maps pseudos in our routine to constants, so - it needs to be large enough for all our pseudos. This is the - number we are currently using plus the number in the called - routine, plus 15 for each arg, five to compute the virtual frame - pointer, and five for the return value. This should be enough - for most cases. We do not reference entries outside the range of - the map. - - ??? These numbers are quite arbitrary and were obtained by - experimentation. At some point, we should try to allocate the - table after all the parameters are set up so we can more accurately - estimate the number of pseudos we will need. */ - - VARRAY_CONST_EQUIV_INIT (map->const_equiv_varray, - (max_reg_num () - + (max_regno - FIRST_PSEUDO_REGISTER) - + 15 * nargs - + 10), - "expand_inline_function"); - map->const_age = 0; - - /* Record the current insn in case we have to set up pointers to frame - and argument memory blocks. If there are no insns yet, add a dummy - insn that can be used as an insertion point. */ - map->insns_at_start = get_last_insn (); - if (map->insns_at_start == 0) - map->insns_at_start = emit_note (NOTE_INSN_DELETED); - - map->regno_pointer_align = inl_f->emit->regno_pointer_align; - map->x_regno_reg_rtx = inl_f->emit->x_regno_reg_rtx; - - /* Update the outgoing argument size to allow for those in the inlined - function. */ - if (inl_f->outgoing_args_size > current_function_outgoing_args_size) - current_function_outgoing_args_size = inl_f->outgoing_args_size; - - /* If the inline function needs to make PIC references, that means - that this function's PIC offset table must be used. */ - if (inl_f->uses_pic_offset_table) - current_function_uses_pic_offset_table = 1; - - /* If this function needs a context, set it up. */ - if (inl_f->needs_context) - static_chain_value = lookup_static_chain (fndecl); - - /* If the inlined function calls __builtin_constant_p, then we'll - need to call purge_builtin_constant_p on this function. */ - if (inl_f->calls_constant_p) - current_function_calls_constant_p = 1; - - if (GET_CODE (parm_insns) == NOTE - && NOTE_LINE_NUMBER (parm_insns) > 0) - { - rtx note = emit_note_copy (parm_insns); - - if (note) - RTX_INTEGRATED_P (note) = 1; - } - - /* Process each argument. For each, set up things so that the function's - reference to the argument will refer to the argument being passed. - We only replace REG with REG here. Any simplifications are done - via const_equiv_map. - - We make two passes: In the first, we deal with parameters that will - be placed into registers, since we need to ensure that the allocated - register number fits in const_equiv_map. Then we store all non-register - parameters into their memory location. */ - - /* Don't try to free temp stack slots here, because we may put one of the - parameters into a temp stack slot. */ - - for (i = 0; i < nargs; i++) - { - rtx copy = arg_vals[i]; - - loc = RTVEC_ELT (arg_vector, i); - - /* There are three cases, each handled separately. */ - if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG - && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER) - { - /* This must be an object passed by invisible reference (it could - also be a variable-sized object, but we forbid inlining functions - with variable-sized arguments). COPY is the address of the - actual value (this computation will cause it to be copied). We - map that address for the register, noting the actual address as - an equivalent in case it can be substituted into the insns. */ - - if (GET_CODE (copy) != REG) - { - temp = copy_addr_to_reg (copy); - if (CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy)) - SET_CONST_EQUIV_DATA (map, temp, copy, CONST_AGE_PARM); - copy = temp; - } - map->reg_map[REGNO (XEXP (loc, 0))] = copy; - } - else if (GET_CODE (loc) == MEM) - { - /* This is the case of a parameter that lives in memory. It - will live in the block we allocate in the called routine's - frame that simulates the incoming argument area. Do nothing - with the parameter now; we will call store_expr later. In - this case, however, we must ensure that the virtual stack and - incoming arg rtx values are expanded now so that we can be - sure we have enough slots in the const equiv map since the - store_expr call can easily blow the size estimate. */ - if (DECL_STRUCT_FUNCTION (fndecl)->args_size != 0) - copy_rtx_and_substitute (virtual_incoming_args_rtx, map, 0); - } - else if (GET_CODE (loc) == REG) - process_reg_param (map, loc, copy); - else if (GET_CODE (loc) == CONCAT) - { - rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc); - rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc); - rtx copyreal = gen_realpart (GET_MODE (locreal), copy); - rtx copyimag = gen_imagpart (GET_MODE (locimag), copy); - - process_reg_param (map, locreal, copyreal); - process_reg_param (map, locimag, copyimag); - } - else - abort (); - } - - /* Tell copy_rtx_and_substitute to handle constant pool SYMBOL_REFs - specially. This function can be called recursively, so we need to - save the previous value. */ - inlining_previous = inlining; - inlining = inl_f; - - /* Now do the parameters that will be placed in memory. */ - - for (formal = DECL_ARGUMENTS (fndecl), i = 0; - formal; formal = TREE_CHAIN (formal), i++) - { - loc = RTVEC_ELT (arg_vector, i); - - if (GET_CODE (loc) == MEM - /* Exclude case handled above. */ - && ! (GET_CODE (XEXP (loc, 0)) == REG - && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)) - { - rtx note = emit_line_note (DECL_SOURCE_LOCATION (formal)); - - if (note) - RTX_INTEGRATED_P (note) = 1; - - /* Compute the address in the area we reserved and store the - value there. */ - temp = copy_rtx_and_substitute (loc, map, 1); - subst_constants (&temp, NULL_RTX, map, 1); - apply_change_group (); - if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0))) - temp = change_address (temp, VOIDmode, XEXP (temp, 0)); - store_expr (arg_trees[i], temp, 0); - } - } - - /* Deal with the places that the function puts its result. - We are driven by what is placed into DECL_RESULT. - - Initially, we assume that we don't have anything special handling for - REG_FUNCTION_RETURN_VALUE_P. */ - - map->inline_target = 0; - loc = (DECL_RTL_SET_P (DECL_RESULT (fndecl)) - ? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX); - - if (TYPE_MODE (type) == VOIDmode) - /* There is no return value to worry about. */ - ; - else if (GET_CODE (loc) == MEM) - { - if (GET_CODE (XEXP (loc, 0)) == ADDRESSOF) - { - temp = copy_rtx_and_substitute (loc, map, 1); - subst_constants (&temp, NULL_RTX, map, 1); - apply_change_group (); - target = temp; - } - else - { - if (! structure_value_addr - || ! aggregate_value_p (DECL_RESULT (fndecl), fndecl)) - abort (); - - /* Pass the function the address in which to return a structure - value. Note that a constructor can cause someone to call us - with STRUCTURE_VALUE_ADDR, but the initialization takes place - via the first parameter, rather than the struct return address. - - We have two cases: If the address is a simple register - indirect, use the mapping mechanism to point that register to - our structure return address. Otherwise, store the structure - return value into the place that it will be referenced from. */ - - if (GET_CODE (XEXP (loc, 0)) == REG) - { - temp = force_operand (structure_value_addr, NULL_RTX); - temp = force_reg (Pmode, temp); - /* A virtual register might be invalid in an insn, because - it can cause trouble in reload. Since we don't have access - to the expanders at map translation time, make sure we have - a proper register now. - If a virtual register is actually valid, cse or combine - can put it into the mapped insns. */ - if (REGNO (temp) >= FIRST_VIRTUAL_REGISTER - && REGNO (temp) <= LAST_VIRTUAL_REGISTER) - temp = copy_to_mode_reg (Pmode, temp); - map->reg_map[REGNO (XEXP (loc, 0))] = temp; - - if (CONSTANT_P (structure_value_addr) - || GET_CODE (structure_value_addr) == ADDRESSOF - || (GET_CODE (structure_value_addr) == PLUS - && (XEXP (structure_value_addr, 0) - == virtual_stack_vars_rtx) - && (GET_CODE (XEXP (structure_value_addr, 1)) - == CONST_INT))) - { - SET_CONST_EQUIV_DATA (map, temp, structure_value_addr, - CONST_AGE_PARM); - } - } - else - { - temp = copy_rtx_and_substitute (loc, map, 1); - subst_constants (&temp, NULL_RTX, map, 0); - apply_change_group (); - emit_move_insn (temp, structure_value_addr); - } - } - } - else if (ignore) - /* We will ignore the result value, so don't look at its structure. - Note that preparations for an aggregate return value - do need to be made (above) even if it will be ignored. */ - ; - else if (GET_CODE (loc) == REG) - { - /* The function returns an object in a register and we use the return - value. Set up our target for remapping. */ - - /* Machine mode function was declared to return. */ - enum machine_mode departing_mode = TYPE_MODE (type); - /* (Possibly wider) machine mode it actually computes - (for the sake of callers that fail to declare it right). - We have to use the mode of the result's RTL, rather than - its type, since expand_function_start may have promoted it. */ - enum machine_mode arriving_mode - = GET_MODE (DECL_RTL (DECL_RESULT (fndecl))); - rtx reg_to_map; - - /* Don't use MEMs as direct targets because on some machines - substituting a MEM for a REG makes invalid insns. - Let the combiner substitute the MEM if that is valid. */ - if (target == 0 || GET_CODE (target) != REG - || GET_MODE (target) != departing_mode) - { - /* Don't make BLKmode registers. If this looks like - a BLKmode object being returned in a register, get - the mode from that, otherwise abort. */ - if (departing_mode == BLKmode) - { - if (REG == GET_CODE (DECL_RTL (DECL_RESULT (fndecl)))) - { - departing_mode = GET_MODE (DECL_RTL (DECL_RESULT (fndecl))); - arriving_mode = departing_mode; - } - else - abort (); - } - - target = gen_reg_rtx (departing_mode); - } - - /* If function's value was promoted before return, - avoid machine mode mismatch when we substitute INLINE_TARGET. - But TARGET is what we will return to the caller. */ - if (arriving_mode != departing_mode) - { - /* Avoid creating a paradoxical subreg wider than - BITS_PER_WORD, since that is illegal. */ - if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD) - { - if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode), - GET_MODE_BITSIZE (arriving_mode))) - /* Maybe could be handled by using convert_move () ? */ - abort (); - reg_to_map = gen_reg_rtx (arriving_mode); - target = gen_lowpart (departing_mode, reg_to_map); - } - else - reg_to_map = gen_rtx_SUBREG (arriving_mode, target, 0); - } - else - reg_to_map = target; - - /* Usually, the result value is the machine's return register. - Sometimes it may be a pseudo. Handle both cases. */ - if (REG_FUNCTION_VALUE_P (loc)) - map->inline_target = reg_to_map; - else - map->reg_map[REGNO (loc)] = reg_to_map; - } - else if (GET_CODE (loc) == CONCAT) - { - enum machine_mode departing_mode = TYPE_MODE (type); - enum machine_mode arriving_mode - = GET_MODE (DECL_RTL (DECL_RESULT (fndecl))); - - if (departing_mode != arriving_mode) - abort (); - if (GET_CODE (XEXP (loc, 0)) != REG - || GET_CODE (XEXP (loc, 1)) != REG) - abort (); - - /* Don't use MEMs as direct targets because on some machines - substituting a MEM for a REG makes invalid insns. - Let the combiner substitute the MEM if that is valid. */ - if (target == 0 || GET_CODE (target) != REG - || GET_MODE (target) != departing_mode) - target = gen_reg_rtx (departing_mode); - - if (GET_CODE (target) != CONCAT) - abort (); - - map->reg_map[REGNO (XEXP (loc, 0))] = XEXP (target, 0); - map->reg_map[REGNO (XEXP (loc, 1))] = XEXP (target, 1); - } - else - abort (); - - /* Remap the exception handler data pointer from one to the other. */ - temp = get_exception_pointer (inl_f); - if (temp) - map->reg_map[REGNO (temp)] = get_exception_pointer (cfun); - - /* Initialize label_map. get_label_from_map will actually make - the labels. */ - memset (&map->label_map[min_labelno], 0, - (max_labelno - min_labelno) * sizeof (rtx)); - - /* Make copies of the decls of the symbols in the inline function, so that - the copies of the variables get declared in the current function. Set - up things so that lookup_static_chain knows that to interpret registers - in SAVE_EXPRs for TYPE_SIZEs as local. */ - inline_function_decl = fndecl; - integrate_parm_decls (DECL_ARGUMENTS (fndecl), map, arg_vector); - block = integrate_decl_tree (inl_f->original_decl_initial, map); - BLOCK_ABSTRACT_ORIGIN (block) = DECL_ORIGIN (fndecl); - inline_function_decl = 0; - - /* Make a fresh binding contour that we can easily remove. Do this after - expanding our arguments so cleanups are properly scoped. */ - expand_start_bindings_and_block (0, block); - - /* Sort the block-map so that it will be easy to find remapped - blocks later. */ - qsort (&VARRAY_TREE (map->block_map, 0), - map->block_map->elements_used, - sizeof (tree), - compare_blocks); - - /* Perform postincrements before actually calling the function. */ - emit_queue (); - - /* Clean up stack so that variables might have smaller offsets. */ - do_pending_stack_adjust (); - - /* Save a copy of the location of const_equiv_varray for - mark_stores, called via note_stores. */ - global_const_equiv_varray = map->const_equiv_varray; - - /* If the called function does an alloca, save and restore the - stack pointer around the call. This saves stack space, but - also is required if this inline is being done between two - pushes. */ - if (inl_f->calls_alloca) - emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX); - - /* Map pseudos used for initial hard reg values. */ - setup_initial_hard_reg_value_integration (inl_f, map); - - /* Now copy the insns one by one. */ - copy_insn_list (insns, map, static_chain_value); - - /* Duplicate the EH regions. This will create an offset from the - region numbers in the function we're inlining to the region - numbers in the calling function. This must wait until after - copy_insn_list, as we need the insn map to be complete. */ - eh_region_offset = duplicate_eh_regions (inl_f, map); - - /* Now copy the REG_NOTES for those insns. */ - copy_insn_notes (insns, map, eh_region_offset); - - /* If the insn sequence required one, emit the return label. */ - if (map->local_return_label) - emit_label (map->local_return_label); - - /* Restore the stack pointer if we saved it above. */ - if (inl_f->calls_alloca) - emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX); - - if (! cfun->x_whole_function_mode_p) - /* In statement-at-a-time mode, we just tell the front-end to add - this block to the list of blocks at this binding level. We - can't do it the way it's done for function-at-a-time mode the - superblocks have not been created yet. */ - lang_hooks.decls.insert_block (block); - else - { - BLOCK_CHAIN (block) - = BLOCK_CHAIN (DECL_INITIAL (current_function_decl)); - BLOCK_CHAIN (DECL_INITIAL (current_function_decl)) = block; - } - - /* End the scope containing the copied formal parameter variables - and copied LABEL_DECLs. We pass NULL_TREE for the variables list - here so that expand_end_bindings will not check for unused - variables. That's already been checked for when the inlined - function was defined. */ - expand_end_bindings (NULL_TREE, 1, 1); - - /* Must mark the line number note after inlined functions as a repeat, so - that the test coverage code can avoid counting the call twice. This - just tells the code to ignore the immediately following line note, since - there already exists a copy of this note before the expanded inline call. - This line number note is still needed for debugging though, so we can't - delete it. */ - if (flag_test_coverage) - emit_note (NOTE_INSN_REPEATED_LINE_NUMBER); - - emit_line_note (input_location); - - /* If the function returns a BLKmode object in a register, copy it - out of the temp register into a BLKmode memory object. */ - if (target - && TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode - && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)), fndecl)) - target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl))); - - if (structure_value_addr) - { - target = gen_rtx_MEM (TYPE_MODE (type), - memory_address (TYPE_MODE (type), - structure_value_addr)); - set_mem_attributes (target, type, 1); - } - - /* Make sure we free the things we explicitly allocated with xmalloc. */ - if (real_label_map) - free (real_label_map); - VARRAY_FREE (map->const_equiv_varray); - free (map->reg_map); - free (map->insn_map); - free (map); - free (arg_vals); - free (arg_trees); - - inlining = inlining_previous; - - return target; -} - -/* Make copies of each insn in the given list using the mapping - computed in expand_inline_function. This function may call itself for - insns containing sequences. - - Copying is done in two passes, first the insns and then their REG_NOTES. - - If static_chain_value is nonzero, it represents the context-pointer - register for the function. */ - -static void -copy_insn_list (rtx insns, struct inline_remap *map, rtx static_chain_value) -{ - int i; - rtx insn; - rtx temp; -#ifdef HAVE_cc0 - rtx cc0_insn = 0; -#endif - rtx static_chain_mem = 0; - - /* Copy the insns one by one. Do this in two passes, first the insns and - then their REG_NOTES. */ - - /* This loop is very similar to the loop in copy_loop_body in unroll.c. */ - - for (insn = insns; insn; insn = NEXT_INSN (insn)) - { - rtx copy, pattern, set; - - map->orig_asm_operands_vector = 0; - - switch (GET_CODE (insn)) - { - case INSN: - pattern = PATTERN (insn); - set = single_set (insn); - copy = 0; - if (GET_CODE (pattern) == USE - && GET_CODE (XEXP (pattern, 0)) == REG - && REG_FUNCTION_VALUE_P (XEXP (pattern, 0))) - /* The (USE (REG n)) at return from the function should - be ignored since we are changing (REG n) into - inline_target. */ - break; - - /* Ignore setting a function value that we don't want to use. */ - if (map->inline_target == 0 - && set != 0 - && GET_CODE (SET_DEST (set)) == REG - && REG_FUNCTION_VALUE_P (SET_DEST (set))) - { - if (volatile_refs_p (SET_SRC (set))) - { - rtx new_set; - - /* If we must not delete the source, - load it into a new temporary. */ - copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0)); - - new_set = single_set (copy); - if (new_set == 0) - abort (); - - SET_DEST (new_set) - = gen_reg_rtx (GET_MODE (SET_DEST (new_set))); - } - /* If the source and destination are the same and it - has a note on it, keep the insn. */ - else if (rtx_equal_p (SET_DEST (set), SET_SRC (set)) - && REG_NOTES (insn) != 0) - copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0)); - else - break; - } - - /* Similarly if an ignored return value is clobbered. */ - else if (map->inline_target == 0 - && GET_CODE (pattern) == CLOBBER - && GET_CODE (XEXP (pattern, 0)) == REG - && REG_FUNCTION_VALUE_P (XEXP (pattern, 0))) - break; - - /* Look for the address of the static chain slot. The - rtx_equal_p comparisons against the - static_chain_incoming_rtx below may fail if the static - chain is in memory and the address specified is not - "legitimate". This happens on Xtensa where the static - chain is at a negative offset from argp and where only - positive offsets are legitimate. When the RTL is - generated, the address is "legitimized" by copying it - into a register, causing the rtx_equal_p comparisons to - fail. This workaround looks for code that sets a - register to the address of the static chain. Subsequent - memory references via that register can then be - identified as static chain references. We assume that - the register is only assigned once, and that the static - chain address is only live in one register at a time. */ - - else if (static_chain_value != 0 - && set != 0 - && GET_CODE (static_chain_incoming_rtx) == MEM - && GET_CODE (SET_DEST (set)) == REG - && rtx_equal_p (SET_SRC (set), - XEXP (static_chain_incoming_rtx, 0))) - { - static_chain_mem = - gen_rtx_MEM (GET_MODE (static_chain_incoming_rtx), - SET_DEST (set)); - - /* Emit the instruction in case it is used for something - other than setting the static chain; if it's not used, - it can always be removed as dead code */ - copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0)); - } - - /* If this is setting the static chain rtx, omit it. */ - else if (static_chain_value != 0 - && set != 0 - && (rtx_equal_p (SET_DEST (set), - static_chain_incoming_rtx) - || (static_chain_mem - && rtx_equal_p (SET_DEST (set), static_chain_mem)))) - break; - - /* If this is setting the static chain pseudo, set it from - the value we want to give it instead. */ - else if (static_chain_value != 0 - && set != 0 - && (rtx_equal_p (SET_SRC (set), - static_chain_incoming_rtx) - || (static_chain_mem - && rtx_equal_p (SET_SRC (set), static_chain_mem)))) - { - rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map, 1); - - copy = emit_move_insn (newdest, static_chain_value); - if (GET_CODE (static_chain_incoming_rtx) != MEM) - static_chain_value = 0; - } - - /* If this is setting the virtual stack vars register, this must - be the code at the handler for a builtin longjmp. The value - saved in the setjmp buffer will be the address of the frame - we've made for this inlined instance within our frame. But we - know the offset of that value so we can use it to reconstruct - our virtual stack vars register from that value. If we are - copying it from the stack pointer, leave it unchanged. */ - else if (set != 0 - && rtx_equal_p (SET_DEST (set), virtual_stack_vars_rtx)) - { - HOST_WIDE_INT offset; - temp = map->reg_map[REGNO (SET_DEST (set))]; - temp = VARRAY_CONST_EQUIV (map->const_equiv_varray, - REGNO (temp)).rtx; - - if (rtx_equal_p (temp, virtual_stack_vars_rtx)) - offset = 0; - else if (GET_CODE (temp) == PLUS - && rtx_equal_p (XEXP (temp, 0), virtual_stack_vars_rtx) - && GET_CODE (XEXP (temp, 1)) == CONST_INT) - offset = INTVAL (XEXP (temp, 1)); - else - abort (); - - if (rtx_equal_p (SET_SRC (set), stack_pointer_rtx)) - temp = SET_SRC (set); - else - temp = force_operand (plus_constant (SET_SRC (set), - - offset), - NULL_RTX); - - copy = emit_move_insn (virtual_stack_vars_rtx, temp); - } - - else - copy = emit_insn (copy_rtx_and_substitute (pattern, map, 0)); - /* REG_NOTES will be copied later. */ - -#ifdef HAVE_cc0 - /* If this insn is setting CC0, it may need to look at - the insn that uses CC0 to see what type of insn it is. - In that case, the call to recog via validate_change will - fail. So don't substitute constants here. Instead, - do it when we emit the following insn. - - For example, see the pyr.md file. That machine has signed and - unsigned compares. The compare patterns must check the - following branch insn to see which what kind of compare to - emit. - - If the previous insn set CC0, substitute constants on it as - well. */ - if (sets_cc0_p (PATTERN (copy)) != 0) - cc0_insn = copy; - else - { - if (cc0_insn) - try_constants (cc0_insn, map); - cc0_insn = 0; - try_constants (copy, map); - } -#else - try_constants (copy, map); -#endif - INSN_LOCATOR (copy) = INSN_LOCATOR (insn); - break; - - case JUMP_INSN: - if (map->integrating && returnjump_p (insn)) - { - if (map->local_return_label == 0) - map->local_return_label = gen_label_rtx (); - pattern = gen_jump (map->local_return_label); - } - else - pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0); - - copy = emit_jump_insn (pattern); - -#ifdef HAVE_cc0 - if (cc0_insn) - try_constants (cc0_insn, map); - cc0_insn = 0; -#endif - try_constants (copy, map); - INSN_LOCATOR (copy) = INSN_LOCATOR (insn); - - /* If this used to be a conditional jump insn but whose branch - direction is now know, we must do something special. */ - if (any_condjump_p (insn) && onlyjump_p (insn) && map->last_pc_value) - { -#ifdef HAVE_cc0 - /* If the previous insn set cc0 for us, delete it. */ - if (only_sets_cc0_p (PREV_INSN (copy))) - delete_related_insns (PREV_INSN (copy)); -#endif - - /* If this is now a no-op, delete it. */ - if (map->last_pc_value == pc_rtx) - { - delete_related_insns (copy); - copy = 0; - } - else - /* Otherwise, this is unconditional jump so we must put a - BARRIER after it. We could do some dead code elimination - here, but jump.c will do it just as well. */ - emit_barrier (); - } - break; - - case CALL_INSN: - /* If this is a CALL_PLACEHOLDER insn then we need to copy the - three attached sequences: normal call, sibling call and tail - recursion. */ - if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - { - rtx sequence[3]; - rtx tail_label; - - for (i = 0; i < 3; i++) - { - rtx seq; - - sequence[i] = NULL_RTX; - seq = XEXP (PATTERN (insn), i); - if (seq) - { - start_sequence (); - copy_insn_list (seq, map, static_chain_value); - sequence[i] = get_insns (); - end_sequence (); - } - } - - /* Find the new tail recursion label. - It will already be substituted into sequence[2]. */ - tail_label = copy_rtx_and_substitute (XEXP (PATTERN (insn), 3), - map, 0); - - copy = emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, - sequence[0], - sequence[1], - sequence[2], - tail_label)); - break; - } - - pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0); - copy = emit_call_insn (pattern); - - SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn); - CONST_OR_PURE_CALL_P (copy) = CONST_OR_PURE_CALL_P (insn); - INSN_LOCATOR (copy) = INSN_LOCATOR (insn); - - /* Because the USAGE information potentially contains objects other - than hard registers, we need to copy it. */ - - CALL_INSN_FUNCTION_USAGE (copy) - = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), - map, 0); - -#ifdef HAVE_cc0 - if (cc0_insn) - try_constants (cc0_insn, map); - cc0_insn = 0; -#endif - try_constants (copy, map); - - /* Be lazy and assume CALL_INSNs clobber all hard registers. */ - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - VARRAY_CONST_EQUIV (map->const_equiv_varray, i).rtx = 0; - break; - - case CODE_LABEL: - copy = emit_label (get_label_from_map (map, - CODE_LABEL_NUMBER (insn))); - LABEL_NAME (copy) = LABEL_NAME (insn); - map->const_age++; - break; - - case BARRIER: - copy = emit_barrier (); - break; - - case NOTE: - if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL) - { - copy = emit_label (get_label_from_map (map, - CODE_LABEL_NUMBER (insn))); - LABEL_NAME (copy) = NOTE_SOURCE_FILE (insn); - map->const_age++; - break; - } - - /* NOTE_INSN_FUNCTION_END and NOTE_INSN_FUNCTION_BEG are - discarded because it is important to have only one of - each in the current function. - - NOTE_INSN_DELETED notes aren't useful. */ - - if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END - && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG - && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED) - { - copy = emit_note_copy (insn); - if (!copy) - /*Copied a line note, but line numbering is off*/; - else if ((NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_BEG - || NOTE_LINE_NUMBER (copy) == NOTE_INSN_BLOCK_END) - && NOTE_BLOCK (insn)) - { - tree *mapped_block_p; - - mapped_block_p - = bsearch (NOTE_BLOCK (insn), - &VARRAY_TREE (map->block_map, 0), - map->block_map->elements_used, - sizeof (tree), - find_block); - - if (!mapped_block_p) - abort (); - else - NOTE_BLOCK (copy) = *mapped_block_p; - } - else if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EXPECTED_VALUE) - NOTE_EXPECTED_VALUE (copy) - = copy_rtx_and_substitute (NOTE_EXPECTED_VALUE (insn), - map, 0); - } - else - copy = 0; - break; - - default: - abort (); - } - - if (copy) - RTX_INTEGRATED_P (copy) = 1; - - map->insn_map[INSN_UID (insn)] = copy; - } -} - -/* Copy the REG_NOTES. Increment const_age, so that only constants - from parameters can be substituted in. These are the only ones - that are valid across the entire function. */ - -static void -copy_insn_notes (rtx insns, struct inline_remap *map, int eh_region_offset) -{ - rtx insn, new_insn; - - map->const_age++; - for (insn = insns; insn; insn = NEXT_INSN (insn)) - { - if (! INSN_P (insn)) - continue; - - new_insn = map->insn_map[INSN_UID (insn)]; - if (! new_insn) - continue; - - if (REG_NOTES (insn)) - { - rtx next, note = copy_rtx_and_substitute (REG_NOTES (insn), map, 0); - - /* We must also do subst_constants, in case one of our parameters - has const type and constant value. */ - subst_constants (¬e, NULL_RTX, map, 0); - apply_change_group (); - REG_NOTES (new_insn) = note; - - /* Delete any REG_LABEL notes from the chain. Remap any - REG_EH_REGION notes. */ - for (; note; note = next) - { - next = XEXP (note, 1); - if (REG_NOTE_KIND (note) == REG_LABEL) - remove_note (new_insn, note); - else if (REG_NOTE_KIND (note) == REG_EH_REGION - && INTVAL (XEXP (note, 0)) > 0) - XEXP (note, 0) = GEN_INT (INTVAL (XEXP (note, 0)) - + eh_region_offset); - } - } - - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - { - int i; - for (i = 0; i < 3; i++) - copy_insn_notes (XEXP (PATTERN (insn), i), map, eh_region_offset); - } - - if (GET_CODE (insn) == JUMP_INSN - && GET_CODE (PATTERN (insn)) == RESX) - XINT (PATTERN (new_insn), 0) += eh_region_offset; - } -} - -/* Given a chain of PARM_DECLs, ARGS, copy each decl into a VAR_DECL, - push all of those decls and give each one the corresponding home. */ - -static void -integrate_parm_decls (tree args, struct inline_remap *map, rtvec arg_vector) -{ - tree tail; - int i; - - for (tail = args, i = 0; tail; tail = TREE_CHAIN (tail), i++) - { - tree decl = copy_decl_for_inlining (tail, map->fndecl, - current_function_decl); - rtx new_decl_rtl - = copy_rtx_and_substitute (RTVEC_ELT (arg_vector, i), map, 1); - - /* We really should be setting DECL_INCOMING_RTL to something reasonable - here, but that's going to require some more work. */ - /* DECL_INCOMING_RTL (decl) = ?; */ - /* Fully instantiate the address with the equivalent form so that the - debugging information contains the actual register, instead of the - virtual register. Do this by not passing an insn to - subst_constants. */ - subst_constants (&new_decl_rtl, NULL_RTX, map, 1); - apply_change_group (); - SET_DECL_RTL (decl, new_decl_rtl); - } -} - -/* Given a BLOCK node LET, push decls and levels so as to construct in the - current function a tree of contexts isomorphic to the one that is given. - - MAP, if nonzero, is a pointer to an inline_remap map which indicates how - registers used in the DECL_RTL field should be remapped. If it is zero, - no mapping is necessary. */ - -static tree -integrate_decl_tree (tree let, struct inline_remap *map) -{ - tree t; - tree new_block; - tree *next; - - new_block = make_node (BLOCK); - VARRAY_PUSH_TREE (map->block_map, new_block); - next = &BLOCK_VARS (new_block); - - for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t)) - { - tree d; - - d = copy_decl_for_inlining (t, map->fndecl, current_function_decl); - - if (DECL_RTL_SET_P (t)) - { - rtx r; - - SET_DECL_RTL (d, copy_rtx_and_substitute (DECL_RTL (t), map, 1)); - - /* Fully instantiate the address with the equivalent form so that the - debugging information contains the actual register, instead of the - virtual register. Do this by not passing an insn to - subst_constants. */ - r = DECL_RTL (d); - subst_constants (&r, NULL_RTX, map, 1); - SET_DECL_RTL (d, r); - - apply_change_group (); - } - - /* Add this declaration to the list of variables in the new - block. */ - *next = d; - next = &TREE_CHAIN (d); - } - - next = &BLOCK_SUBBLOCKS (new_block); - for (t = BLOCK_SUBBLOCKS (let); t; t = BLOCK_CHAIN (t)) - { - *next = integrate_decl_tree (t, map); - BLOCK_SUPERCONTEXT (*next) = new_block; - next = &BLOCK_CHAIN (*next); - } - - TREE_USED (new_block) = TREE_USED (let); - BLOCK_ABSTRACT_ORIGIN (new_block) = let; - - return new_block; -} - /* Create a new copy of an rtx. Recursively copies the operands of the rtx, except for those few rtx codes that are sharable. @@ -1884,10 +241,7 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs) Small hard registers are returned as-is. Pseudo-registers go through their `reg_map'. */ regno = REGNO (orig); - if (regno <= LAST_VIRTUAL_REGISTER - || (map->integrating - && DECL_STRUCT_FUNCTION (map->fndecl)->internal_arg_pointer - == orig)) + if (regno <= LAST_VIRTUAL_REGISTER) { /* Some hard registers are also mapped, but others are not translated. */ @@ -1942,10 +296,7 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs) emit_insn_after (seq, map->insns_at_start); return temp; } - else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM - || (map->integrating - && (DECL_STRUCT_FUNCTION (map->fndecl)->internal_arg_pointer - == orig))) + else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM) { /* Do the same for a block to contain any arguments referenced in memory. */ @@ -1977,44 +328,17 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs) } else if (REG_FUNCTION_VALUE_P (orig)) { - /* This is a reference to the function return value. If - the function doesn't have a return value, error. If the - mode doesn't agree, and it ain't BLKmode, make a SUBREG. */ - if (map->inline_target == 0) - { - if (rtx_equal_function_value_matters) - /* This is an ignored return value. We must not - leave it in with REG_FUNCTION_VALUE_P set, since - that would confuse subsequent inlining of the - current function into a later function. */ - return gen_rtx_REG (GET_MODE (orig), regno); - else - /* Must be unrolling loops or replicating code if we - reach here, so return the register unchanged. */ - return orig; - } - else if (GET_MODE (map->inline_target) != BLKmode - && mode != GET_MODE (map->inline_target)) - return gen_lowpart (mode, map->inline_target); + if (rtx_equal_function_value_matters) + /* This is an ignored return value. We must not + leave it in with REG_FUNCTION_VALUE_P set, since + that would confuse subsequent inlining of the + current function into a later function. */ + return gen_rtx_REG (GET_MODE (orig), regno); else - return map->inline_target; - } -#if defined (LEAF_REGISTERS) && defined (LEAF_REG_REMAP) - /* If leaf_renumber_regs_insn() might remap this register to - some other number, make sure we don't share it with the - inlined function, otherwise delayed optimization of the - inlined function may change it in place, breaking our - reference to it. We may still shared it within the - function, so create an entry for this register in the - reg_map. */ - if (map->integrating && regno < FIRST_PSEUDO_REGISTER - && LEAF_REGISTERS[regno] && LEAF_REG_REMAP (regno) != regno) - { - if (!map->leaf_reg_map[regno][mode]) - map->leaf_reg_map[regno][mode] = gen_rtx_REG (mode, regno); - return map->leaf_reg_map[regno][mode]; + /* Must be unrolling loops or replicating code if we + reach here, so return the register unchanged. */ + return orig; } -#endif else return orig; @@ -2136,44 +460,14 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs) remapped label. Otherwise, symbols are returned unchanged. */ if (CONSTANT_POOL_ADDRESS_P (orig)) { - struct function *f = inlining ? inlining : cfun; + struct function *f = cfun; rtx constant = get_pool_constant_for_function (f, orig); - enum machine_mode const_mode = get_pool_mode_for_function (f, orig); - if (inlining) - { - rtx temp = force_const_mem (const_mode, - copy_rtx_and_substitute (constant, - map, 0)); - -#if 0 - /* Legitimizing the address here is incorrect. - - Since we had a SYMBOL_REF before, we can assume it is valid - to have one in this position in the insn. - - Also, change_address may create new registers. These - registers will not have valid reg_map entries. This can - cause try_constants() to fail because assumes that all - registers in the rtx have valid reg_map entries, and it may - end up replacing one of these new registers with junk. */ - - if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0))) - temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0)); -#endif - - temp = XEXP (temp, 0); - temp = convert_memory_address (GET_MODE (orig), temp); - return temp; - } - else if (GET_CODE (constant) == LABEL_REF) + if (GET_CODE (constant) == LABEL_REF) return XEXP (force_const_mem (GET_MODE (orig), copy_rtx_and_substitute (constant, map, for_lhs)), 0); } - else if (TREE_CONSTANT_POOL_ADDRESS_P (orig) && inlining) - notice_rtl_inlining_of_deferred_constant (); - return orig; case CONST_DOUBLE: @@ -2192,10 +486,6 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs) CONST_DOUBLE_HIGH (orig), VOIDmode); case CONST: - /* Make new constant pool entry for a constant - that was in the pool of the inline function. */ - if (RTX_INTEGRATED_P (orig)) - abort (); break; case ASM_OPERANDS: @@ -2244,7 +534,8 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs) break; #if 0 - /* Must be ifdefed out for loop unrolling to work. */ + /* Must be ifdefed out for loop unrolling to work. */ + /* ??? Is this for the old or the new unroller? */ case RETURN: abort (); #endif @@ -2284,46 +575,9 @@ copy_rtx_and_substitute (rtx orig, struct inline_remap *map, int for_lhs) break; case MEM: - if (inlining - && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF - && CONSTANT_POOL_ADDRESS_P (XEXP (orig, 0))) - { - enum machine_mode const_mode - = get_pool_mode_for_function (inlining, XEXP (orig, 0)); - rtx constant - = get_pool_constant_for_function (inlining, XEXP (orig, 0)); - - constant = copy_rtx_and_substitute (constant, map, 0); - - /* If this was an address of a constant pool entry that itself - had to be placed in the constant pool, it might not be a - valid address. So the recursive call might have turned it - into a register. In that case, it isn't a constant any - more, so return it. This has the potential of changing a - MEM into a REG, but we'll assume that it safe. */ - if (! CONSTANT_P (constant)) - return constant; - - return validize_mem (force_const_mem (const_mode, constant)); - } - copy = gen_rtx_MEM (mode, copy_rtx_and_substitute (XEXP (orig, 0), map, 0)); MEM_COPY_ATTRIBUTES (copy, orig); - - /* If inlining and this is not for the LHS, turn off RTX_UNCHANGING_P - since this may be an indirect reference to a parameter and the - actual may not be readonly. */ - if (inlining && !for_lhs) - RTX_UNCHANGING_P (copy) = 0; - - /* If inlining, squish aliasing data that references the subroutine's - parameter list, since that's no longer applicable. */ - if (inlining && MEM_EXPR (copy) - && TREE_CODE (MEM_EXPR (copy)) == INDIRECT_REF - && TREE_CODE (TREE_OPERAND (MEM_EXPR (copy), 0)) == PARM_DECL) - set_mem_expr (copy, NULL_TREE); - return copy; default: @@ -2950,52 +1204,6 @@ set_decl_abstract_flags (tree decl, int setting) set_block_abstract_flags (DECL_INITIAL (decl), setting); } } - -/* Output the assembly language code for the function FNDECL from - its DECL_STRUCT_FUNCTION. Used for inline functions that are output - at end of compilation instead of where they came in the source. */ - -static GTY(()) struct function *old_cfun; - -void -output_inline_function (tree fndecl) -{ - enum debug_info_type old_write_symbols = write_symbols; - const struct gcc_debug_hooks *const old_debug_hooks = debug_hooks; - struct function *f = DECL_STRUCT_FUNCTION (fndecl); - - old_cfun = cfun; - cfun = f; - current_function_decl = fndecl; - - set_new_last_label_num (f->inl_max_label_num); - - /* We're not deferring this any longer. */ - DECL_DEFER_OUTPUT (fndecl) = 0; - - /* If requested, suppress debugging information. */ - if (f->no_debugging_symbols) - { - write_symbols = NO_DEBUG; - debug_hooks = &do_nothing_debug_hooks; - } - - /* Make sure warnings emitted by the optimizers (e.g. control reaches - end of non-void function) is not wildly incorrect. */ - input_location = DECL_SOURCE_LOCATION (fndecl); - - /* Compile this function all the way down to assembly code. As a - side effect this destroys the saved RTL representation, but - that's okay, because we don't need to inline this anymore. */ - rest_of_compilation (fndecl); - DECL_INLINE (fndecl) = 0; - - cfun = old_cfun; - current_function_decl = old_cfun ? old_cfun->decl : 0; - write_symbols = old_write_symbols; - debug_hooks = old_debug_hooks; -} - /* Functions to keep track of the values hard regs had at the start of the function. */ @@ -3076,21 +1284,6 @@ has_hard_reg_initial_val (enum machine_mode mode, int regno) return has_func_hard_reg_initial_val (cfun, gen_rtx_REG (mode, regno)); } -static void -setup_initial_hard_reg_value_integration (struct function *inl_f, struct inline_remap *remap) -{ - struct initial_value_struct *ivs = inl_f->hard_reg_initial_vals; - int i; - - if (ivs == 0) - return; - - for (i = 0; i < ivs->num_entries; i ++) - remap->reg_map[REGNO (ivs->entries[i].pseudo)] - = get_func_hard_reg_initial_val (cfun, ivs->entries[i].hard_reg); -} - - void emit_initial_value_sets (void) { diff --git a/gcc/integrate.h b/gcc/integrate.h index 94bf2e738d4..88a4f5ddeb7 100644 --- a/gcc/integrate.h +++ b/gcc/integrate.h @@ -35,23 +35,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA struct inline_remap { - /* True if we are doing function integration, false otherwise. - Used to control whether RTX_UNCHANGING bits are copied by - copy_rtx_and_substitute. */ - int integrating; /* Definition of function be inlined. */ tree fndecl; /* Place to put insns needed at start of function. */ rtx insns_at_start; - /* Mapping from old BLOCKs to new BLOCKs. */ - varray_type block_map; /* Mapping from old registers to new registers. It is allocated and deallocated in `expand_inline_function' */ rtx *reg_map; -#if defined (LEAF_REGISTERS) && defined (LEAF_REG_REMAP) - /* Mapping from old leaf registers to new leaf registers. */ - rtx leaf_reg_map[FIRST_PSEUDO_REGISTER][NUM_MACHINE_MODES]; -#endif /* Mapping from old code-labels to new code-labels. The first element of this map is label_map[min_labelno]. */ rtx *label_map; @@ -85,8 +75,6 @@ struct inline_remap #define CONST_AGE_PARM (-1) unsigned int const_age; - /* Target of the inline function being expanded, or NULL if none. */ - rtx inline_target; /* When an insn is being copied by copy_rtx_and_substitute, this is nonzero if we have copied an ASM_OPERANDS. In that case, it is the original input-operand vector. */ @@ -98,9 +86,6 @@ struct inline_remap /* Likewise, this is the copied constraints vector. */ rtvec copy_asm_constraints_vector; - /* Target of a return insn, if needed and inlining. */ - rtx local_return_label; - /* Indications for regs being pointers and their alignment. */ unsigned char *regno_pointer_align; rtx *x_regno_reg_rtx; diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 25594a31db1..7ac2ba59554 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,14 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. See + ChangeLog.tree-ssa for details. + + * Make-lang.in, builtins.c, check-init.c, class.c, + constants.c, decl.c, except.c, expr.c, java-except.h, + java-tree.def, java-tree.h, jcf-parse.c, jcf-write.c, + lang.c, lang.opt, parse.y, resource.c: Merged. + * java-gimplify.c: New file. + 2004-05-10 Andrew Haley * parse.y (create_class): Set TYPE_VFIELD. diff --git a/gcc/java/ChangeLog.tree-ssa b/gcc/java/ChangeLog.tree-ssa new file mode 100644 index 00000000000..81081a52860 --- /dev/null +++ b/gcc/java/ChangeLog.tree-ssa @@ -0,0 +1,360 @@ +2004-05-10 Andrew Haley + + * java-gimplify.c (java_gimplify_expr): Copy the LHS of a binary + expression into a temporary variable. + + (java_gimplify_new_array_init): Set the DECL_CONTEXT of array and + tmp to current_function_decl. + +2004-04-13 Diego Novillo + + * expr.c (build_expr_wfl): Don't check type nodes for + side effects. + +2004-04-12 Diego Novillo + + * decl.c (java_expand_stmt): Remove. + * lang.c (LANG_HOOKS_RTL_EXPAND_STMT): Remove. + +2004-02-24 Richard Henderson + + * java-gimplify.c (java_gimplify_new_array_init): Remove extra + argument building BLOCK. + +2004-02-19 Steven Bosscher + + * decl.c (poplevel): Don't output nested inline functions. + +2004-02-16 Richard Henderson + + * builtins.c (java_build_function_call_expr): Add static chain + operand to call_expr. + +2004-01-29 Richard Henderson + + PR java/12906 + * decl.c (maybe_pushlevels): Careful with TREE_CHAIN when + registering decls with push_jvm_slot. + +2003-12-10 Diego Novillo + + * parse.y (resolve_field_access): Remove superfluous + initialization of decl. + +2003-12-10 Richard Henderson + + * lang.c (java_post_options): Don't ever use rtl inlining. + +2003-12-06 Jan Hubicka + + * parse.y (resolve_field_access): Initialize decl. + +2003-11-31 Richard Henderson + + * lang.c (java_start_inlining): Remove. + (LANG_HOOKS_TREE_INLINING_START_INLINING): Remove. + +2003-11-31 Richard Henderson + + * jcf-parse.c (java_parse_file): Finalize cgraph after emitting + class tables. + +2003-11-24 Richard Henderson + + * Make-lang.in (parse.o): Remove -Wno-error. + +2003-11-20 Richard Henderson + + * constants.c (build_constant_data_ref): Lay out the array type. + +2003-11-20 Richard Henderson + + * class.c (build_indirect_class_ref): Use convert. + * constants.c (build_constant_data_ref): Fix type on the decl + and return that directly. + (build_constants_constructor): Remove kruft to match. + (build_ref_from_constant_pool): Use ARRAY_REF. + * expr.c (build_java_indirect_ref): Use convert. + (build_known_method_ref): Likewise. + * parse.y (patch_string_cst): Likewise. + + * class.c (finish_class): Kill code to output_inline_function. + +2003-11-12 Jason Merrill + + PR optimization/12547 + * lang.c (java_tree_inlining_walk_subtrees): Restore. + (LANG_HOOKS_TREE_INLINING_WALK_SUBTREES): Restore. + +2003-11-12 Richard Henderson + + * java-gimplify.c (java_gimplify_expr): Use annotate_with_locus + instead of annotate_all_with_locus. + +2003-11-10 Richard Henderson + + * expr.c: Use append_to_statement_list instead of add_tree. + +2003-10-30 Richard Henderson + + * java-gimplify.c (cleanup_compound_expr): Remove. + (cleanup_try_finally_expr): Remove. + (java_gimplify_expr): Don't call them. + (java_gimplify_case_expr): Use create_artificial_label. + (java_gimplify_default_expr): Likewise. + +2003-10-30 Richard Henderson + + * expr.c (expand_java_switch, expand_java_add_case): New. + (LOOKUP_SWITCH, TABLE_SWITCH): Use them. + +2003-10-23 Richard Henderson + + * java-gimplify.c (java_gimplify_expr): Return gimplify_status. + +2003-10-14 Richard Henderson + + * decl.c (finish_method): Set cfun->function_end_locus. + * java-gimplify.c (java_gimplify_expr): Set input_location + for EXPR_WITH_FILE_LOCATION. Use annotate_all_with_locus. + * parse.h (DECL_SOURCE_LINE_MERGE): Remove. + (DECL_SOURCE_LINE_FIRST, DECL_SOURCE_LINE_LAST): Remove. + * parse.y (missing_return_error): Use DECL_FUNCTION_LAST_LINE. + (finish_method_declaration): Likewise. + (start_artificial_method_body): Likewise. + (lookup_cl): Use DECL_SOURCE_LINE. + (start_complete_expand_method): Likewise. + (java_complete_lhs): Fix IS_EXPR_CODE_CLASS check. + +2003-10-13 Richard Henderson + + * decl.c (java_add_stmt): Use annotate_with_locus. + +2003-10-13 Richard Henderson + + * expr.c (build_java_jsr): Don't emit LABEL_EXPR or + load_type_state here. + +2003-10-12 Richard Henderson + + * class.c (build_utf8_ref, get_dispatch_table): Set TREE_INVARIANT. + (make_class_data, build_symbol_entry, emit_symbol_table): Likewise. + * decl.c (java_init_decl_processing): Likewise. + * except.c (prepare_eh_table_type): Likewise. + * parse.y (patch_assignment, patch_binop): Likewise. + (patch_string_cst, patch_new_array_init): Likewise. + * resource.c (compile_resource_data): Likewise. + +2003-10-08 Jeff Sturm + + * decl.c (cgraph.h): Include. + (tree-inline.h, tree-dump.h, tree-flow.h): Remove includes. + (complete_start_java_method): Remove. + (start_java_method): Combine with complete_start_java_method. + Remove dead code. + (end_java_method): Don't patch or expand tree. + Use finish_method. + (finish_method): New function. + (java_expand_body): Use tree_rest_of_compilation. + (java_expand_stmt): New function. + + * java-gimplify.c (tree-dump.h): Include. + (java_genericize): New function. + (dump_java_tree): Declare. New function. + + * java-tree.h (start_complete_expand_method): Remove declaration. + (complete_start_java_method): Remove declaration. + (finish_method, java_expand_stmt, java_genericize): Declare. + + * lang.c (LANG_HOOKS_RTL_EXPAND_STMT): Define. + + * parse.y (tree-inline.h, tree-dump.h, tree-flow.h, + cgraph.h): Remove includes. + (start_complete_expand_method): Declare. + (source_end_java_method): Don't expand tree. Use finish_method. + Reset current_function_decl. + (java_expand_method_bodies): Don't patch tree for class + initialization or method synchronization. + +2003-10-01 Richard Henderson + + * decl.c (end_java_method): Invoke remove_useless_stmts_and_vars + and lower_eh_constructs. + * parse.y (source_end_java_method): Likewise. + +2003-09-24 Jason Merrill + + * decl.c, jcf-parse.c, jcf-write.c, parse.h, parse.y, resource.c: + Revert from TREE_LOCUS to DECL_SOURCE_LOCATION. + +2003-09-18 Richard Henderson + + * lang.c (java_estimate_num_insns): Take an expr, not a decl. + +2003-08-12 Diego Novillo + + * java-gimplify.c (java_gimplify_block): If the body is a + NULL_TREE, return an empty statement. + +2003-08-08 Jason Merrill + + * parse.y (source_end_java_method): Support + !keep_function_tree_in_gimple_form. + Do TDI_generic dump. + +2003-07-31 Andrew Haley + + * java-tree.h: (add_stmt_to_compound): New function. + (java_add_stmt): New function. + (java_add_local_var): New function. + (get_stmts): New function. + * java-gimplify.c (java_gimplify_block): Allow for null body. + * except.c (link_handler): Set h->stmt. + (expand_start_java_handler): Build a TRY_CATCH_EXPR for this + range; don't expand_eh_region_start. + (expand_end_java_handler): Rewrite. + * java-except.h (stmt): New field. + * expr.c (flush_quick_stack): Replace expand_assignment with + java_add_stmt. + (java_stack_dup): Replace emit_move_insn with java_add_stmt. + (build_java_athrow): Replace expand_expr_stmt with java_add_stmt. + (build_java_jsr): Replace emit_jump with java_add_stmt (build (GOTO_EXPR)) + (build_java_ret): Replace expand_computed_goto with + java_add_stmt (build (GOTO_EXPR)) + (expand_java_arraystore): Replace expand_assignment with + java_add_stmt. + (expand_java_return): Replace expand_return with + java_add_stmt (build (RETURN_EXPR)) + (expand_load_internal): Remove layout_decl, DECL_REGISTER, + expand_decl, and expand_decl_init. Instead, add the local + variable and a MODIFY_EXPR to the current tree. + (expand_iinc): Replace expand_assignment with + java_add_stmt. + (expand_compare): Replace expand_cond with + java_add_stmt(build (COND_EXPR)) + (expand_java_goto): Replace expand_goto with + java_add_stmt (build (GOTO_EXPR)) + (expand_invoke): Replace expand_expr_stmt with java_add_stmt. + (build_jni_stub): Generate a BIND_EXPR to hold the block we've + created. Don't distinguish between source and byte compiler. + (expand_java_field_op): Replace expand_assignment with + java_add_stmt. + (java_expand_expr): Abort. No-one should call this function any + more. + (expand_byte_code): Replace expand_label with + java_add_stmt (build (LABEL_EXPR)) + (process_jvm_instruction): Replace build (JAVA_EXC_OBJ_EXPR) with + build_exception_object_ref. Replace expand_assignment with + java_add_stmt. + * except.c (link_handler): Null stmt field. + (expand_start_java_handler): Don't expand_eh_region_start. + Instead, generate a TRY_CATCH_EXPR and insert it into the tree + we're building. + (expand_end_java_handler): Don't expand_start_all_catch. Instead, + build a TRY_FINALLY_EXPR and wrap the catch block with it. + Don't expand_end_all_catch. + * decl.c (push_jvm_slot): Call pushdecl(). + (find_local_variable): Give symbolic names to unnamed local + variables. + (struct binding_level: stmts): New field. + (poplevel): If any statements have been generated at this level, + create a BIND_EXPR to hold them and copy the variables to it. If + we are at the outermost level, save this BIND_EXPR in the + DECL_SAVED_TREE of this function. + (maybe_pushlevels): Don't expand_start_bindings. + (maybe_poplevels): Don't expand_end_bindings. + (complete_start_java_method): Reorganize static initialization and + synchronization logic for source compiler. Remove pushlevel and + expand_start_bindings for byte compiler. + (end_java_method): Don't expand_end_bindings. Add static + initialization and synchronization logic for byte compiler. + Set cfun->x_whole_function_mode_p. + Call gimplify_function_tree and optimize_function_tree and + expand_expr_stmt. + (add_stmt_to_compound): New. + (java_add_stmt): New. + (java_add_local_var): New. + (get_stmts): New. + * parse.y (add_stmt_to_compound): Remove. + * jcf-parse.c (parse_class_file): Don't call expand_expr_stmt for + a native method -- we'll do that later. + +2003-07-27 Andreas Jaeger + + * expr.c (build_expr_wfl): Convert remaining K&R prototypes + to ISO C90. + +2003-06-28 Jeff Sturm + + * java-gimplify.c (java_gimplify_block): Rebuild BLOCK_SUBBLOCKS. + * lang.c (flag_disable_gimple): Remove initialization. + +2003-06-23 Jeff Law + + * Make-lang.in (java-gimplify.o): Add dependencies. + +2003-06-22 Jeff Sturm + + * parse.y (source_end_java_method): Don't attempt to inline + or optimize trees if flag_disable_gimple. + + * Make-lang.in (JAVA_OBJS): Remove java-tree-inline.o. + +2003-06-21 Jeff Sturm + + * Make-lang.in (JAVA_OBJS): Add java-gimplify.o. + + * decl.c (java_init_decl_processing): Initialize size_type_node. + (complete_start_java_method): Update DECL_SAVED_TREE. + (dump_function): Remove. + (java_optimize_inline): Remove. + + * expr.c (always_initialize_class_p): Initialize to 1. + (build_instanceof): Build proper boolean condition. + (build_class_init): Set DECL_INITIAL for init_test_decl. + (force_evaluation_order): Don't save_expr a void expr node. + + * java-gimplify.c: New file. + + * java-tree.h (java_gimplify_expr): Declare. + + * lang.c (java_tree_inlining_walk_subtrees): Remove declaration. + (flag_optimize_sci): Initialize to 0. + (LANG_HOOKS_TREE_INLINING_WALK_SUBTREES): Remove define. + (LANG_HOOKS_SIMPLIFY_EXPR): Add define. + (java_tree_inlining_walk_subtrees): Remove function. + (java_init): Set flag_disable_gimple to 1. + + * parse.y (source_end_java_method): Set cfun->x_whole_function_mode_p. + Gimplify. Optimize tree before expanding. Update comments. + (java_expand_method_bodies): Always save DECL_SAVED_TREE. + (patch_invoke): Don't save_expr force_evaluation_order result. + (patch_assignment): Use simpler compound expression. + (patch_if_else_statement): Don't optimize constant condition nodes. + +2003-03-02 Diego Novillo + + * class.c: Replace DECL_SOURCE_FILE with TREE_FILENAME and + DECL_SOURCE_LINE with TREE_LINENO everywhere. + +2003-02-03 Diego Novillo + + * parse.y (qualify_ambiguous_name): Initialize variable 'decl'. + +2003-01-15 Jeff Law + + * class.c: Use TREE_FILENAME and TREE_LINENO to extract file/line + information from tree nodes. Use annotate_with_file_line to + annotate tree nodes with file/line information. + * decl.c, jcf-parse.c, jcf-write.c, parse.h: Likewise. + * parse.y: Likewise. + * expr.c (java_expand_expr): Handle EXPR_WITH_FILE_LOCATION nodes. + (build_expr_wfl): New function. + * java-tree.def (EXPR_WITH_FILE_LOCATION): New node. + * java-tree.h (EXPR_WFL_*): New macros. + (build_expr_wfl): Declare. + +Local Variables: +mode: change-log +change-log-default-name: "ChangeLog.tree-ssa" +End: diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in index fad423ae255..db3ac9d5531 100644 --- a/gcc/java/Make-lang.in +++ b/gcc/java/Make-lang.in @@ -105,7 +105,7 @@ JAVA_OBJS = java/parse.o java/class.o java/decl.o java/expr.o \ java/zextract.o java/jcf-io.o java/win32-host.o java/jcf-parse.o java/mangle.o \ java/mangle_name.o java/builtins.o java/resource.o \ java/jcf-write.o java/buffer.o java/check-init.o java/jcf-depend.o \ - java/jcf-path.o java/xref.o java/boehm.o java/java-tree-inline.o mkdeps.o + java/jcf-path.o java/xref.o java/boehm.o java/java-gimplify.o mkdeps.o GCJH_OBJS = java/gjavah.o java/jcf-io.o java/jcf-depend.o java/jcf-path.o \ java/win32-host.o java/zextract.o version.o mkdeps.o errors.o ggc-none.o \ @@ -333,6 +333,9 @@ java/xref.o: java/xref.c java/xref.h $(CONFIG_H) $(JAVA_TREE_H) toplev.h \ $(SYSTEM_H) coretypes.h $(TM_H) java/zextract.o: java/zextract.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ java/zipfile.h +java/java-gimplify.o: java/java-gimplify.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(JAVA_TREE_H) tree-simple.h toplev.h + java/parse-scan.o: java/parse-scan.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) toplev.h $(JAVA_LEX_C) java/parse.h java/lex.h input.h java/parse.o: java/parse.c java/jcf-reader.c $(CONFIG_H) $(SYSTEM_H) \ diff --git a/gcc/java/builtins.c b/gcc/java/builtins.c index 1d3095f239d..77f0c582105 100644 --- a/gcc/java/builtins.c +++ b/gcc/java/builtins.c @@ -124,7 +124,7 @@ java_build_function_call_expr (tree fn, tree arglist) call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn); call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)), - call_expr, arglist); + call_expr, arglist, NULL_TREE); TREE_SIDE_EFFECTS (call_expr) = 1; return fold (call_expr); } diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c index c4e39484410..f325c4e80ab 100644 --- a/gcc/java/check-init.c +++ b/gcc/java/check-init.c @@ -770,7 +770,7 @@ check_init (tree exp, words before) break; case NOP_EXPR: - if (exp == empty_stmt_node) + if (IS_EMPTY_STMT (exp)) break; /* ... else fall through ... */ case UNARY_PLUS_EXPR: @@ -889,7 +889,7 @@ check_init (tree exp, words before) location_t saved_location = input_location; tree saved_wfl = wfl; tree body = EXPR_WFL_NODE (exp); - if (body == empty_stmt_node) + if (IS_EMPTY_STMT (body)) break; wfl = exp; input_filename = EXPR_WFL_FILENAME (exp); diff --git a/gcc/java/class.c b/gcc/java/class.c index 530b56f6cd8..137b647d191 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -890,6 +890,7 @@ build_utf8_ref (tree name) PUSH_FIELD_VALUE (cinit, "data", string); FINISH_RECORD_CONSTRUCTOR (cinit); TREE_CONSTANT (cinit) = 1; + TREE_INVARIANT (cinit) = 1; /* Generate a unique-enough identifier. */ sprintf(buf, "_Utf%d", ++utf8_count); @@ -940,8 +941,7 @@ build_indirect_class_ref (tree type) tree cl; index = alloc_class_constant (type); cl = build_ref_from_constant_pool (index); - TREE_TYPE (cl) = promote_type (class_ptr_type); - return cl; + return convert (promote_type (class_ptr_type), cl); } /* Build a reference to the class TYPE. @@ -1391,6 +1391,7 @@ get_dispatch_table (tree type, tree this_class_addr) tree fdesc = build (FDESC_EXPR, nativecode_ptr_type_node, method, build_int_2 (j, 0)); TREE_CONSTANT (fdesc) = 1; + TREE_INVARIANT (fdesc) = 1; list = tree_cons (NULL_TREE, fdesc, list); } else @@ -1731,7 +1732,8 @@ make_class_data (tree type) build1 (ADDR_EXPR, symbols_array_ptr_type, TYPE_OTABLE_SYMS_DECL (type))); TREE_CONSTANT (TYPE_OTABLE_DECL (type)) = 1; - } + TREE_INVARIANT (TYPE_OTABLE_DECL (type)) = 1; + } if (TYPE_ATABLE_METHODS(type) == NULL_TREE) { PUSH_FIELD_VALUE (cons, "atable", null_pointer_node); @@ -1745,6 +1747,7 @@ make_class_data (tree type) build1 (ADDR_EXPR, symbols_array_ptr_type, TYPE_ATABLE_SYMS_DECL (type))); TREE_CONSTANT (TYPE_ATABLE_DECL (type)) = 1; + TREE_INVARIANT (TYPE_ATABLE_DECL (type)) = 1; } PUSH_FIELD_VALUE (cons, "catch_classes", @@ -1778,37 +1781,6 @@ make_class_data (tree type) void finish_class (void) { - tree method; - tree type_methods = TYPE_METHODS (current_class); - int saw_native_method = 0; - - /* Find out if we have any native methods. We use this information - later. */ - for (method = type_methods; - method != NULL_TREE; - method = TREE_CHAIN (method)) - { - if (METHOD_NATIVE (method)) - { - saw_native_method = 1; - break; - } - } - - /* Emit deferred inline methods. */ - for (method = type_methods; method != NULL_TREE; ) - { - if (! TREE_ASM_WRITTEN (method) && DECL_STRUCT_FUNCTION (method) != 0) - { - output_inline_function (method); - /* Scan the list again to see if there are any earlier - methods to emit. */ - method = type_methods; - continue; - } - method = TREE_CHAIN (method); - } - java_expand_catch_classes (current_class); current_function_decl = NULL_TREE; @@ -2376,6 +2348,7 @@ build_symbol_entry (tree decl) PUSH_FIELD_VALUE (sym, "signature", signature); FINISH_RECORD_CONSTRUCTOR (sym); TREE_CONSTANT (sym) = 1; + TREE_INVARIANT (sym) = 1; return sym; } @@ -2414,6 +2387,7 @@ emit_symbol_table (tree name, tree the_table, tree decl_list, tree the_syms_decl PUSH_FIELD_VALUE (null_symbol, "signature", null_pointer_node); FINISH_RECORD_CONSTRUCTOR (null_symbol); TREE_CONSTANT (null_symbol) = 1; + TREE_INVARIANT (null_symbol) = 1; list = tree_cons (NULL_TREE, null_symbol, list); /* Put the list in the right order and make it a constructor. */ diff --git a/gcc/java/constants.c b/gcc/java/constants.c index d97e8c07e80..32fc854c9db 100644 --- a/gcc/java/constants.c +++ b/gcc/java/constants.c @@ -386,29 +386,35 @@ alloc_class_constant (tree clas) IDENTIFIER_LENGTH(class_name)))); } -/* Return a reference to the data array of the current constant pool. */ +/* Return the decl of the data array of the current constant pool. */ static tree build_constant_data_ref (void) { - tree cpool_data_ref = NULL_TREE; + tree decl = TYPE_CPOOL_DATA_REF (output_class); - if (TYPE_CPOOL_DATA_REF (output_class)) - cpool_data_ref = TYPE_CPOOL_DATA_REF (output_class); - - if (cpool_data_ref == NULL_TREE) + if (decl == NULL_TREE) { - tree decl; + tree type; tree decl_name = mangled_classname ("_CD_", output_class); - decl = build_decl (VAR_DECL, decl_name, - build_array_type (ptr_type_node, - one_elt_array_domain_type)); + + /* Build a type with unspecified bounds. The will make sure + that targets do the right thing with whatever size we end + up with at the end. Using bounds that are too small risks + assuming the data is in the small data section. */ + type = build_array_type (ptr_type_node, NULL_TREE); + + /* We need to lay out the type ourselves, since build_array_type + thinks the type is incomplete. */ + layout_type (type); + + decl = build_decl (VAR_DECL, decl_name, type); TREE_STATIC (decl) = 1; make_decl_rtl (decl, NULL); - TYPE_CPOOL_DATA_REF (output_class) = cpool_data_ref - = build1 (ADDR_EXPR, ptr_type_node, decl); + TYPE_CPOOL_DATA_REF (output_class) = decl; } - return cpool_data_ref; + + return decl; } /* Get the pointer value at the INDEX'th element of the constant pool. */ @@ -416,11 +422,9 @@ build_constant_data_ref (void) tree build_ref_from_constant_pool (int index) { - tree t = build_constant_data_ref (); - index *= int_size_in_bytes (ptr_type_node); - t = fold (build (PLUS_EXPR, ptr_type_node, - t, build_int_2 (index, 0))); - return build1 (INDIRECT_REF, ptr_type_node, t); + tree d = build_constant_data_ref (); + tree i = build_int_2 (index, 0); + return build (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i); } /* Build an initializer for the constants field of the current constant pool. @@ -456,7 +460,7 @@ build_constants_constructor (void) tags_list = tree_cons (NULL_TREE, get_tag_node (0), tags_list); data_list = tree_cons (NULL_TREE, null_pointer_node, data_list); - data_decl = TREE_OPERAND (build_constant_data_ref (), 0); + data_decl = build_constant_data_ref (); TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type), DECL_INITIAL (data_decl) = build_constructor (TREE_TYPE (data_decl), data_list); diff --git a/gcc/java/decl.c b/gcc/java/decl.c index 047c0af0ee9..7a36e54ffb9 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -44,6 +44,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "java-except.h" #include "ggc.h" #include "timevar.h" +#include "cgraph.h" #include "tree-inline.h" #include "target.h" @@ -91,42 +92,58 @@ int current_pc; void indent (void) { - unsigned i; + int i; for (i = 0; i < binding_depth*2; i++) putc (' ', stderr); } #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ +/* Copy the value in decl into every alias in the same local variable + slot. */ +void +update_aliases (tree decl, int index) +{ + tree tmp = TREE_VEC_ELT (decl_map, index); + tree type = TREE_TYPE (decl); + while (tmp != NULL_TREE) + { + if (tmp != decl + && ! LOCAL_VAR_OUT_OF_SCOPE_P (tmp) + && TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp))) + { + tree src = build1 (NOP_EXPR, TREE_TYPE (tmp), decl); + java_add_stmt + (build (MODIFY_EXPR, TREE_TYPE (tmp), tmp, src)); + } + tmp = DECL_LOCAL_SLOT_CHAIN (tmp); + } +} + static tree push_jvm_slot (int index, tree decl) { - struct rtx_def *rtl = NULL; tree type = TREE_TYPE (decl); tree tmp; DECL_CONTEXT (decl) = current_function_decl; layout_decl (decl, 0); - /* See if we have an appropriate rtl (i.e. same mode) at this index. - If so, we must use it. */ + /* Look for another variable of the same mode in this slot. */ tmp = TREE_VEC_ELT (decl_map, index); while (tmp != NULL_TREE) { - if (TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp)) - && ! LOCAL_VAR_OUT_OF_SCOPE_P (tmp)) - rtl = DECL_RTL_IF_SET (tmp); - if (rtl != NULL) - break; - tmp = DECL_LOCAL_SLOT_CHAIN (tmp); - } - if (rtl != NULL) - SET_DECL_RTL (decl, rtl); - else - { - if (index >= DECL_MAX_LOCALS (current_function_decl)) - DECL_REGISTER (decl) = 1; - expand_decl (decl); + if (! LOCAL_VAR_OUT_OF_SCOPE_P (tmp) + && TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp))) + { + /* At the point of its creation this decl inherits whatever + is in the slot. */ + tree src = build1 (NOP_EXPR, TREE_TYPE (decl), tmp); + java_add_stmt + (build (MODIFY_EXPR, TREE_TYPE (decl), decl, src)); + break; + } + tmp = DECL_LOCAL_SLOT_CHAIN (tmp); } /* Now link the decl into the decl_map. */ @@ -139,6 +156,9 @@ push_jvm_slot (int index, tree decl) } DECL_LOCAL_SLOT_CHAIN (decl) = TREE_VEC_ELT (decl_map, index); TREE_VEC_ELT (decl_map, index) = decl; + + if (TREE_CODE (decl) != PARM_DECL) + pushdecl (decl); return decl; } @@ -201,11 +221,16 @@ find_local_variable (int index, tree type, int pc) /* Scan through every declaration that has been created in this slot. */ while (decl != NULL_TREE) { + bool has_name = false; + tree name = DECL_NAME (decl); + if (name && IDENTIFIER_POINTER (name)) + has_name = IDENTIFIER_POINTER (name)[0] != '#'; + /* Variables created in give_name_to_locals() have a name and have a specified scope, so we can handle them specifically. We want to use the specific decls created for those so they are assigned the right variables in the debugging information. */ - if (DECL_NAME (decl) != NULL_TREE) + if (has_name) { /* This is a variable we have a name for, so it has a scope supplied in the class file. But it only matters when we @@ -230,8 +255,20 @@ find_local_variable (int index, tree type, int pc) if (best != NULL_TREE) return best; - /* If we don't find a match, create one with the type passed in. */ - return push_jvm_slot (index, build_decl (VAR_DECL, NULL_TREE, type)); + /* If we don't find a match, create one with the type passed in. + Ths name of the variable is #n#m, which n is the variable index + in the local variable area and m is a dummy identifier for + uniqueness -- multiple variables may share the same local + variable index. */ + { + char buf[64]; + tree name; + static int uniq; + sprintf (buf, "#%d#%d", index, uniq++); + name = get_identifier (buf); + + return push_jvm_slot (index, build_decl (VAR_DECL, name, type)); + } } @@ -274,6 +311,9 @@ struct binding_level /* The bytecode PC that marks the start of this level. */ int start_pc; + /* The statements in this binding level. */ + tree stmts; + #if defined(DEBUG_JAVA_BINDING_LEVELS) /* Binding depth at which this level began. */ unsigned binding_depth; @@ -304,7 +344,11 @@ static struct binding_level *global_binding_level; static const struct binding_level clear_binding_level = {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, - NULL_BINDING_LEVEL, LARGEST_PC, 0}; + NULL_BINDING_LEVEL, LARGEST_PC, 0, NULL, +#if defined(DEBUG_JAVA_BINDING_LEVELS) + 0, +#endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ +}; #if 0 /* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function @@ -439,7 +483,10 @@ java_init_decl_processing (void) pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned long"), unsigned_long_type_node)); - set_sizetype (make_unsigned_type (POINTER_SIZE)); + /* This is not a java type, however tree-dfa requires a definition for + size_type_node. */ + size_type_node = make_unsigned_type (POINTER_SIZE); + set_sizetype (size_type_node); /* Define these next since types below may used them. */ integer_type_node = java_type_for_size (INT_TYPE_SIZE, 0); @@ -483,10 +530,6 @@ java_init_decl_processing (void) null_pointer_node = build_int_2 (0, 0); TREE_TYPE (null_pointer_node) = ptr_type_node; - /* Used by the parser to represent empty statements and blocks. */ - empty_stmt_node = build1 (NOP_EXPR, void_type_node, size_zero_node); - CAN_COMPLETE_NORMALLY (empty_stmt_node) = 1; - #if 0 /* Make a type to be the domain of a few array types whose domains don't really matter. @@ -1194,7 +1237,7 @@ pushlevel (int unused ATTRIBUTE_UNUSED) #if defined(DEBUG_JAVA_BINDING_LEVELS) newlevel->binding_depth = binding_depth; indent (); - fprintf (stderr, "push %s level 0x%08x pc %d\n", + fprintf (stderr, "push %s level %p pc %d\n", (is_class_level) ? "class" : "block", newlevel, current_pc); is_class_level = 0; binding_depth++; @@ -1226,18 +1269,18 @@ poplevel (int keep, int reverse, int functionbody) tree subblocks = current_binding_level->blocks; tree block = 0; tree decl; + tree bind = 0; int block_previously_created; - { #if defined(DEBUG_JAVA_BINDING_LEVELS) binding_depth--; indent (); if (current_binding_level->end_pc != LARGEST_PC) - fprintf (stderr, "pop %s level 0x%08x pc %d (end pc %d)\n", + fprintf (stderr, "pop %s level %p pc %d (end pc %d)\n", (is_class_level) ? "class" : "block", current_binding_level, current_pc, current_binding_level->end_pc); else - fprintf (stderr, "pop %s level 0x%08x pc %d\n", + fprintf (stderr, "pop %s level %p pc %d\n", (is_class_level) ? "class" : "block", current_binding_level, current_pc); #if 0 if (is_class_level != (current_binding_level == class_binding_level)) @@ -1259,37 +1302,11 @@ poplevel (int keep, int reverse, int functionbody) else decls = current_binding_level->names; - /* Output any nested inline functions within this block - if they weren't already output. */ - for (decl = decls; decl; decl = TREE_CHAIN (decl)) - if (TREE_CODE (decl) == FUNCTION_DECL - && ! TREE_ASM_WRITTEN (decl) - && DECL_INITIAL (decl) != 0 - && TREE_ADDRESSABLE (decl)) - { - /* If this decl was copied from a file-scope decl on account - of a block-scope extern decl, propagate TREE_ADDRESSABLE - to the file-scope decl. - - DECL_ABSTRACT_ORIGIN can be set to itself if - warn_return_type is true, since then the decl goes - through save_for_inline_copying. */ - if (DECL_ABSTRACT_ORIGIN (decl) != 0 - && DECL_ABSTRACT_ORIGIN (decl) != decl) - TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; - else - { - push_function_context (); - output_inline_function (decl); - pop_function_context (); - } - } - else if (TREE_CODE (decl) == VAR_DECL - && DECL_LANG_SPECIFIC (decl) != NULL - && DECL_LOCAL_SLOT_NUMBER (decl)) - LOCAL_VAR_OUT_OF_SCOPE_P (decl) = 1; - } + if (TREE_CODE (decl) == VAR_DECL + && DECL_LANG_SPECIFIC (decl) != NULL + && DECL_LOCAL_SLOT_NUMBER (decl)) + LOCAL_VAR_OUT_OF_SCOPE_P (decl) = 1; /* If there were any declarations in that level, or if this level is a function body, @@ -1300,12 +1317,55 @@ poplevel (int keep, int reverse, int functionbody) if (block_previously_created) block = current_binding_level->this_block; else if (keep || functionbody) - block = make_node (BLOCK); + { + block = make_node (BLOCK); + TREE_TYPE (block) = void_type_node; + } + if (block != 0) { - BLOCK_VARS (block) = decls; + /* If any statements have been generated at this level, create a + BIND_EXPR to hold them and copy the variables to it. This + only applies to the bytecode compiler. */ + if (current_binding_level->stmts) + { + tree decl = decls; + tree *var = &BLOCK_VARS (block); + + /* Copy decls from names list, ignoring labels. */ + while (decl) + { + tree next = TREE_CHAIN (decl); + if (TREE_CODE (decl) != LABEL_DECL) + { + *var = decl; + var = &TREE_CHAIN (decl); + } + decl = next; + } + *var = NULL; + + bind = build (BIND_EXPR, TREE_TYPE (block), BLOCK_VARS (block), + BLOCK_EXPR_BODY (block), block); + + BIND_EXPR_BODY (bind) = current_binding_level->stmts; + + if (BIND_EXPR_BODY (bind) + && TREE_SIDE_EFFECTS (BIND_EXPR_BODY (bind))) + TREE_SIDE_EFFECTS (bind) = 1; + + /* FIXME: gimplifier brain damage. */ + if (BIND_EXPR_BODY (bind) == NULL) + BIND_EXPR_BODY (bind) = build_java_empty_stmt (); + + current_binding_level->stmts = NULL; + } + else + { + BLOCK_VARS (block) = decls; + } BLOCK_SUBBLOCKS (block) = subblocks; - } + } /* In each subblock, record that this is its superior. */ @@ -1390,7 +1450,10 @@ poplevel (int keep, int reverse, int functionbody) /* Dispose of the block that we just made inside some higher level. */ if (functionbody) - DECL_INITIAL (current_function_decl) = block; + { + DECL_INITIAL (current_function_decl) = block; + DECL_SAVED_TREE (current_function_decl) = bind; + } else if (block) { if (!block_previously_created) @@ -1406,21 +1469,9 @@ poplevel (int keep, int reverse, int functionbody) current_binding_level->blocks = chainon (current_binding_level->blocks, subblocks); - /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this - binding contour so that they point to the appropriate construct, i.e. - either to the current FUNCTION_DECL node, or else to the BLOCK node - we just constructed. - - Note that for tagged types whose scope is just the formal parameter - list for some function type specification, we can't properly set - their TYPE_CONTEXTs here, because we don't have a pointer to the - appropriate FUNCTION_TYPE node readily available to us. For those - cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set - in `grokdeclarator' as soon as we have created the FUNCTION_TYPE - node which will represent the "scope" for these "parameter list local" - tagged types. - */ - + if (bind) + java_add_stmt (bind); + if (block) TREE_USED (block) = 1; return block; @@ -1437,7 +1488,7 @@ maybe_pushlevels (int pc) DECL_LOCAL_START_PC (pending_local_decls) <= pc) { tree *ptr = &pending_local_decls; - tree decl = *ptr; + tree decl = *ptr, next; int end_pc = DECL_LOCAL_END_PC (decl); while (*ptr != NULL_TREE @@ -1454,13 +1505,13 @@ maybe_pushlevels (int pc) maybe_start_try (pc, end_pc); pushlevel (1); - expand_start_bindings (0); current_binding_level->end_pc = end_pc; current_binding_level->start_pc = pc; - current_binding_level->names = decl; - for ( ; decl != NULL_TREE; decl = TREE_CHAIN (decl)) + current_binding_level->names = NULL; + for ( ; decl != NULL_TREE; decl = next) { + next = TREE_CHAIN (decl); push_jvm_slot (DECL_LOCAL_SLOT_NUMBER (decl), decl); } } @@ -1477,7 +1528,6 @@ maybe_poplevels (int pc) while (current_binding_level->end_pc <= pc) { - expand_end_bindings (getdecls (), 1, 0); maybe_end_try (current_binding_level->start_pc, pc); poplevel (1, 0, 0); } @@ -1583,7 +1633,7 @@ give_name_to_locals (JCF *jcf) if (end_pc > DECL_CODE_LENGTH (current_function_decl)) { warning ("%Jbad PC range for debug info for local '%D'", - decl, decl); + decl, decl); end_pc = DECL_CODE_LENGTH (current_function_decl); } @@ -1661,78 +1711,6 @@ build_result_decl (tree fndecl) return result; } -void -complete_start_java_method (tree fndecl) -{ - if (! flag_emit_class_files) - { - /* Initialize the RTL code for the function. */ - init_function_start (fndecl); - - /* Set up parameters and prepare for return, for the function. */ - expand_function_start (fndecl, 0); - } - -#if 0 - /* If this fcn was already referenced via a block-scope `extern' decl (or - an implicit decl), propagate certain information about the usage. */ - if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl))) - TREE_ADDRESSABLE (current_function_decl) = 1; - -#endif - - if (METHOD_STATIC (fndecl) && ! METHOD_PRIVATE (fndecl) - && ! flag_emit_class_files - && ! DECL_CLINIT_P (fndecl) - && ! CLASS_INTERFACE (TYPE_NAME (current_class))) - { - tree clas = DECL_CONTEXT (fndecl); - tree init = build (CALL_EXPR, void_type_node, - build_address_of (soft_initclass_node), - build_tree_list (NULL_TREE, build_class_ref (clas)), - NULL_TREE); - TREE_SIDE_EFFECTS (init) = 1; - expand_expr_stmt (init); - } - - /* Push local variables. Function compiled from source code are - using a different local variables management, and for them, - pushlevel shouldn't be called from here. */ - if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl))) - { - pushlevel (2); - if (! flag_emit_class_files) - expand_start_bindings (1); - } - - if (METHOD_SYNCHRONIZED (fndecl) && ! flag_emit_class_files) - { - /* Wrap function body with a monitorenter plus monitorexit cleanup. */ - tree enter, exit, lock; - if (METHOD_STATIC (fndecl)) - lock = build_class_ref (DECL_CONTEXT (fndecl)); - else - lock = DECL_ARGUMENTS (fndecl); - BUILD_MONITOR_ENTER (enter, lock); - BUILD_MONITOR_EXIT (exit, lock); - if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl))) - { - expand_expr_stmt (enter); - expand_decl_cleanup (NULL_TREE, exit); - } - else - { - tree function_body = DECL_FUNCTION_BODY (fndecl); - tree body = BLOCK_EXPR_BODY (function_body); - lock = build (COMPOUND_EXPR, void_type_node, - enter, - build (TRY_FINALLY_EXPR, void_type_node, body, exit)); - TREE_SIDE_EFFECTS (lock) = 1; - BLOCK_EXPR_BODY (function_body) = lock; - } - } -} - void start_java_method (tree fndecl) { @@ -1789,7 +1767,9 @@ start_java_method (tree fndecl) type_map[i++] = NULL_TREE; build_result_decl (fndecl); - complete_start_java_method (fndecl); + + /* Push local variables. */ + pushlevel (2); } void @@ -1797,7 +1777,6 @@ end_java_method (void) { tree fndecl = current_function_decl; - expand_end_bindings (getdecls (), 1, 0); /* pop out of function */ poplevel (1, 1, 0); @@ -1806,64 +1785,71 @@ end_java_method (void) BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; - /* Generate rtl for function exit. */ - expand_function_end (); - - /* Run the optimizers and output assembler code for this function. */ - rest_of_compilation (fndecl); + flag_unit_at_a_time = 0; + finish_method (fndecl); current_function_decl = NULL_TREE; } -/* Expand a function's body. */ +/* Prepare a method for expansion. */ void -java_expand_body (tree fndecl) +finish_method (tree fndecl) { - location_t saved_location = input_location; - - current_function_decl = fndecl; - input_location = DECL_SOURCE_LOCATION (fndecl); - output_class = current_class = DECL_CONTEXT (fndecl); + tree *tp = &DECL_SAVED_TREE (fndecl); - timevar_push (TV_EXPAND); - - /* Prepare the function for tree completion. */ - start_complete_expand_method (fndecl); - - if (! flag_emit_class_files && ! flag_emit_xref) + /* Wrap body of synchronized methods in a monitorenter, + plus monitorexit cleanup. */ + if (METHOD_SYNCHRONIZED (fndecl)) { - /* Initialize the RTL code for the function. */ - init_function_start (fndecl); - - /* Set up parameters and prepare for return, for the function. */ - expand_function_start (fndecl, 0); - - /* Generate the RTL for this function. */ - expand_expr_stmt_value (DECL_SAVED_TREE (fndecl), 0, 1); + tree enter, exit, lock; + if (METHOD_STATIC (fndecl)) + lock = build_class_ref (DECL_CONTEXT (fndecl)); + else + lock = DECL_ARGUMENTS (fndecl); + BUILD_MONITOR_ENTER (enter, lock); + BUILD_MONITOR_EXIT (exit, lock); + *tp = build (COMPOUND_EXPR, void_type_node, + enter, + build (TRY_FINALLY_EXPR, void_type_node, *tp, exit)); } - /* Pop out of its parameters. */ - pushdecl_force_head (DECL_ARGUMENTS (fndecl)); - poplevel (1, 0, 1); - BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; - - if (! flag_emit_class_files && ! flag_emit_xref) + /* Prepend class initialization for static methods reachable from + other classes. */ + if (METHOD_STATIC (fndecl) && ! METHOD_PRIVATE (fndecl) + && ! DECL_CLINIT_P (fndecl) + && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (fndecl)))) { - /* Generate RTL for function exit. */ - input_line = DECL_FUNCTION_LAST_LINE (fndecl); - expand_function_end (); - - /* Run the optimizers and output the assembler code - for this function. */ - rest_of_compilation (fndecl); + tree clas = DECL_CONTEXT (fndecl); + tree init = build (CALL_EXPR, void_type_node, + build_address_of (soft_initclass_node), + build_tree_list (NULL_TREE, build_class_ref (clas)), + NULL_TREE); + *tp = build (COMPOUND_EXPR, TREE_TYPE (*tp), init, *tp); } - timevar_pop (TV_EXPAND); + /* Convert function tree to GENERIC prior to inlining. */ + java_genericize (fndecl); - input_location = saved_location; + /* Store the end of the function, so that we get good line number + info for the epilogue. */ + if (DECL_STRUCT_FUNCTION (fndecl)) + cfun = DECL_STRUCT_FUNCTION (fndecl); + else + allocate_struct_function (fndecl); + cfun->function_end_locus.file = DECL_SOURCE_FILE (fndecl); + cfun->function_end_locus.line = DECL_FUNCTION_LAST_LINE (fndecl); - current_function_decl = NULL_TREE; + /* Defer inlining and expansion to the cgraph optimizers. */ + cgraph_finalize_function (fndecl, false); +} + +/* Optimize and expand a function's entire body. */ + +void +java_expand_body (tree fndecl) +{ + tree_rest_of_compilation (fndecl, 0); } /* We pessimistically marked all methods and fields external until we @@ -1895,4 +1881,62 @@ java_mark_class_local (tree class) java_mark_decl_local (t); } +/* Add a statement to a compound_expr. */ + +tree +add_stmt_to_compound (existing, type, stmt) + tree existing, type, stmt; +{ + if (!stmt) + return existing; + else if (existing) + { + tree expr = build (COMPOUND_EXPR, type, existing, stmt); + TREE_SIDE_EFFECTS (expr) + = TREE_SIDE_EFFECTS (existing) | TREE_SIDE_EFFECTS (stmt); + return expr; + } + else + return stmt; +} + +/* Add a statement to the compound_expr currently being + constructed. */ + +tree +java_add_stmt (stmt) + tree stmt; +{ + if (input_filename) + annotate_with_locus (stmt, input_location); + + return current_binding_level->stmts + = add_stmt_to_compound (current_binding_level->stmts, + TREE_TYPE (stmt), stmt); +} + +/* Add a variable to the current scope. */ + +tree +java_add_local_var (tree decl) +{ + tree *vars = ¤t_binding_level->names; + tree next = *vars; + TREE_CHAIN (decl) = next; + *vars = decl; + DECL_CONTEXT (decl) = current_function_decl; + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl); + return decl; +} + +/* Return a pointer to the compound_expr currently being + constructed. */ + +tree * +get_stmts (void) +{ + return ¤t_binding_level->stmts; +} + + #include "gt-java-decl.h" diff --git a/gcc/java/except.c b/gcc/java/except.c index c5c7dcf27f4..b77842e8a66 100644 --- a/gcc/java/except.c +++ b/gcc/java/except.c @@ -170,6 +170,7 @@ link_handler (struct eh_range *range, struct eh_range *outer) TREE_VALUE (range->handlers)); h->next_sibling = NULL; h->expanded = 0; + h->stmt = NULL; /* Restart both from the top to avoid having to make this function smart about reentrancy. */ link_handler (h, &whole_range); @@ -287,6 +288,7 @@ add_handler (int start_pc, int end_pc, tree handler, tree type) h->handlers = build_tree_list (type, handler); h->next_sibling = NULL; h->expanded = 0; + h->stmt = NULL; if (prev == NULL) whole_range.first_child = h; @@ -294,7 +296,6 @@ add_handler (int start_pc, int end_pc, tree handler, tree type) prev->next_sibling = h; } - /* if there are any handlers for this range, issue start of region */ static void expand_start_java_handler (struct eh_range *range) @@ -304,8 +305,14 @@ expand_start_java_handler (struct eh_range *range) fprintf (stderr, "expand start handler pc %d --> %d\n", current_pc, range->end_pc); #endif /* defined(DEBUG_JAVA_BINDING_LEVELS) */ + { + tree new = build (TRY_CATCH_EXPR, void_type_node, NULL, NULL); + TREE_SIDE_EFFECTS (new) = 1; + java_add_stmt (build_java_empty_stmt ()); + range->stmt = java_add_stmt (new); + } + range->expanded = 1; - expand_eh_region_start (); } tree @@ -348,7 +355,7 @@ prepare_eh_table_type (tree type) DECL_INITIAL (decl) = build_class_ref (type); layout_decl (decl, 0); pushdecl (decl); - exp = build1 (ADDR_EXPR, ptr_type_node, decl); + exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (decl)), decl); } else { @@ -370,6 +377,8 @@ prepare_eh_table_type (tree type) TYPE_CATCH_CLASSES (output_class)); } + exp = convert (ptr_type_node, exp); + *slot = tree_cons (type, exp, NULL_TREE); return exp; @@ -379,7 +388,10 @@ static int expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED) { struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry; - tree decl = TREE_OPERAND (TREE_VALUE ((tree)ite->value), 0); + tree addr = TREE_VALUE ((tree)ite->value); + tree decl; + STRIP_NOPS (addr); + decl = TREE_OPERAND (addr, 0); rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0); return true; } @@ -420,8 +432,9 @@ static void expand_end_java_handler (struct eh_range *range) { tree handler = range->handlers; - force_poplevels (range->start_pc); - expand_start_all_catch (); + tree compound = NULL; + + force_poplevels (range->start_pc); for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler)) { /* For bytecode we treat exceptions a little unusually. A @@ -431,14 +444,56 @@ expand_end_java_handler (struct eh_range *range) extra (and difficult) work to get this to look like a gcc-style finally clause. */ tree type = TREE_PURPOSE (handler); + if (type == NULL) type = throwable_type_node; - expand_start_catch (prepare_eh_table_type (type)); - expand_goto (TREE_VALUE (handler)); - expand_end_catch (); + type = prepare_eh_table_type (type); + + if (compound) + { + /* If we already have a COMPOUND there is more than one + catch handler for this try block. Wrap the + TRY_CATCH_EXPR in operand 1 of COMPOUND with another + TRY_CATCH_EXPR. */ + tree inner_try_expr = TREE_OPERAND (compound, 1); + tree catch_expr + = build (CATCH_EXPR, void_type_node, type, + build (GOTO_EXPR, void_type_node, TREE_VALUE (handler))); + tree try_expr + = build (TRY_CATCH_EXPR, void_type_node, + inner_try_expr, catch_expr); + TREE_OPERAND (compound, 1) = try_expr; + } + else + { + tree *stmts = get_stmts (); + tree outer; + tree try_expr; + compound = range->stmt; + outer = TREE_OPERAND (compound, 0); + try_expr = TREE_OPERAND (compound, 1); + /* On the left of COMPOUND is the expresion to be evaluated + before the try handler is entered; on the right is a + TRY_FINALLY_EXPR with no operands as yet. In the current + statement list is an expression that we're going to move + inside the try handler. We'll create a new COMPOUND_EXPR + with the outer context on the left and the TRY_FINALLY_EXPR + on the right, then nullify both operands of COMPOUND, which + becomes the final expression in OUTER. This new compound + expression replaces the current statement list. */ + TREE_OPERAND (try_expr, 0) = *stmts; + TREE_OPERAND (try_expr, 1) + = build (CATCH_EXPR, void_type_node, type, + build (GOTO_EXPR, void_type_node, TREE_VALUE (handler))); + TREE_SIDE_EFFECTS (try_expr) = 1; + TREE_OPERAND (compound, 0) = build_java_empty_stmt (); + TREE_OPERAND (compound, 1) = build_java_empty_stmt (); + compound + = build (COMPOUND_EXPR, TREE_TYPE (try_expr), outer, try_expr); + *stmts = compound; + } } - expand_end_all_catch (); #if defined(DEBUG_JAVA_BINDING_LEVELS) indent (); fprintf (stderr, "expand end handler pc %d <-- %d\n", diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 11f6c94643c..a63309ec9a4 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -43,6 +43,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "toplev.h" #include "except.h" #include "ggc.h" +#include "tree-simple.h" #include "target.h" static void flush_quick_stack (void); @@ -71,6 +72,8 @@ static void expand_compare (enum tree_code, tree, tree, int); static void expand_test (enum tree_code, tree, int); static void expand_cond (enum tree_code, tree, int); static void expand_java_goto (int); +static tree expand_java_switch (tree, int); +static void expand_java_add_case (tree, int, int); #if 0 static void expand_java_call (int, int); static void expand_java_ret (tree); @@ -94,7 +97,8 @@ tree dtable_ident = NULL_TREE; /* Set to nonzero value in order to emit class initialization code before static field references. */ -int always_initialize_class_p; +/* FIXME: Make this work with gimplify. */ +int always_initialize_class_p = 1; /* We store the stack state in two places: Within a basic block, we use the quick_stack, which is a @@ -231,7 +235,7 @@ flush_quick_stack (void) decl = find_stack_slot (stack_index, type); if (decl != node) - expand_assignment (decl, node, 0); + java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (node), decl, node)); stack_index += 1 + TYPE_IS_WIDE (type); } } @@ -489,7 +493,7 @@ static void java_stack_swap (void) { tree type1, type2; - rtx temp; + tree temp; tree decl1, decl2; if (stack_pointer < 2 @@ -503,10 +507,15 @@ java_stack_swap (void) flush_quick_stack (); decl1 = find_stack_slot (stack_pointer - 1, type1); decl2 = find_stack_slot (stack_pointer - 2, type2); - temp = copy_to_reg (DECL_RTL (decl1)); - emit_move_insn (DECL_RTL (find_stack_slot (stack_pointer - 1, type2)), - DECL_RTL (decl2)); - emit_move_insn (DECL_RTL (find_stack_slot (stack_pointer - 2, type1)), temp); + temp = build_decl (VAR_DECL, NULL_TREE, type1); + java_add_local_var (temp); + java_add_stmt (build (MODIFY_EXPR, type1, temp, decl1)); + java_add_stmt (build (MODIFY_EXPR, type2, + find_stack_slot (stack_pointer - 1, type2), + decl2)); + java_add_stmt (build (MODIFY_EXPR, type1, + find_stack_slot (stack_pointer - 2, type1), + temp)); stack_type_map[stack_pointer - 1] = type2; stack_type_map[stack_pointer - 2] = type1; } @@ -550,7 +559,9 @@ java_stack_dup (int size, int offset) { tree src_decl = find_stack_slot (src_index, type); tree dst_decl = find_stack_slot (dst_index, type); - emit_move_insn (DECL_RTL (dst_decl), DECL_RTL (src_decl)); + + java_add_stmt + (build (MODIFY_EXPR, TREE_TYPE (dst_decl), dst_decl, src_decl)); stack_type_map[dst_index] = type; } } @@ -570,7 +581,7 @@ build_java_athrow (tree node) build_tree_list (NULL_TREE, node), NULL_TREE); TREE_SIDE_EFFECTS (call) = 1; - expand_expr_stmt (call); + java_add_stmt (call); java_stack_pop (stack_pointer); } @@ -584,16 +595,17 @@ build_java_jsr (int target_pc, int return_pc) tree ret_label = fold (build1 (ADDR_EXPR, return_address_type_node, ret)); push_value (ret_label); flush_quick_stack (); - emit_jump (label_rtx (where)); - expand_label (ret); - if (instruction_bits [return_pc] & BCODE_VERIFIED) - load_type_state (ret); + java_add_stmt (build (GOTO_EXPR, void_type_node, where)); + + /* Do not need to emit the label here. We noted the existance of the + label as a jump target in note_instructions; we'll emit the label + for real at the beginning of the expand_byte_code loop. */ } static void build_java_ret (tree location) { - expand_computed_goto (location); + java_add_stmt (build (GOTO_EXPR, void_type_node, location)); } /* Implementation of operations on array: new, load, store, length */ @@ -713,7 +725,10 @@ java_check_reference (tree expr, int check) tree build_java_indirect_ref (tree type, tree expr, int check) { - return build1 (INDIRECT_REF, type, java_check_reference (expr, check)); + tree t; + t = java_check_reference (expr, check); + t = convert (build_pointer_type (type), t); + return build1 (INDIRECT_REF, type, t); } /* Implement array indexing (either as l-value or r-value). @@ -978,13 +993,11 @@ expand_java_arraystore (tree rhs_type_node) if (TREE_CODE (rhs_type_node) == POINTER_TYPE) { tree check = build_java_arraystore_check (array, rhs_node); - expand_expr_stmt (check); + java_add_stmt (check); } - expand_assignment (build_java_arrayaccess (array, - rhs_type_node, - index), - rhs_node, 0); + array = build_java_arrayaccess (array, rhs_type_node, index); + java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (array), array, rhs_node)); } /* Expand the evaluation of ARRAY[INDEX]. build_java_check_indexed_type makes @@ -1077,7 +1090,7 @@ static void expand_java_return (tree type) { if (type == void_type_node) - expand_null_return (); + java_add_stmt (build (RETURN_EXPR, void_type_node, NULL)); else { tree retval = pop_value (type); @@ -1094,7 +1107,7 @@ expand_java_return (tree type) retval = build1(NOP_EXPR, TREE_TYPE(res), retval); TREE_SIDE_EFFECTS (retval) = 1; - expand_return (retval); + java_add_stmt (build (RETURN_EXPR, TREE_TYPE (retval), retval)); } } @@ -1111,13 +1124,9 @@ expand_load_internal (int index, tree type, int pc) value into it. Then we push this new local on the stack. Hopefully this all gets optimized out. */ copy = build_decl (VAR_DECL, NULL_TREE, type); - DECL_CONTEXT (copy) = current_function_decl; - layout_decl (copy, 0); - DECL_REGISTER (copy) = 1; - expand_decl (copy); - MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (copy); - DECL_INITIAL (copy) = var; - expand_decl_init (copy); + java_add_local_var (copy); + java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (var), copy, var)); + push_value (copy); } @@ -1220,7 +1229,8 @@ build_instanceof (tree value, tree type) { tree save = save_expr (value); expr = build (COND_EXPR, itype, - save, + build (NE_EXPR, boolean_type_node, + save, null_pointer_node), build (EQ_EXPR, itype, build_get_class (save), build_class_ref (type)), @@ -1269,7 +1279,8 @@ expand_iinc (unsigned int local_var_index, int ival, int pc) local_var = find_local_variable (local_var_index, int_type_node, pc); constant_value = build_int_2 (ival, ival < 0 ? -1 : 0); res = fold (build (PLUS_EXPR, int_type_node, local_var, constant_value)); - expand_assignment (local_var, res, 0); + java_add_stmt (build (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res)); + update_aliases (local_var, local_var_index); } @@ -1552,7 +1563,6 @@ lookup_label (int pc) /* The type of the address of a label is return_address_type_node. */ tree decl = create_label_decl (name); LABEL_PC (decl) = pc; - label_rtx (decl); return pushdecl (decl); } } @@ -1600,9 +1610,10 @@ expand_compare (enum tree_code condition, tree value1, tree value2, { tree target = lookup_label (target_pc); tree cond = fold (build (condition, boolean_type_node, value1, value2)); - expand_start_cond (java_truthvalue_conversion (cond), 0); - expand_goto (target); - expand_end_cond (); + java_add_stmt + (build (COND_EXPR, void_type_node, java_truthvalue_conversion (cond), + build (GOTO_EXPR, void_type_node, target), + build_java_empty_stmt ())); } /* Emit code for a TEST-type opcode. */ @@ -1636,7 +1647,43 @@ expand_java_goto (int target_pc) { tree target_label = lookup_label (target_pc); flush_quick_stack (); - expand_goto (target_label); + java_add_stmt (build (GOTO_EXPR, void_type_node, target_label)); +} + +static tree +expand_java_switch (tree selector, int default_pc) +{ + tree switch_expr, x; + + flush_quick_stack (); + switch_expr = build (SWITCH_EXPR, TREE_TYPE (selector), selector, + NULL_TREE, NULL_TREE); + java_add_stmt (switch_expr); + + x = build (CASE_LABEL_EXPR, void_type_node, NULL_TREE, NULL_TREE, + create_artificial_label ()); + append_to_statement_list (x, &SWITCH_BODY (switch_expr)); + + x = build (GOTO_EXPR, void_type_node, lookup_label (default_pc)); + append_to_statement_list (x, &SWITCH_BODY (switch_expr)); + + return switch_expr; +} + +static void +expand_java_add_case (tree switch_expr, int match, int target_pc) +{ + tree value, x; + + value = build_int_2 (match, match < 0 ? -1 : 0); + TREE_TYPE (value) = TREE_TYPE (switch_expr); + + x = build (CASE_LABEL_EXPR, void_type_node, value, NULL_TREE, + create_artificial_label ()); + append_to_statement_list (x, &SWITCH_BODY (switch_expr)); + + x = build (GOTO_EXPR, void_type_node, lookup_label (target_pc)); + append_to_statement_list (x, &SWITCH_BODY (switch_expr)); } #if 0 @@ -1728,6 +1775,7 @@ build_class_init (tree clas, tree expr) optimizing class initialization. */ if (!STATIC_CLASS_INIT_OPT_P ()) DECL_BIT_INDEX(*init_test_decl) = -1; + DECL_INITIAL (*init_test_decl) = integer_zero_node; /* Don't emit any symbolic debugging info for this decl. */ DECL_IGNORED_P (*init_test_decl) = 1; } @@ -1769,7 +1817,8 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED, || (!TREE_PUBLIC (method) && DECL_CONTEXT (method))) { make_decl_rtl (method, NULL); - func = build1 (ADDR_EXPR, method_ptr_type_node, method); + func = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (method)), + method); } else { @@ -1780,6 +1829,7 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED, build (ARRAY_REF, method_ptr_type_node, TYPE_ATABLE_DECL (output_class), table_index); } + func = convert (method_ptr_type_node, func); } else { @@ -2086,7 +2136,11 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED) else func = build_invokeinterface (dtable, method); } - func = build1 (NOP_EXPR, build_pointer_type (method_type), func); + + if (TREE_CODE (func) == ADDR_EXPR) + TREE_TYPE (func) = build_pointer_type (method_type); + else + func = build1 (NOP_EXPR, build_pointer_type (method_type), func); call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE); TREE_SIDE_EFFECTS (call) = 1; @@ -2099,7 +2153,7 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED) } if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE) - expand_expr_stmt (call); + java_add_stmt (call); else { push_value (call); @@ -2118,6 +2172,7 @@ build_jni_stub (tree method) tree env_var, res_var = NULL_TREE, block; tree method_args, res_type; tree meth_var; + tree bind; int args_size = 0; @@ -2151,9 +2206,7 @@ build_jni_stub (tree method) DECL_INITIAL (meth_var) = null_pointer_node; TREE_USED (meth_var) = 1; chainon (env_var, meth_var); - layout_decl (meth_var, 0); - make_decl_rtl (meth_var, NULL); - rest_of_decl_compilation (meth_var, NULL, 0, 0); + build_result_decl (method); /* One strange way that the front ends are different is that they store arguments differently. */ @@ -2269,39 +2322,31 @@ build_jni_stub (tree method) body = build (COMPOUND_EXPR, void_type_node, body, call); TREE_SIDE_EFFECTS (body) = 1; - /* Finally, do the return. When compiling from source we rely on - patch_return to patch the return value -- because DECL_RESULT is - not set at the time this function is called. */ - if (from_class) - { - res_type = void_type_node; - if (res_var != NULL_TREE) - { - tree drt; - if (! DECL_RESULT (method)) - abort (); - /* Make sure we copy the result variable to the actual - result. We use the type of the DECL_RESULT because it - might be different from the return type of the function: - it might be promoted. */ - drt = TREE_TYPE (DECL_RESULT (method)); - if (drt != TREE_TYPE (res_var)) - res_var = build1 (CONVERT_EXPR, drt, res_var); - res_var = build (MODIFY_EXPR, drt, DECL_RESULT (method), res_var); - TREE_SIDE_EFFECTS (res_var) = 1; - } - } - else + /* Finally, do the return. */ + res_type = void_type_node; + if (res_var != NULL_TREE) { - /* This is necessary to get patch_return to run. */ - res_type = NULL_TREE; + tree drt; + if (! DECL_RESULT (method)) + abort (); + /* Make sure we copy the result variable to the actual + result. We use the type of the DECL_RESULT because it + might be different from the return type of the function: + it might be promoted. */ + drt = TREE_TYPE (DECL_RESULT (method)); + if (drt != TREE_TYPE (res_var)) + res_var = build1 (CONVERT_EXPR, drt, res_var); + res_var = build (MODIFY_EXPR, drt, DECL_RESULT (method), res_var); + TREE_SIDE_EFFECTS (res_var) = 1; } + body = build (COMPOUND_EXPR, void_type_node, body, build1 (RETURN_EXPR, res_type, res_var)); TREE_SIDE_EFFECTS (body) = 1; - - BLOCK_EXPR_BODY (block) = body; - return block; + + bind = build (BIND_EXPR, void_type_node, BLOCK_VARS (block), + body, block); + return bind; } /* Expand an operation to extract from or store into a field. @@ -2360,12 +2405,13 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index) { if (DECL_CONTEXT (field_decl) != current_class) error ("%Jassignment to final field '%D' not in field's class", - field_decl, field_decl); + field_decl, field_decl); else if (FIELD_STATIC (field_decl)) { if (!DECL_CLINIT_P (current_function_decl)) warning ("%Jassignment to final static field `%D' not in " - "class initializer", field_decl, field_decl); + "class initializer", + field_decl, field_decl); } else { @@ -2376,7 +2422,8 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index) field_decl, field_decl); } } - expand_assignment (field_ref, new_value, 0); + java_add_stmt (build (MODIFY_EXPR, + TREE_TYPE (field_ref), field_ref, new_value)); } else push_value (field_ref); @@ -2437,8 +2484,27 @@ java_expand_expr (tree exp, rtx target, enum machine_mode tmode, { tree current; + abort (); + switch (TREE_CODE (exp)) { + + case EXPR_WITH_FILE_LOCATION: + { + rtx to_return; + const char *saved_input_filename = input_filename; + int saved_lineno = input_line; + input_filename = EXPR_WFL_FILENAME (exp); + input_line = EXPR_WFL_LINENO (exp); + if (EXPR_WFL_EMIT_LINE_NOTE (exp)) + emit_line_note (input_location); + /* Possibly avoid switching back and forth here. */ + to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier); + input_filename = saved_input_filename; + input_line = saved_lineno; + return to_return; + } + case NEW_ARRAY_INIT: { rtx tmp; @@ -2576,12 +2642,6 @@ java_expand_expr (tree exp, rtx target, enum machine_mode tmode, build_decl (LABEL_DECL, NULL_TREE, NULL_TREE), NULL); return const0_rtx; - case SWITCH_EXPR: - expand_start_case (0, TREE_OPERAND (exp, 0), int_type_node, "switch"); - expand_expr_stmt (TREE_OPERAND (exp, 1)); - expand_end_case (TREE_OPERAND (exp, 0)); - return const0_rtx; - case TRY_EXPR: /* We expand a try[-catch] block */ @@ -2609,11 +2669,6 @@ java_expand_expr (tree exp, rtx target, enum machine_mode tmode, return expand_expr (build_exception_object_ref (TREE_TYPE (exp)), target, tmode, modifier); - case LABEL_EXPR: - /* Used only by expanded inline functions. */ - expand_label (TREE_OPERAND (exp, 0)); - return const0_rtx; - default: internal_error ("can't expand %s", tree_code_name [TREE_CODE (exp)]); } @@ -2799,7 +2854,7 @@ expand_byte_code (JCF *jcf, tree method) if (! verify_jvm_instructions (jcf, byte_ops, length)) return; - /* Translate bytecodes to rtl instructions. */ + /* Translate bytecodes. */ linenumber_pointer = linenumber_table; for (PC = 0; PC < length;) { @@ -2808,7 +2863,7 @@ expand_byte_code (JCF *jcf, tree method) tree label = lookup_label (PC); flush_quick_stack (); if ((instruction_bits [PC] & BCODE_TARGET) != 0) - expand_label (label); + java_add_stmt (build (LABEL_EXPR, void_type_node, label)); if (LABEL_VERIFIED (label) || PC == 0) load_type_state (label); } @@ -2855,8 +2910,7 @@ expand_byte_code (JCF *jcf, tree method) linenumber_pointer += 4; if (pc == PC) { - input_line = GET_u2 (linenumber_pointer - 2); - emit_line_note (input_location); + input_location.line = GET_u2 (linenumber_pointer - 2); if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS)) break; } @@ -2886,7 +2940,7 @@ java_push_constant_from_pool (JCF *jcf, int index) name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); index = alloc_name_constant (CONSTANT_String, name); c = build_ref_from_constant_pool (index); - TREE_TYPE (c) = promote_type (string_type_node); + c = convert (promote_type (string_type_node), c); } else c = get_constant (jcf, index); @@ -2905,7 +2959,7 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET) { tree type = pop_type (ptr_type_node); - push_value (build (JAVA_EXC_OBJ_EXPR, type)); + push_value (build_exception_object_ref (type)); } switch (byte_ops[PC++]) @@ -3007,46 +3061,24 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, #define LOOKUP_SWITCH \ { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \ tree selector = pop_value (INT_type_node); \ - tree duplicate, label; \ - tree type = TREE_TYPE (selector); \ - flush_quick_stack (); \ - expand_start_case (0, selector, type, "switch statement");\ + tree switch_expr = expand_java_switch (selector, oldpc + default_offset); \ while (--npairs >= 0) \ { \ jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \ - tree value = build_int_2 (match, match < 0 ? -1 : 0); \ - TREE_TYPE (value) = type; \ - label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ - pushcase (value, convert, label, &duplicate); \ - expand_java_goto (oldpc + offset); \ + expand_java_add_case (switch_expr, match, oldpc + offset); \ } \ - label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ - pushcase (NULL_TREE, 0, label, &duplicate); \ - expand_java_goto (oldpc + default_offset); \ - expand_end_case (selector); \ } #define TABLE_SWITCH \ { jint default_offset = IMMEDIATE_s4; \ jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \ tree selector = pop_value (INT_type_node); \ - tree duplicate, label; \ - tree type = TREE_TYPE (selector); \ - flush_quick_stack (); \ - expand_start_case (0, selector, type, "switch statement");\ + tree switch_expr = expand_java_switch (selector, oldpc + default_offset); \ for (; low <= high; low++) \ { \ jint offset = IMMEDIATE_s4; \ - tree value = build_int_2 (low, low < 0 ? -1 : 0); \ - TREE_TYPE (value) = type; \ - label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ - pushcase (value, convert, label, &duplicate); \ - expand_java_goto (oldpc + offset); \ + expand_java_add_case (switch_expr, low, oldpc + offset); \ } \ - label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ - pushcase (NULL_TREE, 0, label, &duplicate); \ - expand_java_goto (oldpc + default_offset); \ - expand_end_case (selector); \ } #define INVOKE(MAYBE_STATIC, IS_INTERFACE) \ @@ -3111,16 +3143,17 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, /* internal macro added for use by the WIDE case Added TREE_TYPE (decl) assignment, apbianco */ -#define STORE_INTERNAL(OPTYPE, OPVALUE) \ - { \ - tree decl, value; \ - int var = OPVALUE; \ - tree type = OPTYPE; \ - value = pop_value (type); \ - type = TREE_TYPE (value); \ - decl = find_local_variable (var, type, oldpc); \ - set_local_type (var, type ); \ - expand_assignment (decl, value, 0); \ +#define STORE_INTERNAL(OPTYPE, OPVALUE) \ + { \ + tree decl, value; \ + int index = OPVALUE; \ + tree type = OPTYPE; \ + value = pop_value (type); \ + type = TREE_TYPE (value); \ + decl = find_local_variable (index, type, oldpc); \ + set_local_type (index, type); \ + java_add_stmt (build (MODIFY_EXPR, type, decl, value)); \ + update_aliases (decl, index); \ } #define STORE(OPERAND_TYPE, OPERAND_VALUE) \ @@ -3143,7 +3176,7 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, flush_quick_stack (); \ c = build_java_monitor (call, o); \ TREE_SIDE_EFFECTS (c) = 1; \ - expand_expr_stmt (c); \ + java_add_stmt (c); \ } #define SPECIAL_IINC(IGNORED) \ @@ -3388,7 +3421,9 @@ force_evaluation_order (tree node) if (cmp) { - cmp = save_expr (build (COMPOUND_EXPR, TREE_TYPE (node), cmp, node)); + cmp = build (COMPOUND_EXPR, TREE_TYPE (node), cmp, node); + if (TREE_TYPE (cmp) != void_type_node) + cmp = save_expr (cmp); CAN_COMPLETE_NORMALLY (cmp) = CAN_COMPLETE_NORMALLY (node); TREE_SIDE_EFFECTS (cmp) = 1; node = cmp; @@ -3429,5 +3464,46 @@ emit_init_test_initialization (void **entry, void *x ATTRIBUTE_UNUSED) return true; } -#include "gt-java-expr.h" +/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact + location where an expression or an identifier were encountered. It + is necessary for languages where the frontend parser will handle + recursively more than one file (Java is one of them). */ +tree +build_expr_wfl (tree node, const char *file, int line, int col) +{ + static const char *last_file = 0; + static tree last_filenode = NULL_TREE; + tree wfl = make_node (EXPR_WITH_FILE_LOCATION); + + EXPR_WFL_NODE (wfl) = node; + EXPR_WFL_SET_LINECOL (wfl, line, col); + if (file != last_file) + { + last_file = file; + last_filenode = file ? get_identifier (file) : NULL_TREE; + } + + EXPR_WFL_FILENAME_NODE (wfl) = last_filenode; + if (node) + { + if (IS_NON_TYPE_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (node)))) + TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node); + TREE_TYPE (wfl) = TREE_TYPE (node); + } + + return wfl; +} + + +/* Build a node to represent empty statements and blocks. */ + +tree +build_java_empty_stmt (void) +{ + tree t = build_empty_stmt (); + CAN_COMPLETE_NORMALLY (t) = 1; + return t; +} + +#include "gt-java-expr.h" diff --git a/gcc/java/java-except.h b/gcc/java/java-except.h index b536ce0623e..0646d61b591 100644 --- a/gcc/java/java-except.h +++ b/gcc/java/java-except.h @@ -50,6 +50,9 @@ struct eh_range /* True if this range has already been expanded. */ int expanded; + + /* The TRY_CATCH_EXPR for this EH range. */ + tree stmt; }; /* A dummy range that represents the entire method. */ diff --git a/gcc/java/java-gimplify.c b/gcc/java/java-gimplify.c new file mode 100644 index 00000000000..ae8acd54c12 --- /dev/null +++ b/gcc/java/java-gimplify.c @@ -0,0 +1,277 @@ +/* Java(TM) language-specific gimplification routines. + + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +Java and all Java-based marks are trademarks or registered trademarks +of Sun Microsystems, Inc. in the United States and other countries. +The Free Software Foundation is independent of Sun Microsystems, Inc. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "java-tree.h" +#include "tree-dump.h" +#include "tree-simple.h" +#include "toplev.h" + +static tree java_gimplify_case_expr (tree); +static tree java_gimplify_default_expr (tree); +static tree java_gimplify_block (tree); +static tree java_gimplify_new_array_init (tree); +static tree java_gimplify_try_expr (tree); + +static void dump_java_tree (enum tree_dump_index, tree); + +/* Convert a Java tree to GENERIC. */ + +void +java_genericize (tree fndecl) +{ + dump_java_tree (TDI_original, fndecl); + + /* Genericize with the gimplifier. */ + gimplify_function_tree (fndecl); + + dump_function (TDI_generic, fndecl); +} + +/* Gimplify a Java tree. */ + +int +java_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, + tree *post_p ATTRIBUTE_UNUSED) +{ + char code_class = TREE_CODE_CLASS(TREE_CODE (*expr_p)); + + /* Java insists on strict left-to-right evaluation of expressions. + A problem may arise if a variable used in the lhs of a binary + operation is altered by an assignment to that value in the rhs + before we've performed the operation. So, we always copy every + LHS to a temprorary variable. + + FIXME: Are there any other cases where we should do this? + Parameter lists, maybe? Or perhaps that's unnecessary because + the front end already generates SAVE_EXPRs. */ + if (code_class == '2') + { + tree lhs = TREE_OPERAND (*expr_p, 0); + enum gimplify_status stat + = gimplify_expr (&lhs, pre_p, post_p, is_gimple_tmp_var, fb_rvalue); + if (stat == GS_ERROR) + return stat; + TREE_OPERAND (*expr_p, 0) = lhs; + } + + switch (TREE_CODE (*expr_p)) + { + case BLOCK: + *expr_p = java_gimplify_block (*expr_p); + break; + + case EXPR_WITH_FILE_LOCATION: + input_location.file = EXPR_WFL_FILENAME (*expr_p); + input_location.line = EXPR_WFL_LINENO (*expr_p); + *expr_p = EXPR_WFL_NODE (*expr_p); + annotate_with_locus (*expr_p, input_location); + break; + + case CASE_EXPR: + *expr_p = java_gimplify_case_expr (*expr_p); + break; + + case DEFAULT_EXPR: + *expr_p = java_gimplify_default_expr (*expr_p); + break; + + case NEW_ARRAY_INIT: + *expr_p = java_gimplify_new_array_init (*expr_p); + break; + + case TRY_EXPR: + *expr_p = java_gimplify_try_expr (*expr_p); + break; + + case JAVA_CATCH_EXPR: + *expr_p = TREE_OPERAND (*expr_p, 0); + break; + + case JAVA_EXC_OBJ_EXPR: + *expr_p = build_exception_object_ref (TREE_TYPE (*expr_p)); + break; + + /* These should already be lowered before we get here. */ + case URSHIFT_EXPR: + case COMPARE_EXPR: + case COMPARE_L_EXPR: + case COMPARE_G_EXPR: + case UNARY_PLUS_EXPR: + case NEW_ARRAY_EXPR: + case NEW_ANONYMOUS_ARRAY_EXPR: + case NEW_CLASS_EXPR: + case THIS_EXPR: + case SYNCHRONIZED_EXPR: + case CONDITIONAL_EXPR: + case INSTANCEOF_EXPR: + case CLASS_LITERAL: + abort (); + + default: + return GS_UNHANDLED; + } + + return GS_OK; +} + +static tree +java_gimplify_case_expr (tree expr) +{ + tree label = create_artificial_label (); + return build (CASE_LABEL_EXPR, void_type_node, + TREE_OPERAND (expr, 0), NULL_TREE, label); +} + +static tree +java_gimplify_default_expr (tree expr ATTRIBUTE_UNUSED) +{ + tree label = create_artificial_label (); + return build (CASE_LABEL_EXPR, void_type_node, NULL_TREE, NULL_TREE, label); +} + +/* Gimplify BLOCK into a BIND_EXPR. */ + +static tree +java_gimplify_block (tree java_block) +{ + tree decls = BLOCK_VARS (java_block); + tree body = BLOCK_EXPR_BODY (java_block); + tree outer = gimple_current_bind_expr (); + tree block; + + /* Don't bother with empty blocks. */ + if (! body) + return build_empty_stmt (); + + if (IS_EMPTY_STMT (body)) + return body; + + /* Make a proper block. Java blocks are unsuitable for BIND_EXPR + because they use BLOCK_SUBBLOCKS for another purpose. */ + block = make_node (BLOCK); + BLOCK_VARS (block) = decls; + if (outer != NULL_TREE) + { + outer = BIND_EXPR_BLOCK (outer); + BLOCK_SUBBLOCKS (outer) = chainon (BLOCK_SUBBLOCKS (outer), block); + } + + return build (BIND_EXPR, TREE_TYPE (java_block), decls, body, block); +} + +/* Gimplify a NEW_ARRAY_INIT node into array/element assignments. */ + +static tree +java_gimplify_new_array_init (tree exp) +{ + tree array_type = TREE_TYPE (TREE_TYPE (exp)); + tree data_field = lookup_field (&array_type, get_identifier ("data")); + tree element_type = TYPE_ARRAY_ELEMENT (array_type); + HOST_WIDE_INT ilength = java_array_type_length (array_type); + tree length = build_int_2 (ilength, 0); + tree init = TREE_OPERAND (exp, 0); + tree values = CONSTRUCTOR_ELTS (init); + + tree array_ptr_type = build_pointer_type (array_type); + tree block = build (BLOCK, array_ptr_type); + tree tmp = build_decl (VAR_DECL, get_identifier (""), array_ptr_type); + tree array = build_decl (VAR_DECL, get_identifier (""), array_ptr_type); + tree body = build (MODIFY_EXPR, array_ptr_type, tmp, + build_new_array (element_type, length)); + + int index = 0; + + DECL_CONTEXT (array) = current_function_decl; + DECL_CONTEXT (tmp) = current_function_decl; + + /* FIXME: try to allocate array statically? */ + while (values != NULL_TREE) + { + /* FIXME: Should use build_java_arrayaccess here, but avoid + bounds checking. */ + tree lhs = build (COMPONENT_REF, TREE_TYPE (data_field), + build_java_indirect_ref (array_type, tmp, 0), + data_field); + tree assignment = build (MODIFY_EXPR, element_type, + build (ARRAY_REF, element_type, lhs, + build_int_2 (index++, 0)), + TREE_VALUE (values)); + body = build (COMPOUND_EXPR, element_type, body, assignment); + values = TREE_CHAIN (values); + } + + body = build (COMPOUND_EXPR, array_ptr_type, body, + build (MODIFY_EXPR, array_ptr_type, array, tmp)); + TREE_CHAIN (tmp) = array; + BLOCK_VARS (block) = tmp; + BLOCK_EXPR_BODY (block) = body; + return java_gimplify_block (block); +} + +static tree +java_gimplify_try_expr (tree try_expr) +{ + tree body = TREE_OPERAND (try_expr, 0); + tree handler = TREE_OPERAND (try_expr, 1); + tree catch = NULL_TREE; + + /* Build a CATCH_EXPR for each handler. */ + while (handler) + { + tree java_catch = TREE_OPERAND (handler, 0); + tree catch_type = TREE_TYPE (TREE_TYPE (BLOCK_EXPR_DECLS (java_catch))); + tree expr = build (CATCH_EXPR, void_type_node, + prepare_eh_table_type (catch_type), + handler); + if (catch) + catch = build (COMPOUND_EXPR, void_type_node, catch, expr); + else + catch = expr; + handler = TREE_CHAIN (handler); + } + return build (TRY_CATCH_EXPR, void_type_node, body, catch); +} + +/* Dump a tree of some kind. This is a convenience wrapper for the + dump_* functions in tree-dump.c. */ +static void +dump_java_tree (enum tree_dump_index phase, tree t) +{ + FILE *stream; + int flags; + + stream = dump_begin (phase, &flags); + flags |= TDF_SLIM; + if (stream) + { + dump_node (t, flags, stream); + dump_end (phase, stream); + } +} diff --git a/gcc/java/java-tree.def b/gcc/java/java-tree.def index f15bc38701f..25ee5386205 100644 --- a/gcc/java/java-tree.def +++ b/gcc/java/java-tree.def @@ -55,7 +55,7 @@ DEFTREECODE (TRY_EXPR, "try-catch", 'e', 2) /* Catch clause. Operand 0 is the catch clause block, which contains the declaration of the catch clause parameter. */ -DEFTREECODE (CATCH_EXPR, "catch", '1', 1) +DEFTREECODE (JAVA_CATCH_EXPR, "catch", '1', 1) /* Synchronized statement. Operand 0 is the expression on which we wish to synchronize, @@ -91,6 +91,13 @@ DEFTREECODE (CLASS_LITERAL, "class_literal", '1', 1) /* The Java object within the exception object from the runtime. */ DEFTREECODE (JAVA_EXC_OBJ_EXPR, "java_exc_obj_expr", 'e', 0) +/* Annotates a tree node (usually an expression) with source location + information: a file name (EXPR_WFL_FILENAME); a line number + (EXPR_WFL_LINENO); and column number (EXPR_WFL_COLNO). It is + expanded as the contained node (EXPR_WFL_NODE); a line note should + be emitted first if EXPR_WFL_EMIT_LINE_NOTE. */ +DEFTREECODE (EXPR_WITH_FILE_LOCATION, "expr_with_file_location", 'e', 3) + /* Local variables: mode:c diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index faad7279cb1..b04ee4b0a95 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -349,7 +349,6 @@ enum java_tree_index JTI_DOUBLE_ZERO_NODE, JTI_INTEGER_TWO_NODE, JTI_INTEGER_FOUR_NODE, - JTI_EMPTY_STMT_NODE, JTI_METHODTABLE_TYPE, JTI_METHODTABLE_PTR_TYPE, @@ -562,8 +561,6 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; java_global_trees[JTI_INTEGER_TWO_NODE] #define integer_four_node \ java_global_trees[JTI_INTEGER_FOUR_NODE] -#define empty_stmt_node \ - java_global_trees[JTI_EMPTY_STMT_NODE] /* The type for struct methodtable. */ #define methodtable_type \ @@ -1178,6 +1175,7 @@ extern void set_java_signature (tree, tree); extern tree build_static_field_ref (tree); extern tree build_address_of (tree); extern tree find_local_variable (int index, tree type, int pc); +extern void update_aliases (tree decl, int index); extern tree find_stack_slot (int index, tree type); extern tree build_prim_array_type (tree, HOST_WIDE_INT); extern tree build_java_array_type (tree, HOST_WIDE_INT); @@ -1235,7 +1233,6 @@ extern int interface_of_p (tree, tree); extern int inherits_from_p (tree, tree); extern int common_enclosing_context_p (tree, tree); extern int enclosing_context_p (tree, tree); -extern void complete_start_java_method (tree); extern tree build_result_decl (tree); extern void emit_handlers (void); extern void set_method_index (tree decl, tree method_index); @@ -1341,8 +1338,13 @@ extern void compile_resource_data (const char *name, const char *buffer, int); extern void compile_resource_file (const char *, const char *); extern void write_resource_constructor (void); extern void init_resource_processing (void); +extern tree build_java_empty_stmt (void); +extern tree add_stmt_to_compound (tree, tree, tree); +extern tree java_add_stmt (tree); +extern tree java_add_local_var (tree decl); +extern tree *get_stmts (void); -extern void start_complete_expand_method (tree); +extern void finish_method (tree); extern void java_expand_body (tree); extern int get_symbol_table_index (tree, tree *); @@ -1819,4 +1821,28 @@ enum }; #undef DEBUG_JAVA_BINDING_LEVELS + +/* In an EXPR_WITH_FILE_LOCATION node. */ +#define EXPR_WFL_EMIT_LINE_NOTE(NODE) \ + (EXPR_WITH_FILE_LOCATION_CHECK (NODE)->common.public_flag) +#undef EXPR_WFL_NODE +#define EXPR_WFL_NODE(NODE) \ + TREE_OPERAND (EXPR_WITH_FILE_LOCATION_CHECK (NODE), 0) +#undef EXPR_WFL_FILENAME_NODE +#define EXPR_WFL_FILENAME_NODE(NODE) \ + TREE_OPERAND (EXPR_WITH_FILE_LOCATION_CHECK (NODE), 1) +#define EXPR_WFL_FILENAME(NODE) \ + IDENTIFIER_POINTER (EXPR_WFL_FILENAME_NODE (NODE)) +/* ??? Java uses this in all expressions. */ +#define EXPR_WFL_LINECOL(NODE) (EXPR_CHECK (NODE)->exp.complexity) +#define EXPR_WFL_LINENO(NODE) (EXPR_WFL_LINECOL (NODE) >> 12) +#define EXPR_WFL_COLNO(NODE) (EXPR_WFL_LINECOL (NODE) & 0xfff) +#define EXPR_WFL_SET_LINECOL(NODE, LINE, COL) \ + (EXPR_WFL_LINECOL(NODE) = ((LINE) << 12) | ((COL) & 0xfff)) + +extern tree build_expr_wfl PARAMS ((tree, const char *, int, int)); + +extern void java_genericize PARAMS ((tree)); +extern int java_gimplify_expr PARAMS ((tree *, tree *, tree *)); + #endif /* ! GCC_JAVA_TREE_H */ diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index e8fd413e01a..a44e860a242 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -738,7 +738,7 @@ parse_class_file (void) DECL_MAX_LOCALS (method) = decl_max_locals; start_java_method (method); give_name_to_locals (jcf); - expand_expr_stmt (build_jni_stub (method)); + *get_stmts () = build_jni_stub (method); end_java_method (); continue; } @@ -762,7 +762,7 @@ parse_class_file (void) for (ptr += 2; --i >= 0; ptr += 4) { int line = GET_u2 (ptr); - /* Set initial lineno lineno to smallest linenumber. + /* Set initial input_line to smallest linenumber. * Needs to be set before init_function_start. */ if (input_line == 0 || line < input_line) input_line = line; @@ -780,7 +780,7 @@ parse_class_file (void) give_name_to_locals (jcf); - /* Actually generate code. */ + /* Convert bytecode to trees. */ expand_byte_code (jcf, method); end_java_method (); @@ -1111,13 +1111,16 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED) java_expand_classes (); if (!java_report_errors () && !flag_syntax_only) { - /* Optimize and expand all classes compiled from source. */ - cgraph_finalize_compilation_unit (); - cgraph_optimize (); + /* Expand all classes compiled from source. */ java_finish_classes (); /* Emit the .jcf section. */ emit_register_classes (); + + /* Only finalize the compilation unit after we've told cgraph which + functions have their addresses stored. */ + cgraph_finalize_compilation_unit (); + cgraph_optimize (); } write_resource_constructor (); diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index 36a21d3f740..c715a2c1ed8 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -1428,7 +1428,7 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state) { location_t saved_location = input_location; tree body = EXPR_WFL_NODE (exp); - if (body == empty_stmt_node) + if (IS_EMPTY_STMT (body)) break; input_filename = EXPR_WFL_FILENAME (exp); input_line = EXPR_WFL_LINENO (exp); @@ -1773,7 +1773,7 @@ generate_bytecode_insns (tree exp, int target, struct jcf_partial *state) case RETURN_EXPR: exp = TREE_OPERAND (exp, 0); if (exp == NULL_TREE) - exp = empty_stmt_node; + exp = build_java_empty_stmt (); else if (TREE_CODE (exp) != MODIFY_EXPR) abort (); else diff --git a/gcc/java/lang.c b/gcc/java/lang.c index 4856e5f9c6e..20f13e5adb2 100644 --- a/gcc/java/lang.c +++ b/gcc/java/lang.c @@ -66,8 +66,6 @@ static bool java_can_use_bit_fields_p (void); static bool java_dump_tree (void *, tree); static void dump_compound_expr (dump_info_p, tree); static bool java_decl_ok_for_sibcall (tree); -static int java_estimate_num_insns (tree); -static int java_start_inlining (tree); static tree java_get_callee_fndecl (tree); #ifndef TARGET_OBJECT_SUFFIX @@ -174,7 +172,8 @@ int flag_force_classes_archive_check; /* When zero, don't optimize static class initialization. This flag shouldn't be tested alone, use STATIC_CLASS_INITIALIZATION_OPTIMIZATION_P instead. */ -int flag_optimize_sci = 1; +/* FIXME: Make this work with gimplify. */ +int flag_optimize_sci = 0; /* When nonzero, use offset tables for virtual method calls in order to improve binary compatibility. */ @@ -249,18 +248,15 @@ struct language_function GTY(()) #undef LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE #define LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE java_signed_or_unsigned_type -#undef LANG_HOOKS_TREE_INLINING_WALK_SUBTREES -#define LANG_HOOKS_TREE_INLINING_WALK_SUBTREES java_tree_inlining_walk_subtrees - -#undef LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS -#define LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS java_estimate_num_insns - -#undef LANG_HOOKS_TREE_INLINING_START_INLINING -#define LANG_HOOKS_TREE_INLINING_START_INLINING java_start_inlining - #undef LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN #define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN java_dump_tree +#undef LANG_HOOKS_GIMPLIFY_EXPR +#define LANG_HOOKS_GIMPLIFY_EXPR java_gimplify_expr + +#undef LANG_HOOKS_TREE_INLINING_WALK_SUBTREES +#define LANG_HOOKS_TREE_INLINING_WALK_SUBTREES java_tree_inlining_walk_subtrees + #undef LANG_HOOKS_DECL_OK_FOR_SIBCALL #define LANG_HOOKS_DECL_OK_FOR_SIBCALL java_decl_ok_for_sibcall @@ -732,17 +728,13 @@ java_post_options (const char **pfilename) { const char *filename = *pfilename; - /* Use tree inlining if possible. Function instrumentation is only - done in the RTL level, so we disable tree inlining. */ - if (! flag_instrument_function_entry_exit) + /* Use tree inlining. */ + if (!flag_no_inline) + flag_no_inline = 1; + if (flag_inline_functions) { - if (!flag_no_inline) - flag_no_inline = 1; - if (flag_inline_functions) - { - flag_inline_trees = 2; - flag_inline_functions = 0; - } + flag_inline_trees = 2; + flag_inline_functions = 0; } /* Open input file. */ @@ -1124,122 +1116,6 @@ java_decl_ok_for_sibcall (tree decl) return decl != NULL && DECL_CONTEXT (decl) == output_class; } -/* Used by estimate_num_insns. Estimate number of instructions seen - by given statement. */ -static tree -java_estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) -{ - int *count = data; - tree x = *tp; - - if (TYPE_P (x) || DECL_P (x)) - { - *walk_subtrees = 0; - return NULL; - } - /* Assume that constants and references counts nothing. These should - be majorized by amount of operations among them we count later - and are common target of CSE and similar optimizations. */ - if (TREE_CODE_CLASS (TREE_CODE (x)) == 'c' - || TREE_CODE_CLASS (TREE_CODE (x)) == 'r') - return NULL; - switch (TREE_CODE (x)) - { - /* Recognize assignments of large structures and constructors of - big arrays. */ - case MODIFY_EXPR: - case CONSTRUCTOR: - { - HOST_WIDE_INT size; - - size = int_size_in_bytes (TREE_TYPE (x)); - - if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO) - *count += 10; - else - *count += ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES); - } - break; - /* Few special cases of expensive operations. This is usefull - to avoid inlining on functions having too many of these. */ - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - case RDIV_EXPR: - case CALL_EXPR: - - case NEW_ARRAY_EXPR: - case NEW_ANONYMOUS_ARRAY_EXPR: - case NEW_CLASS_EXPR: - *count += 10; - break; - /* Various containers that will produce no code themselves. */ - case INIT_EXPR: - case TARGET_EXPR: - case BIND_EXPR: - case BLOCK: - case TREE_LIST: - case TREE_VEC: - case IDENTIFIER_NODE: - case PLACEHOLDER_EXPR: - case WITH_CLEANUP_EXPR: - case CLEANUP_POINT_EXPR: - case NOP_EXPR: - case VIEW_CONVERT_EXPR: - case SAVE_EXPR: - case UNSAVE_EXPR: - case COMPLEX_EXPR: - case REALPART_EXPR: - case IMAGPART_EXPR: - case TRY_CATCH_EXPR: - case TRY_FINALLY_EXPR: - case LABEL_EXPR: - case EXIT_EXPR: - case LABELED_BLOCK_EXPR: - case EXIT_BLOCK_EXPR: - case EXPR_WITH_FILE_LOCATION: - case UNARY_PLUS_EXPR: - case THIS_EXPR: - case DEFAULT_EXPR: - case TRY_EXPR: - - break; - case CLASS_LITERAL: - *walk_subtrees = 0; - break; - default: - (*count)++; - } - return NULL; -} - -/* Estimate number of instructions that will be created by expanding the body. */ -static int -java_estimate_num_insns (tree decl) -{ - int num = 0; - walk_tree_without_duplicates (&DECL_SAVED_TREE (decl), - java_estimate_num_insns_1, &num); - return num; -} - -/* Start inlining fn. Called by the tree inliner via - lang_hooks.tree_inlining.cannot_inline_tree_fn. */ - -static int -java_start_inlining (tree fn) -{ - /* A java function's body doesn't have a BLOCK structure suitable - for debug output until it is expanded. Prevent inlining functions - that are not yet expanded. */ - return TREE_ASM_WRITTEN (fn) ? 1 : 0; -} - /* Given a call_expr, try to figure out what its target might be. In the case of an indirection via the atable, search for the decl. If the decl is external, we return NULL. If we don't, the optimizer diff --git a/gcc/java/lang.opt b/gcc/java/lang.opt index 3e9cdf1250a..ae367a718a5 100644 --- a/gcc/java/lang.opt +++ b/gcc/java/lang.opt @@ -116,9 +116,6 @@ Java JoinedOrMissing RejectNegative fcompile-resource= Java Joined RejectNegative -fdump- -Java Joined RejectNegative - femit-class-file Java diff --git a/gcc/java/parse.y b/gcc/java/parse.y index 3212ddaf078..d6c597f4a52 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -144,6 +144,7 @@ static tree java_complete_tree (tree); static tree maybe_generate_pre_expand_clinit (tree); static int analyze_clinit_body (tree, tree); static int maybe_yank_clinit (tree); +static void start_complete_expand_method (tree); static void java_complete_expand_method (tree); static void java_expand_method_bodies (tree); static int unresolved_type_p (tree, tree *); @@ -197,7 +198,6 @@ static void check_deprecation (tree, tree); static int class_in_current_package (tree); static tree build_if_else_statement (int, tree, tree, tree); static tree patch_if_else_statement (tree); -static tree add_stmt_to_compound (tree, tree, tree); static tree add_stmt_to_block (tree, tree, tree); static tree patch_exit_expr (tree); static tree build_labeled_block (int, tree); @@ -910,7 +910,7 @@ class_body_declaration: | constructor_declaration | block /* Added, JDK1.1, instance initializer */ { - if ($1 != empty_stmt_node) + if (!IS_EMPTY_STMT ($1)) { TREE_CHAIN ($1) = CPC_INSTANCE_INITIALIZER_STMT (ctxp); SET_CPC_INSTANCE_INITIALIZER_STMT (ctxp, $1); @@ -1198,7 +1198,7 @@ constructor_body: addition (super invocation and field initialization) */ block_begin constructor_block_end { - BLOCK_EXPR_BODY ($2) = empty_stmt_node; + BLOCK_EXPR_BODY ($2) = build_java_empty_stmt (); $$ = $2; } | block_begin explicit_constructor_invocation constructor_block_end @@ -1376,7 +1376,7 @@ block_end: EXPR_WFL_ADD_COL ($1.location, 1); $$ = exit_block (); if (!BLOCK_SUBBLOCKS ($$)) - BLOCK_SUBBLOCKS ($$) = empty_stmt_node; + BLOCK_SUBBLOCKS ($$) = build_java_empty_stmt (); } ; @@ -1455,7 +1455,7 @@ empty_statement: EXPR_WFL_SET_LINECOL (wfl_operator, input_line, -1); parse_warning_context (wfl_operator, "An empty declaration is a deprecated feature that should not be used"); } - $$ = empty_stmt_node; + $$ = build_java_empty_stmt (); } ; @@ -1588,7 +1588,7 @@ switch_statement: switch_expression: SWITCH_TK OP_TK expression CP_TK { - $$ = build (SWITCH_EXPR, NULL_TREE, $3, NULL_TREE); + $$ = build (SWITCH_EXPR, NULL_TREE, $3, NULL_TREE, NULL_TREE); EXPR_WFL_LINECOL ($$) = $2.location; } | SWITCH_TK error @@ -1698,7 +1698,7 @@ for_statement: $$ = finish_for_loop (0, NULL_TREE, $4, $6); /* We have not condition, so we get rid of the EXIT_EXPR */ LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY ($$), 0) = - empty_stmt_node; + build_java_empty_stmt (); } | for_begin SC_TK error {yyerror ("Invalid control expression"); RECOVER;} @@ -1716,7 +1716,7 @@ for_statement_nsi: $$ = finish_for_loop (0, NULL_TREE, $4, $6); /* We have not condition, so we get rid of the EXIT_EXPR */ LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY ($$), 0) = - empty_stmt_node; + build_java_empty_stmt (); } ; @@ -1747,7 +1747,7 @@ for_begin: } ; for_init: /* Can be empty */ - { $$ = empty_stmt_node; } + { $$ = build_java_empty_stmt (); } | statement_expression_list { /* Init statement recorded within the previously @@ -1765,7 +1765,7 @@ for_init: /* Can be empty */ ; for_update: /* Can be empty */ - {$$ = empty_stmt_node;} + {$$ = build_java_empty_stmt ();} | statement_expression_list { $$ = build_debugable_stmt (BUILD_LOCATION (), $1); } ; @@ -1918,7 +1918,7 @@ catch_clause_parameter: declare_local_variables (0, TREE_VALUE ($3), build_tree_list (TREE_PURPOSE ($3), init)); - $$ = build1 (CATCH_EXPR, NULL_TREE, ccpb); + $$ = build1 (JAVA_CATCH_EXPR, NULL_TREE, ccpb); EXPR_WFL_LINECOL ($$) = $1.location; } else @@ -2988,7 +2988,7 @@ parse_jdk1_1_error (const char *msg) { sorry (": `%s' JDK1.1(TM) feature", msg); java_error_count++; - return empty_stmt_node; + return build_java_empty_stmt (); } static int do_warning = 0; @@ -4339,7 +4339,7 @@ register_fields (int flags, tree type, tree variable_list) if (duplicate_declaration_error_p (current_name, real_type, cl)) continue; - /* Set lineno to the line the field was found and create a + /* Set input_line to the line the field was found and create a declaration for it. Eventually sets the @deprecated tag flag. */ if (flag_emit_xref) input_line = EXPR_WFL_LINECOL (cl); @@ -5491,7 +5491,7 @@ java_fix_constructors (void) } /* safe_layout_class just makes sure that we can load a class without - disrupting the current_class, input_file, lineno, etc, information + disrupting the current_class, input_file, input_line, etc, information about the class processed currently. */ void @@ -7047,7 +7047,7 @@ find_in_imports_on_demand (tree enclosing_type, tree class_type) if (! (node = maybe_get_identifier (id_name))) continue; - /* Setup lineno so that it refers to the line of the import (in + /* Setup input_line so that it refers to the line of the import (in case we parse a class file and encounter errors */ input_line = EXPR_WFL_LINENO (TREE_PURPOSE (import)); @@ -7527,19 +7527,17 @@ source_end_java_method (void) /* Turn function bodies with only a NOP expr null, so they don't get generated at all and we won't get warnings when using the -W -Wall flags. */ - if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) == empty_stmt_node) + if (IS_EMPTY_STMT (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)))) BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) = NULL_TREE; - /* We've generated all the trees for this function, and it has been - patched. Dump it to a file if the user requested it. */ - dump_java_tree (TDI_original, fndecl); - - /* Defer expanding the method until cgraph analysis is complete. */ - if (DECL_SAVED_TREE (fndecl)) - cgraph_finalize_function (fndecl, false); + if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) + && ! flag_emit_class_files + && ! flag_emit_xref) + finish_method (fndecl); current_function_decl = NULL_TREE; java_parser_context_restore_global (); + current_function_decl = NULL_TREE; } /* Record EXPR in the current function block. Complements compound @@ -7569,18 +7567,6 @@ add_stmt_to_block (tree b, tree type, tree stmt) return c; } -/* Add STMT to EXISTING if possible, otherwise create a new - COMPOUND_EXPR and add STMT to it. */ - -static tree -add_stmt_to_compound (tree existing, tree type, tree stmt) -{ - if (existing) - return build (COMPOUND_EXPR, type, existing, stmt); - else - return stmt; -} - void java_layout_seen_class_methods (void) { tree previous_list = all_class_list; @@ -7853,7 +7839,7 @@ maybe_generate_pre_expand_clinit (tree class_type) /* We build the assignment expression that will initialize the field to its value. There are strict rules on static initializers (8.5). FIXME */ - if (TREE_CODE (stmt) != BLOCK && stmt != empty_stmt_node) + if (TREE_CODE (stmt) != BLOCK && !IS_EMPTY_STMT (stmt)) stmt = build_debugable_stmt (EXPR_WFL_LINECOL (stmt), stmt); java_method_add_stmt (mdecl, stmt); } @@ -7947,7 +7933,7 @@ maybe_yank_clinit (tree mdecl) bbody = BLOCK_EXPR_BODY (bbody); else return 0; - if (bbody && ! flag_emit_class_files && bbody != empty_stmt_node) + if (bbody && ! flag_emit_class_files && !IS_EMPTY_STMT (bbody)) return 0; type = DECL_CONTEXT (mdecl); @@ -7981,7 +7967,7 @@ maybe_yank_clinit (tree mdecl) /* Now we analyze the method body and look for something that isn't a MODIFY_EXPR */ - if (bbody != empty_stmt_node && analyze_clinit_body (type, bbody)) + if (!IS_EMPTY_STMT (bbody) && analyze_clinit_body (type, bbody)) return 0; /* Get rid of in the class' list of methods */ @@ -8146,7 +8132,6 @@ java_expand_method_bodies (tree class) for (decl = TYPE_METHODS (class); decl; decl = TREE_CHAIN (decl)) { tree block; - tree body; if (! DECL_FUNCTION_BODY (decl)) continue; @@ -8155,17 +8140,9 @@ java_expand_method_bodies (tree class) block = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (decl)); - if (TREE_CODE (block) != BLOCK) - abort (); - - /* Save the function body for inlining. */ + /* Save the function body for gimplify and inlining. */ DECL_SAVED_TREE (decl) = block; - body = BLOCK_EXPR_BODY (block); - - if (TREE_TYPE (body) == NULL_TREE) - abort (); - /* It's time to assign the variable flagging static class initialization based on which classes invoked static methods are definitely initializing. This should be flagged. */ @@ -8197,41 +8174,7 @@ java_expand_method_bodies (tree class) } } - /* Prepend class initialization to static methods. */ - if (METHOD_STATIC (decl) && ! METHOD_PRIVATE (decl) - && ! flag_emit_class_files - && ! DECL_CLINIT_P (decl) - && ! CLASS_INTERFACE (TYPE_NAME (class))) - { - tree init = build (CALL_EXPR, void_type_node, - build_address_of (soft_initclass_node), - build_tree_list (NULL_TREE, - build_class_ref (class)), - NULL_TREE); - TREE_SIDE_EFFECTS (init) = 1; - body = build (COMPOUND_EXPR, TREE_TYPE (body), init, body); - BLOCK_EXPR_BODY (block) = body; - } - - /* Wrap synchronized method bodies in a monitorenter - plus monitorexit cleanup. */ - if (METHOD_SYNCHRONIZED (decl) && ! flag_emit_class_files) - { - tree enter, exit, lock; - if (METHOD_STATIC (decl)) - lock = build_class_ref (class); - else - lock = DECL_ARGUMENTS (decl); - BUILD_MONITOR_ENTER (enter, lock); - BUILD_MONITOR_EXIT (exit, lock); - - body = build (COMPOUND_EXPR, void_type_node, - enter, - build (TRY_FINALLY_EXPR, void_type_node, body, exit)); - BLOCK_EXPR_BODY (block) = body; - } - - /* Expand the the function body. */ + /* Expand the function body. */ source_end_java_method (); } } @@ -8963,7 +8906,7 @@ fix_constructors (tree mdecl) { compound = add_stmt_to_compound (compound, NULL_TREE, TREE_OPERAND (found_call, 0)); - TREE_OPERAND (found_call, 0) = empty_stmt_node; + TREE_OPERAND (found_call, 0) = build_java_empty_stmt (); } DECL_INIT_CALLS_THIS (mdecl) = invokes_this; @@ -9470,7 +9413,7 @@ resolve_field_access (tree qual_wfl, tree *field_decl, tree *field_type) { int is_static = 0; tree field_ref; - tree decl, where_found, type_found; + tree decl = NULL_TREE, where_found, type_found; if (resolve_qualified_expression_name (qual_wfl, &decl, &where_found, &type_found)) @@ -10915,10 +10858,10 @@ patch_invoke (tree patch, tree method, tree args) /* We have to call force_evaluation_order now because creating a COMPOUND_EXPR wraps the arg list in a way that makes it unrecognizable by force_evaluation_order later. Yuk. */ - tree save = save_expr (force_evaluation_order (patch)); + tree save = force_evaluation_order (patch); tree type = TREE_TYPE (patch); - patch = build (COMPOUND_EXPR, type, save, empty_stmt_node); + patch = build (COMPOUND_EXPR, type, save, build_java_empty_stmt ()); list = tree_cons (method, patch, DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl)); @@ -11547,12 +11490,12 @@ java_complete_lhs (tree node) long blocks. */ ptr = &BLOCK_EXPR_BODY (node); while (TREE_CODE (*ptr) == COMPOUND_EXPR - && TREE_OPERAND (*ptr, 1) != empty_stmt_node) + && !IS_EMPTY_STMT (TREE_OPERAND (*ptr, 1))) { tree cur = java_complete_tree (TREE_OPERAND (*ptr, 0)); tree *next = &TREE_OPERAND (*ptr, 1); TREE_OPERAND (*ptr, 0) = cur; - if (cur == empty_stmt_node) + if (IS_EMPTY_STMT (cur)) { /* Optimization; makes it easier to detect empty bodies. Most useful for with all-constant initializer. */ @@ -11613,13 +11556,11 @@ java_complete_lhs (tree node) case TRY_FINALLY_EXPR: COMPLETE_CHECK_OP_0 (node); COMPLETE_CHECK_OP_1 (node); - /* Reduce try/finally nodes with an empty try block. */ - if (TREE_OPERAND (node, 0) == empty_stmt_node - || BLOCK_EMPTY_P (TREE_OPERAND (node, 0))) + if (IS_EMPTY_STMT (TREE_OPERAND (node, 0))) + /* Reduce try/finally nodes with an empty try block. */ return TREE_OPERAND (node, 1); - /* Likewise for an empty finally block. */ - if (TREE_OPERAND (node, 1) == empty_stmt_node - || BLOCK_EMPTY_P (TREE_OPERAND (node, 1))) + if (IS_EMPTY_STMT (TREE_OPERAND (node, 1))) + /* Likewise for an empty finally block. */ return TREE_OPERAND (node, 0); CAN_COMPLETE_NORMALLY (node) = (CAN_COMPLETE_NORMALLY (TREE_OPERAND (node, 0)) @@ -11634,7 +11575,7 @@ java_complete_lhs (tree node) TREE_TYPE (node) = void_type_node; POP_LABELED_BLOCK (); - if (LABELED_BLOCK_BODY (node) == empty_stmt_node) + if (IS_EMPTY_STMT (LABELED_BLOCK_BODY (node))) { LABELED_BLOCK_BODY (node) = NULL_TREE; CAN_COMPLETE_NORMALLY (node) = 1; @@ -11791,7 +11732,7 @@ java_complete_lhs (tree node) wfl_op2 = TREE_OPERAND (node, 1); TREE_OPERAND (node, 0) = nn = java_complete_tree (TREE_OPERAND (node, 0)); - if (wfl_op2 == empty_stmt_node) + if (IS_EMPTY_STMT (wfl_op2)) CAN_COMPLETE_NORMALLY (node) = CAN_COMPLETE_NORMALLY (nn); else { @@ -11864,7 +11805,7 @@ java_complete_lhs (tree node) EXPR_WFL_NODE (node) = body; TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (body); CAN_COMPLETE_NORMALLY (node) = CAN_COMPLETE_NORMALLY (body); - if (body == empty_stmt_node || TREE_CONSTANT (body)) + if (IS_EMPTY_STMT (body) || TREE_CONSTANT (body)) { /* Makes it easier to constant fold, detect empty bodies. */ return body; @@ -12000,7 +11941,7 @@ java_complete_lhs (tree node) else DECL_INITIAL (nn) = TREE_OPERAND (node, 1); DECL_FIELD_FINAL_IUD (nn) = 1; - return empty_stmt_node; + return build_java_empty_stmt (); } } if (! flag_emit_class_files) @@ -12444,14 +12385,14 @@ build_wfl_wrap (tree node, int location) return wfl; } -/* Build a super() constructor invocation. Returns empty_stmt_node if +/* Build a super() constructor invocation. Returns an empty statement if we're currently dealing with the class java.lang.Object. */ static tree build_super_invocation (tree mdecl) { if (DECL_CONTEXT (mdecl) == object_type_node) - return empty_stmt_node; + return build_java_empty_stmt (); else { tree super_wfl = build_wfl_node (super_identifier_node); @@ -12786,6 +12727,7 @@ patch_assignment (tree node, tree wfl_op1) ) { TREE_CONSTANT (lvalue) = 1; + TREE_INVARIANT (lvalue) = 1; DECL_INITIAL (lvalue) = new_rhs; } @@ -12798,7 +12740,7 @@ patch_assignment (tree node, tree wfl_op1) case INDIRECT_REF: case COMPONENT_REF: /* Transform a = foo.bar - into a = { int tmp; tmp = foo.bar; tmp; ). + into a = ({int tmp; tmp = foo.bar;}). We need to ensure that if a read from memory fails because of a NullPointerException, a destination variable will remain unchanged. An explicit temporary does what @@ -12817,8 +12759,7 @@ patch_assignment (tree node, tree wfl_op1) DECL_CONTEXT (tmp) = current_function_decl; TREE_TYPE (block) = TREE_TYPE (new_rhs); BLOCK_VARS (block) = tmp; - BLOCK_EXPR_BODY (block) - = build (COMPOUND_EXPR, TREE_TYPE (new_rhs), assignment, tmp); + BLOCK_EXPR_BODY (block) = assignment; TREE_SIDE_EFFECTS (block) = 1; new_rhs = block; } @@ -13340,6 +13281,7 @@ patch_binop (tree node, tree wfl_op1, tree wfl_op2) { parse_warning_context (wfl_operator, "Evaluating this expression will result in an arithmetic exception being thrown"); TREE_CONSTANT (node) = 0; + TREE_INVARIANT (node) = 0; } /* Change the division operator if necessary */ @@ -13926,8 +13868,15 @@ patch_string_cst (tree node) location = alloc_name_constant (CONSTANT_String, node); node = build_ref_from_constant_pool (location); } - TREE_TYPE (node) = string_ptr_type_node; TREE_CONSTANT (node) = 1; + TREE_INVARIANT (node) = 1; + + /* ??? Guessing that the class file code can't handle casts. */ + if (! flag_emit_class_files) + node = convert (string_ptr_type_node, node); + else + TREE_TYPE (node) = string_ptr_type_node; + return node; } @@ -14645,7 +14594,9 @@ patch_new_array_init (tree type, tree node) TREE_TYPE (init) = TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (type)))); TREE_TYPE (node) = promote_type (type); TREE_CONSTANT (init) = all_constant; + TREE_INVARIANT (init) = all_constant; TREE_CONSTANT (node) = all_constant; + TREE_INVARIANT (node) = all_constant; return node; } @@ -14814,7 +14765,7 @@ build_if_else_statement (int location, tree expression, tree if_body, { tree node; if (!else_body) - else_body = empty_stmt_node; + else_body = build_java_empty_stmt (); node = build (COND_EXPR, NULL_TREE, expression, if_body, else_body); EXPR_WFL_LINECOL (node) = location; node = build_debugable_stmt (location, node); @@ -14843,19 +14794,6 @@ patch_if_else_statement (tree node) return error_mark_node; } - if (TREE_CODE (expression) == INTEGER_CST) - { - if (integer_zerop (expression)) - node = TREE_OPERAND (node, 2); - else - node = TREE_OPERAND (node, 1); - if (CAN_COMPLETE_NORMALLY (node) != can_complete_normally) - { - node = build (COMPOUND_EXPR, void_type_node, node, empty_stmt_node); - CAN_COMPLETE_NORMALLY (node) = can_complete_normally; - } - return node; - } TREE_TYPE (node) = void_type_node; TREE_SIDE_EFFECTS (node) = 1; CAN_COMPLETE_NORMALLY (node) = can_complete_normally; @@ -14964,7 +14902,8 @@ build_loop_body (int location, tree condition, int reversed) second = (reversed ? condition : body); return build (COMPOUND_EXPR, NULL_TREE, - build (COMPOUND_EXPR, NULL_TREE, first, second), empty_stmt_node); + build (COMPOUND_EXPR, NULL_TREE, first, second), + build_java_empty_stmt ()); } /* Install CONDITION (if any) and loop BODY (using REVERSED to tell @@ -15004,14 +14943,14 @@ finish_for_loop (int location, tree condition, tree update, tree body) this because the (current interpretation of the) JLS requires that the update expression be considered reachable even if the for loop's body doesn't complete normally. */ - if (update != NULL_TREE && update != empty_stmt_node) + if (update != NULL_TREE && !IS_EMPTY_STMT (update)) { tree up2 = update; if (TREE_CODE (up2) == EXPR_WITH_FILE_LOCATION) up2 = EXPR_WFL_NODE (up2); /* It is possible for the update expression to be an EXPR_WFL_NODE wrapping nothing. */ - if (up2 != NULL_TREE && up2 != empty_stmt_node) + if (up2 != NULL_TREE && !IS_EMPTY_STMT (up2)) { /* Try to detect constraint violations. These would be programming errors somewhere. */ @@ -15323,7 +15262,7 @@ build_assertion (int location, tree condition, tree value) condition = build (TRUTH_ANDIF_EXPR, NULL_TREE, boolean_false_node, condition); if (value == NULL_TREE) - value = empty_stmt_node; + value = build_java_empty_stmt (); return build_if_else_statement (location, condition, value, NULL_TREE); } @@ -15432,8 +15371,8 @@ encapsulate_with_try_catch (int location, tree type_or_name, tree try_stmts, /* Add the catch statements */ add_stmt_to_block (catch_block, NULL_TREE, catch_stmts); - /* Now we can build a CATCH_EXPR */ - catch_block = build1 (CATCH_EXPR, NULL_TREE, catch_block); + /* Now we can build a JAVA_CATCH_EXPR */ + catch_block = build1 (JAVA_CATCH_EXPR, NULL_TREE, catch_block); return build_try_statement (location, try_block, catch_block); } @@ -15474,7 +15413,7 @@ patch_try_statement (tree node) int unreachable; /* At this point, the structure of the catch clause is - CATCH_EXPR (catch node) + JAVA_CATCH_EXPR (catch node) BLOCK (with the decl of the parameter) COMPOUND_EXPR MODIFY_EXPR (assignment of the catch parameter) diff --git a/gcc/java/resource.c b/gcc/java/resource.c index bc2860dfd1f..dc42a6f6e7e 100644 --- a/gcc/java/resource.c +++ b/gcc/java/resource.c @@ -79,6 +79,7 @@ compile_resource_data (const char *name, const char *buffer, int length) PUSH_FIELD_VALUE (rinit, "data", data); FINISH_RECORD_CONSTRUCTOR (rinit); TREE_CONSTANT (rinit) = 1; + TREE_INVARIANT (rinit) = 1; /* Generate a unique-enough identifier. */ sprintf (buf, "_Jr%d", ++Jr_count); diff --git a/gcc/jump.c b/gcc/jump.c index 643a714c7ad..2b46f7bc991 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -63,10 +63,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA or even change what is live at any point. So perhaps let combiner do it. */ -static rtx next_nonnote_insn_in_loop (rtx); static void init_label_info (rtx); static void mark_all_labels (rtx); -static int duplicate_loop_exit_test (rtx); static void delete_computation (rtx); static void redirect_exp_1 (rtx *, rtx, rtx, rtx); static int redirect_exp (rtx, rtx, rtx); @@ -122,55 +120,6 @@ cleanup_barriers (void) } } } - -/* Return the next insn after INSN that is not a NOTE and is in the loop, - i.e. when there is no such INSN before NOTE_INSN_LOOP_END return NULL_RTX. - This routine does not look inside SEQUENCEs. */ - -static rtx -next_nonnote_insn_in_loop (rtx insn) -{ - while (insn) - { - insn = NEXT_INSN (insn); - if (insn == 0 || GET_CODE (insn) != NOTE) - break; - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) - return NULL_RTX; - } - - return insn; -} - -void -copy_loop_headers (rtx f) -{ - rtx insn, next; - /* Now iterate optimizing jumps until nothing changes over one pass. */ - for (insn = f; insn; insn = next) - { - rtx temp, temp1; - - next = NEXT_INSN (insn); - - /* See if this is a NOTE_INSN_LOOP_BEG followed by an unconditional - jump. Try to optimize by duplicating the loop exit test if so. - This is only safe immediately after regscan, because it uses - the values of regno_first_uid and regno_last_uid. */ - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG - && (temp1 = next_nonnote_insn_in_loop (insn)) != 0 - && any_uncondjump_p (temp1) && onlyjump_p (temp1)) - { - temp = PREV_INSN (insn); - if (duplicate_loop_exit_test (insn)) - { - next = NEXT_INSN (temp); - } - } - } -} void purge_line_number_notes (rtx f) @@ -287,245 +236,6 @@ mark_all_labels (rtx f) } } } - -/* LOOP_START is a NOTE_INSN_LOOP_BEG note that is followed by an unconditional - jump. Assume that this unconditional jump is to the exit test code. If - the code is sufficiently simple, make a copy of it before INSN, - followed by a jump to the exit of the loop. Then delete the unconditional - jump after INSN. - - Return 1 if we made the change, else 0. - - This is only safe immediately after a regscan pass because it uses the - values of regno_first_uid and regno_last_uid. */ - -static int -duplicate_loop_exit_test (rtx loop_start) -{ - rtx insn, set, reg, p, link; - rtx copy = 0, first_copy = 0; - int num_insns = 0; - rtx exitcode - = NEXT_INSN (JUMP_LABEL (next_nonnote_insn_in_loop (loop_start))); - rtx lastexit; - int max_reg = max_reg_num (); - rtx *reg_map = 0; - rtx loop_pre_header_label; - - /* Scan the exit code. We do not perform this optimization if any insn: - - is a CALL_INSN - is a CODE_LABEL - has a REG_RETVAL or REG_LIBCALL note (hard to adjust) - is a NOTE_INSN_LOOP_BEG because this means we have a nested loop - - We also do not do this if we find an insn with ASM_OPERANDS. While - this restriction should not be necessary, copying an insn with - ASM_OPERANDS can confuse asm_noperands in some cases. - - Also, don't do this if the exit code is more than 20 insns. */ - - for (insn = exitcode; - insn - && ! (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END); - insn = NEXT_INSN (insn)) - { - switch (GET_CODE (insn)) - { - case CODE_LABEL: - case CALL_INSN: - return 0; - case NOTE: - - if (optimize < 2 - && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG - || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)) - /* If we were to duplicate this code, we would not move - the BLOCK notes, and so debugging the moved code would - be difficult. Thus, we only move the code with -O2 or - higher. */ - return 0; - - break; - case JUMP_INSN: - case INSN: - if (++num_insns > 20 - || find_reg_note (insn, REG_RETVAL, NULL_RTX) - || find_reg_note (insn, REG_LIBCALL, NULL_RTX)) - return 0; - break; - default: - break; - } - } - - /* Unless INSN is zero, we can do the optimization. */ - if (insn == 0) - return 0; - - lastexit = insn; - - /* See if any insn sets a register only used in the loop exit code and - not a user variable. If so, replace it with a new register. */ - for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == INSN - && (set = single_set (insn)) != 0 - && ((reg = SET_DEST (set), GET_CODE (reg) == REG) - || (GET_CODE (reg) == SUBREG - && (reg = SUBREG_REG (reg), GET_CODE (reg) == REG))) - && REGNO (reg) >= FIRST_PSEUDO_REGISTER - && REGNO_FIRST_UID (REGNO (reg)) == INSN_UID (insn)) - { - for (p = NEXT_INSN (insn); p != lastexit; p = NEXT_INSN (p)) - if (REGNO_LAST_UID (REGNO (reg)) == INSN_UID (p)) - break; - - if (p != lastexit) - { - /* We can do the replacement. Allocate reg_map if this is the - first replacement we found. */ - if (reg_map == 0) - reg_map = xcalloc (max_reg, sizeof (rtx)); - - REG_LOOP_TEST_P (reg) = 1; - - reg_map[REGNO (reg)] = gen_reg_rtx (GET_MODE (reg)); - } - } - loop_pre_header_label = gen_label_rtx (); - - /* Now copy each insn. */ - for (insn = exitcode; insn != lastexit; insn = NEXT_INSN (insn)) - { - switch (GET_CODE (insn)) - { - case BARRIER: - copy = emit_barrier_before (loop_start); - break; - case NOTE: - /* Only copy line-number notes. */ - if (NOTE_LINE_NUMBER (insn) >= 0) - { - copy = emit_note_before (NOTE_LINE_NUMBER (insn), loop_start); - NOTE_SOURCE_FILE (copy) = NOTE_SOURCE_FILE (insn); - } - break; - - case INSN: - copy = emit_insn_before (copy_insn (PATTERN (insn)), loop_start); - if (reg_map) - replace_regs (PATTERN (copy), reg_map, max_reg, 1); - - mark_jump_label (PATTERN (copy), copy, 0); - INSN_LOCATOR (copy) = INSN_LOCATOR (insn); - - /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will - make them. */ - for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) - if (REG_NOTE_KIND (link) != REG_LABEL) - { - if (GET_CODE (link) == EXPR_LIST) - REG_NOTES (copy) - = copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link), - XEXP (link, 0), - REG_NOTES (copy))); - else - REG_NOTES (copy) - = copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link), - XEXP (link, 0), - REG_NOTES (copy))); - } - - if (reg_map && REG_NOTES (copy)) - replace_regs (REG_NOTES (copy), reg_map, max_reg, 1); - break; - - case JUMP_INSN: - copy = emit_jump_insn_before (copy_insn (PATTERN (insn)), - loop_start); - INSN_LOCATOR (copy) = INSN_LOCATOR (insn); - if (reg_map) - replace_regs (PATTERN (copy), reg_map, max_reg, 1); - mark_jump_label (PATTERN (copy), copy, 0); - if (REG_NOTES (insn)) - { - REG_NOTES (copy) = copy_insn_1 (REG_NOTES (insn)); - if (reg_map) - replace_regs (REG_NOTES (copy), reg_map, max_reg, 1); - } - - /* Predict conditional jump that do make loop looping as taken. - Other jumps are probably exit conditions, so predict - them as untaken. */ - if (any_condjump_p (copy)) - { - rtx label = JUMP_LABEL (copy); - if (label) - { - /* The jump_insn after loop_start should be followed - by barrier and loopback label. */ - if (prev_nonnote_insn (label) - && (prev_nonnote_insn (prev_nonnote_insn (label)) - == next_nonnote_insn (loop_start))) - { - predict_insn_def (copy, PRED_LOOP_HEADER, TAKEN); - /* To keep pre-header, we need to redirect all loop - entrances before the LOOP_BEG note. */ - redirect_jump (copy, loop_pre_header_label, 0); - } - else - predict_insn_def (copy, PRED_LOOP_HEADER, NOT_TAKEN); - } - } - break; - - default: - abort (); - } - - /* Record the first insn we copied. We need it so that we can - scan the copied insns for new pseudo registers. */ - if (! first_copy) - first_copy = copy; - } - - /* Now clean up by emitting a jump to the end label and deleting the jump - at the start of the loop. */ - if (! copy || GET_CODE (copy) != BARRIER) - { - copy = emit_jump_insn_before (gen_jump (get_label_after (insn)), - loop_start); - - /* Record the first insn we copied. We need it so that we can - scan the copied insns for new pseudo registers. This may not - be strictly necessary since we should have copied at least one - insn above. But I am going to be safe. */ - if (! first_copy) - first_copy = copy; - - mark_jump_label (PATTERN (copy), copy, 0); - emit_barrier_before (loop_start); - } - - emit_label_before (loop_pre_header_label, loop_start); - - /* Now scan from the first insn we copied to the last insn we copied - (copy) for new pseudo registers. Do this after the code to jump to - the end label since that might create a new pseudo too. */ - reg_scan_update (first_copy, copy, max_reg); - - /* Mark the exit code as the virtual top of the converted loop. */ - emit_note_before (NOTE_INSN_LOOP_VTOP, exitcode); - - delete_related_insns (next_nonnote_insn (loop_start)); - - /* Clean up. */ - if (reg_map) - free (reg_map); - - return 1; -} /* Move all block-beg, block-end, loop-beg, loop-cont, loop-vtop, loop-end, notes between START and END out before START. START and END may be such @@ -1143,6 +853,8 @@ any_uncondjump_p (rtx insn) return 0; if (GET_CODE (SET_SRC (x)) != LABEL_REF) return 0; + if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX)) + return 0; return 1; } @@ -1827,75 +1539,6 @@ delete_for_peephole (rtx from, rtx to) is also an unconditional jump in that case. */ } -/* We have determined that AVOIDED_INSN is never reached, and are - about to delete it. If the insn chain between AVOIDED_INSN and - FINISH contains more than one line from the current function, and - contains at least one operation, print a warning if the user asked - for it. If FINISH is NULL, look between AVOIDED_INSN and a LABEL. - - CSE and inlining can duplicate insns, so it's possible to get - spurious warnings from this. */ - -void -never_reached_warning (rtx avoided_insn, rtx finish) -{ - rtx insn; - rtx a_line_note = NULL; - int two_avoided_lines = 0, contains_insn = 0, reached_end = 0; - - if (!warn_notreached) - return; - - /* Back up to the first of any NOTEs preceding avoided_insn; flow passes - us the head of a block, a NOTE_INSN_BASIC_BLOCK, which often follows - the line note. */ - insn = avoided_insn; - while (1) - { - rtx prev = PREV_INSN (insn); - if (prev == NULL_RTX - || GET_CODE (prev) != NOTE) - break; - insn = prev; - } - - /* Scan forwards, looking at LINE_NUMBER notes, until we hit a LABEL - in case FINISH is NULL, otherwise until we run out of insns. */ - - for (; insn != NULL; insn = NEXT_INSN (insn)) - { - if ((finish == NULL && GET_CODE (insn) == CODE_LABEL) - || GET_CODE (insn) == BARRIER) - break; - - if (GET_CODE (insn) == NOTE /* A line number note? */ - && NOTE_LINE_NUMBER (insn) >= 0) - { - if (a_line_note == NULL) - a_line_note = insn; - else - two_avoided_lines |= (NOTE_LINE_NUMBER (a_line_note) - != NOTE_LINE_NUMBER (insn)); - } - else if (INSN_P (insn)) - { - if (reached_end) - break; - contains_insn = 1; - } - - if (insn == finish) - reached_end = 1; - } - if (two_avoided_lines && contains_insn) - { - location_t locus; - locus.file = NOTE_SOURCE_FILE (a_line_note); - locus.line = NOTE_LINE_NUMBER (a_line_note); - warning ("%Hwill never be executed", &locus); - } -} - /* Throughout LOC, redirect OLABEL to NLABEL. Treat null OLABEL or NLABEL as a return. Accrue modifications into the change group. */ diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 5af66da7223..594103e1292 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -55,7 +55,9 @@ extern int lhd_unsafe_for_reeval (tree); extern void lhd_clear_binding_stack (void); extern void lhd_print_tree_nothing (FILE *, tree, int); extern const char *lhd_decl_printable_name (tree, int); +extern int lhd_types_compatible_p (tree, tree); extern rtx lhd_expand_expr (tree, rtx, enum machine_mode, int, rtx *); +extern int lhd_expand_decl (tree); extern void lhd_print_error_function (struct diagnostic_context *, const char *); extern void lhd_set_decl_assembler_name (tree); @@ -88,6 +90,9 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *); extern tree lhd_callgraph_analyze_expr (tree *, int *, tree); +/* Declarations for tree gimplification hooks. */ +extern int lhd_gimplify_expr (tree *, tree *, tree *); + #define LANG_HOOKS_NAME "GNU unknown" #define LANG_HOOKS_IDENTIFIER_SIZE sizeof (struct lang_identifier) #define LANG_HOOKS_INIT hook_bool_void_false @@ -102,6 +107,7 @@ extern tree lhd_callgraph_analyze_expr (tree *, int *, tree); #define LANG_HOOKS_GET_ALIAS_SET lhd_get_alias_set #define LANG_HOOKS_EXPAND_CONSTANT lhd_return_tree #define LANG_HOOKS_EXPAND_EXPR lhd_expand_expr +#define LANG_HOOKS_EXPAND_DECL lhd_expand_decl #define LANG_HOOKS_SAFE_FROM_P lhd_safe_from_p #define LANG_HOOKS_FINISH_INCOMPLETE_DECL lhd_do_nothing_t #define LANG_HOOKS_UNSAFE_FOR_REEVAL lhd_unsafe_for_reeval @@ -122,18 +128,15 @@ extern tree lhd_callgraph_analyze_expr (tree *, int *, tree); #define LANG_HOOKS_DECL_PRINTABLE_NAME lhd_decl_printable_name #define LANG_HOOKS_GET_CALLEE_FNDECL lhd_return_null_tree #define LANG_HOOKS_EXPR_SIZE lhd_expr_size -#define LANG_HOOKS_DECL_UNINIT lhd_decl_uninit #define LANG_HOOKS_TREE_SIZE lhd_tree_size +#define LANG_HOOKS_TYPES_COMPATIBLE_P lhd_types_compatible_p #define LANG_HOOKS_UPDATE_DECL_AFTER_SAVING NULL #define LANG_HOOKS_FUNCTION_INIT lhd_do_nothing_f #define LANG_HOOKS_FUNCTION_FINAL lhd_do_nothing_f #define LANG_HOOKS_FUNCTION_ENTER_NESTED lhd_do_nothing_f #define LANG_HOOKS_FUNCTION_LEAVE_NESTED lhd_do_nothing_f - -#define LANG_HOOKS_RTL_EXPAND_START lhd_do_nothing -#define LANG_HOOKS_RTL_EXPAND_STMT (void (*) (tree)) abort -#define LANG_HOOKS_RTL_EXPAND_END lhd_do_nothing +#define LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P hook_bool_tree_true /* Attribute hooks. */ #define LANG_HOOKS_ATTRIBUTE_TABLE NULL @@ -195,14 +198,13 @@ extern tree lhd_callgraph_analyze_expr (tree *, int *, tree); LANG_HOOKS_FUNCTION_INIT, \ LANG_HOOKS_FUNCTION_FINAL, \ LANG_HOOKS_FUNCTION_ENTER_NESTED, \ - LANG_HOOKS_FUNCTION_LEAVE_NESTED \ + LANG_HOOKS_FUNCTION_LEAVE_NESTED, \ + LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P \ } -#define LANG_HOOKS_RTL_EXPAND_INITIALIZER { \ - LANG_HOOKS_RTL_EXPAND_START, \ - LANG_HOOKS_RTL_EXPAND_STMT, \ - LANG_HOOKS_RTL_EXPAND_END \ -} +/* Hooks for tree gimplification. */ +#define LANG_HOOKS_GIMPLIFY_EXPR lhd_gimplify_expr +#define LANG_HOOKS_GIMPLE_BEFORE_INLINING true /* Tree dump hooks. */ extern bool lhd_tree_dump_dump_tree (void *, tree); @@ -282,6 +284,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_GET_ALIAS_SET, \ LANG_HOOKS_EXPAND_CONSTANT, \ LANG_HOOKS_EXPAND_EXPR, \ + LANG_HOOKS_EXPAND_DECL, \ LANG_HOOKS_TRUTHVALUE_CONVERSION, \ LANG_HOOKS_SAFE_FROM_P, \ LANG_HOOKS_FINISH_INCOMPLETE_DECL, \ @@ -301,10 +304,10 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_PRINT_TYPE, \ LANG_HOOKS_PRINT_IDENTIFIER, \ LANG_HOOKS_DECL_PRINTABLE_NAME, \ + LANG_HOOKS_TYPES_COMPATIBLE_P, \ LANG_HOOKS_GET_CALLEE_FNDECL, \ LANG_HOOKS_PRINT_ERROR_FUNCTION, \ LANG_HOOKS_EXPR_SIZE, \ - LANG_HOOKS_DECL_UNINIT, \ LANG_HOOKS_UPDATE_DECL_AFTER_SAVING, \ LANG_HOOKS_ATTRIBUTE_TABLE, \ LANG_HOOKS_COMMON_ATTRIBUTE_TABLE, \ @@ -315,7 +318,8 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_TREE_DUMP_INITIALIZER, \ LANG_HOOKS_DECLS, \ LANG_HOOKS_FOR_TYPES_INITIALIZER, \ - LANG_HOOKS_RTL_EXPAND_INITIALIZER \ + LANG_HOOKS_GIMPLIFY_EXPR, \ + LANG_HOOKS_GIMPLE_BEFORE_INLINING \ } #endif /* GCC_LANG_HOOKS_DEF_H */ diff --git a/gcc/langhooks.c b/gcc/langhooks.c index 3e15a359333..58e4eb6b21d 100644 --- a/gcc/langhooks.c +++ b/gcc/langhooks.c @@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "tree.h" #include "tree-inline.h" +#include "tree-simple.h" #include "rtl.h" #include "insn-config.h" #include "integrate.h" @@ -272,6 +273,19 @@ lhd_expand_expr (tree t ATTRIBUTE_UNUSED, rtx r ATTRIBUTE_UNUSED, abort (); } +/* This is the default expand_decl function. */ +/* The default language-specific function for expanding a DECL_STMT. After + the language-independent cases are handled, this function will be + called. If this function is not defined, it is assumed that + declarations other than those for variables and labels do not require + any RTL generation. */ + +int +lhd_expand_decl (tree t ATTRIBUTE_UNUSED) +{ + return 0; +} + /* This is the default decl_printable_name function. */ const char * @@ -280,6 +294,16 @@ lhd_decl_printable_name (tree decl, int verbosity ATTRIBUTE_UNUSED) return IDENTIFIER_POINTER (DECL_NAME (decl)); } +/* This compares two types for equivalence ("compatible" in C-based languages). + This routine should only return 1 if it is sure. It should not be used + in contexts where erroneously returning 0 causes problems. */ + +int +lhd_types_compatible_p (tree x, tree y) +{ + return TYPE_MAIN_VARIANT (x) == TYPE_MAIN_VARIANT (y); +} + /* lang_hooks.tree_inlining.walk_subtrees is called by walk_tree() after handling common cases, but before walking code-specific sub-trees. If this hook is overridden for a language, it should @@ -458,13 +482,14 @@ lhd_expr_size (tree exp) else return size_in_bytes (TREE_TYPE (exp)); } -/* lang_hooks.decl_uninit: Find out if a variable is uninitialized based - on DECL_INITIAL. */ -bool -lhd_decl_uninit (tree t ATTRIBUTE_UNUSED) +/* lang_hooks.gimplify_expr re-writes *EXPR_P into GIMPLE form. */ + +int +lhd_gimplify_expr (tree *expr_p ATTRIBUTE_UNUSED, tree *pre_p ATTRIBUTE_UNUSED, + tree *post_p ATTRIBUTE_UNUSED) { - return false; + return GS_UNHANDLED; } /* lang_hooks.tree_size: Determine the size of a tree with code C, diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 8ad1c477575..92bf00b61c2 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -76,19 +76,9 @@ struct lang_hooks_for_functions /* Called when leaving a nested function. */ void (*leave_nested) (struct function *); -}; - -/* Lang hooks for rtl code generation. */ -struct lang_hooks_for_rtl_expansion -{ - /* Called after expand_function_start, but before expanding the body. */ - void (*start) (void); - - /* Called to expand each statement. */ - void (*stmt) (tree); - /* Called after expanding the body but before expand_function_end. */ - void (*end) (void); + /* Determines if it's ok for a function to have no noreturn attribute. */ + bool (*missing_noreturn_ok_p) (tree); }; /* The following hooks are used by tree-dump.c. */ @@ -287,6 +277,10 @@ struct lang_hooks Fourth argument is actually an enum expand_modifier. */ rtx (*expand_expr) (tree, rtx, enum machine_mode, int, rtx *); + /* Called by expand_expr to generate the definition of a decl. Returns + 1 if handled, 0 otherwise. */ + int (*expand_decl) (tree); + /* Prepare expr to be an argument of a TRUTH_NOT_EXPR or other logical operation. @@ -380,6 +374,11 @@ struct lang_hooks types in C++. */ const char *(*decl_printable_name) (tree decl, int verbosity); + /* This compares two types for equivalence ("compatible" in C-based languages). + This routine should only return 1 if it is sure. It should not be used + in contexts where erroneously returning 0 causes problems. */ + int (*types_compatible_p) (tree x, tree y); + /* Given a CALL_EXPR, return a function decl that is its target. */ tree (*lang_get_callee_fndecl) (tree); @@ -392,10 +391,6 @@ struct lang_hooks semantics in cases that it doesn't want to handle specially. */ tree (*expr_size) (tree); - /* Called from uninitialized_vars_warning to find out if a variable is - uninitialized based on DECL_INITIAL. */ - bool (*decl_uninit) (tree); - /* Update lang specific fields after duplicating function body. */ void (*update_decl_after_saving) (tree, void *); @@ -421,7 +416,13 @@ struct lang_hooks struct lang_hooks_for_types types; - struct lang_hooks_for_rtl_expansion rtl_expand; + /* Perform language-specific gimplification on the argument. Returns an + enum gimplify_status, though we can't see that type here. */ + int (*gimplify_expr) (tree *, tree *, tree *); + + /* True if the front end has gimplified the function before running the + inliner, false if the front end generates GENERIC directly. */ + bool gimple_before_inlining; /* Whenever you add entries here, make sure you adjust langhooks-def.h and langhooks.c accordingly. */ diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 1d89ad61034..bec59c061ae 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -1381,6 +1381,7 @@ build_objc_string_object (tree string) { tree initlist, constructor, constant_string_class; int length; + tree fields; string = fix_string_type (string); @@ -1410,6 +1411,7 @@ build_objc_string_object (tree string) } add_class_reference (constant_string_id); } + fields = TYPE_FIELDS (constant_string_type); /* & ((NXConstantString) { NULL, string, length }) */ @@ -1425,18 +1427,23 @@ build_objc_string_object (tree string) return error_mark_node; } initlist = build_tree_list - (NULL_TREE, + (fields, copy_node (build_unary_op (ADDR_EXPR, string_class_decl, 0))); } else { - initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0)); + initlist = build_tree_list (fields, build_int_2 (0, 0)); } + fields = TREE_CHAIN (fields); + initlist - = tree_cons (NULL_TREE, copy_node (build_unary_op (ADDR_EXPR, string, 1)), + = tree_cons (fields, copy_node (build_unary_op (ADDR_EXPR, string, 1)), initlist); - initlist = tree_cons (NULL_TREE, build_int_2 (length, 0), initlist); + + fields = TREE_CHAIN (fields); + + initlist = tree_cons (fields, build_int_2 (length, 0), initlist); constructor = objc_build_constructor (constant_string_type, nreverse (initlist)); @@ -5965,7 +5972,9 @@ build_protocol_expr (tree protoname) expr = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0); - TREE_TYPE (expr) = protocol_type; + /* ??? Ideally we'd build the reference with protocol_type directly, + if we have it, rather than converting it here. */ + expr = convert (protocol_type, expr); /* The @protocol() expression is being compiled into a pointer to a statically allocated instance of the Protocol class. To become diff --git a/gcc/objc/objc-lang.c b/gcc/objc/objc-lang.c index 2853ded31c8..cdc5453687c 100644 --- a/gcc/objc/objc-lang.c +++ b/gcc/objc/objc-lang.c @@ -61,6 +61,8 @@ enum c_language_kind c_language = clk_objc; #define LANG_HOOKS_CLEAR_BINDING_STACK lhd_do_nothing #undef LANG_HOOKS_EXPAND_EXPR #define LANG_HOOKS_EXPAND_EXPR c_expand_expr +#undef LANG_HOOKS_EXPAND_DECL +#define LANG_HOOKS_EXPAND_DECL c_expand_decl #undef LANG_HOOKS_MARK_ADDRESSABLE #define LANG_HOOKS_MARK_ADDRESSABLE c_mark_addressable #undef LANG_HOOKS_TRUTHVALUE_CONVERSION @@ -83,16 +85,13 @@ enum c_language_kind c_language = clk_objc; #define LANG_HOOKS_DECL_PRINTABLE_NAME objc_printable_name #undef LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL #define LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL c_warn_unused_global_decl -#undef LANG_HOOKS_DECL_UNINIT -#define LANG_HOOKS_DECL_UNINIT c_decl_uninit #undef LANG_HOOKS_FUNCTION_ENTER_NESTED #define LANG_HOOKS_FUNCTION_ENTER_NESTED c_push_function_context #undef LANG_HOOKS_FUNCTION_LEAVE_NESTED #define LANG_HOOKS_FUNCTION_LEAVE_NESTED c_pop_function_context - -#undef LANG_HOOKS_RTL_EXPAND_STMT -#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt +#undef LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P +#define LANG_HOOKS_FUNCTION_MISSING_NORETURN_OK_P c_missing_noreturn_ok_p /* Attribute hooks. */ #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE @@ -113,8 +112,9 @@ enum c_language_kind c_language = clk_objc; #undef LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING #define LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING \ c_convert_parm_for_inlining -#undef LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS -#define LANG_HOOKS_TREE_INLINING_ESTIMATE_NUM_INSNS c_estimate_num_insns +#undef LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P +#define LANG_HOOKS_TREE_INLINING_TREE_CHAIN_MATTERS_P \ + c_tree_chain_matters_p #undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION #define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION c_expand_body @@ -133,6 +133,8 @@ enum c_language_kind c_language = clk_objc; #define LANG_HOOKS_INCOMPLETE_TYPE_ERROR c_incomplete_type_error #undef LANG_HOOKS_TYPE_PROMOTES_TO #define LANG_HOOKS_TYPE_PROMOTES_TO c_type_promotes_to +#undef LANG_HOOKS_GIMPLIFY_EXPR +#define LANG_HOOKS_GIMPLIFY_EXPR c_gimplify_expr /* The C front end's scoping structure is very different from that expected by the language-independent code; it is best diff --git a/gcc/opts.c b/gcc/opts.c index 4cf4446fdb5..c8a488f5d45 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -540,6 +540,24 @@ decode_options (unsigned int argc, const char **argv) flag_loop_optimize = 1; flag_if_conversion = 1; flag_if_conversion2 = 1; + flag_tree_ccp = 1; + flag_tree_dce = 1; + flag_tree_dom = 1; + flag_tree_dse = 1; + flag_tree_pre = 1; + flag_tree_ter = 1; + flag_tree_live_range_split = 1; + flag_tree_sra = 1; + flag_tree_copyrename = 1; + + if (!optimize_size) + { + /* Loop header copying usually increases size of the code. This used + not to be true, since quite often it is possible to verify that + the condition is satisfied in the first iteration and therefore + to eliminate it. Jump threading handles these cases now. */ + flag_tree_ch = 1; + } } if (optimize >= 2) @@ -995,6 +1013,11 @@ common_handle_option (size_t scode, const char *arg, return 0; break; + case OPT_fdump_: + if (!dump_switch_p (arg)) + return 0; + break; + case OPT_fdump_unnumbered: flag_dump_unnumbered = value; break; @@ -1150,6 +1173,19 @@ common_handle_option (size_t scode, const char *arg, flag_move_all_movables = value; break; + case OPT_fmudflap: + flag_mudflap = value; + break; + + case OPT_fmudflapth: + flag_mudflap = value; + flag_mudflap_threads = value; + break; + + case OPT_fmudflapir: + flag_mudflap_ignore_reads = value; + break; + case OPT_fnew_ra: flag_new_regalloc = value; break; @@ -1450,6 +1486,70 @@ common_handle_option (size_t scode, const char *arg, flag_trapv = value; break; + case OPT_ftree_based_profiling: + flag_tree_based_profiling = value; + break; + + case OPT_ftree_ccp: + flag_tree_ccp = value; + break; + + case OPT_ftree_dce: + flag_tree_dce = value; + break; + + case OPT_ftree_combine_temps: + flag_tree_combine_temps = value; + break; + + case OPT_ftree_ter: + flag_tree_ter = value; + break; + + case OPT_ftree_lrs: + flag_tree_live_range_split = value; + break; + + case OPT_ftree_dominator_opts: + flag_tree_dom = value; + break; + + case OPT_ftree_copyrename: + flag_tree_copyrename = value; + break; + + case OPT_ftree_ch: + flag_tree_ch = value; + break; + + case OPT_ftree_dse: + flag_tree_dse = value; + break; + + case OPT_ftree_sra: + flag_tree_sra = value; + break; + + case OPT_ftree_points_to_: + if (!strcmp (arg, "andersen")) +#ifdef HAVE_BANSHEE + flag_tree_points_to = PTA_ANDERSEN; +#else + warning ("Andersen's PTA not available - libbanshee not compiled."); +#endif + else if (!strcmp (arg, "none")) + flag_tree_points_to = PTA_NONE; + else + { + warning ("`%s`: unknown points-to analysis algorithm", arg); + return 0; + } + break; + + case OPT_ftree_pre: + flag_tree_pre = value; + break; + case OPT_funit_at_a_time: flag_unit_at_a_time = value; break; diff --git a/gcc/output.h b/gcc/output.h index 9040327879c..945dace71d2 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -150,12 +150,7 @@ extern int add_weak (tree, const char *, const char *); /* Functions in flow.c */ extern void allocate_for_life_analysis (void); -extern int regno_uninitialized (unsigned int); extern int regno_clobbered_at_setjmp (int); -extern void find_basic_blocks (rtx, int, FILE *); -extern bool cleanup_cfg (int); -extern bool delete_unreachable_blocks (void); -extern void check_function_return_warnings (void); /* Functions in varasm.c. */ diff --git a/gcc/params.def b/gcc/params.def index c406ab87ae9..ff77eb488ce 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -65,6 +65,26 @@ DEFPARAM (PARAM_MAX_INLINE_INSNS_AUTO, "The maximum number of instructions when automatically inlining", 120) +DEFPARAM (PARAM_MAX_INLINE_INSNS_RECURSIVE, + "max-inline-insns-recursive", + "The maximum number of instructions inline function can grow to via recursive inlining", + 500) + +DEFPARAM (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO, + "max-inline-insns-recursive-auto", + "The maximum number of instructions non-inline function can grow to via recursive inlining", + 500) + +DEFPARAM (PARAM_MAX_INLINE_RECURSIVE_DEPTH, + "max-inline-recursive-depth", + "The maximum depth of recursive inlining for inline functions", + 8) + +DEFPARAM (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO, + "max-inline-recursive-depth-auto", + "The maximum depth of recursive inlining for non-inline functions", + 8) + /* For languages that (still) use the RTL inliner, we can specify limits for the RTL inliner separately. The parameter here defines the maximum number of RTL instructions @@ -261,6 +281,13 @@ DEFPARAM(PARAM_MAX_CSE_PATH_LENGTH, "The maximum length of path considered in cse", 10) +/* The product of the next two is used to decide whether or not to + use .GLOBAL_VAR. See tree-dfa.c. */ +DEFPARAM(PARAM_GLOBAL_VAR_THRESHOLD, + "global-var-threshold", + "Given N calls and V call-clobbered vars in a function. Use .GLOBAL_VAR if NxV is larger than this limit", + 500000) + DEFPARAM(PARAM_MAX_CSELIB_MEMORY_LOCATIONS, "max-cselib-memory-locations", "The maximum memory locations recorded by cselib", @@ -293,6 +320,11 @@ DEFPARAM(PARAM_MAX_RELOAD_SEARCH_INSNS, "The maximum number of instructions to search backward when looking for equivalent reload", 100) +DEFPARAM(PARAM_MAX_ALIASED_VOPS, + "max-aliased-vops", + "The maximum number of virtual operands allowed to represent aliases before triggering alias grouping.", + 500) + DEFPARAM(PARAM_MAX_SCHED_REGION_BLOCKS, "max-sched-region-blocks", "The maximum number of blocks in a region to be considered for interblock scheduling", diff --git a/gcc/params.h b/gcc/params.h index fbdb63490c5..996f7a0b77e 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -110,4 +110,8 @@ typedef enum compiler_param PARAM_VALUE (PARAM_GCSE_AFTER_RELOAD_CRITICAL_FRACTION) #define MAX_UNROLLED_INSNS \ PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) +#define GLOBAL_VAR_THRESHOLD \ + PARAM_VALUE (PARAM_GLOBAL_VAR_THRESHOLD) +#define MAX_ALIASED_VOPS \ + PARAM_VALUE (PARAM_MAX_ALIASED_VOPS) #endif /* ! GCC_PARAMS_H */ diff --git a/gcc/passes.c b/gcc/passes.c index eaf4de5df41..43b46e2cae7 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -394,7 +394,8 @@ rest_of_decl_compilation (tree decl, } else { - error ("invalid register name `%s' for register variable", asmspec); + error ("%Hinvalid register name `%s' for register variable", + &DECL_SOURCE_LOCATION (decl), asmspec); DECL_REGISTER (decl) = 0; if (!top_level) expand_decl (decl); @@ -976,34 +977,6 @@ rest_of_handle_addressof (tree decl, rtx insns) close_dump_file (DFI_addressof, print_rtl, insns); } -/* We may have potential sibling or tail recursion sites. Select one - (of possibly multiple) methods of performing the call. */ -static void -rest_of_handle_sibling_calls (rtx insns) -{ - rtx insn; - optimize_sibling_and_tail_recursive_calls (); - - /* Recompute the CFG as sibling optimization clobbers it randomly. */ - free_bb_for_insn (); - find_exception_handler_labels (); - rebuild_jump_labels (insns); - find_basic_blocks (insns, max_reg_num (), dump_file); - - /* There is pass ordering problem - we must lower NOTE_INSN_PREDICTION - notes before simplifying cfg and we must do lowering after sibcall - that unhides parts of RTL chain and cleans up the CFG. - - Until sibcall is replaced by tree-level optimizer, lets just - sweep away the NOTE_INSN_PREDICTION notes that leaked out. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (GET_CODE (insn) == NOTE - && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION) - delete_insn (insn); - - close_dump_file (DFI_sibling, print_rtl, get_insns ()); -} - /* Perform jump bypassing and control flow optimizations. */ static void rest_of_handle_jump_bypass (tree decl, rtx insns) @@ -1031,155 +1004,6 @@ rest_of_handle_jump_bypass (tree decl, rtx insns) #endif } -/* Handle inlining of functions in rest_of_compilation. Return TRUE - if we must exit rest_of_compilation upon return. */ -static bool -rest_of_handle_inlining (tree decl) -{ - rtx insns; - int inlinable = 0; - tree parent; - const char *lose; - - /* If we are reconsidering an inline function at the end of - compilation, skip the stuff for making it inline. */ - if (cfun->rtl_inline_init) - return 0; - cfun->rtl_inline_init = 1; - - /* If this is nested inside an inlined external function, pretend - it was only declared. Since we cannot inline such functions, - generating code for this one is not only not necessary but will - confuse some debugging output writers. */ - for (parent = DECL_CONTEXT (current_function_decl); - parent != NULL_TREE; - parent = get_containing_scope (parent)) - if (TREE_CODE (parent) == FUNCTION_DECL - && DECL_INLINE (parent) && DECL_EXTERNAL (parent)) - { - DECL_INITIAL (decl) = 0; - return true; - } - else if (TYPE_P (parent)) - /* A function in a local class should be treated normally. */ - break; - - /* If requested, consider whether to make this function inline. */ - if ((DECL_INLINE (decl) && !flag_no_inline) - || flag_inline_functions) - { - timevar_push (TV_INTEGRATION); - lose = function_cannot_inline_p (decl); - timevar_pop (TV_INTEGRATION); - if (lose || ! optimize) - { - if (warn_inline && lose && DECL_INLINE (decl)) - { - char *msg = concat ("%J", lose, NULL); - warning (msg, decl); - free (msg); - } - DECL_ABSTRACT_ORIGIN (decl) = 0; - /* Don't really compile an extern inline function. - If we can't make it inline, pretend - it was only declared. */ - if (DECL_EXTERNAL (decl)) - { - DECL_INITIAL (decl) = 0; - return true; - } - } - else - inlinable = DECL_INLINE (decl) = 1; - } - - insns = get_insns (); - - /* Dump the rtl code if we are dumping rtl. */ - - if (open_dump_file (DFI_rtl, decl)) - { - if (DECL_STRUCT_FUNCTION (decl) - && DECL_STRUCT_FUNCTION (decl)->saved_for_inline) - fprintf (dump_file, ";; (integrable)\n\n"); - close_dump_file (DFI_rtl, print_rtl, insns); - } - - /* Convert from NOTE_INSN_EH_REGION style notes, and do other - sorts of eh initialization. Delay this until after the - initial rtl dump so that we can see the original nesting. */ - convert_from_eh_region_ranges (); - - /* If function is inline, and we don't yet know whether to - compile it by itself, defer decision till end of compilation. - wrapup_global_declarations will (indirectly) call - rest_of_compilation again for those functions that need to - be output. Also defer those functions that we are supposed - to defer. */ - - if (inlinable - || (DECL_INLINE (decl) - /* Egad. This RTL deferral test conflicts with Fortran assumptions - for unreferenced symbols. See g77.f-torture/execute/980520-1.f. - But removing this line from the check breaks all languages that - use the call graph to output symbols. This hard-coded check is - the least invasive work-around. */ - && (flag_inline_functions - || strcmp (lang_hooks.name, "GNU F77") == 0) - && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) - && ! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - && ! flag_keep_inline_functions) - || DECL_EXTERNAL (decl)))) - DECL_DEFER_OUTPUT (decl) = 1; - - if (DECL_INLINE (decl)) - /* DWARF wants separate debugging info for abstract and - concrete instances of all inline functions, including those - declared inline but not inlined, and those inlined even - though they weren't declared inline. Conveniently, that's - what DECL_INLINE means at this point. */ - (*debug_hooks->deferred_inline_function) (decl); - - if (DECL_DEFER_OUTPUT (decl)) - { - /* If -Wreturn-type, we have to do a bit of compilation. We just - want to call cleanup the cfg to figure out whether or not we can - fall off the end of the function; we do the minimum amount of - work necessary to make that safe. */ - if (warn_return_type) - { - int saved_optimize = optimize; - - optimize = 0; - rebuild_jump_labels (insns); - find_exception_handler_labels (); - find_basic_blocks (insns, max_reg_num (), dump_file); - cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_PRE_LOOP); - optimize = saved_optimize; - - /* CFG is no longer maintained up-to-date. */ - free_bb_for_insn (); - } - - set_nothrow_function_flags (); - if (current_function_nothrow) - /* Now we know that this can't throw; set the flag for the benefit - of other functions later in this translation unit. */ - TREE_NOTHROW (current_function_decl) = 1; - - timevar_push (TV_INTEGRATION); - save_for_inline (decl); - timevar_pop (TV_INTEGRATION); - DECL_STRUCT_FUNCTION (decl)->inlinable = inlinable; - return true; - } - - /* If specified extern inline but we aren't inlining it, we are - done. This goes for anything that gets here with DECL_EXTERNAL - set, not just things with DECL_INLINE. */ - return (bool) DECL_EXTERNAL (decl); -} - /* Try to identify useless null pointer tests and delete them. */ static void rest_of_handle_null_pointer (tree decl, rtx insns) @@ -1241,11 +1065,10 @@ rest_of_handle_life (tree decl, rtx insns) | (flag_thread_jumps ? CLEANUP_THREADING : 0)); timevar_pop (TV_FLOW); - if (warn_uninitialized) + if (extra_warnings) { - uninitialized_vars_warning (DECL_INITIAL (decl)); - if (extra_warnings) - setjmp_args_warning (); + setjmp_vars_warning (DECL_INITIAL (decl)); + setjmp_args_warning (); } if (optimize) @@ -1368,10 +1191,6 @@ rest_of_handle_gcse (tree decl, rtx insns) save_cfj = flag_cse_follow_jumps; flag_cse_skip_blocks = flag_cse_follow_jumps = 0; - /* Instantiate any remaining CONSTANT_P_RTX nodes. */ - if (current_function_calls_constant_p) - purge_builtin_constant_p (); - /* If -fexpensive-optimizations, re-run CSE to clean up things done by gcse. */ if (flag_expensive_optimizations) @@ -1552,20 +1371,31 @@ rest_of_compilation (tree decl) have been run to re-initialize it. */ cse_not_expected = ! optimize; - /* First, make sure that NOTE_BLOCK is set correctly for each - NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END note. */ - if (!cfun->x_whole_function_mode_p) - identify_blocks (); - - /* In function-at-a-time mode, we do not attempt to keep the BLOCK - tree in sensible shape. So, we just recalculate it here. */ - if (cfun->x_whole_function_mode_p) - reorder_blocks (); + if (!cfun->dont_emit_block_notes) + { + /* First, make sure that NOTE_BLOCK is set correctly for each + NOTE_INSN_BLOCK_BEG/NOTE_INSN_BLOCK_END note. */ + if (!cfun->x_whole_function_mode_p) + identify_blocks (); + + /* In function-at-a-time mode, we do not attempt to keep the BLOCK + tree in sensible shape. So, we just recalculate it here. */ + if (cfun->x_whole_function_mode_p) + reorder_blocks (); + } + else + finalize_block_changes (); init_flow (); - if (rest_of_handle_inlining (decl)) - goto exit_rest_of_compilation; + /* Dump the rtl code if we are dumping rtl. */ + if (open_dump_file (DFI_rtl, decl)) + close_dump_file (DFI_rtl, print_rtl, get_insns ()); + + /* Convert from NOTE_INSN_EH_REGION style notes, and do other + sorts of eh initialization. Delay this until after the + initial rtl dump so that we can see the original nesting. */ + convert_from_eh_region_ranges (); /* If we're emitting a nested function, make sure its parent gets emitted as well. Doing otherwise confuses debug info. */ @@ -1588,7 +1418,8 @@ rest_of_compilation (tree decl) over the instruction sequence faster, and allow the garbage collector to reclaim the memory used by the notes. */ remove_unnecessary_notes (); - reorder_blocks (); + if (!cfun->dont_emit_block_notes) + reorder_blocks (); ggc_collect (); @@ -1631,19 +1462,11 @@ rest_of_compilation (tree decl) timevar_pop (TV_BRANCH_PROB); } - if (flag_optimize_sibling_calls) - rest_of_handle_sibling_calls (insns); - - /* We have to issue these warnings now already, because CFG cleanups - further down may destroy the required information. However, this - must be done after the sibcall optimization pass because the barrier - emitted for noreturn calls that are candidate for the optimization - is folded into the CALL_PLACEHOLDER until after this pass, so the - CFG is inaccurate. */ - check_function_return_warnings (); - timevar_pop (TV_JUMP); + if (cfun->tail_call_emit) + fixup_tail_calls (); + insn_locators_initialize (); /* Complete generation of exception handling code. */ if (doing_eh (0)) @@ -1708,12 +1531,8 @@ rest_of_compilation (tree decl) cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP | (flag_thread_jumps ? CLEANUP_THREADING : 0)); - if (optimize) - { - free_bb_for_insn (); - copy_loop_headers (insns); - find_basic_blocks (insns, max_reg_num (), dump_file); - } + create_loop_notes (); + purge_line_number_notes (insns); timevar_pop (TV_JUMP); @@ -1766,9 +1585,12 @@ rest_of_compilation (tree decl) rest_of_handle_cfg (decl, insns); - if (optimize > 0 - || profile_arc_flag || flag_test_coverage || flag_branch_probabilities) + if (!flag_tree_based_profiling + && (optimize > 0 || profile_arc_flag + || flag_test_coverage || flag_branch_probabilities)) { + rtl_register_profile_hooks (); + rtl_register_value_prof_hooks (); rest_of_handle_branch_prob (decl, insns); if (flag_branch_probabilities diff --git a/gcc/predict.c b/gcc/predict.c index 669760bf41f..271698bd2d1 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -53,6 +53,11 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "target.h" #include "loop.h" #include "cfgloop.h" +#include "tree-flow.h" +#include "ggc.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "timevar.h" /* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE, 1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX. */ @@ -65,9 +70,8 @@ static sreal real_zero, real_one, real_almost_one, real_br_prob_base, #define PROB_VERY_LIKELY (REG_BR_PROB_BASE - PROB_VERY_UNLIKELY) #define PROB_ALWAYS (REG_BR_PROB_BASE) -static bool predicted_by_p (basic_block, enum br_predictor); static void combine_predictions_for_insn (rtx, basic_block); -static void dump_prediction (enum br_predictor, int, basic_block, int); +static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int); static void estimate_loops_at_level (struct loop *loop); static void propagate_freq (struct loop *); static void estimate_bb_frequencies (struct loops *); @@ -148,8 +152,8 @@ probably_never_executed_bb_p (basic_block bb) /* Return true if the one of outgoing edges is already predicted by PREDICTOR. */ -static bool -predicted_by_p (basic_block bb, enum br_predictor predictor) +bool +rtl_predicted_by_p (basic_block bb, enum br_predictor predictor) { rtx note; if (!INSN_P (BB_END (bb))) @@ -161,6 +165,19 @@ predicted_by_p (basic_block bb, enum br_predictor predictor) return false; } +/* Return true if the one of outgoing edges is already predicted by + PREDICTOR. */ + +bool +tree_predicted_by_p (basic_block bb, enum br_predictor predictor) +{ + struct edge_prediction *i = bb_ann (bb)->predictions; + for (i = bb_ann (bb)->predictions; i; i = i->next) + if (i->predictor == predictor) + return true; + return false; +} + void predict_insn (rtx insn, enum br_predictor predictor, int probability) { @@ -194,7 +211,7 @@ predict_insn_def (rtx insn, enum br_predictor predictor, /* Predict edge E with given probability if possible. */ void -predict_edge (edge e, enum br_predictor predictor, int probability) +rtl_predict_edge (edge e, enum br_predictor predictor, int probability) { rtx last_insn; last_insn = BB_END (e->src); @@ -211,6 +228,19 @@ predict_edge (edge e, enum br_predictor predictor, int probability) predict_insn (last_insn, predictor, probability); } +/* Predict edge E with the given PROBABILITY. */ +void +tree_predict_edge (edge e, enum br_predictor predictor, int probability) +{ + struct edge_prediction *i = ggc_alloc (sizeof (struct edge_prediction)); + + i->next = bb_ann (e->src)->predictions; + bb_ann (e->src)->predictions = i; + i->probability = probability; + i->predictor = predictor; + i->edge = e; +} + /* Return true when we can store prediction on insn INSN. At the moment we represent predictions only on conditional jumps, not at computed jump or other complicated cases. */ @@ -255,34 +285,34 @@ invert_br_probabilities (rtx insn) /* Dump information about the branch prediction to the output file. */ static void -dump_prediction (enum br_predictor predictor, int probability, +dump_prediction (FILE *file, enum br_predictor predictor, int probability, basic_block bb, int used) { edge e = bb->succ; - if (!dump_file) + if (!file) return; while (e && (e->flags & EDGE_FALLTHRU)) e = e->succ_next; - fprintf (dump_file, " %s heuristics%s: %.1f%%", + fprintf (file, " %s heuristics%s: %.1f%%", predictor_info[predictor].name, used ? "" : " (ignored)", probability * 100.0 / REG_BR_PROB_BASE); if (bb->count) { - fprintf (dump_file, " exec "); - fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, bb->count); + fprintf (file, " exec "); + fprintf (file, HOST_WIDEST_INT_PRINT_DEC, bb->count); if (e) { - fprintf (dump_file, " hit "); - fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, e->count); - fprintf (dump_file, " (%.1f%%)", e->count * 100.0 / bb->count); + fprintf (file, " hit "); + fprintf (file, HOST_WIDEST_INT_PRINT_DEC, e->count); + fprintf (file, " (%.1f%%)", e->count * 100.0 / bb->count); } } - fprintf (dump_file, "\n"); + fprintf (file, "\n"); } /* Combine all REG_BR_PRED notes into single probability and attach REG_BR_PROB @@ -306,8 +336,7 @@ combine_predictions_for_insn (rtx insn, basic_block bb) bb->index); /* We implement "first match" heuristics and use probability guessed - by predictor with smallest index. In the future we will use better - probability combination techniques. */ + by predictor with smallest index. */ for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) if (REG_NOTE_KIND (note) == REG_BR_PRED) { @@ -339,16 +368,19 @@ combine_predictions_for_insn (rtx insn, basic_block bb) first_match = true; if (!found) - dump_prediction (PRED_NO_PREDICTION, combined_probability, bb, true); + dump_prediction (dump_file, PRED_NO_PREDICTION, + combined_probability, bb, true); else { - dump_prediction (PRED_DS_THEORY, combined_probability, bb, !first_match); - dump_prediction (PRED_FIRST_MATCH, best_probability, bb, first_match); + dump_prediction (dump_file, PRED_DS_THEORY, combined_probability, + bb, !first_match); + dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability, + bb, first_match); } if (first_match) combined_probability = best_probability; - dump_prediction (PRED_COMBINED, combined_probability, bb, true); + dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb, true); while (*pnote) { @@ -357,7 +389,7 @@ combine_predictions_for_insn (rtx insn, basic_block bb) int predictor = INTVAL (XEXP (XEXP (*pnote, 0), 0)); int probability = INTVAL (XEXP (XEXP (*pnote, 0), 1)); - dump_prediction (predictor, probability, bb, + dump_prediction (dump_file, predictor, probability, bb, !first_match || best_predictor == predictor); *pnote = XEXP (*pnote, 1); } @@ -382,21 +414,126 @@ combine_predictions_for_insn (rtx insn, basic_block bb) } } -/* Statically estimate the probability that a branch will be taken. - ??? In the next revision there will be a number of other predictors added - from the above references. Further, each heuristic will be factored out - into its own function for clarity (and to facilitate the combination of - predictions). */ +/* Combine predictions into single probability and store them into CFG. + Remove now useless prediction entries. */ -void -estimate_probability (struct loops *loops_info) +static void +combine_predictions_for_bb (FILE *file, basic_block bb) { - basic_block bb; - unsigned i; + int best_probability = PROB_EVEN; + int best_predictor = END_PREDICTORS; + int combined_probability = REG_BR_PROB_BASE / 2; + int d; + bool first_match = false; + bool found = false; + struct edge_prediction *pred; + int nedges = 0; + edge e, first = NULL, second = NULL; - connect_infinite_loops_to_exit (); - calculate_dominance_info (CDI_DOMINATORS); - calculate_dominance_info (CDI_POST_DOMINATORS); + for (e = bb->succ; e; e = e->succ_next) + if (!(e->flags & (EDGE_EH | EDGE_FAKE))) + { + nedges ++; + if (first && !second) + second = e; + if (!first) + first = e; + } + + /* When there is no successor or only one choice, prediction is easy. + + We are lazy for now and predict only basic blocks with two outgoing + edges. It is possible to predict generic case too, but we have to + ignore first match heuristics and do more involved combining. Implement + this later. */ + if (nedges != 2) + { + for (e = bb->succ; e; e = e->succ_next) + if (!(e->flags & (EDGE_EH | EDGE_FAKE))) + e->probability = (REG_BR_PROB_BASE + nedges / 2) / nedges; + else + e->probability = 0; + bb_ann (bb)->predictions = NULL; + if (file) + fprintf (file, "%i edges in bb %i predicted to even probabilities\n", + nedges, bb->index); + return; + } + + if (file) + fprintf (file, "Predictions for bb %i\n", bb->index); + + /* We implement "first match" heuristics and use probability guessed + by predictor with smallest index. */ + for (pred = bb_ann (bb)->predictions; pred; pred = pred->next) + { + int predictor = pred->predictor; + int probability = pred->probability; + + if (pred->edge != first) + probability = REG_BR_PROB_BASE - probability; + + found = true; + if (best_predictor > predictor) + best_probability = probability, best_predictor = predictor; + + d = (combined_probability * probability + + (REG_BR_PROB_BASE - combined_probability) + * (REG_BR_PROB_BASE - probability)); + + /* Use FP math to avoid overflows of 32bit integers. */ + if (d == 0) + /* If one probability is 0% and one 100%, avoid division by zero. */ + combined_probability = REG_BR_PROB_BASE / 2; + else + combined_probability = (((double) combined_probability) * probability + * REG_BR_PROB_BASE / d + 0.5); + } + + /* Decide which heuristic to use. In case we didn't match anything, + use no_prediction heuristic, in case we did match, use either + first match or Dempster-Shaffer theory depending on the flags. */ + + if (predictor_info [best_predictor].flags & PRED_FLAG_FIRST_MATCH) + first_match = true; + + if (!found) + dump_prediction (file, PRED_NO_PREDICTION, combined_probability, bb, true); + else + { + dump_prediction (file, PRED_DS_THEORY, combined_probability, bb, + !first_match); + dump_prediction (file, PRED_FIRST_MATCH, best_probability, bb, + first_match); + } + + if (first_match) + combined_probability = best_probability; + dump_prediction (file, PRED_COMBINED, combined_probability, bb, true); + + for (pred = bb_ann (bb)->predictions; pred; pred = pred->next) + { + int predictor = pred->predictor; + int probability = pred->probability; + + if (pred->edge != bb->succ) + probability = REG_BR_PROB_BASE - probability; + dump_prediction (file, predictor, probability, bb, + !first_match || best_predictor == predictor); + } + bb_ann (bb)->predictions = NULL; + + first->probability = combined_probability; + second->probability = REG_BR_PROB_BASE - combined_probability; +} + +/* Predict edge probabilities by exploiting loop structure. + When SIMPLELOOPS is set, attempt to count number of iterations by analyzing + RTL. */ +static void +predict_loops (struct loops *loops_info, bool simpleloops) +{ + unsigned i; /* Try to predict out blocks in a loop that are not part of a natural loop. */ @@ -412,27 +549,31 @@ estimate_probability (struct loops *loops_info) flow_loop_scan (loop, LOOP_EXIT_EDGES); exits = loop->num_exits; - iv_analysis_loop_init (loop); - find_simple_exit (loop, &desc); - - if (desc.simple_p && desc.const_iter) + if (simpleloops) { - int prob; - niter = desc.niter + 1; - if (niter == 0) /* We might overflow here. */ - niter = desc.niter; - - prob = (REG_BR_PROB_BASE - - (REG_BR_PROB_BASE + niter /2) / niter); - /* Branch prediction algorithm gives 0 frequency for everything - after the end of loop for loop having 0 probability to finish. */ - if (prob == REG_BR_PROB_BASE) - prob = REG_BR_PROB_BASE - 1; - predict_edge (desc.in_edge, PRED_LOOP_ITERATIONS, - prob); + iv_analysis_loop_init (loop); + find_simple_exit (loop, &desc); + + if (desc.simple_p && desc.const_iter) + { + int prob; + niter = desc.niter + 1; + if (niter == 0) /* We might overflow here. */ + niter = desc.niter; + + prob = (REG_BR_PROB_BASE + - (REG_BR_PROB_BASE + niter /2) / niter); + /* Branch prediction algorithm gives 0 frequency for everything + after the end of loop for loop having 0 probability to finish. */ + if (prob == REG_BR_PROB_BASE) + prob = REG_BR_PROB_BASE - 1; + predict_edge (desc.in_edge, PRED_LOOP_ITERATIONS, + prob); + } } bbs = get_loop_body (loop); + for (j = 0; j < loop->num_nodes; j++) { int header_found = 0; @@ -444,7 +585,7 @@ estimate_probability (struct loops *loops_info) statements construct loops via "non-loop" constructs in the source language and are better to be handled separately. */ - if (!can_predict_insn_p (BB_END (bb)) + if ((simpleloops && !can_predict_insn_p (BB_END (bb))) || predicted_by_p (bb, PRED_CONTINUE)) continue; @@ -474,6 +615,22 @@ estimate_probability (struct loops *loops_info) /* Free basic blocks from get_loop_body. */ free (bbs); } +} + +/* Statically estimate the probability that a branch will be taken and produce + estimated profile. When profile feedback is present never executed portions + of function gets estimated. */ + +void +estimate_probability (struct loops *loops_info) +{ + basic_block bb; + + connect_infinite_loops_to_exit (); + calculate_dominance_info (CDI_DOMINATORS); + calculate_dominance_info (CDI_POST_DOMINATORS); + + predict_loops (loops_info, true); iv_analysis_done (); @@ -622,10 +779,216 @@ estimate_probability (struct loops *loops_info) && bb->succ->succ_next != NULL) combine_predictions_for_insn (BB_END (bb), bb); + remove_fake_edges (); + /* Fill in the probability values in flowgraph based on the REG_BR_PROB + notes. */ + FOR_EACH_BB (bb) + { + rtx last_insn = BB_END (bb); + + if (!can_predict_insn_p (last_insn)) + { + /* We can predict only conditional jumps at the moment. + Expect each edge to be equally probable. + ?? In the future we want to make abnormal edges improbable. */ + int nedges = 0; + edge e; + + for (e = bb->succ; e; e = e->succ_next) + { + nedges++; + if (e->probability != 0) + break; + } + if (!e) + for (e = bb->succ; e; e = e->succ_next) + e->probability = (REG_BR_PROB_BASE + nedges / 2) / nedges; + } + } + estimate_bb_frequencies (loops_info); free_dominance_info (CDI_POST_DOMINATORS); +} + + +/* Predict using opcode of the last statement in basic block. */ +static void +tree_predict_by_opcode (basic_block bb) +{ + tree stmt = last_stmt (bb); + edge then_edge; + tree cond; + tree op0; + tree type; + + if (!stmt || TREE_CODE (stmt) != COND_EXPR) + return; + for (then_edge = bb->succ; then_edge; then_edge = then_edge->succ_next) + if (then_edge->flags & EDGE_TRUE_VALUE) + break; + cond = TREE_OPERAND (stmt, 0); + if (TREE_CODE_CLASS (TREE_CODE (cond)) != '<') + return; + op0 = TREE_OPERAND (cond, 0); + type = TREE_TYPE (op0); + /* Try "pointer heuristic." + A comparison ptr == 0 is predicted as false. + Similarly, a comparison ptr1 == ptr2 is predicted as false. */ + if (POINTER_TYPE_P (type)) + { + if (TREE_CODE (cond) == EQ_EXPR) + predict_edge_def (then_edge, PRED_TREE_POINTER, NOT_TAKEN); + else if (TREE_CODE (cond) == NE_EXPR) + predict_edge_def (then_edge, PRED_TREE_POINTER, TAKEN); + } + else + + /* Try "opcode heuristic." + EQ tests are usually false and NE tests are usually true. Also, + most quantities are positive, so we can make the appropriate guesses + about signed comparisons against zero. */ + switch (TREE_CODE (cond)) + { + case EQ_EXPR: + case UNEQ_EXPR: + /* Floating point comparisons appears to behave in a very + unpredictable way because of special role of = tests in + FP code. */ + if (FLOAT_TYPE_P (type)) + ; + /* Comparisons with 0 are often used for booleans and there is + nothing useful to predict about them. */ + else if (integer_zerop (op0) + || integer_zerop (TREE_OPERAND (cond, 1))) + ; + else + predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, NOT_TAKEN); + break; + + case NE_EXPR: + /* Floating point comparisons appears to behave in a very + unpredictable way because of special role of = tests in + FP code. */ + if (FLOAT_TYPE_P (type)) + ; + /* Comparisons with 0 are often used for booleans and there is + nothing useful to predict about them. */ + else if (integer_zerop (op0) + || integer_zerop (TREE_OPERAND (cond, 1))) + ; + else + predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, TAKEN); + break; + + case ORDERED_EXPR: + predict_edge_def (then_edge, PRED_TREE_FPOPCODE, TAKEN); + break; + + case UNORDERED_EXPR: + predict_edge_def (then_edge, PRED_TREE_FPOPCODE, NOT_TAKEN); + break; + + case LE_EXPR: + case LT_EXPR: + if (integer_zerop (TREE_OPERAND (cond, 1)) + || integer_onep (TREE_OPERAND (cond, 1)) + || integer_all_onesp (TREE_OPERAND (cond, 1)) + || real_zerop (TREE_OPERAND (cond, 1)) + || real_onep (TREE_OPERAND (cond, 1)) + || real_minus_onep (TREE_OPERAND (cond, 1))) + predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, NOT_TAKEN); + break; + + case GE_EXPR: + case GT_EXPR: + if (integer_zerop (TREE_OPERAND (cond, 1)) + || integer_onep (TREE_OPERAND (cond, 1)) + || integer_all_onesp (TREE_OPERAND (cond, 1)) + || real_zerop (TREE_OPERAND (cond, 1)) + || real_onep (TREE_OPERAND (cond, 1)) + || real_minus_onep (TREE_OPERAND (cond, 1))) + predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, TAKEN); + break; + + default: + break; + } +} + +/* Predict branch probabilities and estimate profile of the tree CFG. */ +static void +tree_estimate_probability (void) +{ + basic_block bb; + struct loops loops_info; + + flow_loops_find (&loops_info, LOOP_TREE); + if (dump_file && (dump_flags & TDF_DETAILS)) + flow_loops_dump (&loops_info, dump_file, NULL, 0); + + connect_infinite_loops_to_exit (); + calculate_dominance_info (CDI_DOMINATORS); + calculate_dominance_info (CDI_POST_DOMINATORS); + + predict_loops (&loops_info, false); + + FOR_EACH_BB (bb) + { + edge e; + + for (e = bb->succ; e; e = e->succ_next) + { + /* Predict early returns to be probable, as we've already taken + care for error returns and other are often used for fast paths + trought function. */ + if ((e->dest == EXIT_BLOCK_PTR + || (e->dest->succ && !e->dest->succ->succ_next + && e->dest->succ->dest == EXIT_BLOCK_PTR)) + && !predicted_by_p (bb, PRED_NULL_RETURN) + && !predicted_by_p (bb, PRED_CONST_RETURN) + && !predicted_by_p (bb, PRED_NEGATIVE_RETURN) + && !last_basic_block_p (e->dest)) + predict_edge_def (e, PRED_EARLY_RETURN, TAKEN); + + /* Look for block we are guarding (ie we dominate it, + but it doesn't postdominate us). */ + if (e->dest != EXIT_BLOCK_PTR && e->dest != bb + && dominated_by_p (CDI_DOMINATORS, e->dest, e->src) + && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e->dest)) + { + block_stmt_iterator bi; + + /* The call heuristic claims that a guarded function call + is improbable. This is because such calls are often used + to signal exceptional situations such as printing error + messages. */ + for (bi = bsi_start (e->dest); !bsi_end_p (bi); + bsi_next (&bi)) + { + tree stmt = bsi_stmt (bi); + if ((TREE_CODE (stmt) == CALL_EXPR + || (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)) + /* Constant and pure calls are hardly used to signalize + something exceptional. */ + && TREE_SIDE_EFFECTS (stmt)) + { + predict_edge_def (e, PRED_CALL, NOT_TAKEN); + break; + } + } + } + } + tree_predict_by_opcode (bb); + } + FOR_EACH_BB (bb) + combine_predictions_for_bb (dump_file, bb); + estimate_bb_frequencies (&loops_info); + free_dominance_info (CDI_POST_DOMINATORS); remove_fake_edges (); - estimate_bb_frequencies (loops_info); + flow_loops_free (&loops_info); + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_tree_cfg (dump_file, dump_flags); } /* __builtin_expect dropped tokens into the insn stream describing expected @@ -1138,31 +1501,6 @@ estimate_bb_frequencies (struct loops *loops) } mark_dfs_back_edges (); - /* Fill in the probability values in flowgraph based on the REG_BR_PROB - notes. */ - FOR_EACH_BB (bb) - { - rtx last_insn = BB_END (bb); - - if (!can_predict_insn_p (last_insn)) - { - /* We can predict only conditional jumps at the moment. - Expect each edge to be equally probable. - ?? In the future we want to make abnormal edges improbable. */ - int nedges = 0; - edge e; - - for (e = bb->succ; e; e = e->succ_next) - { - nedges++; - if (e->probability != 0) - break; - } - if (!e) - for (e = bb->succ; e; e = e->succ_next) - e->probability = (REG_BR_PROB_BASE + nedges / 2) / nedges; - } - } ENTRY_BLOCK_PTR->succ->probability = REG_BR_PROB_BASE; @@ -1251,3 +1589,20 @@ choose_function_section (void) build_string (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME), UNLIKELY_EXECUTED_TEXT_SECTION_NAME); } + + +struct tree_opt_pass pass_profile = +{ + "profile", /* name */ + NULL, /* gate */ + tree_estimate_probability, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_BRANCH_PROB, /* tv_id */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ +}; diff --git a/gcc/predict.def b/gcc/predict.def index 25c51025e31..836d853b379 100644 --- a/gcc/predict.def +++ b/gcc/predict.def @@ -89,11 +89,15 @@ DEF_PREDICTOR (PRED_LOOP_HEADER, "loop header", HITRATE (64), 0) /* Pointers are usually not NULL. */ DEF_PREDICTOR (PRED_POINTER, "pointer", HITRATE (81), 0) +DEF_PREDICTOR (PRED_TREE_POINTER, "pointer (on trees)", HITRATE (81), 0) /* NE is probable, EQ not etc... */ DEF_PREDICTOR (PRED_OPCODE_POSITIVE, "opcode values positive", HITRATE (79), 0) DEF_PREDICTOR (PRED_OPCODE_NONEQUAL, "opcode values nonequal", HITRATE (71), 0) DEF_PREDICTOR (PRED_FPOPCODE, "fp_opcode", HITRATE (90), 0) +DEF_PREDICTOR (PRED_TREE_OPCODE_POSITIVE, "opcode values positive (on trees)", HITRATE (79), 0) +DEF_PREDICTOR (PRED_TREE_OPCODE_NONEQUAL, "opcode values nonequal (on trees)", HITRATE (71), 0) +DEF_PREDICTOR (PRED_TREE_FPOPCODE, "fp_opcode (on trees)", HITRATE (90), 0) /* Branch guarding call is probably taken. */ DEF_PREDICTOR (PRED_CALL, "call", HITRATE (70), 0) diff --git a/gcc/predict.h b/gcc/predict.h index d0741dc704d..16817f9b5b6 100644 --- a/gcc/predict.h +++ b/gcc/predict.h @@ -18,6 +18,9 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef GCC_PREDICT_H +#define GCC_PREDICT_H + #define DEF_PREDICTOR(ENUM, NAME, HITRATE, FLAGS) ENUM, enum br_predictor { @@ -39,8 +42,4 @@ enum prediction extern void predict_insn_def (rtx, enum br_predictor, enum prediction); extern void predict_insn (rtx, enum br_predictor, int); -/* Avoid unneeded dependency on basic_block.h. */ -#ifdef BASIC_BLOCK -extern void predict_edge (edge, enum br_predictor, int); -extern void predict_edge_def (edge, enum br_predictor, enum prediction); -#endif +#endif /* GCC_PREDICT_H */ diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c index bb1e72fbcd1..46cae27504c 100644 --- a/gcc/pretty-print.c +++ b/gcc/pretty-print.c @@ -91,7 +91,7 @@ pp_clear_state (pretty_printer *pp) } /* Flush the formatted text of PRETTY-PRINTER onto the attached stream. */ -static inline void +void pp_write_text_to_stream (pretty_printer *pp) { const char *text = pp_formatted_text (pp); diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h index 28179381314..8c568a42f4d 100644 --- a/gcc/pretty-print.h +++ b/gcc/pretty-print.h @@ -258,6 +258,7 @@ extern void pp_base_indent (pretty_printer *); extern void pp_base_newline (pretty_printer *); extern void pp_base_character (pretty_printer *, int); extern void pp_base_string (pretty_printer *, const char *); +extern void pp_write_text_to_stream (pretty_printer *pp); extern void pp_base_maybe_space (pretty_printer *); #endif /* GCC_PRETTY_PRINT_H */ diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index 6562afcc524..66f0a01f063 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -153,9 +153,6 @@ print_rtx (rtx in_rtx) if (RTX_FLAG (in_rtx, unchanging)) fputs ("/u", outfile); - if (RTX_FLAG (in_rtx, integrated)) - fputs ("/i", outfile); - if (RTX_FLAG (in_rtx, frame_related)) fputs ("/f", outfile); @@ -165,6 +162,9 @@ print_rtx (rtx in_rtx) if (RTX_FLAG (in_rtx, call)) fputs ("/c", outfile); + if (RTX_FLAG (in_rtx, return_val)) + fputs ("/i", outfile); + if (GET_MODE (in_rtx) != VOIDmode) { /* Print REG_NOTE names for EXPR_LIST and INSN_LIST. */ diff --git a/gcc/print-tree.c b/gcc/print-tree.c index 9dd9aaa2cd6..fd90b181f46 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -252,6 +252,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent) fputs (" readonly", file); if (!TYPE_P (node) && TREE_CONSTANT (node)) fputs (" constant", file); + if (TREE_INVARIANT (node)) + fputs (" invariant", file); if (TREE_ADDRESSABLE (node)) fputs (" addressable", file); if (TREE_THIS_VOLATILE (node)) @@ -272,6 +274,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent) fputs (" static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); + if (TREE_VISITED (node)) + fputs (" visited", file); if (TREE_LANG_FLAG_0 (node)) fputs (" tree_0", file); if (TREE_LANG_FLAG_1 (node)) @@ -619,14 +623,6 @@ print_node (FILE *file, const char *prefix, tree node, int indent) } } - if (TREE_CODE (node) == EXPR_WITH_FILE_LOCATION) - { - indent_to (file, indent+4); - fprintf (file, "%s:%d:%d", - (EXPR_WFL_FILENAME_NODE (node ) ? - EXPR_WFL_FILENAME (node) : "(no file info)"), - EXPR_WFL_LINENO (node), EXPR_WFL_COLNO (node)); - } print_node (file, "chain", TREE_CHAIN (node), indent + 4); break; @@ -746,5 +742,13 @@ print_node (FILE *file, const char *prefix, tree node, int indent) break; } + if (EXPR_HAS_LOCATION (node)) + { + indent_to (file, indent+4); + fprintf (file, "%s:%d", + EXPR_FILENAME (node), + EXPR_LINENO (node)); + } + fprintf (file, ">"); } diff --git a/gcc/profile.c b/gcc/profile.c index 7095d1bcc43..0468a0f8284 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -39,7 +39,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA edges must be on the spanning tree. We also attempt to place EDGE_CRITICAL edges on the spanning tree. - The auxiliary file generated is .bbg. The format is + The auxiliary files generated are .gcno (at compile time) + and .gcda (at run time). The format is described in full in gcov-io.h. */ /* ??? Register allocation should use basic block execution counts to @@ -62,6 +63,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "coverage.h" #include "value-prof.h" #include "tree.h" +#include "cfghooks.h" +#include "tree-flow.h" + +/* Hooks for profiling. */ +static struct profile_hooks* profile_hooks; + +/* File for profiling debug output. */ +static inline FILE* +profile_dump_file (void) { + return profile_hooks->profile_dump_file (); +} /* Additional information about the edges we need. */ struct edge_info { @@ -106,14 +118,6 @@ static int total_num_branches; /* Forward declarations. */ static void find_spanning_tree (struct edge_list *); -static rtx gen_edge_profiler (int); -static rtx gen_interval_profiler (struct histogram_value *, unsigned, - unsigned); -static rtx gen_pow2_profiler (struct histogram_value *, unsigned, unsigned); -static rtx gen_one_value_profiler (struct histogram_value *, unsigned, - unsigned); -static rtx gen_const_delta_profiler (struct histogram_value *, unsigned, - unsigned); static unsigned instrument_edges (struct edge_list *); static void instrument_values (unsigned, struct histogram_value *); static void compute_branch_probabilities (void); @@ -147,17 +151,13 @@ instrument_edges (struct edge_list *el) if (!inf->ignore && !inf->on_tree) { - rtx edge_profile; - if (e->flags & EDGE_ABNORMAL) abort (); if (dump_file) fprintf (dump_file, "Edge %d to %d instrumented%s\n", e->src->index, e->dest->index, EDGE_CRITICAL_P (e) ? " (and split)" : ""); - edge_profile = gen_edge_profiler (num_instr_edges++); - insert_insn_on_edge (edge_profile, e); - rebuild_jump_labels (e->insns); + (profile_hooks->gen_edge_profiler) (num_instr_edges++, e); } } } @@ -172,16 +172,12 @@ instrument_edges (struct edge_list *el) static void instrument_values (unsigned n_values, struct histogram_value *values) { - rtx sequence; unsigned i, t; - edge e; /* Emit code to generate the histograms before the insns. */ for (i = 0; i < n_values; i++) { - e = split_block (BLOCK_FOR_INSN (values[i].insn), - PREV_INSN (values[i].insn)); switch (values[i].type) { case HIST_TYPE_INTERVAL: @@ -209,26 +205,24 @@ instrument_values (unsigned n_values, struct histogram_value *values) switch (values[i].type) { case HIST_TYPE_INTERVAL: - sequence = gen_interval_profiler (values + i, t, 0); + (profile_hooks->gen_interval_profiler) (values + i, t, 0); break; case HIST_TYPE_POW2: - sequence = gen_pow2_profiler (values + i, t, 0); + (profile_hooks->gen_pow2_profiler) (values + i, t, 0); break; case HIST_TYPE_SINGLE_VALUE: - sequence = gen_one_value_profiler (values + i, t, 0); + (profile_hooks->gen_one_value_profiler) (values + i, t, 0); break; case HIST_TYPE_CONST_DELTA: - sequence = gen_const_delta_profiler (values + i, t, 0); + (profile_hooks->gen_const_delta_profiler) (values + i, t, 0); break; default: abort (); } - - safe_insert_insn_on_edge (sequence, e); } } @@ -512,13 +506,7 @@ compute_branch_probabilities (void) || (e->count > bb->count && e->dest != EXIT_BLOCK_PTR)) { - rtx insn = BB_END (bb); - - while (GET_CODE (insn) != CALL_INSN - && insn != BB_HEAD (bb) - && keep_with_call_p (insn)) - insn = PREV_INSN (insn); - if (GET_CODE (insn) == CALL_INSN) + if (block_ends_with_call_p (bb)) e->count = e->count < 0 ? 0 : bb->count; } if (e->count < 0 || e->count > bb->count) @@ -534,7 +522,7 @@ compute_branch_probabilities (void) for (e = bb->succ; e; e = e->succ_next) e->probability = (e->count * REG_BR_PROB_BASE + bb->count / 2) / bb->count; if (bb->index >= 0 - && any_condjump_p (BB_END (bb)) + && block_ends_with_condjump_p (bb) && bb->succ->succ_next) { int prob; @@ -554,15 +542,19 @@ compute_branch_probabilities (void) index = 19; hist_br_prob[index]++; - note = find_reg_note (BB_END (bb), REG_BR_PROB, 0); - /* There may be already note put by some other pass, such - as builtin_expect expander. */ - if (note) - XEXP (note, 0) = GEN_INT (prob); - else - REG_NOTES (BB_END (bb)) - = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob), - REG_NOTES (BB_END (bb))); + /* Do this for RTL only. */ + if (!ir_type ()) + { + note = find_reg_note (BB_END (bb), REG_BR_PROB, 0); + /* There may be already note put by some other pass, such + as builtin_expect expander. */ + if (note) + XEXP (note, 0) = GEN_INT (prob); + else + REG_NOTES (BB_END (bb)) + = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob), + REG_NOTES (BB_END (bb))); + } num_branches++; } } @@ -594,7 +586,7 @@ compute_branch_probabilities (void) e->probability = REG_BR_PROB_BASE / total; } if (bb->index >= 0 - && any_condjump_p (BB_END (bb)) + && block_ends_with_condjump_p (bb) && bb->succ->succ_next) num_branches++, num_never_executed; } @@ -664,15 +656,21 @@ compute_value_histograms (unsigned n_values, struct histogram_value *values) rtx hist_list = NULL_RTX; t = (int) (values[i].type); - aact_count = act_count[t]; - act_count[t] += values[i].n_counters; - for (j = values[i].n_counters; j > 0; j--) - hist_list = alloc_EXPR_LIST (0, GEN_INT (aact_count[j - 1]), hist_list); - hist_list = alloc_EXPR_LIST (0, copy_rtx (values[i].value), hist_list); - hist_list = alloc_EXPR_LIST (0, GEN_INT (values[i].type), hist_list); - REG_NOTES (values[i].insn) = - alloc_EXPR_LIST (REG_VALUE_PROFILE, hist_list, - REG_NOTES (values[i].insn)); + /* FIXME: make this work for trees. */ + if (!ir_type ()) + { + aact_count = act_count[t]; + act_count[t] += values[i].n_counters; + for (j = values[i].n_counters; j > 0; j--) + hist_list = alloc_EXPR_LIST (0, GEN_INT (aact_count[j - 1]), + hist_list); + hist_list = alloc_EXPR_LIST (0, + copy_rtx ((rtx)values[i].value), hist_list); + hist_list = alloc_EXPR_LIST (0, GEN_INT (values[i].type), hist_list); + REG_NOTES ((rtx)values[i].insn) = + alloc_EXPR_LIST (REG_VALUE_PROFILE, hist_list, + REG_NOTES ((rtx)values[i].insn)); + } } for (t = 0; t < GCOV_N_VALUE_COUNTERS; t++) @@ -885,7 +883,9 @@ branch_prob (void) } /* Line numbers. */ - if (coverage_begin_output ()) + /* FIXME: make this work for trees. (Line numbers are in location_t + objects, but aren't always attached to the obvious tree...) */ + if (coverage_begin_output () && !ir_type ()) { char const *prev_file_name = NULL; gcov_position_t offset; @@ -953,16 +953,13 @@ branch_prob (void) } } } + ENTRY_BLOCK_PTR->index = ENTRY_BLOCK; EXIT_BLOCK_PTR->index = EXIT_BLOCK; #undef BB_TO_GCOV_INDEX if (flag_profile_values) - { - life_analysis (get_insns (), NULL, PROP_DEATH_NOTES); - find_values_to_profile (&n_values, &values); - allocate_reg_info (max_reg_num (), FALSE, FALSE); - } + find_values_to_profile (&n_values, &values); if (flag_branch_probabilities) { @@ -971,7 +968,7 @@ branch_prob (void) compute_value_histograms (n_values, values); } - /* For each edge not on the spanning tree, add counting code as rtl. */ + /* For each edge not on the spanning tree, add counting code. */ if (profile_arc_flag && coverage_counter_alloc (GCOV_COUNTER_ARCS, num_instrumented)) { @@ -984,17 +981,26 @@ branch_prob (void) instrument_values (n_values, values); /* Commit changes done by instrumentation. */ - commit_edge_insertions_watch_calls (); - allocate_reg_info (max_reg_num (), FALSE, FALSE); + if (ir_type ()) + bsi_commit_edge_inserts ((int *)NULL); + else + { + commit_edge_insertions_watch_calls (); + allocate_reg_info (max_reg_num (), FALSE, FALSE); + } } remove_fake_edges (); free_aux_for_edges (); - /* Re-merge split basic blocks and the mess introduced by - insert_insn_on_edge. */ - cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0); - if (dump_file) - dump_flow_info (dump_file); + + if (!ir_type ()) + { + /* Re-merge split basic blocks and the mess introduced by + insert_insn_on_edge. */ + cleanup_cfg (profile_arc_flag ? CLEANUP_EXPENSIVE : 0); + if (profile_dump_file()) + dump_flow_info (profile_dump_file()); + } free_edge_list (el); } @@ -1168,324 +1174,22 @@ end_branch_prob (void) } } - -/* Output instructions as RTL to increment the edge execution count. */ - -static rtx -gen_edge_profiler (int edgeno) -{ - rtx ref = coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); - rtx tmp; - enum machine_mode mode = GET_MODE (ref); - rtx sequence; - - start_sequence (); - ref = validize_mem (ref); - - tmp = expand_simple_binop (mode, PLUS, ref, const1_rtx, - ref, 0, OPTAB_WIDEN); - - if (tmp != ref) - emit_move_insn (copy_rtx (ref), tmp); +/* Set up hooks to enable tree-based profiling. */ - sequence = get_insns (); - end_sequence (); - return sequence; -} - -/* Output instructions as RTL to increment the interval histogram counter. - VALUE is the expression whose value is profiled. TAG is the tag of the - section for counters, BASE is offset of the counter position. */ - -static rtx -gen_interval_profiler (struct histogram_value *value, unsigned tag, - unsigned base) -{ - unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); - enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); - rtx mem_ref, tmp, tmp1, mr, val; - rtx sequence; - rtx more_label = gen_label_rtx (); - rtx less_label = gen_label_rtx (); - rtx end_of_code_label = gen_label_rtx (); - int per_counter = gcov_size / BITS_PER_UNIT; - - start_sequence (); - - if (value->seq) - emit_insn (value->seq); - - mr = gen_reg_rtx (Pmode); - - tmp = coverage_counter_ref (tag, base); - tmp = force_reg (Pmode, XEXP (tmp, 0)); - - val = expand_simple_binop (value->mode, MINUS, - copy_rtx (value->value), - GEN_INT (value->hdata.intvl.int_start), - NULL_RTX, 0, OPTAB_WIDEN); - - if (value->hdata.intvl.may_be_more) - do_compare_rtx_and_jump (copy_rtx (val), GEN_INT (value->hdata.intvl.steps), - GE, 0, value->mode, NULL_RTX, NULL_RTX, more_label); - if (value->hdata.intvl.may_be_less) - do_compare_rtx_and_jump (copy_rtx (val), const0_rtx, LT, 0, value->mode, - NULL_RTX, NULL_RTX, less_label); - - /* We are in range. */ - tmp1 = expand_simple_binop (value->mode, MULT, - copy_rtx (val), GEN_INT (per_counter), - NULL_RTX, 0, OPTAB_WIDEN); - tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), tmp1, mr, - 0, OPTAB_WIDEN); - if (tmp1 != mr) - emit_move_insn (copy_rtx (mr), tmp1); - - if (value->hdata.intvl.may_be_more - || value->hdata.intvl.may_be_less) - { - emit_jump_insn (gen_jump (end_of_code_label)); - emit_barrier (); - } - - /* Above the interval. */ - if (value->hdata.intvl.may_be_more) - { - emit_label (more_label); - tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), - GEN_INT (per_counter * value->hdata.intvl.steps), - mr, 0, OPTAB_WIDEN); - if (tmp1 != mr) - emit_move_insn (copy_rtx (mr), tmp1); - if (value->hdata.intvl.may_be_less) - { - emit_jump_insn (gen_jump (end_of_code_label)); - emit_barrier (); - } - } - - /* Below the interval. */ - if (value->hdata.intvl.may_be_less) - { - emit_label (less_label); - tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), - GEN_INT (per_counter * (value->hdata.intvl.steps - + (value->hdata.intvl.may_be_more ? 1 : 0))), - mr, 0, OPTAB_WIDEN); - if (tmp1 != mr) - emit_move_insn (copy_rtx (mr), tmp1); - } - - if (value->hdata.intvl.may_be_more - || value->hdata.intvl.may_be_less) - emit_label (end_of_code_label); - - mem_ref = validize_mem (gen_rtx_MEM (mode, mr)); - - tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx, - mem_ref, 0, OPTAB_WIDEN); - - if (tmp != mem_ref) - emit_move_insn (copy_rtx (mem_ref), tmp); - - sequence = get_insns (); - end_sequence (); - rebuild_jump_labels (sequence); - return sequence; -} - -/* Output instructions as RTL to increment the power of two histogram counter. - VALUE is the expression whose value is profiled. TAG is the tag of the - section for counters, BASE is offset of the counter position. */ - -static rtx -gen_pow2_profiler (struct histogram_value *value, unsigned tag, unsigned base) -{ - unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); - enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); - rtx mem_ref, tmp, mr, uval; - rtx sequence; - rtx end_of_code_label = gen_label_rtx (); - rtx loop_label = gen_label_rtx (); - int per_counter = gcov_size / BITS_PER_UNIT; - - start_sequence (); - - if (value->seq) - emit_insn (value->seq); - - mr = gen_reg_rtx (Pmode); - tmp = coverage_counter_ref (tag, base); - tmp = force_reg (Pmode, XEXP (tmp, 0)); - emit_move_insn (mr, tmp); - - uval = gen_reg_rtx (value->mode); - emit_move_insn (uval, copy_rtx (value->value)); - - /* Check for non-power of 2. */ - if (value->hdata.pow2.may_be_other) - { - do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->mode, - NULL_RTX, NULL_RTX, end_of_code_label); - tmp = expand_simple_binop (value->mode, PLUS, copy_rtx (uval), - constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN); - tmp = expand_simple_binop (value->mode, AND, copy_rtx (uval), tmp, - NULL_RTX, 0, OPTAB_WIDEN); - do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->mode, NULL_RTX, - NULL_RTX, end_of_code_label); - } - - /* Count log_2(value). */ - emit_label (loop_label); - - tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter), mr, 0, OPTAB_WIDEN); - if (tmp != mr) - emit_move_insn (copy_rtx (mr), tmp); - - tmp = expand_simple_binop (value->mode, ASHIFTRT, copy_rtx (uval), const1_rtx, - uval, 0, OPTAB_WIDEN); - if (tmp != uval) - emit_move_insn (copy_rtx (uval), tmp); - - do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, NE, 0, value->mode, - NULL_RTX, NULL_RTX, loop_label); - - /* Increase the counter. */ - emit_label (end_of_code_label); - - mem_ref = validize_mem (gen_rtx_MEM (mode, mr)); - - tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx, - mem_ref, 0, OPTAB_WIDEN); - - if (tmp != mem_ref) - emit_move_insn (copy_rtx (mem_ref), tmp); - - sequence = get_insns (); - end_sequence (); - rebuild_jump_labels (sequence); - return sequence; -} - -/* Output instructions as RTL for code to find the most common value. - VALUE is the expression whose value is profiled. TAG is the tag of the - section for counters, BASE is offset of the counter position. */ - -static rtx -gen_one_value_profiler (struct histogram_value *value, unsigned tag, - unsigned base) +void +tree_register_profile_hooks (void) { - unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); - enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); - rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all; - rtx tmp, uval; - rtx sequence; - rtx same_label = gen_label_rtx (); - rtx zero_label = gen_label_rtx (); - rtx end_of_code_label = gen_label_rtx (); - - start_sequence (); - - if (value->seq) - emit_insn (value->seq); - - stored_value_ref = coverage_counter_ref (tag, base); - counter_ref = coverage_counter_ref (tag, base + 1); - all_ref = coverage_counter_ref (tag, base + 2); - stored_value = validize_mem (stored_value_ref); - counter = validize_mem (counter_ref); - all = validize_mem (all_ref); - - uval = gen_reg_rtx (mode); - convert_move (uval, copy_rtx (value->value), 0); - - /* Check if the stored value matches. */ - do_compare_rtx_and_jump (copy_rtx (uval), copy_rtx (stored_value), EQ, - 0, mode, NULL_RTX, NULL_RTX, same_label); - - /* Does not match; check whether the counter is zero. */ - do_compare_rtx_and_jump (copy_rtx (counter), const0_rtx, EQ, 0, mode, - NULL_RTX, NULL_RTX, zero_label); - - /* The counter is not zero yet. */ - tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), constm1_rtx, - counter, 0, OPTAB_WIDEN); - - if (tmp != counter) - emit_move_insn (copy_rtx (counter), tmp); - - emit_jump_insn (gen_jump (end_of_code_label)); - emit_barrier (); - - emit_label (zero_label); - /* Set new value. */ - emit_move_insn (copy_rtx (stored_value), copy_rtx (uval)); - - emit_label (same_label); - /* Increase the counter. */ - tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), const1_rtx, - counter, 0, OPTAB_WIDEN); - - if (tmp != counter) - emit_move_insn (copy_rtx (counter), tmp); - - emit_label (end_of_code_label); - - /* Increase the counter of all executions; this seems redundant given - that ve have counts for edges in cfg, but it may happen that some - optimization will change the counts for the block (either because - it is unable to update them correctly, or because it will duplicate - the block or its part). */ - tmp = expand_simple_binop (mode, PLUS, copy_rtx (all), const1_rtx, - all, 0, OPTAB_WIDEN); - - if (tmp != all) - emit_move_insn (copy_rtx (all), tmp); - sequence = get_insns (); - end_sequence (); - rebuild_jump_labels (sequence); - return sequence; + profile_hooks = &tree_profile_hooks; + if (!ir_type ()) + abort (); } -/* Output instructions as RTL for code to find the most common value of - a difference between two evaluations of an expression. - VALUE is the expression whose value is profiled. TAG is the tag of the - section for counters, BASE is offset of the counter position. */ +/* Set up hooks to enable RTL-based profiling. */ -static rtx -gen_const_delta_profiler (struct histogram_value *value, unsigned tag, - unsigned base) +void +rtl_register_profile_hooks (void) { - struct histogram_value one_value_delta; - unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); - enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); - rtx stored_value_ref, stored_value, tmp, uval; - rtx sequence; - - start_sequence (); - - if (value->seq) - emit_insn (value->seq); - - stored_value_ref = coverage_counter_ref (tag, base); - stored_value = validize_mem (stored_value_ref); - - uval = gen_reg_rtx (mode); - convert_move (uval, copy_rtx (value->value), 0); - tmp = expand_simple_binop (mode, MINUS, - copy_rtx (uval), copy_rtx (stored_value), - NULL_RTX, 0, OPTAB_WIDEN); - - one_value_delta.value = tmp; - one_value_delta.mode = mode; - one_value_delta.seq = NULL_RTX; - one_value_delta.insn = value->insn; - one_value_delta.type = HIST_TYPE_SINGLE_VALUE; - emit_insn (gen_one_value_profiler (&one_value_delta, tag, base + 1)); - - emit_move_insn (copy_rtx (stored_value), uval); - sequence = get_insns (); - end_sequence (); - rebuild_jump_labels (sequence); - return sequence; + profile_hooks = &rtl_profile_hooks; + if (ir_type ()) + abort (); } diff --git a/gcc/ra-rewrite.c b/gcc/ra-rewrite.c index 6c6a53d27b6..7479860798e 100644 --- a/gcc/ra-rewrite.c +++ b/gcc/ra-rewrite.c @@ -1130,6 +1130,8 @@ rewrite_program2 (bitmap new_deaths) struct ra_insn_info info; unsigned int n; + memset (&info, 0, sizeof info); + if (INSN_P (insn) && BLOCK_FOR_INSN (insn) != last_bb) { int index = BLOCK_FOR_INSN (insn)->index + 2; diff --git a/gcc/recog.c b/gcc/recog.c index 6d6135a5658..d7c95072400 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -1114,12 +1114,6 @@ immediate_operand (rtx op, enum machine_mode mode) && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op)) return 0; - /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and - result in 0/1. It seems a safe assumption that this is - in range for everyone. */ - if (GET_CODE (op) == CONSTANT_P_RTX) - return 1; - return (CONSTANT_P (op) && (GET_MODE (op) == mode || mode == VOIDmode || GET_MODE (op) == VOIDmode) diff --git a/gcc/regs.h b/gcc/regs.h index e4b78c7531d..c100bdeabac 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -19,6 +19,8 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef GCC_REGS_H +#define GCC_REGS_H #include "varray.h" #include "hard-reg-set.h" @@ -227,3 +229,5 @@ extern void allocate_reg_info (size_t, int, int); /* Specify number of hard registers given machine mode occupy. */ extern unsigned char hard_regno_nregs[FIRST_PSEUDO_REGISTER][MAX_MACHINE_MODE]; + +#endif /* GCC_REGS_H */ diff --git a/gcc/reload.c b/gcc/reload.c index f1682f73aee..ae211302efa 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -2265,9 +2265,8 @@ decompose (rtx x) struct decomposition val; int all_const = 0; - val.reg_flag = 0; - val.safe = 0; - val.base = 0; + memset (&val, 0, sizeof (val)); + if (GET_CODE (x) == MEM) { rtx base = NULL_RTX, offset = 0; diff --git a/gcc/rtl-profile.c b/gcc/rtl-profile.c new file mode 100644 index 00000000000..a53a00464a9 --- /dev/null +++ b/gcc/rtl-profile.c @@ -0,0 +1,424 @@ +/* Calculate branch probabilities, and basic block execution counts. + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by James E. Wilson, UC Berkeley/Cygnus Support; + based on some ideas from Dain Samples of UC Berkeley. + Further mangling by Bob Manson, Cygnus Support. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Generate basic block profile instrumentation and auxiliary files. + Profile generation is optimized, so that not all arcs in the basic + block graph need instrumenting. First, the BB graph is closed with + one entry (function start), and one exit (function exit). Any + ABNORMAL_EDGE cannot be instrumented (because there is no control + path to place the code). We close the graph by inserting fake + EDGE_FAKE edges to the EXIT_BLOCK, from the sources of abnormal + edges that do not go to the exit_block. We ignore such abnormal + edges. Naturally these fake edges are never directly traversed, + and so *cannot* be directly instrumented. Some other graph + massaging is done. To optimize the instrumentation we generate the + BB minimal span tree, only edges that are not on the span tree + (plus the entry point) need instrumenting. From that information + all other edge counts can be deduced. By construction all fake + edges must be on the spanning tree. We also attempt to place + EDGE_CRITICAL edges on the spanning tree. + + The auxiliary file generated is .bbg. The format is + described in full in gcov-io.h. */ + +/* ??? Register allocation should use basic block execution counts to + give preference to the most commonly executed blocks. */ + +/* ??? Should calculate branch probabilities before instrumenting code, since + then we can use arc counts to help decide which arcs to instrument. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "flags.h" +#include "output.h" +#include "regs.h" +#include "expr.h" +#include "function.h" +#include "toplev.h" +#include "coverage.h" +#include "value-prof.h" +#include "tree.h" + +/* Output instructions as RTL to increment the edge execution count. */ + +static void +rtl_gen_edge_profiler (int edgeno, edge e) +{ + rtx ref = rtl_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); + rtx tmp; + enum machine_mode mode = GET_MODE (ref); + rtx sequence; + + start_sequence (); + ref = validize_mem (ref); + + tmp = expand_simple_binop (mode, PLUS, ref, const1_rtx, + ref, 0, OPTAB_WIDEN); + + if (tmp != ref) + emit_move_insn (copy_rtx (ref), tmp); + + sequence = get_insns (); + end_sequence (); + insert_insn_on_edge (sequence, e); + rebuild_jump_labels (e->insns.r); +} + +/* Output instructions as RTL to increment the interval histogram counter. + VALUE is the expression whose value is profiled. TAG is the tag of the + section for counters, BASE is offset of the counter position. */ + +static void +rtl_gen_interval_profiler (struct histogram_value *value, unsigned tag, + unsigned base) +{ + unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); + enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); + rtx mem_ref, tmp, tmp1, mr, val; + rtx sequence; + rtx more_label = gen_label_rtx (); + rtx less_label = gen_label_rtx (); + rtx end_of_code_label = gen_label_rtx (); + int per_counter = gcov_size / BITS_PER_UNIT; + edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn), + PREV_INSN ((rtx)value->insn)); + + start_sequence (); + + if (value->seq) + emit_insn (value->seq); + + mr = gen_reg_rtx (Pmode); + + tmp = rtl_coverage_counter_ref (tag, base); + tmp = force_reg (Pmode, XEXP (tmp, 0)); + + val = expand_simple_binop (value->mode, MINUS, + copy_rtx (value->value), + GEN_INT (value->hdata.intvl.int_start), + NULL_RTX, 0, OPTAB_WIDEN); + + if (value->hdata.intvl.may_be_more) + do_compare_rtx_and_jump (copy_rtx (val), GEN_INT (value->hdata.intvl.steps), + GE, 0, value->mode, NULL_RTX, NULL_RTX, more_label); + if (value->hdata.intvl.may_be_less) + do_compare_rtx_and_jump (copy_rtx (val), const0_rtx, LT, 0, value->mode, + NULL_RTX, NULL_RTX, less_label); + + /* We are in range. */ + tmp1 = expand_simple_binop (value->mode, MULT, + copy_rtx (val), GEN_INT (per_counter), + NULL_RTX, 0, OPTAB_WIDEN); + tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), tmp1, mr, + 0, OPTAB_WIDEN); + if (tmp1 != mr) + emit_move_insn (copy_rtx (mr), tmp1); + + if (value->hdata.intvl.may_be_more + || value->hdata.intvl.may_be_less) + { + emit_jump_insn (gen_jump (end_of_code_label)); + emit_barrier (); + } + + /* Above the interval. */ + if (value->hdata.intvl.may_be_more) + { + emit_label (more_label); + tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), + GEN_INT (per_counter * value->hdata.intvl.steps), + mr, 0, OPTAB_WIDEN); + if (tmp1 != mr) + emit_move_insn (copy_rtx (mr), tmp1); + if (value->hdata.intvl.may_be_less) + { + emit_jump_insn (gen_jump (end_of_code_label)); + emit_barrier (); + } + } + + /* Below the interval. */ + if (value->hdata.intvl.may_be_less) + { + emit_label (less_label); + tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), + GEN_INT (per_counter * (value->hdata.intvl.steps + + (value->hdata.intvl.may_be_more ? 1 : 0))), + mr, 0, OPTAB_WIDEN); + if (tmp1 != mr) + emit_move_insn (copy_rtx (mr), tmp1); + } + + if (value->hdata.intvl.may_be_more + || value->hdata.intvl.may_be_less) + emit_label (end_of_code_label); + + mem_ref = validize_mem (gen_rtx_MEM (mode, mr)); + + tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx, + mem_ref, 0, OPTAB_WIDEN); + + if (tmp != mem_ref) + emit_move_insn (copy_rtx (mem_ref), tmp); + + sequence = get_insns (); + end_sequence (); + rebuild_jump_labels (sequence); + safe_insert_insn_on_edge (sequence, e); +} + +/* Output instructions as RTL to increment the power of two histogram counter. + VALUE is the expression whose value is profiled. TAG is the tag of the + section for counters, BASE is offset of the counter position. */ + +static void +rtl_gen_pow2_profiler (struct histogram_value *value, unsigned tag, + unsigned base) +{ + unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); + enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); + rtx mem_ref, tmp, mr, uval; + rtx sequence; + rtx end_of_code_label = gen_label_rtx (); + rtx loop_label = gen_label_rtx (); + int per_counter = gcov_size / BITS_PER_UNIT; + edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn), + PREV_INSN ((rtx)value->insn)); + + start_sequence (); + + if (value->seq) + emit_insn (value->seq); + + mr = gen_reg_rtx (Pmode); + tmp = rtl_coverage_counter_ref (tag, base); + tmp = force_reg (Pmode, XEXP (tmp, 0)); + emit_move_insn (mr, tmp); + + uval = gen_reg_rtx (value->mode); + emit_move_insn (uval, copy_rtx (value->value)); + + /* Check for non-power of 2. */ + if (value->hdata.pow2.may_be_other) + { + do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->mode, + NULL_RTX, NULL_RTX, end_of_code_label); + tmp = expand_simple_binop (value->mode, PLUS, copy_rtx (uval), + constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN); + tmp = expand_simple_binop (value->mode, AND, copy_rtx (uval), tmp, + NULL_RTX, 0, OPTAB_WIDEN); + do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->mode, NULL_RTX, + NULL_RTX, end_of_code_label); + } + + /* Count log_2(value). */ + emit_label (loop_label); + + tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter), mr, 0, OPTAB_WIDEN); + if (tmp != mr) + emit_move_insn (copy_rtx (mr), tmp); + + tmp = expand_simple_binop (value->mode, ASHIFTRT, copy_rtx (uval), const1_rtx, + uval, 0, OPTAB_WIDEN); + if (tmp != uval) + emit_move_insn (copy_rtx (uval), tmp); + + do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, NE, 0, value->mode, + NULL_RTX, NULL_RTX, loop_label); + + /* Increase the counter. */ + emit_label (end_of_code_label); + + mem_ref = validize_mem (gen_rtx_MEM (mode, mr)); + + tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx, + mem_ref, 0, OPTAB_WIDEN); + + if (tmp != mem_ref) + emit_move_insn (copy_rtx (mem_ref), tmp); + + sequence = get_insns (); + end_sequence (); + rebuild_jump_labels (sequence); + safe_insert_insn_on_edge (sequence, e); +} + +/* Output instructions as RTL for code to find the most common value. + VALUE is the expression whose value is profiled. TAG is the tag of the + section for counters, BASE is offset of the counter position. */ + +static rtx +rtl_gen_one_value_profiler_no_edge_manipulation (struct histogram_value *value, + unsigned tag, unsigned base) +{ + unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); + enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); + rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all; + rtx tmp, uval; + rtx sequence; + rtx same_label = gen_label_rtx (); + rtx zero_label = gen_label_rtx (); + rtx end_of_code_label = gen_label_rtx (); + + start_sequence (); + + if (value->seq) + emit_insn (value->seq); + + stored_value_ref = rtl_coverage_counter_ref (tag, base); + counter_ref = rtl_coverage_counter_ref (tag, base + 1); + all_ref = rtl_coverage_counter_ref (tag, base + 2); + stored_value = validize_mem (stored_value_ref); + counter = validize_mem (counter_ref); + all = validize_mem (all_ref); + + uval = gen_reg_rtx (mode); + convert_move (uval, copy_rtx (value->value), 0); + + /* Check if the stored value matches. */ + do_compare_rtx_and_jump (copy_rtx (uval), copy_rtx (stored_value), EQ, + 0, mode, NULL_RTX, NULL_RTX, same_label); + + /* Does not match; check whether the counter is zero. */ + do_compare_rtx_and_jump (copy_rtx (counter), const0_rtx, EQ, 0, mode, + NULL_RTX, NULL_RTX, zero_label); + + /* The counter is not zero yet. */ + tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), constm1_rtx, + counter, 0, OPTAB_WIDEN); + + if (tmp != counter) + emit_move_insn (copy_rtx (counter), tmp); + + emit_jump_insn (gen_jump (end_of_code_label)); + emit_barrier (); + + emit_label (zero_label); + /* Set new value. */ + emit_move_insn (copy_rtx (stored_value), copy_rtx (uval)); + + emit_label (same_label); + /* Increase the counter. */ + tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), const1_rtx, + counter, 0, OPTAB_WIDEN); + + if (tmp != counter) + emit_move_insn (copy_rtx (counter), tmp); + + emit_label (end_of_code_label); + + /* Increase the counter of all executions; this seems redundant given + that ve have counts for edges in cfg, but it may happen that some + optimization will change the counts for the block (either because + it is unable to update them correctly, or because it will duplicate + the block or its part). */ + tmp = expand_simple_binop (mode, PLUS, copy_rtx (all), const1_rtx, + all, 0, OPTAB_WIDEN); + + if (tmp != all) + emit_move_insn (copy_rtx (all), tmp); + sequence = get_insns (); + end_sequence (); + return sequence; +} + +/* Output instructions as RTL for code to find the most common value. + VALUE is the expression whose value is profiled. TAG is the tag of the + section for counters, BASE is offset of the counter position. */ + +static void +rtl_gen_one_value_profiler (struct histogram_value *value, unsigned tag, + unsigned base) +{ + edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn), + PREV_INSN ((rtx)value->insn)); + rtx sequence = rtl_gen_one_value_profiler_no_edge_manipulation (value, + tag, base); + rebuild_jump_labels (sequence); + safe_insert_insn_on_edge (sequence, e); +} + +/* Output instructions as RTL for code to find the most common value of + a difference between two evaluations of an expression. + VALUE is the expression whose value is profiled. TAG is the tag of the + section for counters, BASE is offset of the counter position. */ + +static void +rtl_gen_const_delta_profiler (struct histogram_value *value, unsigned tag, + unsigned base) +{ + struct histogram_value one_value_delta; + unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1); + enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0); + rtx stored_value_ref, stored_value, tmp, uval; + rtx sequence; + edge e = split_block (BLOCK_FOR_INSN ((rtx)value->insn), + PREV_INSN ((rtx)value->insn)); + + start_sequence (); + + if (value->seq) + emit_insn (value->seq); + + stored_value_ref = rtl_coverage_counter_ref (tag, base); + stored_value = validize_mem (stored_value_ref); + + uval = gen_reg_rtx (mode); + convert_move (uval, copy_rtx (value->value), 0); + tmp = expand_simple_binop (mode, MINUS, + copy_rtx (uval), copy_rtx (stored_value), + NULL_RTX, 0, OPTAB_WIDEN); + + one_value_delta.value = tmp; + one_value_delta.mode = mode; + one_value_delta.seq = NULL_RTX; + one_value_delta.insn = value->insn; + one_value_delta.type = HIST_TYPE_SINGLE_VALUE; + emit_insn (rtl_gen_one_value_profiler_no_edge_manipulation (&one_value_delta, + tag, base + 1)); + emit_move_insn (copy_rtx (stored_value), uval); + sequence = get_insns (); + end_sequence (); + rebuild_jump_labels (sequence); + safe_insert_insn_on_edge (sequence, e); +} + +/* Return the file on which profile dump output goes, if any. */ + +static FILE *rtl_profile_dump_file (void) { + return dump_file; +} + +struct profile_hooks rtl_profile_hooks = +{ + rtl_gen_edge_profiler, + rtl_gen_interval_profiler, + rtl_gen_pow2_profiler, + rtl_gen_one_value_profiler, + rtl_gen_const_delta_profiler, + rtl_profile_dump_file +}; diff --git a/gcc/rtl.def b/gcc/rtl.def index c3653f49dfe..3eecf1fb79e 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -1153,11 +1153,6 @@ DEF_RTL_EXPR(RANGE_VAR, "range_var", "eti", RTX_EXTRA) 0 is the live bitmap. Operand 1 is the original block number. */ DEF_RTL_EXPR(RANGE_LIVE, "range_live", "bi", RTX_EXTRA) -/* A unary `__builtin_constant_p' expression. These are only emitted - during RTL generation, and then only if optimize > 0. They are - eliminated by the first CSE pass. */ -DEF_RTL_EXPR(CONSTANT_P_RTX, "constant_p_rtx", "e", RTX_EXTRA) - /* A placeholder for a CALL_INSN which may be turned into a normal call, a sibling (tail) call or tail recursion. diff --git a/gcc/rtl.h b/gcc/rtl.h index 0808e78c90d..d5f7a1ec644 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -240,12 +240,9 @@ struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"), 1 in a SYMBOL_REF, means that emit_library_call has used it as the function. */ unsigned int used : 1; - /* Nonzero if this rtx came from procedure integration. - 1 in a REG or PARALLEL means this rtx refers to the return value - of the current function. - 1 in a SYMBOL_REF if the symbol is weak. - 1 in a MEM if the MEM refers to a scalar, rather than a member of - an aggregate. */ + /* FIXME. This should be unused now that we do inlinining on trees, + but it is now being used for MEM_SCALAR_P. It should be renamed, + or some other field should be overloaded. */ unsigned integrated : 1; /* 1 in an INSN or a SET if this rtx is related to the call frame, either changing how we compute the frame address or saving and @@ -254,6 +251,9 @@ struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"), 1 in a SYMBOL_REF if it addresses something in the per-function constant string pool. */ unsigned frame_related : 1; + /* 1 in a REG or PARALLEL that is the current function's return value. + 1 in a SYMBOL_REF for a weak symbol. */ + unsigned return_val : 1; /* The first element of the operands of this rtx. The number of operands and their types are controlled @@ -387,8 +387,7 @@ struct rtvec_def GTY(()) { #define CONSTANT_P(X) \ (GET_RTX_CLASS (GET_CODE (X)) == RTX_CONST_OBJ \ - || GET_CODE (X) == CONST_VECTOR \ - || GET_CODE (X) == CONSTANT_P_RTX) + || GET_CODE (X) == CONST_VECTOR) /* 1 if X can be used to represent an object. */ #define OBJECT_P(X) \ @@ -593,11 +592,11 @@ do { \ _rtx->call = 0; \ _rtx->frame_related = 0; \ _rtx->in_struct = 0; \ - _rtx->integrated = 0; \ _rtx->jump = 0; \ _rtx->unchanging = 0; \ _rtx->used = 0; \ _rtx->volatil = 0; \ + _rtx->unused_flag = 0; \ } while (0) #define XINT(RTX, N) (RTL_CHECK2 (RTX, N, 'i', 'n').rtint) @@ -676,10 +675,6 @@ do { \ They are always in the same basic block as this insn. */ #define LOG_LINKS(INSN) XEXP(INSN, 7) -#define RTX_INTEGRATED_P(RTX) \ - (RTL_FLAG_CHECK8("RTX_INTEGRATED_P", (RTX), INSN, CALL_INSN, \ - JUMP_INSN, INSN_LIST, BARRIER, CODE_LABEL, CONST, \ - NOTE)->integrated) #define RTX_UNCHANGING_P(RTX) \ (RTL_FLAG_CHECK3("RTX_UNCHANGING_P", (RTX), REG, MEM, CONCAT)->unchanging) #define RTX_FRAME_RELATED_P(RTX) \ @@ -1135,7 +1130,7 @@ enum label_kind /* 1 if RTX is a reg or parallel that is the current function's return value. */ #define REG_FUNCTION_VALUE_P(RTX) \ - (RTL_FLAG_CHECK2("REG_FUNCTION_VALUE_P", (RTX), REG, PARALLEL)->integrated) + (RTL_FLAG_CHECK2("REG_FUNCTION_VALUE_P", (RTX), REG, PARALLEL)->return_val) /* 1 if RTX is a reg that corresponds to a variable declared by the user. */ #define REG_USERVAR_P(RTX) \ @@ -1408,7 +1403,7 @@ do { \ /* 1 if RTX is a symbol_ref for a weak symbol. */ #define SYMBOL_REF_WEAK(RTX) \ - (RTL_FLAG_CHECK1("SYMBOL_REF_WEAK", (RTX), SYMBOL_REF)->integrated) + (RTL_FLAG_CHECK1("SYMBOL_REF_WEAK", (RTX), SYMBOL_REF)->return_val) /* The tree (decl or constant) associated with the symbol, or null. */ #define SYMBOL_REF_DECL(RTX) X0TREE ((RTX), 2) @@ -1542,7 +1537,8 @@ do { \ /* Nonzero if we need to distinguish between the return value of this function and the return value of a function called by this function. This helps integrate.c. - This is 1 until after the rtl generation pass. */ + This is 1 until after the rtl generation pass. + ??? It appears that this is 1 only when expanding trees to RTL. */ extern int rtx_equal_function_value_matters; /* Nonzero when we are generating CONCATs. */ @@ -2080,9 +2076,6 @@ extern rtx gen_rtx_MEM (enum machine_mode, rtx); extern rtx output_constant_def (tree, int); extern rtx lookup_constant_def (tree); -/* Called from integrate.c when a deferred constant is inlined. */ -extern void notice_rtl_inlining_of_deferred_constant (void); - /* Nonzero after the second flow pass has completed. Set to 1 or 0 by toplev.c */ extern int flow2_completed; @@ -2151,14 +2144,13 @@ extern enum rtx_code reversed_comparison_code_parts (enum rtx_code, rtx, rtx, rtx); extern void delete_for_peephole (rtx, rtx); extern int condjump_in_parallel_p (rtx); -extern void never_reached_warning (rtx, rtx); extern void purge_line_number_notes (rtx); -extern void copy_loop_headers (rtx); /* In emit-rtl.c. */ extern int max_reg_num (void); extern int max_label_num (void); extern int get_first_label_num (void); +extern void maybe_set_first_label_num (rtx); extern void delete_insns_since (rtx); extern void mark_reg_pointer (rtx, int); extern void mark_user_reg (rtx); @@ -2347,11 +2339,6 @@ extern void dump_local_alloc (FILE *); #endif extern int local_alloc (void); -/* In profile.c */ -extern void init_branch_prob (void); -extern void branch_prob (void); -extern void end_branch_prob (void); - /* In reg-stack.c */ #ifdef BUFSIZ extern bool reg_to_stack (rtx, FILE *); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index aade423eefe..a52f614b878 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -452,8 +452,8 @@ get_related_value (rtx x) rtx get_jump_table_offset (rtx insn, rtx *earliest) { - rtx label; - rtx table; + rtx label = NULL; + rtx table = NULL; rtx set; rtx old_insn; rtx x; @@ -3702,18 +3702,18 @@ hoist_insn_to_edge (rtx insn, edge e, rtx val, rtx new) abort (); /* Do not use emit_insn_on_edge as we want to preserve notes and similar - stuff. We also emit CALL_INSNS and friends. */ - if (e->insns == NULL_RTX) + stuff. We also emit CALL_INSNS and firends. */ + if (e->insns.r == NULL_RTX) { start_sequence (); emit_note (NOTE_INSN_DELETED); } else - push_to_sequence (e->insns); + push_to_sequence (e->insns.r); new_insn = hoist_insn_after (insn, get_last_insn (), val, new); - e->insns = get_insns (); + e->insns.r = get_insns (); end_sequence (); return new_insn; } diff --git a/gcc/sbitmap.c b/gcc/sbitmap.c index 1d27a871097..dfd764528cb 100644 --- a/gcc/sbitmap.c +++ b/gcc/sbitmap.c @@ -103,6 +103,32 @@ sbitmap_resize (sbitmap bmap, unsigned int n_elms, int def) return bmap; } +/* Re-allocate a simple bitmap of N_ELMS bits. New storage is uninitialized. */ + +sbitmap +sbitmap_realloc (sbitmap src, unsigned int n_elms) +{ + unsigned int bytes, size, amt; + sbitmap bmap; + + size = SBITMAP_SET_SIZE (n_elms); + bytes = size * sizeof (SBITMAP_ELT_TYPE); + amt = (sizeof (struct simple_bitmap_def) + + bytes - sizeof (SBITMAP_ELT_TYPE)); + + if (src->bytes >= bytes) + { + src->n_bits = n_elms; + return src; + } + + bmap = (sbitmap) xrealloc (src, amt); + bmap->n_bits = n_elms; + bmap->size = size; + bmap->bytes = bytes; + return bmap; +} + /* Allocate a vector of N_VECS bitmaps of N_ELMS bits. */ sbitmap * diff --git a/gcc/sbitmap.h b/gcc/sbitmap.h index fecc4915083..0ddc0d051c6 100644 --- a/gcc/sbitmap.h +++ b/gcc/sbitmap.h @@ -170,4 +170,5 @@ extern void sbitmap_union_of_succs (sbitmap, sbitmap *, int); extern void sbitmap_union_of_preds (sbitmap, sbitmap *, int); extern void debug_sbitmap (sbitmap); +extern sbitmap sbitmap_realloc (sbitmap, unsigned int); #endif /* ! GCC_SBITMAP_H */ diff --git a/gcc/sibcall.c b/gcc/sibcall.c deleted file mode 100644 index cfd1a629c62..00000000000 --- a/gcc/sibcall.c +++ /dev/null @@ -1,753 +0,0 @@ -/* Generic sibling call optimization support - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" - -#include "rtl.h" -#include "regs.h" -#include "function.h" -#include "hard-reg-set.h" -#include "flags.h" -#include "insn-config.h" -#include "recog.h" -#include "basic-block.h" -#include "output.h" -#include "except.h" -#include "tree.h" - -/* In case alternate_exit_block contains copy from pseudo, to return value, - record the pseudo here. In such case the pseudo must be set to function - return in the sibcall sequence. */ -static rtx return_value_pseudo; - -static int identify_call_return_value (rtx, rtx *, rtx *); -static rtx skip_copy_to_return_value (rtx); -static rtx skip_use_of_return_value (rtx, enum rtx_code); -static rtx skip_stack_adjustment (rtx); -static rtx skip_pic_restore (rtx); -static rtx skip_jump_insn (rtx); -static int call_ends_block_p (rtx, rtx); -static int uses_addressof (rtx); -static int sequence_uses_addressof (rtx); -static void purge_reg_equiv_notes (void); -static void purge_mem_unchanging_flag (rtx); -static rtx skip_unreturned_value (rtx); - -/* Examine a CALL_PLACEHOLDER pattern and determine where the call's - return value is located. P_HARD_RETURN receives the hard register - that the function used; P_SOFT_RETURN receives the pseudo register - that the sequence used. Return nonzero if the values were located. */ - -static int -identify_call_return_value (rtx cp, rtx *p_hard_return, rtx *p_soft_return) -{ - rtx insn, set, hard, soft; - - insn = XEXP (cp, 0); - /* Search backward through the "normal" call sequence to the CALL insn. */ - while (NEXT_INSN (insn)) - insn = NEXT_INSN (insn); - while (GET_CODE (insn) != CALL_INSN) - insn = PREV_INSN (insn); - - /* Assume the pattern is (set (dest) (call ...)), or that the first - member of a parallel is. This is the hard return register used - by the function. */ - if (GET_CODE (PATTERN (insn)) == SET - && GET_CODE (SET_SRC (PATTERN (insn))) == CALL) - hard = SET_DEST (PATTERN (insn)); - else if (GET_CODE (PATTERN (insn)) == PARALLEL - && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET - && GET_CODE (SET_SRC (XVECEXP (PATTERN (insn), 0, 0))) == CALL) - hard = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); - else - return 0; - - /* If we didn't get a single hard register (e.g. a parallel), give up. */ - if (GET_CODE (hard) != REG) - return 0; - - /* Stack adjustment done after call may appear here. */ - insn = skip_stack_adjustment (insn); - if (! insn) - return 0; - - /* Restore of GP register may appear here. */ - insn = skip_pic_restore (insn); - if (! insn) - return 0; - - /* If there's nothing after, there's no soft return value. */ - insn = NEXT_INSN (insn); - if (! insn) - return 0; - - /* We're looking for a source of the hard return register. */ - set = single_set (insn); - if (! set || SET_SRC (set) != hard) - return 0; - - soft = SET_DEST (set); - insn = NEXT_INSN (insn); - - /* Allow this first destination to be copied to a second register, - as might happen if the first register wasn't the particular pseudo - we'd been expecting. */ - if (insn - && (set = single_set (insn)) != NULL_RTX - && SET_SRC (set) == soft) - { - soft = SET_DEST (set); - insn = NEXT_INSN (insn); - } - - /* Don't fool with anything but pseudo registers. */ - if (GET_CODE (soft) != REG || REGNO (soft) < FIRST_PSEUDO_REGISTER) - return 0; - - /* This value must not be modified before the end of the sequence. */ - if (reg_set_between_p (soft, insn, NULL_RTX)) - return 0; - - *p_hard_return = hard; - *p_soft_return = soft; - - return 1; -} - -/* If the first real insn after ORIG_INSN copies to this function's - return value from RETVAL, then return the insn which performs the - copy. Otherwise return ORIG_INSN. */ - -static rtx -skip_copy_to_return_value (rtx orig_insn) -{ - rtx insn, set = NULL_RTX; - rtx hardret, softret; - - /* If there is no return value, we have nothing to do. */ - if (! identify_call_return_value (PATTERN (orig_insn), &hardret, &softret)) - return orig_insn; - - insn = next_nonnote_insn (orig_insn); - if (! insn) - return orig_insn; - - set = single_set (insn); - if (! set) - return orig_insn; - - if (return_value_pseudo) - { - if (SET_DEST (set) == return_value_pseudo - && SET_SRC (set) == softret) - return insn; - return orig_insn; - } - - /* The destination must be the same as the called function's return - value to ensure that any return value is put in the same place by the - current function and the function we're calling. - - Further, the source must be the same as the pseudo into which the - called function's return value was copied. Otherwise we're returning - some other value. */ - - if (SET_DEST (set) == current_function_return_rtx - && REG_P (SET_DEST (set)) - && OUTGOING_REGNO (REGNO (SET_DEST (set))) == REGNO (hardret) - && SET_SRC (set) == softret) - return insn; - - /* Recognize the situation when the called function's return value - is copied in two steps: first into an intermediate pseudo, then - the into the calling functions return value register. */ - - if (REG_P (SET_DEST (set)) - && SET_SRC (set) == softret) - { - rtx x = SET_DEST (set); - - insn = next_nonnote_insn (insn); - if (! insn) - return orig_insn; - - set = single_set (insn); - if (! set) - return orig_insn; - - if (SET_DEST (set) == current_function_return_rtx - && REG_P (SET_DEST (set)) - && OUTGOING_REGNO (REGNO (SET_DEST (set))) == REGNO (hardret) - && SET_SRC (set) == x) - return insn; - } - - /* It did not look like a copy of the return value, so return the - same insn we were passed. */ - return orig_insn; -} - -/* If the first real insn after ORIG_INSN is a CODE of this function's return - value, return insn. Otherwise return ORIG_INSN. */ - -static rtx -skip_use_of_return_value (rtx orig_insn, enum rtx_code code) -{ - rtx insn; - - insn = next_nonnote_insn (orig_insn); - - if (insn - && GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == code - && (XEXP (PATTERN (insn), 0) == current_function_return_rtx - || XEXP (PATTERN (insn), 0) == const0_rtx)) - return insn; - - return orig_insn; -} - -/* In case function does not return value, we get clobber of pseudo followed - by set to hard return value. */ -static rtx -skip_unreturned_value (rtx orig_insn) -{ - rtx insn = next_nonnote_insn (orig_insn); - - /* Skip possible clobber of pseudo return register. */ - if (insn - && GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == CLOBBER - && REG_P (XEXP (PATTERN (insn), 0)) - && (REGNO (XEXP (PATTERN (insn), 0)) >= FIRST_PSEUDO_REGISTER)) - { - rtx set_insn = next_nonnote_insn (insn); - rtx set; - if (!set_insn) - return insn; - set = single_set (set_insn); - if (!set - || SET_SRC (set) != XEXP (PATTERN (insn), 0) - || SET_DEST (set) != current_function_return_rtx) - return insn; - return set_insn; - } - return orig_insn; -} - -/* If the first real insn after ORIG_INSN adjusts the stack pointer - by a constant, return the insn with the stack pointer adjustment. - Otherwise return ORIG_INSN. */ - -static rtx -skip_stack_adjustment (rtx orig_insn) -{ - rtx insn, set = NULL_RTX; - - insn = next_nonnote_insn (orig_insn); - - if (insn) - set = single_set (insn); - - if (insn - && set - && GET_CODE (SET_SRC (set)) == PLUS - && XEXP (SET_SRC (set), 0) == stack_pointer_rtx - && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT - && SET_DEST (set) == stack_pointer_rtx) - return insn; - - return orig_insn; -} - -/* If the first real insn after ORIG_INSN sets the pic register, - return it. Otherwise return ORIG_INSN. */ - -static rtx -skip_pic_restore (rtx orig_insn) -{ - rtx insn, set = NULL_RTX; - - insn = next_nonnote_insn (orig_insn); - - if (insn) - set = single_set (insn); - - if (insn && set && SET_DEST (set) == pic_offset_table_rtx) - return insn; - - return orig_insn; -} - -/* If the first real insn after ORIG_INSN is a jump, return the JUMP_INSN. - Otherwise return ORIG_INSN. */ - -static rtx -skip_jump_insn (rtx orig_insn) -{ - rtx insn; - - insn = next_nonnote_insn (orig_insn); - - if (insn - && GET_CODE (insn) == JUMP_INSN - && any_uncondjump_p (insn)) - return insn; - - return orig_insn; -} - -/* Using the above functions, see if INSN, skipping any of the above, - goes all the way to END, the end of a basic block. Return 1 if so. */ - -static int -call_ends_block_p (rtx insn, rtx end) -{ - rtx new_insn; - /* END might be a note, so get the last nonnote insn of the block. */ - end = next_nonnote_insn (PREV_INSN (end)); - - /* If the call was the end of the block, then we're OK. */ - if (insn == end) - return 1; - - /* Skip over copying from the call's return value pseudo into - this function's hard return register and if that's the end - of the block, we're OK. */ - new_insn = skip_copy_to_return_value (insn); - - /* In case we return value in pseudo, we must set the pseudo to - return value of called function, otherwise we are returning - something else. */ - if (return_value_pseudo && insn == new_insn) - return 0; - insn = new_insn; - - if (insn == end) - return 1; - - /* Skip any stack adjustment. */ - insn = skip_stack_adjustment (insn); - if (insn == end) - return 1; - - /* Skip over a CLOBBER of the return value as a hard reg. */ - insn = skip_use_of_return_value (insn, CLOBBER); - if (insn == end) - return 1; - - /* Skip over a CLOBBER of the return value as a hard reg. */ - insn = skip_unreturned_value (insn); - if (insn == end) - return 1; - - /* Skip over a USE of the return value (as a hard reg). */ - insn = skip_use_of_return_value (insn, USE); - if (insn == end) - return 1; - - /* Skip over a JUMP_INSN at the end of the block. If that doesn't end the - block, the original CALL_INSN didn't. */ - insn = skip_jump_insn (insn); - return insn == end; -} - -/* Scan the rtx X for ADDRESSOF expressions or - current_function_internal_arg_pointer registers. - Return nonzero if an ADDRESSOF or current_function_internal_arg_pointer - is found outside of some MEM expression, else return zero. */ - -static int -uses_addressof (rtx x) -{ - RTX_CODE code; - int i, j; - const char *fmt; - - if (x == NULL_RTX) - return 0; - - code = GET_CODE (x); - - if (code == ADDRESSOF || x == current_function_internal_arg_pointer) - return 1; - - if (code == MEM) - return 0; - - /* Scan all subexpressions. */ - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - { - if (*fmt == 'e') - { - if (uses_addressof (XEXP (x, i))) - return 1; - } - else if (*fmt == 'E') - { - for (j = 0; j < XVECLEN (x, i); j++) - if (uses_addressof (XVECEXP (x, i, j))) - return 1; - } - } - return 0; -} - -/* Scan the sequence of insns in SEQ to see if any have an ADDRESSOF - rtl expression or current_function_internal_arg_pointer occurrences - not enclosed within a MEM. If an ADDRESSOF expression or - current_function_internal_arg_pointer is found, return nonzero, otherwise - return zero. - - This function handles CALL_PLACEHOLDERs which contain multiple sequences - of insns. */ - -static int -sequence_uses_addressof (rtx seq) -{ - rtx insn; - - for (insn = seq; insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - /* If this is a CALL_PLACEHOLDER, then recursively call ourselves - with each nonempty sequence attached to the CALL_PLACEHOLDER. */ - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - { - if (XEXP (PATTERN (insn), 0) != NULL_RTX - && sequence_uses_addressof (XEXP (PATTERN (insn), 0))) - return 1; - if (XEXP (PATTERN (insn), 1) != NULL_RTX - && sequence_uses_addressof (XEXP (PATTERN (insn), 1))) - return 1; - if (XEXP (PATTERN (insn), 2) != NULL_RTX - && sequence_uses_addressof (XEXP (PATTERN (insn), 2))) - return 1; - } - else if (uses_addressof (PATTERN (insn)) - || (REG_NOTES (insn) && uses_addressof (REG_NOTES (insn)))) - return 1; - } - return 0; -} - -/* Remove all REG_EQUIV notes found in the insn chain. */ - -static void -purge_reg_equiv_notes (void) -{ - rtx insn; - - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - while (1) - { - rtx note = find_reg_note (insn, REG_EQUIV, 0); - if (note) - { - /* Remove the note and keep looking at the notes for - this insn. */ - remove_note (insn, note); - continue; - } - break; - } - } -} - -/* Clear RTX_UNCHANGING_P flag of incoming argument MEMs. */ - -static void -purge_mem_unchanging_flag (rtx x) -{ - RTX_CODE code; - int i, j; - const char *fmt; - - if (x == NULL_RTX) - return; - - code = GET_CODE (x); - - if (code == MEM) - { - if (RTX_UNCHANGING_P (x) - && (XEXP (x, 0) == current_function_internal_arg_pointer - || (GET_CODE (XEXP (x, 0)) == PLUS - && XEXP (XEXP (x, 0), 0) == - current_function_internal_arg_pointer - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))) - RTX_UNCHANGING_P (x) = 0; - return; - } - - /* Scan all subexpressions. */ - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - { - if (*fmt == 'e') - purge_mem_unchanging_flag (XEXP (x, i)); - else if (*fmt == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - purge_mem_unchanging_flag (XVECEXP (x, i, j)); - } -} - -/* Replace the CALL_PLACEHOLDER with one of its children. INSN should be - the CALL_PLACEHOLDER insn; USE tells which child to use. */ - -void -replace_call_placeholder (rtx insn, sibcall_use_t use) -{ - if (use == sibcall_use_tail_recursion) - emit_insn_before (XEXP (PATTERN (insn), 2), insn); - else if (use == sibcall_use_sibcall) - emit_insn_before (XEXP (PATTERN (insn), 1), insn); - else if (use == sibcall_use_normal) - emit_insn_before (XEXP (PATTERN (insn), 0), insn); - else - abort (); - - /* Turn off LABEL_PRESERVE_P for the tail recursion label if it - exists. We only had to set it long enough to keep the jump - pass above from deleting it as unused. */ - if (XEXP (PATTERN (insn), 3)) - LABEL_PRESERVE_P (XEXP (PATTERN (insn), 3)) = 0; - - /* "Delete" the placeholder insn. */ - remove_insn (insn); -} - -/* Given a (possibly empty) set of potential sibling or tail recursion call - sites, determine if optimization is possible. - - Potential sibling or tail recursion calls are marked with CALL_PLACEHOLDER - insns. The CALL_PLACEHOLDER insn holds chains of insns to implement a - normal call, sibling call or tail recursive call. - - Replace the CALL_PLACEHOLDER with an appropriate insn chain. */ - -void -optimize_sibling_and_tail_recursive_calls (void) -{ - rtx insn, insns; - basic_block alternate_exit = EXIT_BLOCK_PTR; - bool no_sibcalls_this_function = false; - bool successful_replacement = false; - bool replaced_call_placeholder = false; - edge e; - - insns = get_insns (); - - cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_PRE_LOOP); - - /* If there are no basic blocks, then there is nothing to do. */ - if (n_basic_blocks == 0) - return; - - /* If we are using sjlj exceptions, we may need to add a call to - _Unwind_SjLj_Unregister at exit of the function. Which means - that we cannot do any sibcall transformations. */ - if (USING_SJLJ_EXCEPTIONS && current_function_has_exception_handlers ()) - no_sibcalls_this_function = true; - - return_value_pseudo = NULL_RTX; - - /* Find the exit block. - - It is possible that we have blocks which can reach the exit block - directly. However, most of the time a block will jump (or fall into) - N_BASIC_BLOCKS - 1, which in turn falls into the exit block. */ - for (e = EXIT_BLOCK_PTR->pred; - e && alternate_exit == EXIT_BLOCK_PTR; - e = e->pred_next) - { - rtx insn; - - if (e->dest != EXIT_BLOCK_PTR || e->succ_next != NULL) - continue; - - /* Walk forwards through the last normal block and see if it - does nothing except fall into the exit block. */ - for (insn = BB_HEAD (EXIT_BLOCK_PTR->prev_bb); - insn; - insn = NEXT_INSN (insn)) - { - rtx set; - /* This should only happen once, at the start of this block. */ - if (GET_CODE (insn) == CODE_LABEL) - continue; - - if (GET_CODE (insn) == NOTE) - continue; - - if (GET_CODE (insn) == INSN - && GET_CODE (PATTERN (insn)) == USE) - continue; - - /* Exit block also may contain copy from pseudo containing - return value to hard register. */ - if (GET_CODE (insn) == INSN - && (set = single_set (insn)) - && SET_DEST (set) == current_function_return_rtx - && REG_P (SET_SRC (set)) - && !return_value_pseudo) - { - return_value_pseudo = SET_SRC (set); - continue; - } - - break; - } - - /* If INSN is zero, then the search walked all the way through the - block without hitting anything interesting. This block is a - valid alternate exit block. */ - if (insn == NULL) - alternate_exit = e->src; - else - return_value_pseudo = NULL; - } - - /* If the function uses ADDRESSOF, we can't (easily) determine - at this point if the value will end up on the stack. */ - no_sibcalls_this_function |= sequence_uses_addressof (insns); - - /* Walk the insn chain and find any CALL_PLACEHOLDER insns. We need to - select one of the insn sequences attached to each CALL_PLACEHOLDER. - - The different sequences represent different ways to implement the call, - ie, tail recursion, sibling call or normal call. - - Since we do not create nested CALL_PLACEHOLDERs, the scan - continues with the insn that was after a replaced CALL_PLACEHOLDER; - we don't rescan the replacement insns. */ - for (insn = insns; insn; insn = NEXT_INSN (insn)) - { - if (GET_CODE (insn) == CALL_INSN - && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER) - { - int sibcall = (XEXP (PATTERN (insn), 1) != NULL_RTX); - int tailrecursion = (XEXP (PATTERN (insn), 2) != NULL_RTX); - basic_block call_block = BLOCK_FOR_INSN (insn); - - /* alloca (until we have stack slot life analysis) inhibits - sibling call optimizations, but not tail recursion. - Similarly if we use varargs or stdarg since they implicitly - may take the address of an argument. */ - if (current_function_calls_alloca || current_function_stdarg) - sibcall = 0; - - /* See if there are any reasons we can't perform either sibling or - tail call optimizations. We must be careful with stack slots - which are live at potential optimization sites. */ - if (no_sibcalls_this_function - /* ??? Overly conservative. */ - || frame_offset - /* Any function that calls setjmp might have longjmp called from - any called function. ??? We really should represent this - properly in the CFG so that this needn't be special cased. */ - || current_function_calls_setjmp - /* Can't if more than one successor or single successor is not - exit block. These two tests prevent tail call optimization - in the presence of active exception handlers. */ - || call_block->succ == NULL - || call_block->succ->succ_next != NULL - || (call_block->succ->dest != EXIT_BLOCK_PTR - && call_block->succ->dest != alternate_exit) - /* If this call doesn't end the block, there are operations at - the end of the block which we must execute after returning. */ - || ! call_ends_block_p (insn, BB_END (call_block))) - sibcall = 0, tailrecursion = 0; - - /* Select a set of insns to implement the call and emit them. - Tail recursion is the most efficient, so select it over - a tail/sibling call. */ - - if (sibcall || tailrecursion) - successful_replacement = true; - replaced_call_placeholder = true; - - replace_call_placeholder (insn, - tailrecursion != 0 - ? sibcall_use_tail_recursion - : sibcall != 0 - ? sibcall_use_sibcall - : sibcall_use_normal); - } - } - - if (successful_replacement) - { - rtx insn; - tree arg; - - /* A sibling call sequence invalidates any REG_EQUIV notes made for - this function's incoming arguments. - - At the start of RTL generation we know the only REG_EQUIV notes - in the rtl chain are those for incoming arguments, so we can safely - flush any REG_EQUIV note. - - This is (slight) overkill. We could keep track of the highest - argument we clobber and be more selective in removing notes, but it - does not seem to be worth the effort. */ - purge_reg_equiv_notes (); - - /* A sibling call sequence also may invalidate RTX_UNCHANGING_P - flag of some incoming arguments MEM RTLs, because it can write into - those slots. We clear all those bits now. - - This is (slight) overkill, we could keep track of which arguments - we actually write into. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - purge_mem_unchanging_flag (PATTERN (insn)); - } - - /* Similarly, invalidate RTX_UNCHANGING_P for any incoming - arguments passed in registers. */ - for (arg = DECL_ARGUMENTS (current_function_decl); - arg; - arg = TREE_CHAIN (arg)) - { - if (REG_P (DECL_RTL (arg))) - RTX_UNCHANGING_P (DECL_RTL (arg)) = false; - } - } - - /* There may have been NOTE_INSN_BLOCK_{BEGIN,END} notes in the - CALL_PLACEHOLDER alternatives that we didn't emit. Rebuild the - lexical block tree to correspond to the notes that still exist. */ - if (replaced_call_placeholder) - reorder_blocks (); - - /* This information will be invalid after inline expansion. Kill it now. */ - free_basic_block_vars (); - free_EXPR_LIST_list (&tail_recursion_label_list); -} diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 74377b64eb6..680ecafc21a 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -3784,11 +3784,6 @@ simplify_rtx (rtx x) return simplify_gen_subreg (mode, SUBREG_REG (x), GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x)); - if (code == CONSTANT_P_RTX) - { - if (CONSTANT_P (XEXP (x, 0))) - return const1_rtx; - } break; case RTX_OBJ: diff --git a/gcc/stmt.c b/gcc/stmt.c index 422fd054491..0baeb8ce272 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -385,15 +385,13 @@ struct stmt_status GTY(()) #define goto_fixup_chain (cfun->stmt->x_goto_fixup_chain) /* Nonzero if we are using EH to handle cleanups. */ -static int using_eh_for_cleanups_p = 0; +int using_eh_for_cleanups_p = 0; static int n_occurrences (int, const char *); static bool decl_conflicts_with_clobbers_p (tree, const HARD_REG_SET); static void expand_goto_internal (tree, rtx, rtx); static int expand_fixup (tree, rtx, rtx); -static rtx expand_nl_handler_label (rtx, rtx); static void expand_nl_goto_receiver (void); -static void expand_nl_goto_receivers (struct nesting *); static void fixup_gotos (struct nesting *, rtx, tree, rtx, int); static bool check_operand_nalternatives (tree, tree); static bool check_unique_operand_names (tree, tree); @@ -470,7 +468,12 @@ label_rtx (tree label) abort (); if (!DECL_RTL_SET_P (label)) - SET_DECL_RTL (label, gen_label_rtx ()); + { + rtx r = gen_label_rtx (); + SET_DECL_RTL (label, r); + if (FORCED_LABEL (label) || DECL_NONLOCAL (label)) + LABEL_PRESERVE_P (r) = 1; + } return DECL_RTL (label); } @@ -487,8 +490,7 @@ force_label_rtx (tree label) if (!function) abort (); - if (function != current_function_decl - && function != inline_function_decl) + if (function != current_function_decl) p = find_function_data (function); else p = cfun; @@ -555,12 +557,27 @@ void expand_label (tree label) { struct label_chain *p; + rtx label_r = label_rtx (label); do_pending_stack_adjust (); - emit_label (label_rtx (label)); + emit_label (label_r); if (DECL_NAME (label)) LABEL_NAME (DECL_RTL (label)) = IDENTIFIER_POINTER (DECL_NAME (label)); + if (DECL_NONLOCAL (label)) + { + expand_nl_goto_receiver (); + nonlocal_goto_handler_labels + = gen_rtx_EXPR_LIST (VOIDmode, label_r, + nonlocal_goto_handler_labels); + } + + if (FORCED_LABEL (label)) + forced_labels = gen_rtx_EXPR_LIST (VOIDmode, label_r, forced_labels); + + if (DECL_NONLOCAL (label) || FORCED_LABEL (label)) + maybe_set_first_label_num (label_r); + if (stack_block_stack != 0) { p = ggc_alloc (sizeof (struct label_chain)); @@ -570,26 +587,6 @@ expand_label (tree label) } } -/* Declare that LABEL (a LABEL_DECL) may be used for nonlocal gotos - from nested functions. */ - -void -declare_nonlocal_label (tree label) -{ - rtx slot = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0); - - nonlocal_labels = tree_cons (NULL_TREE, label, nonlocal_labels); - LABEL_PRESERVE_P (label_rtx (label)) = 1; - if (nonlocal_goto_handler_slots == 0) - { - emit_stack_save (SAVE_NONLOCAL, - &nonlocal_goto_stack_level, - PREV_INSN (tail_recursion_reentry)); - } - nonlocal_goto_handler_slots - = gen_rtx_EXPR_LIST (VOIDmode, slot, nonlocal_goto_handler_slots); -} - /* Generate RTL code for a `goto' statement with target label LABEL. LABEL should be a LABEL_DECL tree node that was or will later be defined with `expand_label'. */ @@ -597,91 +594,15 @@ declare_nonlocal_label (tree label) void expand_goto (tree label) { - tree context; - - /* Check for a nonlocal goto to a containing function. */ - context = decl_function_context (label); +#ifdef ENABLE_CHECKING + /* Check for a nonlocal goto to a containing function. Should have + gotten translated to __builtin_nonlocal_goto. */ + tree context = decl_function_context (label); if (context != 0 && context != current_function_decl) - { - struct function *p = find_function_data (context); - rtx label_ref = gen_rtx_LABEL_REF (Pmode, label_rtx (label)); - rtx handler_slot, static_chain, save_area, insn; - tree link; - - /* Find the corresponding handler slot for this label. */ - handler_slot = p->x_nonlocal_goto_handler_slots; - for (link = p->x_nonlocal_labels; TREE_VALUE (link) != label; - link = TREE_CHAIN (link)) - handler_slot = XEXP (handler_slot, 1); - handler_slot = XEXP (handler_slot, 0); - - p->has_nonlocal_label = 1; - current_function_has_nonlocal_goto = 1; - LABEL_REF_NONLOCAL_P (label_ref) = 1; - - /* Copy the rtl for the slots so that they won't be shared in - case the virtual stack vars register gets instantiated differently - in the parent than in the child. */ - - static_chain = copy_to_reg (lookup_static_chain (label)); - - /* Get addr of containing function's current nonlocal goto handler, - which will do any cleanups and then jump to the label. */ - handler_slot = copy_to_reg (replace_rtx (copy_rtx (handler_slot), - virtual_stack_vars_rtx, - static_chain)); - - /* Get addr of containing function's nonlocal save area. */ - save_area = p->x_nonlocal_goto_stack_level; - if (save_area) - save_area = replace_rtx (copy_rtx (save_area), - virtual_stack_vars_rtx, static_chain); - -#if HAVE_nonlocal_goto - if (HAVE_nonlocal_goto) - emit_insn (gen_nonlocal_goto (static_chain, handler_slot, - save_area, label_ref)); - else + abort (); #endif - { - emit_insn (gen_rtx_CLOBBER (VOIDmode, - gen_rtx_MEM (BLKmode, - gen_rtx_SCRATCH (VOIDmode)))); - emit_insn (gen_rtx_CLOBBER (VOIDmode, - gen_rtx_MEM (BLKmode, - hard_frame_pointer_rtx))); - - /* Restore frame pointer for containing function. - This sets the actual hard register used for the frame pointer - to the location of the function's incoming static chain info. - The non-local goto handler will then adjust it to contain the - proper value and reload the argument pointer, if needed. */ - emit_move_insn (hard_frame_pointer_rtx, static_chain); - emit_stack_restore (SAVE_NONLOCAL, save_area, NULL_RTX); - - /* USE of hard_frame_pointer_rtx added for consistency; - not clear if really needed. */ - emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); - emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx)); - emit_indirect_jump (handler_slot); - } - /* Search backwards to the jump insn and mark it as a - non-local goto. */ - for (insn = get_last_insn (); insn; insn = PREV_INSN (insn)) - { - if (GET_CODE (insn) == JUMP_INSN) - { - REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, - const0_rtx, REG_NOTES (insn)); - break; - } - else if (GET_CODE (insn) == CALL_INSN) - break; - } - } - else - expand_goto_internal (label, label_rtx (label), NULL_RTX); + expand_goto_internal (label, label_rtx (label), NULL_RTX); } /* Generate RTL code for a `goto' statement with target label BODY. @@ -1251,9 +1172,6 @@ parse_output_constraint (const char **constraint_p, int operand_num, break; } - if (*is_inout && !*allows_reg) - warning ("read-write constraint does not allow a register"); - return true; } @@ -1393,6 +1311,33 @@ parse_input_constraint (const char **constraint_p, int input_num, return true; } +/* INPUT is one of the input operands from EXPR, an ASM_EXPR. Returns true + if it is an operand which must be passed in memory (i.e. an "m" + constraint), false otherwise. */ + +bool +asm_op_is_mem_input (tree input, tree expr) +{ + const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (input))); + tree outputs = ASM_OUTPUTS (expr); + int noutputs = list_length (outputs); + const char **constraints + = (const char **) alloca ((noutputs) * sizeof (const char *)); + int i = 0; + bool allows_mem, allows_reg; + tree t; + + /* Collect output constraints. */ + for (t = outputs; t ; t = TREE_CHAIN (t), i++) + constraints[i] = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); + + /* We pass 0 for input_num, ninputs and ninout; they are only used for + error checking which will be done at expand time. */ + parse_input_constraint (&constraint, 0, 0, noutputs, 0, constraints, + &allows_mem, &allows_reg); + return (!allows_reg && allows_mem); +} + /* Check for overlap between registers marked in CLOBBERED_REGS and anything inappropriate in DECL. Emit error and return TRUE for error, FALSE for ok. */ @@ -1889,6 +1834,52 @@ expand_asm_operands (tree string, tree outputs, tree inputs, free_temp_slots (); } +void +expand_asm_expr (tree exp) +{ + int noutputs, i; + tree outputs, tail; + tree *o; + + if (ASM_INPUT_P (exp)) + { + expand_asm (ASM_STRING (exp), ASM_VOLATILE_P (exp)); + return; + } + + outputs = ASM_OUTPUTS (exp); + noutputs = list_length (outputs); + /* o[I] is the place that output number I should be written. */ + o = (tree *) alloca (noutputs * sizeof (tree)); + + /* Record the contents of OUTPUTS before it is modified. */ + for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++) + o[i] = TREE_VALUE (tail); + + /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of + OUTPUTS some trees for where the values were actually stored. */ + expand_asm_operands (ASM_STRING (exp), outputs, ASM_INPUTS (exp), + ASM_CLOBBERS (exp), ASM_VOLATILE_P (exp), + input_location); + + /* 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_assignment (o[i], TREE_VALUE (tail), 0); + free_temp_slots (); + + /* Restore the original value so that it's correct the next + time we expand this function. */ + TREE_VALUE (tail) = o[i]; + } + } + + /* Those MODIFY_EXPRs could do autoincrements. */ + emit_queue (); +} + /* A subroutine of expand_asm_operands. Check that all operands have the same number of alternatives. Return true if so. */ @@ -2150,7 +2141,7 @@ expand_expr_stmt_value (tree exp, int want_value, int maybe_last) { if (TREE_SIDE_EFFECTS (exp)) warn_if_unused_value (exp); - else if (!VOID_TYPE_P (TREE_TYPE (exp))) + else if (!VOID_TYPE_P (TREE_TYPE (exp)) && !TREE_NO_WARNING (exp)) warning ("%Hstatement with no effect", &emit_locus); } @@ -2242,7 +2233,7 @@ warn_if_unused_value (tree exp) return warn_if_unused_value (TREE_OPERAND (exp, 1)); case SAVE_EXPR: - return warn_if_unused_value (TREE_OPERAND (exp, 1)); + return warn_if_unused_value (TREE_OPERAND (exp, 0)); case TRUTH_ORIF_EXPR: case TRUTH_ANDIF_EXPR: @@ -2250,7 +2241,7 @@ warn_if_unused_value (tree exp) return warn_if_unused_value (TREE_OPERAND (exp, 1)); case COMPOUND_EXPR: - if (TREE_NO_UNUSED_WARNING (exp)) + if (TREE_NO_WARNING (exp)) return 0; if (warn_if_unused_value (TREE_OPERAND (exp, 0))) return 1; @@ -2263,7 +2254,7 @@ warn_if_unused_value (tree exp) case CONVERT_EXPR: case NON_LVALUE_EXPR: /* Don't warn about conversions not explicit in the user's program. */ - if (TREE_NO_UNUSED_WARNING (exp)) + if (TREE_NO_WARNING (exp)) return 0; /* Assignment to a cast usually results in a cast of a modify. Don't complain about that. There can be an arbitrary number of @@ -2508,7 +2499,6 @@ expand_start_loop (int exit_flag) do_pending_stack_adjust (); emit_queue (); - emit_note (NOTE_INSN_LOOP_BEG); emit_label (thisloop->data.loop.start_label); return thisloop; @@ -2558,7 +2548,6 @@ void expand_loop_continue_here (void) { do_pending_stack_adjust (); - emit_note (NOTE_INSN_LOOP_CONT); emit_label (loop_stack->data.loop.continue_label); } @@ -2573,10 +2562,6 @@ expand_end_loop (void) int eh_regions, debug_blocks; bool empty_test; - /* Mark the continue-point at the top of the loop if none elsewhere. */ - if (start_label == loop_stack->data.loop.continue_label) - emit_note_before (NOTE_INSN_LOOP_CONT, start_label); - do_pending_stack_adjust (); /* If the loop starts with a loop exit, roll that to the end where @@ -2584,7 +2569,6 @@ expand_end_loop (void) If the loop presently looks like this (in pseudo-C): - LOOP_BEG start_label: if (test) goto end_label; LOOP_END_TOP_COND @@ -2594,7 +2578,6 @@ expand_end_loop (void) transform it to look like: - LOOP_BEG goto start_label; top_label: body; @@ -2623,16 +2606,12 @@ expand_end_loop (void) if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_END_TOP_COND) break; - /* We must not walk into a nested loop. */ - else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_BEG) - { - etc_note = NULL_RTX; - break; - } + if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_LOOP_BEG) + abort (); /* At the same time, scan for EH region notes, as we don't want to scrog region nesting. This shouldn't happen, but... */ - else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_BEG) + if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_BEG) eh_regions++; else if (NOTE_LINE_NUMBER (etc_note) == NOTE_INSN_EH_REGION_END) { @@ -2672,12 +2651,6 @@ expand_end_loop (void) rtx top_label = gen_label_rtx (); rtx start_move = start_label; - /* If the start label is preceded by a NOTE_INSN_LOOP_CONT note, - then we want to move this note also. */ - if (GET_CODE (PREV_INSN (start_move)) == NOTE - && NOTE_LINE_NUMBER (PREV_INSN (start_move)) == NOTE_INSN_LOOP_CONT) - start_move = PREV_INSN (start_move); - emit_label_before (top_label, start_move); /* Actually move the insns. If the debug scopes are nested, we @@ -2709,8 +2682,10 @@ expand_end_loop (void) start_label = top_label; } + if (etc_note) + delete_insn (etc_note); + emit_jump (start_label); - emit_note (NOTE_INSN_LOOP_END); emit_label (loop_stack->data.loop.end_label); POPSTACK (loop_stack); @@ -3077,11 +3052,8 @@ expand_return (tree retval) else if ((TREE_CODE (retval) == MODIFY_EXPR || TREE_CODE (retval) == INIT_EXPR) && TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL) retval_rhs = TREE_OPERAND (retval, 1); - else if (VOID_TYPE_P (TREE_TYPE (retval))) - /* Recognize tail-recursive call to void function. */ - retval_rhs = retval; else - retval_rhs = NULL_TREE; + retval_rhs = retval; last_insn = get_last_insn (); @@ -3316,8 +3288,8 @@ tail_recursion_args (tree actuals, tree formals) for (a = actuals, f = formals, i = 0; a && f; a = TREE_CHAIN (a), f = TREE_CHAIN (f), i++) { - if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (a))) - != TYPE_MAIN_VARIANT (TREE_TYPE (f))) + if (!lang_hooks.types_compatible_p (TREE_TYPE (TREE_VALUE (a)), + TREE_TYPE (f))) return 0; if (GET_CODE (DECL_RTL (f)) != REG || DECL_MODE (f) == BLKmode) return 0; @@ -3409,7 +3381,7 @@ expand_start_bindings_and_block (int flags, tree block) abort (); /* Create a note to mark the beginning of the block. */ - if (block_flag) + if (block_flag && !cfun->dont_emit_block_notes) { note = emit_note (NOTE_INSN_BLOCK_BEG); NOTE_BLOCK (note) = block; @@ -3539,35 +3511,12 @@ current_nesting_level (void) return cfun ? block_stack : 0; } -/* Emit a handler label for a nonlocal goto handler. - Also emit code to store the handler label in SLOT before BEFORE_INSN. */ - -static rtx -expand_nl_handler_label (rtx slot, rtx before_insn) -{ - rtx insns; - rtx handler_label = gen_label_rtx (); - - /* Don't let cleanup_cfg delete the handler. */ - LABEL_PRESERVE_P (handler_label) = 1; - - start_sequence (); - emit_move_insn (slot, gen_rtx_LABEL_REF (Pmode, handler_label)); - insns = get_insns (); - end_sequence (); - emit_insn_before (insns, before_insn); - - emit_label (handler_label); - - return handler_label; -} - /* Emit code to restore vital registers at the beginning of a nonlocal goto handler. */ static void expand_nl_goto_receiver (void) { - /* Clobber the FP when we get here, so we have to make sure it's + /* Clobber the FP when we get here, so we have to make sure it's marked as used by this function. */ emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx)); @@ -3632,82 +3581,6 @@ expand_nl_goto_receiver (void) emit_insn (gen_rtx_ASM_INPUT (VOIDmode, "")); } -/* Make handlers for nonlocal gotos taking place in the function calls in - block THISBLOCK. */ - -static void -expand_nl_goto_receivers (struct nesting *thisblock) -{ - tree link; - rtx afterward = gen_label_rtx (); - rtx insns, slot; - rtx label_list; - int any_invalid; - - /* Record the handler address in the stack slot for that purpose, - during this block, saving and restoring the outer value. */ - if (thisblock->next != 0) - for (slot = nonlocal_goto_handler_slots; slot; slot = XEXP (slot, 1)) - { - rtx save_receiver = gen_reg_rtx (Pmode); - emit_move_insn (XEXP (slot, 0), save_receiver); - - start_sequence (); - emit_move_insn (save_receiver, XEXP (slot, 0)); - insns = get_insns (); - end_sequence (); - emit_insn_before (insns, thisblock->data.block.first_insn); - } - - /* Jump around the handlers; they run only when specially invoked. */ - emit_jump (afterward); - - /* Make a separate handler for each label. */ - link = nonlocal_labels; - slot = nonlocal_goto_handler_slots; - label_list = NULL_RTX; - for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1)) - /* Skip any labels we shouldn't be able to jump to from here, - we generate one special handler for all of them below which just calls - abort. */ - if (! DECL_TOO_LATE (TREE_VALUE (link))) - { - rtx lab; - lab = expand_nl_handler_label (XEXP (slot, 0), - thisblock->data.block.first_insn); - label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list); - - expand_nl_goto_receiver (); - - /* Jump to the "real" nonlocal label. */ - expand_goto (TREE_VALUE (link)); - } - - /* A second pass over all nonlocal labels; this time we handle those - we should not be able to jump to at this point. */ - link = nonlocal_labels; - slot = nonlocal_goto_handler_slots; - any_invalid = 0; - for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1)) - if (DECL_TOO_LATE (TREE_VALUE (link))) - { - rtx lab; - lab = expand_nl_handler_label (XEXP (slot, 0), - thisblock->data.block.first_insn); - label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list); - any_invalid = 1; - } - - if (any_invalid) - { - expand_nl_goto_receiver (); - expand_builtin_trap (); - } - - nonlocal_goto_handler_labels = label_list; - emit_label (afterward); -} - /* Warn about any unused VARS (which may contain nodes other than VAR_DECLs, but such nodes are ignored). The nodes are connected via the TREE_CHAIN field. */ @@ -3755,18 +3628,6 @@ expand_end_bindings (tree vars, int mark_ends, int dont_jump_in) emit_label (thisblock->exit_label); } - /* If necessary, make handlers for nonlocal gotos taking - place in the function calls in this block. */ - if (function_call_count != 0 && nonlocal_labels - /* Make handler for outermost block - if there were any nonlocal gotos to this function. */ - && (thisblock->next == 0 ? current_function_has_nonlocal_label - /* Make handler for inner block if it has something - special to do when you jump out of it. */ - : (thisblock->data.block.cleanups != 0 - || thisblock->data.block.stack_level != 0))) - expand_nl_goto_receivers (thisblock); - /* Don't allow jumping into a block that has a stack level. Cleanups are allowed, though. */ if (dont_jump_in > 0 @@ -3827,9 +3688,8 @@ expand_end_bindings (tree vars, int mark_ends, int dont_jump_in) { emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION, thisblock->data.block.stack_level, NULL_RTX); - if (nonlocal_goto_handler_slots != 0) - emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, - NULL_RTX); + if (cfun->nonlocal_goto_save_area) + update_nonlocal_goto_save_area (); } /* Any gotos out of this block must also do these things. @@ -3846,7 +3706,7 @@ expand_end_bindings (tree vars, int mark_ends, int dont_jump_in) We do this now, after running cleanups on the variables just going out of scope, so they are in scope for their cleanups. */ - if (mark_ends) + if (mark_ends && !cfun->dont_emit_block_notes) { rtx note = emit_note (NOTE_INSN_BLOCK_END); NOTE_BLOCK (note) = NOTE_BLOCK (thisblock->data.block.first_insn); @@ -4041,6 +3901,66 @@ expand_decl (tree decl) } } +/* Emit code to allocate T_SIZE bytes of dynamic stack space for ALLOC. */ +void +expand_stack_alloc (tree alloc, tree t_size) +{ + rtx address, dest, size; + tree var, type; + + if (TREE_CODE (alloc) != ADDR_EXPR) + abort (); + var = TREE_OPERAND (alloc, 0); + if (TREE_CODE (var) != VAR_DECL) + abort (); + + type = TREE_TYPE (var); + + /* In function-at-a-time mode, variable_size doesn't expand this, + so do it now. */ + if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type)) + expand_expr (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), + const0_rtx, VOIDmode, 0); + + /* Compute the variable's size, in bytes. */ + size = expand_expr (t_size, NULL_RTX, VOIDmode, 0); + free_temp_slots (); + + /* Allocate space on the stack for the variable. */ + address = XEXP (DECL_RTL (var), 0); + dest = allocate_dynamic_stack_space (size, address, TYPE_ALIGN (type)); + if (dest != address) + emit_move_insn (address, dest); + + /* Indicate the alignment we actually gave this variable. */ +#ifdef STACK_BOUNDARY + DECL_ALIGN (var) = STACK_BOUNDARY; +#else + DECL_ALIGN (var) = BIGGEST_ALIGNMENT; +#endif + DECL_USER_ALIGN (var) = 0; +} + +/* Emit code to save the current value of stack. */ +rtx +expand_stack_save (void) +{ + rtx ret = NULL_RTX; + + do_pending_stack_adjust (); + emit_stack_save (SAVE_BLOCK, &ret, NULL_RTX); + return ret; +} + +/* Emit code to restore the current value of stack. */ +void +expand_stack_restore (tree var) +{ + rtx sa = DECL_RTL (var); + + emit_stack_restore (SAVE_BLOCK, sa, NULL_RTX); +} + /* Emit code to perform the initialization of a declaration DECL. */ void @@ -4364,6 +4284,23 @@ last_cleanup_this_contour (void) return block_stack->data.block.cleanups; } + +/* Return nonzero if any containing block has a stack level or + cleanups. */ + +int +containing_blocks_have_cleanups_or_stack_level (void) +{ + struct nesting *block; + + for (block = block_stack; block; block = block->next) + if (block->data.block.stack_level != 0 + || block->data.block.cleanups != 0) + return 1; + + return 0; +} + /* Return 1 if there are any pending cleanups at this point. Check the current contour as well as contours that enclose the current contour. */ @@ -4526,7 +4463,7 @@ pushcase (tree value, tree (*converter) (tree, tree), tree label, || ! int_fits_type_p (value, index_type))) return 3; - return add_case_node (value, value, label, duplicate); + return add_case_node (value, value, label, duplicate, false); } /* Like pushcase but this case applies to all values between VALUE1 and @@ -4592,7 +4529,7 @@ pushcase_range (tree value1, tree value2, tree (*converter) (tree, tree), || ! int_fits_type_p (value2, index_type)) return 3; - return add_case_node (value1, value2, label, duplicate); + return add_case_node (value1, value2, label, duplicate, false); } /* Do the actual insertion of a case label for pushcase and pushcase_range @@ -4600,7 +4537,8 @@ pushcase_range (tree value1, tree value2, tree (*converter) (tree, tree), slowdown for large switch statements. */ int -add_case_node (tree low, tree high, tree label, tree *duplicate) +add_case_node (tree low, tree high, tree label, tree *duplicate, + bool dont_expand_label) { struct case_node *p, **q, *r; @@ -4619,7 +4557,8 @@ add_case_node (tree low, tree high, tree label, tree *duplicate) return 2; } case_stack->data.case_stmt.default_label = label; - expand_label (label); + if (!dont_expand_label) + expand_label (label); return 0; } @@ -4658,7 +4597,8 @@ add_case_node (tree low, tree high, tree label, tree *duplicate) r->high = high; r->code_label = label; - expand_label (label); + if (!dont_expand_label) + expand_label (label); *q = r; r->parent = p; @@ -4834,326 +4774,6 @@ add_case_node (tree low, tree high, tree label, tree *duplicate) return 0; } - -/* Returns the number of possible values of TYPE. - Returns -1 if the number is unknown, variable, or if the number does not - fit in a HOST_WIDE_INT. - Sets *SPARSENESS to 2 if TYPE is an ENUMERAL_TYPE whose values - do not increase monotonically (there may be duplicates); - to 1 if the values increase monotonically, but not always by 1; - otherwise sets it to 0. */ - -HOST_WIDE_INT -all_cases_count (tree type, int *sparseness) -{ - tree t; - HOST_WIDE_INT count, minval, lastval; - - *sparseness = 0; - - switch (TREE_CODE (type)) - { - case BOOLEAN_TYPE: - count = 2; - break; - - case CHAR_TYPE: - count = 1 << BITS_PER_UNIT; - break; - - default: - case INTEGER_TYPE: - if (TYPE_MAX_VALUE (type) != 0 - && 0 != (t = fold (build (MINUS_EXPR, type, TYPE_MAX_VALUE (type), - TYPE_MIN_VALUE (type)))) - && 0 != (t = fold (build (PLUS_EXPR, type, t, - convert (type, integer_zero_node)))) - && host_integerp (t, 1)) - count = tree_low_cst (t, 1); - else - return -1; - break; - - case ENUMERAL_TYPE: - /* Don't waste time with enumeral types with huge values. */ - if (! host_integerp (TYPE_MIN_VALUE (type), 0) - || TYPE_MAX_VALUE (type) == 0 - || ! host_integerp (TYPE_MAX_VALUE (type), 0)) - return -1; - - lastval = minval = tree_low_cst (TYPE_MIN_VALUE (type), 0); - count = 0; - - for (t = TYPE_VALUES (type); t != NULL_TREE; t = TREE_CHAIN (t)) - { - HOST_WIDE_INT thisval = tree_low_cst (TREE_VALUE (t), 0); - - if (*sparseness == 2 || thisval <= lastval) - *sparseness = 2; - else if (thisval != minval + count) - *sparseness = 1; - - lastval = thisval; - count++; - } - } - - return count; -} - -#define BITARRAY_TEST(ARRAY, INDEX) \ - ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\ - & (1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR))) -#define BITARRAY_SET(ARRAY, INDEX) \ - ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\ - |= 1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR)) - -/* Set the elements of the bitstring CASES_SEEN (which has length COUNT), - with the case values we have seen, assuming the case expression - has the given TYPE. - SPARSENESS is as determined by all_cases_count. - - The time needed is proportional to COUNT, unless - SPARSENESS is 2, in which case quadratic time is needed. */ - -void -mark_seen_cases (tree type, unsigned char *cases_seen, HOST_WIDE_INT count, - int sparseness) -{ - tree next_node_to_try = NULL_TREE; - HOST_WIDE_INT next_node_offset = 0; - - struct case_node *n, *root = case_stack->data.case_stmt.case_list; - tree val = make_node (INTEGER_CST); - - TREE_TYPE (val) = type; - if (! root) - /* Do nothing. */ - ; - else if (sparseness == 2) - { - tree t; - unsigned HOST_WIDE_INT xlo; - - /* This less efficient loop is only needed to handle - duplicate case values (multiple enum constants - with the same value). */ - TREE_TYPE (val) = TREE_TYPE (root->low); - for (t = TYPE_VALUES (type), xlo = 0; t != NULL_TREE; - t = TREE_CHAIN (t), xlo++) - { - TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (TREE_VALUE (t)); - TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (TREE_VALUE (t)); - n = root; - do - { - /* Keep going past elements distinctly greater than VAL. */ - if (tree_int_cst_lt (val, n->low)) - n = n->left; - - /* or distinctly less than VAL. */ - else if (tree_int_cst_lt (n->high, val)) - n = n->right; - - else - { - /* We have found a matching range. */ - BITARRAY_SET (cases_seen, xlo); - break; - } - } - while (n); - } - } - else - { - if (root->left) - case_stack->data.case_stmt.case_list = root = case_tree2list (root, 0); - - for (n = root; n; n = n->right) - { - TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low); - TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low); - while (! tree_int_cst_lt (n->high, val)) - { - /* Calculate (into xlo) the "offset" of the integer (val). - The element with lowest value has offset 0, the next smallest - element has offset 1, etc. */ - - unsigned HOST_WIDE_INT xlo; - HOST_WIDE_INT xhi; - tree t; - - if (sparseness && TYPE_VALUES (type) != NULL_TREE) - { - /* The TYPE_VALUES will be in increasing order, so - starting searching where we last ended. */ - t = next_node_to_try; - xlo = next_node_offset; - xhi = 0; - for (;;) - { - if (t == NULL_TREE) - { - t = TYPE_VALUES (type); - xlo = 0; - } - if (tree_int_cst_equal (val, TREE_VALUE (t))) - { - next_node_to_try = TREE_CHAIN (t); - next_node_offset = xlo + 1; - break; - } - xlo++; - t = TREE_CHAIN (t); - if (t == next_node_to_try) - { - xlo = -1; - break; - } - } - } - else - { - t = TYPE_MIN_VALUE (type); - if (t) - neg_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t), - &xlo, &xhi); - else - xlo = xhi = 0; - add_double (xlo, xhi, - TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val), - &xlo, &xhi); - } - - if (xhi == 0 && xlo < (unsigned HOST_WIDE_INT) count) - BITARRAY_SET (cases_seen, xlo); - - add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val), - 1, 0, - &TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val)); - } - } - } -} - -/* Given a switch statement with an expression that is an enumeration - type, warn if any of the enumeration type's literals are not - covered by the case expressions of the switch. Also, warn if there - are any extra switch cases that are *not* elements of the - enumerated type. - - Historical note: - - At one stage this function would: ``If all enumeration literals - were covered by the case expressions, turn one of the expressions - into the default expression since it should not be possible to fall - through such a switch.'' - - That code has since been removed as: ``This optimization is - disabled because it causes valid programs to fail. ANSI C does not - guarantee that an expression with enum type will have a value that - is the same as one of the enumeration literals.'' */ - -void -check_for_full_enumeration_handling (tree type) -{ - struct case_node *n; - tree chain; - - /* True iff the selector type is a numbered set mode. */ - int sparseness = 0; - - /* The number of possible selector values. */ - HOST_WIDE_INT size; - - /* For each possible selector value. a one iff it has been matched - by a case value alternative. */ - unsigned char *cases_seen; - - /* The allocated size of cases_seen, in chars. */ - HOST_WIDE_INT bytes_needed; - - size = all_cases_count (type, &sparseness); - bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR; - - if (size > 0 && size < 600000 - /* We deliberately use calloc here, not cmalloc, so that we can suppress - this optimization if we don't have enough memory rather than - aborting, as xmalloc would do. */ - && (cases_seen = really_call_calloc (bytes_needed, 1)) != NULL) - { - HOST_WIDE_INT i; - tree v = TYPE_VALUES (type); - - /* The time complexity of this code is normally O(N), where - N being the number of members in the enumerated type. - However, if type is an ENUMERAL_TYPE whose values do not - increase monotonically, O(N*log(N)) time may be needed. */ - - mark_seen_cases (type, cases_seen, size, sparseness); - - for (i = 0; v != NULL_TREE && i < size; i++, v = TREE_CHAIN (v)) - if (BITARRAY_TEST (cases_seen, i) == 0) - warning ("enumeration value `%s' not handled in switch", - IDENTIFIER_POINTER (TREE_PURPOSE (v))); - - free (cases_seen); - } - - /* Now we go the other way around; we warn if there are case - expressions that don't correspond to enumerators. This can - occur since C and C++ don't enforce type-checking of - assignments to enumeration variables. */ - - if (case_stack->data.case_stmt.case_list - && case_stack->data.case_stmt.case_list->left) - case_stack->data.case_stmt.case_list - = case_tree2list (case_stack->data.case_stmt.case_list, 0); - for (n = case_stack->data.case_stmt.case_list; n; n = n->right) - { - for (chain = TYPE_VALUES (type); - chain && !tree_int_cst_equal (n->low, TREE_VALUE (chain)); - chain = TREE_CHAIN (chain)) - ; - - if (!chain) - { - if (TYPE_NAME (type) == 0) - warning ("case value `%ld' not in enumerated type", - (long) TREE_INT_CST_LOW (n->low)); - else - warning ("case value `%ld' not in enumerated type `%s'", - (long) TREE_INT_CST_LOW (n->low), - IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type)) - == IDENTIFIER_NODE) - ? TYPE_NAME (type) - : DECL_NAME (TYPE_NAME (type)))); - } - if (!tree_int_cst_equal (n->low, n->high)) - { - for (chain = TYPE_VALUES (type); - chain && !tree_int_cst_equal (n->high, TREE_VALUE (chain)); - chain = TREE_CHAIN (chain)) - ; - - if (!chain) - { - if (TYPE_NAME (type) == 0) - warning ("case value `%ld' not in enumerated type", - (long) TREE_INT_CST_LOW (n->high)); - else - warning ("case value `%ld' not in enumerated type `%s'", - (long) TREE_INT_CST_LOW (n->high), - IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type)) - == IDENTIFIER_NODE) - ? TYPE_NAME (type) - : DECL_NAME (TYPE_NAME (type)))); - } - } - } -} - /* Maximum number of case bit tests. */ #define MAX_CASE_BIT_TESTS 3 @@ -5357,19 +4977,6 @@ expand_end_case_type (tree orig_index, tree orig_type) /* An ERROR_MARK occurs for various reasons including invalid data type. */ if (index_type != error_mark_node) { - /* If the switch expression was an enumerated type, check that - exactly all enumeration literals are covered by the cases. - The check is made when -Wswitch was specified and there is no - default case, or when -Wswitch-enum was specified. */ - if (((warn_switch && !thiscase->data.case_stmt.default_label) - || warn_switch_enum) - && TREE_CODE (orig_type) == ENUMERAL_TYPE - && TREE_CODE (index_expr) != INTEGER_CST) - check_for_full_enumeration_handling (orig_type); - - if (warn_switch_default && !thiscase->data.case_stmt.default_label) - warning ("switch missing default case"); - /* If we don't have a default-label, create one here, after the body of the switch. */ if (thiscase->data.case_stmt.default_label == 0) @@ -5796,6 +5403,7 @@ estimate_case_costs (case_node_ptr node) static bool same_case_target_p (rtx l1, rtx l2) { +#if 0 rtx i1, i2; if (l1 == l2) @@ -5815,6 +5423,11 @@ same_case_target_p (rtx l1, rtx l2) { l2 = XEXP (SET_SRC (PATTERN (i2)), 0); } +#endif + /* When coming from gimple, we usually won't have emitted either + the labels or the body of the switch statement. The job being + done here should be done via jump threading at the tree level. + Cases that go the same place should have the same label. */ return l1 == l2; } @@ -5848,9 +5461,11 @@ group_case_nodes (case_node_ptr head) while (node) { - rtx lab = label_rtx (node->code_label); + rtx lab; case_node_ptr np = node; + lab = label_rtx (node->code_label); + /* Try to group the successors of NODE with NODE. */ while (((np = np->right) != 0) /* Do they jump to the same place? */ diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index 33d0a86e90d..13f95a44ff5 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -67,8 +67,6 @@ static int excess_unit_span (HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT, tree); #endif static void force_type_save_exprs_1 (tree); -static unsigned int update_alignment_for_field (record_layout_info, tree, - unsigned int); extern void debug_rli (record_layout_info); /* SAVE_EXPRs for sizes of types and decls, waiting to be expanded. */ @@ -161,6 +159,11 @@ variable_size (tree size) if (TREE_CODE (save) == SAVE_EXPR) SAVE_EXPR_PERSISTENT_P (save) = 1; + if (!immediate_size_expand && cfun && cfun->x_dont_save_pending_sizes_p) + /* The front-end doesn't want us to keep a list of the expressions + that determine sizes for variable size objects. Trust it. */ + return size; + if (lang_hooks.decls.global_bindings_p ()) { if (TREE_CONSTANT (size)) @@ -173,10 +176,6 @@ variable_size (tree size) if (immediate_size_expand) expand_expr (save, const0_rtx, VOIDmode, 0); - else if (cfun != 0 && cfun->x_dont_save_pending_sizes_p) - /* The front-end doesn't want us to keep a list of the expressions - that determine sizes for variable size objects. */ - ; else put_pending_size (save); @@ -722,7 +721,7 @@ rli_size_so_far (record_layout_info rli) variable alignment fields in RLI, and return the alignment to give the FIELD. */ -static unsigned int +unsigned int update_alignment_for_field (record_layout_info rli, tree field, unsigned int known_align) { @@ -1559,6 +1558,9 @@ layout_type (tree type) if (type == 0) abort (); + if (type == error_mark_node) + return; + /* Do nothing if type has been laid out before. */ if (TYPE_SIZE (type)) return; diff --git a/gcc/system.h b/gcc/system.h index 6e2a26d205f..56aeb25fa0b 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -638,6 +638,7 @@ typedef char _Bool; LINKER_DOES_NOT_WORK_WITH_DWARF2 FUNCTION_ARG_KEEP_AS_REFERENCE \ GIV_SORT_CRITERION MAX_LONG_TYPE_SIZE MAX_LONG_DOUBLE_TYPE_SIZE \ MAX_WCHAR_TYPE_SIZE GCOV_TYPE_SIZE SHARED_SECTION_ASM_OP \ + INTEGRATE_THRESHOLD \ FINAL_REG_PARM_STACK_SPACE MAYBE_REG_PARM_STACK_SPACE \ TRADITIONAL_PIPELINE_INTERFACE DFA_PIPELINE_INTERFACE \ DBX_OUTPUT_STANDARD_TYPES BUILTIN_SETJMP_FRAME_VALUE \ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9d72267b592..7f62d4b07db 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-05-13 Diego Novillo + + Merge from tree-ssa-20020619-branch. See + ChangeLog.tree-ssa for details. + 2004-05-11 Ziemowit Laski * g++.dg/ext/altivec-8.C: Use '-maltivec' instead of '-faltivec'; diff --git a/gcc/testsuite/ChangeLog.tree-ssa b/gcc/testsuite/ChangeLog.tree-ssa new file mode 100644 index 00000000000..03ccbb01ed2 --- /dev/null +++ b/gcc/testsuite/ChangeLog.tree-ssa @@ -0,0 +1,1204 @@ +2004-05-07 Diego Novillo + + * g++.old-deja/g++.ext/arrnew2.C: Restore XFAIL. It's broken + on mainline too. + +2004-05-06 Richard Henderson + + * gcc.dg/tree-ssa/20031015-1.c: Rewrite for all targets. Look at + alias dump for two VDEFs. + + * gcc.dg/tree-ssa/20040210-1.c: Tweak scan pattern to look for ifs. + +2004-05-05 Diego Novillo + + * g++.dg/parse/stack1.C: Remove XFAIL. + * g++.old-deja/g++.bugs/900205_03.C: Likewise. + * g++.old-deja/g++.ext/arrnew2.C: Likewise. + * g++.old-deja/g++.mike/p646.C: Likewise. + * gcc.c-torture/execute/string-opt-19.x: Remove. + +2004-05-05 Andrew Pinski + + PR c/15062 + * gcc.c-torture/compile/pr15062.c: New test. + +2004-05-03 Andrew Pinski + + PR optimization/15245 + * gcc.c-torture/compile/pr15245.c: New test. + +2004-05-03 Diego Novillo + + * gcc.dg/tree-ssa/20040430-1.c: New test. + +2004-04-26 Bud Davis + + PR fortran/14056 + * gfortran.fortran-torture/execute/spec_abs.f90: Add new test. + +2004-04-25 Bud Davis + + PR fortran/14942 + * gfortran.fortran-torture/execute/list_read_1.f90: Add new test. + +2004-04-24 Victor Leikehman + + * gfortran.fortran-torture/execute/der_io.f90: New test. + +2004-04-24 Bud Davis + + PR fortran/15113 + * gfortran.fortran-torture/execute/a_edit_1.f90: Add new test. + +2004-04-23 Andrew Pinski + + * gcc.c-torture/execute/20040423-1.c: New test. + +2004-04-22 Bud Davis + + PR fortran/14906 + * gfortran.fortran-torture/execute/empty_format.f90: Add new test. + +2004-04-21 Ben Elliston + + PR middle-end/14730 + * gcc.c-torture/compile/pr14730.c: New test. + +2004-04-24 Tobias Schlüter + + * execute/intrinsic_count.f90: Fix typo. + * execute/intrinsic_mmloc.f90: Fix typo. + +2004-04-18 Feng Wang + + PR fortran/14921 + PR fortran/14540 + * gfortran.fortran-torture/execute/math.f90: Add atan2 and clog + simplify test. + +2004-04-15 Andrew Pinski + + * gcc.c-torture/compile/20040415-1.c: New test. + * gcc.c-torture/compile/20040415-2.c: New test. + +2004-04-11 Bud Davis + + PR fortran/14904 + * gfortran.fortran-torture/execute/inquire_4.f90: New test. + +2004-04-11 Bud Davis + + PR fortran/14901 + * gfortran.fortran-torture/execute/internal_write.f90: New test. + +2004-04-11 Bud Davis + + PR gfortran/14872 + * gfortran.fortran-torture/execute/direct_io.f90: Add new test. + +2004-04-11 Feng Wang + + PR fortran/14377 + * gfortran.fortran-torture/execute/intrinsic_minmax.f90: Add new test. + +2004-04-08 Brian Booth + + * gcc.dg/tree-ssa/20040408-1.c: New test. + +2004-04-08 Diego Novillo + + * gcc.dg/tree-ssa/20040326-2.c (boz): Add call to abort. + +2004-04-07 Diego Novillo + + * gcc.dg/tree-ssa/20040326-2.c: Update to test for correct + gimplification of function call expressions. + +2004-04-07 Diego Novillo + + * gcc.dg/tree-ssa/20040326-2.c: New test. + +2003-04-04 Paul Brook + + PR 13252 + PR 14081 + * gfortran.fortran-torture/execute/strarray_1.f90: New test. + * gfortran.fortran-torture/execute/strarray_2.f90: New test. + * gfortran.fortran-torture/execute/strarray_3.f90: New test. + * gfortran.fortran-torture/execute/strarray_4.f90: New test. + * gfortran.fortran-torture/execute/strcommon_1.f90: New test. + +2004-04-04 Paul Brook + + * lib/fortran-torture.exp (TORTURE_OPTIONS): Remove -fg77-calls. + +2004-04-03 Bud Davis + + PR gfortran/14762 + * gfortran.fortran-torture/execute/slash_edit.f90: New test. + +2004-04-03 Bud Davis + + PR gfortran/14386 + * gfortran.fortran-torture/execute/inquire_3.f90: New test. + +2004-04-03 Bud Davis + + PR gfortran/14837 + * gfortran.fortran-torture/execute/inquire_2.f90: New test. + +2004-04-03 Andrew Pinski + + * lib/gfortran.exp: Sync LD_LIBRARY_PATH part from + lib/g++.exp. + +2004-04-03 Bud Davis + + PR 14831 + * gfortran.fortran-torture/execute/inquire_1.f90: New test. + +2004-04-03 Paolo Bonzini + + * gcc.dg/tree-ssa/20040324-1.c: New test. + +2004-04-01 Jeff Law + + * gcc.c-torture/compile/20040401-1.c: New test. + +2004-04-01 Bud Davis + + PR 14746 + * gfortran.fortran-torture/execute/f2_edit_1.f90: New test. + +2004-04-01 Bud Davis + + PR gfortran/14565 + * gfortran.fortran-torture/execute/unopened_unit_1.f90: New test. + +2004-03-30 Richard Henderson + + * gcc.dg/uninit-1.c, gcc.dg/uninit-3.c, gcc.dg/uninit-8.c, + gcc.dg/uninit-9.c: Remove XFAIL. + +2004-03-26 Jeff Law + + * gcc.dg/tree-ssa/20040326-1.c: New test. + +2004-03-24 Paul Brook + + * gfortran.fortran-torture/execute/csqrt_1.f90: Use f95 style + comments. + +2004-03-24 Bud Davis + + PR 14334 + * gfortran.fortran-torture/execute/write_logical_1.f90: New test. + +2004-03-24 Bud Davis + + PR 13919 + * gfortran.fortran-torture/execute/read_eof.f90: New test. + +2004-03-24 Bud Davis + + PR 14396 + * gfortran.fortran-torture/execute/csqrt_1.f90: New test. + +2004-02-24 Paul Brook + + PR 14055 + * gfortran.fortran-torture/execute/plusconst_1.f90: New test. + +2004-03-23 Diego Novillo + + * gcc.c-torture/20040420-1.c: Move and rename ... + * gcc.c-torture/compile/20040220-1.c ... here. + +2004-03-23 Zdenek Dvorak + + * gcc.dg/tree-ssa/20040211-1.c: Update outcome. + * gcc.dg/tree-ssa/ssa-dce-3.c: New test. + +2004-03-19 Diego Novillo + + PR optimization/14643 + * gcc.dg/tree-ssa/20040319-1.c: New test. + +2004-03-19 Jeff Law + + * gcc.c-torture/execute/20040319-1.c: New test. + +2004-03-17 Jeff Law + + * gcc.c-torture/compile/20040317-1.c: New test. + * gcc.c-torture/compile/20040317-2.c: New test. + * gcc.c-torture/compile/20040317-3.c: New test. + +2004-03-17 Diego Novillo + + PR optimization/14511 + * g++.dg/tree-ssa/20040317-1.C: New test. + +2004-03-13 Diego Novillo + + PR optimization/14553 + * gcc.dg/tree-ssa/20040313-1.c: New test. + +2004-03-11 Kazu Hirata + + * gcc.dg/tree-ssa/20040305-1.c: Change a constant to fit in a + 16-bit int. + +2004-03-10 Andrew Pinski + + PR c/14475 + * gcc.dg/pr14475.c: New test. + +2004-03-09 Jeff Law + + * gcc.c-torture/compile/20040309-1.c: New test. + +2004-03-05 Jeff Law + + * gcc.dg/tree-ssa/20040305-1.c: New test. + +2004-03-04 Jeff Law + + * gcc.c-torture/20040304-1.c: New test. + +2004-03-03 Jeff Law + + * gcc.c-torture/20040303-1.c: New test. + * gcc.c-torture/20040303-2.c: New test. + +2004-03-02 Zdenek Dvorak + + * gcc.dg/tree-ssa/tailrecursion-5.c: New test. + +2004-03-02 Diego Novillo + + * testsuite/gcc.dg/tree-ssa/20030815-1.c: Expect 1 type cast. + * testsuite/gcc.dg/tree-ssa/ssa-dce-1.c: Check after aliasing. + * testsuite/gcc.dg/tree-ssa/ssa-dce-2.c: Likewise. + * testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c: Likewise. + +2004-03-02 Diego Novillo + + * gcc.dg/tree-ssa/20040302-1.c: New test. + +2004-02-10 Jeff Law + + * gcc.dg/tree-ssa/20040211-1.c: Update slightly. + +2004-02-27 Richard Henderson + + * gcc.dg/warn-1.c: Update warning line. + * gcc.dg/tree-ssa/20030730-1.c: Declare ggc_alloc. + * gcc.dg/tree-ssa/20030730-2.c: Likewise. + * gcc.dg/tree-ssa/20030917-2.c: Fix int->pointer cast. + * gcc.dg/tree-ssa/20030922-2.c: XFAIL. + +2004-02-27 Diego Novillo + + * gcc.dg/tree-ssa/tailcall-2.c: New test. + +2004-02-20 Zdenek Dvorak + + * gcc.dg/tree-ssa/copy-headers.c: New test. + * gcc.dg/tree-ssa/20030711-1.c: Update outcome. + * gcc.dg/tree-ssa/20030714-2.c: Ditto. + * gcc.dg/tree-ssa/20030807-3.c: Ditto. + +2004-02-10 Jeff Law + + * gcc.c-torture/compile/20040219-1.c: New test. + +2004-02-16 Jeff Law + + * gcc.dg/tree-ssa/20030807-4.c: Remove bogus test. + + * gcc.dg/tree-ssa/20040216-1.c: New test. + * gcc.dg/tree-ssa/20040211-1.c: New test. + +2004-02-15 Paul Brook + + PR fortran/13433 + * gfortran.fortran-torture/execute/straret.f90: New test. + +2004-02-14 Richard Henderson + + * gcc.c-torture/execute/20030120-3.c: Remove duplicate of 920415-1.c. + +2004-02-11 Jeff Law + + * gcc.dg/tree-ssa/20040210-1.c: New test. + +2004-02-10 Diego Novillo + + * gcc.c-torture/execute/20000603-1.c: Resolve alias ambiguity and + point to DR#236. + +2004-02-09 Richard Henderson + + * gcc.dg/noreturn-1.c: Adjust line numbers on warnings. + * gcc.dg/noreturn-4.c: Likewise. + * gcc.dg/noreturn-7.c: Likewise. Adjust warnings for + changes to tail-call optimizations. + * gcc.dg/return-type-3.c: Turn on optimization. + * gcc.dg/uninit-6.c: Adjust line numbers on warnings. + * gcc.dg/uninit-8.c: XFAIL. + +2004-02-09 Feng Wang + + * gfortran.fortran-torture/execute/specifics.f90: Fix mod type. + +2004-02-09 Zdenek Dvorak + Jeff Law + + * gcc.dg/tree-ssa/20040209-2.c: New test. + +2004-02-06 Feng Wang + + * gfortran.fortran-torture/execute/intrinsic_dotprod.f90: Add complex + test. + +2004-02-07 Bud Davis + + PR libfortran/14038 + * gfortran.fortran-torture/execute/holletith.f90: New test. + +2004-02-06 Andrew Pinski + + PR middle-end/13127 + * gcc.dg/20040206-1.c: New test. + +2004-02-04 Richard Henderson + + * g++.dg/opt/bool1.C: Declare abort. + +2004-02-04 Richard Henderson + + * gcc.dg/tree-ssa/ssa-ccp-10.c: Look at fab dump. + +2004-02-03 Richard Henderson + + * gcc.dg/tree-ssa/20040204-1.c: Rename from ssa-ccp-5.c. + Look at .optimized output. XFAIL. + * gcc.dg/tree-ssa/ssa-ccp-11.c: XFAIL. + * gcc.dg/tree-ssa/ssa-ccp-3.c: XFAIL. + * gcc.dg/tree-ssa/ssa-ccp-4.c: Remove. + * gcc.dg/tree-ssa/ssa-ccp-6.c: Remove. + * gcc.dg/tree-ssa/ssa-ccp-8.c: Remove. + + * gcc.dg/tree-ssa/20030731-1.c: XFAIL. + * gcc.dg/tree-ssa/20030814-6.c: XFAIL. + * gcc.dg/tree-ssa/20031106-1.c: XFAIL. + * gcc.dg/tree-ssa/20031106-2.c: XFAIL. + * gcc.dg/tree-ssa/20031106-3.c: XFAIL. + * gcc.dg/tree-ssa/20031106-4.c: XFAIL. + * gcc.dg/tree-ssa/20031106-5.c: XFAIL. + * gcc.dg/tree-ssa/20031106-6.c: XFAIL. + * gcc.dg/tree-ssa/sra-2.c: XFAIL. + * gcc.dg/tree-ssa/sra-3.c: XFAIL. + + * gcc.dg/i386-ssetype-1.c: XFAIL. + * gcc.dg/i386-ssetype-3.c: XFAIL. + +2004-02-03 Steven Bosscher + + * gcc.dg/tree-ssa/20030709-2.c: Replace `dce4' with `cddce' for + tree dump scans. + * gcc.dg/tree-ssa/20030808-1.c: Likewise. + +2004-01-31 Canqun Yang + + * gfortran.fortran-torture/execute/intrinsic_mmloc_4.f90: + Delete print statements. + +2004-01-25 Richard Henderson + + * gcc.c-torture/execute/930529-1.x: Disable, update commentary. + +2004-01-21 Richard Henderson + + * gcc.dg/tree-ssa/asm-1.c: Fix memory constaint. + +2004-01-21 Dale Johannesen + + * gcc.dg/tree-ssa/20040121-1.c: New test. + +2004-01-17 Richard Henderson + + * gcc.c-torture/execute/string-opt-18.x: Remove. + * gcc.dg/uninit-2.c, gcc.dg/uninit-4.c: Don't XFAIL. + * gcc.dg/uninit-5.c, gcc.dg/uninit-8.c: Likewise. + +2004-01-16 Steven Bosscher + + * gcc.dg/tree-ssa/20030709-2.c, gcc.dg/tree-ssa/20030808-1.c: + Update for extra DCE pass. + +2004-01-15 Jeff Law + + * gcc.dg/tree-ssa/20030807-1.c: Update due to improvements in + jump threading. + +2004-01-12 Richard Henderson + + * gcc.dg/tree-ssa/20030808-1.c: Fix dump option. + * gcc.dg/tree-ssa/20031015-1.c: Update dump name. + * gcc.dg/tree-ssa/tailcall-1.c, gcc.dg/tree-ssa/tailrecursion-1.c, + gcc.dg/tree-ssa/tailrecursion-2.c, gcc.dg/tree-ssa/tailrecursion-3.c, + gcc.dg/tree-ssa/tailrecursion-4.c: Likewise. + +2004-01-11 Paul Brook + + * gfortran.fortran-torture/execute/emptyif.f90: New test. + +2004-01-11 Feng Wang + + * gfortran.fortran-torture/execute/cmplx.f90: Add dcmplx test. + +2004-01-10 Paul Brook + + * gfortran.fortran-torture/execute/mystery_proc.f90: New test. + * gfortran.fortran-torture/compile/mystery_proc.f90: Remove. + +2004-01-10 Paul Brook + + * gfortran.fortran-torture/execute/intrinsic_minmax.f90: Test + specific names. + +2004-01-10 Paul Brook + + * gfortran.fortran-torture/execute/intrinsic_transpose.f90: Test + complex variables. + +2004-01-09 Steven Bosscher + + * gcc.dg/tree-ssa/useless-1.c: New test. + +2004-01-07 Diego Novillo + + * gcc.dg/tree-ssa/20030530-2.c: Adjust dump file patterns. + * gcc.dg/tree-ssa/20030611-1.c: Likewise. + * gcc.dg/tree-ssa/20030703-1.c: Likewise. + * gcc.dg/tree-ssa/20030703-2.c: Likewise. + * gcc.dg/tree-ssa/20030708-1.c: Likewise. + * gcc.dg/tree-ssa/20030709-2.c: Likewise. + * gcc.dg/tree-ssa/20030709-3.c: Likewise. + * gcc.dg/tree-ssa/20030710-1.c: Likewise. + * gcc.dg/tree-ssa/20030711-1.c: Likewise. + * gcc.dg/tree-ssa/20030711-2.c: Likewise. + * gcc.dg/tree-ssa/20030711-3.c: Likewise. + * gcc.dg/tree-ssa/20030714-1.c: Likewise. + * gcc.dg/tree-ssa/20030714-2.c: Likewise. + * gcc.dg/tree-ssa/20030729-1.c: Likewise. + * gcc.dg/tree-ssa/20030730-1.c: Likewise. + * gcc.dg/tree-ssa/20030730-2.c: Likewise. + * gcc.dg/tree-ssa/20030731-1.c: Likewise. + * gcc.dg/tree-ssa/20030807-10.c: Likewise. + * gcc.dg/tree-ssa/20030807-11.c: Likewise. + * gcc.dg/tree-ssa/20030807-2.c: Likewise. + * gcc.dg/tree-ssa/20030807-3.c: Likewise. + * gcc.dg/tree-ssa/20030807-4.c: Likewise. + * gcc.dg/tree-ssa/20030807-5.c: Likewise. + * gcc.dg/tree-ssa/20030807-6.c: Likewise. + * gcc.dg/tree-ssa/20030807-7.c: Likewise. + * gcc.dg/tree-ssa/20030807-8.c: Likewise. + * gcc.dg/tree-ssa/20030807-9.c: Likewise. + * gcc.dg/tree-ssa/20030808-1.c: Likewise. + * gcc.dg/tree-ssa/20030814-1.c: Likewise. + * gcc.dg/tree-ssa/20030814-2.c: Likewise. + * gcc.dg/tree-ssa/20030814-3.c: Likewise. + * gcc.dg/tree-ssa/20030814-4.c: Likewise. + * gcc.dg/tree-ssa/20030814-5.c: Likewise. + * gcc.dg/tree-ssa/20030814-6.c: Likewise. + * gcc.dg/tree-ssa/20030814-7.c: Likewise. + * gcc.dg/tree-ssa/20030815-1.c: Likewise. + * gcc.dg/tree-ssa/20030922-1.c: Likewise. + * gcc.dg/tree-ssa/20030807-1.c: Likewise. + Fix test to avoid dereferencing a NULL pointer. + +2004-01-07 Zdenek Dvorak + Jeff Law + + * gcc.dg/tree-ssa/20030709-2.c: Update test and expected + output to accomodate improvements in the optimizers. + +2004-01-02 Dan Nicolaescu + + * gcc.dg/tree-ssa/sra-3.c: Replace test, old version was a + copy of sra-2.c + +2004-01-01 Paul Brook + + * gfortran.fortran-torture/execute/data_2.f90: New test. + +2003-12-16 Diego Novillo + + * gcc.dg/tree-ssa/20031216-2.c: Remove duplicate test. + * gcc.dg/tree-ssa/20030807-7.c: Use -O2 to enable strict + aliasing. + (simplify_condition): Remove static declarator. + +2003-12-16 Diego Novillo + + * gcc.dg/tree-ssa/20031216-2.c: New test. + +2003-12-16 Dan Nicolaescu + + * gcc.dg/tree-ssa/sra-1.c: New test. + * gcc.dg/tree-ssa/sra-2.c: New test. + * gcc.dg/tree-ssa/sra-3.c: New test. + * gcc.dg/tree-ssa/20031216-1.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-11.c: New test. + +2003-12-12 Jeff Law + + * ssa-dom-thread-1.c: Update now that jump threading pass is + no longer separate from the dominator optimizer. + +2003-12-12 Huang Chun + + * gfortran.fortran-torture/execute/intrinsic_len.f90: Fix. + * gfortran.fortran-torture/execute/intrinsic_index.f90: New test. + +2003-12-11 Jeff Law + + * gcc.c-torture/execute/20031211-1.c: New test. + * gcc.c-torture/execute/20031211-2.c: New test. + +2003-12-05 Canqun Yang + + * gfortran.fortran-torture/execute/common.f90: New test for + COMMON and EQUIVALENCE. + +2003-12-01 Feng Wang + + * gfortran.fortran-torture/excute/intrinsic_fraction_exponent.f90: + Use correct types. Handle negative exponents. + * gfortran.fortran-torture/excute/intrinsic_scale.f90: Remove + incorrect conditions. + +2003-12-01 Diego Novillo + + * gcc.dg/tls/asm-1.c: Update expected error message. + +2003-11-30 Andrew Pinski + + PR optimization/13067 + * g++.dg/opt/cfg4.C: New test. + +2003-11-30 Paul Brook + + PR fortran/13155 + * gfortran.fortran-torture/execute/module_interface_2.f90: New test. + +2003-11-29 Paul Brook + + * gfortran.fortran-torture/execute/allocate.f90: New test. + +2003-11-27 Zdenek Dvorak + + * gcc.dg/tree-ssa/ssa-ccp-10.c: New test. + +2003-11-26 Richard Henderson + + * gfortran.fortran-torture/execute/intrinsic_nearest.f90: Correctly + test behaviour at infinity. + +2003-11-25 Canqun Yang + + * gfortran.fortran-torture/execute/common_size.f90: New test for + size of COMMON block containing EQUIVALENCE objects. + +2003-11-24 Richard Henderson + + * gcc.c-torture/compile/20031124-1.c: New. + +2003-11-24 Paul Brook + + PR fortran/13154 + * gfortran.fortran-torture/compile/module_common.f90: New test. + +2003-11-18 Jan Hubicka + + * gcc.dg/tree-ssa/tailcall-1.c: New. + * gcc.dg/tree-ssa/tailrecursion-?.c: Rename dump + +2003-11-18 Jan Hubicka + + * gcc.dg/tree-ssa/tailrecursion-1.c: New test. + * gcc.dg/tree-ssa/tailrecursion-2.c: New test. + * gcc.dg/tree-ssa/tailrecursion-3.c: New test. + * gcc.dg/tree-ssa/tailrecursion-4.c: New test. + +2003-11-13 Paul Brook + + * gfortran.fortran-torture/execute/module_interface.f90: New test. + +2003-11-13 Jeff Law + + * gcc.dg/tree-ssa/20030808-1.c:Scan dce2 output rather than dom2 + output. + + * gcc.dg/tree-ssa/20030728-1.c: Update for jump threading changes. + + * gcc.dg/tree-ssa/20030730-1.c: No longer expect abort declaration + to be present. + + * gcc.dg/tree-ssa/20030730-1.c: Make "foo" have external linkage. + * gcc.dg/tree-ssa/20030730-2.c: Similarly. + +2003-11-13 Jan Hubicka + + * gcc.dg/tree-ssa/ssa-dce-1.c: New test. + * gcc.dg/tree-ssa/ssa-dce-2.c: New test. + * gcc.dg/tree-ssa/ssa-dom-ccp-1.c: New test. + * gcc.dg/tree-ssa/ssa-dom-cse-1.c: New test. + * gcc.dg/tree-ssa/ssa-dom-thread-1.c: New test. + * gcc.dg/tree-ssa/cfgcleanup-1.c: New test. + +2003-11-13 Steven Bosscher + + * gcc.dg/tree-ssa/20031113-1.c: New test. + +2003-11-12 Jan Hubicka + + * g++.dg/tree-ssa: New file. + * g++.dg/tree-ssa/tree-ssa.exp: New file based on + gcc.dg/tree-ssa/tree-ssa.exp. + * g++.dg/tree-ssa/nothrow-1.C: New test. + +2003-11-11 Canqun Yang + + * gfortran.fortran-torture/execute/stack_varsize.f90: New test. + +2003-11-08 Paul Brook + + * gfortran.fortran-toriture/execute/intrinsic_mmloc_3.f90: Extra test. + * gfortran.fortran-toriture/execute/intrinsic_mmloc_4.f90: New test. + +2003-11-06 Paul Brook + + * gfortran.fortran-toriture/execute/intrinsic_mmloc_3.f90: New test. + +2003-11-06 Dan Nicolaescu + + * gcc.dg/tree-ssa/20031106-1.c: New test. + * gcc.dg/tree-ssa/20031106-2.c: New test. + * gcc.dg/tree-ssa/20031106-3.c: New test. + * gcc.dg/tree-ssa/20031106-4.c: New test. + * gcc.dg/tree-ssa/20031106-5.c: New test. + * gcc.dg/tree-ssa/20031106-6.c: New test. + +2003-11-06 Steven Bosscher + + * gcc.dg/tree-ssa/ssa-ccp-2.c: Fix overoptimistic expectations + of our optimizers. + +2003-10-31 Diego Novillo + + * gcc.dg/tree-ssa/20031031-1.c: New test. + +2003-10-30 Richard Henderson + + * g++.dg/warn/Wswitch-1.C: Move "case value not in enumerated type" + warning to the proper line. + * gcc.dg/Wswitch-enum.c: Likewise. + * gcc.dg/Wswitch.c: Likewise. + +2003-10-22 Jeff Law + + * gcc.dg/tree-ssa/20031022-1.c: New test. + +2003-10-17 Paul Brook + + * gfortran.fortran-torture/execute/intrinsic_size.f90: Add + additional case. + +2003-10-17 Feng Wang + + * gfortran.fortran-torture/execute/intrinsic_mmloc_2.f90: New test. + +2003-10-16 Richard Henderson + + * g++.dg/ext/asm3.C: Update expected error text. + +2003-10-16 Steven Bosscher + + * gcc.dg/noreturn-1.c: Adjust expected error lines. + * gcc.dg/return-type-1.c: Likewise. + +2003-10-15 Steven Bosscher + + * gcc.dg/tree-ssa/20031015-1.c: New test. + +2003-10-14 Richard Henderson + + * gcc.dg/asm-7.c: Update expected error text. + +2003-10-14 Diego Novillo + + * gcc.dg/tree-ssa/20030918-1.c: New test. + +2003-10-13 Paul Brook + + * gfortran.fortran-torture/execute/retarray_2.f90: New test. + * gfortran.fortran-torture/compile/named_args.f90: New test. + +2003-10-12 Feng Wang + + * gfortran.fortran-torture/execute/intrinsic_cshift.f90: New test. + +2003-10-11 Huang Chun + + * gfortran.fortran-torture/execute/intrinsic_len.f90: New test. + * gfortran.fortran-torture/execute/intrinsic_trim.f90: New test. + +2003-10-11 Paul Brook + + * gfortran.fortran-torture/execute/specifics.f90: New test. + * gfortran.fortran-torture/execute/intrinsic_achar.f90: New test. + * gfortran.fortran-torture/execute/strret.f90: Also test result vars. + +2003-10-01 Richard Henderson + + * g++.dg/parse/crash10.C: Adjust expected error lines. + * g++.old-deja/g++.other/crash31.C: Likewise. + +2003-09-29 Richard Henderson + + * g++.dg/ext/stmtexpr1.C, g++.dg/parse/stack1.C: XFAIL. + +2003-09-29 Richard Henderson + + * g++.dg/opt/nothrow1.C: Use locally declared function rather + than printf. + + * g++.dg/ext/label3.C: Add dg-options. + +2003-09-25 Jeff Law + + * gcc.dg/tree-ssa/20030922-2.c: New test. + +2003-09-24 Jeff Law + + * gcc.dg/tree-ssa/20030708-1.c: Expect all IF conditions to be + removed. + * gcc.dg/tree-ssa/20030808-1.c: Similarly. + + * gcc.dg/tree-ssa/20030807-9.c: Add additional test. + +2003-09-22 Jeff Law + + * gcc.dg/tree-ssa/20030922-1.c: New test. + + * gcc.dg/tree-ssa/20030807-2.c: Add additional cases to this test. + +2003-09-21 Diego Novillo + + * gcc.dg/tree-ssa/20030920-1.c: New test. + +2003-09-21 Diego Novillo + + * gcc.dg/tree-ssa/20030703-2.c: Expect one if() conditional after + the second dominator pass. + * gcc.dg/tree-ssa/20030807-1.c: Likewise. + * gcc.dg/tree-ssa/20030807-1.c: Add return statement to avoid DCE + removing the whole body. + Expect two if() statements after the second dominator pass. + * gcc.dg/tree-ssa/20030807-7.c: Explain why we fail to optimize. + +2003-09-21 Diego Novillo + + * gcc.dg/tree-ssa/20030530-2.c: Adjust to use -fdump-tree-dom2. + * gcc.dg/tree-ssa/20030611-1.c: Likewise. + * gcc.dg/tree-ssa/20030703-1.c: Likewise + * gcc.dg/tree-ssa/20030703-2.c: Likewise. + * gcc.dg/tree-ssa/20030708-1.c: Likewise. + * gcc.dg/tree-ssa/20030709-2.c: Likewise. + * gcc.dg/tree-ssa/20030709-3.c: Likewise. + * gcc.dg/tree-ssa/20030710-1.c: Likewise. + * gcc.dg/tree-ssa/20030711-1.c: Likewise. + * gcc.dg/tree-ssa/20030711-2.c: Likewise. + * gcc.dg/tree-ssa/20030711-3.c: Likewise. + * gcc.dg/tree-ssa/20030714-1.c: Likewise. + * gcc.dg/tree-ssa/20030714-2.c: Likewise. + * gcc.dg/tree-ssa/20030729-1.c: Likewise. + * gcc.dg/tree-ssa/20030730-1.c: Likewise. + * gcc.dg/tree-ssa/20030730-2.c: Likewise. + * gcc.dg/tree-ssa/20030731-1.c: Likewise. + * gcc.dg/tree-ssa/20030807-1.c: Likewise. + * gcc.dg/tree-ssa/20030807-10.c: Likewise. + * gcc.dg/tree-ssa/20030807-11.c: Likewise. + * gcc.dg/tree-ssa/20030807-2.c: Likewise. + * gcc.dg/tree-ssa/20030807-3.c: Likewise. + * gcc.dg/tree-ssa/20030807-4.c: Likewise. + * gcc.dg/tree-ssa/20030807-5.c: Likewise. + * gcc.dg/tree-ssa/20030807-6.c: Likewise. + * gcc.dg/tree-ssa/20030807-7.c: Likewise. + * gcc.dg/tree-ssa/20030807-8.c: Likewise. + * gcc.dg/tree-ssa/20030807-9.c: Likewise. + * gcc.dg/tree-ssa/20030808-1.c: Likewise. + * gcc.dg/tree-ssa/20030814-1.c: Likewise. + * gcc.dg/tree-ssa/20030814-2.c: Likewise. + * gcc.dg/tree-ssa/20030814-3.c: Likewise. + * gcc.dg/tree-ssa/20030814-4.c: Likewise. + * gcc.dg/tree-ssa/20030814-5.c: Likewise. + * gcc.dg/tree-ssa/20030814-6.c: Likewise. + * gcc.dg/tree-ssa/20030814-7.c: Likewise. + * gcc.dg/tree-ssa/20030815-1.c: Likewise. + * gcc.dg/tree-ssa/20030824-2.c: Likewise. + * gcc.dg/tree-ssa/20030907-1.c: Likewise. + +2003-09-21 Lifang Zeng + + * gfortran.fortran-torture/execute/data.f90: New test. + +2003-09-20 Kejia Zhao + + * gfortran.fortran-torture/execute/intrisic_si_kind.f90: New test. + * gfortran.fortran-torture/execute/intrisic_sr_kind.f90: New test. + +2003-09-17 Diego Novillo + + * gcc.dg/tree-ssa/20030917-2.c: New test. + +2003-09-17 Jeff Law + + * gcc.c-torture/compile/20030917-1.c: New test. + + * gcc.dg/tree-ssa/20030917-1.c: New test. + * gcc.dg/tree-ssa/20030917-3.c: New test. + + * gcc.dg/tree-ssa/20030807-8.c: Update. + +2003-09-14 Paul Brook + + * gfortran.fortran-torture/der_init.f90: Also test arrays. + +2003-09-13 Paul Brook + + * gcc.c-torture/execute/20030913-1.c: New test. + +2003-09-10 Kejia Zhao + + * gfortran.fortran-torture/intrinsic_fraction_exponent.f90: New test. + * gfortran.fortran-torture/intrinsic_nearest.f90: New test. + * gfortran.fortran-torture/intrinsic_rrspacing.f90: New test. + * gfortran.fortran-torture/intrinsic_scale.f90: New test. + * gfortran.fortran-torture/intrinsic_set_exponent.f90: New test + * gfortran.fortran-torture/intrinsic_spacing.f90: New test. + +2003-09-10 Paul Brook + + * gcc.c-torture/execute/20030910-1.c: New test. + * gcc.g-torture/compile/20030910-1.c: New test. + +2003-09-09 Zdenek Dvorak + + * gcc.c-torture/execute/20030909-1.c: New test. + +2003-09-07 Steven Bosscher + + PR optimization/12198 + * gcc.dg/tree-ssa/20030907-1.c: New test. + + PR optimization/12109 + * gcc.dg/tree-ssa/20030907-2.c: New test. + +2003-09-04 Diego Novillo + + * gcc.c-torture/execute/20030828-1.c: New test. + * gcc.c-torture/execute/20030828-2.c: New test. + +2003-09-02 Jeff Law + + * gcc.c-torture/compile/20030902-1.c: New test. + +2003-08-27 Jeff Law + + * gcc.dg/tree-ssa/20030821-1.c: Don't get confused by declaration + of dont_remove. + +2003-08-25 Zdenek Dvorak + Jeff Law + + * gcc.dg/tree-ssa/20030815-1.c: New test. + * gcc.dg/tree-ssa/20030821-1.c: New test. + + +2003-08-25 Zdenek Dvorak + + * gcc.dg/tree-ssa/20030825-1.c: New test. + +2003-08-24 Diego Novillo + + * gcc.dg/tree-ssa/20030824-1.c: New test. + * gcc.dg/tree-ssa/20030824-2.c: New test. + +2003-08-23 Diego Novillo + + * gcc.c-torture/compile/20030823-1.c: New test. + +2003-08-20 Diego Novillo + + * gcc.dg/tree-ssa/20030807-3.c: Adjust expected number of + conditionals. + * gcc.dg/tree-ssa/20030807-4.c: Likewise. + +2003-08-20 Zdenek Dvorak + + * gcc.dg/tree-ssa/20030820-1.c: New test. + * gcc.dg/tree-ssa/20030820-2.c: New test. + +2003-08-15 Jeff Law + + * gcc.dg/tree-ssa/20030814-6.c: New test. + * gcc.dg/tree-ssa/20030814-7.c: New test. + + * gcc.dg/tree-ssa/20030814-4.c: Test optimized output to verify + useless statement created by out-of-ssa pass is removed. + * gcc.dg/tree-ssa/20030814-5.c: Similarly. + +2003-08-14 Paul Brook + + * gfortran.fortran-torture/compile/allocate.f90: Also test scalars. + +2003-08-14 Jeff Law + + * gcc.dg/tree-ssa/20030814-1.c: New test. + * gcc.dg/tree-ssa/20030814-2.c: New test. + * gcc.dg/tree-ssa/20030814-3.c: New test. + * gcc.dg/tree-ssa/20030814-4.c: New test. + * gcc.dg/tree-ssa/20030814-5.c: New test. + + * gcc.dg/tree-ssa/20030708-1.c: There should only be one conditional. + * gcc.dg/tree-ssa/20030714-2.c: New test. + * gcc.dg/tree-ssa/20030731-1.c: New test. + + * gcc.dg/tree-ssa/20030711-2.c: Update slightly to avoid + dereferences of constant addresses. + + * gcc.dg/tree-ssa/20030729-1.c: Remove incorrect test for + IF statement removal. + + * gcc.dg/tree-ssa/20030808-1.c: New test. + +2003-08-12 Jeff Law + + * gcc.dg/tree-ssa/20030807-8.c: New test. + +2003-08-12 Diego Novillo + + * gcc.c-torture/execute/builtins/string-4.x: Remove. + +2003-08-12 Paul Brook + + * gfortran.fortran-torture/execute/forall_4.f90: Fix illegal code. + +2003-08-12 Jeff Law + + * gcc.dg/tree-ssa/*.c: Add missing close braces to various tests. + + * gcc.dg/tree-ssa/20030807-6.c: New test. + * gcc.dg/tree-ssa/20030807-7.c: New test. + * gcc.dg/tree-ssa/20030807-9.c: New test. + * gcc.dg/tree-ssa/20030807-11.c: New test. + +2003-08-11 Jeff Law + + * gcc.dg/tree-ssa/20030807-1.c: New test. + * gcc.dg/tree-ssa/20030807-2.c: New test. + * gcc.dg/tree-ssa/20030807-3.c: New test. + * gcc.dg/tree-ssa/20030807-4.c: New test. + * gcc.dg/tree-ssa/20030807-5.c: New test. + * gcc.dg/tree-ssa/20030807-10.c: New test. + +2003-08-10 Paul Brook + + * gfortran.fortran-torture/compile/allocate.f90: Also test memebers of + derived types. + +2003-08-05 Jeff Law + + * gcc.dg/tree-ssa/20030731-2.c: New test. + * gcc.c-torture/execute/builtins/string-5.x: Kill. + +2003-07-30 Jeff Law + + * gcc.dg/tree-ssa/20030730-1.c: New test. + * gcc.dg/tree-ssa/20030730-2.c: New test. + * gcc.dg/tree-ssa/20030729-1.c: Fix comment typo. + +2003-07-29 Jeff Law + + * gcc.dg/tree-ssa/20030729-1.c: New test. + + * gcc.dg/tree-ssa/20030709-1.c: Look at the .optimized output. + + * gcc.dg/tree-ssa/20030711-2.c: There should only be one load + of rtmem after rewriting into SSA form. + +2003-07-28 Jeff Law + + * gcc.dg/tree-ssa/20030728-1.c: New test. + +2003-07-26 Paul Brook + + * gfortran.fortran-torture: New testsuite. + * lib/fortran-torture.exp: New file. + * lib/gfortran.exp: New file. + +2003-07-16 Jeff Law + + * gcc.dg/tree-ssa/20030709-2.c: Also test that we eliminate + the redundant load of ->fld[1].rtmem. + + * gcc.c-torture/compile/20030716-1.c: New test. + +2003-07-16 Dan Nicolaescu + + * gcc.dg/tree-ssa/ssa-ccp-1.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-2.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-3.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-4.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-5.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-6.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-7.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-8.c: New test. + * gcc.dg/tree-ssa/ssa-ccp-9.c: New test. + +2003-07-10 Jeff Law + + * gcc.dg/tree-ssa/20030703-1.c: New test. + * gcc.dg/tree-ssa/20030703-2.c: New test. + * gcc.dg/tree-ssa/20030708-1.c: New test. + * gcc.dg/tree-ssa/20030709-1.c: New test. + * gcc.dg/tree-ssa/20030709-2.c: New test. + * gcc.dg/tree-ssa/20030709-3.c: New test. + * gcc.dg/tree-ssa/20030710-1.c: New test. + * gcc.dg/tree-ssa/20030711-1.c: New test. + * gcc.dg/tree-ssa/20030711-2.c: New test. + * gcc.dg/tree-ssa/20030711-3.c: New test. + * gcc.dg/tree-ssa/20030714-1.c: New test. + +2003-07-10 Jeff Law + + * lib/scantree.exp: Always glob the output file. +: +2003-06-27 Diego Novillo + + * gcc.dg/20030612-1.c: New test. + +2003-06-25 Jeff Law + + * gcc.dg/noncompile/920507-1.c: Return a value so that the + variable "a" is always used. + +2003-06-11 Jeff Law + + * gcc.c-torture/gcc.dg/tree-ssa/20030611-1.c: New test. + + * gcc.c-torture/compile/20030530-2.c: Move to... + * gcc.c-torture/gcc.dg/tree-ssa/20030530-2.c: Here. Use dg + and scan-tree-output framework. Verify that redundant expressions + are removed. + * gcc.c-torture/gcc.dg/tree-ssa/tree-ssa.exp: New driver. + * lib/gcc.dg.exp: Load scantree.exp. + * lib/scantree.exp: New library of routines to scan tree dumps. + +2003-06-03 Diego Novillo + + * gcc.c-torture/execute/builtins/string-4.x: Expect + execution failures. + * gcc.c-torture/execute/builtins/string-5.x: Likewise. + +2003-05-30 Jeff Law + + * gcc.c-torture/compile/20030530-1.c: New test. + * gcc.c-torture/compile/20030530-2.c: New test. + * gcc.c-torture/compile/20030530-3.c: New test. + +2003-05-12 Diego Novillo + + * gcc.c-torture/execute/string-opt-19.x: Expect execution + failures. + +2003-05-06 Jeff Law + + * gcc.c-torture/execute/string-opt-18.x: Expect execution + failures. + +2003-05-01 Jeff Law + + * gcc.c-torture/execute/20030501-1.c: New test for tree-ssa bug. + +2003-04-16 Jeff Law + + * gcc.c-torture/compile/20030416-1.c: New test from Diego. + + * gcc.c-torture/execute/20030120-3.c: Updates suggested by Kaveh. + +2003-04-05 Diego Novillo + + * gcc.c-torture/compile/20030405-1.[cx]: New test. + +2003-04-05 Diego Novillo + + * gcc.c-torture/execute/20030404-1.c: New test. + +2003-04-03 Diego Novillo + + * gcc.c-torture/execute/20030403-1.c: New test. + +2003-03-10 Steven Bosscher + + * gcc.c-torture/compile/20030310-1.c: New test. + +2003-02-12 Jeff Law + + * gcc.c-torture/execute/20030120-3.c: New test. + +2003-02-08 Diego Novillo + + * lib/c-torture.exp: Remove -ftree-dce from compiler flags. + +2003-02-06 Diego Novillo + + * gcc.c-torture/compile/20001226-1.c: Remove deliberate syntax + error. + +2003-02-02 Diego Novillo + + * lib/c-torture.exp (TORTURE_OPTIONS): Add -ftree-dce. + +2003-01-28 Diego Novillo + + * gcc.c-torture/execute/builtin-constant.x: Remove. + +2003-01-05 Diego Novillo + + * gcc.c-torture/compile/20001226-1.c: Add clarifying + remarks about why we introduced a deliberate syntax + error. + +2002-11-24 Diego Novillo + + * gcc.c-torture/compile/20001226-1.c: Introduce a + deliberate syntax error. + +2002-11-13 Diego Novillo + + * gcc.c-torture/execute/20021113-1.c: New test. + +2002-08-19 Diego Novillo + + * gcc.c-torture/execute/20020819-1.c: New test. + +2002-08-21 Diego Novillo + + * gcc.c-torture/execute/20020819-1.c: Add exit(0). diff --git a/gcc/testsuite/g++.dg/README b/gcc/testsuite/g++.dg/README index 4e2e4ce9bbc..14b736e7a73 100644 --- a/gcc/testsuite/g++.dg/README +++ b/gcc/testsuite/g++.dg/README @@ -22,6 +22,7 @@ rtti Tests for run-time type identification (typeid, dynamic_cast, etc.) template Tests for templates. tc1 Tests for Technical Corrigendum 1 conformance. tls Tests for support of thread-local data. +tree-ssa Tests for Tree SSA optimizations. warn Tests for compiler warnings. other Tests that don't fit into one of the other categories. diff --git a/gcc/testsuite/g++.dg/eh/goto1.C b/gcc/testsuite/g++.dg/eh/goto1.C new file mode 100644 index 00000000000..f3e3e4216fb --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/goto1.C @@ -0,0 +1,34 @@ +extern "C" void abort (); + +static int count; + +struct S { + S() { ++count; } + ~S() { --count; } +}; + +int foo(int p) +{ + S s1; + { + S s2; + if (p) + goto L; + else + return 1; + } + foo (p); + L: + return 0; +} + +int main() +{ + foo(0); + if (count != 0) + abort (); + foo(1); + if (count != 0) + abort (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/asm3.C b/gcc/testsuite/g++.dg/ext/asm3.C index 699ab4c8252..5eff16ffe7c 100644 --- a/gcc/testsuite/g++.dg/ext/asm3.C +++ b/gcc/testsuite/g++.dg/ext/asm3.C @@ -8,6 +8,6 @@ int two(int in) { register int out; - __asm__ ("" : "r" (out) : "r" (in)); // { dg-error "output operand" "" } + __asm__ ("" : "r" (out) : "r" (in)); // { dg-error "" "" } return out; } diff --git a/gcc/testsuite/g++.dg/ext/label3.C b/gcc/testsuite/g++.dg/ext/label3.C new file mode 100644 index 00000000000..604bfdc12c3 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/label3.C @@ -0,0 +1,39 @@ +// Bug: we were removing the p = q assignment in dce, and then reinserting +// it *after* the try/catch in out-of-ssa. Oops. + +// testcase reduced from libjava/interpret.cc. + +// { dg-do run } +// { dg-options "-O2" } + +extern "C" int printf (const char *, ...); + +bool b; + +int main() +{ + __label__ one, two, done; + void *labs[] = { &&one, &&two, &&done }; + const void **q = (const void **)labs; + const void **p = q; + + try + { + one: + printf ("one!\n"); + if (b) + throw 42; + goto **p++; + + two: + printf ("two!\n"); + goto **p++; + + done: + printf ("done!\n"); + } + catch (int) + { + printf ("caught!\n"); + } +} diff --git a/gcc/testsuite/g++.dg/init/pmf1.C b/gcc/testsuite/g++.dg/init/pmf1.C new file mode 100644 index 00000000000..93c67bdd706 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/pmf1.C @@ -0,0 +1,17 @@ +// PR c++/14089 +// { dg-do compile } +// +// C++ front end generated assignment between types that were not +// compatible in any sense visible to the optimizers. + +struct pair { + typedef void (pair::*fp)(); + int first; + pair::fp second; + pair(const int& a, const pair::fp& b) : first(a), second(b) {} + void f(const int& a, const pair::fp& b) { first = a; second = b; } +}; + +void op() { + pair(5, pair::fp()); +} diff --git a/gcc/testsuite/g++.dg/opt/bool1.C b/gcc/testsuite/g++.dg/opt/bool1.C new file mode 100644 index 00000000000..78cdebe32aa --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/bool1.C @@ -0,0 +1,25 @@ +// PR opt/13869 +// { dg-do run } +// { dg-options "-O2" } + +extern "C" void abort (); + +int test () +{ + bool my_bool = true; + for (int i = 0; i < 10; ++i) + { + if (!my_bool) + ; + else + my_bool = false; + }; + return my_bool; +} + +int main () +{ + if (test ()) + abort (); + return 0; +} diff --git a/gcc/testsuite/g++.dg/opt/cfg4.C b/gcc/testsuite/g++.dg/opt/cfg4.C new file mode 100644 index 00000000000..94522ed4171 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/cfg4.C @@ -0,0 +1,45 @@ +// PR optimization/13067 +// Origin: + +// This used to fail on the tree-ssa because of "out-of-ssa" +// We might have a valid variable, but not a valid value when trying to find +// useless statements created by out-of-ssa translation. In this case +// val will be set to null, then later dereferenced. Bad. + +// { dg-do compile } +// { dg-options "-Os" } + + + +struct Iterator +{ + Iterator operator++(); +}; + +void GetChar(char* aChar); + +void foo(char aChar) +{ + char quote; + Iterator end; + + while (1) { + if (aChar == '"') + GetChar(&aChar); + + switch (aChar) { + case 'a': + ++end; + if (quote) { + if (quote == aChar) { + quote = 0; + } + } else { + quote = aChar; + } + } + } +} + + + diff --git a/gcc/testsuite/g++.dg/opt/crash1.C b/gcc/testsuite/g++.dg/opt/crash1.C new file mode 100644 index 00000000000..3526df1ddc9 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/crash1.C @@ -0,0 +1,14 @@ +// PR opt/13681 +// Here we have an out-of-range array index. We should not abort +// trying to resolve the indirection back to an object. + +struct X { + double values[1]; + double & foo (const unsigned int index) { return values[index]; } +}; + +void foo() { + double d; + X h1; + h1.foo(1) = d; +} diff --git a/gcc/testsuite/g++.dg/opt/inline7.C b/gcc/testsuite/g++.dg/opt/inline7.C new file mode 100644 index 00000000000..7a873b01a31 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/inline7.C @@ -0,0 +1,7 @@ +// PR c++/13543 +// { dg-do compile } +// { dg-options "-O3" } + +struct basic_string { basic_string(const basic_string&); }; +basic_string operator+(const basic_string& lhs, char); +void dumpNode(basic_string start) { dumpNode(start + 'a'); } diff --git a/gcc/testsuite/g++.dg/opt/nothrow1.C b/gcc/testsuite/g++.dg/opt/nothrow1.C new file mode 100644 index 00000000000..fb6c6040408 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/nothrow1.C @@ -0,0 +1,24 @@ +// Test that the nothrow optimization works properly. +// { dg-do compile } +// { dg-options "-O -fdump-tree-optimized" } + +extern void blah() throw(); + +int i, j, k; + +int main() +{ + try + { + ++i; + blah(); + ++j; + } + catch (...) + { + return 42; + } +} + +// The catch block should be optimized away. +// { dg-final { scan-tree-dump-times "42" 0 "optimized" } } diff --git a/gcc/testsuite/g++.dg/opt/static4.C b/gcc/testsuite/g++.dg/opt/static4.C new file mode 100644 index 00000000000..87e11b02756 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/static4.C @@ -0,0 +1,15 @@ +// PR 13898 +// Make sure the two X variables get assigned unique assembler names +// if they are promoted to static storage. + +// { dg-do compile } + +int g(int i) { + if (i<1) { + const int x[3] = { 1,2,3 }; + return x[i]; + } else { + const int x[3] = { 4,5,6 }; + return x[i]; + } +} diff --git a/gcc/testsuite/g++.dg/parse/crash10.C b/gcc/testsuite/g++.dg/parse/crash10.C index 878139fa0de..8212fcb5b29 100644 --- a/gcc/testsuite/g++.dg/parse/crash10.C +++ b/gcc/testsuite/g++.dg/parse/crash10.C @@ -5,6 +5,8 @@ // PR c++ 10953. ICE +// { dg-bogus "" "" { target *-*-* } 14 } + class { typename:: // { dg-error "" "" } diff --git a/gcc/testsuite/g++.dg/tree-ssa/20040317-1.C b/gcc/testsuite/g++.dg/tree-ssa/20040317-1.C new file mode 100644 index 00000000000..e2f3dcdceb8 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/20040317-1.C @@ -0,0 +1,38 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +/* Test provided by Brian Ryner in PR 14511. The alias analyzer was + not handling structures containing arrays properly. In this case, + the static cast was introducing two assignments of the form + + this_6->_vptr.IFoo = &_ZTV4IFoo[2]; + this_4->_vptr.IFoo = &_ZTV3Bar[2]; + + which were not considered to alias each other because the alias + analyzer was not computing a proper pointer to array elements. + Another related bug was the type based alias analyzer not computing + alias relations to _ZTV4IFoo and _ZTV3Bar. Since those variables + are read-only, it was disregarding alias information for them. + So, the memory tags for the two 'this' variables were not being + marked as aliased with these variables. Resulting in the two + assignments not aliasing each other. + + This was causing the optimizers to generate a call to the virtual + method Foo() instead of the overloaded version. */ + +struct IFoo +{ + virtual void Foo() = 0; +}; + +struct Bar : IFoo +{ + void Foo() { } +}; + +int main(int argc, char **argv) +{ + Bar* b = new Bar(); + static_cast(b)->Foo(); + return 0; +} diff --git a/gcc/testsuite/g++.dg/tree-ssa/nothrow-1.C b/gcc/testsuite/g++.dg/tree-ssa/nothrow-1.C new file mode 100644 index 00000000000..6bd092977cd --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/nothrow-1.C @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-cfg" } */ +double a; +void t() +{ + a=1; +} +void t1(void); +void abort(void); + +void q() +{ + try { + t(); + } + catch (...) {abort();} +} +/* We shouldnotice nothrow attribute. */ +/* { dg-final { scan-tree-dump-times "exception" 0 "cfg"} } */ diff --git a/gcc/testsuite/g++.dg/tree-ssa/tree-ssa.exp b/gcc/testsuite/g++.dg/tree-ssa/tree-ssa.exp new file mode 100644 index 00000000000..4788baa7838 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/tree-ssa.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib g++-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CXXFLAGS +if ![info exists DEFAULT_CXXFLAGS] then { + set DEFAULT_CXXFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[CS\]]] \ + "" $DEFAULT_CXXFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.dg/warn/Wswitch-1.C b/gcc/testsuite/g++.dg/warn/Wswitch-1.C index e9fcb581817..4f44e12576e 100644 --- a/gcc/testsuite/g++.dg/warn/Wswitch-1.C +++ b/gcc/testsuite/g++.dg/warn/Wswitch-1.C @@ -19,17 +19,17 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, case 4: return 3; default: break; } - switch (ei) - { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" { target *-*-* } 24 } */ - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ + switch (ei) /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ + { /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" { target *-*-* } 22 } */ + } switch (ej) { default: break; } - switch (ek) + switch (ek) /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ { case e1: return 1; - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ + } switch (el) { case e1: return 1; @@ -50,8 +50,8 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, { case e1: return 1; case e2: return 2; - case 3: return 3; - } /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + case 3: return 3; /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + } switch (ep) { case e1: return 1; diff --git a/gcc/testsuite/g++.dg/warn/Wswitch-2.C b/gcc/testsuite/g++.dg/warn/Wswitch-2.C index b151e2310c7..9bc7d022b46 100644 --- a/gcc/testsuite/g++.dg/warn/Wswitch-2.C +++ b/gcc/testsuite/g++.dg/warn/Wswitch-2.C @@ -13,19 +13,19 @@ foo (enum e ei, int j) case e3: return 2; case e4: return 3; } /* No warning here since e2 has the same value as e3. */ - switch (ei) + switch (ei) /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */ { case e1: return 1; case e2: return 2; - } /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */ + } switch ((int) ei) { case e1: return 1; } /* No warning here since switch condition was cast to int. */ - switch ((enum e) j) + switch ((enum e) j) /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ { case e2: return 1; case e4: return 2; - } /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ + } return 0; } diff --git a/gcc/testsuite/g++.dg/warn/Wunused-5.C b/gcc/testsuite/g++.dg/warn/Wunused-5.C index 06d1a0516bc..8a8d9d280fc 100644 --- a/gcc/testsuite/g++.dg/warn/Wunused-5.C +++ b/gcc/testsuite/g++.dg/warn/Wunused-5.C @@ -1,13 +1,19 @@ -// PR c++/14199 -// { dg-options "-W -Wall -Wunused" } - -struct X { - static void foo (); -}; - -template -void foo (const T &t) { - t.foo(); -} +/* PR opt/14288 */ +/* { dg-do compile } */ +/* { dg-options "-O -Wall" } */ + +volatile int sink; +extern int foo(int); + +struct S +{ + int x; -template void foo (const X &); + S() { x = foo(0); } + ~S() { sink = x; } +}; + +int test(bool p) +{ + return p ? foo(S().x) : 0; /* { dg-bogus "uninitialized" } */ +} diff --git a/gcc/testsuite/g++.dg/warn/noeffect5.C b/gcc/testsuite/g++.dg/warn/noeffect5.C new file mode 100644 index 00000000000..f0f4e74109a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/noeffect5.C @@ -0,0 +1,8 @@ +/* PR middle-end/13325 */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +void *memcpy(void *dest, const void *src, __SIZE_TYPE__ n); +void f (void *dest, const void *src) { + memcpy (dest, src, 0); +} diff --git a/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C b/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C index 84063834f1d..93d15d08d90 100644 --- a/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C +++ b/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C @@ -1,4 +1,8 @@ -// { dg-do assemble } -// { dg-options "" } +// { dg-do run { xfail *-*-* } } +// { dg-options "-w -fpermissive" } -int *foo = new int[1](0); // { dg-bogus "" } +int *foo = new int[1](42); // { dg-bogus "" } +int main () +{ + return foo[0] != 42; +} diff --git a/gcc/testsuite/g++.old-deja/g++.martin/new1.C b/gcc/testsuite/g++.old-deja/g++.martin/new1.C index c7951654c26..502c4f42ad0 100644 --- a/gcc/testsuite/g++.old-deja/g++.martin/new1.C +++ b/gcc/testsuite/g++.old-deja/g++.martin/new1.C @@ -71,8 +71,8 @@ void test1() func(new B(A(10).addr())); }catch(int){ } - CHECK(new_done==1); - CHECK(ctor_done==2); + CHECK(ctor_done==1); + CHECK(new_done==2); CHECK(func_done==3); CHECK(dtor_done==4); CHECK(delete_done==0); @@ -86,10 +86,10 @@ void test2() func(new B(A(10).addr())); }catch(int){ } - CHECK(new_done==1); - CHECK(ctor_done==0); + CHECK(ctor_done==1); + CHECK(new_done==2); CHECK(func_done==0); - CHECK(dtor_done==0); + CHECK(dtor_done==3); CHECK(delete_done==0); } @@ -101,11 +101,11 @@ void test3() func(new B(A(10).addr())); }catch(int){ } - CHECK(new_done==1); - CHECK(ctor_done==2); + CHECK(new_done==0); + CHECK(ctor_done==1); CHECK(func_done==0); CHECK(dtor_done==0); - CHECK(delete_done==3); + CHECK(delete_done==0); } int main() diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C index 566cf9a7831..04ec92a30af 100644 --- a/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C +++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C @@ -1,5 +1,5 @@ // { dg-do run } -// { dg-options "" } +// { dg-options "-w -fpermissive" } // Test for g++ array init extension class A { diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C index a1601f80f9f..a49fb02641c 100644 --- a/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C +++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C @@ -1,5 +1,5 @@ // { dg-do run } -// { dg-options "" } +// { dg-options "-w -fpermissive" } //This uses GNU extensions, so disable -ansi #include #include diff --git a/gcc/testsuite/gcc.c-torture/compile/20010516-1.c b/gcc/testsuite/gcc.c-torture/compile/20010516-1.c deleted file mode 100644 index 7732812cfb1..00000000000 --- a/gcc/testsuite/gcc.c-torture/compile/20010516-1.c +++ /dev/null @@ -1,5 +0,0 @@ -foo() -{ - char d; - asm volatile ( "" :: "m"(&d)); -} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030310-1.c b/gcc/testsuite/gcc.c-torture/compile/20030310-1.c new file mode 100644 index 00000000000..0e89e0bfca2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030310-1.c @@ -0,0 +1,13 @@ +static inline void +foo (char accept) +{ + char s; + while (s == accept) ; +} + +static void +bar (void) +{ + char ch; + foo (ch); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030405-1.c b/gcc/testsuite/gcc.c-torture/compile/20030405-1.c index 2e61f1fa3ff..f84e606c045 100644 --- a/gcc/testsuite/gcc.c-torture/compile/20030405-1.c +++ b/gcc/testsuite/gcc.c-torture/compile/20030405-1.c @@ -1,58 +1,30 @@ -/* PR optimization/10024 */ -extern int *allegro_errno; -typedef long fixed; -extern inline int -fixfloor (fixed x) -{ - if (x >= 0) - return (x >> 16); - else - return ~((~x) >> 16); -} -extern inline int -fixtoi (fixed x) -{ - return fixfloor (x) + ((x & 0x8000) >> 15); -} -extern inline fixed -ftofix (double x) -{ - if (x > 32767.0) - { - *allegro_errno = 34; - return 0x7FFFFFFF; - } - if (x < -32767.0) - { - *allegro_errno = 34; - return -0x7FFFFFFF; - } - return (long) (x * 65536.0 + (x < 0 ? -0.5 : 0.5)); -} -extern inline double -fixtof (fixed x) -{ - return (double) x / 65536.0; -} -extern inline fixed -fixdiv (fixed x, fixed y) +/* When compiled with -pedantic, this program will cause an ICE when the + constant propagator tries to set the value of *str to UNDEFINED. + + This happens because *str is erroneously considered as a store alias. + The aliasing code is then making *str an alias leader for its alias set + and when the PHI node at the end of the while() is visited the first + time, CCP will try to assign it a value of UNDEFINED, but the default + value for *str is a constant. */ +typedef unsigned int size_t; +size_t strlength (const char * const); +char foo(); + +static const char * const str = "mingo"; + +bar() { - if (y == 0) + size_t c; + char *x; + + c = strlength (str); + while (c < 10) { - *allegro_errno = 34; - return (x < 0) ? -0x7FFFFFFF : 0x7FFFFFFF; + if (c > 5) + *x = foo (); + if (*x < 'a') + break; } - else - return ftofix (fixtof (x) / fixtof (y)); -} -extern inline fixed -itofix (int x) -{ - return x << 16; -} -int -foo (int n) -{ - return fixtoi (fixdiv (itofix (512), itofix (n))); + return *x == '3'; } diff --git a/gcc/testsuite/gcc.c-torture/compile/20030405-1.x b/gcc/testsuite/gcc.c-torture/compile/20030405-1.x new file mode 100644 index 00000000000..3dbbbda51b7 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030405-1.x @@ -0,0 +1,3 @@ +# This test was found to fail only when -pedantic is used. +set options "-pedantic" +return 0 diff --git a/gcc/testsuite/gcc.c-torture/compile/20030416-1.c b/gcc/testsuite/gcc.c-torture/compile/20030416-1.c new file mode 100644 index 00000000000..c3d18b68281 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030416-1.c @@ -0,0 +1,16 @@ +void foo(int x) +{ + if (x > 3) + {;} + else + bar(); + x = 9; +} + +main() +{ + int j; + + foo(j); + return j; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030530-1.c b/gcc/testsuite/gcc.c-torture/compile/20030530-1.c new file mode 100644 index 00000000000..b479ea22b1d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030530-1.c @@ -0,0 +1,23 @@ +union tree_node; +typedef union tree_node *tree; +struct tree_common +{ + tree type; + unsigned lang_flag_0 : 1; +}; +union tree_node +{ + struct tree_common common; +}; +static void +java_check_regular_methods (tree class_decl) +{ + int saw_constructor = class_decl->common.type->common.lang_flag_0; + tree class = class_decl->common.type; + for (;;) + { + if (class) + if (class_decl->common.type) + bar (class); + } +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030530-3.c b/gcc/testsuite/gcc.c-torture/compile/20030530-3.c new file mode 100644 index 00000000000..0a93d2f13fa --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030530-3.c @@ -0,0 +1,16 @@ +struct tree_decl +{ + unsigned in_system_header_flag:1; +}; +union tree_node +{ + struct tree_decl decl; +}; +typedef union tree_node *tree; +static int +redeclaration_error_message (olddecl) + tree olddecl; +{ + if (({olddecl;})->decl.in_system_header_flag) + ; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030716-1.c b/gcc/testsuite/gcc.c-torture/compile/20030716-1.c new file mode 100644 index 00000000000..ceb4b6171e9 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030716-1.c @@ -0,0 +1,7 @@ +void baz(int i); + +void foo(int i, int A[i+1]) +{ + int j=A[i]; + void bar() { baz(A[i]); } +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030823-1.c b/gcc/testsuite/gcc.c-torture/compile/20030823-1.c new file mode 100644 index 00000000000..89a3ea50a7f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030823-1.c @@ -0,0 +1,18 @@ +struct A +{ + int a; +}; + +int foo (struct A *a) +{ + static int c = 30; + int x; + + a->a = c; + /* Dominator optimizations will replace the use of 'a->a' with 'c', but + they won't copy the virtual operands for 'c' from its originating + statement. This exposes symbol 'c' without a correct SSA version + number. */ + x = a->a; + return x; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030902-1.c b/gcc/testsuite/gcc.c-torture/compile/20030902-1.c new file mode 100644 index 00000000000..443b43921b8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030902-1.c @@ -0,0 +1,37 @@ +typedef unsigned int size_t; +typedef unsigned long int reg_syntax_t; +struct re_pattern_buffer +{ + unsigned char *buffer; +}; +typedef enum +{ + jump, + jump_n, +} re_opcode_t; +static int +foo (bufp) + struct re_pattern_buffer *bufp; +{ + int mcnt; + unsigned char *p = bufp->buffer; + switch (((re_opcode_t) * p++)) + { + unconditional_jump: + ; + /* This test case caused an ICE because the statement insertion + routines were failing to update basic block boundaries. */ + case jump: + do + { + (mcnt) = *(p) & 0377; + } + while (0); + (p) += 2; + p += mcnt; + case jump_n: + (mcnt) = *(p + 2) & 0377; + if (mcnt) + goto unconditional_jump; + } +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20030910-1.c b/gcc/testsuite/gcc.c-torture/compile/20030910-1.c new file mode 100644 index 00000000000..9fad109208c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030910-1.c @@ -0,0 +1,11 @@ +/* The gimplifier was getting confused when taking the real or + imaginary component of a complex rvalue. */ + +void test() +{ + __complex double dc; + double d; + + d = __real (dc * dc); +} + diff --git a/gcc/testsuite/gcc.c-torture/compile/20030917-1.c b/gcc/testsuite/gcc.c-torture/compile/20030917-1.c new file mode 100644 index 00000000000..38b6598af14 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20030917-1.c @@ -0,0 +1,18 @@ +typedef struct string STR; +typedef struct atbl ARRAY; +struct string { + unsigned char str_pok; +}; +struct atbl { + int ary_fill; +}; +blah(size,strp) +register int size; +register STR **strp; +{ + register ARRAY *ar; + ar->ary_fill = size - 1; + while (size--) + (*strp)->str_pok &= ~128; +} + diff --git a/gcc/testsuite/gcc.c-torture/compile/20031124-1.c b/gcc/testsuite/gcc.c-torture/compile/20031124-1.c new file mode 100644 index 00000000000..102e71aa84f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20031124-1.c @@ -0,0 +1,8 @@ +/* PR 13143 */ + +int f (void *ptr) +{ + extern char const stop[]; + return ptr >= (void *) &stop; +} + diff --git a/gcc/testsuite/gcc.c-torture/compile/20031125-1.c b/gcc/testsuite/gcc.c-torture/compile/20031125-1.c new file mode 100644 index 00000000000..735a20bc241 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20031125-1.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +short *_offsetTable; +/* This tests to make sure PRE splits the entry block ->block 0 edge + when there are multiple block 0 predecessors. + This is done so that we don't end up with an insertion on the + entry block -> block 0 edge which would require a split at insertion + time. + PR 13163. */ +void proc4WithoutFDFE(char *dst, const char *src, int next_offs, int bw, + int bh, int pitch) +{ + do { + int i = bw; + int code = *src++; + int x, l; + int length = *src++ + 1; + + for (l = 0; l < length; l++) { + int x; + + for (x = 0; x < 4; x++) ; + if (i == 0) + dst += pitch * 3; + } + char *dst2 = dst + _offsetTable[code] + next_offs; + + for (x = 0; x < 4; x++) { + int j = 0; + (dst + pitch * x)[j] = (dst2 + pitch * x)[j]; + } + dst += pitch * 3; + } while (--bh); +} + + diff --git a/gcc/testsuite/gcc.c-torture/compile/20031125-2.c b/gcc/testsuite/gcc.c-torture/compile/20031125-2.c new file mode 100644 index 00000000000..2af8a021175 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20031125-2.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +struct BlobSpan { + int right; +}; +/* This test makes sure we don't accidently cause a bad insertion to occur + by choosing the wrong variable name so that we end up with a use not + dominated by a def. */ +void render_blob_line(struct BlobSpan blobdata) { + int buf[4 * 8]; + int *data = buf; + int i, n = 0; + if (blobdata.right) + n++; + if (n) + for (; i < 2 * n;) + data[i] = 0; + n *= 2; + for (; n;) ; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20031203-1.c b/gcc/testsuite/gcc.c-torture/compile/20031203-1.c new file mode 100644 index 00000000000..7827eb9066f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20031203-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +void make_file_symbol_completion_list (char *); +/* This tests to make sure PRE doesn't choose the wrong name when + inserting phi nodes. Otherwise, we get uses that aren't dominated + by defs. + PR 13177. */ +void location_completer (char *text) +{ + char *p, *symbol_start = text; + for (p = text; *p != '\0'; ++p) { + if (*p == '\\' && p[1] == '\'') + p++; + else if (*p == ':') + symbol_start = p + 1; + else + symbol_start = p + 1; + make_file_symbol_completion_list(symbol_start); + } +} + + diff --git a/gcc/testsuite/gcc.c-torture/compile/20031203-2.c b/gcc/testsuite/gcc.c-torture/compile/20031203-2.c new file mode 100644 index 00000000000..47f561bae77 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20031203-2.c @@ -0,0 +1,6 @@ +/* Don't ICE on stupid user tricks. */ + +int foo(int bar) +{ + return (&bar)[-1]; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20031203-3.c b/gcc/testsuite/gcc.c-torture/compile/20031203-3.c new file mode 100644 index 00000000000..341a9df984a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20031203-3.c @@ -0,0 +1,7 @@ +/* Don't ICE on user silliness. GCC 3.4 and before accepts this without + comment; 3.5 warns. Perhaps eventually we'll declare this an error. */ + +void bar (void) +{ + ({}); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040219-1.c b/gcc/testsuite/gcc.c-torture/compile/20040219-1.c new file mode 100644 index 00000000000..d3bc9272b64 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040219-1.c @@ -0,0 +1 @@ +double foo() { return __builtin_isgreater(0.,0.); } diff --git a/gcc/testsuite/gcc.c-torture/compile/20040220-1.c b/gcc/testsuite/gcc.c-torture/compile/20040220-1.c new file mode 100644 index 00000000000..8a4a5ba6d0f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040220-1.c @@ -0,0 +1,16 @@ +/* PR 14194 */ + +int irqs; + +static inline __attribute__((always_inline)) +int kstat_irqs (void) { + int i, sum = 0; + for (i = 0; i < 1; i++) + if (__builtin_expect(i, 0)) + sum += irqs; + return sum; +} + +int show_interrupts (void) { + return kstat_irqs (); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040303-1.c b/gcc/testsuite/gcc.c-torture/compile/20040303-1.c new file mode 100644 index 00000000000..6b2452adab9 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040303-1.c @@ -0,0 +1,16 @@ +typedef struct input { + struct input *next; +} input_t; +static input_t *inputs = (input_t *)((void *)0); +void +RemoveInput(unsigned long id) +{ + input_t *ip; + input_t *prev; + while (1) + if (ip == (input_t *)id) + break; + if (ip == (input_t *)((void *)0)) + return; + prev->next = ip->next; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040303-2.c b/gcc/testsuite/gcc.c-torture/compile/20040303-2.c new file mode 100644 index 00000000000..6751620a43a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040303-2.c @@ -0,0 +1,23 @@ +void abort(void); +int x, y; +void init_xy(void); +void +test4(void) +{ + init_xy(); + _Bool iftemp0; + int x1 = x; + _Bool iftemp1; + x1++; + if (x1 != 3) + { + iftemp1 = 1; + goto endfirstif; + } + iftemp1 = 0; + endfirstif: + iftemp0 = iftemp1; + if (iftemp0) + abort(); +} + diff --git a/gcc/testsuite/gcc.c-torture/compile/20040304-1.c b/gcc/testsuite/gcc.c-torture/compile/20040304-1.c index 146d42f23d6..ee277d799a4 100644 --- a/gcc/testsuite/gcc.c-torture/compile/20040304-1.c +++ b/gcc/testsuite/gcc.c-torture/compile/20040304-1.c @@ -1,45 +1,20 @@ -/* PR optimization/14235 */ -/* Origin: */ - -typedef signed char int8_t; -typedef short int16_t; -typedef int int32_t; -typedef unsigned long long uint64_t; - -static const uint64_t LOW_BYTE_MASK = 0x00000000000000ffULL; -static const uint64_t HIGH_BYTE_MASK = 0x000000000000ff00ULL; -static const uint64_t WORD_MASK = 0x000000000000ffffULL; -static const uint64_t DWORD_MASK = 0x00000000ffffffffULL; - -extern uint64_t *srca_mask; -extern int *assert_thrown; - -void foo() +void +cpplib_macroExpand (char * pfile) { - uint64_t tempA = 0; /* actually a bunch of code to set A */ - uint64_t tempB = 0; /* actually a bunch of code to set B */ - - /* cast A to right size */ - tempA = (((*srca_mask == LOW_BYTE_MASK) || - (*srca_mask == HIGH_BYTE_MASK)) ? - ((int8_t)tempA) : - ((*srca_mask == WORD_MASK) ? - ((int16_t)tempA) : - ((*srca_mask == DWORD_MASK) ? - ((int32_t)tempA) : - tempA))); - - /* cast B to right size */ - tempB = (((*srca_mask == LOW_BYTE_MASK) || - (*srca_mask == HIGH_BYTE_MASK)) ? - ((int8_t)tempB) : - ((*srca_mask == WORD_MASK) ? - ((int16_t)tempB) : - ((*srca_mask == DWORD_MASK) ? - ((int32_t)tempB) : - tempB))); - - if ((int) tempA > (int) tempB) { - *assert_thrown = 1; - } + int nargs; + int rest_args; + int token = -1; + rest_args = 0; + do + { + if (rest_args != 0) + continue; + if (nargs == 0) + { + rest_args = 1; + token = macarg (pfile, rest_args); + } + } + while (token == 20); } + diff --git a/gcc/testsuite/gcc.c-torture/compile/20040309-1.c b/gcc/testsuite/gcc.c-torture/compile/20040309-1.c new file mode 100644 index 00000000000..df8390f207b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040309-1.c @@ -0,0 +1,20 @@ +static const char default_tupleseps[] = ", \t"; + + +fubar (tupleseps) + const char *tupleseps; +{ + char *kp, *sp; + const char *septmp; + const char *tseplist; + tseplist = (tupleseps) ? tupleseps : default_tupleseps; + while (kp) + { + if (*tseplist) + septmp = tseplist; + bar (*septmp); + if (*tseplist) + if (*kp) + ; + } +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040310-1.c b/gcc/testsuite/gcc.c-torture/compile/20040310-1.c new file mode 100644 index 00000000000..f0c85f0ada5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040310-1.c @@ -0,0 +1,10 @@ +void I_wacom () +{ + char buffer[50], *p; + int RequestData (char *cmd) + { + p = buffer; + foo (buffer); + } + RequestData (0); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040317-1.c b/gcc/testsuite/gcc.c-torture/compile/20040317-1.c new file mode 100644 index 00000000000..4a3455115cb --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040317-1.c @@ -0,0 +1,4 @@ +int String2Array(int len, char strarr[][len]) +{ + strarr[0]; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040317-2.c b/gcc/testsuite/gcc.c-torture/compile/20040317-2.c new file mode 100644 index 00000000000..3c8ee2b8ec5 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040317-2.c @@ -0,0 +1,25 @@ +typedef struct _ScaleRec *ScaleWidget; +typedef struct +{ + short *x; + unsigned short *width; +} Table; +typedef struct +{ + Table table; +} ScalePart; +typedef struct _ScaleRec +{ + ScalePart scale; +} ScaleRec; +static int +FindPixel (ScaleWidget sw, short x, short y, + short * img_x, short * img_y, unsigned long * img_pixel) +{ + if (sw->scale.table.x[(int) *img_x] + + (short) sw->scale.table.width[(int) *img_x] < x) + { + ++*img_x; + return FindPixel (sw, x, y, img_x, img_y, img_pixel); + } +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040317-3.c b/gcc/testsuite/gcc.c-torture/compile/20040317-3.c new file mode 100644 index 00000000000..e6982c3e3b3 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040317-3.c @@ -0,0 +1,11 @@ +I_wacom () +{ + char buffer[50], *p; + int RequestData (char *cmd) + { + p = buffer; + foo (buffer); + } + RequestData (0); +} + diff --git a/gcc/testsuite/gcc.c-torture/compile/20040323-1.c b/gcc/testsuite/gcc.c-torture/compile/20040323-1.c new file mode 100644 index 00000000000..c87e7dc70ba --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040323-1.c @@ -0,0 +1,11 @@ +/* PR 14694 */ +/* { dg-require-alias "" } */ + +extern unsigned int _rtld_local __attribute__ ((alias ("_rtld_global"))); + +unsigned int +_dl_start (void *arg) +{ + unsigned int elf_machine_rel () { return _rtld_local; } + return elf_machine_rel (); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040401-1.c b/gcc/testsuite/gcc.c-torture/compile/20040401-1.c new file mode 100644 index 00000000000..ee727a9b205 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040401-1.c @@ -0,0 +1,6 @@ +int __atomic_readv_replacement(unsigned char iov_len, int count, int i) { + unsigned char bytes = 0; + if ((unsigned char)((char)127 - bytes) < iov_len) + return 22; + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040415-1.c b/gcc/testsuite/gcc.c-torture/compile/20040415-1.c new file mode 100644 index 00000000000..1b1537a7ba6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040415-1.c @@ -0,0 +1,5 @@ +int isdigit (int); +int f (const char *type) +{ + return isdigit ((unsigned char) *type++); +} diff --git a/gcc/testsuite/gcc.c-torture/compile/20040415-2.c b/gcc/testsuite/gcc.c-torture/compile/20040415-2.c new file mode 100644 index 00000000000..e78e81e8cf8 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20040415-2.c @@ -0,0 +1,7 @@ +int isascii (int); + +int f1 (const char *type) +{ + return isascii ((unsigned char) *type++); +} + diff --git a/gcc/testsuite/gcc.c-torture/compile/pr14730.c b/gcc/testsuite/gcc.c-torture/compile/pr14730.c new file mode 100644 index 00000000000..b4f36a9ae3c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr14730.c @@ -0,0 +1,16 @@ +/* PR middle-end/14730 */ + +int t (char i) +{ + switch (i) + { + case 1: + case 7: + case 10: + case 14: + case 9: + case 256: + return 0; + } + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/compile/pr15245.c b/gcc/testsuite/gcc.c-torture/compile/pr15245.c new file mode 100644 index 00000000000..d7d9051a1c1 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr15245.c @@ -0,0 +1,21 @@ +/* Testcase from + PR optimization/15245 + This used to ICE as convert was used + in tree-ssa-phiopt which created non gimple + code. */ + +char *f(char *x, int flag) +{ + char *ret = (char*)0; + + + if( x > (char*)1 ) { + if(x) + return (char*)0; + } else { + if( flag & 1 ) + ret = (char*)1; + flag |= 2; + } + return ret; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20000603-1.c b/gcc/testsuite/gcc.c-torture/execute/20000603-1.c index 9c9f69baf04..4e31eee4563 100644 --- a/gcc/testsuite/gcc.c-torture/execute/20000603-1.c +++ b/gcc/testsuite/gcc.c-torture/execute/20000603-1.c @@ -1,5 +1,10 @@ +/* It is not clear whether this test is conforming. See DR#236 + http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_236.htm. However, + there seems to be consensus that the presence of a union to aggregate + struct s1 and struct s2 should make it conforming. */ struct s1 { double d; }; struct s2 { double d; }; +union u { struct s1 x; struct s2 y; }; double f(struct s1 *a, struct s2 *b) { @@ -9,9 +14,9 @@ double f(struct s1 *a, struct s2 *b) int main() { - struct s1 a; - a.d = 0.0; - if (f (&a, (struct s2 *)&a) != 2.0) + union u a; + a.x.d = 0.0; + if (f (&a.x, &a.y) != 2.0) abort (); return 0; } diff --git a/gcc/testsuite/gcc.c-torture/execute/20020819-1.c b/gcc/testsuite/gcc.c-torture/execute/20020819-1.c new file mode 100644 index 00000000000..549da910cd4 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20020819-1.c @@ -0,0 +1,22 @@ +foo () +{ + return 0; +} + +main() +{ + int i, j, k, ccp_bad = 0; + + for (i = 0; i < 10; i++) + { + for (j = 0; j < 10; j++) + if (foo ()) + ccp_bad = 1; + + k = ccp_bad != 0; + if (k) + abort (); + } + + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20021113-1.c b/gcc/testsuite/gcc.c-torture/execute/20021113-1.c new file mode 100644 index 00000000000..420926d7548 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20021113-1.c @@ -0,0 +1,17 @@ +/* This program tests a data flow bug that would cause constant propagation + to propagate constants through function calls. */ + +foo (int *p) +{ + *p = 10; +} + +main() +{ + int *ptr = alloca (sizeof (int)); + *ptr = 5; + foo (ptr); + if (*ptr == 5) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20030403-1.c b/gcc/testsuite/gcc.c-torture/execute/20030403-1.c new file mode 100644 index 00000000000..cbf1351c4be --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030403-1.c @@ -0,0 +1,16 @@ +/* The non-destructive folder was always emitting >= when folding + comparisons to signed_max+1. */ + +#include + +int +main () +{ + unsigned long count = 8; + + if (count > INT_MAX) + abort (); + + return (0); +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/20030404-1.c b/gcc/testsuite/gcc.c-torture/execute/20030404-1.c new file mode 100644 index 00000000000..1dd1ec09906 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030404-1.c @@ -0,0 +1,23 @@ +/* This exposed a bug in tree-ssa-ccp.c. Since 'j' and 'i' are never + defined, CCP was not traversing the edges out of the if(), which caused + the PHI node for 'k' at the top of the while to only be visited once. + This ended up causing CCP to think that 'k' was the constant '1'. */ +main() +{ + int i, j, k; + + k = 0; + while (k < 10) + { + k++; + if (j > i) + j = 5; + else + j =3; + } + + if (k != 10) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20030501-1.c b/gcc/testsuite/gcc.c-torture/execute/20030501-1.c new file mode 100644 index 00000000000..f47dc291bd3 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030501-1.c @@ -0,0 +1,17 @@ +int +main (int argc, char **argv) +{ + int size = 10; + + { + int retframe_block() + { + return size + 5; + } + + if (retframe_block() != 15) + abort (); + exit (0); + + } +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20030828-1.c b/gcc/testsuite/gcc.c-torture/execute/20030828-1.c new file mode 100644 index 00000000000..e8c1f0195df --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030828-1.c @@ -0,0 +1,18 @@ +const int *p; + +int bar (void) +{ + return *p + 1; +} + +main () +{ + /* Variable 'i' is never used but it's aliased to a global pointer. The + alias analyzer was not considering that 'i' may be used in the call to + bar(). */ + const int i = 5; + p = &i; + if (bar() != 6) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20030828-2.c b/gcc/testsuite/gcc.c-torture/execute/20030828-2.c new file mode 100644 index 00000000000..0c3a195e626 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030828-2.c @@ -0,0 +1,28 @@ +struct rtx_def +{ + int code; +}; + +main() +{ + int tmp[2]; + struct rtx_def *r, s; + int *p, *q; + + /* The alias analyzer was creating the same memory tag for r, p and q + because 'struct rtx_def *' is type-compatible with 'int *'. However, + the alias set of 'int[2]' is not the same as 'int *', so variable + 'tmp' was deemed not aliased with anything. */ + r = &s; + r->code = 39; + + /* If 'r' wasn't declared, then q and tmp would have had the same memory + tag. */ + p = tmp; + q = p + 1; + *q = 0; + tmp[1] = 39; + if (*q != 39) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20030903-1.c b/gcc/testsuite/gcc.c-torture/execute/20030903-1.c new file mode 100644 index 00000000000..95dad576f2d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030903-1.c @@ -0,0 +1,21 @@ +/* Test that we don't let stmt.c think that the enumeration's values are + the entire set of possibilities. Such an assumption is false for C, + but true for other languages. */ + +enum X { X1 = 1, X2, X3, X4 }; +static volatile enum X test = 0; +static void y(int); + +int main() +{ + switch (test) + { + case X1: y(1); break; + case X2: y(2); break; + case X3: y(3); break; + case X4: y(4); break; + } + return 0; +} + +static void y(int x) { abort (); } diff --git a/gcc/testsuite/gcc.c-torture/execute/20030909-1.c b/gcc/testsuite/gcc.c-torture/execute/20030909-1.c new file mode 100644 index 00000000000..2f149857fc7 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030909-1.c @@ -0,0 +1,35 @@ +void abort (); +void exit (int); + +void test(int x, int y) +{ + if (x == y) + abort (); +} + +void foo(int x, int y) +{ + if (x == y) + goto a; + else + { +a:; + if (x == y) + goto b; + else + { +b:; + if (x != y) + test (x, y); + } + } +} + +int main(void) +{ + foo (0, 0); + + exit (0); +} + + diff --git a/gcc/testsuite/gcc.c-torture/execute/20030910-1.c b/gcc/testsuite/gcc.c-torture/execute/20030910-1.c new file mode 100644 index 00000000000..6c849134a9b --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030910-1.c @@ -0,0 +1,13 @@ +/* The gimplifier was inserting unwanted temporaries for REALPART_EXPR + nodes. These need to be treated like a COMPONENT_REF so their address can + be taken. */ + +int main() +{ + __complex double dc; + double *dp = &(__real dc); + *dp = 3.14; + if ((__real dc) != 3.14) abort(); + exit (0); +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/20030913-1.c b/gcc/testsuite/gcc.c-torture/execute/20030913-1.c new file mode 100644 index 00000000000..5e33f50f560 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20030913-1.c @@ -0,0 +1,26 @@ +/* Assignments via pointers pointing to global variables were being killed + by SSA-DCE. Test contributed by Paul Brook */ + +int glob; + +void +fn2(int ** q) +{ + *q = &glob; +} + +void test() +{ + int *p; + + fn2(&p); + + *p=42; +} + +int main() +{ + test(); + if (glob != 42) abort(); + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20031010-1.c b/gcc/testsuite/gcc.c-torture/execute/20031010-1.c new file mode 100644 index 00000000000..54457f964c3 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20031010-1.c @@ -0,0 +1,34 @@ +/* A reminder to process ops in generate_expr_as_of_bb exactly once. */ + +long __attribute__((noinline)) +foo (long ct, long cf, _Bool p1, _Bool p2, _Bool p3) +{ + long diff; + + diff = ct - cf; + + if (p1) + { + if (p2) + { + if (p3) + { + long tmp = ct; + ct = cf; + cf = tmp; + } + diff = ct - cf; + } + + return diff; + } + + abort (); +} + +int main () +{ + if (foo(2, 3, 1, 1, 1) == 0) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20031211-1.c b/gcc/testsuite/gcc.c-torture/execute/20031211-1.c new file mode 100644 index 00000000000..2361509a096 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20031211-1.c @@ -0,0 +1,13 @@ +struct a { unsigned int bitfield : 1; }; + +unsigned int x; + +main() +{ + struct a a = {0}; + x = 0xbeef; + a.bitfield |= x; + if (a.bitfield != 1) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20031211-2.c b/gcc/testsuite/gcc.c-torture/execute/20031211-2.c new file mode 100644 index 00000000000..555b17d9ac6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20031211-2.c @@ -0,0 +1,19 @@ +struct a +{ + unsigned int bitfield : 3; +}; + +int main() +{ + struct a a; + + a.bitfield = 131; + foo (a.bitfield); + exit (0); +} + +foo(unsigned int z) +{ + if (z != 3) + abort (); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20040319-1.c b/gcc/testsuite/gcc.c-torture/execute/20040319-1.c new file mode 100644 index 00000000000..357932d9b24 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040319-1.c @@ -0,0 +1,17 @@ +int +blah (int zzz) +{ + int foo; + if (zzz >= 0) + return 1; + foo = (zzz >= 0 ? (zzz) : -(zzz)); + return foo; +} + +main() +{ + if (blah (-1) != 1) + abort (); + else + exit (0); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/20040423-1.c b/gcc/testsuite/gcc.c-torture/execute/20040423-1.c new file mode 100644 index 00000000000..ace797e79d3 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/20040423-1.c @@ -0,0 +1,30 @@ +int +sub1 (int i, int j) +{ + typedef struct + { + int c[i+2]; + }c; + int x[10], y[10]; + + if (j == 2) + { + memcpy (x, y, 10 * sizeof (int)); + return sizeof (c); + } + else + return sizeof (c) * 3; +} + +int +main () +{ + typedef struct + { + int c[22]; + }c; + if (sub1 (20, 3) != sizeof (c)*3) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/930529-1.x b/gcc/testsuite/gcc.c-torture/execute/930529-1.x index a44f482c22f..fb86979f7c1 100644 --- a/gcc/testsuite/gcc.c-torture/execute/930529-1.x +++ b/gcc/testsuite/gcc.c-torture/execute/930529-1.x @@ -4,15 +4,20 @@ # The problem is that the multiplication was unsigned SImode, and the # induction variable is DImode, and we lose the truncation that # should have happened. +# +# On tree-ssa branch, the loop problem is still extant, but the +# gimple-level optimization makes it easy for the tree-rtl expanders +# to see that the comparisons are always true, and so the loop code +# is never exercized. -set torture_eval_before_execute { - - set compiler_conditional_xfail_data { - "division by a constant conflicts with strength reduction" \ - "alpha*-*-*" \ - { "-O3" } \ - { "" } - } -} +# set torture_eval_before_execute { +# +# set compiler_conditional_xfail_data { +# "division by a constant conflicts with strength reduction" \ +# "alpha*-*-*" \ +# { "-O3" } \ +# { "" } +# } +# } return 0 diff --git a/gcc/testsuite/gcc.c-torture/execute/builtin-constant.x b/gcc/testsuite/gcc.c-torture/execute/builtin-constant.x deleted file mode 100644 index 7a2e3146675..00000000000 --- a/gcc/testsuite/gcc.c-torture/execute/builtin-constant.x +++ /dev/null @@ -1,11 +0,0 @@ -set torture_eval_before_execute { - global compiler_conditional_xfail_data - set compiler_conditional_xfail_data { - "This test fails on all targets when optimizing." \ - { "*-*-*" } \ - { "-O1" } \ - { "" } - } -} - -return 0 diff --git a/gcc/testsuite/gcc.dg/20010516-1.c b/gcc/testsuite/gcc.dg/20010516-1.c new file mode 100644 index 00000000000..e9b419f1a68 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20010516-1.c @@ -0,0 +1,5 @@ +foo() +{ + char d; + __asm volatile ( "" :: "m"(&d)); /* { dg-error "" "non-lvalue" } */ +} diff --git a/gcc/testsuite/gcc.dg/20030612-1.c b/gcc/testsuite/gcc.dg/20030612-1.c index f9f212caba1..5ecc4c1da89 100644 --- a/gcc/testsuite/gcc.dg/20030612-1.c +++ b/gcc/testsuite/gcc.dg/20030612-1.c @@ -1,20 +1,22 @@ -/* Derived from PR middle-end/168. */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ -/* { dg-do compile } */ -/* { dg-options "-W" } */ +int A, B; -extern void foo (); - -unsigned char uc; -unsigned short int usi; -unsigned int ui; - - -void bar() +void foo() { - if (uc + usi >= ui) /* { dg-bogus "between signed and unsigned" } */ - foo (); - if (uc * usi >= ui) /* { dg-bogus "between signed and unsigned" } */ - foo (); + long x = 3; + (void)({ + A = B + x + ((1) - 1); + return; /* { dg-warning "statement-expressions should end with a non-void expression" } */ + }); } +main() +{ + B = 5; + foo(); + if (A != 8) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/20030805-1.c b/gcc/testsuite/gcc.dg/20030805-1.c new file mode 100644 index 00000000000..6297c5d83ea --- /dev/null +++ b/gcc/testsuite/gcc.dg/20030805-1.c @@ -0,0 +1,23 @@ +/* Test that gcc understands that the call to g might clobber i. */ + +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +__inline int f () +{ + static int i; + int i2 = i; + i = i2 + 1; + return i; +} + +int g () { return f (); } + +int main () +{ + if (f() != 1 + || g() != 2 + || f() != 3) + return 1; + return 0; +} diff --git a/gcc/testsuite/gcc.dg/20040202-1.c b/gcc/testsuite/gcc.dg/20040202-1.c new file mode 100644 index 00000000000..f0f4e74109a --- /dev/null +++ b/gcc/testsuite/gcc.dg/20040202-1.c @@ -0,0 +1,8 @@ +/* PR middle-end/13325 */ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +void *memcpy(void *dest, const void *src, __SIZE_TYPE__ n); +void f (void *dest, const void *src) { + memcpy (dest, src, 0); +} diff --git a/gcc/testsuite/gcc.dg/20040206-1.c b/gcc/testsuite/gcc.dg/20040206-1.c new file mode 100644 index 00000000000..7fc4b0d7605 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20040206-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -W -Wall" } */ +/* PR c/13127 + On the tree-ssa this used to warn about an anonymous + uninitialized variable. + + The warning about "no return statement in function + returning non-void" is PR 13000. */ + +static int foo (int a __attribute__((unused)) ) { } /* { dg-warning "return" "" { xfail *-*-* } } */ +int main (void) { return foo (0); } diff --git a/gcc/testsuite/gcc.dg/Wswitch-2.c b/gcc/testsuite/gcc.dg/Wswitch-2.c index b151e2310c7..9bc7d022b46 100644 --- a/gcc/testsuite/gcc.dg/Wswitch-2.c +++ b/gcc/testsuite/gcc.dg/Wswitch-2.c @@ -13,19 +13,19 @@ foo (enum e ei, int j) case e3: return 2; case e4: return 3; } /* No warning here since e2 has the same value as e3. */ - switch (ei) + switch (ei) /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */ { case e1: return 1; case e2: return 2; - } /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */ + } switch ((int) ei) { case e1: return 1; } /* No warning here since switch condition was cast to int. */ - switch ((enum e) j) + switch ((enum e) j) /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ { case e2: return 1; case e4: return 2; - } /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ + } return 0; } diff --git a/gcc/testsuite/gcc.dg/Wswitch-default.c b/gcc/testsuite/gcc.dg/Wswitch-default.c index a1a3d39c1d9..2d4e7994c25 100644 --- a/gcc/testsuite/gcc.dg/Wswitch-default.c +++ b/gcc/testsuite/gcc.dg/Wswitch-default.c @@ -7,11 +7,11 @@ int foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, enum e em, enum e en, enum e eo, enum e ep) { - switch (i) + switch (i) /* { dg-warning "switch missing default case" } */ { case 1: return 1; case 2: return 2; - } /* { dg-warning "switch missing default case" } */ + } switch (j) { case 3: return 4; @@ -25,32 +25,32 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, { default: break; } - switch (ek) + switch (ek) /* { dg-warning "switch missing default case" } */ { case e1: return 1; - } /* { dg-warning "switch missing default case" } */ + } switch (el) { case e1: return 1; default: break; } - switch (em) + switch (em) /* { dg-warning "switch missing default case" } */ { case e1: return 1; case e2: return 2; - } /* { dg-warning "switch missing default case" } */ + } switch (en) { case e1: return 1; case e2: return 2; default: break; } - switch (eo) + switch (eo) /* { dg-warning "switch missing default case" } */ { case e1: return 1; case e2: return 2; case 3: return 3; - } /* { dg-warning "switch missing default case" } */ + } switch (ep) { case e1: return 1; diff --git a/gcc/testsuite/gcc.dg/Wswitch-enum.c b/gcc/testsuite/gcc.dg/Wswitch-enum.c index d031b12ce14..b51ecfdcc9e 100644 --- a/gcc/testsuite/gcc.dg/Wswitch-enum.c +++ b/gcc/testsuite/gcc.dg/Wswitch-enum.c @@ -22,19 +22,19 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, switch (ei) /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ { /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" { target *-*-* } 22 } */ } - switch (ej) - { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" { target *-*-* } 28 } */ + switch (ej) /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ + { /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" { target *-*-* } 25 } */ default: break; - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ - switch (ek) + } + switch (ek) /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ { case e1: return 1; - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ - switch (el) + } + switch (el) /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ { case e1: return 1; default: break; - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ + } switch (em) { case e1: return 1; @@ -50,14 +50,14 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, { case e1: return 1; case e2: return 2; - case 3: return 3; - } /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + case 3: return 3; /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + } switch (ep) { case e1: return 1; case e2: return 2; - case 3: return 3; + case 3: return 3; /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ default: break; - } /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + } return 0; } diff --git a/gcc/testsuite/gcc.dg/Wswitch.c b/gcc/testsuite/gcc.dg/Wswitch.c index 38c3cbbb446..e3deeab0f4b 100644 --- a/gcc/testsuite/gcc.dg/Wswitch.c +++ b/gcc/testsuite/gcc.dg/Wswitch.c @@ -26,10 +26,10 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, { default: break; } - switch (ek) + switch (ek) /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ { case e1: return 1; - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ + } switch (el) { case e1: return 1; @@ -50,8 +50,8 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, { case e1: return 1; case e2: return 2; - case 3: return 3; - } /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + case 3: return 3; /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + } switch (ep) { case e1: return 1; diff --git a/gcc/testsuite/gcc.dg/asm-7.c b/gcc/testsuite/gcc.dg/asm-7.c index 42f40e719f9..a14bb807369 100644 --- a/gcc/testsuite/gcc.dg/asm-7.c +++ b/gcc/testsuite/gcc.dg/asm-7.c @@ -12,8 +12,8 @@ void test(void) __asm__ ("" : : "m"(r)); /* { dg-warning "address of register" } */ __asm__ ("" : : "m"(i)); __asm__ ("" : : "m"(m)); - __asm__ ("" : : "m"(0)); /* { dg-warning "input without lvalue" } */ - __asm__ ("" : : "m"(i+1)); /* { dg-warning "input without lvalue" } */ + __asm__ ("" : : "m"(0)); /* { dg-error "" } */ + __asm__ ("" : : "m"(i+1)); /* { dg-error "" } */ __asm__ ("" : : "m"(*p++)); __asm__ ("" : : "g"(r)); diff --git a/gcc/testsuite/gcc.dg/i386-ssetype-1.c b/gcc/testsuite/gcc.dg/i386-ssetype-1.c index 50d0fcaa58a..e4a099bb0b0 100644 --- a/gcc/testsuite/gcc.dg/i386-ssetype-1.c +++ b/gcc/testsuite/gcc.dg/i386-ssetype-1.c @@ -4,7 +4,8 @@ /* { dg-final { scan-assembler "andnpd\[^\\n\]*magic" } } */ /* { dg-final { scan-assembler "xorpd\[^\\n\]*magic" } } */ /* { dg-final { scan-assembler "orpd\[^\\n\]*magic" } } */ -/* { dg-final { scan-assembler-not "movdqa" } } */ +/* ??? All of the backend patters are WAY too fragile. */ +/* { dg-final { scan-assembler-not "movdqa" { xfail *-*-* } } } */ /* { dg-final { scan-assembler "movapd\[^\\n\]*magic" } } */ /* Verify that we generate proper instruction with memory operand. */ diff --git a/gcc/testsuite/gcc.dg/i386-ssetype-3.c b/gcc/testsuite/gcc.dg/i386-ssetype-3.c index 3b2461be32c..f19f5e8b928 100644 --- a/gcc/testsuite/gcc.dg/i386-ssetype-3.c +++ b/gcc/testsuite/gcc.dg/i386-ssetype-3.c @@ -4,7 +4,8 @@ /* { dg-final { scan-assembler "andnps\[^\\n\]*magic" } } */ /* { dg-final { scan-assembler "xorps\[^\\n\]*magic" } } */ /* { dg-final { scan-assembler "orps\[^\\n\]*magic" } } */ -/* { dg-final { scan-assembler-not "movdqa" } } */ +/* ??? All of the backend patters are WAY too fragile. */ +/* { dg-final { scan-assembler-not "movdqa" { xfail *-*-* } } } */ /* { dg-final { scan-assembler "movaps\[^\\n\]*magic" } } */ /* Verify that we generate proper instruction with memory operand. */ diff --git a/gcc/testsuite/gcc.dg/local1.c b/gcc/testsuite/gcc.dg/local1.c index 9d6fdb16752..e9f653bcc56 100644 --- a/gcc/testsuite/gcc.dg/local1.c +++ b/gcc/testsuite/gcc.dg/local1.c @@ -3,14 +3,14 @@ C90 6.1.2.2 [as corrected by TC1], C99 6.2.2: - For an identifier declared with the storage-class specifier - extern in a scope in which a prior declaration of that - identifier is visible, if the prior declaration specifies - internal or external linkage, the linkage of the identifier at - the later daclaration is the same as the linkage specified at - the prior declaration. If no prior declaration is visible, - or if the prior declaration specifies no linkage, then the - identifer has external linkage. + For an identifier declared with the storage-class specifier + extern in a scope in which a prior declaration of that + identifier is visible, if the prior declaration specifies + internal or external linkage, the linkage of the identifier at + the later daclaration is the same as the linkage specified at + the prior declaration. If no prior declaration is visible, + or if the prior declaration specifies no linkage, then the + identifer has external linkage. This is PR 14366. */ diff --git a/gcc/testsuite/gcc.dg/noncompile/920507-1.c b/gcc/testsuite/gcc.dg/noncompile/920507-1.c index 64ddce7f1ff..c1a3523008c 100644 --- a/gcc/testsuite/gcc.dg/noncompile/920507-1.c +++ b/gcc/testsuite/gcc.dg/noncompile/920507-1.c @@ -1,6 +1,7 @@ -void +int * x(void) { register int *a asm("unknown_register"); /* { dg-error "invalid register" } */ int *v[1] = {a}; + return v[1]; } diff --git a/gcc/testsuite/gcc.dg/noreturn-1.c b/gcc/testsuite/gcc.dg/noreturn-1.c index 3bf62c15b40..90660fa028c 100644 --- a/gcc/testsuite/gcc.dg/noreturn-1.c +++ b/gcc/testsuite/gcc.dg/noreturn-1.c @@ -7,8 +7,8 @@ extern void exit (int); extern void foo1(void) __attribute__ ((__noreturn__)); void foo1(void) -{ /* { dg-warning "`noreturn' function does return" "detect falling off end of noreturn" } */ -} +{ +} /* { dg-warning "`noreturn' function does return" "detect falling off end of noreturn" } */ extern void foo2(void) __attribute__ ((__noreturn__)); void @@ -26,16 +26,17 @@ foo3(void) extern void foo4(void); void foo4(void) -{ +{ /* { dg-warning "candidate for attribute `noreturn'" "detect noreturn candidate" } */ exit(0); -} /* { dg-warning "candidate for attribute `noreturn'" "detect noreturn candidate" } */ +} extern void foo5(void) __attribute__ ((__noreturn__)); void foo5(void) { return; /* { dg-warning "`noreturn' has a `return' statement" "detect invalid return" } */ -} /* { dg-warning "`noreturn' function does return" "detect return from noreturn" } */ +} +/* { dg-warning "function does return" "detect return from noreturn" { target *-*-* } 37 } */ extern void foo6(void); void diff --git a/gcc/testsuite/gcc.dg/noreturn-4.c b/gcc/testsuite/gcc.dg/noreturn-4.c index 4a2de5f4200..6a081b3fb4e 100644 --- a/gcc/testsuite/gcc.dg/noreturn-4.c +++ b/gcc/testsuite/gcc.dg/noreturn-4.c @@ -5,6 +5,6 @@ extern void exit (int) __attribute__ ((__noreturn__)); int main (void) -{ +{ /* { dg-warning "warning: function might be possible candidate for attribute `noreturn'" "warn for main" } */ exit (0); -} /* { dg-warning "warning: function might be possible candidate for attribute `noreturn'" "warn for main" } */ +} diff --git a/gcc/testsuite/gcc.dg/noreturn-7.c b/gcc/testsuite/gcc.dg/noreturn-7.c index 1d94a7ccea5..94a26cc3875 100644 --- a/gcc/testsuite/gcc.dg/noreturn-7.c +++ b/gcc/testsuite/gcc.dg/noreturn-7.c @@ -14,11 +14,11 @@ void _exit(int status) __attribute__ ((__noreturn__)); int z = 0; void g() -{ +{ /* { dg-warning "possible candidate" } */ if (++z > 10) _exit(0); g(); -} /* { dg-warning "possible candidate" } */ +} void f() { @@ -28,15 +28,15 @@ void f() } /* { dg-bogus "does return" } */ int h() -{ +{ /* { dg-warning "possible candidate" } */ if (++z > 10) _exit(0); return h(); } /* { dg-bogus "end of non-void function" } */ int k() -{ +{ /* { dg-warning "possible candidate" } */ if (++z > 10) _exit(0); k(); -} /* { dg-warning "end of non-void function" } */ +} diff --git a/gcc/testsuite/gcc.dg/pr14475.c b/gcc/testsuite/gcc.dg/pr14475.c new file mode 100644 index 00000000000..8009d465657 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr14475.c @@ -0,0 +1,8 @@ +/* This used to ICE because there was no null check in + check_bitfield_type_and_width. */ + +struct tree_common +{ + enum tree_code code : 8; /* {dg-error "" "" } */ +/* { dg-warning "" "" { target *-*-* } 6 } */ +}; diff --git a/gcc/testsuite/gcc.dg/return-type-1.c b/gcc/testsuite/gcc.dg/return-type-1.c index 037dbbf0823..2507cafa5e4 100644 --- a/gcc/testsuite/gcc.dg/return-type-1.c +++ b/gcc/testsuite/gcc.dg/return-type-1.c @@ -5,5 +5,5 @@ /* { dg-options "-O -Wreturn-type" } */ int foo(void) -{ /* { dg-warning "control reaches end of non-void function" "warning for falling off end of non-void function" } */ -} +{ +} /* { dg-warning "control reaches end of non-void function" "warning for falling off end of non-void function" } */ diff --git a/gcc/testsuite/gcc.dg/return-type-3.c b/gcc/testsuite/gcc.dg/return-type-3.c index b6fa16539a4..e06ba7c0233 100644 --- a/gcc/testsuite/gcc.dg/return-type-3.c +++ b/gcc/testsuite/gcc.dg/return-type-3.c @@ -3,7 +3,7 @@ call optimization. The return clobber insn was cleaned up and the warning was never issued. */ /* { dg-do compile } */ -/* { dg-options "-foptimize-sibling-calls -Wreturn-type" } */ +/* { dg-options "-O -foptimize-sibling-calls -Wreturn-type" } */ extern void foo(void); diff --git a/gcc/testsuite/gcc.dg/tls/asm-1.c b/gcc/testsuite/gcc.dg/tls/asm-1.c index 68c49f61180..476fe7cbb72 100644 --- a/gcc/testsuite/gcc.dg/tls/asm-1.c +++ b/gcc/testsuite/gcc.dg/tls/asm-1.c @@ -3,5 +3,5 @@ __thread int i; int foo () { - asm volatile ("" :: "m" (&i)); /* { dg-error "lvalue" } */ + asm volatile ("" :: "m" (&i)); /* { dg-error "directly addressable" } */ } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030530-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030530-2.c new file mode 100644 index 00000000000..408e2464e96 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030530-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +typedef struct rs6000_stack { + int first_gp_reg_save; +} rs6000_stack_t; +extern char regs_ever_live[113]; +extern rs6000_stack_t *rs6000_stack_info (void); +void +rs6000_emit_prologue (int i, rs6000_stack_t *info) +{ + if (regs_ever_live[info->first_gp_reg_save + i] || i+info->first_gp_reg_save) + gen_rtx_REG (info->first_gp_reg_save + i); +} + +/* There should be precisely one load of first_gp_reg_save. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "first_gp_reg_save" 1 "dom3"} } */ + +/* There should be precisely one addition. If there is more than one, then + the dominator optimizations failed, most likely due to not handling + commutative operands correctly. */ +/* { dg-final { scan-tree-dump-times "\\+" 1 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030611-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030611-1.c new file mode 100644 index 00000000000..d16bda4c1f1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030611-1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +extern int square (int) __attribute__ ((__const__)); +shit(int a) +{ + return square (a) + square (a); + +} + +/* There should be precisely one call to square. If there is more than one, + then the dominator optimizations failed to remove the redundant call. */ +/* { dg-final { scan-tree-dump-times "square" 1 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030703-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030703-1.c new file mode 100644 index 00000000000..f5b3db3460d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030703-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +extern int blah[]; + +foo(int index) +{ + if (blah [(unsigned int)index] != 0) + abort (); + if (blah [(unsigned int)index] != 0) + abort (); +} + +/* There should be precisely one load of blah. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "blah" 1 "dom3"} } */ + +/* There should be exactly one IF conditional. */ +/* { dg-final { scan-tree-dump-times "if " 1 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030703-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030703-2.c new file mode 100644 index 00000000000..a73150a06a3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030703-2.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +union tree_node; +typedef union tree_node *tree; +extern const char tree_code_type[]; + +union tree_node +{ + int code; + long pointer_alias_set; +}; + +long +get_alias_set (t) + tree t; +{ + if (tree_code_type[t->code]) + abort (); + if (t->pointer_alias_set) + { + tree __t = t; + if (tree_code_type[__t->code]) + abort (); + } +} + +/* There should be precisely one load of {t,__t}->code. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "->code" 1 "dom3"} } */ + +/* There should be precisely one load of tree_code_type. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "tree_code_type" 1 "dom3"} } */ + +/* There should be one IF conditional. If 'tree_code_type[t->code]' is + zero, then the third if() conditional is unnecessary. That should cause + the call to abort() to be removed, which in turn causes the whole second + if() to disappear. */ +/* { dg-final { scan-tree-dump-times "if " 1 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030708-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030708-1.c new file mode 100644 index 00000000000..a94f2a7c6c9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030708-1.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ +struct rtx_def; +typedef struct rtx_def *rtx; +enum rtx_code +{ + CALL_INSN, + EXPR_LIST, + NOTE +}; + +struct rtx_def +{ + + enum rtx_code code:16; +}; + +static int +nonlocal_mentioned_p (x) + rtx x; +{ + if (x->code == CALL_INSN) + { + rtx const _rtx = ((x)); + if (_rtx->code != CALL_INSN + && _rtx->code != NOTE + && _rtx->code != EXPR_LIST) + abort (); + } + + blah (&x); +} + +/* There should be no casts to a short unsigned int since the entire + set of conditionals should optimize away. */ +/* { dg-final { scan-tree-dump-times "\\(short unsigned int\\)" 0 "dom3"} } */ + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030709-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030709-1.c new file mode 100644 index 00000000000..dc45cbd73a2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030709-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +static int copying_arguments; +static int +foo () +{ + unsigned int regno; + if (regno < 53 && copying_arguments) + if (regno >= 53) + return 1; +} + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c new file mode 100644 index 00000000000..ffa7f477622 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030709-2.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-cddce" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; +union tree_node; +typedef union tree_node *tree; +typedef struct mem_attrs +{ + int foo; + +} mem_attrs; +union rtunion_def +{ + mem_attrs *rtmem; +}; +typedef union rtunion_def rtunion; +struct rtx_def +{ + rtunion fld[1]; +}; +struct tree_decl +{ + rtx rtl; +}; +union tree_node +{ + struct tree_decl decl; +}; +void * +get_alias_set (t) + tree t; +{ + long set; + if (t->decl.rtl) + return (t->decl.rtl->fld[1].rtmem + ? 0 + : (((t->decl.rtl ? t->decl.rtl: (make_decl_rtl (t, 0), t->decl.rtl)))->fld[1]).rtmem); + return (void*)-1; +} + +/* There should be precisely one load of ->decl.rtl. If there is + more than, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "->decl\\.rtl" 1 "cddce"} } */ + +/* There should be no loads of .rtmem since the complex return statement + is just "return 0". */ +/* { dg-final { scan-tree-dump-times ".rtmem" 0 "cddce"} } */ + +/* There should be one IF statement (the complex return statement should + collapse down to a simple return 0 without any conditionals). */ +/* { dg-final { scan-tree-dump-times "if " 1 "cddce"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030709-3.c b/gcc/testsuite/gcc.dg/tree-ssa/20030709-3.c new file mode 100644 index 00000000000..98681c088c9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030709-3.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +union tree_node; +typedef union tree_node *tree; +enum tree_code +{ + TREE_VEC = 20, +}; +struct tree_common +{ + int code; +}; +struct tree_type +{ + tree binfo; +}; +union tree_node +{ + struct tree_common common; + struct tree_type type; +}; +void +record_component_aliases (type) + tree type; +{ + const tree __z = type->type.binfo; + if (type->type.binfo->common.code != TREE_VEC) + abort (); + + if (__z->common.code != TREE_VEC) + abort (); +} + +/* There should be precisely one load of type.binfo. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "type\\.binfo" 1 "dom3"} } */ + +/* There should be precisely one load of common.code. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "common\\.code" 1 "dom3"} } */ + +/* There should be one IF conditional. */ +/* { dg-final { scan-tree-dump-times "if " 1 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030710-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030710-1.c new file mode 100644 index 00000000000..53e3d5992cf --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030710-1.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +union tree_node; +typedef union tree_node *tree; +struct tree_vec +{ + int length; + tree a[1]; +}; +struct tree_type +{ + tree binfo; +}; +union tree_node +{ + struct tree_type type; + struct tree_vec vec; +}; +void +record_component_aliases (type) + tree type; +{ + if (type->type.binfo->vec.length) + abort (); + for (; (( + { + const tree __z = type->type.binfo; + if (type->type.binfo->vec.length) + abort (); + type->type.binfo->vec.a[4];} + )->vec.length);) + { + if (4 >= type->type.binfo->vec.length) + abort (); + blah (); + } +} + +/* The call to blah should have been eliminated. If the call is not + eliminated, then dominator optimizations failed and it'll be + impossible to delete other unnecessary code. */ +/* { dg-final { scan-tree-dump-not "blah \\(\\)" "dom3" } } */ + +/* There should be two IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 2 "dom3"} } */ + +/* There should be a single load of type.binfo. */ +/* { dg-final { scan-tree-dump-times "type\\.binfo" 1 "dom3"} } */ + +/* There should be two loads of vec.length. */ +/* { dg-final { scan-tree-dump-times "vec.length" 2 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c new file mode 100644 index 00000000000..eba207a25e5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030711-1.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +union tree_node; +typedef union tree_node *tree; +struct tree_vec +{ + int length; + tree a[1]; +}; +struct tree_type +{ + tree binfo; +}; +union tree_node +{ + struct tree_type type; + struct tree_vec vec; +}; + +void +record_component_aliases (type) + tree type; +{ + int i; + if (4 >= type->type.binfo->vec.length) + abort (); + for (; i < (( + { + const tree __t = type->type.binfo; + if (4 >= __t->vec.length) + abort (); type->type.binfo->vec.a[4];} + )->vec.length);) + { + if (4 >= type->type.binfo->vec.length) + abort (); + blah (); + } +} + +/* The call to blah can not be eliminated. */ +/* { dg-final { scan-tree-dump-times "blah \\(\\)" 1 "dom3" } } */ + +/* There should be four IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 4 "dom3"} } */ + +/* There should be two loads of type.binfo. */ +/* { dg-final { scan-tree-dump-times "type\\.binfo" 2 "dom3"} } */ + +/* There should be four loads of vec.length. */ +/* { dg-final { scan-tree-dump-times "vec.length" 4 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030711-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030711-2.c new file mode 100644 index 00000000000..2fd47f753cf --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030711-2.c @@ -0,0 +1,67 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +struct rtx_def; +typedef struct rtx_def *rtx; +struct rtvec_def; +typedef struct rtvec_def *rtvec; +union tree_node; +typedef union tree_node *tree; +typedef struct mem_attrs +{ + long alias; +} +mem_attrs; +union rtunion_def +{ + mem_attrs *rtmem; +}; +typedef union rtunion_def rtunion; +struct rtx_def +{ + int code; + rtunion fld[1]; +}; +struct tree_decl +{ + rtx rtl; +}; +union tree_node +{ + struct tree_decl decl; +}; +long +get_alias_set (t,z) + tree t; + rtx z; +{ + if (t->decl.rtl && (((t->decl.rtl ? z + : (make_decl_rtl (t, 0), t->decl.rtl)))->code)) + return (((((t->decl.rtl ? z : (make_decl_rtl (t, 0), t->decl.rtl)))-> + fld[1]).rtmem) == 0 ? 0 : ((((( + { + t;} + )->decl. + rtl ? z : (make_decl_rtl (t, 0), + t->decl.rtl)))-> + fld[1]).rtmem)->alias); +} + +/* The calls to make_decl_rtl should be eliminated +/* { dg-final { scan-tree-dump-not "make_decl_rtl \\(\\)" "dom3" } } */ + +/* There should be three IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 3 "dom3"} } */ + +/* There should be one loads of decl.rtl. */ +/* { dg-final { scan-tree-dump-times "decl\\.rtl" 1 "dom3"} } */ + +/* There should be one load of code. */ +/* { dg-final { scan-tree-dump-times "code" 1 "dom3"} } */ + +/* There should be one load of rtmem. */ +/* { dg-final { scan-tree-dump-times "rtmem" 1 "dom3"} } */ + +/* There should be one load of alias. */ +/* { dg-final { scan-tree-dump-times "->alias" 1 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030711-3.c b/gcc/testsuite/gcc.dg/tree-ssa/20030711-3.c new file mode 100644 index 00000000000..515f3609f70 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030711-3.c @@ -0,0 +1,59 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +struct rtx_def; +typedef struct rtx_def *rtx; +struct rtvec_def; +typedef struct rtvec_def *rtvec; +union tree_node; +typedef union tree_node *tree; +typedef struct mem_attrs +{ + long alias; +} +mem_attrs; +union rtunion_def +{ + mem_attrs *rtmem; +}; +typedef union rtunion_def rtunion; +struct rtx_def +{ + int code; + rtunion fld[1]; +}; +struct tree_decl +{ + rtx rtl; +}; +union tree_node +{ + struct tree_decl decl; +}; +long +get_alias_set (t) + tree t; +{ + if (t->decl.rtl != (void *) 0) + return (((t->decl.rtl->fld[1]).rtmem) == + 0 ? 0 + : ((((t->decl. + rtl ? 0 : (make_decl_rtl (t, ((void *) 0)), + t->decl.rtl)))->fld[1]).rtmem)->alias); +} + +/* The calls to make_decl_rtl should be eliminated. */ +/* { dg-final { scan-tree-dump-not "make_decl_rtl \\(\\)" "dom3" } } */ + +/* There should be two IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 2 "dom3"} } */ + +/* There should be one load of decl.rtl. */ +/* { dg-final { scan-tree-dump-times "decl\\.rtl" 1 "dom3"} } */ + +/* There should be two loads of rtmem. */ +/* { dg-final { scan-tree-dump-times "rtmem" 2 "dom3"} } */ + +/* There should be one load of alias. */ +/* { dg-final { scan-tree-dump-times "->alias" 1 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030714-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030714-1.c new file mode 100644 index 00000000000..936df5371c4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030714-1.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; +enum rtx_code +{ + REG, + LAST_AND_UNUSED_RTX_CODE +}; +typedef union rtunion_def rtunion; +struct rtx_def +{ + enum rtx_code code:16; + unsigned frame_related:1; +}; +static rtx +find_base_value (src) + rtx src; +{ + rtx temp; + rtx src_0; + rtx src_1; + + if ((src_0->code == REG) && (({src_0;})->frame_related)) + return find_base_value (src_0); + if ((src_1->code == REG) && (({ src_1;})->frame_related)) + return find_base_value (src_1); + if (src_0->code == REG) + find_base_value (src_0); + if (src_1->code == REG) + find_base_value (src_1); +} + + +/* There should be six IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 6 "dom3"} } */ + +/* There should be no casts to short unsigned int. */ +/* { dg-final { scan-tree-dump-times "\\(short unsigned int\\)" 0 "dom3"} } */ + +/* There should be three loads of ->code. */ +/* { dg-final { scan-tree-dump-times "->code" 3 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030714-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030714-2.c new file mode 100644 index 00000000000..6a43360b07f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030714-2.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +union tree_node; +typedef union tree_node *tree; +extern const char tree_code_type[]; +struct tree_common +{ + int code; + tree type; +}; +struct tree_exp +{ + tree operands[1]; +}; +union tree_node +{ + struct tree_common common; + struct tree_exp exp; +}; +long +get_alias_set (t) + tree t; +{ + if (tree_code_type[t->common.code] != 't' && t->common.type == 0) + return 0; + if (tree_code_type[t->common.code] != 't') + { + while (t->exp.operands[0]) + t = t->exp.operands[0]; + } +} + +/* There should be exactly four IF conditionals if we thread jumps + properly. */ +/* { dg-final { scan-tree-dump-times "if " 4 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030728-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030728-1.c new file mode 100644 index 00000000000..4bc04bc4da4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030728-1.c @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + + +union tree_node; +typedef union tree_node *tree; + +enum tree_code +{ + ARRAY_TYPE, + LAST_AND_UNUSED_TREE_CODE +}; + +struct tree_common +{ + enum tree_code code:8; +}; + + + + + +union tree_node +{ + struct tree_common common; +}; + + + + +int +objects_must_conflict_p (t1, t2) + tree t1, t2; +{ + + if ((t1->common.code == ARRAY_TYPE) != (t2 + && t2->common.code == ARRAY_TYPE)) + return 0; + + + return foo (t2 ? get_alias_set (t2) : 0); +} + +/* There should be three assignments of variables to the value zero. */ +/* { dg-final { scan-tree-dump-times " = 0" 3 "optimized"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030729-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030729-1.c new file mode 100644 index 00000000000..b4b1a819ff4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030729-1.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +union tree_node; +typedef union tree_node *tree; + + +enum tree_code +{ + SET_TYPE, + RECORD_TYPE, + LAST_AND_UNUSED_TREE_CODE +}; +extern const char tree_code_type[]; + +struct tree_common +{ + + enum tree_code code:8; +}; + + + + + +union tree_node +{ + struct tree_common common; +}; + +readonly_fields_p (type) + tree type; +{ + + if (type->common.code != RECORD_TYPE) + return; + + if (tree_code_type[type->common.code] != 't') + abort (); + + return; +} + +/* A good optimizer would realize that the cast to (unsigned int) is + useless as the earlier cast of the same value of (unsigned char) will + always produce the same result. */ +/* { dg-final { scan-tree-dump-times "\\(unsigned int\\)" 0 "dom3"} } */ + +/* There should be one load of ->common.code. We currently fail this + because we load from ->common.code using different types. */ +/* { dg-final { scan-tree-dump-times "common\.code" 1 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030730-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030730-1.c new file mode 100644 index 00000000000..643b5e79271 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030730-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom3" } */ + +extern void *ggc_alloc (__SIZE_TYPE__); +typedef struct dw_attr_struct *dw_attr_ref; +typedef struct dw_attr_struct +{ + int dw_attr; +} +dw_attr_node; +void +foo (int attr_kind, unsigned long offset) +{ + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); + attr->dw_attr = attr_kind; + if (attr != 0) + exit (0); +} + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030730-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030730-2.c new file mode 100644 index 00000000000..06b5710f65f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030730-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom3" } */ + +extern void *ggc_alloc (__SIZE_TYPE__); +typedef struct dw_attr_struct *dw_attr_ref; +typedef struct dw_attr_struct +{ + int dw_attr; +} +dw_attr_node; +void +foo (int attr_kind, unsigned long offset) +{ + dw_attr_ref attr = (dw_attr_ref) ggc_alloc (sizeof (dw_attr_node)); + attr->dw_attr = attr_kind; + if (attr != ((void *)0)) + exit (0); +} + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030731-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030731-1.c new file mode 100644 index 00000000000..82634da1c5b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030731-1.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +struct rtx_def; +typedef struct rtx_def *rtx; +struct rtvec_def; +typedef struct rtvec_def *rtvec; +union tree_node; +typedef union tree_node *tree; +struct rtx_def +{ + int code; + int mode; + unsigned int in_struct:1; +}; +struct tree_common +{ + int code; +}; +struct tree_decl +{ + rtx rtl; +}; +union tree_node +{ + struct tree_common common; + struct tree_decl decl; +}; +rtx +store_expr (exp, target, want_value) + tree exp; + rtx target; + int want_value; +{ + if (exp->common.code == 42) + abort (); + else if (queued_subexp_p (target)) + { + blah (target->mode); + if (target->code) + abort (); + } + else + { + if (target->code && (__extension__({target;})->in_struct)); + } + + if ((target != (exp->decl.rtl + ? (exp->decl.rtl + ? exp->decl.rtl + : (make_decl_rtl (exp, 0), exp->decl.rtl)) + : 0)) + && expr_size (exp)) + ; +} + +/* All paths to the test "target != 0" occuring in the final IF statement + dereference target. Thus target can not have the value zero at that + point and the test should have been eliminated. */ +/* ??? The dominator walker (A) doesn't merge this data at joins and + (B) only looks at immediate dominators, and only queued_subexp_p + immediately dominates the comparison in question. We need something + stronger. */ +/* { dg-final { scan-tree-dump-times "target.*!= 0" 0 "dom3" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030731-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030731-2.c new file mode 100644 index 00000000000..b088f007447 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030731-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ccp" } */ + + +bar (int i, int partial, int args_addr) +{ + int offset = 0; + if (args_addr == 0) + offset = 0; + if (i >= offset) + foo (); +} + +/* There should be only one IF conditional since the first does nothing + useful. */ +/* { dg-final { scan-tree-dump-times "if " 1 "ccp"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-1.c new file mode 100644 index 00000000000..ab013d3d9fc --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-1.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; + + + +union rtunion_def +{ + int rtint; +}; +typedef union rtunion_def rtunion; + + + +struct rtx_def +{ + rtunion fld[1]; + +}; + +static int *uid_cuid; +static int max_uid_cuid; + +static rtx +bar (rtx r) +{ + rtx place = r; + + if (place->fld[0].rtint <= max_uid_cuid + && (place->fld[0].rtint > max_uid_cuid ? insn_cuid (place) : + uid_cuid[place->fld[0].rtint])) + return r; + + return 0; +} + +/* There should be two IF conditionals. One tests <= max_uid_cuid, the + other tets the value in uid_cuid. If either is false the jumps + are threaded to the return 0. Which in turn means the path + which combines the result of those two tests into a new test + must always be true and it is optimized appropriately. */ +/* { dg-final { scan-tree-dump-times "if " 2 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-10.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-10.c new file mode 100644 index 00000000000..709395511a4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-10.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +extern const unsigned char mode_size[]; +unsigned int +subreg_highpart_offset (outermode, innermode) + int outermode, innermode; +{ + unsigned int offset = 0; + int difference = (mode_size[innermode] - mode_size[outermode]); + if (difference > 0) + { + offset += difference % (0 ? 8 : 4); + offset += difference / 4 * 4; + } + return offset; +} + +/* There should be one mask with the value 3. */ +/* { dg-final { scan-tree-dump-times " \& 3" 1 "dom3"} } */ + +/* There should be one right shift by 2 places. */ +/* { dg-final { scan-tree-dump-times " >> 2" 1 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-11.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-11.c new file mode 100644 index 00000000000..6296346095d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-11.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; +struct rtx_def +{ + int code; +}; +foo (reg) + rtx reg; +{ + reg->code = 42; + if (reg->code != 42) + abort (); +} + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-2.c new file mode 100644 index 00000000000..e9837d38814 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-2.c @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +oof () +{ + int live_head; + int * live = &live_head; + + if (live) + bitmap_clear (live); +} + +foo(int n) +{ + int *space = (int *)__builtin_alloca (n); + + if (space == 0) + abort (); + else + bar (space); +} + + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-3.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-3.c new file mode 100644 index 00000000000..7e10d382c4e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-3.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +typedef unsigned int cppchar_t; +cppchar_t +cpp_parse_escape (pstr, limit, wide) + const unsigned char **pstr; + const unsigned char *limit; + int wide; +{ + cppchar_t i = 0; + int overflow = 0; + cppchar_t mask = ~0; + + while (*pstr < limit) + { + overflow |= i ^ (i << 4 >> 4); + i = oof (); + } + if (overflow | (i != (i & mask))) + foo(); +} + +/* There should be precisely three IF statements. If there is + more than two, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "if " 3 "dom3"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c new file mode 100644 index 00000000000..b530c841a7f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-5.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; + + +struct rtx_def +{ + + int code; + unsigned int unchanging:1; + +}; +static rtx current_sym_addr; + +static int +foo () +{ + if (current_sym_addr->code == 42 + && (({ + rtx _rtx = current_sym_addr; + if (((_rtx)->code) != 42) + abort (); + _rtx;} + )->unchanging)) + return 0; +} + +/* There should be precisely one load of ->code. If there is + more than, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "->code" 1 "dom3"} } */ + +/* There should be two IF statements. One for 'current_sym_addr->code == 42'. + The other one for '(EXPR)->unchanging'. */ +/* { dg-final { scan-tree-dump-times "if " 2 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-6.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-6.c new file mode 100644 index 00000000000..3b24bcaf662 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-6.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +static void +foo (distance, i, j) + int distance[13][13]; + int i, j; +{ + if (distance[i][j] < 0) + distance[i][0] = ((distance[i][j]) < 0 ? -(distance[i][j]) : (distance[i][j])); +} + +static void +foo2 (distance, i, j) + int distance[13][13]; + int i, j; +{ + if (distance[i][j] <= 0) + distance[i][0] = ((distance[i][j]) < 0 ? -(distance[i][j]) : (distance[i][j])); +} + +static void +foo3 (distance, i, j) + int distance[13][13]; + int i, j; +{ + if (distance[i][j] > 0) + distance[i][0] = ((distance[i][j]) < 0 ? -(distance[i][j]) : (distance[i][j])); +} + +static void +foo4 (distance, i, j) + double distance[13][13]; + int i, j; +{ + if (distance[i][j] >= 0) + distance[i][0] = ((distance[i][j]) < 0 ? -(distance[i][j]) : (distance[i][j])); +} + +/* There should be no ABS_EXPR. */ +/* { dg-final { scan-tree-dump-times "ABS_EXPR " 0 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-7.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-7.c new file mode 100644 index 00000000000..7f31578307a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-7.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom3" } */ + + + +union tree_node; +typedef union tree_node *tree; +struct tree_common +{ + int code; +}; +struct tree_list +{ + tree purpose; +}; +union tree_node +{ + struct tree_common common; + struct tree_list list; +}; +void +simplify_condition (cond_p) + tree *cond_p; +{ + tree decl; + tree cond = *cond_p; + if (cond->common.code != 42) + abort (); + decl = cond->list.purpose; + if (cond->common.code != 42) + abort (); + c_simplify_stmt (&decl); +} + +/* There should be exactly one IF conditional. TBAA is not able to + determine that 'decl' and 'cond' can't alias. */ +/* { dg-final { scan-tree-dump-times "if " 1 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-8.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-8.c new file mode 100644 index 00000000000..1241f32a7f8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-8.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +struct die_struct; +typedef struct die_struct *dw_die_ref; +typedef struct dw_loc_list_struct *dw_loc_list_ref; +enum dw_val_class +{ + dw_val_class_loc_list, +}; +typedef struct dw_val_struct +{ + enum dw_val_class val_class; + union dw_val_struct_union + { + dw_loc_list_ref val_loc_list; + } + v; +} +dw_val_node; +typedef struct dw_attr_struct *dw_attr_ref; +typedef struct dw_attr_struct +{ + dw_val_node dw_attr_val; +} +dw_attr_node; + +extern __inline__ enum dw_val_class +AT_class (a) + dw_attr_ref a; +{ + return a->dw_attr_val.val_class; +} +extern __inline__ dw_loc_list_ref +AT_loc_list (a) + dw_attr_ref a; +{ + if (AT_class (a) == dw_val_class_loc_list) + return a->dw_attr_val.v.val_loc_list; +} +static void +output_location_lists (die) + dw_die_ref die; +{ + dw_die_ref c; + dw_attr_ref d_attr; + if (AT_class (d_attr) == dw_val_class_loc_list) + output_loc_list (AT_loc_list (d_attr)); +} + +/* There should be exactly one IF conditional, in output_location_lists. */ +/* { dg-final { scan-tree-dump-times "if " 1 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030807-9.c b/gcc/testsuite/gcc.dg/tree-ssa/20030807-9.c new file mode 100644 index 00000000000..6144bd187ed --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030807-9.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +static void +bar () +{ + const char *label2 = (*"*.L_sfnames_b" == '*') + "*.L_sfnames_b"; + oof (label2); +} + +void +ooof () +{ + if (""[0] == 0) + foo(); +} + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030808-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030808-1.c new file mode 100644 index 00000000000..9a20a3040c5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030808-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-cddce" } */ + + +struct rtx_def; +typedef struct rtx_def *rtx; +enum rtx_code +{ + UNKNOWN, + CODE_LABEL, + NOTE, + LAST_AND_UNUSED_RTX_CODE +}; +typedef union rtunion_def rtunion; +struct rtx_def +{ + enum rtx_code code:16; +}; +void +delete_dead_jumptables () +{ + rtx insn, next; + if (insn->code == CODE_LABEL) + { + rtx const _rtx = insn; + if (_rtx->code != CODE_LABEL && _rtx->code != NOTE) + abort (); + } + ; +} + +/* There should be no loads of ->code. If any exist, then we failed to + optimize away all the IF statements and the statements feeding + their conditions. */ +/* { dg-final { scan-tree-dump-times "->code" 0 "cddce"} } */ + +/* There should be no IF statements. */ +/* { dg-final { scan-tree-dump-times "if " 0 "cddce"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030814-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030814-1.c new file mode 100644 index 00000000000..d165b19bfda --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030814-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +com(int *blah) +{ + int z = *blah; + if (z == 256) + { + oof (z); + abort (); + } + return *blah; +} + +/* There should be precisely one load of blah. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "\\*blah" 1 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030814-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030814-2.c new file mode 100644 index 00000000000..a3f2ae6b70b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030814-2.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +void +foo (int value) +{ + switch (value) + { + case 42: + if (value != 42) + abort (); + case 50: + blah (); + } +} + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030814-3.c b/gcc/testsuite/gcc.dg/tree-ssa/20030814-3.c new file mode 100644 index 00000000000..2058c0c987a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030814-3.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +void +foo (int value) +{ + switch (value) + { + case 40: + case 42: + if (value != 42) + abort (); + case 50: + blah (); + } +} + +/* There should be one IF conditional. */ +/* { dg-final { scan-tree-dump-times "if " 1 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030814-4.c b/gcc/testsuite/gcc.dg/tree-ssa/20030814-4.c new file mode 100644 index 00000000000..81711dd75cd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030814-4.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3 -fdump-tree-optimized" } */ + +union tree_node; +typedef union tree_node *tree; +extern const char tree_code_type[]; +struct tree_common +{ + int code; +}; +struct tree_decl +{ + long pointer_alias_set; +}; +union tree_node +{ + struct tree_common common; + struct tree_decl decl; +}; +long +blah (decl, set) + tree decl; + long set; +{ + decl->decl.pointer_alias_set = set; + if (tree_code_type[decl->common.code] != 'd') + abort (); + record_alias_subset (decl->decl.pointer_alias_set); + if (set != -1) + set = 0; + return set; +} + +/* There should be precisely one reference to pointer_alias_set. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "pointer_alias_set" 1 "dom3"} } */ + +/* The assignment set = -1 in the ELSE clause of the last IF + statement should be removed by the final cleanup phase. */ +/* { dg-final { scan-tree-dump-times "set = -1" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030814-5.c b/gcc/testsuite/gcc.dg/tree-ssa/20030814-5.c new file mode 100644 index 00000000000..bab21a3cae8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030814-5.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3 -fdump-tree-optimized" } */ + +union tree_node; +typedef union tree_node *tree; +extern const char tree_code_type[]; +struct tree_common +{ + int code; +}; +struct tree_decl +{ + long pointer_alias_set; +}; +union tree_node +{ + struct tree_common common; + struct tree_decl decl; +}; +long +blah (decl, set) + tree decl; + long set; +{ + decl->decl.pointer_alias_set = oof(); + if (tree_code_type[decl->common.code] != 'd') + abort (); + record_alias_subset (decl->decl.pointer_alias_set); + if (set != -1) + set = 0; + return set; +} + +/* There should be precisely one reference to pointer_alias_set. If there is + more than one, then the dominator optimizations failed. */ +/* { dg-final { scan-tree-dump-times "pointer_alias_set" 1 "dom3"} } */ + +/* The assignment set = -1 in the ELSE clause of the last IF + statement should be removed by the final cleanup phase. */ +/* { dg-final { scan-tree-dump-times "set = -1" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030814-6.c b/gcc/testsuite/gcc.dg/tree-ssa/20030814-6.c new file mode 100644 index 00000000000..c16fda9155c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030814-6.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +union tree_node; +typedef union tree_node *tree; +enum tree_code +{ + LAST_AND_UNUSED_TREE_CODE +}; +extern const char tree_code_type[]; +struct tree_common +{ + enum tree_code code:8; +}; +struct tree_type +{ + double alias_set; +}; +union tree_node +{ + struct tree_common common; + struct tree_type type; +}; +long +foo (t, set) + tree t; + double set; +{ + if (tree_code_type[t->common.code] != 't') + abort (); + + t->type.alias_set = set; + + if (t->common.code == 42) + return 1; + else + return 0; +} +/* There should be precisely one load of common.code. If there is + more than one, then the dominator optimizations failed. */ +/* ??? Will fail until we properly distinguish member stores. At + present the write to type.alias_set kills the previous load. */ +/* { dg-final { scan-tree-dump-times "common.code" 1 "dom3" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030814-7.c b/gcc/testsuite/gcc.dg/tree-ssa/20030814-7.c new file mode 100644 index 00000000000..cbefbb33c1a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030814-7.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; +struct rtvec_def; +typedef struct rtvec_def *rtvec; +union tree_node; +typedef union tree_node *tree; +struct tree_common +{ + int code; +}; +union tree_node +{ + struct tree_common common; +}; +extern tree current_function_decl; +struct cgraph_rtl_info +{ + _Bool pure_function; +}; +struct cgraph_rtl_info *cgraph_rtl_info (tree); +void +mark_constant_function (void) +{ + rtx insn; + int nonlocal_memory_referenced; + + if (current_function_decl->common.code != 42) + abort (); + + cgraph_rtl_info (current_function_decl)->pure_function = 1; +} + +/* current_function_decl should be loaded once into a temporary + and the temporary used as the argument to cgraph_rtl_info. + This if we find current_function_decl used as an argument, then + we have failed. */ +/* { dg-final { scan-tree-dump-times "\\(current_function_decl\\)" 0 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030815-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030815-1.c new file mode 100644 index 00000000000..13a4917e912 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030815-1.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + +typedef unsigned int size_t; +struct rtx_def; +typedef struct rtx_def *rtx; +typedef union varray_data_tag +{ + struct reg_info_def *reg[1]; +} varray_data; +struct varray_head_tag +{ + size_t num_elements; + varray_data data; +}; +typedef struct varray_head_tag *varray_type; +typedef struct reg_info_def +{ +} reg_info; +extern varray_type reg_n_info; +static rtx *reg_base_value; +static rtx *new_reg_base_value; +static rtx +blah (unsigned int regno) +{ + if (new_reg_base_value[regno] && ((*( + { + if (regno >= + reg_n_info-> + num_elements) + abort (); + ®_n_info->data.reg[regno];} + )))) + return reg_base_value[regno]; +} + +/* If we have more than 1 cast to a struct rtx_def * *, then we failed to + eliminate some useless typecasting. The first type cast is needed + to convert the unsigned int regno parameter into a struct rtx_def **. */ +/* { dg-final { scan-tree-dump-times "\\(struct rtx_def \\* \\*\\)" 1 "dom3"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030820-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030820-1.c new file mode 100644 index 00000000000..4b659ca3411 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030820-1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +/* A test for unreachable blocks removal -- bind_expr whose entry is + unreachable, but it contains reachable statements. */ + +void foo(void) +{ + if (1) + { + goto bla; + } + else + { +xxx: + { +bla: + bar (); + return; + } + goto xxx; + } +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030820-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030820-2.c new file mode 100644 index 00000000000..9ca9fbb59c6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030820-2.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +/* A test for variables getting out of their scope in copy propagation. */ + +void foo(void) +{ + int k; + + goto forward; +back: + bla (k); + return; + +forward: + { + int i = bar (); + + k = i; + + goto back; + } +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030821-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030821-1.c new file mode 100644 index 00000000000..2d1e9e78df2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030821-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +void foo(int k) +{ + int i = 1; + void *label; + + label = k ? &&x : &&y; + + if (k == 1) + goto *label; + + i = 0; + goto z; +z: +x: + if (i) + dont_remove (); +y: ; +} + +/* { dg-final { scan-tree-dump-times "dont_remove \\(\\)" 1 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030824-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030824-1.c new file mode 100644 index 00000000000..328d33d1243 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030824-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +struct A +{ + int a,b; +}; + +int foo (int x, int y) +{ + int i, j; + struct A a,b; + + a.a = x; + b.b = y; + j = a.a; + i = b.b; + return i + j; +} + +/* The addition should be optimized into 'y+x'. */ +/* { dg-final { scan-tree-dump-times "y \\+ x" 1 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030824-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030824-2.c new file mode 100644 index 00000000000..5ed66d094a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030824-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +struct A +{ + int a,b; +}; + +int foo (int x, int y) +{ + int i, j; + struct A a; + + a.a = x; + a.b = y; + j = a.a; + i = a.b; + return i + j; +} + +/* This function should be optimized into 'return y+x'. */ +/* { dg-final { scan-tree-dump-times "return y \\+ x" 1 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030825-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030825-1.c new file mode 100644 index 00000000000..440f75571d4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030825-1.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +void bla(void); + +void +foo(int c, int d) +{ + goto skip; + +ebef: + goto xxx; + +skip: + + if (c) + { +xxx:; + if (!c) + bla (); + } + + if (d) + goto ebef; +} + +/* Bla should not be optimized away. */ +/* { dg-final { scan-tree-dump-times "bla" 1 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030907-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030907-1.c new file mode 100644 index 00000000000..3bc5557cf00 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030907-1.c @@ -0,0 +1,26 @@ +/* PR optimization/12198 + + This was a miscompilation of a switch expressions because + the "Case Ranges" extension wasn't handled in tree-cfg.c. */ + +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +int main() +{ + int i; + i = 2; + switch (i) + { + case 1 ... 5: + goto L1; + default: + abort (); + goto L1; + } + L1: + exit(0); +} + +/* The abort() call clearly is unreachable. */ +/* { dg-final { scan-tree-dump-times "abort" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030907-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030907-2.c new file mode 100644 index 00000000000..47d60946e0c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030907-2.c @@ -0,0 +1,30 @@ +/* PR optimization/12109 + + This would ICE in tree-ssa-dce.c:process_worklist() when + the function was expecting an SSA_NAME but found a VAR_DECL. */ + +/* { dg-do compile } */ +/* { dg-options "-O -ftree-dce" } */ + +void *do_it(void * dest, const void * src); +double *create_float(void); + +void parse_rvalue(void **DataPtr) +{ + double local = 0.0; + int terms = 1; + + *DataPtr = create_float(); + + switch (terms) + { + case 1: + *((double *)*DataPtr) = local; + break; + + case 2: + do_it(*DataPtr, &local); + break; + } +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030917-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030917-1.c new file mode 100644 index 00000000000..1b1441f0f9b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030917-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ccp" } */ + + +extern int board[]; + +void +findbestextension (int blah, int blah2) +{ + int defval; + defval = def_val (board[blah2]); + if (blah) + defval = 0; + foo (defval); +} + +/* The argument to "foo" should be a variable, not a constant. */ +/* { dg-final { scan-tree-dump-times "foo .defval" 1 "ccp"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030917-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030917-2.c new file mode 100644 index 00000000000..2c08050c975 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030917-2.c @@ -0,0 +1,40 @@ +/* This test was causing an ICE in DCE because we were allowing void * + pointers to have a memory tag, which we were copying when doing copy + propagation. Since void * can never be de-referenced, its memory tag + was never renamed. */ + +/* { dg-do compile } */ +/* { dg-options "-O -ftree-dominator-opts" } */ + +typedef __SIZE_TYPE__ size_t; +typedef union tree_node *tree; +struct operands_d +{ + tree *def_op; +}; + +void +gt_ggc_mx_operands_d (void *x_p) +{ + struct operands_d *const x = (struct operands_d *) x_p; + if ((*x).def_op != ((void *) 0)) + { + size_t i0; + do + { + const void *const a__ = ((*x).def_op); + if (a__ != ((void *) 0) && a__ != (void *) 1) + ggc_set_mark (a__); + } + while (0); + for (i0 = 0; i0 < (size_t) (1); i0++) + { + do + { + if ((void *) (*x).def_op[i0] != ((void *) 0)) + gt_ggc_mx_lang_tree_node ((*x).def_op[i0]); + } + while (0); + } + } +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030917-3.c b/gcc/testsuite/gcc.dg/tree-ssa/20030917-3.c new file mode 100644 index 00000000000..f7fabe5008c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030917-3.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fno-tree-dominator-opts -fdump-tree-ccp" } */ + + +main () +{ + int variable = 0; + int p = 1; + while (1) + { + if (p) + break; + variable = variable + 1; + if (variable == 10) + break; + } + printf("%d\n", variable); +} + + +/* The argument to "printf" should be a constant, not a variable. */ +/* { dg-final { scan-tree-dump-times "printf.*, 0" 1 "ccp"} } */ + + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030918-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030918-1.c new file mode 100644 index 00000000000..719ea65f5bf --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030918-1.c @@ -0,0 +1,15 @@ +/* The compiler was failing to adjust pointer dereferences into array + references after propagating &equot[0] into p. */ + +/* { dg-do compile } */ +/* { dg-options "-O -ftree-dominator-opts" } */ + +static unsigned short equot[(6 +3)]; +int +foo (num) + unsigned short num[]; +{ + unsigned short *p = &equot[0]; + *p++ = num[0]; + *p++ = num[1]; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030920-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030920-1.c new file mode 100644 index 00000000000..e27764aecda --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030920-1.c @@ -0,0 +1,112 @@ +/* Jump threading was creating FALLTHRU edges out of blocks ending in + GOTO_EXPR. */ + +extern int frame_pointer_needed; + +struct value_data_entry +{ + unsigned int mode; + unsigned int oldest_regno; + unsigned int next_regno; +}; + +struct value_data +{ + struct value_data_entry e[53]; + unsigned int max_value_regs; +}; + +struct rtx_def +{ + unsigned int code: 16; + unsigned int mode : 8; + unsigned int jump : 1; + unsigned int call : 1; + unsigned int unchanging : 1; + unsigned int volatil : 1; + unsigned int in_struct : 1; + unsigned int used : 1; + unsigned integrated : 1; + unsigned frame_related : 1; + int fld[1]; +}; + +typedef struct rtx_def *rtx; + +enum machine_mode { VOIDmode, BImode, QImode, HImode, SImode, DImode, + TImode, OImode, PQImode, PHImode, PSImode, PDImode, QFmode, HFmode, + TQFmode, SFmode, DFmode, XFmode, TFmode, QCmode, HCmode, SCmode, + DCmode, XCmode, TCmode, CQImode, CHImode, CSImode, CDImode, CTImode, + COImode, V1DImode, V2QImode, V2HImode, V2SImode, V2DImode, V4QImode, + V4HImode, V4SImode, V4DImode, V8QImode, V8HImode, V8SImode, V8DImode, + V16QImode, V2HFmode, V2SFmode, V2DFmode, V4HFmode, V4SFmode, V4DFmode, + V8HFmode, V8SFmode, V8DFmode, V16SFmode, BLKmode, CCmode, CCGCmode, + CCGOCmode, CCNOmode, CCZmode, CCFPmode, CCFPUmode, MAX_MACHINE_MODE }; + +enum mode_class { MODE_RANDOM, MODE_INT, MODE_FLOAT, MODE_PARTIAL_INT, MODE_CC, + MODE_COMPLEX_INT, MODE_COMPLEX_FLOAT, + MODE_VECTOR_INT, MODE_VECTOR_FLOAT, + MAX_MODE_CLASS}; + +extern const unsigned char mode_size[(int) MAX_MACHINE_MODE]; +extern const enum mode_class mode_class[(int) MAX_MACHINE_MODE]; + +extern int target_flags; + +static void +copy_value (rtx dest, rtx src, struct value_data *vd) +{ + unsigned int dr = (((dest)->fld[0])); + unsigned int sr = (((src)->fld[0])); + unsigned int dn, sn; + unsigned int i; + + + + if (sr == dr) + return; + + + + if (dr == 7) + return; + + + if (frame_pointer_needed && dr == 6) + return; + + + dn = (((dr) >= 8 && (dr) <= (8 + 7)) || (((dr) >= (20 + 1) && (dr) <= ((20 + 1) + 7)) || ((dr) >= (((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) && (dr) <= ((((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) + 7))) || ((dr) >= (((20 + 1) + 7) + 1) && (dr) <= ((((20 + 1) + 7) + 1) + 7)) ? (((mode_class[(int) (((enum machine_mode) (dest)->mode))]) == MODE_COMPLEX_INT || (mode_class[(int) (((enum machine_mode) (dest)->mode))]) == MODE_COMPLEX_FLOAT) ? 2 : 1) : ((((enum machine_mode) (dest)->mode)) == TFmode ? ((target_flags & 0x00100000) ? 2 : 3) : (((enum machine_mode) (dest)->mode)) == TCmode ? ((target_flags & 0x00100000) ? 4 : 6) : (((mode_size[(int) (((enum machine_mode) (dest)->mode))]) + ((target_flags & 0x00100000) ? 8 : 4) - 1) / ((target_flags & 0x00100000) ? 8 : 4)))); + sn = (((sr) >= 8 && (sr) <= (8 + 7)) || (((sr) >= (20 + 1) && (sr) <= ((20 + 1) + 7)) || ((sr) >= (((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) && (sr) <= ((((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) + 7))) || ((sr) >= (((20 + 1) + 7) + 1) && (sr) <= ((((20 + 1) + 7) + 1) + 7)) ? (((mode_class[(int) (((enum machine_mode) (dest)->mode))]) == MODE_COMPLEX_INT || (mode_class[(int) (((enum machine_mode) (dest)->mode))]) == MODE_COMPLEX_FLOAT) ? 2 : 1) : ((((enum machine_mode) (dest)->mode)) == TFmode ? ((target_flags & 0x00100000) ? 2 : 3) : (((enum machine_mode) (dest)->mode)) == TCmode ? ((target_flags & 0x00100000) ? 4 : 6) : (((mode_size[(int) (((enum machine_mode) (dest)->mode))]) + ((target_flags & 0x00100000) ? 8 : 4) - 1) / ((target_flags & 0x00100000) ? 8 : 4)))); + if ((dr > sr && dr < sr + sn) + || (sr > dr && sr < dr + dn)) + return; + + + + + if (vd->e[sr].mode == VOIDmode) + set_value_regno (sr, vd->e[dr].mode, vd); + else if (sn < (unsigned int) (((sr) >= 8 && (sr) <= (8 + 7)) || (((sr) >= (20 + 1) && (sr) <= ((20 + 1) + 7)) || ((sr) >= (((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) && (sr) <= ((((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) + 7))) || ((sr) >= (((20 + 1) + 7) + 1) && (sr) <= ((((20 + 1) + 7) + 1) + 7)) ? (((mode_class[(int) (vd->e[sr].mode)]) == MODE_COMPLEX_INT || (mode_class[(int) (vd->e[sr].mode)]) == MODE_COMPLEX_FLOAT) ? 2 : 1) : ((vd->e[sr].mode) == TFmode ? ((target_flags & 0x00100000) ? 2 : 3) : (vd->e[sr].mode) == TCmode ? ((target_flags & 0x00100000) ? 4 : 6) : (((mode_size[(int) (vd->e[sr].mode)]) + ((target_flags & 0x00100000) ? 8 : 4) - 1) / ((target_flags & 0x00100000) ? 8 : 4)))) + && ((mode_size[(int) (vd->e[sr].mode)]) > ((target_flags & 0x00100000) ? 8 : 4) + ? 0 : 0)) + return; + + + + + else if (sn > (unsigned int) (((sr) >= 8 && (sr) <= (8 + 7)) || (((sr) >= (20 + 1) && (sr) <= ((20 + 1) + 7)) || ((sr) >= (((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) && (sr) <= ((((((((20 + 1) + 7) + 1) + 7) + 1) + 7) + 1) + 7))) || ((sr) >= (((20 + 1) + 7) + 1) && (sr) <= ((((20 + 1) + 7) + 1) + 7)) ? (((mode_class[(int) (vd->e[sr].mode)]) == MODE_COMPLEX_INT || (mode_class[(int) (vd->e[sr].mode)]) == MODE_COMPLEX_FLOAT) ? 2 : 1) : ((vd->e[sr].mode) == TFmode ? ((target_flags & 0x00100000) ? 2 : 3) : (vd->e[sr].mode) == TCmode ? ((target_flags & 0x00100000) ? 4 : 6) : (((mode_size[(int) (vd->e[sr].mode)]) + ((target_flags & 0x00100000) ? 8 : 4) - 1) / ((target_flags & 0x00100000) ? 8 : 4))))) + return; + + + + vd->e[dr].oldest_regno = vd->e[sr].oldest_regno; + + for (i = sr; vd->e[i].next_regno != (~(unsigned int) 0); i = vd->e[i].next_regno) + continue; + vd->e[i].next_regno = dr; + + + validate_value_data (vd); + +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030922-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20030922-1.c new file mode 100644 index 00000000000..8876071c81f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030922-1.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom3" } */ + + +union tree_node; +typedef union tree_node *tree; +enum tree_code +{ + BIND_EXPR, +}; +struct tree_common +{ + enum tree_code code:8; +}; +union tree_node +{ + struct tree_common common; +}; +tree +voidify_wrapper_expr (tree wrapper) +{ + switch (wrapper->common.code) + { + case BIND_EXPR: + if (wrapper->common.code != BIND_EXPR) + abort (); + } +} + + +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20030922-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20030922-2.c new file mode 100644 index 00000000000..322f3ab3891 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20030922-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom1" } */ + +struct rtx_def; +typedef struct rtx_def *rtx; +struct rtx_def +{ + int bb; +}; +static int *block_to_bb; +static int target_bb; +static int +rgn_rank (rtx insn1, rtx insn2) +{ + if (block_to_bb[insn1->bb] != block_to_bb[insn2->bb]) + if (block_to_bb[insn2->bb] == target_bb + && block_to_bb[insn1->bb] != target_bb) + return 1; +} + +/* There should be two IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 2 "dom1" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031015-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20031015-1.c new file mode 100644 index 00000000000..62772b7b939 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031015-1.c @@ -0,0 +1,16 @@ +/* With tree-ssa, gcc.dg/20000724-1.c failed because we missed + a VOP of x in the asm statement. */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-alias-vops" } */ + +struct s { int a; }; + +int +main(void) +{ + struct s x = { 0 }; + asm volatile ("" : : "r" (&x) : "memory"); + return 0; +} + +/* { dg-final { scan-tree-dump-times "VDEF" 2 "alias" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031021-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20031021-1.c new file mode 100644 index 00000000000..4534ef34fc8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031021-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +struct A +{ + int i : 8; +}; + +signed char c1, c2; +struct A a; + +int main() +{ + a.i = c1; + c2 = a.i; + return a.i; +} + +/* We should only store to a.i, not load from it. */ +/* { dg-final { scan-tree-dump-times "a.i" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031022-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20031022-1.c new file mode 100644 index 00000000000..546e6b00759 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031022-1.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dom1" } */ + +typedef struct edge_def +{ + int z; +} *edge; +typedef struct basic_block_def +{ + edge pred; +} *basic_block; +extern struct basic_block_def entry_exit_blocks[2]; +void +blah (int arf) +{ + edge e; + e = (&entry_exit_blocks[1])->pred; + for ( ; ;) + if (arf) + break; + commit_edge_insertions (); + e = (&entry_exit_blocks[1])->pred; + foo (e); +} + +/* There should be two loads from entry_exit_blocks[1].pred. */ +/* { dg-final { scan-tree-dump-times "entry_exit_blocks.1..pred" 2 "dom1"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031031-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20031031-1.c new file mode 100644 index 00000000000..baca2a00a94 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031031-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +/* This program requires the SSA renamer to be run after the second DOM + pass. Test provided by Falk Hueffner as Bugzilla #12825. */ + +struct floppy_raw_cmd { + int flags, track; +} *raw_cmd, default_raw_cmd; + +void +setup_format_params (void) +{ + raw_cmd = &default_raw_cmd; + raw_cmd->track = 0; + raw_cmd->flags = 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031106-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20031106-1.c new file mode 100644 index 00000000000..eb312cea1e2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031106-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +/* Check for dead stores to an array. */ + +void foo (int testarray[]) +{ + testarray[0] = 0; + testarray[0]++; + if (testarray[0] != 1) + link_error (); +} + +/* There should be only one reference to "testarray". */ +/* { dg-final { scan-tree-dump-times "testarray" 1 "optimized" { xfail *-*-* } } } */ + +/* There should be no link_error calls. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031106-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20031106-2.c new file mode 100644 index 00000000000..da430dc5813 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031106-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +/* Check for dead stores to a struct. */ + +struct s +{ + char d; + int a, b; + double m; +}; + +void foo (struct s* teststruct) +{ + teststruct->a = 0; + teststruct->a++; + if (teststruct->a != 1) + link_error (); +} + +/* There should be only one reference to "teststruct". */ +/* { dg-final { scan-tree-dump-times "teststruct" 1 "optimized" { xfail *-*-* } } } */ + +/* There should be no link_error calls. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031106-3.c b/gcc/testsuite/gcc.dg/tree-ssa/20031106-3.c new file mode 100644 index 00000000000..ee7cb8a009d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031106-3.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +/* Check for cprop on array elements. */ + +void foo (int testarray[]) +{ + testarray[0] = 0; + testarray[1] = 1; + testarray[0]++; + testarray[1]++; + if (testarray[0] != 1) + link_error (); + if (testarray[1] != 2) + link_error (); +} + +/* There should be no link_error calls. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031106-4.c b/gcc/testsuite/gcc.dg/tree-ssa/20031106-4.c new file mode 100644 index 00000000000..a288dacee47 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031106-4.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +/* Check for cprop on fields of the same struct. */ + +struct s +{ + char d; + int a, b; + double m; +}; + + +void foo (struct s* r) +{ + r->a = 0; + r->b = 1; + r->a++; + r->b++; + if (r->a != 1) + link_error (); + if (r->b != 2) + link_error (); +} + +/* There should be no link_error calls. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031106-5.c b/gcc/testsuite/gcc.dg/tree-ssa/20031106-5.c new file mode 100644 index 00000000000..e543939c77b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031106-5.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +/* Check for cprop on different fields of same type structs. */ + +struct s +{ + char d; + int a, b; + double m; +}; + +void foo2 (struct s* r, struct s* p) +{ + r->a = 0; + p->b = 1; + r->a++; + p->b++; + if (r->a != 1) + link_error (); + if (p->b != 2) + link_error (); +} + +/* There should be no link_error calls. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c b/gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c new file mode 100644 index 00000000000..39fb08b032a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031106-6.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +/* Check for copyprop on structs. */ + +struct s +{ + char d; + int a, b; + double m; +}; + +struct s foo (struct s r) +{ + struct s temp_struct1; + struct s temp_struct2; + struct s temp_struct3; + temp_struct1 = r; + temp_struct2 = temp_struct1; + temp_struct3 = temp_struct2; + return temp_struct3; +} + +/* There should be no references to any of "temp_struct*" + temporaries. */ +/* { dg-final { scan-tree-dump-times "temp_struct" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031113-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20031113-1.c new file mode 100644 index 00000000000..a114379a7ad --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031113-1.c @@ -0,0 +1,30 @@ +/* PR optimization/12640 + + We used to get into an infinite loop while trying to + figure out `strlen (resultString)'. This showed up as + a stack overflow while compiling tk. */ + +/* { dg-do compile } */ +/* { dg-options "-O1" } */ + +int i; + +static void +SendEventProc (char *resultString) +{ + char *p; + + resultString = ""; + while (*p == '-') + { + if (p[2] == ' ') + { + resultString = p + 3; + } + } + for (;;) + { + i = strlen (resultString) + 1; + } +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20031216-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20031216-1.c new file mode 100644 index 00000000000..d3d39df3b11 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20031216-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +void +foo (int b) +{ + int a; + a = b + 2; + a--; + a--; + if (a != b) + link_error (); +} + +/* The comparison should be eliminated, there should be no reference + to link_error. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040121-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040121-1.c new file mode 100644 index 00000000000..6987e17d907 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040121-1.c @@ -0,0 +1,27 @@ + + +/* Test that (p!=0) + (q!=0) is computed as int, + not boolean */ +/* { dg-options "-O3" } */ +/* { dg-do run } */ +char *foo(char *p, char *q) { + int x = (p !=0) + (q != 0); + if (x==2) return "a"; else return 0; +} +extern char *bar(char*, char*) __attribute__((noinline)); +char *bar(char *first, char *last) +{ + int y; + if (!first) return last; + if (!last) return first; + if (*first == 'a') + return foo(first, last); + return 0; +} +main() { + char *p = "a", *q = "b"; + if (p) + if (bar(p,q)) + return 0; + abort(); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c new file mode 100644 index 00000000000..426e2eab51a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040204-1.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +extern void link_error (void); + +/* + test that a condition is propagated inside an if +*/ + +void test5 (int x) +{ + extern int foo (int); + if (x == 0) + foo (x); + else if (x == 0 ) + link_error (); +} + +void test55 (int x, int y) +{ + int u; + if (x == 5 && y) + { + u = x + 22; + if (u != 27) + link_error (); + } +} + +/* There should be not link_error calls, if there is any the + optimization has failed */ +/* ??? Ug. This one may or may not fail based on how fold decides + that the && should be emitted (based on BRANCH_COST). Fix this + by teaching dom to look through && and register all components + as true. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040209-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040209-1.c new file mode 100644 index 00000000000..087715322b7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040209-1.c @@ -0,0 +1,52 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wuninitialized" } */ + +typedef union tree_node *tree; + +struct tree_common +{ + tree chain; +}; + +struct tree_decl +{ + struct tree_common common; + tree name; +}; + + +union tree_node +{ + struct tree_common common; + struct tree_decl decl; +}; + +int pedantic; + +void +finish_struct (tree t, tree fieldlist, tree attributes) +{ + union tree_node * x; + + if (pedantic) + { + x = fieldlist; + if (x->decl.name == 0) + { + while (x) + x = x->common.chain; + foo (fieldlist); + } + } + + x = fieldlist; + if (x) + { + do + { + x = x->common.chain; + } while (x != 0); + } + + bar1 (&fieldlist); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040210-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040210-1.c new file mode 100644 index 00000000000..9eb7905aef0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040210-1.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-phiopt1-details" } */ + + +void abort(void); +void exit(int); + +int x, y; + +static void +init_xy(void) +{ + x = 3; + y = 2; +} + +void +test4(void) +{ + init_xy(); + if ((x < y ? x++ : y++) != 2) + abort (); +} + +int +main(){ + test4 (); + exit (0); +} + +/* Should have no more than two ifs left after straightening. */ +/* { dg-final { scan-tree-dump-times "if " 2 "phiopt1"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040211-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040211-1.c new file mode 100644 index 00000000000..5d6e07940a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040211-1.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-cddce" } */ + + + + +struct rtx_def; +typedef struct rtx_def *rtx; +extern const char rtx_class[]; +union rtunion_def +{ + rtx rtx; +}; +typedef union rtunion_def rtunion; +struct rtx_def +{ + int code; + rtunion fld[1]; +}; +static int +can_move_up (rtx insn, int n_insns) +{ + while (n_insns > 0) + { + insn = (((insn)->fld[1]).rtx); + if (((rtx_class[(int) (((insn)->code))]) == 'i')) + n_insns--; + } + return n_insns <= 0; +} +int +com (rtx insn, int blah) +{ + if (!can_move_up (insn, blah)) + foo (); +} + +/* Cddce cannot remove possibly infinite loops and there is no way how to + determine whether the loop in can_move_up ends. */ +/* { dg-final { scan-tree-dump "if " "cddce"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040216-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040216-1.c new file mode 100644 index 00000000000..7585905a4da --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040216-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dse1-details" } */ + +foo(int *z, int *y, int xx) +{ + *z = 1; + if (xx) + xx = 20; + else + xx = 30; + *z = 2; + *z = 3; + return xx; +} + +/* We should convert two COND_EXPRs into straightline code. */ +/* { dg-final { scan-tree-dump-times "Deleted dead store" 2 "dse1"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040302-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040302-1.c new file mode 100644 index 00000000000..ef59b041030 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040302-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 --param global-var-threshold=0" } */ + +/* Test for .GLOBAL_VAR not being renamed into SSA after alias analysis. + provided by Dale Johannesen in PR 14266. */ + +void foo() { bar (); } +main () { foo (); } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c new file mode 100644 index 00000000000..2d098d50e1d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040305-1.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-cddce -fdump-tree-forwprop1-details" } */ + +int abarney[2]; +int afred[1]; + +void foo(int edx, int eax) +{ + if (eax == 100) + { + if (edx == 1) + { + abarney[0] = 5; + abarney[1] = 6; + } + } + if (eax == 100) + { + if (-- edx == 0) + afred[0] = 2; + } +} + + +/* Verify that we did a forward propagation. */ +/* { dg-final { scan-tree-dump-times "Replaced" 1 "forwprop1"} } */ + +/* After cddce we should have two IF statements remaining as the other + two tests can be threaded. */ +/* { dg-final { scan-tree-dump-times "if " 2 "cddce"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040313-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040313-1.c new file mode 100644 index 00000000000..0ad144c03dd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040313-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +/* Test provided by Volker Reichelt in PR 14553. The redundant PHI + node elimination pass was not using the right API functions to + propagate pointers, which resulted in dereferenced pointers that + did not have memory tags associated with them. */ + +void foo(int* p) +{ + int i; + for (i=1; i>0; --i, ++p) + *p=0; +} + +void bar(int* p) { foo(p); } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040319-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040319-1.c new file mode 100644 index 00000000000..571c2aeabad --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040319-1.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +/* Test derived from PR 14643. When a function has no addressable + variables but 2 or more pointers have conflicting memory tags, they + were not being processed by the type based alias analyzer, + resulting in optimizations removing a non-redundant load. */ + +struct bar { int count; int *arr;}; + +void foo (struct bar *b) +{ + b->count = 0; + *(b->arr) = 2; + if (b->count == 0) /* b->count can't be assumed to be 0 here. */ + abort (); +} + +main () +{ + struct bar x; + x.arr = &x.count; + foo (&x); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040324-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040324-1.c new file mode 100644 index 00000000000..15eb0d62381 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040324-1.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +/* Ensure that BIT_FIELD_REFs gets the appropriate VUSE. + Contributed by Paolo Bonzini . + + This testcase actually never triggered in the CVS repo, but it did + in my local tree and it seems worth testing. In this test, the if's + are folded to BIT_FIELD_REFs but the VUSEs were erroneously left out. + Therefore, DOM did not see that i was modified between the two ifs + and optimized away the second if. */ + +struct x +{ + unsigned b:1; + unsigned c:1; +}; + +struct x i = { 1, 1 }; + +int +main () +{ + i.b = 1; + if (i.b == 1 && i.c == 0) + exit (0); + i.c = 0; + if (i.b == 1 && i.c == 0) + exit (0); + abort (); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040326-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040326-1.c new file mode 100644 index 00000000000..c29655a24fd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040326-1.c @@ -0,0 +1,29 @@ +/* { dg-options "-O2 -fno-inline-functions" } */ +/* { dg-do run } */ +/* When there are no call-clobbered variables, we should still create + a .GLOBAL_VAR to model the side effects of functions. Without it, + we were moving the call to Faref() inside the second call to + Faset(). */ +main () +{ + int table, c, elt; + int tem = Faref (table, elt); + Faset (table, elt, c); + Faset (table, c, tem);/* tem cannot be replaced with Faref (table, elt) */ + exit (0); +} + +int j = 0; + +int __attribute__ ((noinline)) Faref (table, elt) +{ + j = 1; + return 0; +} + +int __attribute__ ((noinline)) Faset (table, elt, c) +{ + if (j != 1) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040326-2.c b/gcc/testsuite/gcc.dg/tree-ssa/20040326-2.c new file mode 100644 index 00000000000..a3e16ad451e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040326-2.c @@ -0,0 +1,63 @@ +/* { dg-options "-O2 -fno-inline-functions" } */ +/* { dg-do run } */ + +/* Gimplification problem exposed by zsh. All the side-effects in + function arguments and in the called expression should happen + before the actual function call. */ +int A; + +typedef void (*fnptr) (void); +fnptr *F; + +void +foo (int x) +{ + if (A == x) + abort (); +} + +void +bar (int x, int y) +{ + if (x == 5 || y != 3) + abort (); +} + +void +boz (void) +{ + abort (); +} + +void +baz (void) +{ + if (*F != boz) + abort (); +} + +fnptr B[2] = { baz, boz }; + +main () +{ + int b, c; + + /* The gimplifier was emitting A++ after the call to foo. */ + A = 5; + foo (A++); + + /* The increment to 'b' and 'c' must happen before the call. However, + the first argument to bar() must be the original value of 'b', while + the second argument must be the new value of 'c'. */ + b = 4; + c = 2; + bar (b++, ++c); + + /* This call via function pointer *F should go to baz, but F should + be incremented before the actual call (i.e., right before the + call F should be pointing to boz). */ + F = &B[0]; + (*F++) (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040408-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040408-1.c new file mode 100644 index 00000000000..6578be543a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040408-1.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* Make sure that when a variable with an NMT is marked for renaming + that the NMT's aliases are also marked for renaming. */ + +static int eiisnan (short unsigned int *x) +{ + int i; + + if( x[i] != 0 ) + return(1); +} + +static int eiisinf (unsigned short *x) +{ + if (eiisnan (x)) + return (0); + + if ((x[1] & 0x7fff) == 0x7fff) + return (1); +} + +static void toe64(short unsigned int *a, short unsigned int *b) +{ + register unsigned short *p, *q; + unsigned short i; + + q = b + 4; + + if (eiisinf (a)); + + for( i=0; i<4; i++ ) + *q-- = *p++; +} + +static int asctoeg(short unsigned int *y, int oprec) +{ + unsigned short yy[13]; + char *s; + + while( *s == ' ' ) + ++s; + + toe64( yy, y ); +} + +long double _strtold (char *s, char **se) +{ + long double x; + asctoeg( (unsigned short *)&x, 64 ); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040430-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040430-1.c new file mode 100644 index 00000000000..73ee8da85a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/20040430-1.c @@ -0,0 +1,25 @@ +/* PR middle-end/14470. Similar to + gcc.c-torture/execute/20040313-1.c, but with a compile time test to + make sure the second if() is removed. We should actually get rid + of the first if() too, but we're not that smart yet. */ + +/* { dg-do run } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + + +extern void abort(void); + +int main() +{ + int t[1025] = { 1024 }, d; + + d = 0; + d = t[d]++; + if (t[0] != 1025) + abort(); + if (d != 1024) + abort(); + return 0; +} + +/* { dg-final { scan-tree-dump-times "if " 1 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/asm-1.c b/gcc/testsuite/gcc.dg/tree-ssa/asm-1.c new file mode 100644 index 00000000000..ad92408f170 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/asm-1.c @@ -0,0 +1,16 @@ +/* Make sure that gcc understands that an in/out operand is a use as well + as a def. */ + +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +void f() +{ + int i = 42; + int j = 63; + + asm ("": "=m"(i), "+r"(j) : "m"(i)); +} + +/* { dg-final { scan-tree-dump-times "42" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "63" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cfgcleanup-1.c b/gcc/testsuite/gcc.dg/tree-ssa/cfgcleanup-1.c new file mode 100644 index 00000000000..4d22a42814a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/cfgcleanup-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dce1" } */ +void +cleanup (int a, int b) +{ + if (a) + if (b) + a = 1; + else + b = 1; + else if (a) + a = 1; + else + b = 1; + return; +} +/* Dce should get rid of the initializers and cfgcleanup should elliminate ifs */ +/* { dg-final { scan-tree-dump-times "if " 0 "dce1"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-headers.c b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers.c new file mode 100644 index 00000000000..efe831beab5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-headers.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-ch-details" } */ + +extern int foo (int); + +void bla (void) +{ + int i, n = foo (0); + + for (i = 0; i < n; i++) + foo (i); +} + +/* There should be a header scheduled for duplication. */ +/* { dg-final { scan-tree-dump-times "Scheduled" 1 "ch"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/sra-1.c b/gcc/testsuite/gcc.dg/tree-ssa/sra-1.c new file mode 100644 index 00000000000..652f402dc83 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/sra-1.c @@ -0,0 +1,72 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +/* Tests for SRA. */ + +typedef struct teststruct +{ + double d; + char f1; +} teststruct; + +void +copystruct1 (teststruct param) +{ + teststruct local; + param.f1 = 0; + local = param; + if (local.f1 != 0) + link_error (); +} + +void +copystruct11 (teststruct *param) +{ + teststruct local; + param->f1 = 0; + local = *param; + if (local.f1 != 0) + link_error (); +} + +void +copystruct111 (teststruct param) +{ + teststruct *local = ¶m; + param.f1 = 0; + if (local->f1 != 0) + link_error (); +} + +teststruct globf; +void +copystruct1111 (void) +{ + teststruct local; + globf.f1 = 0; + local = globf; + if (local.f1 != 0) + link_error (); +} + +void +copystruct11111 (void) +{ + teststruct *local = &globf; + globf.f1 = 0; + if (local->f1 != 0) + link_error (); +} + +void +copystruct111111 (teststruct param) +{ + static teststruct local; + param.f1 = 0; + local = param; + if (local.f1 != 0) + link_error (); +} + +/* There should be no referenc to link_error. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/sra-2.c b/gcc/testsuite/gcc.dg/tree-ssa/sra-2.c new file mode 100644 index 00000000000..fa8bea51bc7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/sra-2.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +/* Test for SRA. */ + +typedef struct teststruct +{ + double d; + char f1; +} teststruct; + + +void +copystruct11 (teststruct *param) +{ + static teststruct local; + param->f1 = 0; + local = *param; + if (local.f1 != 0) + link_error (); +} + + +/* There should be no reference to link_error. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/sra-3.c b/gcc/testsuite/gcc.dg/tree-ssa/sra-3.c new file mode 100644 index 00000000000..f6ffc575938 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/sra-3.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +/* Test for SRA. */ + +typedef struct teststruct +{ + double d; + char f1; +} teststruct; + +teststruct *globf1; + +extern void link_error (void); + +void +copystruct1 (void) +{ + teststruct local; + globf1->f1 = 0; + local = *globf1; + if (local.f1 != 0) + link_error (); +} + +/* There should be no reference to link_error. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-1.c new file mode 100644 index 00000000000..419cc95c71e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-1.c @@ -0,0 +1,74 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ccp" } */ + +extern void link_error (void); + +/* check folding */ + +void test1 (void) +{ + unsigned int l = 3 * 4 - 5 / 2; + if (l != 10) + link_error (); +} + +void test11 (void) +{ + unsigned int l = (((((((3 / 2 + 2) * 4) & 7) ^ 3) % 8) << 2) + 1) >> 2; + if (l != 7) + link_error (); +} + +/* cprop in a basic block */ +void test111 (void) +{ + unsigned int l0 = 3 / 2 + 2; + unsigned int l1 = l0 * 4; + unsigned int l2 = 7; + unsigned int l3 = l1 & l2; + unsigned int l4 = 3; + unsigned int l5 = l3 ^ l4; + unsigned int l6 = 8; + unsigned int l7 = l5 % l6; + unsigned int l8 = 2; + unsigned int l9 = l7 << l8; + unsigned int l10 = l9 + 1; + unsigned int l11 = l10 >> 2; + if (l11 != 7) + link_error (); +} + + +/* cprop after an if statement */ +void test1111 (int p) +{ + int l = 53; + if (p) + { + if ((67 + l - 25) != 95) + link_error (); + } + else + { + if ((93 - l + 25) != 65) + link_error (); + } +} + +/* cprop after a loop */ +void test11111 (int p, int q, int r) +{ + int l = 53; + while (p < r) + { + if ((67 + l - 25) != 95) + link_error (); + p -= q; + } +} + + + +/* There should be not link_error calls, if there is any the + optimization has failed */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c new file mode 100644 index 00000000000..091703a1017 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-fab" } */ + +/* Check that we fold strlen of equally long strings, and that we do not + fail to terminate when there is a nontrivial cycle in the corresponding + ssa graph. */ + +void foo(int i) +{ + char *s = "abcde"; + + if (i) + { + s = "defgh"; + goto middle; + } + +start: + + bla (); + +middle: + + if (bla ()) + goto start; + + bar (strlen (s)); +} + +/* There should be no calls to strlen. */ +/* { dg-final { scan-tree-dump-times "strlen" 0 "fab"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c new file mode 100644 index 00000000000..b7f307964a6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-11.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +/* Test for CPROP across a DAG. */ + +int test111 (int param) +{ + int a, b, c; + if (param) { + a = 3; + b = 2; + } + else { + a = 2; + b = 3; + } + c = a + b; + if (c != 5) + return 2; + return 0; +} + +int test1111 (int param) +{ + _Bool a, b, c; + if (param) { + a = 1; + b = 0; + } + else { + a = 0; + b = 1; + } + c = a && b; + if (c) + return 2; + return 0; +} + +/* All ifs should be eliminated. */ +/* { dg-final { scan-tree-dump-times "if" 0 "optimized" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c new file mode 100644 index 00000000000..b3c87fdc7b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c @@ -0,0 +1,171 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ccp" } */ + +extern void link_error (void); + + +/* check that cprop for variables of different types still works even + if function calls or assignments to different types of data are + interposed. */ + +int test7 (int *intarr) +{ + extern int foo7 (int); + int u = 7, v1; + foo7 (u); + v1 = u; + if (v1 != 7) + link_error (); + return v1; +} + +int test77 (int *arr) +{ + int u = 7, v1; + arr[0] = 4; + v1 = u; + if (v1 != 7) + link_error (); + return v1 + arr[0]; +} + +int test777 (void) +{ + extern int foo(int *); + int u = 7, v1; + static int sarr[10]; + sarr[0] = 4; + v1 = u; + if (v1 != 7) + link_error (); + foo (sarr); + return v1 + sarr[0]; +} + +int garr[10]; +int test7777 (void) +{ + int u = 7, v1; + garr[0] = 4; + v1 = u; + if (v1 != 7) + link_error (); + return v1 + garr[0]; +} + +int test88 (int *arr) +{ + static int l; + int v1; + l = 8; + arr[0] = 4; + v1 = l; + if (v1 != 8) + link_error (); + l = foo88 (l); + return v1 + arr[0]; +} + +int test888 (void) +{ + static int l; + extern int foo(int *); + int v1; + static int sarr[10]; + l = 8; + sarr[0] = 4; + v1 = l; + if (v1 != 8) + link_error (); + foo (sarr); + l = foo88(l); + return v1 + sarr[0]; +} + +int test8888 (void) +{ + static int l; + int v1; + l = 8; + garr[0] = 4; + v1 = l; + if (v1 != 8) + link_error (); + return v1 + garr[0]; +} + + + +/* global var */ +int g9; +int garr9[10]; +int test9 (int *intarr) +{ + extern int foo9 (int) __attribute__ ((const)); + int h, v; + g9 = 9; + h = foo9 (g9); + v = g9; + if (v != 9) + link_error (); + return g9; +} + +int test99 (int *intarr) +{ + extern int foo9 (int) __attribute__ ((pure)); + int h, v; + g9 = 9; + h = foo9 (g9); + v = g9; + if (v != 9) + link_error (); + return g9; +} + +extern int foo99 (int); + +int test999 (int *arr) +{ + static int l; + int v1; + g9 = 9; + l = 4; + v1 = g9; + if (v1 != 9) + link_error (); + l = foo99 (l); + return v1 + l; +} + + +int test9999 (void) +{ + int v1; + static int sarr[10]; + g9 = 9; + sarr[0] = 4; + v1 = g9; + if (v1 != 9) + link_error (); + foo (sarr); + g9 = foo99 (g9); + return v1 + sarr[0]; +} + + +int test99999 (void) +{ + int v1; + g9 = 9; + garr9[0] = 4; + v1 = g9; + if (v1 != 9) + link_error (); + return v1 + garr9[0]; +} + + +/* There should be not link_error calls, if there is any the + optimization has failed */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-3.c new file mode 100644 index 00000000000..15d43cb7ef7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-3.c @@ -0,0 +1,134 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ccp" } */ + +extern void link_error (void); + +/* some addresses clearly cannot be equal, check that some address + expressions can be evaluated as constants */ + +char g1, g2; +void test6 (char p1, char p2) +{ + char l1 = 1, l2 = 2; + static char s1 = 5, s2 = 7; + if (&l1 == &l2) + link_error (); + + if (&p1 == &p2) + link_error (); + + if (&s1 == &s2) + link_error (); + + if (&g1 == &g2) + link_error (); + + if (&p1 == &l1) + link_error (); + + if (&p1 == &s1) + link_error (); + + if (&p1 == &l2) + link_error (); + + if (&p1 == &g1) + link_error (); + + if (&l1 == &g1) + link_error (); + + if (&s1 == &g1) + link_error (); +} + +extern void *alloc (int) __attribute__ ((malloc)); +char gca1[128]; +char* __restrict__ rgc1; +char* test66 (char * __restrict__ rp1, char * __restrict__ rp2, char *p1) +{ + char * __restrict__ rl1 = p1; + char * l1 = (char*) alloc (20); + + if (l1 == rgc1) + link_error (); + + if (l1 == rp1) + link_error (); + + if (l1 == rl1) + link_error (); + + if (l1 == gca1) + link_error (); + + if (rl1 == rgc1) + link_error (); + + if (rl1 == rp1) + link_error (); + + if (rl1 == gca1) + link_error (); + + if (rp1 == rp2) + link_error (); + + if (rp1 == rgc1) + link_error (); + + if (rp1 == gca1) + link_error (); + + if (gca1 == rgc1) + link_error (); + +} + +int gci1[128]; +int* __restrict__ rgi1; +int* test666 (int * __restrict__ rp1, int * __restrict__ rp2, int *p1) +{ + int * __restrict__ rl1 = p1; + int * l1 = (int*) alloc (20); + + if (l1 == rgi1) + link_error (); + + if (l1 == rp1) + link_error (); + + if (l1 == rl1) + link_error (); + + if (l1 == gci1) + link_error (); + + if (rl1 == rgi1) + link_error (); + + if (rl1 == rp1) + link_error (); + + if (rl1 == gci1) + link_error (); + + if (rp1 == rp2) + link_error (); + + if (rp1 == rgi1) + link_error (); + + if (rp1 == gci1) + link_error (); + + if (gci1 == rgi1) + link_error (); +} + + +/* There should be not link_error calls, if there is any the + optimization has failed */ +/* ??? While we indeed don't handle some of these, a couple of the + restrict tests are incorrect. */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-7.c new file mode 100644 index 00000000000..ba6db18e00e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-7.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ccp" } */ + +extern void link_error (void); + +/* tests to check if cprop works when using non-return functions */ + +extern int not_returning (int) __attribute__ ((noreturn)); + +int b; +int test7 (int a) +{ + b = 7; + if (a) + { + not_returning (a); + } + if (b != 7) + link_error (); + return b; +} + + +/* There should be not link_error calls, if there is any the + optimization has failed */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-9.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-9.c new file mode 100644 index 00000000000..4656558814e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-9.c @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-ccp" } */ + +/* Check that cprop works for assignments to array elements and structs. */ + +struct foo { + int a; +}; + +extern void link_error (void); + +void +test9 (struct foo f) +{ + f.a = 0; + if (f.a != 0) + link_error (); +} + +void +test99 (struct foo *f) +{ + f->a = 0; + if (f->a != 0) + link_error (); +} + +void +test999 (int *arr) +{ + *arr = 0; + if (*arr != 0) + link_error (); +} + +void +test9999 (int *arr) +{ + arr[13] = 0; + if (arr[13] != 0) + link_error (); +} + +void +test99999 (int *arr, int j) +{ + arr[j] = 0; + if (arr[j] != 0) + link_error (); +} + +/* There should be no link_error calls, if there is any, the + optimization has failed */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "ccp"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-1.c new file mode 100644 index 00000000000..e95cf67cde0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dce3" } */ + +int t() __attribute__ ((const)); +q() +{ + int i = t(); + if (!i) + i = t(); +} +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dce3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-2.c new file mode 100644 index 00000000000..64525141beb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-dce3" } */ + +/* We should notice constantness of this function. */ +int t(int a) +{ + return a+1; +} +q() +{ + int i = t(1); + if (!i) + i = t(1); +} +/* There should be no IF conditionals. */ +/* { dg-final { scan-tree-dump-times "if " 0 "dce3"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-3.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-3.c new file mode 100644 index 00000000000..efaa3affaf6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dce-3.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-cddce" } */ + +int main(void) +{ + unsigned i, j; + + for (i = 1, j = 0; i != 0; i+=2) + { + j += 500; + if (j % 7) + { + j++; + } + else + { + j--; + } + } + + return 0; +} + +/* We should eliminate the inner condition, but the loop must be preserved + as it is infinite. Therefore there should be just one phi node (for i): */ +/* { dg-final { scan-tree-dump-times "PHI " 1 "cddce"} } */ + +/* And one if (for the exit condition of the loop): */ +/* { dg-final { scan-tree-dump-times "if " 1 "cddce"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-ccp-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-ccp-1.c new file mode 100644 index 00000000000..db7b4b49ed2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-ccp-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom1-details" } */ +int t(int a) __attribute__ ((const)); +void abort (void); +int +ccp(int b) +{ + int a=1; + a++; + a++; + a++; + if (b) + abort(); + return a; +} +/* We should propagate constant 4 into return. */ +/* { dg-final { scan-tree-dump-times "Replaced.*with constant '4'" 1 "dom1"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c new file mode 100644 index 00000000000..4e4ed8c912f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom2-details" } */ +int t(int a) __attribute__ ((const)); +void q (void); +void +threading(int a,int b) +{ + if (t(a)) + { + if (t(a)) + q(); + } +} +/* We should thread the jump twice and eliminate it. Test this in + DOM2, after aliases have been computed. */ +/* { dg-final { scan-tree-dump-times "Replaced.* t " 1 "dom2"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-1.c new file mode 100644 index 00000000000..e4ae8ea0b92 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dom1-details" } */ +void t(void); +void q(void); +void q1(void); +void +threading(int a,int b) +{ + if (a>b) + t(); + else + q(); + if (a<=b) + q1(); +} +/* We should thread the jump twice and elliminate it. */ +/* { dg-final { scan-tree-dump-times "Threaded" 2 "dom1"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c new file mode 100644 index 00000000000..43eb6e0848f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-1.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +int main(int argc, char **argv) +{ + int a; + int b; + int c; + b = argc + 1; + c = argc + 2; + a = b + c; + if (argc * 2) + { + c = argc + 3; + } + printf ("%d, %d\n", a, b + c); +} +/* We should eliminate one evaluation of b + c along the main path, + causing one reload. */ +/* { dg-final { scan-tree-dump-times "Reloads:1" 1 "pre"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c new file mode 100644 index 00000000000..e264c50f920 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-2.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +int motion_test1(int data, int data_0, int data_3, int v) +{ + int i; + int t, u; + + if (data) + i = data_0 + data_3; + else { + v = 2; + i = 5; + } + t = data_0 + data_3; + u = i; + return v * t * u; +} +/* We should eliminate one computation of data_0 + data_3 along the + main path, causing one reload. */ +/* { dg-final { scan-tree-dump-times "Reloads:1" 1 "pre"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-1.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-1.c new file mode 100644 index 00000000000..c2a85940a30 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ +int q(int a); +int *v; +int +t(int a) +{ + int r,r1; + if (a) + r1=r = q(a-1); + else + return 0; + /* Dead alloca should not disturb us. */ + if (r!=r1) + v=alloca(r); + return r; +} +/* { dg-final { scan-tree-dump-times "Found tail call" 1 "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-2.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-2.c new file mode 100644 index 00000000000..7f3415444ff --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-tailc-details" } */ +/* Test provided by Richard Earnshaw in PR 14312. */ + +void bar (int i); +void baz (int *); + +void +foo (int *x) +{ + if (*x < 0) + { + baz (x); + return; + } + bar (*x); +} + +/* The test has no local call-clobbered variables. Only the memory + tag for 'x' is call-clobbered. And since tags are not real + variables, they ought to be ignored. There should be two tail + calls here. */ +/* { dg-final { scan-tree-dump-times "Found tail call" 2 "tailc"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-1.c b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-1.c new file mode 100644 index 00000000000..dc61c1324bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-tailr-details" } */ +int +t(int a) +{ + if (a) + return t(a-1); + else + return 0; +} +/* { dg-final { scan-tree-dump-times "Eliminated tail recursion" 1 "tailr"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-2.c b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-2.c new file mode 100644 index 00000000000..095993bc133 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-tailr-details" } */ +int +t(char *a) +{ + static char p[100]; + if (a) + return t(p); + else + return 0; +} +/* { dg-final { scan-tree-dump-times "Eliminated tail recursion" 1 "tailr"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-3.c b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-3.c new file mode 100644 index 00000000000..097a1de0e4e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-3.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-tailr-details" } */ +int +t(int a) +{ + int r; + if (a) + r = t(a-1); + else + return 0; + if (r) + r=r; + return r; +} +/* { dg-final { scan-tree-dump-times "Eliminated tail recursion" 1 "tailr"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-4.c b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-4.c new file mode 100644 index 00000000000..71a4f6716a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-4.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-tailr-details" } */ +int +t(int a) +{ + int r; + if (a&1) + r = t(a-1); + else if (a) + r = t(a-2); + else + return 0; + if (r) + r=r; + return r; +} +/* { dg-final { scan-tree-dump-times "Eliminated tail recursion" 2 "tailr"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-5.c b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-5.c new file mode 100644 index 00000000000..2940a5019bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tailrecursion-5.c @@ -0,0 +1,72 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +int sum (int n) +{ + if (n == 0) + return 0; + + return n + sum (n - 1); +} + +int fac (int n) +{ + if (n == 0) + return 1; + + return n * fac (n - 1); +} + +int sq_sum (int n) +{ + if (n == 0) + return 0; + + return n * n + sq_sum (n - 1); +} + +int pow2m1 (int n) +{ + if (n == 0) + return 0; + + return 2 * pow2m1 (n - 1) + 1; +} + +int fib (int n) +{ + if (n <= 1) + return 1; + + return fib (n - 2) + fib (n - 1); +} + +int main(void) +{ + if (sum (5) != 15) + abort (); + + if (fac (5) != 120) + abort (); + + if (sq_sum (5) != 55) + abort (); + + if (pow2m1 (5) != 31) + abort (); + + if (fib (5) != 8) + abort (); + + exit (0); +} + +/* There is one call of sum in main and then 2 instances of the word in + ;; Function sum (sum) and one in the function header. */ +/* { dg-final { scan-tree-dump-times "\\msum\\M" 4 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "\\mfac\\M" 4 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "\\msq_sum\\M" 4 "optimized"} } */ +/* { dg-final { scan-tree-dump-times "\\mpow2m1\\M" 4 "optimized"} } */ + +/* There is one recursive call to fib. */ +/* { dg-final { scan-tree-dump-times "\\mfib\\M" 5 "optimized"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tree-ssa.exp b/gcc/testsuite/gcc.dg/tree-ssa/tree-ssa.exp new file mode 100644 index 00000000000..7b3403c957d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/tree-ssa.exp @@ -0,0 +1,36 @@ +# Copyright (C) 1997,2002,2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.dg/tree-ssa/useless-1.c b/gcc/testsuite/gcc.dg/tree-ssa/useless-1.c new file mode 100644 index 00000000000..3274998d1fc --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/useless-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-useless" } */ + +void +foo (void) +{ + int i, a; + for (i = 0; i < 10; i++) + { a = i; } +} + +/* There should be three gotos in the dump. If one was removed + in the loop exit condition, it would be re-introduced during + GIMPLE lowering, at the cost of an extra statement, label, + and basic block. */ +/* { dg-final { scan-tree-dump-times "goto" 3 "useless"} } */ diff --git a/gcc/testsuite/gcc.dg/uninit-1.c b/gcc/testsuite/gcc.dg/uninit-1.c index 91838810fda..060ec250ba7 100644 --- a/gcc/testsuite/gcc.dg/uninit-1.c +++ b/gcc/testsuite/gcc.dg/uninit-1.c @@ -13,7 +13,7 @@ extern void free (void *); void remove_dupes (struct list *el) { - struct list *p, *q, *r; /* { dg-bogus "r" "uninitialized variable warning" { xfail *-*-* } } */ + struct list *p, *q, *r; /* { dg-bogus "r" "uninitialized variable warning" } */ for (p = el; p; p = p->next) { diff --git a/gcc/testsuite/gcc.dg/uninit-11.c b/gcc/testsuite/gcc.dg/uninit-11.c new file mode 100644 index 00000000000..5251f0a2a70 --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-11.c @@ -0,0 +1,42 @@ +/* Positive test for uninitialized variables. */ +/* { dg-do compile } */ +/* { dg-options "-O -Wuninitialized" } */ + +int sink; + +void f1(int parm) /* { dg-bogus "uninitialized" "parameter" } */ +{ + sink = parm; /* { dg-bogus "uninitialized" "parameter" } */ +} + +void f2(void) +{ + int x; + sink = x; /* { dg-warning "is used" "unconditional" } */ +} + +void f3(int p) +{ + int x; /* { dg-warning "may be used" "conditional" } */ + if (p) + x = p; + sink = x; +} + +void f4(int p) +{ + int x; /* { dg-bogus "uninitialized" "easy if" } */ + if (p) + x = 1; + else + x = 2; + sink = x; +} + +void f5(void) +{ + int x, i; /* { dg-bogus "uninitialized" "easy loop" } */ + for (i = 0; i < 10; ++i) + x = 1; + sink = x; +} diff --git a/gcc/testsuite/gcc.dg/uninit-2.c b/gcc/testsuite/gcc.dg/uninit-2.c index 5035a309ebd..352bbac06c5 100644 --- a/gcc/testsuite/gcc.dg/uninit-2.c +++ b/gcc/testsuite/gcc.dg/uninit-2.c @@ -25,7 +25,7 @@ macroexpand (struct cpp_reader *pfile, struct definition *defn) if (nargs >= 0) { - enum cpp_token token; /* { dg-bogus "token" "uninitialized variable warning" { xfail *-*-* } } */ + enum cpp_token token; /* { dg-bogus "token" "uninitialized variable warning" } */ int i, rest_args; i = 0; rest_args = 0; diff --git a/gcc/testsuite/gcc.dg/uninit-3.c b/gcc/testsuite/gcc.dg/uninit-3.c index 78c4254dea5..ac5bfec8e72 100644 --- a/gcc/testsuite/gcc.dg/uninit-3.c +++ b/gcc/testsuite/gcc.dg/uninit-3.c @@ -8,7 +8,7 @@ extern void error (char *); int parse_charconst (const char *start, const char *end) { - int c; /* { dg-bogus "c" "uninitialized variable warning" { xfail *-*-* } } */ + int c; /* { dg-bogus "c" "uninitialized variable warning" } */ int nchars, retval; nchars = 0; diff --git a/gcc/testsuite/gcc.dg/uninit-4.c b/gcc/testsuite/gcc.dg/uninit-4.c index a27317ebed5..c51d00802b7 100644 --- a/gcc/testsuite/gcc.dg/uninit-4.c +++ b/gcc/testsuite/gcc.dg/uninit-4.c @@ -23,7 +23,7 @@ extern struct operation cpp_lex (void); void cpp_parse_expr (void) { - int rprio; /* { dg-bogus "rprio" "uninitialized variable warning" { xfail *-*-* } } */ + int rprio; /* { dg-bogus "rprio" "uninitialized variable warning" } */ struct operation op; for (;;) diff --git a/gcc/testsuite/gcc.dg/uninit-5.c b/gcc/testsuite/gcc.dg/uninit-5.c index ac760d69e03..ae7a8de7646 100644 --- a/gcc/testsuite/gcc.dg/uninit-5.c +++ b/gcc/testsuite/gcc.dg/uninit-5.c @@ -1,5 +1,4 @@ -/* Spurious uninitialized-variable warnings. - These cases are documented as not working in the gcc manual. */ +/* Spurious uninitialized-variable warnings. */ /* { dg-do compile } */ /* { dg-options "-O -Wuninitialized" } */ @@ -10,7 +9,7 @@ extern void foo(void); void func1(int cond) { - int x; /* { dg-bogus "x" "uninitialized variable warning" { xfail *-*-* } } */ + int x; /* { dg-bogus "x" "uninitialized variable warning" } */ if(cond) x = 1; @@ -24,7 +23,7 @@ func1(int cond) void func2 (int cond) { - int x; /* { dg-bogus "x" "uninitialized variable warning" { xfail *-*-* } } */ + int x; /* { dg-bogus "x" "uninitialized variable warning" } */ int flag = 0; if(cond) diff --git a/gcc/testsuite/gcc.dg/uninit-6.c b/gcc/testsuite/gcc.dg/uninit-6.c index 2c428df79b6..b0f2083ab4b 100644 --- a/gcc/testsuite/gcc.dg/uninit-6.c +++ b/gcc/testsuite/gcc.dg/uninit-6.c @@ -34,12 +34,12 @@ struct tree * make_something(int a, int b, int c) { struct tree *rv; - struct tree *field; /* { dg-bogus "field" "uninitialized variable warning" { xfail *-*-* } } */ + struct tree *field; rv = malloc (sizeof (struct tree)); rv->car = 0; - APPEND(rv, field, INTEGER_T, a); + APPEND(rv, field, INTEGER_T, a); /* { dg-bogus "field" "uninitialized variable warning" { xfail *-*-* } } */ APPEND(rv, field, PTR_T, b); APPEND(rv, field, INTEGER_T, c); diff --git a/gcc/testsuite/gcc.dg/uninit-8.c b/gcc/testsuite/gcc.dg/uninit-8.c index 94117da37c9..98700f4aa1f 100644 --- a/gcc/testsuite/gcc.dg/uninit-8.c +++ b/gcc/testsuite/gcc.dg/uninit-8.c @@ -11,7 +11,7 @@ void add_bignums (int *out, int *x, int *y) { int p, sum; - int carry; /* { dg-bogus "carry" "uninitialized variable warning" { xfail *-*-* } } */ + int carry; /* { dg-bogus "carry" "uninitialized variable warning" } */ p = 0; for (; *x; x++, y++, out++, p++) diff --git a/gcc/testsuite/gcc.dg/uninit-9.c b/gcc/testsuite/gcc.dg/uninit-9.c index 62681f9e0fd..2a8ccb69f32 100644 --- a/gcc/testsuite/gcc.dg/uninit-9.c +++ b/gcc/testsuite/gcc.dg/uninit-9.c @@ -23,7 +23,7 @@ func(struct foo *list, int count) { int n_clobbers = 0; int i; - struct foo **clob_list; /* { dg-bogus "clob_list" "uninitialized variable warning" { xfail *-*-* } } */ + struct foo **clob_list; /* { dg-bogus "clob_list" "uninitialized variable warning" } */ if(list[0].type == PARALLEL) { diff --git a/gcc/testsuite/gcc.dg/uninit-H.c b/gcc/testsuite/gcc.dg/uninit-H.c new file mode 100644 index 00000000000..30f58308886 --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-H.c @@ -0,0 +1,19 @@ +/* PR 14204 */ +/* { dg-do compile } */ +/* { dg-options "-O -Wall -Werror" } */ + +#if defined __alpha__ +# define ASM __asm__("$30") +#elif defined __i386__ +# define ASM __asm__("esp") +#elif defined __powerpc__ +# define ASM __asm__("r1") +#else +# define ASM +#endif + +void *load_PCB (void) +{ + register void *sp ASM; + return sp; /* { dg-bogus "uninitialized" } */ +} diff --git a/gcc/testsuite/gcc.dg/warn-1.c b/gcc/testsuite/gcc.dg/warn-1.c index 9d0080171d2..ce35b41e941 100644 --- a/gcc/testsuite/gcc.dg/warn-1.c +++ b/gcc/testsuite/gcc.dg/warn-1.c @@ -5,12 +5,12 @@ static void foo (p) int p; -{ /* { dg-warning "passing arg 1 of" } */ +{ } void bar (void) { void *vp; - foo (vp); /* { dg-warning "" } */ + foo (vp); /* { dg-warning "passing arg 1 of" } */ } diff --git a/gcc/testsuite/gfortran.fortran-torture/ChangeLog.g95 b/gcc/testsuite/gfortran.fortran-torture/ChangeLog.g95 new file mode 100644 index 00000000000..c333a3eab1a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/ChangeLog.g95 @@ -0,0 +1,99 @@ +2003-07-24 Lifang Zeng + + * execute/where_3.f90: Modified. + * execute/where_6.f90: New testcase. + +2003-07-09 Chun HUang + + * execute/intrinsic_scan.f90: Test the SCAN intrinsic. + * execute/intrinsic_verify.f90: Test the VERIFY intrinsic. + +2003-07-02 Paul Brook + + * execite/initializer.f90: Test arrays with scalar initializer. + +2003-06-02 Kejia Zhao + + * execute/intrinsic_associated.f90: New testcase. + * execute/intrinsic_associated_2.f90: New testcase. + +2003-06-01 Paul Brook + + * execute/power.f90: Check complex ** real. + +2003-05-20 Paul Brook + + * execute/forall_1.f90: Avoid many to one assignment. + +2003-05-20 Canqun Yang + + * execute/forall_1.f90: Replace logical operator 'and' with 'or'. + +2003-05-19 Lifang Zeng + + * execute/forall_1.f90: FORALL with negative stride, FORALL has + arbitrary number of indexes, and actual variables used as FORALL + indexes. + +2003-05-07 Kejia Zhao + + * execute/der_point.f90: DERIVED type with components point to the + DERIVED type itself, and two DERIVED type with components point to + each other. + +2003-03-16 Paul Brook + + * execute/arrayarg.f90: Assumed shape dummy arrays aren't legal when + using an implicit interface. + * execute/arraysave.f90: Ditto. + * execute/bounds.f90: Ditto. + * lib/f95-torture.exp (TORTURE_OPTIONS): Check f77 arrays. + +2003-03-15 Paul Brook + + * execute/elemental.f90: Test expressions inside elemental functions. + +2003-03-14 Paul Brook + + * lib/f95-torture.exp (TORTURE_OPTIONS): Check different array + repacking strategies. + +2003-02-15 Paul Brook + + * execute/der_init.f90: Add tests for non-constant constructors. + +2003-02-08 Paul Brook + + * execute/constructor.f90: Additional tests for non-constant + constructors with unexpanded implicit do loops. + +2003-02-06 Paul Brook + + * execute/der_type.f90: Add extra tests for initializers and passing + components as arguments. + +2003-02-01 Paul Brook + + * execute/elemental.f90: Test intrinsic elemental conversion + routines. + +2003-01-28 Paul Brook + + * compile/mystery_proc.f90: New testcase. + +2003-01-27 Paul Brook + + * execute/intrinsic_minmax.f90: Add a couple more variations. + +2003-01-26 Paul Brook + + * execute/contained.f90: New testcase. + * execute/intrinsic_present.f90: New testcase. + +2003-01-22 Steven Bosscher + + * compile/bergervoet2.f90, compile/ambig.f90, + compile/actual.f90, execute/integer_select.f90: + New testcases. + * execute/function_module_1.f90: Fix syntax error. + * execute/retarray.f90: Fix another syntax error. diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/actual.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/actual.f90 new file mode 100644 index 00000000000..871c0814900 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/actual.f90 @@ -0,0 +1,38 @@ +module modull + +contains + +function fun( a ) + real, intent(in) :: a + real :: fun + fun = a +end function fun + +end module modull + + + +program t5 + +use modull + +real :: a, b + +b = foo( fun, a ) + +contains + +function foo( f, a ) + real, intent(in) :: a + interface + function f( x ) + real, intent(in) :: x + real :: f + end function f + end interface + real :: foo + + foo = f( a ) +end function foo + +end program t5 diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/allocate.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/allocate.f90 new file mode 100644 index 00000000000..f5cce41f71e --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/allocate.f90 @@ -0,0 +1,26 @@ +! Snippet to test various allocate statements + +program test_allocate + implicit none + type t + integer i + real r + end type + type pt + integer, pointer :: p + end type + integer, allocatable, dimension(:, :) :: a + type (t), pointer, dimension(:) :: b + type (pt), pointer :: c + integer, pointer:: p + integer n + + n = 10 + allocate (a(1:10, 4)) + allocate (a(5:n, n:14)) + allocate (a(6, 8)) + allocate (b(n)) + allocate (c) + allocate (c%p) + allocate (p) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/ambig.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/ambig.f90 new file mode 100644 index 00000000000..3e5e07dadb0 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/ambig.f90 @@ -0,0 +1,26 @@ +MODULE TYPESP + TYPE DMT + REAL(KIND(1.D0)), POINTER :: ASPK(:) + END TYPE DMT +END MODULE TYPESP + +MODULE TCNST + Integer, Parameter :: DIM_TEMP_BUFFER=10000 + Real(Kind(1.d0)), Parameter :: COLROW_=0.33,PERCENT=0.7 +end MODULE TCNST + + +Subroutine DOWORK(A) + Use TYPESP + Use TCNST + Type(DMT), intent (inout) :: A + Real(Kind(1.d0)),Pointer :: ASPK(:) + Integer :: ISIZE, IDIM + + ISIZE=DIM_TEMP_BUFFER + + Allocate(ASPK(ISIZE),STAT=INFO) + IDIM = MIN(ISIZE,SIZE(A%ASPK)) + ASPK(1:IDIM) = A%ASPK(1:IDIM) + Return +End Subroutine DOWORK diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/arrayio.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/arrayio.f90 new file mode 100644 index 00000000000..1eec0bb59ce --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/arrayio.f90 @@ -0,0 +1,12 @@ +! Program to test array IO. Should print the numbers 1-20 in order +program arrayio + implicit none + integer, dimension(5, 4) :: a + integer i, j + + do j=1,4 + a(:, j) = (/ (i + (j - 1) * 5, i=1,5) /) + end do + + write (*) a +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/bergervoet2.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/bergervoet2.f90 new file mode 100644 index 00000000000..eef33e425c2 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/bergervoet2.f90 @@ -0,0 +1,5 @@ + function testi() result(res) + integer :: res + res = 0 + end function testi + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/compile.exp b/gcc/testsuite/gfortran.fortran-torture/compile/compile.exp new file mode 100644 index 00000000000..81e1c1cebee --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/compile.exp @@ -0,0 +1,55 @@ +# Expect driver script for GCC Regression Tests +# Copyright (C) 2003 Free Software Foundation +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# These tests come from many different contributors. + +if $tracelevel then { + strace $tracelevel +} + +# load support procs +load_lib fortran-torture.exp + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.f]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture $testcase +} + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.F]] { + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture $testcase +} + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.f90]] { + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture $testcase +} + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.f95]] { + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture $testcase +} + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/contained_1.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/contained_1.f90 new file mode 100644 index 00000000000..60f31092e73 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/contained_1.f90 @@ -0,0 +1,15 @@ +! Obscure failure that disappeared when the parameter was removed. +! Works OK now. +module mymod +implicit none +contains + subroutine test(i) + implicit none + integer i + end subroutine +end module mymod + +program error + use mymod +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/contained_2.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/contained_2.f90 new file mode 100644 index 00000000000..76ef6c62871 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/contained_2.f90 @@ -0,0 +1,11 @@ +! Arrays declared in parent but used in the child. +program error + implicit none + integer, dimension (10) :: a +contains + subroutine test() + implicit none + a(1) = 0 + end subroutine +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/contained_3.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/contained_3.f90 new file mode 100644 index 00000000000..da5e8475c54 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/contained_3.f90 @@ -0,0 +1,12 @@ +! Program to check using parent variables in more than one contained function +program contained_3 + implicit none + integer var +contains + subroutine one + var = 1 + end subroutine + subroutine two + var = 2 + end subroutine +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/contained_4.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/contained_4.f90 new file mode 100644 index 00000000000..233dab878fd --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/contained_4.f90 @@ -0,0 +1,35 @@ +! Check contained functions with the same name. +module contained_4 + +contains + + subroutine foo1() + call bar() + contains + subroutine bar() + end subroutine bar + end subroutine foo1 + + subroutine foo2() + call bar() + contains + subroutine bar() + end subroutine bar + end subroutine foo2 + +end module contained_4 + +subroutine foo1() +call bar() +contains + subroutine bar() + end subroutine bar +end subroutine + +subroutine foo2() + call bar() +contains + subroutine bar() + end subroutine bar +end subroutine foo2 + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/contained_5.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/contained_5.f90 new file mode 100644 index 00000000000..94946f76b0d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/contained_5.f90 @@ -0,0 +1,10 @@ +! Function returning an array continaed in a module. Caused problems 'cos +! we tried to add the dummy return vars to the parent scope. + +Module contained_5 +contains +FUNCTION test () + REAL, DIMENSION (1) :: test + test(1)=0.0 +END FUNCTION +end module diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/convert.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/convert.f90 new file mode 100644 index 00000000000..777cd132c85 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/convert.f90 @@ -0,0 +1,37 @@ +! Program to test conversion. Does not actualy test the generated code +program convert + implicit none + integer(kind=4) i + integer(kind=8) m + real(kind=4) r + real(kind=8) q + complex(kind=4) c + complex(kind=8) z + + ! each of these should generate a single intrinsic conversion expression + i = int(i) + i = int(m) + i = int(r) + i = int(q) + i = int(c) + i = int(z) + m = int(i, kind=8) + m = int(m, kind=8) + m = int(r, kind=8) + m = int(q, kind=8) + m = int(c, kind=8) + m = int(z, kind=8) + r = real(i) + r = real(m) + r = real(r) + r = real(q) + r = real(c) + r = real(z, kind=4) + q = real(i, kind=8) + q = real(m, kind=8) + q = real(r, kind=8) + q = real(q, kind=8) + q = real(c, kind=8) + ! Note real() returns the type kind of the argument. + q = real(z) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/dummyfn.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/dummyfn.f90 new file mode 100644 index 00000000000..d54f64899f3 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/dummyfn.f90 @@ -0,0 +1,13 @@ +! Program to test array valued dummy functions +SUBROUTINE dummyfn(deriv) + implicit none + INTERFACE + FUNCTION deriv() + REAL :: deriv(4) + END FUNCTION deriv + END INTERFACE + + REAL :: dx(4) + + dx = deriv() +END SUBROUTINE diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/emptyif.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/emptyif.f90 new file mode 100644 index 00000000000..bd12d502ef8 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/emptyif.f90 @@ -0,0 +1,42 @@ +! Program to test empty IF statements +program emptyif + implicit none + logical c + logical d + + if (c) then + c = .true. + end if + + if (c) then + else + c = .true. + end if + + if (c) then + c = .true. + else + end if + + if (c) then + c = .true. + elseif (d) then + c = .true. + else + end if + + if (c) then + c = .true. + elseif (d) then + else + c = .true. + end if + + if (c) then + elseif (d) then + c = .true. + else + c = .true. + end if + +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/fnresvar.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/fnresvar.f90 new file mode 100644 index 00000000000..fab9aa665a4 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/fnresvar.f90 @@ -0,0 +1,5 @@ +! Explicit function rsult variables +function fnresvar() result (r) + integer r + r = 0 +end function diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/gen_interf.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/gen_interf.f90 new file mode 100644 index 00000000000..eb493411b34 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/gen_interf.f90 @@ -0,0 +1,19 @@ +! Program to test generic interfaces. +program gen_interf + implicit none + interface gen + function ifn (a) + integer :: a, ifn + end function + end interface + interface gsub + subroutine igsub (a) + integer a + end subroutine + end interface + + integer i + + call gsub (i) + i = gen(i) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/implicit.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/implicit.f90 new file mode 100644 index 00000000000..296821e8983 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/implicit.f90 @@ -0,0 +1,8 @@ +implicit integer(a), logical(b-c), real(d-y), integer(z) +a = 1_4 +b = .true. +c = b +d = 1.0e2 +y = d +z = a +end diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/io_end.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/io_end.f90 new file mode 100644 index 00000000000..f67ae57ae8e --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/io_end.f90 @@ -0,0 +1,9 @@ +! Check we can cope with end labels in IO statements +program m + implicit none + integer i + do while (.true.) + read(*, *, end = 1) i + end do +1 continue +end program m diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/module_common.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/module_common.f90 new file mode 100644 index 00000000000..f727881d75b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/module_common.f90 @@ -0,0 +1,10 @@ +! We were incorrectly trying to create a variable for the common block itself, +! in addition to the variables it contains. +module FOO + implicit none + integer I + common /C/I +contains + subroutine BAR + end subroutine BAR +end module FOO diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/module_expr.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/module_expr.f90 new file mode 100644 index 00000000000..a1ca83a9a21 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/module_expr.f90 @@ -0,0 +1,18 @@ +! This uncovered a bug in the reading/writing of expressions. +module module_expr_1 + integer a +end module + +module module_expr_2 + use module_expr_1 +contains + +subroutine myproc (p) + integer, dimension (a) :: p +end subroutine +end module + +program module_expr + use module_expr_1 + use module_expr_2 +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/module_proc.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/module_proc.f90 new file mode 100644 index 00000000000..17386d4b8e0 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/module_proc.f90 @@ -0,0 +1,14 @@ +! Check module procedures with arguments +module module_proc +contains +subroutine s(p) + integer p +end subroutine +end module + +program test +use module_proc +integer i +call s(i) +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/module_result.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/module_result.f90 new file mode 100644 index 00000000000..105073596f5 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/module_result.f90 @@ -0,0 +1,9 @@ +! Result variables in module procedures +module module_result + implicit none +contains +function test () result (res) + integer res + res = 0 +end function +end module diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/named_args.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/named_args.f90 new file mode 100644 index 00000000000..1e0b4a6733c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/named_args.f90 @@ -0,0 +1,6 @@ +! This caused problems because we created a symbol for P while +! trying to parse the argument list as a substring reference. +program named_args + implicit none + integer, parameter :: realdp = selected_real_kind(p=8,r=30) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/parameter_1.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/parameter_1.f90 new file mode 100644 index 00000000000..8921bcddcad --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/parameter_1.f90 @@ -0,0 +1,7 @@ +! legal +integer, parameter :: j = huge(j) +integer i + + if (j /= huge(i)) call abort +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/parameter_2.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/parameter_2.f90 new file mode 100644 index 00000000000..e480751f19d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/parameter_2.f90 @@ -0,0 +1,23 @@ +! Program to test initialization expressions involving subobjects +program parameter_2 + implicit none + type :: SS + integer :: I + integer :: J + end type SS + type :: TT + integer :: N + type (SS), dimension(2) :: o + end type + + type (SS), parameter :: s = SS (1, 2) + type (TT), parameter :: t = TT(42, (/ SS(3, 4), SS(8, 9) /)) + + integer, parameter :: a(2) = (/5, 10/) + integer, parameter :: d1 = s%i + integer, parameter :: d2 = a(2) + integer, parameter :: d4 = t%o(2)%j + + integer q1, q2, q3, q4 + common /c1/q1(d1), q2(d2), q3(a(1)), q4(d4) ! legal +end diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/shape_reshape.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/shape_reshape.f90 new file mode 100644 index 00000000000..a8e632b1f4b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/shape_reshape.f90 @@ -0,0 +1,8 @@ +! This checks that the shape of the SHAPE intrinsic is known. +PROGRAM shape_reshape + INTEGER, ALLOCATABLE :: I(:,:) + ALLOCATE(I(2,2)) + I = RESHAPE((/1,2,3,4/),SHAPE=SHAPE(I)) + DEALLOCATE(I) +END PROGRAM + diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/stoppause.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/stoppause.f90 new file mode 100644 index 00000000000..9a936f09c3d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/stoppause.f90 @@ -0,0 +1,10 @@ +! Program to check the STOP and PAUSE intrinsics +program stoppause + + pause + pause 1 + pause 'Hello world' + stop + stop 42 + stop 'Go away' +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/strparm_1.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/strparm_1.f90 new file mode 100644 index 00000000000..9625b10fed2 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/strparm_1.f90 @@ -0,0 +1,6 @@ +! Check known length string parameters +subroutine test (s) + character(len=80) :: s + + s = "Hello World" +end subroutine diff --git a/gcc/testsuite/gfortran.fortran-torture/compile/write.f90 b/gcc/testsuite/gfortran.fortran-torture/compile/write.f90 new file mode 100644 index 00000000000..50b83cc6a12 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/compile/write.f90 @@ -0,0 +1,5 @@ +! Program to test simple IO +program testwrite + write (*) 1 + write (*) "Hello World" +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/a_edit_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/a_edit_1.f90 new file mode 100644 index 00000000000..55a6f3cdf2c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/a_edit_1.f90 @@ -0,0 +1,17 @@ +! pr 15113 +! Ax edit descriptor x larger than destination +! A edit descriptor with no field width segfaults + character*16 C + character*4 D + data C / 'ABCDEFGHIJKLMNOP'/ + read(C,'(A7)')D + if (D.NE.'DEFG') then +! print*,D + call abort + endif + read(C,'(A)')D + if (D.NE.'ABCD') then +! print*,D + call abort + endif + end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/allocate.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/allocate.f90 new file mode 100644 index 00000000000..61f717da7bc --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/allocate.f90 @@ -0,0 +1,38 @@ +! Test allocation and deallocation. +program test_allocate + call t1 (.true.) + call t1 (.false.) + call t2 +contains + +! Implicit deallocation and saved aloocated variables. +subroutine t1(first) + real, allocatable, save :: p(:) + real, allocatable :: q(:) + logical first + + if (first) then + if (allocated (p)) call abort () + else + if (.not. allocated (p)) call abort () + end if + if (allocated (q)) call abort () + + if (first) then + allocate (p(5)) + else + deallocate (p) + end if + allocate (q(5)) +end subroutine + +! Explicit deallocation. +subroutine t2() + real, allocatable :: r(:) + + allocate (r(5)) + pr = 1.0 + deallocate (r) + if (allocated(r)) call abort () +end subroutine +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/alternate_return.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/alternate_return.f90 new file mode 100644 index 00000000000..5c77844e6da --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/alternate_return.f90 @@ -0,0 +1,18 @@ +program alt_return + implicit none + + call myproc (1, *10, 42) +20 continue + call abort () +10 continue + call myproc(2, *20, 42) + call myproc(3, *20, 42) +contains +subroutine myproc(n, *, i) + integer n, i + if (i .ne. 42) call abort () + if (n .eq. 1) return 1 + if (n .eq. 2) return +end subroutine +end program alt_return + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/args.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/args.f90 new file mode 100644 index 00000000000..263c795ed70 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/args.f90 @@ -0,0 +1,22 @@ +! Program to test procudure args +subroutine test (a, b) + integer, intent (IN) :: a + integer, intent (OUT) :: b + + if (a .ne. 42) call abort + b = 43 +end subroutine + +program args + implicit none + external test + integer i, j + + i = 42 + j = 0 + CALL test (i, j) + if (i .ne. 42) call abort + if (j .ne. 43) call abort + i = 41 + CALL test (i + 1, j) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/arithmeticif.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/arithmeticif.f90 new file mode 100644 index 00000000000..d06167e6814 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/arithmeticif.f90 @@ -0,0 +1,25 @@ +! Program to test the arithmetic if statement +function testif (a) + implicit none + integer a, b, testif + + if (a) 1, 2, 3 + b = 2 + goto 4 + 1 b = -1 + goto 4 + 2 b = 0 + goto 4 + 3 b = 1 + 4 testif = b +end function + +program testwrite + implicit none + integer i + integer testif + + if (testif (-10) .ne. -1) call abort + if (testif (0) .ne. 0) call abort + if (testif (10) .ne. 1) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/arrayarg.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/arrayarg.f90 new file mode 100644 index 00000000000..b588d050b69 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/arrayarg.f90 @@ -0,0 +1,145 @@ +! Program to test arrays +! The program outputs a series of numbers. +! Two digit numbers beginning with 0, 1, 2 or 3 is a normal. +! Three digit numbers starting with 4 indicate an error. +! Using 1D arrays isn't a sufficient test, the first dimension is often +! handled specially. + +! Fixed size parameter +subroutine f1 (a) + implicit none + integer, dimension (5, 8) :: a + + if (a(1, 1) .ne. 42) call abort + + if (a(5, 8) .ne. 43) call abort +end subroutine + + +program testprog + implicit none + integer, dimension(3:7, 4:11) :: a + a(:,:) = 0 + a(3, 4) = 42 + a(7, 11) = 43 + call test(a) +contains +subroutine test (parm) + implicit none + ! parameter + integer, dimension(2:, 3:) :: parm + ! Known size arry + integer, dimension(5, 8) :: a + ! Known size array with different bounds + integer, dimension(4:8, 3:10) :: b + ! Unknown size arrays + integer, dimension(:, :), allocatable :: c, d, e + ! Vectors + integer, dimension(5) :: v1 + integer, dimension(10, 10) :: v2 + integer n + external f1 + + ! Same size + allocate (c(5,8)) + ! Same size, different bounds + allocate (d(11:15, 12:19)) + ! A larger array + allocate (e(15, 24)) + a(:,:) = 0 + b(:,:) = 0 + c(:,:) = 0 + d(:,:) = 0 + a(1,1) = 42 + b(4, 3) = 42 + c(1,1) = 42 + d(11,12) = 42 + a(5, 8) = 43 + b(8, 10) = 43 + c(5, 8) = 43 + d(15, 19) = 43 + + v2(:, :) = 0 + do n=1,5 + v1(n) = n + end do + + v2 (3, 1::2) = v1 (5:1:-1) + v1 = v1 + 1 + + if (v1(1) .ne. 2) call abort + if (v2(3, 3) .ne. 4) call abort + + ! Passing whole arrays + call f1 (a) + call f1 (b) + call f1 (c) + call f2 (a) + call f2 (b) + call f2 (c) + ! passing expressions + a(1,1) = 41 + a(5,8) = 42 + call f1(a+1) + call f2(a+1) + a(1,1) = 42 + a(5,8) = 43 + call f1 ((a + b) / 2) + call f2 ((a + b) / 2) + ! Passing whole arrays as sections + call f1 (a(:,:)) + call f1 (b(:,:)) + call f1 (c(:,:)) + call f2 (a(:,:)) + call f2 (b(:,:)) + call f2 (c(:,:)) + ! Passing sections + e(:,:) = 0 + e(2, 3) = 42 + e(6, 10) = 43 + n = 3 + call f1 (e(2:6, n:10)) + call f2 (e(2:6, n:10)) + ! Vector subscripts + ! v1= index plus one, v2(3, ::2) = reverse of index + e(:,:) = 0 + e(2, 3) = 42 + e(6, 10) = 43 + call f1 (e(v1, n:10)) + call f2 (e(v1, n:10)) + ! Double vector subscript + e(:,:) = 0 + e(6, 3) = 42 + e(2, 10) = 43 + !These are not resolved properly + call f1 (e(v1(v2(3, ::2)), n:10)) + call f2 (e(v1(v2(3, ::2)), n:10)) + ! non-contiguous sections + e(:,:) = 0 + e(1, 1) = 42 + e(13, 22) = 43 + n = 3 + call f1 (e(1:15:3, 1:24:3)) + call f2 (e(::3, ::n)) + ! non-contiguous sections with bounds + e(:,:) = 0 + e(3, 4) = 42 + e(11, 18) = 43 + n = 19 + call f1 (e(3:11:2, 4:n:2)) + call f2 (e(3:11:2, 4:n:2)) + + ! Passing a dummy variable + call f1 (parm) + call f2 (parm) +end subroutine +! Assumed shape parameter +subroutine f2 (a) + integer, dimension (1:, 1:) :: a + + if (a(1, 1) .ne. 42) call abort + + if (a(5, 8) .ne. 43) call abort +end subroutine +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/arrayarg2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/arrayarg2.f90 new file mode 100644 index 00000000000..9cb5b613d64 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/arrayarg2.f90 @@ -0,0 +1,21 @@ +! Program to test array arguments which depend on other array arguments +program arrayarg2 + integer, dimension(5) :: a, b + + a = (/1, 2, 3, 4, 5/) + b = (/2, 3, 4, 5, 6/) + + call test (a, b) + + if (any (b .ne. (/4, 7, 10, 13, 16/))) call abort +contains +subroutine test (x1, x2) + implicit none + integer, dimension(1:), intent(in) :: x1 + integer, dimension(1:), intent(inout) :: x2 + integer, dimension(1:size(x1)) :: x3 + + x3 = x1 * 2 + x2 = x2 + x3 +end subroutine test +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/arraysave.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/arraysave.f90 new file mode 100644 index 00000000000..94b234bd512 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/arraysave.f90 @@ -0,0 +1,24 @@ +! Program to test arrays with the save attribute +program testarray + implicit none + integer, save, dimension (6, 5) :: a, b + + a = 0 + a(1, 1) = 42 + a(6, 5) = 43 + b(:,1:5) = a + + call fn (a) +contains +subroutine fn (a) + implicit none + integer, dimension(1:, 1:) :: a + integer, dimension(2) :: b + + b = ubound (a) + if (any (b .ne. (/6, 5/))) call abort + if (a(1, 1) .ne. 42) call abort + if (a(6, 5) .ne. 43) call abort +end subroutine +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/assumed_size.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/assumed_size.f90 new file mode 100644 index 00000000000..b2c4657c647 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/assumed_size.f90 @@ -0,0 +1,39 @@ +! Program to test assumed size arrays +subroutine test2(p) + integer, dimension(2, *) :: p + + if (any (p(:, 1:3) .ne. reshape((/1, 2, 4, 5, 7, 8/), (/2, 3/)))) & + call abort () +end subroutine + +program assumed_size + integer, dimension (3, 3) :: a + external test2 + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + + call test1(a, (/1, 2, 3, 4, 5, 6/)) + if (a(1,1) .ne. 0) call abort + a(1, 1) = 1 + call test1(a(1:2, :), (/1, 2, 4, 5, 7, 8/)) + if (a(1,1) .ne. 0) call abort + a(1, 1) = 1 + call test1(a(3:1:-1, :), (/3, 2, 1, 6, 5, 4/)) + if (a(3,1) .ne. 0) call abort + a(3, 1) = 3 + call test1(a(:, 2:3), (/4, 5, 6, 7, 8, 9/)) + if (a(1, 2) .ne. 0) call abort + a(1, 2) = 4 + + call test2(a(1:2, :)) + call test2((/1, 2, 4, 5, 7, 8/)) +contains +subroutine test1(p, q) + integer, dimension(*) :: p + integer, dimension(1:) :: q + + if (any (p(1:size(q)) .ne. q)) call abort () + p(1) = 0 +end subroutine + +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/bounds.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/bounds.f90 new file mode 100644 index 00000000000..b1ad840738c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/bounds.f90 @@ -0,0 +1,35 @@ +! Program to test the upper and lower bound intrinsics +program testbounds + implicit none + real, dimension(:, :), allocatable :: a + integer, dimension(5) :: j + integer i + + allocate (a(3:8, 6:7)) + + ! With one parameter + j = 0; + j(3:4) = ubound(a) + if (j(3) .ne. 8) call abort + if (j(4) .ne. 7) call abort + + ! With two parameters, assigning to an array + j = lbound(a, 1) + if ((j(1) .ne. 3) .or. (j(5) .ne. 3)) call abort + + ! With a variable second parameter + i = 2 + i = lbound(a, i) + if (i .ne. 6) call abort + + call test(a) +contains +subroutine test (a) + real, dimension (1:, 1:) :: a + integer i + + i = 2 + if ((ubound(a, 1) .ne. 6) .or. (ubound(a, i) .ne. 2)) call abort +end subroutine +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/character_select_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/character_select_1.f90 new file mode 100644 index 00000000000..c42cea4fc21 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/character_select_1.f90 @@ -0,0 +1,12 @@ +CHARACTER(LEN=6) :: C = "STEVEN" + +SELECT CASE (C) + CASE ("AAA":"EEE") + CALL abort + CASE ("R":"T") + CONTINUE + CASE DEFAULT + CALL abort +END SELECT +END + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/cmplx.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/cmplx.f90 new file mode 100644 index 00000000000..8e434c03342 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/cmplx.f90 @@ -0,0 +1,45 @@ +! Test complex munbers +program testcmplx + implicit none + complex(kind=4) c, d + complex(kind=8) z + real(kind=4) x, y + real(kind=8) q + + ! cmplx intrinsic + x = 3 + y = 4 + c = cmplx(x,y) + if (c .ne. (3.0, 4.0)) call abort + x = 4 + y = 3 + z = cmplx(x, y, 8) + if (z .ne. (4.0, 3.0)) call abort + z = c + if (z .ne. (3.0, 4.0)) call abort + + ! dcmplx intrinsic + x = 3 + y = 4 + z = dcmplx (x, y) + if (z .ne. (3.0, 4.0)) call abort + + ! conjucates and aimag + c = (1.0, 2.0) + c = conjg (c) + x = aimag (c) + if (abs (c - (1.0, -2.0)) .gt. 0.001) call abort + if (x .ne. -2.0) call abort + z = (2.0, 1.0) + z = conjg (z) + q = aimag (z) + if (z .ne. (2.0, -1.0)) call abort + if (q .ne. -1.0) call abort + + ! addition, subtraction and multiplication + c = (1, 3) + d = (5, 2) + if (c + d .ne. ( 6, 5)) call abort + if (c - d .ne. (-4, 1)) call abort + if (c * d .ne. (-1, 17)) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/common.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/common.f90 new file mode 100644 index 00000000000..2ea1788eb54 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/common.f90 @@ -0,0 +1,53 @@ +! Program to test COMMON and EQUIVALENCE. +program common + real (kind=8) a(8) + real (kind=8) b(5), c(5) + common /com1/b,c + equivalence (a(1), b(2)) + b = 100 + c = 200 + call common_pass + call common_par (a, b,c) + call global_equiv + call local_equiv +end + +! Use common block to pass values +subroutine common_pass + real (kind=8) a(8) + real (kind=8) b(5), c(5) + common /com1/b,c + equivalence (a(1), b(2)) + if (any (a .ne. (/100,100,100,100,200,200,200,200/))) call abort +end subroutine + +! Common variables as argument +subroutine common_par (a, b, c) + real (kind=8) a(8), b(5), c(5) + if (any (a .ne. (/100,100,100,100,200,200,200,200/))) call abort + if (any (b .ne. (/100,100,100,100,100/))) call abort + if (any (c .ne. (/200,200,200,200,200/))) call abort +end subroutine + +! Global equivalence +subroutine global_equiv + real (kind=8) a(8), b(5), c(5), x(8), y(4), z(4) + common /com2/b, c, y, z + equivalence (a(1), b(2)) + equivalence (x(4), y(1)) + b = 100 + c = 200 + y = 300 + z = 400 + if (any (a .ne. (/100,100,100,100,200,200,200,200/))) call abort + if (any (x .ne. (/200,200,200,300,300,300,300,400/))) call abort +end + +! Local equivalence +subroutine local_equiv + real (kind=8) a(8), b(10) + equivalence (a(1), b(3)) + b(1:5) = 100 + b(6:10) = 200 + if (any (a .ne. (/100,100,100,200,200,200,200,200/))) call abort +end subroutine diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/common_size.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/common_size.f90 new file mode 100644 index 00000000000..936c41e3282 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/common_size.f90 @@ -0,0 +1,10 @@ +! The size of common 'com1' should be 80, instead of 112. +program common_size + real (kind=8) a(8) + real (kind=8) b(5), c(5) + common /com1/b,c + equivalence (a(1), b(2)) + b = 100 + c = 200 + if ((a (4) .ne. 100) .or. (a(5) .ne. 200)) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/constructor.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/constructor.f90 new file mode 100644 index 00000000000..96cb89d721c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/constructor.f90 @@ -0,0 +1,29 @@ +! Program to test array constructors +program constructors + integer, dimension (4) :: a + integer, dimension (3, 2) :: b + integer i, j, k, l, m, n + + a = (/1, (i,i=2,4)/) + do i = 1, 4 + if (a(i) .ne. i) call abort + end do + + b = reshape ((/0, 1, 2, 3, 4, 5/), (/3, 2/)) + 1 + do i=1,3 + if (b(i, 1) .ne. i) call abort + if (b(i, 2) .ne. i + 3) call abort + end do + + k = 1 + l = 2 + m = 3 + n = 4 + ! The remainder assumes constant constructors work ok. + a = (/n, m, l, k/) + if (any (a .ne. (/4, 3, 2, 1/))) call abort + a = (/((/i+10, 42/), i = k, l)/) + if (any (a .ne. (/11, 42, 12, 42/))) call abort + a = (/(I, I=k,l) , (J, J=m,n)/) + if (any (a .ne. (/1, 2, 3, 4/))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/contained.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/contained.f90 new file mode 100644 index 00000000000..3c7117744dd --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/contained.f90 @@ -0,0 +1,16 @@ +program contained + implicit none + integer i + + i = 0; + call testproc (40) + if (i .ne. 42) call abort +contains + subroutine testproc (p) + implicit none + integer p + + if (p .ne. 40) call abort + i = p + 2 + end subroutine +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/contained2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/contained2.f90 new file mode 100644 index 00000000000..cae94b704e1 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/contained2.f90 @@ -0,0 +1,28 @@ +! Program to check resolution of symbols with the same name +program contained2 + implicit none + integer var1 + + var1 = 42 + if (f1() .ne. 1) call abort + call f2() + if (var1 .ne. 42) call abort +contains + +function f1 () + implicit none + integer f1 + integer var1 + integer f2 + + var1 = 1 + f2 = var1 + f1 = f2 +end function + +subroutine f2() + implicit none + if (f1() .ne. 1) call abort +end subroutine + +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/csqrt_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/csqrt_1.f90 new file mode 100644 index 00000000000..680449f3ede --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/csqrt_1.f90 @@ -0,0 +1,78 @@ +! PR 14396 +! These we failing on targets which do not provide the c99 complex math +! functions. +! Extracted from intrinsic77.f in the g77 testsuite. + logical fail + common /flags/ fail + fail = .false. + call square_root + if (fail) call abort + end + subroutine square_root + intrinsic sqrt, dsqrt, csqrt + real x, a + x = 4.0 + a = 2.0 + call c_r(SQRT(x),a,'SQRT(real)') + call c_d(SQRT(1.d0*x),1.d0*a,'SQRT(double)') + call c_c(SQRT((1.,0.)*x),(1.,0.)*a,'SQRT(complex)') + call c_d(DSQRT(1.d0*x),1.d0*a,'DSQRT(double)') + call c_c(CSQRT((1.,0.)*x),(1.,0.)*a,'CSQRT(complex)') + call p_r_r(SQRT,x,a,'SQRT') + call p_d_d(DSQRT,1.d0*x,1.d0*a,'DSQRT') + call p_c_c(CSQRT,(1.,0.)*x,(1.,0.)*a ,'CSQRT') + end + subroutine failure(label) +! Report failure and set flag + character*(*) label + logical fail + common /flags/ fail + write(6,'(a,a,a)') 'Test ',label,' FAILED' + fail = .true. + end + subroutine c_r(a,b,label) +! Check if REAL a equals b, and fail otherwise + real a, b + character*(*) label + if ( abs(a-b) .gt. 1.0e-5 ) then + call failure(label) + write(6,*) 'Got ',a,' expected ', b + end if + end + subroutine c_d(a,b,label) +! Check if DOUBLE PRECISION a equals b, and fail otherwise + double precision a, b + character*(*) label + if ( abs(a-b) .gt. 1.0d-5 ) then + call failure(label) + write(6,*) 'Got ',a,' expected ', b + end if + end + + subroutine c_c(a,b,label) +! Check if COMPLEX a equals b, and fail otherwise + complex a, b + character*(*) label + if ( abs(a-b) .gt. 1.0e-5 ) then + call failure(label) + write(6,*) 'Got ',a,' expected ', b + end if + end + subroutine p_r_r(f,x,a,label) +! Check if REAL f(x) equals a for REAL x + real f,x,a + character*(*) label + call c_r(f(x),a,label) + end + subroutine p_d_d(f,x,a,label) +! Check if DOUBLE PRECISION f(x) equals a for DOUBLE PRECISION x + double precision f,x,a + character*(*) label + call c_d(f(x),a,label) + end + subroutine p_c_c(f,x,a,label) +! Check if COMPLEX f(x) equals a for COMPLEX x + complex f,x,a + character*(*) label + call c_c(f(x),a,label) + end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/data.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/data.f90 new file mode 100644 index 00000000000..81954e222b5 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/data.f90 @@ -0,0 +1,72 @@ + ! Program to test data statement + program data + call sub1() + call sub2() + end + subroutine sub1() + integer i + type tmp + integer, dimension(4)::a + real :: r + end type + type tmp1 + type (tmp) t1(4) + integer b + end type + type (tmp1) tmp2(2) + ! Full array and scalar component initializer + data tmp2(2)%t1(2)%r, tmp2(1)%t1(3)%a, tmp2(1)%b/220,136,137,138,139,10/ + data tmp2(2)%t1(4)%a,tmp2(2)%t1(3)%a/241,242,4*5,233,234/ + ! implied DO + data (tmp2(1)%t1(2)%a(i),i=4,1,-1)/124,123,122,121/ + ! array section + data tmp2(1)%t1(4)%a(4:1:-1)/144,143,142,141/ + data tmp2(1)%t1(1)%a(1:4:2)/111,113/ + ! array element reference + data tmp2(2)%t1(2)%a(3), tmp2(2)%t1(2)%a(1)/223,221/ + + if (any(tmp2(1)%t1(1)%a .ne. (/111,0,113,0/))) call abort + if (tmp2(1)%t1(1)%r .ne. 0.0) call abort + if (tmp2(1)%b .ne. 10) call abort + + if (any(tmp2(1)%t1(2)%a .ne. (/121,122,123,124/))) call abort + if (tmp2(1)%t1(2)%r .ne. 0.0) call abort + if (tmp2(1)%b .ne. 10) call abort + + if (any(tmp2(1)%t1(3)%a .ne. (/136,137,138,139/))) call abort + if (tmp2(1)%t1(3)%r .ne. 0.0) call abort + if (tmp2(1)%b .ne. 10) call abort + + if (any(tmp2(1)%t1(4)%a .ne. (/141,142,143,144/))) call abort + if (tmp2(1)%t1(4)%r .ne. 0.0) call abort + if (tmp2(1)%b .ne. 10) call abort + + if (any(tmp2(2)%t1(1)%a .ne. (/0,0,0,0/))) call abort + if (tmp2(2)%t1(1)%r .ne. 0.0) call abort + if (tmp2(2)%b .ne. 0) call abort + + if (any(tmp2(2)%t1(2)%a .ne. (/221,0,223,0/))) call abort + if (tmp2(2)%t1(2)%r .ne. 220.0) call abort + if (tmp2(2)%b .ne. 0) call abort + + if (any(tmp2(2)%t1(3)%a .ne. (/5,5,233,234/))) call abort + if (tmp2(2)%t1(3)%r .ne. 0.0) call abort + if (tmp2(2)%b .ne. 0) call abort + + if (any(tmp2(2)%t1(4)%a .ne. (/241,242,5,5/))) call abort + if (tmp2(2)%t1(4)%r .ne. 0.0) call abort + if (tmp2(2)%b .ne. 0) call abort + + end + subroutine sub2() + integer a(4,4), b(10) + integer i,j,k + real r,t + data i,j,r,k,t,b(5),b(2),((a(i,j),i=1,4,1),j=4,1,-1)/1,2,3,4,5,5,2,& + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/ + if ((i.ne.1) .and. (j.ne.2).and.(k.ne.4)) call abort + if ((r.ne.3.0).and.(t.ne.5.0)) call abort + if (any(b.ne.(/0,2,0,0,5,0,0,0,0,0/))) call abort + if (any(a.ne.reshape((/13,14,15,16,9,10,11,12,5,6,7,8,1,2,3,4/),(/4,4/)))) call abort + end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/data_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/data_2.f90 new file mode 100644 index 00000000000..0aa44f6052a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/data_2.f90 @@ -0,0 +1,17 @@ +! Check more array variants of the data statement +program data_2 + implicit none + type t + integer i + end type t + integer, dimension(3) :: a + type (t), dimension(3) :: b + integer, dimension(2,2) :: c + data a(:), b%i /1, 2, 3, 4, 5, 6/ + data c(1, :), c(2, :) /7, 8, 9, 10/ + + if (any (a .ne. (/1, 2, 3/))) call abort () + if (any (b%i .ne. (/4, 5, 6/))) call abort () + if ((any (c(1, :) .ne. (/7, 8/))) & + .or. (any (c(2,:) .ne. (/9, 10/)))) call abort () +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/dep_fails.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/dep_fails.f90 new file mode 100644 index 00000000000..c8eec5c73ac --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/dep_fails.f90 @@ -0,0 +1,50 @@ +! This gives incorrect results when compiled with +! the intel and pgf90 compilers +Program Strange + + Implicit None + + Type Link + Integer, Dimension(2) :: Next + End Type Link + + Integer, Parameter :: N = 2 + Integer, dimension (2, 4) :: results + Integer :: i, j + + Type(Link), Dimension(:,:), Pointer :: Perm + Integer, Dimension(2) :: Current + + Allocate (Perm(N,N)) + +! Print*, 'Spanned by indices' + Do i = 1, N**2 + Perm(mod(i-1,N)+1, (i-1)/N+1)%Next = (/ Mod(i,N) + 1, Mod(i/N+1,N)+1/) +! Write(*,100) mod(i-1,N)+1, (i-1)/N+1, Perm(mod(i-1,N)+1, (i-1)/N+1)%Next +! Expected output: +! Spanned by indices +! 1 1---> 2 2 +! 2 1---> 1 1 +! 1 2---> 2 1 +! 2 2---> 1 2 + End Do + +! Print*, 'Spanned as a cycle' + Current = (/1,1/) + Do i = 1, n**2 + results (:, i) = Perm(Current(1), Current(2))%Next +! Write(*,100) Current, Perm(Current(1), Current(2))%Next +! Expected output: +! 1 1---> 2 2 +! 2 2---> 1 2 +! 1 2---> 2 1 +! 2 1---> 1 1 + Current = Perm(Current(1), Current(2))%Next + End Do + + if (any(results .ne. reshape ((/2,2,1,2,2,1,1,1/), (/2, 4/)))) call abort + +! 100 Format( 2I3, '--->', 2I3) + DeAllocate (Perm) + +End Program Strange diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/der_init.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/der_init.f90 new file mode 100644 index 00000000000..72531f9acf6 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/der_init.f90 @@ -0,0 +1,32 @@ +! Program to test derived type initializers and constructors +program der_init + implicit none + type t + integer :: i + integer :: j = 4 + end type + integer :: m, n + + ! Explicit initializer + type (t) :: var = t(1, 2) + ! Type (default) initializer + type (t) :: var2 + ! Initialization of arrays + type (t), dimension(2) :: var3 + type (t), dimension(2) :: var4 = (/t(7, 9), t(8, 6)/) + + if (var%i .ne. 1 .or. var%j .ne. 2) call abort + if (var2%j .ne. 4) call abort + var2 = t(6, 5) + if (var2%i .ne. 6 .or. var2%j .ne. 5) call abort + + if ((var3(1)%j .ne. 4) .or. (var3(2)%j .ne. 4)) call abort + if ((var4(1)%i .ne. 7) .or. (var4(2)%i .ne. 8) & + .or. (var4(1)%j .ne. 9) .or. (var4(2)%j .ne. 6)) call abort + + ! Non-constant constructor + n = 1 + m = 5 + var2 = t(n, n + m) + if (var2%i .ne. 1 .or. var2%j .ne. 6) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/der_io.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/der_io.f90 new file mode 100644 index 00000000000..0e9b0716654 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/der_io.f90 @@ -0,0 +1,67 @@ +! Program to test IO of derived types +program derived_io + character(100) :: buf1, buf2, buf3 + + type xyz_type + integer :: x + character(11) :: y + logical :: z + end type xyz_type + + type abcdef_type + integer :: a + logical :: b + type (xyz_type) :: c + integer :: d + real(4) :: e + character(11) :: f + end type abcdef_type + + type (xyz_type), dimension(2) :: xyz + type (abcdef_type) abcdef + + xyz(1)%x = 11111 + xyz(1)%y = "hello world" + xyz(1)%z = .true. + xyz(2)%x = 0 + xyz(2)%y = "go away" + xyz(2)%z = .false. + + abcdef%a = 0 + abcdef%b = .true. + abcdef%c%x = 111 + abcdef%c%y = "bzz booo" + abcdef%c%z = .false. + abcdef%d = 3 + abcdef%e = 4.0 + abcdef%f = "kawabanga" + + write (buf1, *), xyz(1)%x, xyz(1)%y, xyz(1)%z + ! Use function call to ensure it is only evaluated once + write (buf2, *), xyz(bar()) + if (buf1.ne.buf2) call abort + + write (buf1, *), abcdef + write (buf2, *), abcdef%a, abcdef%b, abcdef%c, abcdef%d, abcdef%e, abcdef%f + write (buf3, *), abcdef%a, abcdef%b, abcdef%c%x, abcdef%c%y, & + abcdef%c%z, abcdef%d, abcdef%e, abcdef%f + if (buf1.ne.buf2) call abort + if (buf1.ne.buf3) call abort + + call foo(xyz(1)) + + contains + + subroutine foo(t) + type (xyz_type) t + write (buf1, *), t%x, t%y, t%z + write (buf2, *), t + if (buf1.ne.buf2) call abort + end subroutine foo + + integer function bar() + integer, save :: i = 1 + bar = i + i = i + 1 + end function +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/der_point.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/der_point.f90 new file mode 100644 index 00000000000..1dcb07c2108 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/der_point.f90 @@ -0,0 +1,45 @@ +! Program to test DERIVED type with components point to the DERIVED +! type itself, and two DERIVED type with componets point to each +! other. +program nest_derived + type record + integer :: value + type(record), pointer :: rp + end type record + + type record1 + integer value + type(record2), pointer :: r1p + end type + + type record2 + integer value + type(record1), pointer :: r2p + end type + + type(record), target :: e1, e2, e3 + type(record1), target :: r1 + type(record2), target :: r2 + nullify(r1%r1p,r2%r2p,e1%rp,e2%rp,e3%rp) + + r1%r1p => r2 + r2%r2p => r1 + e1%rp => e2 + e2%rp => e3 + + r1%value = 11 + r2%value = 22 + + e1%value = 33 + e1%rp%value = 44 + e1%rp%rp%value = 55 + + if (r1%r1p%value .ne. 22) call abort + if (r2%r2p%value .ne. 11) call abort + if (e1%value .ne. 33) call abort + if (e2%value .ne. 44) call abort + if (e3%value .ne. 55) call abort + if (r1%value .ne. 11) call abort + if (r2%value .ne. 22) call abort + +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/der_type.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/der_type.f90 new file mode 100644 index 00000000000..6a2716407bf --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/der_type.f90 @@ -0,0 +1,45 @@ +! Program to test derived types +program der_type + implicit none + type t1 + integer, dimension (4, 5) :: a + integer :: s + end type + + type my_type + character(20) :: c + type (t1), dimension (4, 3) :: ca + type (t1) :: r + end type + + type init_type + integer :: i = 13 + integer :: j = 14 + end type + + type (my_type) :: var + type (init_type) :: def_init + type (init_type) :: is_init = init_type (10, 11) + integer i; + + if ((def_init%i .ne. 13) .or. (def_init%j .ne. 14)) call abort + if ((is_init%i .ne. 10) .or. (is_init%j .ne. 11)) call abort + ! Passing a component as a parameter tests getting the addr of a component + call test_call(def_init%i) + var%c = "Hello World" + if (var%c .ne. "Hello World") call abort + var%r%a(:, :) = 0 + var%ca(:, :)%s = 0 + var%r%a(1, 1) = 42 + var%r%a(4, 5) = 43 + var%ca(:, :)%s = var%r%a(:, 1:5:2) + if (var%ca(1, 1)%s .ne. 42) call abort + if (var%ca(4, 3)%s .ne. 43) call abort +contains + subroutine test_call (p) + integer p + + if (p .ne. 13) call abort + end subroutine +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/direct_io.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/direct_io.f90 new file mode 100644 index 00000000000..b8078f03d5e --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/direct_io.f90 @@ -0,0 +1,20 @@ +! demonstrates basic direct access using variables for REC +! pr14872 + OPEN(UNIT=10,ACCESS='DIRECT',RECL=128) + DO I = 1,10 + WRITE(10,REC=I,ERR=10)I + ENDDO + CLOSE(10) + OPEN(UNIT=10,ACCESS='DIRECT',RECL=128) + DO I = 1,10 + READ(10,REC=I,ERR=10)J + IF (J.NE.I) THEN +! PRINT*,' READ ',J,' EXPECTED ',I + CALL ABORT + ENDIF + ENDDO + STOP + 10 CONTINUE +! PRINT*,' ERR= RETURN FROM READ OR WRITE' + CALL ABORT + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/elemental.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/elemental.f90 new file mode 100644 index 00000000000..fcfe233df9c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/elemental.f90 @@ -0,0 +1,32 @@ +! Program to test elemental functions. +program test_elemental + implicit none + integer(kind = 4), dimension (2, 4) :: a + integer(kind = 4), dimension (2, 4) :: b + integer(kind = 8), dimension(2) :: c + + a = reshape ((/2, 3, 4, 5, 6, 7, 8, 9/), (/2, 4/)) + b = 0 + b(2, :) = e_fn (a(1, :), 1) + if (any (b .ne. reshape ((/0, 1, 0, 3, 0, 5, 0, 7/), (/2, 4/)))) call abort + a = e_fn (a(:, 4:1:-1), 1 + b) + if (any (a .ne. reshape ((/7, 7, 5, 3, 3, -1, 1, -5/), (/2, 4/)))) call abort + ! This tests intrinsic elemental conversion functions. + c = 2 * a(1, 1) + if (any (c .ne. 14)) call abort + + ! This triggered bug due to building ss chains in the wrong order. + b = 0; + a = a - e_fn (a, b) + if (any (a .ne. 0)) call abort + + ! Check expressions involving constants + a = e_fn (b + 1, 1) + if (any (a .ne. 0)) call abort +contains + +elemental integer function e_fn (p, q) + integer, intent(in) :: p, q + e_fn = p - q +end function +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/empty_format.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/empty_format.f90 new file mode 100644 index 00000000000..242bee8b467 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/empty_format.f90 @@ -0,0 +1,14 @@ +! from NIST test FM406.FOR + CHARACTER*10 A10VK + A10VK = 'XXXXXXXXXX' + WRITE(A10VK,39110) +39110 FORMAT() +! +! the empty format should fill the target of the internal +! write with blanks. +! + IF (A10VK.NE.'') THEN +! PRINT*,A10VK + CALL ABORT + ENDIF + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/emptyif.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/emptyif.f90 new file mode 100644 index 00000000000..0c19fa57108 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/emptyif.f90 @@ -0,0 +1,20 @@ +! Test empty if statements. We Used to fail this because we folded +! the if stmt before we finished building it. +program emptyif + implicit none + integer i + + i=1 + if(i .le. 0) then + else + i = 2 + endif + if (i .ne. 2) call abort() + + if (i .eq. 0) then + elseif (i .eq. 2) then + i = 3 + end if + if (i .ne. 3) call abort() +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/execute.exp b/gcc/testsuite/gfortran.fortran-torture/execute/execute.exp new file mode 100644 index 00000000000..a476ee945bf --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/execute.exp @@ -0,0 +1,59 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file was written by Rob Savoye. (rob@cygnus.com) +# Modified and maintained by Jeffrey Wheat (cassidy@cygnus.com) + +# +# These tests come from many different contributors. +# + +if $tracelevel then { + strace $tracelevel +} + +# load support procs +load_lib fortran-torture.exp + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.f]] { + # If we're only testing specific files and this isn't one of them, skip it. + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture-execute $testcase +} + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.F]] { + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture-execute $testcase +} + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.f90]] { + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture-execute $testcase +} + +foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.f95]] { + if ![runtest_file_p $runtests $testcase] then { + continue + } + fortran-torture-execute $testcase +} + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/f2_edit_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/f2_edit_1.f90 new file mode 100644 index 00000000000..cb2f5eacd33 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/f2_edit_1.f90 @@ -0,0 +1,10 @@ +! check F2.x edit descriptors +! PR 14746 + CHARACTER*15 LINE + RCON21 = 9. + RCON22 = .9 + WRITE(LINE,'(F2.0,1H,,F2.1)')RCON21,RCON22 + READ(LINE,'(F2.0,1X,F2.1)')XRCON21,XRCON22 + IF (RCON21.NE.XRCON21) CALL ABORT + IF (RCON22.NE.XRCON22) CALL ABORT + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/forall.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/forall.f90 new file mode 100644 index 00000000000..b60e67fb0d7 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/forall.f90 @@ -0,0 +1,17 @@ +! Program to test the FORALL construct +program testforall + implicit none + integer, dimension (3, 3) :: a + integer, dimension (3) :: b + integer i + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)); + + forall (i=1:3) + b(i) = sum (a(:, i)) + end forall + + if (b(1) .ne. 6) call abort + if (b(2) .ne. 15) call abort + if (b(3) .ne. 24) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/forall_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/forall_1.f90 new file mode 100644 index 00000000000..806dede70f3 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/forall_1.f90 @@ -0,0 +1,61 @@ +! Program to test FORALL construct +program forall_1 + + call actual_variable () + call negative_stride () + call forall_index () + +contains + subroutine actual_variable () + integer:: x = -1 + integer a(3,4) + j = 100 + + ! Actual variable 'x' and 'j' used as FORALL index + forall (x = 1:3, j = 1:4) + a (x,j) = j + end forall + if (any (a.ne.reshape ((/1,1,1,2,2,2,3,3,3,4,4,4/), (/3,4/)))) call abort + if ((x.ne.-1).or.(j.ne.100)) call abort + + call actual_variable_2 (x, j, a) + end subroutine + + subroutine actual_variable_2(x, j, a) + integer x,j,x1,j1 + integer a(3,4), b(3,4) + + ! Actual variable 'x' and 'j' used as FORALL index. + forall (x=3:1:-1, j=4:1:-1) + a(x,j) = j + b(x,j) = j + end forall + + if (any (a.ne.reshape ((/1,1,1,2,2,2,3,3,3,4,4,4/), (/3,4/)))) call abort + if (any (b.ne.reshape ((/1,1,1,2,2,2,3,3,3,4,4,4/), (/3,4/)))) call abort + if ((x.ne.-1).or.(j.ne.100)) call abort + end subroutine + + subroutine negative_stride () + integer a(3,4) + integer x, j + + ! FORALL with negative stride + forall (x = 3:1:-1, j = 4:1:-1) + a(x,j) = j + x + end forall + if (any (a.ne.reshape ((/2,3,4,3,4,5,4,5,6,5,6,7/), (/3,4/)))) call abort + end subroutine + + subroutine forall_index + integer a(32,32) + + ! FORALL with arbitrary number indexes + forall (i1=1:2,i2=1:2,i3=1:2,i4=1:2,i5=1:2,i6=1:2,i7=1:2,i8=1:2,i9=1:2,& + i10=1:2) + a(i1+2*i3+4*i5+8*i7+16*i9-30,i2+2*i4+4*i6+8*i8+16*i10-30) = 1 + end forall + if ((a(5,5).ne.1).or. (a(32,32).ne.1)) call abort + end subroutine + +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/forall_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/forall_2.f90 new file mode 100644 index 00000000000..92a4ff102cc --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/forall_2.f90 @@ -0,0 +1,20 @@ +!program to test nested forall construct and forall mask +program test + implicit none + integer a(4,4) + integer i, j + + do i=1,4 + do j=1,4 + a(j,i) = j-i + enddo + enddo + forall (i=2:4, a(1,i).GT.-2) + forall (j=1:4, a(j,2).GT.0) + a(j,i) = a(j,i-1) + end forall + end forall + if (any (a.ne.reshape ((/0,1,2,3,-1,0,2,3,-2,-1,0,1,-3,-2,-1,0/),& + (/4,4/)))) call abort +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/forall_3.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/forall_3.f90 new file mode 100644 index 00000000000..957178c8a65 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/forall_3.f90 @@ -0,0 +1,36 @@ +! Really test forall with temporary +program evil_forall + implicit none + type t + logical valid + integer :: s + integer, dimension(:), pointer :: p + end type + type (t), dimension (5) :: v + integer i + + allocate (v(1)%p(2)) + allocate (v(2)%p(8)) + v(3)%p => NULL() + allocate (v(4)%p(8)) + allocate (v(5)%p(2)) + + v(:)%valid = (/.true., .true., .false., .true., .true./) + v(:)%s = (/1, 8, 999, 6, 2/) + v(1)%p(:) = (/9, 10/) + v(2)%p(:) = (/1, 2, 3, 4, 5, 6, 7, 8/) + v(4)%p(:) = (/13, 14, 15, 16, 17, 18, 19, 20/) + v(5)%p(:) = (/11, 12/) + + + forall (i=1:5,v(i)%valid) + v(i)%p(1:v(i)%s) = v(6-i)%p(1:v(i)%s) + end forall + + if (any(v(1)%p(:) .ne. (/11, 10/))) call abort + if (any(v(2)%p(:) .ne. (/13, 14, 15, 16, 17, 18, 19, 20/))) call abort + if (any(v(4)%p(:) .ne. (/1, 2, 3, 4, 5, 6, 19, 20/))) call abort + if (any(v(5)%p(:) .ne. (/9, 10/))) call abort + + ! I should really free the memory I've allocated. +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/forall_4.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/forall_4.f90 new file mode 100644 index 00000000000..f2dded73587 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/forall_4.f90 @@ -0,0 +1,27 @@ +! Program to test nested forall +program forall2 + implicit none + integer a(4,4,2) + integer i, j, k, n + + a(:,:,1) = reshape((/ 1, 2, 3, 4,& + 5, 6, 7, 8,& + 9,10,11,12,& + 13,14,15,16/), (/4,4/)) + a(:,:,2) = a(:,:,1) + 16 + n=4 + k=1 + ! Mirror half the matrix + forall (i=k:n) + forall (j=1:5-i) + a(i,j,:) = a(j,i,:) + end forall + end forall + + if (any (a(:,:,1) & + .ne. reshape((/ 1, 5, 9,13,& + 2, 6,10, 8,& + 3, 7,11,12,& + 4,14,15,16/),(/4,4/)))) call abort + if (any (a(:,:,2) .ne. a(:,:,1) + 16)) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/forall_5.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/forall_5.f90 new file mode 100644 index 00000000000..0595adf0c89 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/forall_5.f90 @@ -0,0 +1,28 @@ +! Program to test FORALL with pointer assignment inside it. +program forall_5 + type element + integer, pointer, dimension(:)::p + end type + + type (element) q(5) + integer, target, dimension(25)::t + + n = 5 + do i = 1,5 + q(i)%p => t((i-1)*n + 1:i*n) + enddo + + forall (i = 2:5) + q(i)%p => q(i-1)%p + end forall + + do i = 1, 25 + t(i) = i + enddo + + if (any(q(1)%p .ne. (/1,2,3,4,5/))) call abort + if (any(q(2)%p .ne. (/1,2,3,4,5/))) call abort + if (any(q(3)%p .ne. (/6,7,8,9,10/))) call abort + if (any(q(4)%p .ne. (/11,12,13,14,15/))) call abort + if (any(q(5)%p .ne. (/16,17,18,19,20/))) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/forall_6.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/forall_6.f90 new file mode 100644 index 00000000000..b277814fb3f --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/forall_6.f90 @@ -0,0 +1,25 @@ +! Program to test FORALL with scalar pointer assignment inside it. +program forall_6 + type element + real, pointer :: p + end type + + type (element) q(5) + real, target, dimension(5) :: t + integer i; + + t = (/1.0, 2.0, 3.0, 4.0, 5.0/) + + do i = 1,5 + q(i)%p => t(i) + end do + + forall (i = 1:5) + q(i)%p => q(6 - i)%p + end forall + + + do i = 1,5 + if (q(i)%p .ne. t(6 - i)) call abort + end do +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/function_module_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/function_module_1.f90 new file mode 100644 index 00000000000..e57ff161d29 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/function_module_1.f90 @@ -0,0 +1,36 @@ +! This can fail because BB is not resolved correctly. +module M1 + +INTEGER p + +CONTAINS +subroutine AA () + implicit NONE + p = BB () + CONTAINS + subroutine AA_1 () + implicit NONE + integer :: i + i = BB () + end subroutine + + function BB() + integer :: BB + BB = 1 + end function +end subroutine + +function BB() + implicit NONE + integer :: BB + BB = 2 +end function +end module + +program P1 + USE M1 + implicit none + p = 0 + call AA () + if (p /= 1) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/hollerith.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/hollerith.f90 new file mode 100644 index 00000000000..aa7b17def75 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/hollerith.f90 @@ -0,0 +1,9 @@ +! PR 14038- 'H' in hollerith causes mangling of string +program hollerith + IMPLICIT NONE + CHARACTER*4 LINE +100 FORMAT (4H12H4) + WRITE(LINE,100) + IF (LINE .NE. '12H4') call abort () +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/initializer.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/initializer.f90 new file mode 100644 index 00000000000..55cc185f370 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/initializer.f90 @@ -0,0 +1,26 @@ +! Program to test static variable initialization +! returns the parameter from the previous invocation, or 42 on the first call. +function test (parm) + implicit none + integer test, parm + integer :: val = 42 + + test = val + val = parm +end function + +program intializer + implicit none + integer test + character(11) :: c = "Hello World" + character(15) :: d = "Teststring" + integer, dimension(3) :: a = 1 + + if (any (a .ne. 1)) call abort + if (test(11) .ne. 42) call abort + ! The second call should return + if (test(0) .ne. 11) call abort + + if (c .ne. "Hello World") call abort + if (d .ne. "Teststring") call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/inquire_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_1.f90 new file mode 100644 index 00000000000..492f74476d3 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_1.f90 @@ -0,0 +1,8 @@ +! PR 14831 + CHARACTER*4 BLANK + CHARACTER*10 ACCESS + OPEN(UNIT=9,ACCESS='SEQUENTIAL') + INQUIRE(UNIT=9,ACCESS=ACCESS,BLANK=BLANK) + IF(BLANK.NE.'NULL') CALL ABORT + IF(ACCESS.NE.'SEQUENTIAL') CALL ABORT + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/inquire_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_2.f90 new file mode 100644 index 00000000000..bc7ea74c39a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_2.f90 @@ -0,0 +1,6 @@ +! PR 14837 + INTEGER UNIT + OPEN(FILE='CSEQ', UNIT=23) + INQUIRE(FILE='CSEQ',NUMBER=UNIT) + IF (UNIT.NE.23) CALL ABORT + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/inquire_3.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_3.f90 new file mode 100644 index 00000000000..8967dcfbc0f --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_3.f90 @@ -0,0 +1,13 @@ +! pr14836 + OPEN(UNIT=9, ACCESS='DIRECT', RECL=80, FORM='UNFORMATTED') + INQUIRE(UNIT=9,NEXTREC=NREC) + WRITE(UNIT=9,REC=5) 1 + INQUIRE(UNIT=9,NEXTREC=NREC) +! PRINT*,NREC + IF (NREC.NE.6) CALL ABORT + READ(UNIT=9,REC=1) MVI + INQUIRE(UNIT=9,NEXTREC=NREC) + IF (NREC.NE.2) CALL ABORT +! PRINT*,NREC + END + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/inquire_4.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_4.f90 new file mode 100644 index 00000000000..5b94ad232bc --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/inquire_4.f90 @@ -0,0 +1,20 @@ +! pr 14904 +! inquire lastrec not correct when two records written +! with one write statement + OPEN(UNIT=10,ACCESS='DIRECT',FORM='FORMATTED',RECL=120) + 100 FORMAT(I4) + WRITE(UNIT=10,REC=1,FMT=100)1 + INQUIRE(UNIT=10,NEXTREC=J) + IF (J.NE.2) THEN +! PRINT*,'NEXTREC RETURNED ',J,' EXPECTED 2' + CALL ABORT + ENDIF + 200 FORMAT(I4,/,I4) + WRITE(UNIT=10,REC=2,FMT=200)2,3 + INQUIRE(UNIT=10,NEXTREC=J) + IF (J.NE.4) THEN +! PRINT*,'NEXTREC RETURNED ',J,' EXPECTED 4' + CALL ABORT + ENDIF + END + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/integer_select.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/integer_select.f90 new file mode 100644 index 00000000000..148cd394e68 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/integer_select.f90 @@ -0,0 +1,71 @@ +PROGRAM Test_INTEGER_select + +! Every wrong branch leads to destruction. + + INTEGER, PARAMETER :: maxI = HUGE (maxI) + INTEGER, PARAMETER :: minI = -1 * maxI + INTEGER :: I = 0 + + SELECT CASE (I) + CASE (:-1) + CALL abort + CASE (1:) + CALL abort + CASE DEFAULT + CONTINUE + END SELECT + + SELECT CASE (I) + CASE (3,2,1) + CALL abort + CASE (0) + CONTINUE + CASE DEFAULT + call abort + END SELECT + +! Not aborted by here, so it worked +! See about weird corner cases + + I = maxI + + SELECT CASE (I) + CASE (:-1) + CALL abort + CASE (1:) + CONTINUE + CASE DEFAULT + CALL abort + END SELECT + + SELECT CASE (I) + CASE (3,2,1,:0) + CALL abort + CASE (maxI) + CONTINUE + CASE DEFAULT + call abort + END SELECT + + I = minI + + SELECT CASE (I) + CASE (:-1) + CONTINUE + CASE (1:) + CALL abort + CASE DEFAULT + CALL abort + END SELECT + + SELECT CASE (I) + CASE (3:,2,1,0) + CALL abort + CASE (minI) + CONTINUE + CASE DEFAULT + call abort + END SELECT + +END + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/integer_select_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/integer_select_1.f90 new file mode 100644 index 00000000000..cd9bb00a98c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/integer_select_1.f90 @@ -0,0 +1,31 @@ +INTEGER :: I = 1 +SELECT CASE (I) + CASE (-3:-5) ! Can never be matched + CALL abort + CASE (1) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT + +I = -3 +SELECT CASE (I) + CASE (-3:-5) ! Can never be matched + CALL abort + CASE (1) + CONTINUE + CASE DEFAULT + CONTINUE +END SELECT + +I = -5 +SELECT CASE (I) + CASE (-3:-5) ! Can never be matched + CALL abort + CASE (-5) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT +END + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/internal_write.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/internal_write.f90 new file mode 100644 index 00000000000..1e492977b06 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/internal_write.f90 @@ -0,0 +1,11 @@ +! PR 14901 +! Internal writes were appending CR after the last char +! written by the format statement. + CHARACTER*10 A + WRITE(A,'(3HGCC)') + IF (A.NE.'GCC ') THEN +! PRINT*,'A was not filled correctly by internal write' +! PRINT*,' A = ',A + CALL ABORT + ENDIF + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_abs.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_abs.f90 new file mode 100644 index 00000000000..9e44657bad1 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_abs.f90 @@ -0,0 +1,33 @@ +! Program to test the ABS intrinsic +program intrinsic_abs + implicit none + integer i + real(kind=4) r + real(kind=8) q + complex z + + i = 42 + i = abs(i) + if (i .ne. 42) call abort + i = -43 + i = abs(i) + if (i .ne. 43) call abort + + r = 42.0 + r = abs(r) + if (r .ne. 42.0) call abort + r = -43.0 + r = abs(r) + if (r .ne. 43.0) call abort + + q = 42.0_8 + q = abs(q) + if (q .ne. 42.0_8) call abort + q = -43.0_8 + q = abs(q) + if (q .ne. 43.0_8) call abort + + z = (3, 4) + r = abs(z) + if (r .ne. 5) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_achar.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_achar.f90 new file mode 100644 index 00000000000..fba0a08974f --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_achar.f90 @@ -0,0 +1,9 @@ +! Program to test the ACHAR and IACHAR intrinsics +program intrinsic_achar + integer i + + i = 32 + if (achar(i) .ne. " ") call abort + i = iachar("A") + if ((i .ne. 65) .or. char(i) .ne. "A") call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_aint_anint.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_aint_anint.f90 new file mode 100644 index 00000000000..16e816c6bd0 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_aint_anint.f90 @@ -0,0 +1,55 @@ +! Program to test AINT and ANINT intrinsics + +subroutine real4test (op, res1, res2) + implicit none + real(kind=4) :: op + real(kind=4) :: res1, res2 + + if (diff(aint(op), res1) .or. & + diff(anint(op), res2)) call abort +contains +function diff(a, b) + real(kind=4) :: a, b + logical diff + + diff = (abs (a - b) .gt. abs(a * 1e-6)) +end function +end subroutine + +subroutine real8test (op, res1, res2) + implicit none + real(kind=8) :: op + real(kind=8) :: res1, res2 + + if (diff(aint(op), res1) .or. & + diff(anint(op), res2)) call abort +contains +function diff(a, b) + real(kind=8) :: a, b + logical diff + + diff = (abs(a - b) .gt. abs(a * 1e-6)) +end function +end subroutine + +program aint_aninttest + implicit none + + call real4test (3.456, 3.0, 3.0) + call real4test (-2.798, -2.0, -3.0) + call real4test (3.678, 3.0, 4.0) + call real4test (-1.375, -1.0, -1.0) + call real4test (-0.5, 0.0,-1.0) + call real4test (0.4, 0.0,0.0) + + call real8test (3.456_8, 3.0_8, 3.0_8) + call real8test (-2.798_8, -2.0_8, -3.0_8) + call real8test (3.678_8, 3.0_8, 4.0_8) + call real8test (-1.375_8, -1.0_8, -1.0_8) + call real8test (-0.5_8, 0.0_8,-1.0_8) + call real8test (0.4_8, 0.0_8,0.0_8) + + ! Check large numbers + call real4test (2e34, 2e34, 2e34) + call real4test (-2e34, -2e34, -2e34) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_anyall.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_anyall.f90 new file mode 100644 index 00000000000..d1b99dacb5d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_anyall.f90 @@ -0,0 +1,26 @@ +! Program to test the ANY and ALL intrinsics +program anyall + implicit none + logical, dimension(3, 3) :: a + logical, dimension(3) :: b + + a = .false. + if (any(a)) call abort + a(1, 1) = .true. + a(2, 3) = .true. + if (.not. any(a)) call abort + b = any(a, 1) + if (.not. b(1)) call abort + if (b(2)) call abort + if (.not. b(3)) call abort + + a = .true. + if (.not. all(a)) call abort + a(1, 1) = .false. + a(2, 3) = .false. + if (all(a)) call abort + b = all(a, 1) + if (b(1)) call abort + if (.not. b(2)) call abort + if (b(3)) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated.f90 new file mode 100644 index 00000000000..24d647ef15a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated.f90 @@ -0,0 +1,137 @@ +! Program to test the ASSOCIATED intrinsic. +program intrinsic_associated + call pointer_to_section () + call associate_1 () + call pointer_to_derived_1 () + call associated_2 () +end + +subroutine pointer_to_section () + integer, dimension(100, 100), target :: xy + integer, dimension(:, :), pointer :: window + integer i, j, k, m, n + data xy /10000*0/ + logical t + + window => xy(10:50, 30:60) + window = 10 + window (1, 1) = 0101 + window (41, 31) = 4161 + window (41, 1) = 4101 + window (1, 31) = 0161 + + t = associated (window, xy(10:50, 30:60)) + if (.not.t) call abort () + if (window(1, 1) .ne. xy(10, 30)) call abort () + if (window(41, 31) .ne. xy(50, 60)) call abort () + if (window(1, 31) .ne. xy(10, 60)) call abort () + if (window(41, 1) .ne. xy(50, 30)) call abort () + if (xy(9, 29) .ne. 0) call abort () + if (xy(51,29 ) .ne. 0) call abort () + if (xy(9, 60) .ne. 0) call abort () + if (xy(51, 60) .ne. 0) call abort () + if (xy(11, 31) .ne. 10) call abort () + if (xy(49, 59) .ne. 10) call abort () + if (xy(11, 59) .ne. 10) call abort () + if (xy(49, 31) .ne. 10) call abort () +end + +subroutine sub1 (a, ap) + integer, pointer :: ap(:, :) + integer, target :: a(10, 10) + + ap => a +end + +subroutine nullify_pp (a) + integer, pointer :: a(:, :) + + if (.not. associated (a)) call abort () + nullify (a) +end + +subroutine associate_1 () + integer, pointer :: a(:, :), b(:, :) + interface + subroutine nullify_pp (a) + integer, pointer :: a(:, :) + end subroutine nullify_pp + end interface + + allocate (a(80, 80)) + b => a + if (.not. associated(a)) call abort () + if (.not. associated(b)) call abort () + call nullify_pp (a) + if (associated (a)) call abort () + if (.not. associated (b)) call abort () +end + +subroutine pointer_to_derived_1 () + type record + integer :: value + type(record), pointer :: rp + end type record + + type record1 + integer value + type(record2), pointer :: r1p + end type + + type record2 + integer value + type(record1), pointer :: r2p + end type + + type(record), target :: e1, e2, e3 + type(record1), target :: r1 + type(record2), target :: r2 + + nullify (r1%r1p, r2%r2p, e1%rp, e2%rp, e3%rp) + if (associated (r1%r1p)) call abort () + if (associated (r2%r2p)) call abort () + if (associated (e2%rp)) call abort () + if (associated (e1%rp)) call abort () + if (associated (e3%rp)) call abort () + r1%r1p => r2 + r2%r2p => r1 + r1%value = 11 + r2%value = 22 + e1%rp => e2 + e2%rp => e3 + e1%value = 33 + e1%rp%value = 44 + e1%rp%rp%value = 55 + if (.not. associated (r1%r1p)) call abort () + if (.not. associated (r2%r2p)) call abort () + if (.not. associated (e1%rp)) call abort () + if (.not. associated (e2%rp)) call abort () + if (associated (e3%rp)) call abort () + if (r1%r1p%value .ne. 22) call abort () + if (r2%r2p%value .ne. 11) call abort () + if (e1%value .ne. 33) call abort () + if (e2%value .ne. 44) call abort () + if (e3%value .ne. 55) call abort () + if (r1%value .ne. 11) call abort () + if (r2%value .ne. 22) call abort () + +end + +subroutine associated_2 () + integer, pointer :: xp(:, :) + integer, target :: x(10, 10) + integer, target :: y(100, 100) + interface + subroutine sub1 (a, ap) + integer, pointer :: ap(:, :) + integer, target :: a(10, 1) + end + endinterface + + xp => y + if (.not. associated (xp)) call abort () + call sub1 (x, xp) + if (associated (xp, y)) call abort () + if (.not. associated (xp, x)) call abort () +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated_2.f90 new file mode 100644 index 00000000000..5f353b2f85b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_associated_2.f90 @@ -0,0 +1,36 @@ +! Program to test the ASSOCIATED intrinsic with cross-kinds +program intrinsic_associated_2 + logical*4 :: t4, L44, L48 + logical*8 :: t8, L84, L88 + real*4, pointer :: a4p(:, :) + real*8, pointer :: a8p(:, :) + real*4, target :: a4(10, 10) + real*8, target :: a8(10, 10) + + t4 = .true. + t8 = .true. + t8 = t4 + a4p => a4 + a8p => a8 + L44 = t4 .and. associated (a4p, a4) + L84 = t8 .and. associated (a4p, a4) + L48 = t4 .and. associated (a8p, a8) + L88 = t8 .and. associated (a8p, a8) + if (.not. (L44 .and. L84 .and. L48 .and. L88)) call abort () + + nullify (a4p, a8p) + L44 = t4 .and. associated (a4p, a4) + L84 = t8 .and. associated (a4p, a4) + L48 = t4 .and. associated (a8p, a8) + L88 = t8 .and. associated (a8p, a8) + if (L44 .and. L84 .and. L48 .and. L88) call abort () + + a4p => a4(1:10:2, 1:10:2) + a8p => a8(1:4, 1:4) + L44 = t4 .and. associated (a4p, a4(1:10:2, 1:10:2)) + L84 = t8 .and. associated (a4p, a4(1:10:2, 1:10:2)) + L48 = t4 .and. associated (a8p, a8(1:4, 1:4)) + L88 = t8 .and. associated (a8p, a8(1:4, 1:4)) + if (.not. (L44 .and. L84 .and. L48 .and. L88)) call abort () +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_bitops.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_bitops.f90 new file mode 100644 index 00000000000..95ff44c999e --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_bitops.f90 @@ -0,0 +1,29 @@ +! Program to test intrinsic bitops +program intrinsic_bitops + implicit none + integer(kind=4) :: i, j, k, o, t + integer(kind=8) :: a, b, c + + o = 0 + i = 2 + j = 3 + k = 12 + + if (.not. btest (i, o+1)) call abort + if (btest (i, o+2)) call abort + if (iand (i, j) .ne. 2) call abort + if (ibclr (j, o+1) .ne. 1) call abort + if (ibclr (j, o+2) .ne. 3) call abort + if (ibits (k, o+1, o+2) .ne. 2) call abort + if (ibset (j, o+1) .ne. 3) call abort + if (ibset (j, o+2) .ne. 7) call abort + if (ieor (i, j) .ne. 1) call abort + if (ior (i, j) .ne. 3) call abort + if (ishft (k, o+2) .ne. 48) call abort + if (ishft (k, o-3) .ne. 1) call abort + if (ishft (k, o) .ne. 12) call abort + if (ishftc (k, o+30) .ne. 3) call abort + if (ishftc (k, o-30) .ne. 48) call abort + if (ishftc (k, o+1, o+3) .ne. 9) call abort + if (not (i) .ne. -3) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_count.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_count.f90 new file mode 100644 index 00000000000..a2de59fb985 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_count.f90 @@ -0,0 +1,21 @@ +! Program to test the COUNT intrinsic +program intrinsic_count + implicit none + logical(kind=4), dimension (3, 5) :: a + integer(kind=4), dimension (5) :: b + integer i + + a = .false. + if (count(a) .ne. 0) call abort + a = .true. + if (count(a) .ne. 15) call abort + a(1, 1) = .false. + a(2, 2) = .false. + a(2, 5) = .false. + if (count(a) .ne. 12) call abort + + b(1:3) = count(a, 2); + if (b(1) .ne. 4) call abort + if (b(2) .ne. 3) call abort + if (b(3) .ne. 5) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_cshift.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_cshift.f90 new file mode 100644 index 00000000000..f188cd8f4bb --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_cshift.f90 @@ -0,0 +1,43 @@ +! Program to test the cshift intrinsic +program intrinsic_cshift + integer, dimension(3, 3) :: a + integer, dimension(3, 3, 2) :: b + + ! Scalar shift + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = cshift (a, 1, 1) + if (any (a .ne. reshape ((/2, 3, 1, 5, 6, 4, 8, 9, 7/), (/3, 3/)))) & + call abort + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = cshift (a, -2, dim = 2) + if (any (a .ne. reshape ((/4, 5, 6, 7, 8, 9, 1, 2, 3/), (/3, 3/)))) & + call abort + + ! Array shift + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = cshift (a, (/1, 0, -1/)) + if (any (a .ne. reshape ((/2, 3, 1, 4, 5, 6, 9, 7, 8/), (/3, 3/)))) & + call abort + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = cshift (a, (/2, -2, 0/), dim = 2) + if (any (a .ne. reshape ((/7, 5, 3, 1, 8, 6, 4, 2, 9/), (/3, 3/)))) & + call abort + + ! Test arrays > rank 2 + b = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17,& + 18, 19/), (/3, 3, 2/)) + b = cshift (b, 1) + if (any (b .ne. reshape ((/2, 3, 1, 5, 6, 4, 8, 9, 7, 12, 13, 11, 15,& + 16, 14, 18, 19, 17/), (/3, 3, 2/)))) & + call abort + + b = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17,& + 18, 19/), (/3, 3, 2/)) + b = cshift (b, reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)), 3) + if (any (b .ne. reshape ((/11, 2, 13, 4, 15, 6, 17, 8, 19, 1, 12, 3,& + 14, 5, 16, 7, 18, 9/), (/3, 3, 2/)))) & + call abort + +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dim.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dim.f90 new file mode 100644 index 00000000000..4753de3606d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dim.f90 @@ -0,0 +1,20 @@ +! Program to test the DIM intrinsic +program intrinsic_dim + implicit none + integer i, j + real(kind=4) :: r, s + real(kind=8) :: p, q + + i = 1 + j = 4 + if (dim (i, j) .ne. 0) call abort + if (dim (j, i) .ne. 3) call abort + r = 1.0 + s = 4.0 + if (dim (r, s) .ne. 0.0) call abort + if (dim (s, r) .ne. 3.0) call abort + p = 1.0 + q = 4.0 + if (dim (p, q) .ne. 0.0) call abort + if (dim (q, p) .ne. 3.0) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dotprod.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dotprod.f90 new file mode 100644 index 00000000000..5444dd6dac1 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dotprod.f90 @@ -0,0 +1,25 @@ +! Program to test the DOT_PRODUCT intrinsic +program testforall + implicit none + integer, dimension (3) :: a + integer, dimension (3) :: b + real, dimension(3) :: c + real r + complex, dimension (2) :: z1 + complex, dimension (2) :: z2 + complex z + + a = (/1, 2, 3/); + b = (/4, 5, 6/); + c = (/4, 5, 6/); + + if (dot_product(a, b) .ne. 32) call abort + + r = dot_product(a, c) + if (abs(r - 32.0) .gt. 0.001) call abort + + z1 = (/(1.0, 2.0), (2.0, 3.0)/) + z2 = (/(3.0, 4.0), (4.0, 5.0)/) + z = dot_product (z1, z2) + if (abs (z - (34.0, -4.0)) .gt. 0.001) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dprod.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dprod.f90 new file mode 100644 index 00000000000..feb3367934b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dprod.f90 @@ -0,0 +1,13 @@ +! Program to test DPROD intrinsic +program intrinsic_dprod + implicit none + real r, s, t + double precision dp + + ! 6d60 doesn't fit in a 4-byte real + r = 2e30 + s = 4e30 + dp = dprod (r, s) + if ((dp .gt. 8.001d60) .or. (dp .lt. 7.999d60)) call abort +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dummy.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dummy.f90 new file mode 100644 index 00000000000..2e8a3401492 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_dummy.f90 @@ -0,0 +1,23 @@ +! Program to test passing intrinsic functions as actual arguments for +! dummy procedures. +subroutine test (proc) + implicit none + real proc + real a, b, c + + a = 1.0 + b = sin (a) + c = proc (a) + + if (abs (b - c) .gt. 0.001) call abort + +end subroutine + +program dummy + implicit none + external test + intrinsic sin + + call test (sin) +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_eoshift.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_eoshift.f90 new file mode 100644 index 00000000000..12edc630e50 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_eoshift.f90 @@ -0,0 +1,60 @@ +! Program to test the eoshift intrinsic +program intrinsic_eoshift + integer, dimension(3, 3) :: a + integer, dimension(3, 3, 2) :: b + + ! Scalar shift and scalar bound. + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, 1, 99, 1) + if (any (a .ne. reshape ((/2, 3, 99, 5, 6, 99, 8, 9, 99/), (/3, 3/)))) & + call abort + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, -2, dim = 2) + if (any (a .ne. reshape ((/0, 0, 0, 0, 0, 0, 1, 2, 3/), (/3, 3/)))) & + call abort + + ! Array shift and scalar bound. + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, (/1, 0, -1/), 99, 1) + if (any (a .ne. reshape ((/2, 3, 99, 4, 5, 6, 99, 7, 8/), (/3, 3/)))) & + call abort + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, (/2, -2, 0/), dim = 2) + if (any (a .ne. reshape ((/7, 0, 3, 0, 0, 6, 0, 2, 9/), (/3, 3/)))) & + call abort + + ! Scalar shift and array bound. + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, 1, (/99, -1, 42/), 1) + if (any (a .ne. reshape ((/2, 3, 99, 5, 6, -1, 8, 9, 42/), (/3, 3/)))) & + call abort + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, -2, (/99, -1, 42/), 2) + if (any (a .ne. reshape ((/99, -1, 42, 99, -1, 42, 1, 2, 3/), (/3, 3/)))) & + call abort + + ! Array shift and array bound. + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, (/1, 0, -1/), (/99, -1, 42/), 1) + if (any (a .ne. reshape ((/2, 3, 99, 4, 5, 6, 42, 7, 8/), (/3, 3/)))) & + call abort + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = eoshift (a, (/2, -2, 0/), (/99, -1, 42/), 2) + if (any (a .ne. reshape ((/7, -1, 3, 99, -1, 6, 99, 2, 9/), (/3, 3/)))) & + call abort + + ! Test arrays > rank 2 + b(:, :, 1) = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + b(:, :, 2) = 10 + reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + b = eoshift (b, 1, 99, 1) + if (any (b(:, :, 1) .ne. reshape ((/2, 3, 99, 5, 6, 99, 8, 9, 99/), (/3, 3/)))) & + call abort + if (any (b(:, :, 2) .ne. reshape ((/12, 13, 99, 15, 16, 99, 18, 19, 99/), (/3, 3/)))) & + call abort + + ! TODO: Test array sections +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_fraction_exponent.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_fraction_exponent.f90 new file mode 100644 index 00000000000..a22d0b9f50a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_fraction_exponent.f90 @@ -0,0 +1,84 @@ +!Program to test EXPONENT and FRACTION intrinsic function. + +program test_exponent_fraction + real x + integer*4 i + real*8 y + integer*8 j + equivalence (x, i), (y, j) + + x = 3. + call test_4(x) + + x = 0. + call test_4(x) + + i = o'00000000001' + call test_4(x) + + i = o'00010000000' + call test_4(x) + + i = o'17700000000' + call test_4(x) + + i = o'00004000001' + call test_4(x) + + i = o'17737777777' + call test_4(x) + + i = o'10000000000' + call test_4(x) + + i = o'0000010000' + call test_4(x) + + y = 0.5 + call test_8(y) + + y = 0. + call test_8(y) + + j = o'00000000001' + call test_8(y) + + y = 0.2938735877D-38 + call test_8(y) + + y = -1.469369D-39 + call test_8(y) + + y = z'7fe00000' + call test_8(y) + + y = -5.739719D+42 + call test_8(y) +end + +subroutine test_4(x) +real*4 x,y +integer z +y = fraction (x) +z = exponent(x) +if (z .gt. 0) then + y = (y * 2.) * (2. ** (z - 1)) +else + y = (y / 2.) * (2. ** (z + 1)) +end if +if (abs (x - y) .gt. abs(x * 1e-6)) call abort() +end + +subroutine test_8(x) +real*8 x, y +integer z +y = fraction (x) +z = exponent(x) +if (z .gt. 0) then + y = (y * 2._8) * (2._8 ** (z - 1)) +else + y = (y / 2._8) * (2._8 ** (z + 1)) +end if +if (abs (x - y) .gt. abs(x * 1e-6)) call abort() +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_index.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_index.f90 new file mode 100644 index 00000000000..9b181775f9c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_index.f90 @@ -0,0 +1,15 @@ +! Program to test the INDEX intrinsic +program test + character(len=10) a + integer w + if (index("FORTRAN", "R") .ne. 3) call abort + if (index("FORTRAN", "R", .TRUE.) .ne. 5) call abort + if (w ("FORTRAN") .ne. 3) call abort +end + +function w(str) + character(len=8) str + integer w + w = index(str, "R") +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_integer.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_integer.f90 new file mode 100644 index 00000000000..43578ed54a7 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_integer.f90 @@ -0,0 +1,18 @@ +! Program to test the real->integer conversion routines. +program intrinsic_integer + implicit none + + call test (0.0, (/0, 0, 0, 0/)) + call test (0.3, (/0, 1, 0, 0/)) + call test (0.7, (/0, 1, 0, 1/)) + call test (-0.3, (/-1, 0, 0, 0/)) + call test (-0.7, (/-1, 0, 0, -1/)) +contains +subroutine test(val, res) + real :: val + integer, dimension(4) :: res + + if ((floor(val) .ne. res(1)) .or. (ceiling(val) .ne. res(2)) & + .or. (int(val) .ne. res(3)) .or. (nint(val) .ne. res(4))) call abort +end subroutine +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_len.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_len.f90 new file mode 100644 index 00000000000..6721738608f --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_len.f90 @@ -0,0 +1,22 @@ +! Program to test the LEN intrinsic +program test + character(len=10) a + character(len=8) w + type person + character(len=10) name + integer age + end type person + type(person) Tom + integer n + a = w (n) + + if ((a .ne. "01234567") .or. (n .ne. 8)) call abort + if (len(Tom%name) .ne. 10) call abort +end + +function w(i) + character(len=8) w + integer i + w = "01234567" + i = len(w) +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_matmul.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_matmul.f90 new file mode 100644 index 00000000000..4b195d267bd --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_matmul.f90 @@ -0,0 +1,24 @@ +! Program to test the MATMUL intrinsic +program intrinsic_matmul + implicit none + integer, dimension(2, 3) :: a + integer, dimension(3, 2) :: b + integer, dimension(2) :: x + integer, dimension(3) :: y + integer, dimension(2, 2) :: r + integer, dimension(3) :: v + + a = reshape((/1, 2, 2, 3, 3, 4/), (/2, 3/)) + b = reshape((/1, 2, 3, 3, 4, 5/), (/3, 2/)) + x = (/1, 2/) + y = (/1, 2, 3/) + + r = matmul(a, b) + if (any(r .ne. reshape((/14, 20, 26, 38/), (/2, 2/)))) call abort + + v = matmul(x, a) + if (any(v .ne. (/5, 8, 11/))) call abort + + v(1:2) = matmul(a, y) + if (any(v(1:2) .ne. (/14, 20/))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_merge.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_merge.f90 new file mode 100644 index 00000000000..b4fc18f4dd6 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_merge.f90 @@ -0,0 +1,15 @@ +! Program to test the MERGE intrinsic +program intrinsic_merge + integer, dimension(3) :: a, b + integer i + + a = (/-1, 2, 3/) + + i = 5 + if (merge (-1, 1, i .gt. 3) .ne. -1) call abort + i = 1 + if (merge (-1, 1, i .ge. 3) .ne. 1) call abort + + b = merge(a, 0, a .ge. 0) + if (any (b .ne. (/0, 2, 3/))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_minmax.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_minmax.f90 new file mode 100644 index 00000000000..02feaad1523 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_minmax.f90 @@ -0,0 +1,37 @@ +! Program to test min and max intrinsics +program intrinsic_minmax + implicit none + integer i, j, k, m + real r, s, t, u + + i = 1 + j = -2 + k = 3 + m = 4 + if (min (i, k) .ne. 1) call abort + if (min (i, j, k, m) .ne. -2) call abort + if (max (i, k) .ne. 3) call abort + if (max (i, j, k, m) .ne. 4) call abort + if (max (i+1, j) .ne. 2) call abort + + r = 1 + s = -2 + t = 3 + u = 4 + if (min (r, t) .ne. 1) call abort + if (min (r, s, t, u) .ne. -2) call abort + if (max (r, t) .ne. 3) call abort + if (max (r, s, t, u) .ne. 4) call abort + + if (max (4d0, r) .ne. 4d0) call abort + if (amax0 (i, j) .ne. 1.0) call abort + if (min1 (r, s) .ne. -2) call abort + + ! Test simplify. + if (min (1, -2, 3, 4) .ne. -2) call abort + if (max (1, -2, 3, 4) .ne. 4) call abort + if (amax0 (1, -2) .ne. 1.0) call abort + if (min1 (1., -2.) .ne. -2) call abort + +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc.f90 new file mode 100644 index 00000000000..f64242af9e8 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc.f90 @@ -0,0 +1,52 @@ +! Program to test the MINLOC and MAXLOC intrinsics +program testmmloc + implicit none + integer, dimension (3, 3) :: a + integer, dimension (3) :: b + logical, dimension (3, 3) :: m + integer i + + a = reshape ((/1, 2, 3, 5, 4, 6, 9, 8, 7/), (/3, 3/)); + + b = minloc (a, 1) + if (b(1) .ne. 1) call abort + if (b(2) .ne. 2) call abort + if (b(3) .ne. 3) call abort + + m = .true. + m(1, 1) = .false. + m(1, 2) = .false. + b = minloc (a, 1, m) + if (b(1) .ne. 2) call abort + if (b(2) .ne. 2) call abort + if (b(3) .ne. 3) call abort + + b(1:2) = minloc(a) + if (b(1) .ne. 1) call abort + if (b(2) .ne. 1) call abort + + b(1:2) = minloc(a, mask=m) + if (b(1) .ne. 2) call abort + if (b(2) .ne. 1) call abort + + b = maxloc (a, 1) + if (b(1) .ne. 3) call abort + if (b(2) .ne. 3) call abort + if (b(3) .ne. 1) call abort + + m = .true. + m(1, 2) = .false. + m(1, 3) = .false. + b = maxloc (a, 1, m) + if (b(1) .ne. 3) call abort + if (b(2) .ne. 3) call abort + if (b(3) .ne. 2) call abort + + b(1:2) = maxloc(a) + if (b(1) .ne. 1) call abort + if (b(2) .ne. 3) call abort + + b(1:2) = maxloc(a, mask=m) + if (b(1) .ne. 2) call abort + if (b(2) .ne. 3) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_2.f90 new file mode 100644 index 00000000000..5f0b5b5da1d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_2.f90 @@ -0,0 +1,22 @@ +program intrinsic_mmloc_2 + real a(-1:1), b(2:3), c(1:2) + integer, dimension(1):: i + real (kind = 8), dimension(-1:1) :: vc + + a = 0 + b = 0 + c = 0 + a(-1) = 1 + b(2) = 1 + c(1) = 1 + + if (maxloc (a, 1) .ne. 1) call abort() + if (maxloc (b, 1) .ne. 1) call abort() + if (maxloc (c, 1) .ne. 1) call abort() + + + ! We were giving MINLOC and MAXLOC the wrong return type + vc = (/4.0d0, 2.50d1, 1.0d1/) + i = minloc (vc) + if (i(1) .ne. 1) call abort() +END PROGRAM diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_3.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_3.f90 new file mode 100644 index 00000000000..2e18a29bc16 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_3.f90 @@ -0,0 +1,12 @@ +! Check we do the right thing with extreme values. +! From PR12704 +program intrinsic_mmloc_3 + integer, dimension(2) :: d + integer, dimension(2,2) :: a + + d = -huge (d) + if (maxloc (d, 1) .ne. 1) call abort() + a = huge (a) + d = minloc (a) + if (any (d .ne. 1)) call abort() +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_4.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_4.f90 new file mode 100644 index 00000000000..2a53fb0124a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmloc_4.f90 @@ -0,0 +1,13 @@ +! Check zero sized arrays work correcly +! From PR12704 +program intrinsic_mmloc_4 + integer, allocatable, dimension(:) :: d + integer, allocatable, dimension(:,:) :: a + integer, dimension(2) :: b + + allocate (d(0)) + if (maxloc (d, 1) .ne. 0) call abort() + allocate (a(1, 0)) + b = minloc (a) + if (any (b .ne. 0)) call abort() +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmval.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmval.f90 new file mode 100644 index 00000000000..368c83ba133 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mmval.f90 @@ -0,0 +1,28 @@ +! Program to test the MINVAL and MAXVAL intrinsics +program testmmval + implicit none + integer, dimension (3, 3) :: a + integer, dimension (3) :: b + logical, dimension (3, 3) :: m + integer i + + a = reshape ((/1, 2, 3, 5, 4, 6, 9, 8, 7/), (/3, 3/)); + + b = minval (a, 1) + if (any(b .ne. (/1, 4, 7/))) call abort + + m = .true. + m(1, 1) = .false. + m(1, 2) = .false. + b = minval (a, 1, m) + if (any(b .ne. (/2, 4, 7/))) call abort + + b = maxval (a, 1) + if (any(b .ne. (/3, 6, 9/))) call abort + + m = .true. + m(1, 2) = .false. + m(1, 3) = .false. + b = maxval (a, 1, m) + if (any(b .ne. (/3, 6, 8/))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mod_ulo.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mod_ulo.f90 new file mode 100644 index 00000000000..7050c2ccd53 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_mod_ulo.f90 @@ -0,0 +1,64 @@ +! Program to test MOD and MODULO intrinsics +subroutine integertest (ops, res) + implicit none + integer, dimension(2) :: ops + integer, dimension(2) :: res + + if ((mod(ops(1), ops(2)) .ne. res(1)) .or. & + (modulo(ops(1), ops(2)) .ne. res(2))) call abort +end subroutine + +subroutine real4test (ops, res) + implicit none + real(kind=4), dimension(2) :: ops + real(kind=4), dimension(2) :: res + + if (diff(mod(ops(1), ops(2)), res(1)) .or. & + diff(modulo(ops(1), ops(2)), res(2))) call abort +contains +function diff(a, b) + real(kind=4) :: a, b + logical diff + + diff = (abs (a - b) .gt. abs(a * 1e-6)) +end function +end subroutine + +subroutine real8test (ops, res) + implicit none + real(kind=8), dimension(2) :: ops + real(kind=8), dimension(2) :: res + + if (diff(mod(ops(1), ops(2)), res(1)) .or. & + diff(modulo(ops(1), ops(2)), res(2))) call abort +contains +function diff(a, b) + real(kind=8) :: a, b + logical diff + + diff = (abs(a - b) .gt. abs(a * 1e-6)) +end function +end subroutine + +program mod_modulotest + implicit none + + call integertest ((/8, 5/), (/3, 3/)) + call integertest ((/-8, 5/), (/-3, 2/)) + call integertest ((/8, -5/), (/3, -2/)) + call integertest ((/-8, -5/), (/-3, -3/)) + + call real4test ((/3.0, 2.5/), (/0.5, 0.5/)) + call real4test ((/-3.0, 2.5/), (/-0.5, 2.0/)) + call real4test ((/3.0, -2.5/), (/0.5, -2.0/)) + call real4test ((/-3.0, -2.5/), (/-0.5, -0.5/)) + + call real8test ((/3.0_8, 2.5_8/), (/0.5_8, 0.5_8/)) + call real8test ((/-3.0_8, 2.5_8/), (/-0.5_8, 2.0_8/)) + call real8test ((/3.0_8, -2.5_8/), (/0.5_8, -2.0_8/)) + call real8test ((/-3.0_8, -2.5_8/), (/-0.5_8, -0.5_8/)) + + ! Check large numbers + call real4test ((/2e34, 1.0/), (/0.0, 0.0/)) + call real4test ((/2e34, 1.5e34/), (/0.5e34, 0.5e34/)) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_nearest.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_nearest.f90 new file mode 100644 index 00000000000..99d802e6189 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_nearest.f90 @@ -0,0 +1,71 @@ +!Program to test NEAREST intrinsic function. + +program test_nearest + real s, r, x, y, inf, max, min + integer i, infi, maxi, mini + equivalence (s,i) + equivalence (inf,infi) + equivalence (max,maxi) + equivalence (min,mini) + + r = 2.0 + s = 3.0 + call test_n (s, r) + + i = z'00800000' + call test_n (s, r) + + i = z'007fffff' + call test_n (s, r) + + i = z'00800100' + call test_n (s, r) + + s = 0 + x = nearest(s, r) + y = nearest(s, -r) + if (.not. (x .gt. s .and. y .lt. s )) call abort() + + infi = z'7f800000' + maxi = z'7f7fffff' + mini = 1 + + call test_up(max, inf) + call test_up(-inf, -max) + call test_up(0, min) + call test_up(-min, 0) + + call test_down(inf, max) + call test_down(-max, -inf) + call test_down(0, -min) + call test_down(min, 0) +end + +subroutine test_up(s, e) + real s, e, x + + x = nearest(s, 1.0) + if (x .ne. e) call abort() +end + +subroutine test_down(s, e) + real s, e, x + + x = nearest(s, -1.0) + if (x .ne. e) call abort() +end + +subroutine test_n(s1, r) + real r, s1, x + + x = nearest(s1, r) + if (nearest(x, -r) .ne. s1) call abort() + x = nearest(s1, -r) + if (nearest(x, r) .ne. s1) call abort() + + s1 = -s1 + x = nearest(s1, r) + if (nearest(x, -r) .ne. s1) call abort() + x = nearest(s1, -r) + if (nearest(x, r) .ne. s1) call abort() +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_pack.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_pack.f90 new file mode 100644 index 00000000000..565446e4e8b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_pack.f90 @@ -0,0 +1,12 @@ +! Program to test the PACK intrinsic +program intrinsic_pack + integer, dimension(3, 3) :: a + integer, dimension(6) :: b + + a = reshape ((/0, 0, 0, 0, 9, 0, 0, 0, 7/), (/3, 3/)) + b = 0 + b(1:6:3) = pack (a, a .ne. 0); + if (any (b(1:6:3) .ne. (/9, 7/))) call abort + b = pack (a(2:3, 2:3), a(2:3, 2:3) .ne. 0, (/1, 2, 3, 4, 5, 6/)); + if (any (b .ne. (/9, 7, 3, 4, 5, 6/))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_present.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_present.f90 new file mode 100644 index 00000000000..d2e9981353d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_present.f90 @@ -0,0 +1,40 @@ +! Program to test the PRESENT intrinsic +program intrinsic_present + implicit none + integer a + integer, pointer :: b + integer, dimension(10) :: c + integer, pointer, dimension(:) :: d + + if (testvar()) call abort () + if (.not. testvar(a)) call abort () + if (testptr()) call abort () + if (.not. testptr(b)) call abort () + if (testarray()) call abort () + if (.not. testarray(c)) call abort () + if (testparray()) call abort () + if (.not. testparray(d)) call abort () + +contains +logical function testvar (p) + integer, optional :: p + testvar = present(p) +end function + +logical function testptr (p) + integer, pointer, optional :: p + testptr = present(p) +end function + +logical function testarray (p) + integer, dimension (10), optional :: p + testarray = present(p) +end function + +logical function testparray (p) + integer, pointer, dimension(:), optional :: p + testparray = present(p) +end function + +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_product.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_product.f90 new file mode 100644 index 00000000000..102832c9f9b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_product.f90 @@ -0,0 +1,25 @@ +! Program to test the PRODUCT intrinsic +program testproduct + implicit none + integer, dimension (3, 3) :: a + integer, dimension (3) :: b + logical, dimension (3, 3) :: m + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)); + + b = product (a, 1) + + if (any(b .ne. (/6, 120, 504/))) call abort + + if (product (a) .ne. 362880) call abort + + m = .true. + m(1, 1) = .false. + m(2, 1) = .false. + b = product (a, 2, m) + + if (any(b .ne. (/28, 40, 162/))) call abort + + if (product (a, mask=m) .ne. 181440) call abort + +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_rrspacing.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_rrspacing.f90 new file mode 100644 index 00000000000..0f411a633b2 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_rrspacing.f90 @@ -0,0 +1,27 @@ +!Program to test RRSPACING intrinsic function. + +program test_rrspacing + call test_real4(3.0) + call test_real4(33.0) + call test_real4(-3.0) + call test_real8(3.0_8) + call test_real8(33.0_8) + call test_real8(-33.0_8) +end +subroutine test_real4(x) + real x,y + integer p + p = 24 + y = abs (x * 2.0 ** (- exponent (x))) * (2.0 ** p) + x = rrspacing(x) + if (abs (x - y) .gt. abs(x * 1e-6)) call abort +end + +subroutine test_real8(x) + real*8 x,y,t + integer p + p = 53 + y = abs (x * 2.0 ** (- exponent (x))) * (2.0 ** p) + x = rrspacing(x) + if (abs (x - y) .gt. abs(x * 1e-6)) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_scale.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_scale.f90 new file mode 100644 index 00000000000..df483811415 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_scale.f90 @@ -0,0 +1,27 @@ +!Program to test SCALE intrinsic function. + +program test_scale + call test_real4 (3.0, 2) + call test_real4 (33.0, -2) + call test_real4 (-3., 2) + call test_real4 (0, 3) + call test_real8 (0, 3) + call test_real8 (3.0_8, 4) + call test_real8 (33.0_8, -4) + call test_real8 (-33._8, 4) +end +subroutine test_real4 (x, i) + real x,y + integer i + y = x * (2.0 ** i) + x = scale (x, i) + if (abs (x - y) .gt. abs(x * 1e-6)) call abort +end + +subroutine test_real8 (x, i) + real*8 x,y + integer i + y = x * (2.0 ** i) + x = scale (x, i) + if (abs (x - y) .gt. abs(x * 1e-6)) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_set_exponent.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_set_exponent.f90 new file mode 100644 index 00000000000..da84ea7d723 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_set_exponent.f90 @@ -0,0 +1,91 @@ +!Program to test SET_EXPONENT intrinsic function. + +program test_set_exponent + call test_real4() + call test_real8() +end +subroutine test_real4() + real x,y + integer i,n + equivalence(x,i) + + n = -148 + x = 1024.0 + y = set_exponent (x, n) + if (exponent (y) .ne. n) call abort() + + n = 8 + x = 1024.0 + y = set_exponent (x, n) + if (exponent (y) .ne. n) call abort() + + n = 128 + i = o'00037777777' + y = set_exponent (x, n) + if (exponent (y) .ne. n) call abort() + + n = -148 + x = -1024.0 + y = set_exponent (x, n) + if (exponent (y) .ne. n) call abort() + + n = 8 + x = -1024.0 + y = set_exponent (x, n) + if (y .ne. -128.0) call abort() + if (exponent (y) .ne. n) call abort() + + n = 128 + i = o'20037777777' + y = set_exponent (x, n) + if (exponent (y) .ne. n) call abort() + +end + +subroutine test_real8() + implicit none + real*8 x, y + integer*8 i, n, low + equivalence(x, i) + + n = -1073 + x = 1024.0_8 + y = set_exponent (x, n) + if (exponent (y) .ne. n) call abort() + + n = 8 + x = 1024.0_8 + y = set_exponent (x, n) + if (y .ne. 128.0) call abort() + if (exponent (y) .ne. n) call abort() + + n = 1024 + low = z'ffffffff' + i = z'000fffff' + i = ishft (i, 32) + low !'000fffffffffffff' + y = set_exponent (x, n) + low = z'fffffffe' + i = z'7fefffff' + i = ishft (i, 32) + low + if (exponent (y) .ne. n) call abort() + + n = -1073 + x = -1024.0 + y = set_exponent (x, n) + low = z'00000001' + if (exponent (y) .ne. n) call abort() + + n = 8 + x = -1024.0 + y = set_exponent (x, n) + if (y .ne. -128.0) call abort() + if (exponent (y) .ne. n) call abort() + + n = 1024 + low = z'ffffffff' + i = z'800fffff' + i = ishft (i, 32) + low !z'800fffffffffffff' + y = set_exponent (x, n) + if (exponent (y) .ne. n) call abort() + +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_shape.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_shape.f90 new file mode 100644 index 00000000000..e1c5f7b4ba1 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_shape.f90 @@ -0,0 +1,22 @@ +! Program to test the shape intrinsic +program testbounds + implicit none + real, dimension(:, :), allocatable :: a + integer, dimension(2) :: j + integer i + + allocate (a(3:8, 6:7)) + + j = shape (a); + if (any (j .ne. (/ 6, 2 /))) call abort + + call test(a) +contains + +subroutine test (a) + real, dimension (1:, 1:) :: a + + if (any (shape (a) .ne. (/ 6, 2 /))) call abort +end subroutine +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_si_kind.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_si_kind.f90 new file mode 100644 index 00000000000..b231dc66ebe --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_si_kind.f90 @@ -0,0 +1,35 @@ +! Program to test SELECTED_INT_KIND intrinsic function. +Program test_si_kind + integer*1 i1 + integer*2 i2 + integer*4 i4 + integer*8 i8 + integer res + real t + + t = huge (i1) + t = log10 (t) + res = selected_int_kind (int (t)) + if (res .ne. 1) call abort + + t = huge (i2) + t = log10 (t) + res = selected_int_kind (int (t)) + if (res .ne. 2) call abort + + t = huge (i4) + t = log10 (t) + res = selected_int_kind (int (t)) + if (res .ne. 4) call abort + + t = huge (i8) + t = log10 (t) + res = selected_int_kind (int (t)) + if (res .ne. 8) call abort + + i4 = huge (i4) + res = selected_int_kind (i4) + if (res .ne. (-1)) call abort + +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sign.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sign.f90 new file mode 100644 index 00000000000..fbc457d917c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sign.f90 @@ -0,0 +1,31 @@ +! Program to test SIGN intrinsic +program intrinsic_sign + implicit none + integer i, j + real r, s + + i = 2 + j = 3 + if (sign (i, j) .ne. 2) call abort + i = 4 + j = -5 + if (sign (i, j) .ne. -4) call abort + i = -6 + j = 7 + if (sign (i, j) .ne. 6) call abort + i = -8 + j = -9 + if (sign (i, j) .ne. -8) call abort + r = 1 + s = 2 + if (sign (r, s) .ne. 1) call abort + r = 1 + s = -2 + if (sign (r, s) .ne. -1) call abort + s = 0 + if (sign (r, s) .ne. 1) call abort + ! Will fail on machines which cannot represent negative zero. + s = -s ! Negative zero + if (sign (r, s) .ne. -1) call abort +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_size.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_size.f90 new file mode 100644 index 00000000000..729c55f2283 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_size.f90 @@ -0,0 +1,37 @@ +! Program to test the SIZE intrinsics +program testsize + implicit none + real, dimension(:, :), allocatable :: a + integer, dimension(5) :: j + integer, dimension(2, 3) :: b + integer i + + if (size (b(2, :), 1) .ne. 3) call abort + + allocate (a(3:8, 5:7)) + + ! With one parameter + if (size(a) .ne. 18) call abort + + ! With two parameters, assigning to an array + j = size(a, 1) + if (any (j .ne. (/6, 6, 6, 6, 6/))) call abort + + ! With a variable second parameter + i = 2 + i = size(a, i) + if (i .ne. 3) call abort + + call test(a) +contains + +subroutine test (a) + real, dimension (1:, 1:) :: a + integer i + + i = 2 + if ((size(a, 1) .ne. 6) .or. (size(a, i) .ne. 3)) call abort + if (size (a) .ne. 18 ) call abort +end subroutine +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spacing.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spacing.f90 new file mode 100644 index 00000000000..4fac9f1b303 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spacing.f90 @@ -0,0 +1,33 @@ +!Program to test SPACING intrinsic function. + +program test_spacing + call test_real4(3.0) + call test_real4(33.0) + call test_real4(-3.) + call test_real4(0) + call test_real8(0) + call test_real8(3.0_8) + call test_real8(33.0_8) + call test_real8(-33._8) +end +subroutine test_real4(x) + real x,y,t + integer p + p = 24 + y = 2.0 ** (exponent (x) - p) + t = tiny(x) + x = spacing(x) + if ((abs (x - y) .gt. abs(x * 1e-6)) & + .and. (abs (x - t) .gt. abs(x * 1e-6)))call abort +end + +subroutine test_real8(x) + real*8 x,y,t + integer p + p = 53 + y = 2.0 ** (exponent (x) - p) + t = tiny (x) + x = spacing(x) + if ((abs (x - y) .gt. abs(x * 1e-6)) & + .and. (abs (x - t) .gt. abs(x * 1e-6)))call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spread.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spread.f90 new file mode 100644 index 00000000000..50b66ff6c2b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_spread.f90 @@ -0,0 +1,10 @@ +program foo + integer, dimension (2, 3) :: a + integer, dimension (2, 2, 3) :: b + + a = reshape ((/1, 2, 3, 4, 5, 6/), (/2, 3/)) + b = spread (a, 1, 2) + if (any (b .ne. reshape ((/1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6/), & + (/2, 2, 3/)))) & + call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sr_kind.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sr_kind.f90 new file mode 100644 index 00000000000..fe2f978197d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sr_kind.f90 @@ -0,0 +1,61 @@ +! Program to test SELECTED_REAL_KIND intrinsic function. +Program test_sr_kind + integer res, i4, i8, t + real*4 r4 + real*8 r8 + + i4 = int (log10 (huge (r4))) + t = - int (log10 (tiny (r4))) + if (i4 .gt. t) i4 = t + + i8 = int (log10 (huge (r8))) + t = - int (log10 (tiny (r8))) + if (i8 .gt. t) i8 = t + + res = selected_real_kind (r = i4) + if (res .ne. 4) call abort + + res = selected_real_kind (r = i8) + if (res .ne. 8) call abort + + res = selected_real_kind (r = (i8 + 1)) + if (res .ne. -2) call abort + + res = selected_real_kind (p = precision (r4)) + if (res .ne. 4) call abort + + res = selected_real_kind (p = precision (r4), r = i4) + if (res .ne. 4) call abort + + res = selected_real_kind (p = precision (r4), r = i8) + if (res .ne. 8) call abort + + res = selected_real_kind (p = precision (r4), r = i8 + 1) + if (res .ne. -2) call abort + + res = selected_real_kind (p = precision (r8)) + if (res .ne. 8) call abort + + res = selected_real_kind (p = precision (r8), r = i4) + if (res .ne. 8) call abort + + res = selected_real_kind (p = precision (r8), r = i8) + if (res .ne. 8) call abort + + res = selected_real_kind (p = precision (r8), r = i8 + 1) + if (res .ne. -2) call abort + + res = selected_real_kind (p = (precision (r8) + 1)) + if (res .ne. -1) call abort + + res = selected_real_kind (p = (precision (r8) + 1), r = i4) + if (res .ne. -1) call abort + + res = selected_real_kind (p = (precision (r8) + 1), r = i8) + if (res .ne. -1) call abort + + res = selected_real_kind (p = (precision (r8) + 1), r = i8 + 1) + if (res .ne. -3) call abort + +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sum.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sum.f90 new file mode 100644 index 00000000000..43f832ec63c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_sum.f90 @@ -0,0 +1,26 @@ +! Program to test the FORALL construct +program testforall + implicit none + integer, dimension (3, 3) :: a + integer, dimension (3) :: b + logical, dimension (3, 3) :: m + integer i + + a = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)); + + if (sum(a) .ne. 45) call abort + b = sum (a, 1) + if (b(1) .ne. 6) call abort + if (b(2) .ne. 15) call abort + if (b(3) .ne. 24) call abort + + m = .true. + m(1, 1) = .false. + m(2, 1) = .false. + + if (sum (a, mask=m) .ne. 42) call abort + b = sum (a, 2, m) + if (b(1) .ne. 11) call abort + if (b(2) .ne. 13) call abort + if (b(3) .ne. 18) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_transpose.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_transpose.f90 new file mode 100644 index 00000000000..e1f268e310d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_transpose.f90 @@ -0,0 +1,24 @@ +! Program to test the transpose intrinsic +program intrinsic_transpose + integer, dimension (3, 3) :: a, b + complex(kind=8), dimension (2, 2) :: c, d + complex(kind=4), dimension (2, 2) :: e + + a = 0 + b = reshape ((/1, 2, 3, 4, 5, 6, 7, 8, 9/), (/3, 3/)) + a = transpose (b) + if (any (a .ne. reshape ((/1, 4, 7, 2, 5, 8, 3, 6, 9/), (/3, 3/)))) & + call abort + c = (0.0, 0.0) + d = reshape ((/(1d0,2d0), (3d0, 4d0), (5d0, 6d0), (7d0, 8d0)/), (/2, 2/)) + c = transpose (d); + if (any (c .ne. reshape ((/(1d0, 2d0), (5d0, 6d0), & + (3d0, 4d0), (7d0, 8d0)/), (/2, 2/)))) & + call abort (); + + e = reshape ((/(1.0,2.0), (3.0, 4.0), (5.0, 6.0), (7.0, 8.0)/), (/2, 2/)) + e = transpose (e); + if (any (e .ne. reshape ((/(1.0, 2.0), (5.0, 6.0), & + (3.0, 4.0), (7.0, 8.0)/), (/2, 2/)))) & + call abort (); +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_trim.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_trim.f90 new file mode 100644 index 00000000000..90e4131685a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_trim.f90 @@ -0,0 +1,23 @@ +! Program to test the TRIM and REPEAT intrinsics. +program intrinsic_trim + character(len=8) a + character(len=4) b,work + a='1234 ' + b=work(9,a) + if (llt(b,"1234")) call abort() + a=' ' + b=trim(a) + if (b .gt. "") call abort() + b='12' + a=repeat(b,0) + if (a .gt. "") call abort() + a=repeat(b,2) + if (a .ne. "12 12 ") call abort() +end + +function work(i,a) + integer i + character(len=i) a + character(len=4) work + work = trim(a) +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_unpack.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_unpack.f90 new file mode 100644 index 00000000000..807aadf136f --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/intrinsic_unpack.f90 @@ -0,0 +1,17 @@ +! Program to test the UNPACK intrinsic +program intrinsic_unpack + integer, dimension(3, 3) :: a, b + logical, dimension(3, 3) :: mask; + integer i + + mask = reshape ((/.false.,.true.,.false.,.true.,.false.,.false.,& + &.false.,.false.,.true./), (/3, 3/)); + a = reshape ((/1, 0, 0, 0, 1, 0, 0, 0, 1/), (/3, 3/)); + b = unpack ((/2, 3, 4/), mask, a) + if (any (b .ne. reshape ((/1, 2, 0, 3, 1, 0, 0, 0, 4/), (/3, 3/)))) & + call abort + b = -1 + b = unpack ((/2, 3, 4/), mask, 0) + if (any (b .ne. reshape ((/0, 2, 0, 3, 0, 0, 0, 0, 4/), (/3, 3/)))) & + call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/list_read_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/list_read_1.f90 new file mode 100644 index 00000000000..040ae72d8e0 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/list_read_1.f90 @@ -0,0 +1,53 @@ +! pr 14942, list directed io + program d + implicit none + integer i, j, m, n, nin, k + real x(3,4) + data x / 1,1,1,2,2,2,3,3,3,4,4,4 / + real y(3,4) + data y / 1,1,1,2,2,2,3,3,3,4,4,4 / + logical debug ! set me true to see the output + debug = .FALSE. + nin = 1 + n = 4 + open(unit = nin) + write(nin,*) n + do I = 1,3 + write(nin,*)(x(i,j), j=1, n) + end do + m = 3 + n = 4 + write(nin,*) m,n + do I = 1,3 + write(nin,*)(x(i,j), j=1, n) + enddo + close(nin) +! ok, the data file is written + open(unit = nin) + read(nin, fmt = *) n + if (debug ) write(*,'(A,I2)') 'n = ', n + do i = 1, 3 + do K = 1,n + x(i,k) = -1 + enddo + read(nin, fmt = *) (x(i,j), j=1, n) + if (debug) write(*, *) (x(i,j), j=1, n) + do K = 1,n + if (x(i,k).ne.y(i,k)) call abort + end do + end do + m = 0 + n = 0 + read(nin, fmt = *) m, n + if (debug) write(*,'(A,I2,2X,A,I2)') 'm = ', m, 'n = ', n + do i = 1, m + do K = 1,n + x(i,k) = -1 + enddo + read(nin, fmt = *) (x(i,j), j=1, n) + if (debug) write(*, *) (x(i,j), j=1, n) + do K = 1,n + if (x(i,k).ne.y(i,k)) call abort + end do + end do + end program d diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/logical_select_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/logical_select_1.f90 new file mode 100644 index 00000000000..60c077c4347 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/logical_select_1.f90 @@ -0,0 +1,55 @@ +LOGICAL :: L = .FALSE. + +SELECT CASE (L) + CASE (.TRUE.) + CALL abort + CASE (.FALSE.) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT + +SELECT CASE (L) + CASE (.TRUE., .FALSE.) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT + +SELECT CASE (L) + CASE (.FALSE.) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT + +SELECT CASE (L) + CASE (.NOT. .TRUE.) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT + +SELECT CASE (.NOT. L) + CASE (.TRUE.) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT + +SELECT CASE (Truth_or_Dare() .OR. L) + CASE (.TRUE.) + CONTINUE + CASE DEFAULT + CALL abort +END SELECT + +CONTAINS + + FUNCTION Truth_or_Dare () + LOGICAL Truth_or_Dare + Truth_or_Dare = .TRUE. + END FUNCTION + +END + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/mainsub.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/mainsub.f90 new file mode 100644 index 00000000000..f84e91f2525 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/mainsub.f90 @@ -0,0 +1,17 @@ +! Program to test compilation of subroutines following the main program +program mainsub + implicit none + integer i + external test + + i = 0 + call test (i) + if (i .ne. 42) call abort +end program + +subroutine test (p) + implicit none + integer p + + p = 42 +end subroutine diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/math.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/math.f90 new file mode 100644 index 00000000000..4f54dcfc7fb --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/math.f90 @@ -0,0 +1,100 @@ +! Program to test mathematical intrinsics +subroutine dotest (n, val4, val8, known) + implicit none + real(kind=4) val4, known + real(kind=8) val8 + integer n + + if (abs (val4 - known) .gt. 0.001) call abort + if (abs (real (val8, kind=4) - known) .gt. 0.001) call abort +end subroutine + +subroutine dotestc (n, val4, val8, known) + implicit none + complex(kind=4) val4, known + complex(kind=8) val8 + integer n + if (abs (val4 - known) .gt. 0.001) call abort + if (abs (cmplx (val8, kind=4) - known) .gt. 0.001) call abort +end subroutine + +program testmath + implicit none + real(kind=4) r, two4, half4 + real(kind=8) q, two8, half8 + complex(kind=4) cr + complex(kind=8) cq + external dotest, dotest2 + + two4 = 2.0 + two8 = 2.0_8 + half4 = 0.5 + half8 = 0.5_8 + r = sin (two4) + q = sin (two8) + call dotest (1, r, q, 0.9093) + r = cos (two4) + q = cos (two8) + call dotest (2, r, q, -0.4161) + r = tan (two4) + q = tan (two8) + call dotest (3, r, q, -2.1850) + r = asin (half4) + q = asin (half8) + call dotest (4, r, q, 0.5234) + r = acos (half4) + q = acos (half8) + call dotest (5, r, q, 1.0472) + r = atan (half4) + q = atan (half8) + call dotest (6, r, q, 0.4636) + r = atan2 (two4, half4) + q = atan2 (two8, half8) + call dotest (7, r, q, 1.3258) + r = exp (two4) + q = exp (two8) + call dotest (8, r, q, 7.3891) + r = log (two4) + q = log (two8) + call dotest (9, r, q, 0.6931) + r = log10 (two4) + q = log10 (two8) + call dotest (10, r, q, 0.3010) + r = sinh (two4) + q = sinh (two8) + call dotest (11, r, q, 3.6269) + r = cosh (two4) + q = cosh (two8) + call dotest (12, r, q, 3.7622) + r = tanh (two4) + q = tanh (two8) + call dotest (13, r, q, 0.9640) + r = sqrt (two4) + q = sqrt (two8) + call dotest (14, r, q, 1.4142) + + r = atan2 (0.0, 1.0) + q = atan2 (0.0_8, 1.0_8) + call dotest (15, r, q, 0.0) + r = atan2 (-1.0, 1.0) + q = atan2 (-1.0_8, 1.0_8) + call dotest (16, r, q, -0.7854) + r = atan2 (0.0, -1.0) + q = atan2 (0.0_8, -1.0_8) + call dotest (17, r, q, 3.1416) + r = atan2 (-1.0, -1.0) + q = atan2 (-1.0_8, -1.0_8) + call dotest (18, r, q, -2.3562) + r = atan2 (1.0, 0.0) + q = atan2 (1.0_8, 0.0_8) + call dotest (19, r, q, 1.5708) + r = atan2 (-1.0, 0.0) + q = atan2 (-1.0_8, 0.0_8) + call dotest (20, r, q, -1.5708) + + cr = log ((-1.0, -1.0)) + cq = log ((-1.0_8, -1.0_8)) + call dotestc (21, cr, cq, (0.3466, -2.3562)) + +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/module_interface.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/module_interface.f90 new file mode 100644 index 00000000000..86fd7914b4d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/module_interface.f90 @@ -0,0 +1,39 @@ +! We were incorrectly mangling procedures in interfaces in modules + +module module_interface + interface + subroutine foo () + end subroutine foo + end interface +contains +subroutine cs +end subroutine + +subroutine cproc + interface + subroutine bar () + end subroutine + end interface + call bar () + call foo () + call cs () +end subroutine +end module + +subroutine foo () +end subroutine + +subroutine bar () +end subroutine + +program module_interface_proc + use module_interface + interface + subroutine bar () + end subroutine + end interface + + call cproc () + call foo () + call bar () +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/module_interface_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/module_interface_2.f90 new file mode 100644 index 00000000000..dba736654c4 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/module_interface_2.f90 @@ -0,0 +1,29 @@ +! Test generic interfaces declared in modules. +! We used to get the name mangling wrong for these. +module module_interface_2 + interface foo + subroutine myfoo (i) + integer i + end subroutine + module procedure bar + end interface +contains +subroutine bar (r) + real r + + if (r .ne. 1.0) call abort () +end subroutine +end module + +subroutine myfoo (i) + integer i + + if (i .ne. 42) call abort () +end subroutine + +program test + use module_interface_2 + + call foo (42) + call foo (1.0) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/mystery_proc.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/mystery_proc.f90 new file mode 100644 index 00000000000..06fa21614ed --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/mystery_proc.f90 @@ -0,0 +1,23 @@ +! Program to test dummy procedures +subroutine bar() +end subroutine + +subroutine foo2(p) + external p + + call p() +end subroutine + +subroutine foo(p) + external p + ! We never actually discover if this is a function or a subroutine + call foo2(p) +end subroutine + +program intrinsic_minmax + implicit none + external bar + + call foo(bar) +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/nestcons.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/nestcons.f90 new file mode 100644 index 00000000000..d2d54562503 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/nestcons.f90 @@ -0,0 +1,9 @@ +! Program to test array expressions in array constructors. +program nestcons + implicit none + integer, parameter :: w1(3)= (/ 5, 6, 7/) + integer, dimension(6) :: w2 + + w2 = (/ 1, 2, w1(3:1:-1), 3 /) + if (any (w2 .ne. (/ 1, 2, 7, 6, 5, 3/))) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/parameter_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/parameter_1.f90 new file mode 100644 index 00000000000..8a8af73851d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/parameter_1.f90 @@ -0,0 +1,12 @@ +! Program to test array parameter variables. +program parameter_1 + implicit none + integer i + INTEGER, PARAMETER :: ii(10) = (/ (I,I=1,10) /) + REAL, PARAMETER :: rr(10) = ii + + do i = 1, 10 + if (ii(i) /= i) call abort() + if (rr(i) /= i) call abort() + end do +end program parameter_1 diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/partparm.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/partparm.f90 new file mode 100644 index 00000000000..839ecf02f69 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/partparm.f90 @@ -0,0 +1,15 @@ +! Program to test +subroutine test (p) + integer, dimension (3) :: p + + if (any (p .ne. (/ 2, 4, 6/))) call abort +end subroutine + +program partparm + implicit none + integer, dimension (2, 3) :: a + external test + + a = reshape ((/ 1, 2, 3, 4, 5, 6/), (/ 2, 3/)) + call test (a(2, :)) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/plusconst_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/plusconst_1.f90 new file mode 100644 index 00000000000..7fc3eebb15b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/plusconst_1.f90 @@ -0,0 +1,15 @@ +! PR14005 +! The GMP conversion routines object to a leading "+" +program plusconst_1 + implicit none + real p + integer i + data p /+3.1415/ + data i /+42/ + real :: q = +1.234 + integer :: j = +100 + + if ((p .ne. 3.1415) .or. (i .ne. 42) .or. (q .ne. 1.234) .or. (j .ne. 100)) & + call abort +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/power.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/power.f90 new file mode 100644 index 00000000000..91ddc73d3e4 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/power.f90 @@ -0,0 +1,43 @@ +! Program to test the power (**) operator +program testpow + implicit none + real(kind=4) r, s, two + real(kind=8) :: q + complex(kind=4) :: c + real, parameter :: del = 0.0001 + integer i + + two = 2.0 + + r = two ** 1 + if (abs (r - 2.0) .gt. del) call abort + r = two ** 2 + if (abs (r - 4.0) .gt. del) call abort + r = two ** 3 + if (abs (r - 8.0) .gt. del) call abort + r = two ** 4 + if (abs (r - 16.0) .gt. del) call abort + r = two ** 0 + if (abs (r - 1.0) .gt. del) call abort + r = two ** (-1) + if (abs (r - 0.5) .gt. del) call abort + r = two ** (-2) + if (abs (r - 0.25) .gt. del) call abort + r = two ** (-4) + if (abs (r - 0.0625) .gt. del) call abort + s = 3.0 + r = two ** s + if (abs (r - 8.0) .gt. del) call abort + s = -3.0 + r = two ** s + if (abs (r - 0.125) .gt. del) call abort + i = 3 + r = two ** i + if (abs (r - 8.0) .gt. del) call abort + i = -3 + r = two ** i + if (abs (r - 0.125) .gt. del) call abort + c = (2.0, 3.0) + c = c ** two + if (abs(c - (-5.0, 12.0)) .gt. del) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/procarg.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/procarg.f90 new file mode 100644 index 00000000000..37718f5fc43 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/procarg.f90 @@ -0,0 +1,29 @@ +! Pogram to test +subroutine myp (a) + implicit none + integer a + + if (a .ne. 42) call abort +end subroutine + +subroutine test2 (p) + implicit none + external p + + call p(42) +end subroutine + +subroutine test (p) + implicit none + external p, test2 + + call p(42) + call test2(p) +end subroutine + +program arrayio + implicit none + external test, myp + + call test (myp) +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/ptr.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/ptr.f90 new file mode 100644 index 00000000000..2675f0866c2 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/ptr.f90 @@ -0,0 +1,20 @@ +program ptr + implicit none + integer, pointer, dimension(:) :: a, b + integer, pointer :: p + integer, target :: i + + allocate (a(1:6)) + + a = (/ 1, 2, 3, 4, 5, 6 /) + b => a + if (any (b .ne. (/ 1, 2, 3, 4, 5, 6 /))) call abort + b => a(1:6:2) + if (any (b .ne. (/ 1, 3, 5/))) call abort + + p => i + i = 42 + if (p .ne. 42) call abort + p => a(4) + if (p .ne. 4) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/read_eof.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/read_eof.f90 new file mode 100644 index 00000000000..92e454025b5 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/read_eof.f90 @@ -0,0 +1,5 @@ +! PR 13919, segfault when file is empty + open(unit=8,file='/dev/null') + read(8,*,end=1)i +1 continue + end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/retarray.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/retarray.f90 new file mode 100644 index 00000000000..a0bdc97c47d --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/retarray.f90 @@ -0,0 +1,45 @@ +! Program to test functions returning arrays + +program testfnarray + implicit none + integer, dimension (6, 5) :: a + integer n + +! These first two shouldn't require a temporary. + a = 0 + a = test(6, 5) + if (a(1,1) .ne. 42) call abort + if (a(6,5) .ne. 43) call abort + + a = 0 + a(1:6:2, 2:5) = test2() + if (a(1,2) .ne. 42) call abort + if (a(5,5) .ne. 43) call abort + + a = 1 + ! This requires a temporary + a = test(6, 5) - a + if (a(1,1) .ne. 41) call abort + if (a(6,5) .ne. 42) call abort + + contains + + function test (x, y) + implicit none + integer x, y + integer, dimension (1:x, 1:y) :: test + + test(1, 1) = 42 + test(x, y) = 43 + end function + + function test2 () result (foo) + implicit none + integer, dimension (3, 4) :: foo + + foo(1, 1) = 42 + foo(3, 4) = 43 + end function + +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/retarray_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/retarray_2.f90 new file mode 100644 index 00000000000..ab14dd03caf --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/retarray_2.f90 @@ -0,0 +1,20 @@ +! Procedure to test module procedures returning arrays. +! The array spec only gets applied to the result variable, not the function +! itself. As a result we missed it during resolution, and used the wrong +! calling convention (functions returning arrays must always have explicit +! interfaces). +module retarray_2 +contains + function z(a) result (aout) + integer, dimension(4) :: aout,a + aout = a + end function z +end module retarray_2 + +program retarray + use retarray_2 + integer, dimension(4) :: b, a=(/1,2,3,4/) + b = z(a) + if (any (b .ne. (/1, 2, 3, 4/))) call abort +end + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/scalarize.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/scalarize.f90 new file mode 100644 index 00000000000..63004c82797 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/scalarize.f90 @@ -0,0 +1,23 @@ +! Program to test the scalarizer +program testarray + implicit none + integer, dimension (6, 5) :: a, b + integer n + + a = 0 + do n = 1, 5 + a(4, n) = n + end do + + b(:, 5:1:-1) = a + a(1:5, 2) = a(4, :) + 1 + + ! The following expression should cause loop reordering + a(:, 2:4) = a(:, 1:3) + + do n = 1, 5 + if (a(n, 3) .ne. (n + 1)) call abort + if (b(4, n) .ne. (6 - n)) call abort + end do +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/scalarize2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/scalarize2.f90 new file mode 100644 index 00000000000..608c051d31c --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/scalarize2.f90 @@ -0,0 +1,24 @@ +! Program to test the scalarizer +program testarray + implicit none + integer, dimension (:, :), allocatable :: a, b + integer n + + allocate(a(6, 5), b(6, 5)) + a = 0 + do n = 1, 5 + a(4, n) = n + end do + + b(:, 5:1:-1) = a + a(1:5, 2) = a(4, :) + 1 + + ! The following expression should cause loop reordering + a(:, 2:4) = a(:, 1:3) + + do n = 1, 5 + if (a(n, 3) .ne. (n + 1)) call abort + if (b(4, n) .ne. (6 - n)) call abort + end do +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/scalarize3.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/scalarize3.f90 new file mode 100644 index 00000000000..76d41484c70 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/scalarize3.f90 @@ -0,0 +1,8 @@ +program foo + integer, dimension(3, 2) :: a + + a = reshape ((/1, 2, 3, 4, 5, 6/), (/3, 2/)) + a = a(3:1:-1, 2:1:-1); + + if (any (a .ne. reshape ((/6, 5, 4, 3, 2, 1/), (/3, 2/)))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/slash_edit.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/slash_edit.f90 new file mode 100644 index 00000000000..c73d5432a31 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/slash_edit.f90 @@ -0,0 +1,14 @@ +! pr 14762 - '/' not working in format + INTEGER N(5) + DATA N/1,2,3,4,5/ + OPEN(UNIT=7) + 100 FORMAT(I4) + WRITE(7,100)N + CLOSE(7) + OPEN(7) + 200 FORMAT(I4,///I4) + READ(7,200)I,J + CLOSE(7) + IF (I.NE.1) CALL ABORT + IF (J.NE.4) CALL ABORT + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/spec_abs.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/spec_abs.f90 new file mode 100644 index 00000000000..be8e3f7487b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/spec_abs.f90 @@ -0,0 +1,12 @@ +!pr 14056 + INTRINSIC IABS + INTEGER FF324 + IVCOMP = FF324(IABS,-7) + IF (IVCOMP.NE.8) CALL ABORT + END + INTEGER FUNCTION FF324(NINT, IDON03) + FF324 = NINT(IDON03) + 1 +! **** THE NAME NINT IS A DUMMY ARGUMENT +! AND NOT AN INTRINSIC FUNCTION REFERENCE ***** + RETURN + END diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/specifics.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/specifics.f90 new file mode 100644 index 00000000000..d9f3ff0c7b2 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/specifics.f90 @@ -0,0 +1,133 @@ +! Program to test intrinsic functions as actual arguments +subroutine test_r(fn, val, res) + real fn + real val, res + + if (diff(fn(val), res)) call abort +contains +function diff(a, b) + real a, b + logical diff + diff = (abs(a - b) .gt. 0.00001) +end function +end subroutine + +subroutine test_d(fn, val, res) + double precision fn + double precision val, res + + if (diff(fn(val), res)) call abort +contains +function diff(a, b) + double precision a, b + logical diff + diff = (abs(a - b) .gt. 0.00001d0) +end function +end subroutine + +subroutine test_r2(fn, val1, val2, res) + real fn + real val1, val2, res + + if (diff(fn(val1, val2), res)) call abort +contains +function diff(a, b) + real a, b + logical diff + diff = (abs(a - b) .gt. 0.00001) +end function +end subroutine + +subroutine test_d2(fn, val1, val2, res) + double precision fn + double precision val1, val2, res + + if (diff(fn(val1, val2), res)) call abort +contains +function diff(a, b) + double precision a, b + logical diff + diff = (abs(a - b) .gt. 0.00001d0) +end function +end subroutine + +subroutine test_dprod(fn) + if (abs (fn (2.0, 3.0) - 6d0) .gt. 0.00001) call abort +end subroutine + +program specifics + intrinsic abs + intrinsic aint + intrinsic anint + intrinsic acos + intrinsic asin + intrinsic atan + intrinsic cos + intrinsic sin + intrinsic tan + intrinsic cosh + intrinsic sinh + intrinsic tanh + intrinsic alog + intrinsic exp + intrinsic sign + intrinsic amod + + intrinsic dabs + intrinsic dint + intrinsic dnint + intrinsic dacos + intrinsic dasin + intrinsic datan + intrinsic dcos + intrinsic dsin + intrinsic dtan + intrinsic dcosh + intrinsic dsinh + intrinsic dtanh + intrinsic dlog + intrinsic dexp + intrinsic dsign + intrinsic dmod + + intrinsic dprod + + !TODO: Also test complex variants + + call test_r (abs, -1.0, abs(-1.0)) + call test_r (aint, 1.7, 1.0) + call test_r (anint, 1.7, 2.0) + call test_r (acos, 0.5, acos(0.5)) + call test_r (asin, 0.5, asin(0.5)) + call test_r (atan, 0.5, atan(0.5)) + call test_r (cos, 1.0, cos(1.0)) + call test_r (sin, 1.0, sin(1.0)) + call test_r (tan, 1.0, tan(1.0)) + call test_r (cosh, 1.0, cosh(1.0)) + call test_r (sinh, 1.0, sinh(1.0)) + call test_r (tanh, 1.0, tanh(1.0)) + call test_r (alog, 2.0, alog(2.0)) + call test_r (exp, 1.0, exp(1.0)) + call test_r2 (sign, 1.0, -2.0, sign(1.0, -2.0)) + call test_r2 (amod, 3.5, 2.0, amod(3.5, 2.0)) + + call test_d (dabs, -1d0, abs(-1d0)) + call test_d (dint, 1.7d0, 1d0) + call test_d (dnint, 1.7d0, 2d0) + call test_d (dacos, 0.5d0, dacos(0.5d0)) + call test_d (dasin, 0.5d0, dasin(0.5d0)) + call test_d (datan, 0.5d0, datan(0.5d0)) + call test_d (dcos, 1d0, dcos(1d0)) + call test_d (dsin, 1d0, dsin(1d0)) + call test_d (dtan, 1d0, dtan(1d0)) + call test_d (dcosh, 1d0, dcosh(1d0)) + call test_d (dsinh, 1d0, dsinh(1d0)) + call test_d (dtanh, 1d0, dtanh(1d0)) + call test_d (dlog, 2d0, dlog(2d0)) + call test_d (dexp, 1d0, dexp(1d0)) + call test_d2 (dsign, 1d0, -2d0, sign(1d0, -2d0)) + call test_d2 (dmod, 3.5d0, 2d0, dmod(3.5d0, 2d0)) + + call test_dprod(dprod) +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/st_function.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/st_function.f90 new file mode 100644 index 00000000000..8bde9b2f740 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/st_function.f90 @@ -0,0 +1,87 @@ +! Program to test STATEMENT function +program st_fuction + call simple_case + call with_function_call + call with_character_dummy + call with_derived_type_dummy + call with_pointer_dummy + call multiple_eval + +contains + subroutine simple_case + integer st1, st2 + integer c(10, 10) + st1 (i, j) = i + j + st2 (i, j) = c(i, j) + + if (st1 (1, 2) .ne. 3) call abort + c = 3 + if (st2 (1, 2) .ne. 3 .or. st2 (2, 3) .ne. 3) call abort + end subroutine + + subroutine with_function_call + integer fun, st3 + st3 (i, j) = fun (i) + fun (j) + + if (st3 (fun (2), 4) .ne. 16) call abort + end subroutine + + subroutine with_character_dummy + character (len=4) s1, s2, st4 + character (len=10) st5, s0 + st4 (i, j) = "0123456789"(i:j) + st5 (s1, s2) = s1 // s2 + + if (st4 (1, 4) .ne. "0123" ) call abort + if (st5 ("01", "02") .ne. "01 02 ") call abort + end subroutine + + subroutine with_derived_type_dummy + type person + integer age + character (len=50) name + end type person + type (person) me, p, tom + type (person) st6 + st6 (p) = p + + me%age = 5 + me%name = "Tom" + tom = st6 (me) + if (tom%age .ne. 5) call abort + if (tom%name .gt. "Tom") call abort + end subroutine + + subroutine with_pointer_dummy + character(len=4), pointer:: p, p1 + character(len=4), target:: i + character(len=6) a + a (p) = p // '10' + + p1 => i + i = '1234' + if (a (p1) .ne. '123410') call abort + end subroutine + + subroutine multiple_eval + integer st7, fun2, fun + + st7(i) = i + fun(i) + + if (st7(fun2(10)) .ne. 3) call abort + end subroutine +end + +! This functon returns the argument passed on the previous call. +integer function fun2 (i) + integer i + integer, save :: val = 1 + + fun2 = val + val = i +end function + +integer function fun (i) + integer i + fun = i * 2 +end function diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/stack_varsize.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/stack_varsize.f90 new file mode 100644 index 00000000000..f839c8e36bc --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/stack_varsize.f90 @@ -0,0 +1,30 @@ +! Program to test the stack variable size limit. +program stack + call sub1 + call sub2 (1) +contains + + ! Local variables larger than 32768 in byte size shall be placed in static + ! storage area, while others be put on stack by default. + subroutine sub1 + real a, b(32768/4), c(32768/4+1) + integer m, n(1024,4), k(1024,1024) + a = 10.0 + b = 20.0 + c = 30.0 + m = 10 + n = 20 + k = 30 + if ((a .ne. 10.0).or.(b(1) .ne. 20.0).or.(c(1) .ne. 30.0)) call abort + if ((m .ne. 10).or.(n(256,4) .ne. 20).or.(k(1,1024) .ne. 30)) call abort + end + + ! Local variables defined in recursive subroutine are always put on stack. + recursive subroutine sub2 (n) + real a (32769) + a (1) = 42 + if (n .ge. 1) call sub2 (n-1) + if (a(1) .ne. 42) call abort + a (1) = 0 + end +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/straret.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/straret.f90 new file mode 100644 index 00000000000..579e35a70a4 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/straret.f90 @@ -0,0 +1,18 @@ +! Test assumed length character functions. + +character*(*) function f() + f = "Hello" +end function + +character*6 function g() + g = "World" +end function + +program straret + character*6 f, g + character*12 v + + + v = f() // g() + if (v .ne. "Hello World ") call abort () +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strarray_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_1.f90 new file mode 100644 index 00000000000..95e9b038559 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_1.f90 @@ -0,0 +1,13 @@ +subroutine foo(i) +character c +integer i +character(1),parameter :: hex_chars(0:15)=& + (/'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'/) + +c = hex_chars(i) +if (c.ne.'3') call abort() +end + +program strarray_1 +call foo(3) +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strarray_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_2.f90 new file mode 100644 index 00000000000..dbb3b89e43f --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_2.f90 @@ -0,0 +1,14 @@ +subroutine foo(i,c) +character c +integer i +character(1),parameter :: hex_chars(0:15)=& + (/'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'/) + +c = hex_chars(i) +end + +program strarray_2 + character c + call foo(3,c) + if (c.ne.'3') call abort() +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strarray_3.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_3.f90 new file mode 100644 index 00000000000..9d369c7f196 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_3.f90 @@ -0,0 +1,50 @@ +program strarray_3 + character(len=5), dimension(2) :: c + + c(1) = "Hello" + c(2) = "World" + + call foo1(c) + call foo2(c, 2) + call foo3(c, 5) + call foo4(c, 5, 2) + call foo5(c(2:1:-1)) +contains +subroutine foo1(a) + implicit none + character(len=5), dimension(2) :: a + + if ((a(1) .ne. "Hello") .or. (a(2) .ne. "World")) call abort +end subroutine + +subroutine foo2(a, m) + implicit none + integer m + character(len=5), dimension(m) :: a + + if ((a(1) .ne. "Hello") .or. (a(2) .ne. "World")) call abort +end subroutine + +subroutine foo3(a, n) + implicit none + integer n + character(len=n), dimension(:) :: a + + if ((a(1) .ne. "Hello") .or. (a(2) .ne. "World")) call abort +end subroutine + +subroutine foo4(a, n, m) + implicit none + integer n, m + character(len=n), dimension(m) :: a + + if ((a(1) .ne. "Hello") .or. (a(2) .ne. "World")) call abort +end subroutine + +subroutine foo5(a) + implicit none + character(len=2), dimension(5) :: a + + if ((a(1) .ne. "Wo") .or. (a(3) .ne. "dH") .or. (a(5) .ne. "lo")) call abort +end subroutine +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strarray_4.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_4.f90 new file mode 100644 index 00000000000..c33f4b53d69 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strarray_4.f90 @@ -0,0 +1,39 @@ +program strarray_4 + character(len=5), dimension(2) :: c + + c(1) = "Hello" + c(2) = "World" + + call foo1(c) + call foo2(c, 2) + call foo3(c, 5, 2) +contains +subroutine foo1(a) + implicit none + character(len=5), dimension(2) :: a + character(len=5), dimension(2) :: b + + b = a; + if ((b(1) .ne. "Hello") .or. (b(2) .ne. "World")) call abort +end subroutine + +subroutine foo2(a, m) + implicit none + integer m + character(len=5), dimension(m) :: a + character(len=5), dimension(m) :: b + + b = a + if ((b(1) .ne. "Hello") .or. (b(2) .ne. "World")) call abort +end subroutine + +subroutine foo3(a, n, m) + implicit none + integer n, m + character(len=n), dimension(m) :: a + character(len=n), dimension(m) :: b + + b = a + if ((b(1) .ne. "Hello") .or. (b(2) .ne. "World")) call abort +end subroutine +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strcmp.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strcmp.f90 new file mode 100644 index 00000000000..26980901c7e --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strcmp.f90 @@ -0,0 +1,16 @@ +program test + implicit none + character(len=20) :: foo + + foo="hello" + + if (llt(foo, "hello")) call abort + if (.not. lle(foo, "hello")) call abort + if (lgt("hello", foo)) call abort + if (.not. lge("hello", foo)) call abort + + if (.not. llt(foo, "world")) call abort + if (.not. lle(foo, "world")) call abort + if (lgt(foo, "world")) call abort + if (lge(foo, "world")) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strcommon_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strcommon_1.f90 new file mode 100644 index 00000000000..aa51ccf4bae --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strcommon_1.f90 @@ -0,0 +1,28 @@ +! PR14081 character variables in common blocks. + +subroutine test1 + implicit none + common /block/ c + character(len=12) :: c + + if (c .ne. "Hello World") call abort +end subroutine + +subroutine test2 + implicit none + common /block/ a + character(len=6), dimension(2) :: a + + if ((a(1) .ne. "Hello") .or. (a(2) .ne. "World")) call abort +end subroutine + +program strcommon_1 + implicit none + common /block/ s, t + character(len=6) :: s, t + s = "Hello " + t = "World " + call test1 + call test2 +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/string.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/string.f90 new file mode 100644 index 00000000000..f220f4a477b --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/string.f90 @@ -0,0 +1,15 @@ +! Program to test string handling +program string + implicit none + character(len=5) :: a, b + character(len=20) :: c + + a = 'Hello' + b = 'World' + c = a//b + + if (c .ne. 'HelloWorld') call abort + if (c .eq. 'WorldHello') call abort + if (a//'World' .ne. 'HelloWorld') call abort + if (a .ge. b) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strlen.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strlen.f90 new file mode 100644 index 00000000000..17f9aa277b6 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strlen.f90 @@ -0,0 +1,34 @@ +! Program to test the LEN and LEN_TRIM intrinsics. +subroutine test (c) + character(*) c + character(len(c)) d + + d = c + if (len(d) .ne. 20) call abort + if (d .ne. "Longer Test String") call abort + c = "Hello World" +end subroutine + +subroutine test2 (c) + character (*) c + character(len(c)) d + + d = c + if (len(d) .ne. 6) call abort + if (d .ne. "Foobar") call abort +end subroutine + +program strlen + implicit none + character(20) c + character(5) a, b + integer i + + c = "Longer Test String" + call test (c) + + if (len(c) .ne. 20) call abort + if (len_trim(c) .ne. 11) call abort + + call test2 ("Foobar"); +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/strret.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/strret.f90 new file mode 100644 index 00000000000..7346fff5df7 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/strret.f90 @@ -0,0 +1,25 @@ +! Program to test caracter string return values +function test () + implicit none + character(len=10) :: test + test = "World" +end function + +function test2 () result (r) + implicit none + character(len=5) :: r + r = "Hello" +end function + +program strret + implicit none + character(len=15) :: s + character(len=10) :: test + character(len=5) :: test2 + + s = test () + if (s .ne. "World") call abort + + s = "Hello " // test () + if (s .ne. test2 () //" World") call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/test_slice.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/test_slice.f90 new file mode 100644 index 00000000000..f2291cd832a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/test_slice.f90 @@ -0,0 +1,17 @@ +! Program to test handling of reduced rank array sections. This uncovered +! bugs in simplify_shape and the scalarization of array sections. +program test_slice + implicit none + + real (kind = 8), dimension(2, 2, 2) :: x + real (kind = 8) :: min, max + + x = 1.0 + if (minval(x(1, 1:2, 1:1)) .ne. 1.0) call abort () + if (maxval(x(1, 1:2, 1:1)) .ne. 1.0) call abort () + if (any (shape(x(1, 1:2, 1:1)) .ne. (/2, 1/))) call abort () + + if (any (shape(x(1, 1:2, 1)) .ne. (/2/))) call abort () + if (any (shape(x(1:1, 1:2, 1:1)) .ne. (/1, 2, 1/))) call abort () + +end program test_slice diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/unopened_unit_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/unopened_unit_1.f90 new file mode 100644 index 00000000000..d87406ab4db --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/unopened_unit_1.f90 @@ -0,0 +1,13 @@ +! PR 14565 +program unopened_unit_1 + Integer I,J + Do I = 1,10 + Write(99,*)I + End Do + Rewind(99) + Do I = 1,10 + Read(99,*)J + If (J.ne.I) Call abort + End Do +End program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/userop.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/userop.f90 new file mode 100644 index 00000000000..4fceb476685 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/userop.f90 @@ -0,0 +1,67 @@ +module uops + implicit none + interface operator (.foo.) + module procedure myfoo + end interface + + interface operator (*) + module procedure boolmul + end interface + + interface assignment (=) + module procedure int2bool + end interface + +contains +function myfoo (lhs, rhs) + implicit none + integer myfoo + integer, intent(in) :: lhs, rhs + + myfoo = lhs + rhs +end function + +! This is deliberately different from integer multiplication +function boolmul (lhs, rhs) + implicit none + logical boolmul + logical, intent(IN) :: lhs, rhs + + boolmul = lhs .and. .not. rhs +end function + +subroutine int2bool (lhs, rhs) + implicit none + logical, intent(out) :: lhs + integer, intent(in) :: rhs + + lhs = rhs .ne. 0 +end subroutine +end module + +program me + use uops + implicit none + integer i, j + logical b, c + + b = .true. + c = .true. + if (b * c) call abort + c = .false. + if (.not. (b * c)) call abort + if (c * b) call abort + b = .false. + if (b * c) call abort + + i = 0 + b = i + if (b) call abort + i = 2 + b = i + if (.not. b) call abort + + j = 3 + if ((i .foo. j) .ne. 5) call abort +end program + diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/where_1.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/where_1.f90 new file mode 100644 index 00000000000..ba1f8a62579 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/where_1.f90 @@ -0,0 +1,41 @@ +! Program to test WHERE inside FORALL +program where_1 + integer :: A(5,5) + + A(1,:) = (/1,0,0,0,0/) + A(2,:) = (/2,1,1,1,0/) + A(3,:) = (/1,2,2,0,2/) + A(4,:) = (/2,1,0,2,3/) + A(5,:) = (/1,0,0,0,0/) + + ! Where inside FORALL. + ! WHERE masks must be evaluated before executing the assignments + forall (I=1:5) + where (A(I,:) .EQ. 0) + A(:,I) = I + elsewhere (A(I,:) >2) + A(I,:) = 6 + endwhere + end forall + + if (any (A .ne. reshape ((/1, 1, 1, 1, 1, 0, 1, 2, 1, 2, 0, 1, 2, 3, 0, & + 0, 1, 4, 2, 0, 0, 5, 6, 6, 5/), (/5, 5/)))) call abort + + ! Where inside DO + A(1,:) = (/1,0,0,0,0/) + A(2,:) = (/2,1,1,1,0/) + A(3,:) = (/1,2,2,0,2/) + A(4,:) = (/2,1,0,2,3/) + A(5,:) = (/1,0,0,0,0/) + + do I=1,5 + where (A(I,:) .EQ. 0) + A(:,I) = I + elsewhere (A(I,:) >2) + A(I,:) = 6 + endwhere + enddo + + if (any (A .ne. reshape ((/1, 1, 1, 1, 1, 0, 1, 2, 1, 2, 0, 1, 2, 6, 0, & + 0, 1, 0, 2, 0, 0, 0, 5, 5, 5/), (/5, 5/)))) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/where_2.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/where_2.f90 new file mode 100644 index 00000000000..25a8dc9e7a8 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/where_2.f90 @@ -0,0 +1,22 @@ +! Program to test the WHERE constructs +program where_2 + integer temp(10), reduce(10) + + temp = 10 + reduce(1:3) = -1 + reduce(4:6) = 0 + reduce(7:8) = 5 + reduce(9:10) = 10 + + WHERE (reduce < 0) + temp = 100 + ELSE WHERE (reduce .EQ. 0) + temp = 200 + temp + ELSE WHERE + WHERE (reduce > 6) temp = temp + sum(reduce) + temp = 300 + temp + END WHERE + + if (any (temp .ne. (/100, 100, 100, 210, 210, 210, 310, 310, 337, 337/))) & + call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/where_3.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/where_3.f90 new file mode 100644 index 00000000000..a9f7ef7bc08 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/where_3.f90 @@ -0,0 +1,21 @@ +! Program to test WHERE on unknown size arrays +program where_3 + integer A(10, 2) + + A = 0 + call sub(A) + +contains + +subroutine sub(B) + integer, dimension(:, :) :: B + + B(1:5, 1) = 0 + B(6:10, 1) = 5 + where (B(:,1)>0) + B(:,1) = B(:,1) + 10 + endwhere + if (any (B .ne. reshape ((/0, 0, 0, 0, 0, 15, 15, 15, 15, 15, & + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0/), (/10, 2/)))) call abort +end subroutine +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/where_4.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/where_4.f90 new file mode 100644 index 00000000000..104096b356a --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/where_4.f90 @@ -0,0 +1,13 @@ +! Tests WHERE statement with a data dependency +program where_4 + integer, dimension(5) :: a + integer, dimension(5) :: b + + a = (/1, 2, 3, 4, 5/) + b = (/1, 0, 1, 0, 1/) + + where (b .ne. 0) + a(:) = a(5:1:-1) + endwhere + if (any (a .ne. (/5, 2, 3, 4, 1/))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/where_5.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/where_5.f90 new file mode 100644 index 00000000000..58d24ecbb30 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/where_5.f90 @@ -0,0 +1,13 @@ +! Tests WHERE satement with non-integer array in the mask expression +program where_5 + integer, dimension(5) :: a + real(kind=8), dimension(5) :: b + + a = (/1, 2, 3, 4, 5/) + b = (/1d0, 0d0, 1d0, 0d0, 1d0/) + + where (b .ne. 0d0) + a(:) = a(:) + 10 + endwhere + if (any (a .ne. (/11, 2, 13, 4, 15/))) call abort +end program diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/where_6.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/where_6.f90 new file mode 100644 index 00000000000..274598b8d77 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/where_6.f90 @@ -0,0 +1,23 @@ +! Program to test WHERE inside FORALL and the WHERE assignment need temporary +program where_6 + integer :: A(5,5) + + A(1,:) = (/1,0,0,0,0/) + A(2,:) = (/2,1,1,1,0/) + A(3,:) = (/1,2,2,0,2/) + A(4,:) = (/2,1,0,2,3/) + A(5,:) = (/1,0,0,0,0/) + + ! Where inside FORALL. + ! WHERE masks must be evaluated before executing the assignments + m=5 + forall (I=1:4) + where (A(I,:) .EQ. 0) + A(1:m,I) = A(1:m,I+1) + I + elsewhere (A(I,:) >2) + A(I,1:m) = 6 + endwhere + end forall + if (any (A .ne. reshape ((/1,2,6,2,1,0,1,2,1,2,0,1,2,5,0,0,1,6,2,0,0,0,2,& + 6,0/), (/5, 5/)))) call abort +end diff --git a/gcc/testsuite/gfortran.fortran-torture/execute/write_logical.f90 b/gcc/testsuite/gfortran.fortran-torture/execute/write_logical.f90 new file mode 100644 index 00000000000..4e0060702f3 --- /dev/null +++ b/gcc/testsuite/gfortran.fortran-torture/execute/write_logical.f90 @@ -0,0 +1,23 @@ +! PR 14334, L edit descriptor does not work +! +! this test uses L1 and L4 to print TRUE and FALSE + logical true,false + character*10 b + true = .TRUE. + false = .FALSE. + b = '' + write (b, '(L1)') true + if (b(1:1) .ne. 'T') call abort + + b = '' + write (b, '(L1)') false + if (b(1:1) .ne. 'F') call abort + + b = '' + write(b, '(L4)') true + if (b(1:4) .ne. ' T') call abort + + b = '' + write(b, '(L4)') false + if (b(1:4) .ne. ' F') call abort + end diff --git a/gcc/testsuite/lib/fortran-torture.exp b/gcc/testsuite/lib/fortran-torture.exp new file mode 100644 index 00000000000..67b18ebc7ac --- /dev/null +++ b/gcc/testsuite/lib/fortran-torture.exp @@ -0,0 +1,344 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to +# the author. + +# This file was written by Steven Bosscher (s.bosscher@student.tudelft.nl) +# based on f-torture.exp, which was written by Rob Savoye. + +# The biggest change from g77 is that we always test all testcases with +# loop options, because it is much harder to figure out whether a testcase +# has loops if you have array syntax, like Fortran 95. In fact, the whole +# point of F95 is arrays, so loops show up in most testcases anyway. + + +# The default option list can be overridden by +# TORTURE_OPTIONS="{ { list1 } ... { listN } }" + +if ![info exists TORTURE_OPTIONS] { + set TORTURE_OPTIONS [list \ + { -O0 } { -O1 } { -O2 } \ + { -O2 -fomit-frame-pointer -finline-functions } \ + { -O2 -fomit-frame-pointer -finline-functions -funroll-loops } \ + { -O2 -fomit-frame-pointer -finline-functions -funroll-all-loops } \ + { -O2 -fno-repack-arrays } \ + { -O3 -g } \ + { -Os }] +} + + +# +# fortran-torture-compile -- compile a gfortran.fortran-torture testcase. +# +# SRC is the full pathname of the testcase. +# OPTION is the specific compiler flag we're testing (eg: -O2). +# +proc fortran-torture-compile { src option } { + global output + global srcdir tmpdir + global host_triplet + + set output "$tmpdir/[file tail [file rootname $src]].o" + + regsub "^$srcdir/?" $src "" testcase + + # If we couldn't rip $srcdir out of `src' then just do the best we can. + # The point is to reduce the unnecessary noise in the logs. Don't strip + # out too much because different testcases with the same name can confuse + # `test-tool'. + if [string match "/*" $testcase] { + set testcase "[file tail [file dirname $src]]/[file tail $src]" + } + + verbose "Testing $testcase, $option" 1 + + # Run the compiler and get results in comp_output. + set options "" + lappend options "additional_flags=-w $option" + + set comp_output [gfortran_target_compile "$src" "$output" object $options]; + + # See if we got something bad. + set fatal_signal "*95*: Internal compiler error: program*got fatal signal" + + if [string match "$fatal_signal 6" $comp_output] then { + gfortran_fail $testcase "Got Signal 6, $option" + remote_file build delete $output + return + } + + if [string match "$fatal_signal 11" $comp_output] then { + gfortran_fail $testcase "Got Signal 11, $option" + remote_file build delete $output + return + } + + # We shouldn't get these because of -w, but just in case. + if [string match "*95*:*warning:*" $comp_output] then { + warning "$testcase: (with warnings) $option" + send_log "$comp_output\n" + unresolved "$testcase, $option" + remote_file build delete $output + return + } + + # Prune warnings we know are unwanted. + set comp_output [prune_warnings $comp_output] + + # Report if the testcase is not supported. + set unsupported_message [gfortran_check_unsupported_p $comp_output] + if { $unsupported_message != "" } { + unsupported "$testcase: $unsupported_message" + remote_file build delete $output + return + } + + # remove any leftover LF/CR to make sure any output is legit + regsub -all -- "\[\r\n\]*" $comp_output "" comp_output + + # If any message remains, we fail. + if ![string match "" $comp_output] then { + gfortran_fail $testcase $option + remote_file build delete $output + return + } + + gfortran_pass $testcase $option + remote_file build delete $output +} + + +# +# fortran-torture-execute -- compile and execute a testcase. +# +# SRC is the full pathname of the testcase. +# +# If the testcase has an associated .x file, we source that to run the +# test instead. We use .x so that we don't lengthen the existing filename +# to more than 14 chars. +# +proc fortran-torture-execute { src } { + global output + global srcdir tmpdir + global tool + global compiler_conditional_xfail_data + global TORTURE_OPTIONS + + # Check for alternate driver. + if [file exists [file rootname $src].x] { + verbose "Using alternate driver [file rootname [file tail $src]].x" 2 + set done_p 0 + catch "set done_p \[source [file rootname $src].x\]" + if { $done_p } { + return + } + } + + # Setup the options for the testcase run. + set option_list $TORTURE_OPTIONS + set executable $tmpdir/[file tail [file rootname $src].x] + regsub "^$srcdir/?" $src "" testcase + + # If we couldn't rip $srcdir out of `src' then just do the best we can. + # The point is to reduce the unnecessary noise in the logs. Don't strip + # out too much because different testcases with the same name can confuse + # `test-tool'. + if [string match "/*" $testcase] { + set testcase "[file tail [file dirname $src]]/[file tail $src]" + } + + # Walk the list of options and copmile and run the testcase for all + # options that are not explicitly disabled by the .x script (if present). + foreach option $option_list { + + # Torture_{compile,execute}_xfail are set by the .x script. + if [info exists torture_compile_xfail] { + setup_xfail $torture_compile_xfail + } + + # Torture_execute_before_{compile,execute} can be set by the .x script. + if [info exists torture_eval_before_compile] { + set ignore_me [eval $torture_eval_before_compile] + } + + # FIXME: We should make sure that the modules required by this testcase + # exist. If not, the testcase should XFAIL. + + # Compile the testcase. + remote_file build delete $executable + verbose "Testing $testcase, $option" 1 + + set options "" + lappend options "additional_flags=-w $option" + set comp_output [gfortran_target_compile "$src" "$executable" executable $options]; + + # See if we got something bad. + set fatal_signal "*95*: Internal compiler error: program*got fatal signal" + + if [string match "$fatal_signal 6" $comp_output] then { + gfortran_fail $testcase "Got Signal 6, $option" + remote_file build delete $executable + continue + } + + if [string match "$fatal_signal 11" $comp_output] then { + gfortran_fail $testcase "Got Signal 11, $option" + remote_file build delete $executable + continue + } + + # We shouldn't get these because of -w, but just in case. + if [string match "*95*:*warning:*" $comp_output] then { + warning "$testcase: (with warnings) $option" + send_log "$comp_output\n" + unresolved "$testcase, $option" + remote_file build delete $executable + continue + } + + # Prune warnings we know are unwanted. + set comp_output [prune_warnings $comp_output] + + # Report if the testcase is not supported. + set unsupported_message [gfortran_check_unsupported_p $comp_output] + if { $unsupported_message != "" } { + unsupported "$testcase: $unsupported_message" + continue + } elseif ![file exists $executable] { + if ![is3way] { + fail "$testcase compilation, $option" + untested "$testcase execution, $option" + continue + } else { + # FIXME: since we can't test for the existance of a remote + # file without short of doing an remote file list, we assume + # that since we got no output, it must have compiled. + pass "$testcase compilation, $option" + } + } else { + pass "$testcase compilation, $option" + } + + # See if this source file uses INTEGER(KIND=8) types, if it does, and + # no_long_long is set, skip execution of the test. + # FIXME: We should also look for F95 style "_8" or select_int_kind() + # integers, but that is obviously much harder than just regexping this. + # So maybe we should just avoid those in testcases. + if [target_info exists no_long_long] then { + if [expr [search_for $src "integer\*8"] \ + +[search_for $src "integer *( *8 *)"] \ + +[search_for $src "integer *( *kind *= *8 *)"]] \ + then { + untested "$testcase execution, $option" + continue + } + } + + if [info exists torture_execute_xfail] { + setup_xfail $torture_execute_xfail + } + + if [info exists torture_eval_before_execute] { + set ignore_me [eval $torture_eval_before_execute] + } + + # Run the testcase, and analyse the output. + set result [gfortran_load "$executable" "" ""] + set status [lindex $result 0]; + set output [lindex $result 1]; + if { $status == "pass" } { + remote_file build delete $executable + } + $status "$testcase execution, $option" + } +} + + +# +# search_for -- looks for a string match in a file +# +proc search_for { file pattern } { + set fd [open $file r] + while { [gets $fd cur_line]>=0 } { + set lower [string tolower $cur_line] + if [regexp "$pattern" $lower] then { + close $fd + return 1 + } + } + close $fd + return 0 +} + + +# +# fortran-torture -- the fortran-torture testcase source file processor +# +# This runs compilation only tests (no execute tests). +# +# SRC is the full pathname of the testcase, or just a file name in which +# case we prepend $srcdir/$subdir. +# +# If the testcase has an associated .x file, we source that to run the +# test instead. We use .x so that we don't lengthen the existing filename +# to more than 14 chars. +# +proc fortran-torture { args } { + global srcdir subdir + global compiler_conditional_xfail_data + global TORTURE_OPTIONS + + set src [lindex $args 0]; + if { [llength $args] > 1 } { + set options [lindex $args 1]; + } else { + set options "" + } + + # Prepend $srdir/$subdir if missing. + if ![string match "*/*" $src] { + set src "$srcdir/$subdir/$src" + } + + # Check for alternate driver. + if [file exists [file rootname $src].x] { + verbose "Using alternate driver [file rootname [file tail $src]].x" 2 + set done_p 0 + catch "set done_p \[source [file rootname $src].x\]" + if { $done_p } { + return + } + } + + # loop through all the options + set option_list $TORTURE_OPTIONS + foreach option $option_list { + + # torture_compile_xfail is set by the .x script (if present) + if [info exists torture_compile_xfail] { + setup_xfail $torture_compile_xfail + } + + # torture_execute_before_compile is set by the .x script (if present) + if [info exists torture_eval_before_compile] { + set ignore_me [eval $torture_eval_before_compile] + } + + fortran-torture-compile $src "$option $options" + } +} + diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp index 7977893cae6..803d609068f 100644 --- a/gcc/testsuite/lib/gcc-dg.exp +++ b/gcc/testsuite/lib/gcc-dg.exp @@ -18,6 +18,7 @@ load_lib dg.exp load_lib file-format.exp load_lib target-supports.exp load_lib scanasm.exp +load_lib scantree.exp load_lib prune.exp if ![info exists TORTURE_OPTIONS] { diff --git a/gcc/testsuite/lib/gfortran.exp b/gcc/testsuite/lib/gfortran.exp new file mode 100644 index 00000000000..483c3893a79 --- /dev/null +++ b/gcc/testsuite/lib/gfortran.exp @@ -0,0 +1,233 @@ +# Copyright (C) 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# This file is just 'sed -e 's/77/fortran/g' \ +# -e 's/f2c/gfortran' g77.exp > gfortran.exp' +# +# with some minor modifications to make it work. + +# +# gfortran support library routines +# +load_lib prune.exp +load_lib gcc-defs.exp + +# +# GFORTRAN_UNDER_TEST is the compiler under test. +# + + +set gpp_compile_options "" + + +# +# gfortran_version -- extract and print the version number of the compiler +# + +proc gfortran_version { } { + global GFORTRAN_UNDER_TEST + + gfortran_init + + # ignore any arguments after the command + set compiler [lindex $GFORTRAN_UNDER_TEST 0] + + # verify that the compiler exists + if { [is_remote host] || [which $compiler] != 0 } then { + set tmp [remote_exec host "$compiler -v"] + set status [lindex $tmp 0]; + set output [lindex $tmp 1]; + regexp "version.*$" $output version + if { $status == 0 && [info exists version] } then { + if [is_remote host] { + clone_output "$compiler $version\n" + } else { + clone_output "[which $compiler] $version\n" + } + } else { + clone_output "Couldn't determine version of [which $compiler]\n" + } + } else { + # compiler does not exist (this should have already been detected) + warning "$compiler does not exist" + } +} + +# +# gfortran_link_flags -- provide new version of gfortran_link_flags +# (originally from libgloss.exp) which knows about the gcc tree structure +# + +proc gfortran_link_flags { paths } { + global rootme + global srcdir + global ld_library_path + global GFORTRAN_UNDER_TEST + + set gccpath ${paths} + set libio_dir "" + set flags "" + set ld_library_path "." + + if { $gccpath != "" } { + if [file exists "${gccpath}/libgfortran/.libs/libgfortran.a"] { + append flags "-L${gccpath}/libgfortran/.libs " + append ld_library_path ":${gccpath}/libgfortran/.libs" + } + if [file exists "${gccpath}/libgfortran/libgforbegin.a"] { + append flags "-L${gccpath}/libgfortran " + } + if [file exists "${gccpath}/libiberty/libiberty.a"] { + append flags "-L${gccpath}/libiberty " + } + append ld_library_path ":${rootme}" + set compiler [lindex $GFORTRAN_UNDER_TEST 0] + if { [is_remote host] == 0 && [which $compiler] != 0 } { + foreach i "[exec $compiler --print-multi-lib]" { + set mldir "" + regexp -- "\[a-z0-9=/\.-\]*;" $i mldir + set mldir [string trimright $mldir "\;@"] + if { "$mldir" == "." } { + continue + } + if { [llength [glob -nocomplain ${rootme}/${mldir}/libgcc_s*.so.*]] == 1 } { + append ld_library_path ":${rootme}/${mldir}" + } + } + } + } + + # On IRIX 6, we have to set variables akin to LD_LIBRARY_PATH, but + # called LD_LIBRARYN32_PATH (for the N32 ABI) and LD_LIBRARY64_PATH + # (for the 64-bit ABI). The right way to do this would be to modify + # unix.exp -- but that's not an option since it's part of DejaGNU + # proper, so we do it here. + # The same applies to Darwin (DYLD_LIBRARY_PATH), Solaris 32 bit + # (LD_LIBRARY_PATH_32), Solaris 64 bit (LD_LIBRARY_PATH_64), and HP-UX + # (SHLIB_PATH). + # Doing this does cause trouble when testing cross-compilers. + if {![is_remote target]} { + global env; + if { [info exists env(LD_LIBRARY_PATH)] + && $env(LD_LIBRARY_PATH) != "" } { + append ld_library_path ":$env(LD_LIBRARY_PATH)"; + } + setenv LD_LIBRARY_PATH $ld_library_path + setenv SHLIB_PATH $ld_library_path + setenv LD_LIBRARYN32_PATH $ld_library_path + setenv LD_LIBRARY64_PATH $ld_library_path + setenv LD_LIBRARY_PATH_32 $ld_library_path + setenv LD_LIBRARY_PATH_64 $ld_library_path + setenv DYLD_LIBRARY_PATH $ld_library_path + } + + return "$flags" +} + +# +# gfortran_init -- called at the start of each subdir of tests +# + +proc gfortran_init { args } { + global subdir + global gpp_initialized + global base_dir + global tmpdir + global libdir + global gluefile wrap_flags; + global objdir srcdir + global ALWAYS_GFORTRANFLAGS + global TOOL_EXECUTABLE TOOL_OPTIONS + global GFORTRAN_UNDER_TEST + global TESTING_IN_BUILD_TREE + + if ![info exists GFORTRAN_UNDER_TEST] then { + if [info exists TOOL_EXECUTABLE] { + set GFORTRAN_UNDER_TEST $TOOL_EXECUTABLE; + } else { + if { [is_remote host] || ! [info exists TESTING_IN_BUILD_TREE] } { + set GFORTRAN_UNDER_TEST [transform gfortran] + } else { + set GFORTRAN_UNDER_TEST [findfile $base_dir/../gfortran "$base_dir/../gfortran -B$base_dir/../" [findfile $base_dir/gfortran "$base_dir/gfortran -B$base_dir/" [transform gfortran]]] + } + } + } + + if ![is_remote host] { + if { [which $GFORTRAN_UNDER_TEST] == 0 } then { + perror "GFORTRAN_UNDER_TEST ($GFORTRAN_UNDER_TEST) does not exist" + exit 1 + } + } + if ![info exists tmpdir] { + set tmpdir "/tmp" + } + + if [info exists gluefile] { + unset gluefile + } + + if { [target_info needs_status_wrapper] != "" } { + set gluefile ${tmpdir}/gfortran-testglue.o; + set result [build_wrapper $gluefile]; + if { $result != "" } { + set gluefile [lindex $result 0]; + set wrap_flags [lindex $result 1]; + } else { + unset gluefile + } + } + + set ALWAYS_GFORTRANFLAGS "" + + if ![is_remote host] { + if [info exists TOOL_OPTIONS] { + lappend ALWAYS_GFORTRANFLAGS "ldflags=[gfortran_link_flags [get_multilibs ${TOOL_OPTIONS}] ]"; + } else { + lappend ALWAYS_GFORTRANFLAGS "ldflags=[gfortran_link_flags [get_multilibs] ]"; + } + } + + if [info exists TOOL_OPTIONS] { + lappend ALWAYS_GFORTRANFLAGS "additional_flags=$TOOL_OPTIONS"; + } + + verbose -log "ALWAYS_GFORTRANFLAGS set to $ALWAYS_GFORTRANFLAGS" + + verbose "gfortran is initialized" 3 +} + +# +# gfortran_target_compile -- compile a source file +# + +proc gfortran_target_compile { source dest type options } { + global tmpdir; + global gluefile wrap_flags + global ALWAYS_GFORTRANFLAGS; + global GFORTRAN_UNDER_TEST; + + if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } { + lappend options "libs=${gluefile}" + lappend options "ldflags=${wrap_flags}" + } + + lappend options "compiler=$GFORTRAN_UNDER_TEST"; + + set options [concat "$ALWAYS_GFORTRANFLAGS" $options]; + + return [target_compile $source $dest $type $options] +} diff --git a/gcc/testsuite/lib/scantree.exp b/gcc/testsuite/lib/scantree.exp new file mode 100644 index 00000000000..76d1a59fb60 --- /dev/null +++ b/gcc/testsuite/lib/scantree.exp @@ -0,0 +1,243 @@ +# Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Various utilities for scanning tree dump output, used by gcc-dg.exp and +# g++-dg.exp. +# +# This is largely borrowed from scanasm.exp. + +# Utility for scanning compiler result, invoked via dg-final. +# Call pass if pattern is present, otherwise fail. +# +# Argument 0 is the regexp to match. +# Argument 1 is the suffix for the tree dump file +# Argument 2 handles expected failures and the like +proc scan-tree-dump { args } { + if { [llength $args] < 2 } { + error "scan-tree-dump: too few arguments" + return + } + if { [llength $args] > 3 } { + error "scan-tree-dump: too many arguments" + return + } + if { [llength $args] >= 3 } { + switch [dg-process-target [lindex $args 2]] { + "S" { } + "N" { return } + "F" { setup_xfail "*-*-*" } + "P" { } + } + } + + # This assumes that we are two frames down from dg-test, and that + # it still stores the filename of the testcase in a local variable "name". + # A cleaner solution would require a new dejagnu release. + upvar 2 name testcase + + # This must match the rule in gcc-dg.exp. + set output_file "[glob [file tail $testcase].t??.[lindex $args 1]]" + + set fd [open $output_file r] + set text [read $fd] + close $fd + + if [regexp -- [lindex $args 0] $text] { + pass "$testcase scan-tree-dump [lindex $args 0]" + } else { + fail "$testcase scan-tree-dump [lindex $args 0]" + } +} + +# Call pass if pattern is present given number of times, otherwise fail. +# Argument 0 is the regexp to match. +# Argument 1 is number of times the regexp must be found +# Argument 2 is the suffix for the tree dump file +# Argument 3 handles expected failures and the like +proc scan-tree-dump-times { args } { + if { [llength $args] < 3 } { + error "scan-tree-dump: too few arguments" + return + } + if { [llength $args] > 4 } { + error "scan-tree-dump: too many arguments" + return + } + if { [llength $args] >= 4 } { + switch [dg-process-target [lindex $args 3]] { + "S" { } + "N" { return } + "F" { setup_xfail "*-*-*" } + "P" { } + } + } + + # This assumes that we are two frames down from dg-test, and that + # it still stores the filename of the testcase in a local variable "name". + # A cleaner solution would require a new dejagnu release. + upvar 2 name testcase + + # This must match the rule in gcc-dg.exp. + set output_file "[glob [file tail $testcase].t??.[lindex $args 2]]" + + set fd [open $output_file r] + set text [read $fd] + close $fd + + if { [llength [regexp -inline -all -- [lindex $args 0] $text]] == [lindex $args 1]} { + pass "$testcase scan-tree-dump-times [lindex $args 0] [lindex $args 1]" + } else { + fail "$testcase scan-tree-dump-times [lindex $args 0] [lindex $args 1]" + } +} + +# Call pass if pattern is not present, otherwise fail. +# +# Argument 0 is the regexp to match. +# Argument 1 is the suffix for the tree dump file +# Argument 2 handles expected failures and the like +proc scan-tree-dump-not { args } { + if { [llength $args] < 2 } { + error "scan-tree-dump-not: too few arguments" + return + } + if { [llength $args] > 3 } { + error "scan-tree-dump-not: too many arguments" + return + } + if { [llength $args] >= 3 } { + switch [dg-process-target [lindex $args 2]] { + "S" { } + "N" { return } + "F" { setup_xfail "*-*-*" } + "P" { } + } + } + + upvar 2 name testcase + set output_file "[glob [file tail $testcase].t??.[lindex $args 1]]" + + set fd [open $output_file r] + set text [read $fd] + close $fd + + if ![regexp -- [lindex $args 0] $text] { + pass "$testcase scan-tree-dump-not [lindex $args 0]" + } else { + fail "$testcase scan-tree-dump-not [lindex $args 0]" + } +} + +# Utility for scanning demangled compiler result, invoked via dg-final. +# Call pass if pattern is present, otherwise fail. +# +# Argument 0 is the regexp to match. +# Argument 1 is the suffix for the tree dump file +# Argument 2 handles expected failures and the like +proc scan-tree-dump-dem { args } { + global cxxfilt + global base_dir + + if { [llength $args] < 2 } { + error "scan-tree-dump-dem: too few arguments" + return + } + if { [llength $args] > 3 } { + error "scan-tree-dump-dem: too many arguments" + return + } + if { [llength $args] >= 3 } { + switch [dg-process-target [lindex $args 2]] { + "S" { } + "N" { return } + "F" { setup_xfail "*-*-*" } + "P" { } + } + } + + # Find c++filt like we find g++ in g++.exp. + if ![info exists cxxfilt] { + set cxxfilt [findfile $base_dir/../../binutils/cxxfilt \ + $base_dir/../../binutils/cxxfilt \ + [findfile $base_dir/../c++filt $base_dir/../c++filt \ + [findfile $base_dir/c++filt $base_dir/c++filt \ + [transform c++filt]]]] + verbose -log "c++filt is $cxxfilt" + } + + upvar 2 name testcase + set output_file "[glob [file tail $testcase].t??.[lindex $args 1]]" + + set fd [open "| $cxxfilt < $output_file" r] + set text [read $fd] + close $fd + + if [regexp -- [lindex $args 0] $text] { + pass "$testcase scan-tree-dump-dem [lindex $args 0]" + } else { + fail "$testcase scan-tree-dump-dem [lindex $args 0]" + } +} + +# Call pass if demangled pattern is not present, otherwise fail. +# +# Argument 0 is the regexp to match. +# Argument 1 is the suffix for the tree dump file +# Argument 2 handles expected failures and the like +proc scan-tree-dump-dem-not { args } { + global cxxfilt + global base_dir + + if { [llength $args] < 2 } { + error "scan-tree-dump-dem-not: too few arguments" + return + } + if { [llength $args] > 3 } { + error "scan-tree-dump-dem-not: too many arguments" + return + } + if { [llength $args] >= 3 } { + switch [dg-process-target [lindex $args 2]] { + "S" { } + "N" { return } + "F" { setup_xfail "*-*-*" } + "P" { } + } + } + + # Find c++filt like we find g++ in g++.exp. + if ![info exists cxxfilt] { + set cxxfilt [findfile $base_dir/../../binutils/cxxfilt \ + $base_dir/../../binutils/cxxfilt \ + [findfile $base_dir/../c++filt $base_dir/../c++filt \ + [findfile $base_dir/c++filt $base_dir/c++filt \ + [transform c++filt]]]] + verbose -log "c++filt is $cxxfilt" + } + + upvar 2 name testcase + set output_file "[glob [file tail $testcase].t??.[lindex $args 1]]" + + set fd [open "| $cxxfilt < $output_file" r] + set text [read $fd] + close $fd + + if ![regexp -- [lindex $args 0] $text] { + pass "$testcase scan-tree-dump-dem-not [lindex $args 0]" + } else { + fail "$testcase scan-tree-dump-dem-not [lindex $args 0]" + } +} diff --git a/gcc/testsuite/treelang/compile/compile.exp b/gcc/testsuite/treelang/compile/compile.exp deleted file mode 100644 index 836c3251099..00000000000 --- a/gcc/testsuite/treelang/compile/compile.exp +++ /dev/null @@ -1,31 +0,0 @@ -# Tests for treelang; run from gcc/treelang/Make-lang.in => gcc/Makefile - -# Copyright (C) 2004 by The 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 2, or (at your option) any -# later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. -# -# In other words, you are welcome to use, share and improve this program. -# You are forbidden to forbid anyone else to use, share and improve -# what you give them. Help stamp out software-hoarding! - -# Treelang tests that only need to compile. - -# Load support procs. -load_lib treelang-dg.exp - -dg-init -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.tree]] "" "" -dg-finish diff --git a/gcc/testsuite/treelang/compile/tabs.tree b/gcc/testsuite/treelang/compile/tabs.tree deleted file mode 100644 index 6294c15c49a..00000000000 --- a/gcc/testsuite/treelang/compile/tabs.tree +++ /dev/null @@ -1,11 +0,0 @@ -// { dg-do compile } -external_definition int main(int argc); - -main { - automatic int v1; - automatic int v2; - v1 = argc; - v2 = 3; - - return v2; -} diff --git a/gcc/timevar.def b/gcc/timevar.def index c7ccd53a484..ec942588c0e 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -59,12 +59,41 @@ DEFTIMEVAR (TV_CPP , "preprocessing") DEFTIMEVAR (TV_LEX , "lexical analysis") DEFTIMEVAR (TV_PARSE , "parser") DEFTIMEVAR (TV_NAME_LOOKUP , "name lookup") +DEFTIMEVAR (TV_INTEGRATION , "integration") +DEFTIMEVAR (TV_TREE_GIMPLIFY , "tree gimplify") +DEFTIMEVAR (TV_TREE_EH , "tree eh") +DEFTIMEVAR (TV_TREE_CFG , "tree CFG construction") +DEFTIMEVAR (TV_TREE_CLEANUP_CFG , "tree CFG cleanup") +DEFTIMEVAR (TV_TREE_PTA , "tree PTA") +DEFTIMEVAR (TV_TREE_MAY_ALIAS , "tree alias analysis") +DEFTIMEVAR (TV_TREE_INSERT_PHI_NODES , "tree PHI insertion") +DEFTIMEVAR (TV_TREE_SSA_REWRITE_BLOCKS, "tree SSA rewrite") +DEFTIMEVAR (TV_TREE_SSA_OTHER , "tree SSA other") +DEFTIMEVAR (TV_TREE_OPS , "tree operand scan") +DEFTIMEVAR (TV_TREE_SSA_DOMINATOR_OPTS , "dominator optimization") +DEFTIMEVAR (TV_TREE_SRA , "tree SRA") +DEFTIMEVAR (TV_TREE_CCP , "tree CCP") +DEFTIMEVAR (TV_TREE_SPLIT_EDGES , "tree split crit edges") +DEFTIMEVAR (TV_TREE_PRE , "tree PRE") +DEFTIMEVAR (TV_TREE_PHIOPT , "tree linearize phis") +DEFTIMEVAR (TV_TREE_FORWPROP , "tree forward propagate") +DEFTIMEVAR (TV_TREE_DCE , "tree conservative DCE") +DEFTIMEVAR (TV_TREE_CD_DCE , "tree aggressive DCE") +DEFTIMEVAR (TV_TREE_DSE , "tree DSE") +DEFTIMEVAR (TV_TREE_LOOP , "tree loop optimization") +DEFTIMEVAR (TV_TREE_CH , "tree copy headers") +DEFTIMEVAR (TV_TREE_SSA_TO_NORMAL , "tree SSA to normal") +DEFTIMEVAR (TV_TREE_NRV , "tree NRV optimization") +DEFTIMEVAR (TV_TREE_COPY_RENAME , "tree rename SSA copies") +DEFTIMEVAR (TV_TREE_SSA_VERIFY , "tree SSA verifier") +DEFTIMEVAR (TV_TREE_STMT_VERIFY , "tree STMT verifier") +DEFTIMEVAR (TV_CGRAPH_VERIFY , "callgraph verifier") +DEFTIMEVAR (TV_DOM_FRONTIERS , "dominance frontiers") +DEFTIMEVAR (TV_CONTROL_DEPENDENCES , "control dependences") DEFTIMEVAR (TV_OVERLOAD , "overload resolution") DEFTIMEVAR (TV_TEMPLATE_INSTANTIATION, "template instantiation") -DEFTIMEVAR (TV_CGRAPH_VERIFY , "callgraph verifier") DEFTIMEVAR (TV_EXPAND , "expand") DEFTIMEVAR (TV_VARCONST , "varconst") -DEFTIMEVAR (TV_INTEGRATION , "integration") DEFTIMEVAR (TV_JUMP , "jump") DEFTIMEVAR (TV_CSE , "CSE") DEFTIMEVAR (TV_GCSE , "global CSE") diff --git a/gcc/toplev.c b/gcc/toplev.c index 046501846f2..c15ab99f910 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -73,6 +73,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "target.h" #include "langhooks.h" #include "cfglayout.h" +#include "tree-alias-common.h" #include "cfgloop.h" #include "hosthooks.h" #include "cgraph.h" @@ -219,6 +220,11 @@ tree current_function_decl; if none. */ tree current_function_func_begin_label; +/* A DECL for the current file-scope context. When using IMA, this heads a + chain of FILE_DECLs; currently only C uses it. */ + +tree current_file_decl; + /* Nonzero if doing dwarf2 duplicate elimination. */ int flag_eliminate_dwarf2_dups = 0; @@ -789,6 +795,11 @@ int flag_guess_branch_prob = 0; For Fortran: defaults to off. */ int flag_bounds_check = 0; +/* Mudflap bounds-checking transform. */ +int flag_mudflap = 0; +int flag_mudflap_threads = 0; +int flag_mudflap_ignore_reads = 0; + /* This will attempt to merge constant section constants, if 1 only string constants and constants from constant pool, if 2 also constant variables. */ @@ -802,8 +813,49 @@ int flag_renumber_insns = 1; /* If nonzero, use the graph coloring register allocator. */ int flag_new_regalloc = 0; -/* Nonzero if we perform superblock formation. */ +/* If nonzero, use tree-based instead of rtl-based profiling. */ +int flag_tree_based_profiling = 0; + +/* Enable SSA-GVN on trees. */ +int flag_tree_gvn = 0; + +/* Enable the SSA-PRE tree optimization. */ +int flag_tree_pre = 0; + +/* Enable points-to analysis on trees. */ +enum pta_type flag_tree_points_to = PTA_NONE; + +/* Enable SSA-CCP on trees. */ +int flag_tree_ccp = 0; + +/* Enable SSA-DCE on trees. */ +int flag_tree_dce = 0; + +/* Enable loop header copying on tree-ssa. */ +int flag_tree_ch = 0; + +/* Enable scalar replacement of aggregates. */ +int flag_tree_sra = 0; +/* Enable SSA->normal pass memory location coalescing. */ +int flag_tree_combine_temps = 0; + +/* Enable SSA->normal pass expression replacement. */ +int flag_tree_ter = 0; + +/* Enable SSA->normal live range splitting. */ +int flag_tree_live_range_split = 0; + +/* Enable dominator optimizations. */ +int flag_tree_dom = 0; + +/* Enable copy rename optimization. */ +int flag_tree_copyrename = 0; + +/* Enable dead store elimination. */ +int flag_tree_dse = 0; + +/* Nonzero if we perform superblock formation. */ int flag_tracer = 0; /* Nonzero if we perform whole unit at a time compilation. */ @@ -970,6 +1022,7 @@ static const lang_independent_options f_options[] = {"test-coverage", &flag_test_coverage, 1 }, {"branch-probabilities", &flag_branch_probabilities, 1 }, {"profile", &profile_flag, 1 }, + {"tree-based-profiling", &flag_tree_based_profiling, 1 }, {"reorder-blocks", &flag_reorder_blocks, 1 }, {"reorder-blocks-and-partition", &flag_reorder_blocks_and_partition, 1}, {"reorder-functions", &flag_reorder_functions, 1 }, @@ -1014,7 +1067,18 @@ static const lang_independent_options f_options[] = { "trapv", &flag_trapv, 1 }, { "wrapv", &flag_wrapv, 1 }, { "new-ra", &flag_new_regalloc, 1 }, - { "var-tracking", &flag_var_tracking, 1} + { "var-tracking", &flag_var_tracking, 1}, + { "tree-gvn", &flag_tree_gvn, 1 }, + { "tree-pre", &flag_tree_pre, 1 }, + { "tree-ccp", &flag_tree_ccp, 1 }, + { "tree-dce", &flag_tree_dce, 1 }, + { "tree-dominator-opts", &flag_tree_dom, 1 }, + { "tree-copyrename", &flag_tree_copyrename, 1 }, + { "tree-dse", &flag_tree_dse, 1 }, + { "tree-combine-temps", &flag_tree_combine_temps, 1 }, + { "tree-ter", &flag_tree_ter, 1 }, + { "tree-lrs", &flag_tree_live_range_split, 1 }, + { "tree-ch", &flag_tree_ch, 1 } }; /* Here is a table, controlled by the tm.h file, listing each -m switch @@ -1411,18 +1475,6 @@ wrapup_global_declarations (tree *vec, int len) rest_of_decl_compilation (decl, NULL, 1, 1); } } - - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) != 0 - && DECL_STRUCT_FUNCTION (decl) != 0 - && DECL_STRUCT_FUNCTION (decl)->saved_for_inline - && (flag_keep_inline_functions - || (TREE_PUBLIC (decl) && !DECL_COMDAT (decl)) - || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) - { - reconsider = 1; - output_inline_function (decl); - } } if (reconsider) @@ -2215,6 +2267,7 @@ general_init (const char *argv0) /* This must be done after add_params but before argument processing. */ init_ggc_heuristics(); + init_tree_optimization_passes (); } /* Process the options that have been parsed. */ @@ -2315,6 +2368,11 @@ process_options (void) warning ("this target machine does not have delayed branches"); #endif + if (flag_tree_based_profiling && flag_test_coverage) + sorry ("test-coverage not yet implemented in trees."); + if (flag_tree_based_profiling && flag_profile_values) + sorry ("value-based profiling not yet implemented in trees."); + user_label_prefix = USER_LABEL_PREFIX; if (flag_leading_underscore != -1) { @@ -2488,9 +2546,9 @@ process_options (void) warning ("-ffunction-sections may affect debugging on some targets"); #endif - /* The presence of IEEE signaling NaNs, implies all math can trap. */ - if (flag_signaling_nans) - flag_trapping_math = 1; + /* The presence of IEEE signaling NaNs, implies all math can trap. */ + if (flag_signaling_nans) + flag_trapping_math = 1; } /* Initialize the compiler back end. */ diff --git a/gcc/toplev.h b/gcc/toplev.h index 91fea9e253c..daad92fa10e 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -68,6 +68,7 @@ extern void rest_of_decl_compilation (tree, const char *, int, int); extern void rest_of_type_compilation (tree, int); extern void rest_of_compilation (tree); extern void tree_rest_of_compilation (tree, bool); +extern void init_tree_optimization_passes (void); extern void init_optimization_passes (void); extern void finish_optimization_passes (void); extern bool enable_rtl_dump_file (int); @@ -124,6 +125,7 @@ extern int flag_unswitch_loops; extern int flag_cprop_registers; extern int time_report; extern int flag_new_regalloc; +extern int flag_tree_based_profiling; /* Things to do with target switches. */ extern void display_target_options (void); diff --git a/gcc/tracer.c b/gcc/tracer.c index 1e23a8e236a..9635737ff53 100644 --- a/gcc/tracer.c +++ b/gcc/tracer.c @@ -271,7 +271,7 @@ tail_duplicate (void) } traced_insns += bb2->frequency * counts [bb2->index]; if (bb2->pred && bb2->pred->pred_next - && cfg_layout_can_duplicate_bb_p (bb2)) + && can_duplicate_block_p (bb2)) { edge e = bb2->pred; basic_block old = bb2; @@ -279,7 +279,7 @@ tail_duplicate (void) while (e->src != bb) e = e->pred_next; nduplicated += counts [bb2->index]; - bb2 = cfg_layout_duplicate_bb (bb2, e); + bb2 = duplicate_block (bb2, e); /* Reconsider the original copy of block we've duplicated. Removing the most common predecessor may make it to be diff --git a/gcc/tree-alias-ander.c b/gcc/tree-alias-ander.c new file mode 100644 index 00000000000..b3b14d1fa12 --- /dev/null +++ b/gcc/tree-alias-ander.c @@ -0,0 +1,933 @@ +/* Tree based Andersen points-to analysis + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Daniel Berlin + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "ggc.h" +#include "bitmap.h" +#include "tree-alias-type.h" +#include "tree-alias-ander.h" +#include "flags.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "expr.h" +#include "diagnostic.h" +#include "tree.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "varray.h" +#include "tree-simple.h" +#include "splay-tree.h" +#include "engine/util.h" +#include "libcompat/regions.h" +#include "andersen_terms.h" +#include "cgraph.h" +#include "tree-pass.h" + + +/* Andersen's interprocedural points-to analysis. + This is a flow-insensitive, context insensitive algorithm. + + This file is an implementation of the alias_ops structure used by + tree-alias-common.c to drive PTA analysis. + + All these functions do is generate constraints for and through + libbanshee. When we query for a points-to set, we ask libbanshee + to solve the constraints and give us the answer. The terms of the + constraints are the aterms, which are an opaque data structure + that stores libbanshee specific data for the constraints. + + The constraints to be generated come from andersen's paper. By + constraint, we mean something like "the points-to set of A must be + a subset or equal to the points-to set of B" or "the points-to set + of A must include Q". In order to avoid having to write all the + constraints directly in the code, we use helper functions such as + pta_assignment, pta_rvalue, etc, that generate the necessary + constraint terms for us, making for much more readable code. + + One could replace libbanshee with some other constraint solving + engine, and you'd simply have to replace the implementation of the + pta_* functions, and provide replacements for the aterm specific + functions (like making a list of aterms, printing the label of an + aterm). However, libbanshee is extremely fast, and extremely low + memory usage, so one would be hard pressed to do better than it + anyway. + + Understanding how constraint solving and what each constraint means is + beyond the scope of this documentation. See the libbanshee + documentation, and references therein for more enlightenment. + + That said, our constraints inclusion constraints of set + expressions. Given the helper functions, the various inference + functions we implement should *look* relatively straightforward. + + In order to save time during queries, we cache the resulting + points-to sets of each variable, rather than recalculate them + again and again. (libbanshee actually has it's own internal + caching, but the function call overhead for calling the solver is + non-trivial, given the number of queries). + + Todo: Don't pass alias ops as first argument, just have a global + "current_alias_ops". */ + +static unsigned int id_num = 1; +static region andersen_rgn; +static void andersen_simple_assign (struct tree_alias_ops *, + alias_var, alias_var); +static void andersen_addr_assign (struct tree_alias_ops *, + alias_var, alias_var); +static void andersen_ptr_assign (struct tree_alias_ops *, + alias_var, alias_var); +static void andersen_op_assign (struct tree_alias_ops *, + alias_var, varray_type, tree, bitmap); +static void andersen_heap_assign (struct tree_alias_ops *, alias_var); +static void andersen_assign_ptr (struct tree_alias_ops *, + alias_var, alias_var); +static void andersen_function_def (struct tree_alias_ops *, alias_var, + varray_type, alias_var); +static int andersen_function_call (struct tree_alias_ops *, alias_var, + alias_var, varray_type, bitmap); +static void andersen_init (struct tree_alias_ops *); +static int print_out_result (splay_tree_node, void *); +static void andersen_cleanup (struct tree_alias_ops *); +static bool andersen_may_alias (struct tree_alias_ops *, alias_var, + alias_var); +static bool andersen_same_points_to_set (struct tree_alias_ops *, + alias_var, alias_var); +static bool andersen_empty_points_to_set (struct tree_alias_ops *, + alias_var); +static alias_var andersen_add_var (struct tree_alias_ops *, tree); +static alias_var andersen_add_var_same (struct tree_alias_ops *, + tree, alias_var); +static bool pointer_destroying_op (tree); +static aterm_list get_ptset (alias_var); +static splay_tree ptamap; + + +static struct tree_alias_ops andersen_ops = { + andersen_init, + andersen_cleanup, + andersen_add_var, + andersen_add_var_same, + andersen_simple_assign, + andersen_addr_assign, + andersen_ptr_assign, + andersen_op_assign, + andersen_heap_assign, + andersen_assign_ptr, + andersen_function_def, + andersen_function_call, + andersen_may_alias, + andersen_same_points_to_set, + andersen_empty_points_to_set, + 0, /* data */ + 0, /* Currently non-interprocedural */ + 1 /* Can do IP on all statics without help. */ +}; +struct tree_alias_ops *andersen_alias_ops = &andersen_ops; + +static void term_inclusion (aterm, aterm); +static void pta_init (void); +static void pta_reset (void); +static aterm get_ref (aterm); +static argterm fun_rec_aterm (aterm_list); +static aterm pta_make_lam (const char *, aterm, aterm_list); +static aterm pta_make_ref (const char *); +static aterm pta_bottom (void); +static aterm pta_join (aterm, aterm); +static aterm pta_deref (aterm); +static aterm pta_rvalue (aterm); +static aterm pta_address (aterm); +static void pta_assignment (aterm, aterm); +static aterm pta_make_fun (const char *, aterm, aterm_list); +static aterm pta_application (aterm, aterm_list); + +typedef aterm contents_type; +static contents_type pta_get_contents (aterm); +static void pr_ptset_aterm_elem (aterm); +static void pta_pr_ptset (contents_type); + +/* Hook for debugging. This function is called instead of + aterm_inclusion, and lets us print the actual constraints as they + are generated. */ + +static void +term_inclusion (aterm t1, aterm t2) +{ + if (dump_file) + { + fprintf (dump_file, "Constraint: "); + aterm_print (dump_file, t1); + fprintf (dump_file, " <= "); + aterm_print (dump_file, t2); + fprintf (dump_file, "\n"); + } + + aterm_inclusion (t1, t2); +} + +/* Initialize libbanshee's constraint engine. */ + +static void +pta_init (void) +{ + andersen_terms_init (); +} + +/* Reset libbanshee's constraint engine. We do this when we are done + using it, as it releases the memory libbanshee is using. */ + +static void +pta_reset (void) +{ + andersen_terms_reset (); +} + +static aterm +get_ref (aterm t) +{ + struct ref_decon r_decon; + r_decon = ref_decon (t); + + assert (r_decon.f1); + + return r_decon.f1; +} + +/* Make a function record out of the arguments. */ + +static argterm +fun_rec_aterm (aterm_list args) +{ + region scratch; + int counter = 0; + argterm rest, result; + aterm_list_scanner scan; + aterm temp; + char field_name[512]; + argterm_map map; + + scratch = newregion (); + map = new_argterm_map (scratch); + aterm_list_scan (args, &scan); + while (aterm_list_next (&scan, &temp)) + { + snprintf (field_name, 512, "%d", counter++); + argterm_map_cons (argterm_make_field (field_name, temp), map); + } + + rest = argterm_wild (); + /* rest = argterm_fresh(); */ + + /* safe since field_add makes a copy of the string*/ + result = argterm_row (map, rest); + + deleteregion (scratch); + + return result; +} + + +static aterm +pta_make_lam (const char *id, aterm ret, aterm_list args) +{ + return lam (label_term_constant (id), fun_rec_aterm (args), ret); +} + +/* Make a label reference to the given id. */ + +static aterm +pta_make_ref (const char *id) +{ + + aterm var = aterm_fresh (id); + + label_term tag = label_term_constant (id); + + return ref (tag, var, var); +} + +/* Return the empty set. */ + +static aterm +pta_bottom (void) +{ + return aterm_zero (); +} + +/* Join two terms, such that anything in set t1 will also be in set + t2, and vice versa. */ + +static aterm +pta_join (aterm t1, aterm t2) +{ + aterm result; + region scratch_rgn = newregion (); + aterm_list list = new_aterm_list (scratch_rgn); + + aterm_list_cons (t1, list); + aterm_list_cons (t2, list); + + + result = aterm_union (list); + deleteregion (scratch_rgn); + + return result; +} + +/* Generate the constraint for a dereference of term t1. */ + +static aterm +pta_deref (aterm t1) +{ + return ref_proj2 (t1); +} + +/* Generate the constraint for t1 being an rvalue. */ + +static aterm +pta_rvalue (aterm t1) +{ + return pta_deref (t1); +} + +/* Generate the constraint for taking the address of t1. */ + +static aterm +pta_address (aterm t1) +{ + return ref (label_term_one (), aterm_one (), t1); +} + +/* Generate the constraint for assigning t2 to t1. */ + +static void +pta_assignment (aterm t1, aterm t2) +{ + term_inclusion (t1, ref_pat1 (t2)); +} + +/* Make a function from the given name, return value, and arguments. */ + +static aterm +pta_make_fun (const char *name, aterm ret, aterm_list args) +{ + aterm temp; + aterm_list_scanner scan; + region scratch_rgn = newregion (); + aterm_list arg_list = new_aterm_list (scratch_rgn); + + aterm_list_scan (args, &scan); + + while (aterm_list_next (&scan, &temp)) + { + aterm_list_cons (get_ref (temp), arg_list); + } + + return pta_make_lam (name, get_ref (ret), arg_list); +} + +/* Return the constraint for calling function T with arguments + ACTUALS. */ + +static aterm +pta_application (aterm t, aterm_list actuals) +{ + argterm args = fun_rec_aterm (actuals); + + term_inclusion (t, lam_pat1 (args)); + return pta_address (lam_proj2 (t)); +} + +/* Return the contents of set expression T. */ + +static contents_type +pta_get_contents (aterm t) +{ + struct ref_decon t_decon; + t_decon = ref_decon (t); + + return t_decon.f1; +} + +/* Print out a points-to set element. */ + +static void +pr_ptset_aterm_elem (aterm t) +{ + struct ref_decon ref; + struct lam_decon lam; + + ref = ref_decon (t); + lam = lam_decon (t); + + fprintf (dump_file, ","); + if (ref.f0) + label_term_print (dump_file, ref.f0); + else if (lam.f0) + label_term_print (dump_file, lam.f0); +} + + +/* Print out a points-to set. */ + +static void +pta_pr_ptset (contents_type t) +{ + int size; + region scratch_rgn; + aterm_list ptset; + scratch_rgn = newregion (); + ptset = aterm_list_copy (scratch_rgn, aterm_tlb (t)); + + size = aterm_list_length (ptset); + + fprintf (dump_file, "{"); + if (!aterm_list_empty (ptset)) + { + struct ref_decon ref; + struct lam_decon lam; + ref = ref_decon (aterm_list_head (ptset)); + lam = lam_decon (aterm_list_head (ptset)); + if (ref.f0) + label_term_print (dump_file, ref.f0); + else if (lam.f0) + label_term_print (dump_file, lam.f0); + + /* aterm_pr(stdout,aterm_hd(ptset)); */ + ptset = aterm_list_tail (ptset); + } + aterm_list_app (ptset, pr_ptset_aterm_elem); + fprintf (dump_file, "}(%d)\n", size); + deleteregion (scratch_rgn); +} + +/* Initialize Andersen alias analysis. */ +static int initted = 0; + +static void +andersen_init (struct tree_alias_ops *ops ATTRIBUTE_UNUSED) +{ +#if 0 + /* Don't claim we can do ip partial unless we have unit_at_a_time on. */ + if (!flag_unit_at_a_time) +#endif + andersen_ops.ip_partial = 0; + if (!initted || (!andersen_ops.ip_partial && !andersen_ops.ip)) + { + pta_init (); + andersen_rgn = newregion (); + initted = 1; + } + + ptamap = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); + +} + +static int +print_out_result (splay_tree_node node, void *data ATTRIBUTE_UNUSED) +{ + fprintf (dump_file, "%s :=", + alias_get_name (ALIAS_VAR_DECL (((alias_var) node->value)))); + pta_pr_ptset (pta_get_contents ((aterm) node->key)); + return 0; +} + +/* Cleanup after Andersen alias analysis. */ + +static void +andersen_cleanup (struct tree_alias_ops *ops ATTRIBUTE_UNUSED) +{ + if (dump_file) + { + if (dump_flags & TDF_STATS) + { + fprintf (dump_file, "\nPoints-to stats:\n"); + andersen_terms_stats (dump_file); + } + + fprintf (dump_file, "\nPoints-to sets:\n"); + splay_tree_foreach (ptamap, print_out_result, NULL); + } + + splay_tree_delete (ptamap); + + if (!andersen_ops.ip_partial && !andersen_ops.ip) + { + pta_reset (); + deleteregion (andersen_rgn); + andersen_rgn = NULL; + } +} + +/* Add decl to the analyzer, and return a var for it. For + Andersen, we create a new alias var for the declaration, and + return that. */ + +static alias_var +andersen_add_var (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, tree decl) +{ + alias_var ret; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Adding variable %s\n", + alias_get_name (decl)); + + if (alias_get_name (decl) != NULL) + { + ret = alias_var_new_with_aterm (decl, + pta_make_ref (alias_get_name (decl))); + } + else + { + char *tmp_name; + ASM_FORMAT_PRIVATE_NAME (tmp_name, "unnamed var", id_num++); + ret = alias_var_new_with_aterm (decl, pta_make_ref (tmp_name)); + } + splay_tree_insert (ptamap, (splay_tree_key) ALIAS_VAR_ATERM (ret), + (splay_tree_value) ret); + ALIAS_VAR_PTSET (ret) = NULL; + + return ret; +} + +/* Add a variable to the analyzer that is equivalent (as far as + aliases go) to some existing alias variable. + For Andersen, we just call a function that does this for us. */ + +static alias_var +andersen_add_var_same (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, tree decl, + alias_var tv) +{ + alias_var ret; + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Adding variable %s same as %s\n", + alias_get_name (decl), alias_get_name (ALIAS_VAR_DECL (tv))); + + if (alias_get_name (decl) != NULL) + ret = alias_var_new_with_aterm (decl, + pta_make_ref (alias_get_name (decl))); + else + { + char *tmp_name; + ASM_FORMAT_PRIVATE_NAME (tmp_name, "unnamed var", id_num++); + ret = alias_var_new_with_aterm (decl, pta_make_ref (tmp_name)); + } + + pta_join (ALIAS_VAR_ATERM (tv), ALIAS_VAR_ATERM (ret)); + splay_tree_insert (ptamap, (splay_tree_key) ALIAS_VAR_ATERM (ret), + (splay_tree_value) ret); + ALIAS_VAR_PTSET (tv) = NULL; + ALIAS_VAR_PTSET (ret) = NULL; + + return ret; +} + +/* Inference for simple assignment (lhs = rhs) */ + +static void +andersen_simple_assign (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var lhs, alias_var rhs) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Simple assignment %s = %s\n", + alias_get_name (ALIAS_VAR_DECL (lhs)), + alias_get_name (ALIAS_VAR_DECL (rhs))); + if (lhs == rhs) + return; + + /* The rvalue is just the term itself, and we generate a constraint + for assigning it to the lhs. */ + pta_assignment (ALIAS_VAR_ATERM (lhs), + pta_rvalue (ALIAS_VAR_ATERM (rhs))); +} + +/* Inference for address assignment (lhs = &addr) */ + +static void +andersen_addr_assign (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var lhs, alias_var addr) +{ + if (addr == NULL) + return; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Address assignment %s = &%s\n", + alias_get_name (ALIAS_VAR_DECL (lhs)), + alias_get_name (ALIAS_VAR_DECL (addr))); + + /* The rvalue here is the address of a term, and we generate a + constraint to assign this address to the lhs. */ + pta_assignment (ALIAS_VAR_ATERM (lhs), + pta_rvalue (pta_address (ALIAS_VAR_ATERM (addr)))); +} + + +/* Inference for pointer assignment (lhs = *ptr) */ + +static void +andersen_ptr_assign (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var lhs, alias_var ptr) +{ + + if (ptr == NULL) + return; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Pointer assignment %s = *%s\n", + alias_get_name (ALIAS_VAR_DECL (lhs)), + alias_get_name (ALIAS_VAR_DECL (ptr))); + + pta_assignment (ALIAS_VAR_ATERM (lhs), + pta_rvalue (pta_deref (ALIAS_VAR_ATERM (ptr)))); + +} + +/* Determine if OP destroys the current assumed to be valid pointer + (whether it generates a new valid pointer is not relevant). */ + +static bool +pointer_destroying_op (tree op) +{ + switch (TREE_CODE (op)) + { + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_NOT_EXPR: + case LT_EXPR: + case GT_EXPR: + case GE_EXPR: + case LE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + return true; + default: + return false; + } + return false; +} + +/* Inference rule for operations (lhs = operation(operands)). */ + +static void +andersen_op_assign (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var lhs, varray_type operands, tree operation, + bitmap addrargs) +{ + aterm newvar = NULL; + + if (VARRAY_ACTIVE_SIZE (operands) == 0) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Op assignment %s = ", + alias_get_name (ALIAS_VAR_DECL (lhs))); + print_generic_stmt (dump_file, operation, dump_flags); + fprintf (dump_file, "\n"); + } + + + /* Pointer destroying operations do not give us the same valid pointer + back, and thus, are assignment to pta_bottom. */ + if (pointer_destroying_op (operation)) + { + pta_assignment (ALIAS_VAR_ATERM (lhs), pta_rvalue (pta_bottom ())); + return; + } + + /* Operations in general we can't track the exact effect of. Thus, + we conservatively assume that it could make the LHS point to + *anything* the RHS points to. To signify this, we join the RHS + variables together and assign it to the LHS. */ + /* The >2 case occurs when we are dealing with constructors. */ + if (VARRAY_ACTIVE_SIZE (operands) > 2) + { + size_t i; + alias_var tv1 = VARRAY_GENERIC_PTR (operands, 0); + newvar = ALIAS_VAR_ATERM (tv1); + for (i = 1; i < VARRAY_ACTIVE_SIZE (operands); i++) + { + alias_var tempvar = VARRAY_GENERIC_PTR (operands, i); + aterm t2 = ALIAS_VAR_ATERM (tempvar); + if (bitmap_bit_p (addrargs, i)) + newvar = pta_join (newvar, pta_address (t2)); + else + newvar = pta_join (newvar, t2); + } + } + else if (VARRAY_ACTIVE_SIZE (operands) == 2) + { + alias_var tv1 = VARRAY_GENERIC_PTR (operands, 0); + alias_var tv2 = VARRAY_GENERIC_PTR (operands, 1); + aterm t1 = ALIAS_VAR_ATERM (tv1); + aterm t2 = ALIAS_VAR_ATERM (tv2); + if (bitmap_bit_p (addrargs, 0) && bitmap_bit_p (addrargs, 1)) + newvar = pta_join (pta_address (t1), pta_address (t2)); + else if (bitmap_bit_p (addrargs, 0)) + newvar = pta_join (pta_address (t1), t2); + else if (bitmap_bit_p (addrargs, 1)) + newvar = pta_join (t1, pta_address (t2)); + else + newvar = pta_join (t1, t2); + } + else if (VARRAY_ACTIVE_SIZE (operands) == 1) + { + alias_var tv1 = VARRAY_GENERIC_PTR (operands, 0); + aterm t1 = ALIAS_VAR_ATERM (tv1); + if (bitmap_bit_p (addrargs, 0)) + newvar = pta_address (t1); + else + newvar = t1; + } + pta_assignment (ALIAS_VAR_ATERM (lhs), pta_rvalue (newvar)); +} + +/* Inference for heap assignment (lhs = alloc). */ + +static void +andersen_heap_assign (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var lhs ATTRIBUTE_UNUSED) +{ +#if 0 + alias_type type1; + ECR tau; + type1 = ECR_get_type (alias_var_get_ECR (lhs)); + tau = alias_ltype_loc (type1); + + if (ECR_get_type (tau) == alias_bottom) + ECR_set_type (tau, alias_ltype_new ()); +#endif +} + +/* Inference for assignment to a pointer (*ptr = rhs). */ + +static void +andersen_assign_ptr (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var ptr, alias_var rhs) +{ + + if (rhs == NULL) + return; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Assignment to pointer *%s = %s\n", + alias_get_name (ALIAS_VAR_DECL (ptr)), + alias_get_name (ALIAS_VAR_DECL (rhs))); + /* The RHS is a standard rvalue, and the LHS is a pointer + dereference. */ + pta_assignment (pta_deref (ALIAS_VAR_ATERM (ptr)), + pta_rvalue (ALIAS_VAR_ATERM (rhs))); +} + +/* Inference for a function definition. */ + +static void +andersen_function_def (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var func, varray_type params, + alias_var retval) +{ + aterm_list args = new_aterm_list (andersen_rgn); + aterm fun_type; + + size_t l = VARRAY_ACTIVE_SIZE (params); + size_t i; + + /* Set up the arguments for the new function type. */ + for (i = 0; i < l; i++) + { + alias_var tv = VARRAY_GENERIC_PTR (params, i); + aterm_list_cons (ALIAS_VAR_ATERM (tv), args); + } + /* Create the function type. */ + fun_type = pta_make_fun (alias_get_name (ALIAS_VAR_DECL (func)), + ALIAS_VAR_ATERM (retval), args); + + /* Assign the function type itself to the function. */ + pta_assignment (ALIAS_VAR_ATERM (func), fun_type); +} + +/* Inference for a function call assignment. */ + +static int +andersen_function_call (struct tree_alias_ops *ops, + alias_var lhs, alias_var func, + varray_type args, bitmap addrargs) +{ + aterm_list actuals = new_aterm_list (andersen_rgn); + aterm ftype = ALIAS_VAR_ATERM (func); + aterm ret = NULL; + aterm res; + tree decl = ALIAS_VAR_DECL (func); + + size_t i; + + if (lhs) + ret = ALIAS_VAR_ATERM (lhs); + for (i = 0; i < VARRAY_ACTIVE_SIZE (args); i++) + { + alias_var argtv = VARRAY_GENERIC_PTR (args, i); + aterm arg = ALIAS_VAR_ATERM (argtv); + if (bitmap_bit_p (addrargs, i)) + aterm_list_cons (pta_rvalue (pta_address (arg)), actuals); + else + aterm_list_cons (pta_rvalue (arg), actuals); + } + aterm_list_reverse (actuals); + + /* Generate the constraint that calls the function with it's + arguments, and gives us the result. This in turn applies + whatever constraints are in that function. */ + res = pta_application (pta_rvalue (ftype), actuals); + /* We only need care about the result if we have an LHS. If we do, + assign the result of function application back to the LHS. */ + if (ret) + pta_assignment (ret, pta_rvalue (res)); + + /* We can handle functions we've got trees for. non-statics will + just have incoming parameters assigned to global_var if + necessary. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_PTA_ALIASVAR (decl) + && ops->ip_partial + && (cgraph_local_info (decl)->local)) + { + return 0; + } + return 1; +} + + +/* Simple pointer comparison function for list sorting. */ + +static int +simple_cmp (const aterm a, const aterm b) +{ + return (int *)a - (int *)b; +} + + +/* Get the points-to set for TV, caching if it we had to compute it. */ + +static aterm_list +get_ptset (alias_var tv) +{ + aterm_list ptset; + ptset = ALIAS_VAR_PTSET (tv); + if (ptset != NULL) + return ptset; + ptset = aterm_tlb (pta_get_contents (ALIAS_VAR_ATERM (tv))); + ALIAS_VAR_PTSET (tv) = ptset; + return ptset; +} + + +/* Determine if two aterm's have the same points-to set. */ + +static bool +andersen_same_points_to_set (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var ptrtv, alias_var vartv) +{ + aterm_list ptset1, ptset2; + aterm_list_scanner scan1, scan2; + aterm data1, data2; + region scratch_rgn = newregion (); + + ptset1 = get_ptset (ptrtv); + ptset2 = get_ptset (vartv); + + if (aterm_list_length (ptset1) != aterm_list_length (ptset2)) + { + deleteregion (scratch_rgn); + return false; + } + + if (ptset1 == ptset2) + { + deleteregion (scratch_rgn); + return true; + } + + ptset1 = aterm_list_copy (scratch_rgn, ptset1); + ptset2 = aterm_list_copy (scratch_rgn, ptset2); + + if (aterm_list_length (ptset1) != aterm_list_length (ptset2)) + { + deleteregion (scratch_rgn); + return false; + } + + ptset1 = aterm_list_sort (ptset1, simple_cmp); + ptset2 = aterm_list_sort (ptset2, simple_cmp); + + aterm_list_scan (ptset1, &scan1); + aterm_list_scan (ptset2, &scan2); + while (aterm_list_next (&scan1, &data1)) + { + aterm_list_next (&scan2, &data2); + if (data1 != data2) + { + deleteregion(scratch_rgn); + return false; + } + } + deleteregion(scratch_rgn); + return true; +} + + +/* Determine if two variables may alias. In our case, this means + whether the decl represented by PTRTV can point to VARTV. */ + +static bool +andersen_may_alias (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var ptrtv, alias_var vartv) +{ + aterm_list ptset; + ptset = get_ptset (ptrtv); + + if (aterm_list_empty (ptset)) + return false; + + return aterm_list_member (ptset, ALIAS_VAR_ATERM (vartv)); +} + +/* Determine whether PTRTV has an empty points-to set. IE it may not + point to anything. */ + +static bool +andersen_empty_points_to_set (struct tree_alias_ops *ops ATTRIBUTE_UNUSED, + alias_var ptrtv) +{ + aterm_list ptset; + ptset = get_ptset (ptrtv); + return aterm_list_empty (ptset); +} diff --git a/gcc/tree-alias-ander.h b/gcc/tree-alias-ander.h new file mode 100644 index 00000000000..92e313fd066 --- /dev/null +++ b/gcc/tree-alias-ander.h @@ -0,0 +1,7 @@ +#ifndef TREE_ALIAS_ANDER +#define TREE_ALIAS_ANDER +#include "tree-alias-common.h" + + +extern struct tree_alias_ops *andersen_alias_ops; +#endif diff --git a/gcc/tree-alias-common.c b/gcc/tree-alias-common.c new file mode 100644 index 00000000000..cd36eef5942 --- /dev/null +++ b/gcc/tree-alias-common.c @@ -0,0 +1,1264 @@ +/* Tree based points-to analysis + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Daniel Berlin + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "ggc.h" +#include "tree-alias-type.h" +#include "bitmap.h" +#include "tree-alias-common.h" +/* If we have andersen's points-to analysis, include it. */ +#ifdef HAVE_BANSHEE +#include "tree-alias-ander.h" +#endif +#include "flags.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "expr.h" +#include "diagnostic.h" +#include "tree.h" +#include "c-common.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "varray.h" +#include "c-tree.h" +#include "tree-simple.h" +#include "hashtab.h" +#include "function.h" +#include "cgraph.h" +#include "tree-pass.h" +#include "timevar.h" + +/* Reduce ifdefery later. */ +#ifndef HAVE_BANSHEE +#define HAVE_BANSHEE 0 +#endif + +/* This file contains the implementation of the common parts of the + tree points-to analysis infrastructure. + + Overview: + + This file contains the points-to analysis driver. It does two main things: + 1. Keeps track of the PTA data for each variable (IE the data each + specific PTA implementation wants to keep associated with a + variable). + 2. Walks the function trees, calling the appropriate functions that + each PTA implementation has implemented. + + In order to speed up PTA queries, the PTA specific data is stored + in the tree for *_DECL's, in DECL_PTA_ALIASVAR. This way, we only + need to use the hash table for non-DECL's. */ +#define FIELD_BASED 0 + +/* Array of all created alias_vars. + Note that this should contain all the alias_vars we wanted + marked during GC. */ +static GTY((param_is (union alias_var_def))) varray_type alias_vars = NULL; +struct tree_alias_ops *current_alias_ops; + +/* Array of local (to a function) alias_vars. + Note that this should contain all the alias_vars that are + local to this function. We delete these from alias_vars before + collection. */ +static GTY(()) varray_type local_alias_vars; +static GTY(()) varray_type local_alias_varnums; +tree pta_global_var; +static bitmap addrargs; +static alias_var get_alias_var_decl (tree); +static alias_var get_alias_var (tree); +static void find_func_aliases (tree); +static void deal_with_call_aliasing (tree, alias_var); +static alias_var create_fun_alias_var_ptf (tree, tree); +static alias_var create_fun_alias_var (tree, int); +static alias_var create_alias_var (tree); +static void intra_function_call (varray_type); +static void get_values_from_constructor (tree, varray_type *, bitmap, int *); +static bool call_may_clobber (tree); +static bool call_may_return (tree); + +/* Return true if a EXPR, which is a CALL_EXPR, may clobber variables. */ + +static bool +call_may_clobber (tree expr) +{ + int flags; + + if (TREE_CODE (expr) != CALL_EXPR) + return false; + + flags = call_expr_flags (expr); + return (! (flags & (ECF_CONST | ECF_PURE | ECF_NORETURN))); +} + +/* Return true if a EXPR, which is a CALL_EXPR, may return. */ + +static bool +call_may_return (tree expr) +{ + int flags; + + if (TREE_CODE (expr) != CALL_EXPR) + return false; + + flags = call_expr_flags (expr); + return ! (flags & ECF_NORETURN); +} + +/* Get the alias_var for DECL. + Creates the alias_var if it does not exist already. Also + handles FUNCTION_DECL properly. */ + +static alias_var +get_alias_var_decl (tree decl) +{ + alias_var newvar; + if (TREE_CODE (decl) == FIELD_DECL) + abort (); + if (DECL_P (decl)) + { + if (DECL_PTA_ALIASVAR (decl)) + return DECL_PTA_ALIASVAR (decl); + } + + if (TREE_CODE (decl) == FUNCTION_DECL) + newvar = create_fun_alias_var (decl, 0); + else + { + newvar = create_alias_var (decl); + /* Assign globals to global var for purposes of intraprocedural + analysis. */ + if ((DECL_CONTEXT (decl) == NULL + || TREE_PUBLIC (decl) + || TREE_STATIC (decl) + || decl_function_context (decl) == NULL) + && decl != pta_global_var) + { + current_alias_ops->addr_assign (current_alias_ops, + get_alias_var (pta_global_var), + newvar); + /* If the global has some DECL_INITIAL, we need to process + it here. */ + if (DECL_INITIAL (decl)) + find_func_aliases (decl); + } + } + + if (!current_alias_ops->ip) + { + if (!current_alias_ops->ip_partial + || (TREE_CODE (decl) != FUNCTION_DECL + && TREE_CODE (decl) != PARM_DECL)) + { + VARRAY_PUSH_INT (local_alias_varnums, ALIAS_VAR_VARNUM (newvar)); + VARRAY_PUSH_TREE (local_alias_vars, decl); + } + } + return newvar; +} + +/* Get the alias_var for an expression EXPR. + Note that this function expects to only be handed a RHS or LHS, not + a MODIFY_EXPR. */ + +static alias_var +get_alias_var (tree expr) +{ + /* If it's a decl, get the alias var of the decl. We farm this off + to get_alias_var_decl so it can abort if the alias var doesn't + exist, and in case something else *knows* it has a decl, and + wants the alias var. */ + + if (DECL_P (expr)) + return get_alias_var_decl (expr); + + /* True constants have no aliases (unless modifiable strings are on, + in which case i don't think we'll end up with a STRING_CST anyway) */ + if (TREE_CODE_CLASS (TREE_CODE (expr)) == 'c') + return NULL; + + + switch (TREE_CODE (expr)) + { + case ARRAY_REF: + { + /* Find the first non-array ref, and return it's alias + variable */ + tree p; + for (p = expr; TREE_CODE (p) == ARRAY_REF; + p = TREE_OPERAND (p, 0)); + return get_alias_var (p); + } + break; + case COMPONENT_REF: + { +#if FIELD_BASED + bool safe = true; + tree p; + for (p = expr; + TREE_CODE (p) == COMPONENT_REF || TREE_CODE (p) == INDIRECT_REF; + p = TREE_OPERAND (p, 0)) + { + if (TREE_CODE (TREE_TYPE (p)) == UNION_TYPE + || TREE_CODE (TREE_TYPE (p)) == QUAL_UNION_TYPE) + { + safe = false; + break; + } + } + if (!safe) + { + for (p = expr; TREE_CODE (p) == COMPONENT_REF; + p = TREE_OPERAND (p, 0)); + return get_alias_var (p); + } + else + { + return get_alias_var (TREE_OPERAND (expr, 1)); + } +#else + /* Find the first non-component ref, and return its alias variable. */ + tree p; + for (p = expr; TREE_CODE (p) == COMPONENT_REF; + p = TREE_OPERAND (p, 0)); + return get_alias_var (p); +#endif + } + break; + case REALPART_EXPR: + case IMAGPART_EXPR: + case NOP_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case ADDR_EXPR: + case INDIRECT_REF: + case BIT_FIELD_REF: + /* If it's a ref or cast or conversion of something, get the + alias var of the something. */ + return get_alias_var (TREE_OPERAND (expr, 0)); + break; + + default: + return NULL; + } +} + +/* Perform conservative aliasing for an intraprocedural mode function + call. ARGS are the arguments that were passed to that function + call. */ + +static void +intra_function_call (varray_type args) +{ + size_t l = VARRAY_ACTIVE_SIZE (args); + size_t i; + alias_var av = get_alias_var (pta_global_var); + + /* We assume assignments among the actual parameters. */ + for (i = 0; i < l; i++) + { + alias_var argi = VARRAY_GENERIC_PTR (args, i); + size_t j; + for (j = 0; j < l; j++) + { + alias_var argj; + if (i == j) + continue; + argj = VARRAY_GENERIC_PTR (args, j); + /* Restricted pointers can't be aliased with other + restricted pointers. */ + if (!TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argi))) + || !TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argj)))) + /* Do a bit of TBAA to avoid pointless assignments. */ + if (alias_sets_conflict_p (get_alias_set (ALIAS_VAR_DECL (argi)), + get_alias_set (ALIAS_VAR_DECL (argj)))) + current_alias_ops->simple_assign (current_alias_ops, argi, argj); + } + } + /* We assume that an actual parameter can point to any global. */ + for (i = 0; i < l; i++) + { + alias_var argav = VARRAY_GENERIC_PTR (args, i); + /* Restricted pointers can't be aliased with other + restricted pointers. */ + if (!TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argav))) + || !TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (av)))) + { + /* Arguments can alias globals, and whatever they point to + can point to a global as well. */ + current_alias_ops->simple_assign (current_alias_ops, argav, av); + } + } +} + +/* Put all pointers in a constructor in an array. */ + +static void +get_values_from_constructor (tree constructor, varray_type *vals, + bitmap addrargs, int *i) +{ + tree elt_list; + switch (TREE_CODE (constructor)) + { + case CONSTRUCTOR: + { + for (elt_list = CONSTRUCTOR_ELTS (constructor); + elt_list; + elt_list = TREE_CHAIN (elt_list)) + { + tree value = TREE_VALUE (elt_list); + if (TREE_CODE (value) == TREE_LIST + || TREE_CODE (value) == CONSTRUCTOR) + { + get_values_from_constructor (value, vals, addrargs, i); } + else + { + alias_var aav; + aav = get_alias_var (value); + if (aav) + VARRAY_PUSH_GENERIC_PTR (*vals, aav); + if (TREE_CODE (value) == ADDR_EXPR) + bitmap_set_bit (addrargs, *i); + *i = *i + 1; + } + } + } + break; + case TREE_LIST: + for (elt_list = constructor; + elt_list; + elt_list = TREE_CHAIN (elt_list)) + { + get_values_from_constructor (TREE_VALUE (elt_list), vals, addrargs, i); + } + break; + default: + abort(); + } +} + +/* Deal with the possible return values of a call that we don't have + actual PTA info about. */ + +static void +deal_with_call_aliasing (tree callargs, alias_var lhsAV) +{ + tree arg, argp; + + for (argp = callargs; + argp; + argp = TREE_CHAIN (argp)) + { + arg = TREE_VALUE (argp); + /* If we take the address of a variable directly in the + argument, the return value could be the address of that + variable. */ + if (TREE_CODE (arg) == ADDR_EXPR) + current_alias_ops->addr_assign (current_alias_ops, lhsAV, + get_alias_var (arg)); + /* If we pass in a pointer, we could return that pointer. */ + else if (POINTER_TYPE_P (TREE_TYPE (arg))) + { + alias_var argtv = get_alias_var (arg); + if (argtv) + current_alias_ops->simple_assign (current_alias_ops, lhsAV, + argtv); + } + } +} + +/* Find the operand of the component ref that actually is doing + something to the DECL */ +static tree +find_op_of_decl (tree cref) +{ + while (!DECL_P (TREE_OPERAND (cref, 0))) + { + cref = TREE_OPERAND (cref, 0); + } + return cref; +} + + +/* Tree walker that is the heart of the aliasing infrastructure. + TP is a pointer to the current tree. + WALK_SUBTREES specifies whether to continue traversing subtrees or + not. + Returns NULL_TREE when we should stop. + + This function is the main part of the aliasing infrastructure. It + walks the trees, calling the appropriate alias analyzer functions to process + various statements. */ + +static void +find_func_aliases (tree stp) +{ + if (TREE_CODE (stp) == RETURN_EXPR) + { + stp = TREE_OPERAND (stp, 0); + if (!stp) + return; + } + + if (TREE_CODE (stp) == MODIFY_EXPR + || (DECL_P (stp) && DECL_INITIAL (stp) != NULL_TREE )) + { + tree op0, op1; + alias_var lhsAV = NULL; + alias_var rhsAV = NULL; + + if (DECL_P (stp)) + { + op0 = stp; + op1 = DECL_INITIAL (stp); + } + else + { + op0 = TREE_OPERAND (stp, 0); + op1 = TREE_OPERAND (stp, 1); + } + /* lhsAV should always have an alias variable */ + lhsAV = get_alias_var (op0); + if (!lhsAV) + return; + /* rhsAV might not have one, c.f. c = 5 */ + rhsAV = get_alias_var (op1); +#if !FIELD_BASED + while (TREE_CODE (op1) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (op1, 0)) == COMPONENT_REF) + { + op1 = TREE_OPERAND (op1, 0); + } + while (TREE_CODE (op1) == BIT_FIELD_REF) + { + op1 = TREE_OPERAND (op1, 0); + } + /* Take care of fact that we may have multi-level component + refs. */ + if (TREE_CODE (op1) == COMPONENT_REF) + op1 = find_op_of_decl (op1); +#endif + + /* You would think we could test rhsAV at the top, rather than + 50 separate times, but we can't, because it can be NULL for + operator assignments, where we'd still collect the individual + alias vars for the operator. */ + + /* Note that structures are treated as a single alias + variable, since we can disambiguate based on TBAA first, + and fall back on points-to. */ + /* x = */ + if (is_gimple_variable (op0)) + { + /* x = y */ + if (is_gimple_variable (op1)) + { + if (rhsAV != NULL) + current_alias_ops->simple_assign (current_alias_ops, lhsAV, + rhsAV); + } + /* x = foo.y */ + else if (TREE_CODE (op1) == COMPONENT_REF + && DECL_P (TREE_OPERAND (op1, 0))) + { + if (rhsAV != NULL) + current_alias_ops->simple_assign (current_alias_ops, lhsAV, + rhsAV); + } + /* x = (cast) [maybe-addr-expr] y */ + else if (is_gimple_cast (op1)) + { + tree stripped_op1 = op1; + STRIP_NOPS (stripped_op1); + if (rhsAV != NULL) + { + if (TREE_CODE (stripped_op1) == ADDR_EXPR) + current_alias_ops->addr_assign (current_alias_ops, lhsAV, + rhsAV); + else + current_alias_ops->simple_assign (current_alias_ops, lhsAV, + rhsAV); + } + } + /* x = *y or x = foo->y */ + else if (TREE_CODE (op1) == INDIRECT_REF + || TREE_CODE (op1) == ARRAY_REF + || (TREE_CODE (op1) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (op1, 0)) == INDIRECT_REF)) + { + if (rhsAV != NULL) + current_alias_ops->ptr_assign (current_alias_ops, lhsAV, + rhsAV); + } + /* x = &y = x = &foo.y */ + else if (TREE_CODE (op1) == ADDR_EXPR) + { + if (rhsAV != NULL) + current_alias_ops->addr_assign (current_alias_ops, lhsAV, + rhsAV); + } + /* x = func(...) */ + else if (TREE_CODE (op1) == CALL_EXPR) + { + /* Heap assignment. These are __attribute__ malloc or + something, i'll deal with it later. */ + if (0) + {} + else + { + + /* NORETURN functions have no effect on aliasing. */ + if (call_may_return (op1)) + { + varray_type args; + tree arg; + tree callop0, callop1; + int argnum; + + /* Collect the arguments */ + VARRAY_GENERIC_PTR_INIT (args, 1, "Arguments"); + bitmap_clear (addrargs); + callop1 = TREE_OPERAND (op1, 1); + callop0 = TREE_OPERAND (op1, 0); + for (arg = callop1, argnum = 0; + arg; + arg = TREE_CHAIN (arg), argnum++) + { + alias_var aav = get_alias_var (TREE_VALUE (arg)); + if (aav) + { + VARRAY_PUSH_GENERIC_PTR (args, aav); + if (TREE_CODE (TREE_VALUE (arg)) == ADDR_EXPR) + bitmap_set_bit (addrargs, argnum); + } + } + /* Simulate the call */ + if (current_alias_ops->function_call (current_alias_ops, lhsAV, + get_alias_var (callop0), + args, addrargs)) + { + if (call_may_clobber (op1) + && !current_alias_ops->ip + && flag_argument_noalias != 2) + { + intra_function_call (args); + } + if (POINTER_TYPE_P (TREE_TYPE (op0))) + deal_with_call_aliasing (callop1, lhsAV); + } + } + } + } + /* x = op (...) */ + else + { + bitmap_clear (addrargs); + if (TREE_CODE (op1) == CONSTRUCTOR) + { + varray_type ops; + int i = 0; + VARRAY_GENERIC_PTR_INIT (ops, 1, "Operands"); + get_values_from_constructor (op1, &ops, addrargs, &i); + current_alias_ops->op_assign (current_alias_ops, lhsAV, + ops, op1, addrargs); + } + else + switch (TREE_CODE_CLASS (TREE_CODE (op1))) + { + case 'e': /* an expression */ + case 's': /* an expression with side effects */ + case '<': /* a comparison expression */ + case '1': /* a unary arithmetic expression */ + case 'r': /* a reference */ + case '2': /* a binary arithmetic expression */ + { + tree op; + varray_type ops; + int i; + VARRAY_GENERIC_PTR_INIT (ops, 1, "Operands"); + for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (op1)); i++) + { + alias_var aav; + op = TREE_OPERAND (op1, i); + aav = get_alias_var (op); + if (aav) + VARRAY_PUSH_GENERIC_PTR (ops, aav); + if (TREE_CODE (op) == ADDR_EXPR) + bitmap_set_bit (addrargs, i); + } + current_alias_ops->op_assign (current_alias_ops, lhsAV, + ops, op1, addrargs); + } + break; + default: + break; + } + } + } + /* *x = */ + else + { + /* x.f = y or x->f = y */ + if ((TREE_CODE (op0) == COMPONENT_REF + || TREE_CODE (op0) == BIT_FIELD_REF) + && is_gimple_variable (op1)) + { + if (rhsAV != NULL) + current_alias_ops->simple_assign (current_alias_ops, lhsAV, + rhsAV); + } + /* x.f = &y or x->f = &y */ + else if (TREE_CODE (op0) == COMPONENT_REF + && TREE_CODE (op1) == ADDR_EXPR) + { + if (rhsAV != NULL) + current_alias_ops->addr_assign (current_alias_ops, lhsAV, + rhsAV); + } + /* *x.f = y or *x->f = y */ + else if ((TREE_CODE (op0) == INDIRECT_REF + || TREE_CODE (op0) == ARRAY_REF) + && TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF + && is_gimple_variable (op1)) + { + if (rhsAV != NULL) + current_alias_ops->assign_ptr (current_alias_ops, lhsAV, + rhsAV); + } + /* *x = &y */ + else if ((TREE_CODE (op0) == INDIRECT_REF + || TREE_CODE (op0) == ARRAY_REF) + && TREE_CODE (op1) == ADDR_EXPR) + { + /* This becomes temp = &y and *x = temp . */ + alias_var tempvar; + tree temp = create_tmp_var_raw (void_type_node, "aliastmp"); + tempvar = current_alias_ops->add_var (current_alias_ops, temp); + current_alias_ops->addr_assign (current_alias_ops, tempvar, + rhsAV); + current_alias_ops->assign_ptr (current_alias_ops, lhsAV, + tempvar); + } + + /* *x = *y */ + else if ((TREE_CODE (op0) == INDIRECT_REF + || TREE_CODE (op0) == ARRAY_REF) + && (TREE_CODE (op1) == INDIRECT_REF + || TREE_CODE (op1) == ARRAY_REF)) + { + /* This becomes temp = *y and *x = temp . */ + alias_var tempvar; + tree temp; + temp = create_tmp_var_raw (void_type_node, "aliastmp"); + tempvar = current_alias_ops->add_var (current_alias_ops, temp); + current_alias_ops->ptr_assign (current_alias_ops, tempvar, + rhsAV); + current_alias_ops->assign_ptr (current_alias_ops, lhsAV, + tempvar); + } + + /* *x = (cast) y */ + else if ((TREE_CODE (op0) == INDIRECT_REF + || TREE_CODE (op0) == ARRAY_REF) + && is_gimple_cast (op1)) + { + if (rhsAV != NULL) + { + /* This becomes temp = (cast) y and *x = temp. */ + alias_var tempvar; + tree temp; + temp = create_tmp_var_raw (void_type_node, "aliastmp"); + tempvar = current_alias_ops->add_var (current_alias_ops, + temp); + current_alias_ops->simple_assign (current_alias_ops, + tempvar, rhsAV); + current_alias_ops->assign_ptr (current_alias_ops, lhsAV, + tempvar); + } + } + /* *x = */ + else + { + if (rhsAV != NULL) + current_alias_ops->assign_ptr (current_alias_ops, lhsAV, + rhsAV); + } + } + } + /* Calls without return values. */ + else if (TREE_CODE (stp) == CALL_EXPR) + { + alias_var callvar; + varray_type args; + tree arg; + callvar = get_alias_var (TREE_OPERAND (stp, 0)); + if (callvar != NULL) + { + + /* NORETURN and CONST functions with no return value + have no effect on aliasing (as may be seen above, + const functions that return a value might have an + effect on aliasing, since the return value can point + to one of the arguments. */ + if (call_may_clobber (stp)) + { + int argnum; + VARRAY_GENERIC_PTR_INIT (args, 1, "Arguments"); + bitmap_clear (addrargs); + for (arg = TREE_OPERAND (stp, 1), argnum=0; + arg; + arg = TREE_CHAIN (arg), argnum++) + { + alias_var aav = get_alias_var (TREE_VALUE (arg)); + if (aav) + { + VARRAY_PUSH_GENERIC_PTR (args, aav); + if (TREE_CODE (TREE_VALUE (arg)) == ADDR_EXPR) + bitmap_set_bit (addrargs, argnum); + } + + } + + if (current_alias_ops->function_call (current_alias_ops, NULL, + callvar, args, addrargs)) + if (!current_alias_ops->ip && flag_argument_noalias != 2) + intra_function_call (args); + } + } + } +} + +/* Create the alias_var for a function definition DECL, it's + arguments, and it's return value. If FORCE is true, we force + creation of the alias_var, regardless of whether one exists already. + + This includes creation of alias_var's for + - The function itself. + - The arguments. + - The return value. */ + +static alias_var +create_fun_alias_var (tree decl, int force) +{ + alias_var avar, retvar; + tree rdecl; + varray_type params = NULL; + + if (!force) + { + if (DECL_PTA_ALIASVAR (decl)) + return DECL_PTA_ALIASVAR (decl); + } + + VARRAY_GENERIC_PTR_INIT (params, 1, "Arguments"); + if (DECL_ARGUMENTS (decl) != NULL) + { + tree arg; + for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg)) + { + alias_var var = get_alias_var (arg); + VARRAY_PUSH_GENERIC_PTR (params, var); + /* Incoming pointers can point to pta_global_var, unless + either we are interprocedural, or we can do ip on all + statics + this function has been defined + it's not an + external function. */ + if (POINTER_TYPE_P (TREE_TYPE (arg)) + && !current_alias_ops->ip + /* FIXME: Need to let analyzer decide in partial case. */ + && (!current_alias_ops->ip_partial + || !cgraph_local_info (decl)->local)) + current_alias_ops->simple_assign (current_alias_ops, var, + get_alias_var (pta_global_var)); + } + } + else if (TYPE_ARG_TYPES (TREE_TYPE (decl)) != NULL) + { + tree arg; + /* FIXME: Handle varargs */ + for (arg = TYPE_ARG_TYPES (TREE_TYPE (decl)); + arg && TREE_VALUE (arg) != void_type_node; + arg = TREE_CHAIN (arg)) + { + tree fakedecl = create_tmp_var_raw (TREE_VALUE (arg), "normarg"); + alias_var var; + DECL_CONTEXT (fakedecl) = current_function_decl; + var = get_alias_var (fakedecl); + VARRAY_PUSH_GENERIC_PTR (params, var); + + /* Incoming pointers can point to pta_global_var, unless + either we are interprocedural, or we can do ip on all + statics + this function has been defined + it's not an + external function. */ + if (POINTER_TYPE_P (TREE_TYPE (fakedecl)) + && !current_alias_ops->ip + /* FIXME: need to let analyzer decide in partial case. */ + && (!current_alias_ops->ip_partial + || !TREE_STATIC (decl) + || TREE_PUBLIC (decl))) + current_alias_ops->simple_assign (current_alias_ops, var, + get_alias_var (pta_global_var)); + } + } + /* Functions declared like void f() are *not* equivalent to void + f(void). You can pass an argument to them. Thus, we need to + create some fake argument that would alias any actuals that get + passed to our function. */ + else + { + tree fakedecl = create_tmp_var_raw (void_type_node, "fakearg"); + alias_var fakevar; + DECL_CONTEXT (fakedecl) = current_function_decl; + fakevar = get_alias_var (fakedecl); + VARRAY_PUSH_GENERIC_PTR (params, fakevar); + } + + if (!DECL_RESULT (decl)) + { + rdecl = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (decl)), "_rv_"); + retvar = current_alias_ops->add_var (current_alias_ops, rdecl); + DECL_PTA_ALIASVAR (rdecl) = retvar; + } + else + { + retvar = current_alias_ops->add_var (current_alias_ops, + DECL_RESULT (decl)); + DECL_PTA_ALIASVAR (DECL_RESULT (decl)) = retvar; + } + VARRAY_PUSH_GENERIC_PTR (alias_vars, retvar); + ALIAS_VAR_VARNUM (retvar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1; + avar = current_alias_ops->add_var (current_alias_ops, decl); + VARRAY_PUSH_GENERIC_PTR (alias_vars, avar); + ALIAS_VAR_VARNUM (avar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1; + + current_alias_ops->function_def (current_alias_ops, avar, params, retvar); + DECL_PTA_ALIASVAR (decl) = avar; + + /* FIXME: Also, if this is a defining declaration then add the annotation + to all extern definitions of the function. */ + return avar; +} + +/* Create an alias variable for a pointer-to-member function DECL of + type TYPE, it's arguments, and it's return value. + Returns the alias_var for the PTF. + + This includes creating alias_var's for + - The function itself. + - The arguments. + - The return value. */ + +static alias_var +create_fun_alias_var_ptf (tree decl, tree type) +{ + alias_var avar, retvar; + tree rdecl; + varray_type params = NULL; + + if (DECL_PTA_ALIASVAR (decl)) + return DECL_PTA_ALIASVAR (decl); + + VARRAY_GENERIC_PTR_INIT (params, 1, "Arguments"); + + if (TYPE_ARG_TYPES (type) != NULL) + { + tree arg; + /* FIXME: Handle varargs */ + for (arg = TYPE_ARG_TYPES (type); + arg && TREE_VALUE (arg) != void_type_node; + arg = TREE_CHAIN (arg)) + { + tree fakedecl = create_tmp_var_raw (TREE_VALUE (arg), "ptfarg"); + alias_var var; + DECL_CONTEXT (fakedecl) = DECL_CONTEXT (decl); + var = get_alias_var (fakedecl); + VARRAY_PUSH_GENERIC_PTR (params, var); + } + } + /* Functions declared like void f() are *not* equivalent to void + f(void). You can pass an argument to them. Thus, we need to + create some fake argument that would alias any actuals that get + passed to our function. */ + else + { + tree fakedecl = create_tmp_var_raw (void_type_node, "fakearg"); + alias_var fakevar; + DECL_CONTEXT (fakedecl) = DECL_CONTEXT (decl); + fakevar = get_alias_var (fakedecl); + VARRAY_PUSH_GENERIC_PTR (params, fakevar); + } + + rdecl = create_tmp_var_raw (TREE_TYPE (type), "_rv_"); + retvar = current_alias_ops->add_var (current_alias_ops, rdecl); + VARRAY_PUSH_GENERIC_PTR (alias_vars, retvar); + ALIAS_VAR_VARNUM (retvar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1; + + avar = current_alias_ops->add_var (current_alias_ops, decl); + VARRAY_PUSH_GENERIC_PTR (alias_vars, avar); + ALIAS_VAR_VARNUM (avar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1; + + current_alias_ops->function_def (current_alias_ops, avar, params, retvar); + DECL_PTA_ALIASVAR (decl) = avar; + + return avar; +} + +/* Create the alias_var for a *_DECL node DECL. + Returns the alias_var for DECL. + + This function also handles creation of alias_var's for PTF + variables. */ + +static alias_var +create_alias_var (tree decl) +{ + alias_var avar; + + if (!DECL_P (decl)) + abort (); + + if (DECL_P (decl)) + { + if (DECL_PTA_ALIASVAR (decl)) + return DECL_PTA_ALIASVAR (decl); + } + + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == FUNCTION_TYPE) + { + avar = create_fun_alias_var_ptf (decl, TREE_TYPE (TREE_TYPE (decl))); + } + else + avar = current_alias_ops->add_var (current_alias_ops, decl); + + if (DECL_P (decl)) + { + DECL_PTA_ALIASVAR (decl) = avar; + } + + VARRAY_PUSH_GENERIC_PTR (alias_vars, avar); + ALIAS_VAR_VARNUM (avar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1; + return avar; +} + +/* Create points-to sets for the current function. */ + +static void +create_alias_vars (void) +{ + basic_block bb; +#if HAVE_BANSHEE + if (flag_tree_points_to == PTA_ANDERSEN) + current_alias_ops = andersen_alias_ops; + else +#endif + { + current_alias_ops = NULL; + flag_tree_points_to = PTA_NONE; + return; + } + + pta_global_var = build_decl (VAR_DECL, get_identifier (".pta_global_var"), + size_type_node); + DECL_ARTIFICIAL (pta_global_var) = 1; + TREE_READONLY (pta_global_var) = 1; + DECL_EXTERNAL (pta_global_var) = 0; + TREE_STATIC (pta_global_var) = 1; + TREE_USED (pta_global_var) = 1; + DECL_CONTEXT (pta_global_var) = current_function_decl; + TREE_THIS_VOLATILE (pta_global_var) = 1; + TREE_ADDRESSABLE (pta_global_var) = 0; + + init_alias_vars (); + + DECL_PTA_ALIASVAR (current_function_decl) = NULL; + get_alias_var (current_function_decl); + + /* First, walk the variables and their DECL_INITIAL's */ + if (cfun->unexpanded_var_list) + { + tree vars, var; + for (vars = cfun->unexpanded_var_list; vars; vars = TREE_CHAIN (vars)) + { + var = TREE_VALUE (vars); + if (TREE_CODE (var) != LABEL_DECL + && decl_function_context (var) == NULL + && DECL_INITIAL (var)) + find_func_aliases (var); + } + } + + /* Now walk all statements and derive aliases. */ + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + find_func_aliases (bsi_stmt (bsi)); + } + + pta_global_var = NULL_TREE; +} + +struct tree_opt_pass pass_build_pta = +{ + "pta", /* name */ + NULL, /* gate */ + create_alias_vars, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_PTA, /* tv_id */ + PROP_cfg, /* properties_required */ + PROP_pta, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + + +/* Delete created points-to sets. */ + +static void +delete_alias_vars (void) +{ + size_t i; + + if (flag_tree_points_to != PTA_ANDERSEN) + return; + + for (i = 0; i < VARRAY_ACTIVE_SIZE (local_alias_vars); i++) + { + tree key = VARRAY_TREE (local_alias_vars, i); + if (DECL_P (key)) + DECL_PTA_ALIASVAR (key) = NULL; + else + abort (); + } + + for (i = 0; i < VARRAY_ACTIVE_SIZE (local_alias_varnums); i ++) + VARRAY_GENERIC_PTR (alias_vars, VARRAY_INT (local_alias_varnums, i)) = NULL; + if (!current_alias_ops->ip && !current_alias_ops->ip_partial) + { + /* VARRAY_CLEAR (alias_vars); */ + VARRAY_CLEAR (local_alias_vars); + VARRAY_CLEAR (local_alias_varnums); + } + BITMAP_XFREE (addrargs); + current_alias_ops->cleanup (current_alias_ops); +} + +struct tree_opt_pass pass_del_pta = +{ + "pta", /* name */ + NULL, /* gate */ + delete_alias_vars, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_PTA, /* tv_id */ + PROP_pta, /* properties_required */ + 0, /* properties_provided */ + PROP_pta, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + + +/* Initialize points-to analysis machinery. */ + +void +init_alias_vars (void) +{ + current_alias_ops->init (current_alias_ops); + addrargs = BITMAP_XMALLOC (); + VARRAY_TREE_INIT (local_alias_vars, 10, "Local alias vars"); + VARRAY_INT_INIT (local_alias_varnums, 10, "Local alias varnums"); + if ((!current_alias_ops->ip && !current_alias_ops->ip_partial) + || alias_vars == NULL) + VARRAY_GENERIC_PTR_INIT (alias_vars, 10, "Alias vars"); +} + +/* Return true if PTR can't point to anything (i.e. it has an empty + points-to set. */ +bool +empty_points_to_set (tree ptr) +{ + alias_var ptrtv; + +#if !FIELD_BASED +#else + if (TREE_CODE (ptr) == COMPONENT_REF) + ptr = TREE_OPERAND (ptr, 1); +#endif + + if (DECL_P (ptr)) + { + ptrtv = DECL_PTA_ALIASVAR (ptr); + if (!ptrtv) + return true; + } + else + abort (); + + return current_alias_ops->empty_points_to_set (current_alias_ops, ptrtv); +} + +/* Return true if PTR and VAR have the same points-to set. */ + +bool +same_points_to_set (tree ptr, tree var) +{ + alias_var ptrtv, vartv; + +#if !FIELD_BASED +#else + if (TREE_CODE (ptr) == COMPONENT_REF) + ptr = TREE_OPERAND (ptr, 1); + if (TREE_CODE (var) == COMPONENT_REF) + var = TREE_OPERAND (var, 1); +#endif + + if (ptr == var) + return true; + + if (DECL_P (ptr)) + { + ptrtv = DECL_PTA_ALIASVAR (ptr); + if (!ptrtv) + return false; + } + else + abort (); + + if (DECL_P (var)) + { + vartv = DECL_PTA_ALIASVAR (var); + if (!vartv) + return false; + } + else + abort (); + + return current_alias_ops->same_points_to_set (current_alias_ops, vartv, ptrtv); +} + +/* Determine whether two variables (PTR and VAR) may-alias. + Returns TRUE if PTR may-alias VAR. */ + +bool +ptr_may_alias_var (tree ptr, tree var) +{ + alias_var ptrtv, vartv; + +#if !FIELD_BASED +#else + if (TREE_CODE (ptr) == COMPONENT_REF) + ptr = TREE_OPERAND (ptr, 1); + if (TREE_CODE (var) == COMPONENT_REF) + var = TREE_OPERAND (var, 1); +#endif + + if (ptr == var) + return true; + + if (DECL_P (ptr)) + { + ptrtv = DECL_PTA_ALIASVAR (ptr); + if (!ptrtv) + return false; + } + else + abort (); + + if (DECL_P (var)) + { + vartv = DECL_PTA_ALIASVAR (var); + if (!vartv) + return false; + } + else + abort (); + + return current_alias_ops->may_alias (current_alias_ops, ptrtv, vartv); +} + +#define MASK_POINTER(P) ((unsigned)((unsigned long)(P) & 0xffff)) + +const char * +alias_get_name (tree t) +{ + const char *name; + +#if FIELD_BASED + if (TREE_CODE (t) == FIELD_DECL) + { + /* First get the name of the field, then the prefix, then smash them + together. */ + const char *fieldname = IDENTIFIER_POINTER (DECL_NAME (t)); + const char *prefix = alias_get_name (DECL_CONTEXT (t)); + char *smashed; + size_t neededlen = strlen (fieldname) + strlen (prefix) + 2; + smashed = ggc_alloc (neededlen); + sprintf (smashed, "%s.%s", prefix, fieldname); + name = smashed; + + } + else if (TYPE_P (t)) + { + if (TYPE_NAME (t) && IDENTIFIER_POINTER (TYPE_NAME (t))) + name = IDENTIFIER_POINTER (TYPE_NAME (t)); + else + name = ""; + } + else +#endif + { + if (TREE_CODE (t) == FUNCTION_DECL) + name = IDENTIFIER_POINTER (DECL_NAME (t)); + else if (TREE_CODE (t) == RESULT_DECL) + name = ""; + else + name = get_name (t); + } + + if (!name) + { + char *namep; + /* 2 = UF + 4 = the masked pointer + 2 = the <> around it + 1 = the terminator. */ + namep = ggc_alloc (2 + 4 + 2 + 1); + sprintf (namep, "", MASK_POINTER (t)); + return namep; + } + + return name; +} + +#include "gt-tree-alias-common.h" diff --git a/gcc/tree-alias-common.h b/gcc/tree-alias-common.h new file mode 100644 index 00000000000..45c9e4b8973 --- /dev/null +++ b/gcc/tree-alias-common.h @@ -0,0 +1,99 @@ +#ifndef TREE_ALIAS_COMMON +#define TREE_ALIAS_COMMON +#include "tree-alias-type.h" +/* Alias analysis function pointers. + Functions implemented by the actual alias analysis algorithms in + order for them to work with the common points-to structure. */ +struct tree_alias_ops +{ + /* Initialization. + Called right before we start using the other functions. */ + void (*init) (struct tree_alias_ops *); + + /* Cleanup. + Called when we are finished with the alias analyzer. */ + void (*cleanup) (struct tree_alias_ops *); + + /* Add variable. + Called when we want to inform the alias analyzer about a new + variable we've found. */ + alias_var (*add_var) (struct tree_alias_ops *, tree); + + /* Add variable equivalent to existing one. + Called when we want to inform the alias analyzer about a new + variable that has the same points-to set as an existing + variable. */ + alias_var (*add_var_same) (struct tree_alias_ops *, tree, + alias_var); + + /* Process a simple assignment (a = b). + Called to process simple assignment statements of the form a = b, + where a and b are both variables. */ + void (*simple_assign) (struct tree_alias_ops *, alias_var, + alias_var); + /* Process an address assignment (a = &b). + Called to process address assignment statements of the form a = + &b, where a and b are both variables. */ + void (*addr_assign) (struct tree_alias_ops *, alias_var, alias_var); + + /* Process a pointer assignment (a = *b). + Called to process pointer assignment statements of the form a = + *b, where a and b are both variables. */ + void (*ptr_assign) (struct tree_alias_ops *, alias_var, alias_var); + + /* Process an operator assignment (a = op (...)) + Called to process operators of the form a = op(...), where a is a + variable. */ + void (*op_assign) (struct tree_alias_ops *, alias_var, varray_type, + tree, bitmap); + /* Process a heap assignment (a = alloc (...)) + Called to process a heap assignment of the form a = alloc + (...), where a is a variable, and *alloc is a function that + returns new memory. */ + void (*heap_assign) (struct tree_alias_ops *, alias_var); + + /* Process an assignment to a pointer (*a = b) + Called to process assignment to pointer statements of the form + *a = b, where a and b are both variables. */ + void (*assign_ptr) (struct tree_alias_ops *, alias_var, alias_var); + + /* Process a function definition. + Called to inform the alias analyzer about a new function + definition. */ + void (*function_def) (struct tree_alias_ops *, alias_var, + varray_type, alias_var); + + /* Process a function call. + Return 1 if we need to assume conservative side-effects. */ + int (*function_call) (struct tree_alias_ops *, alias_var, + alias_var, varray_type, bitmap); + + /* Determine if two alias variables may alias. */ + bool (*may_alias) (struct tree_alias_ops *, alias_var, alias_var); + + /* Determine if two alias variables have the same points-to set. */ + bool (*same_points_to_set) (struct tree_alias_ops *, alias_var, + alias_var); + + /* Determine if the alias variable has an empty points-to set. */ + bool (*empty_points_to_set) (struct tree_alias_ops *, alias_var); + + /* Private data. */ + void *data; + + /* Interprocedural. */ + int ip:1; + + /* Can do conservative interprocedural analysis if we save the + * info. */ + int ip_partial:1; + +}; + +extern struct tree_alias_ops *current_alias_ops; +extern void init_alias_vars (void); +extern bool ptr_may_alias_var (tree, tree); +extern bool same_points_to_set (tree, tree); +extern bool empty_points_to_set (tree); +extern const char *alias_get_name (tree); +#endif diff --git a/gcc/tree-alias-type.c b/gcc/tree-alias-type.c new file mode 100644 index 00000000000..20bcbf733fd --- /dev/null +++ b/gcc/tree-alias-type.c @@ -0,0 +1,37 @@ +/* Tree based linear points-to analysis + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Daniel Berlin + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "ggc.h" +#include "tree-alias-type.h" + +alias_var +alias_var_new_with_aterm (tree decl, struct aterm_ *term) +{ + alias_var ret = ggc_alloc (sizeof (struct alias_var_aterm)); + ALIAS_VAR_KIND (ret) = ATERM_AVAR; + ALIAS_VAR_DECL (ret) = decl; + ALIAS_VAR_ATERM (ret) = term; + return ret; +} diff --git a/gcc/tree-alias-type.h b/gcc/tree-alias-type.h new file mode 100644 index 00000000000..7740e9933d7 --- /dev/null +++ b/gcc/tree-alias-type.h @@ -0,0 +1,41 @@ +#ifndef TREE_ALIAS_TYPE_H +#define TREE_ALIAS_TYPE_H + +#include "varray.h" + +union alias_var_def; +struct aterm_; +struct aterm_list_a; +enum alias_var_kind +{ + ATERM_AVAR +}; +struct alias_var_common GTY (()) +{ + enum alias_var_kind kind; + unsigned int varnum; + tree decl; +}; +struct alias_var_aterm GTY (()) +{ + struct alias_var_common common; + struct aterm_ * GTY((skip (""))) term; + struct aterm_list_a *GTY ((skip (""))) ptset; +}; +union alias_var_def GTY ((desc ("%0.common.kind"))) +{ + struct alias_var_common GTY ((tag ("-1"))) common; + struct alias_var_aterm GTY ((tag ("ATERM_AVAR"))) aterm; +}; +typedef union alias_var_def *alias_var; + +#define ALIAS_VAR_KIND(x) ((x)->common.kind) +#define ALIAS_VAR_VARNUM(x) ((x)->common.varnum) +#define ALIAS_VAR_DECL(x) ((x)->common.decl) +#define ALIAS_VAR_ATERM(x) ((x)->aterm.term) +#define ALIAS_VAR_PTSET(x) ((x)->aterm.ptset) +union alias_type_def; +typedef union alias_type_def *alias_type; + +alias_var alias_var_new_with_aterm (tree, struct aterm_ *); +#endif diff --git a/gcc/tree-browser.c b/gcc/tree-browser.c new file mode 100644 index 00000000000..f7c6136c51f --- /dev/null +++ b/gcc/tree-browser.c @@ -0,0 +1,1045 @@ +/* Tree browser. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Sebastian Pop + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "tree.h" +#include "tree-inline.h" +#include "diagnostic.h" +#include "hashtab.h" + + +#define TB_OUT_FILE stdout +#define TB_IN_FILE stdin +#define TB_NIY fprintf (TB_OUT_FILE, "Sorry this command is not yet implemented.\n") +#define TB_WF fprintf (TB_OUT_FILE, "Warning, this command failed.\n") + + +/* Structures for handling Tree Browser's commands. */ +#define DEFTBCODE(COMMAND, STRING, HELP) COMMAND, +enum TB_Comm_code { +#include "tree-browser.def" + TB_UNUSED_COMMAND +}; +#undef DEFTBCODE +typedef enum TB_Comm_code TB_CODE; + +struct tb_command { + const char *help_msg; + const char *comm_text; + size_t comm_len; + TB_CODE comm_code; +}; + +#define DEFTBCODE(code, str, help) { help, str, sizeof(str) - 1, code }, +#ifdef HOST_EBCDIC +static struct tb_command tb_commands[] = +#else +static const struct tb_command tb_commands[] = +#endif +{ +#include "tree-browser.def" +}; +#undef DEFTBCODE + +#define TB_COMMAND_LEN(N) (tb_commands[N].comm_len) +#define TB_COMMAND_TEXT(N) (tb_commands[N].comm_text) +#define TB_COMMAND_CODE(N) (tb_commands[N].comm_code) +#define TB_COMMAND_HELP(N) (tb_commands[N].help_msg) + + +/* Next structure is for parsing TREE_CODEs. */ +struct tb_tree_code { + enum tree_code code; + const char *code_string; + size_t code_string_len; +}; + +#define DEFTREECODE(SYM, STRING, TYPE, NARGS) { SYM, STRING, sizeof (STRING) - 1 }, +#ifdef HOST_EBCDIC +static struct tb_tree_code tb_tree_codes[] = +#else +static const struct tb_tree_code tb_tree_codes[] = +#endif +{ +#include "tree.def" +}; +#undef DEFTREECODE + +#define TB_TREE_CODE(N) (tb_tree_codes[N].code) +#define TB_TREE_CODE_TEXT(N) (tb_tree_codes[N].code_string) +#define TB_TREE_CODE_LEN(N) (tb_tree_codes[N].code_string_len) + + +/* Function declarations. */ + +static long TB_getline (char **, long *, FILE *); +static TB_CODE TB_get_command (char *); +static enum tree_code TB_get_tree_code (char *); +static tree find_node_with_code (tree *, int *, void *); +static tree store_child_info (tree *, int *, void *); +static void TB_update_up (tree); +static tree TB_current_chain_node (tree); +static tree TB_prev_expr (tree); +static tree TB_next_expr (tree); +static tree TB_up_expr (tree); +static tree TB_first_in_bind (tree); +static tree TB_last_in_bind (tree); +static int TB_parent_eq (const void *, const void *); +static tree TB_history_prev (void); + +/* FIXME: To be declared in a .h file. */ +void browse_tree (tree); + +/* Static variables. */ +static htab_t TB_up_ht; +static tree TB_history_stack = NULL_TREE; +static int TB_verbose = 1; + + +/* Entry point in the Tree Browser. */ + +void +browse_tree (tree begin) +{ + tree head; + TB_CODE tbc = TB_UNUSED_COMMAND; + ssize_t rd; + char *input = NULL; + long input_size = 0; + + fprintf (TB_OUT_FILE, "\nTree Browser\n"); + +#define TB_SET_HEAD(N) do { \ + TB_history_stack = tree_cons (NULL_TREE, (N), TB_history_stack); \ + head = N; \ + if (TB_verbose) \ + if (head) \ + { \ + print_generic_expr (TB_OUT_FILE, head, 0); \ + fprintf (TB_OUT_FILE, "\n"); \ + } \ +} while (0) + + TB_SET_HEAD (begin); + + /* Store in a hashtable information about previous and upper statements. */ + { + TB_up_ht = htab_create (1023, htab_hash_pointer, &TB_parent_eq, NULL); + TB_update_up (head); + } + + while (24) + { + fprintf (TB_OUT_FILE, "TB> "); + rd = TB_getline (&input, &input_size, TB_IN_FILE); + + if (rd == -1) + /* EOF. */ + goto ret; + + if (rd != 1) + /* Get a new command. Otherwise the user just pressed enter, and thus + she expects the last command to be reexecuted. */ + tbc = TB_get_command (input); + + switch (tbc) + { + case TB_UPDATE_UP: + TB_update_up (head); + break; + + case TB_MAX: + if (head && (INTEGRAL_TYPE_P (head) + || TREE_CODE (head) == REAL_TYPE)) + TB_SET_HEAD (TYPE_MAX_VALUE (head)); + else + TB_WF; + break; + + case TB_MIN: + if (head && (INTEGRAL_TYPE_P (head) + || TREE_CODE (head) == REAL_TYPE)) + TB_SET_HEAD (TYPE_MIN_VALUE (head)); + else + TB_WF; + break; + + case TB_ELT: + if (head && TREE_CODE (head) == TREE_VEC) + { + /* This command takes another argument: the element number: + for example "elt 1". */ + TB_NIY; + } + else if (head && TREE_CODE (head) == VECTOR_CST) + { + /* This command takes another argument: the element number: + for example "elt 1". */ + TB_NIY; + } + else + TB_WF; + break; + + case TB_VALUE: + if (head && TREE_CODE (head) == TREE_LIST) + TB_SET_HEAD (TREE_VALUE (head)); + else + TB_WF; + break; + + case TB_PURPOSE: + if (head && TREE_CODE (head) == TREE_LIST) + TB_SET_HEAD (TREE_PURPOSE (head)); + else + TB_WF; + break; + + case TB_IMAG: + if (head && TREE_CODE (head) == COMPLEX_CST) + TB_SET_HEAD (TREE_IMAGPART (head)); + else + TB_WF; + break; + + case TB_REAL: + if (head && TREE_CODE (head) == COMPLEX_CST) + TB_SET_HEAD (TREE_REALPART (head)); + else + TB_WF; + break; + + case TB_BLOCK: + if (head && TREE_CODE (head) == BIND_EXPR) + TB_SET_HEAD (TREE_OPERAND (head, 2)); + else + TB_WF; + break; + + case TB_SUBBLOCKS: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'b') + TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); + else + TB_WF; + break; + + case TB_SUPERCONTEXT: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'b') + TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); + else + TB_WF; + break; + + case TB_VARS: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'b') + TB_SET_HEAD (BLOCK_VARS (head)); + else if (head && TREE_CODE (head) == BIND_EXPR) + TB_SET_HEAD (TREE_OPERAND (head, 0)); + else + TB_WF; + break; + + case TB_REFERENCE_TO_THIS: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 't') + TB_SET_HEAD (TYPE_REFERENCE_TO (head)); + else + TB_WF; + break; + + case TB_POINTER_TO_THIS: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 't') + TB_SET_HEAD (TYPE_POINTER_TO (head)); + else + TB_WF; + break; + + case TB_BASETYPE: + if (head && TREE_CODE (head) == OFFSET_TYPE) + TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); + else + TB_WF; + break; + + case TB_ARG_TYPES: + if (head && (TREE_CODE (head) == FUNCTION_TYPE + || TREE_CODE (head) == METHOD_TYPE)) + TB_SET_HEAD (TYPE_ARG_TYPES (head)); + else + TB_WF; + break; + + case TB_METHOD_BASE_TYPE: + if (head && (TREE_CODE (head) == FUNCTION_TYPE + || TREE_CODE (head) == METHOD_TYPE) + && TYPE_METHOD_BASETYPE (head)) + TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); + else + TB_WF; + break; + + case TB_FIELDS: + if (head && (TREE_CODE (head) == RECORD_TYPE + || TREE_CODE (head) == UNION_TYPE + || TREE_CODE (head) == QUAL_UNION_TYPE)) + TB_SET_HEAD (TYPE_FIELDS (head)); + else + TB_WF; + break; + + case TB_DOMAIN: + if (head && (TREE_CODE (head) == ARRAY_TYPE + || TREE_CODE (head) == SET_TYPE)) + TB_SET_HEAD (TYPE_DOMAIN (head)); + else + TB_WF; + break; + + case TB_VALUES: + if (head && TREE_CODE (head) == ENUMERAL_TYPE) + TB_SET_HEAD (TYPE_VALUES (head)); + else + TB_WF; + break; + + case TB_ARG_TYPE_AS_WRITTEN: + if (head && TREE_CODE (head) == PARM_DECL) + TB_SET_HEAD (DECL_ARG_TYPE_AS_WRITTEN (head)); + else + TB_WF; + break; + + case TB_ARG_TYPE: + if (head && TREE_CODE (head) == PARM_DECL) + TB_SET_HEAD (DECL_ARG_TYPE (head)); + else + TB_WF; + break; + + case TB_INITIAL: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_INITIAL (head)); + else + TB_WF; + break; + + case TB_RESULT: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_RESULT_FLD (head)); + else + TB_WF; + break; + + case TB_ARGUMENTS: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_ARGUMENTS (head)); + else + TB_WF; + break; + + case TB_ABSTRACT_ORIGIN: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); + else if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'b') + TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); + else + TB_WF; + break; + + case TB_ATTRIBUTES: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_ATTRIBUTES (head)); + else if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 't') + TB_SET_HEAD (TYPE_ATTRIBUTES (head)); + else + TB_WF; + break; + + case TB_CONTEXT: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_CONTEXT (head)); + else if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 't' + && TYPE_CONTEXT (head)) + TB_SET_HEAD (TYPE_CONTEXT (head)); + else + TB_WF; + break; + + case TB_OFFSET: + if (head && TREE_CODE (head) == FIELD_DECL) + TB_SET_HEAD (DECL_FIELD_OFFSET (head)); + else + TB_WF; + break; + + case TB_BIT_OFFSET: + if (head && TREE_CODE (head) == FIELD_DECL) + TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); + else + TB_WF; + break; + + case TB_UNIT_SIZE: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_SIZE_UNIT (head)); + else if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 't') + TB_SET_HEAD (TYPE_SIZE_UNIT (head)); + else + TB_WF; + break; + + case TB_SIZE: + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'd') + TB_SET_HEAD (DECL_SIZE (head)); + else if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 't') + TB_SET_HEAD (TYPE_SIZE (head)); + else + TB_WF; + break; + + case TB_TYPE: + if (head && TREE_TYPE (head)) + TB_SET_HEAD (TREE_TYPE (head)); + else + TB_WF; + break; + + case TB_DECL_SAVED_TREE: + if (head && TREE_CODE (head) == FUNCTION_DECL + && DECL_SAVED_TREE (head)) + TB_SET_HEAD (DECL_SAVED_TREE (head)); + else + TB_WF; + break; + + case TB_BODY: + if (head && TREE_CODE (head) == BIND_EXPR) + TB_SET_HEAD (TREE_OPERAND (head, 1)); + else + TB_WF; + break; + + case TB_CHILD_0: + if (head && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (head))) + && TREE_OPERAND (head, 0)) + TB_SET_HEAD (TREE_OPERAND (head, 0)); + else + TB_WF; + break; + + case TB_CHILD_1: + if (head && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (head))) + && TREE_OPERAND (head, 1)) + TB_SET_HEAD (TREE_OPERAND (head, 1)); + else + TB_WF; + break; + + case TB_CHILD_2: + if (head && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (head))) + && TREE_OPERAND (head, 2)) + TB_SET_HEAD (TREE_OPERAND (head, 2)); + else + TB_WF; + break; + + case TB_CHILD_3: + if (head && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (head))) + && TREE_OPERAND (head, 3)) + TB_SET_HEAD (TREE_OPERAND (head, 3)); + else + TB_WF; + break; + + case TB_PRINT: + if (head) + debug_tree (head); + else + TB_WF; + break; + + case TB_PRETTY_PRINT: + if (head) + { + print_generic_stmt (TB_OUT_FILE, head, 0); + fprintf (TB_OUT_FILE, "\n"); + } + else + TB_WF; + break; + + case TB_SEARCH_NAME: + + break; + + case TB_SEARCH_CODE: + { + enum tree_code code; + char *arg_text; + + arg_text = strchr (input, ' '); + if (arg_text == NULL) + { + fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); + break; + } + code = TB_get_tree_code (arg_text + 1); + + /* Search in the subtree a node with the given code. */ + { + tree res; + + res = walk_tree (&head, find_node_with_code, &code, NULL); + if (res == NULL_TREE) + { + fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); + } + else + { + fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); + TB_SET_HEAD (res); + } + } + break; + } + +#define TB_MOVE_HEAD(FCT) do { \ + if (head) \ + { \ + tree t; \ + t = FCT (head); \ + if (t) \ + TB_SET_HEAD (t); \ + else \ + TB_WF; \ + } \ + else \ + TB_WF; \ +} while (0) + + case TB_FIRST: + TB_MOVE_HEAD (TB_first_in_bind); + break; + + case TB_LAST: + TB_MOVE_HEAD (TB_last_in_bind); + break; + + case TB_UP: + TB_MOVE_HEAD (TB_up_expr); + break; + + case TB_PREV: + TB_MOVE_HEAD (TB_prev_expr); + break; + + case TB_NEXT: + TB_MOVE_HEAD (TB_next_expr); + break; + + case TB_HPREV: + /* This command is a little bit special, since it deals with history + stack. For this reason it should keep the "head = ..." statement + and not use TB_MOVE_HEAD. */ + if (head) + { + tree t; + t = TB_history_prev (); + if (t) + { + head = t; + if (TB_verbose) + { + print_generic_expr (TB_OUT_FILE, head, 0); + fprintf (TB_OUT_FILE, "\n"); + } + } + else + TB_WF; + } + else + TB_WF; + break; + + case TB_CHAIN: + /* Don't go further if it's the last node in this chain. */ + if (head && TREE_CODE_CLASS (TREE_CODE (head)) == 'b') + TB_SET_HEAD (BLOCK_CHAIN (head)); + else if (head && TREE_CHAIN (head)) + TB_SET_HEAD (TREE_CHAIN (head)); + else + TB_WF; + break; + + case TB_FUN: + /* Go up to the current function declaration. */ + TB_SET_HEAD (current_function_decl); + fprintf (TB_OUT_FILE, "Current function declaration.\n"); + break; + + case TB_HELP: + /* Display a help message. */ + { + int i; + fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); + for (i = 0; i < TB_UNUSED_COMMAND; i++) + { + fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); + } + } + break; + + case TB_VERBOSE: + if (TB_verbose == 0) + { + TB_verbose = 1; + fprintf (TB_OUT_FILE, "Verbose on.\n"); + } + else + { + TB_verbose = 0; + fprintf (TB_OUT_FILE, "Verbose off.\n"); + } + break; + + case TB_EXIT: + case TB_QUIT: + /* Just exit from this function. */ + goto ret; + + default: + TB_NIY; + } + } + + ret:; + htab_delete (TB_up_ht); + return; +} + + +/* Search the first node in this BIND_EXPR. */ + +static tree +TB_first_in_bind (tree node) +{ + tree t; + + if (node == NULL_TREE) + return NULL_TREE; + + while ((t = TB_prev_expr (node))) + node = t; + + return node; +} + +/* Search the last node in this BIND_EXPR. */ + +static tree +TB_last_in_bind (tree node) +{ + tree t; + + if (node == NULL_TREE) + return NULL_TREE; + + while ((t = TB_next_expr (node))) + node = t; + + return node; +} + +/* Search the parent expression for this node. */ + +static tree +TB_up_expr (tree node) +{ + tree res; + if (node == NULL_TREE) + return NULL_TREE; + + res = (tree) htab_find (TB_up_ht, node); + return res; +} + +/* Search the previous expression in this BIND_EXPR. */ + +static tree +TB_prev_expr (tree node) +{ + node = TB_current_chain_node (node); + + if (node == NULL_TREE) + return NULL_TREE; + + node = TB_up_expr (node); + if (node && TREE_CODE (node) == COMPOUND_EXPR) + return node; + else + return NULL_TREE; +} + +/* Search the next expression in this BIND_EXPR. */ + +static tree +TB_next_expr (tree node) +{ + node = TB_current_chain_node (node); + + if (node == NULL_TREE) + return NULL_TREE; + + node = TREE_OPERAND (node, 1); + return node; +} + +static tree +TB_current_chain_node (tree node) +{ + if (node == NULL_TREE) + return NULL_TREE; + + if (TREE_CODE (node) == COMPOUND_EXPR) + return node; + + node = TB_up_expr (node); + if (node) + { + if (TREE_CODE (node) == COMPOUND_EXPR) + return node; + + node = TB_up_expr (node); + if (TREE_CODE (node) == COMPOUND_EXPR) + return node; + } + + return NULL_TREE; +} + +/* For each node store in its children nodes that the current node is their + parent. This function is used by walk_tree. */ + +static tree +store_child_info (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + tree node; + void **slot; + + node = *tp; + + /* 'node' is the parent of 'TREE_OPERAND (node, *)'. */ + if (TREE_CODE_CLASS (TREE_CODE (node)) == 'e') + { + +#define STORE_CHILD(N) do { \ + tree op = TREE_OPERAND (node, N); \ + slot = htab_find_slot (TB_up_ht, op, INSERT); \ + *slot = (void *) node; \ +} while (0) + + switch (TREE_CODE_LENGTH (TREE_CODE (node))) + { + case 4: + STORE_CHILD (0); + STORE_CHILD (1); + STORE_CHILD (2); + STORE_CHILD (3); + break; + + case 3: + STORE_CHILD (0); + STORE_CHILD (1); + STORE_CHILD (2); + break; + + case 2: + STORE_CHILD (0); + STORE_CHILD (1); + break; + + case 1: + STORE_CHILD (0); + break; + + case 0: + default: + /* No children: nothing to do. */ + break; + } +#undef STORE_CHILD + } + + /* Never stop walk_tree. */ + return NULL_TREE; +} + +/* Function used in TB_up_ht. */ + +static int +TB_parent_eq (const void *p1, const void *p2) +{ + tree node, parent; + node = (tree) p2; + parent = (tree) p1; + + if (p1 == NULL || p2 == NULL) + return 0; + + if (TREE_CODE_CLASS(TREE_CODE(parent)) == 'e') + { + +#define TEST_CHILD(N) do { \ + if (node == TREE_OPERAND (parent, N)) \ + return 1; \ +} while (0) + + switch (TREE_CODE_LENGTH (TREE_CODE (parent))) + { + case 4: + TEST_CHILD (0); + TEST_CHILD (1); + TEST_CHILD (2); + TEST_CHILD (3); + break; + + case 3: + TEST_CHILD (0); + TEST_CHILD (1); + TEST_CHILD (2); + break; + + case 2: + TEST_CHILD (0); + TEST_CHILD (1); + break; + + case 1: + TEST_CHILD (0); + break; + + case 0: + default: + /* No children: nothing to do. */ + break; + } +#undef TEST_CHILD + } + + return 0; +} + +/* Update information about upper expressions in the hash table. */ + +static void +TB_update_up (tree node) +{ + while (node) + { + walk_tree (&node, store_child_info, NULL, NULL); + + /* Walk function's body. */ + if (TREE_CODE (node) == FUNCTION_DECL) + if (DECL_SAVED_TREE (node)) + walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL); + + /* Walk rest of the chain. */ + node = TREE_CHAIN (node); + } + fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n"); +} + +/* Parse the input string for determining the command the user asked for. */ + +static TB_CODE +TB_get_command (char *input) +{ + unsigned int mn, size_tok; + int comp; + char *space; + + space = strchr (input, ' '); + if (space != NULL) + size_tok = strlen (input) - strlen (space); + else + size_tok = strlen (input) - 1; + + for (mn = 0; mn < TB_UNUSED_COMMAND; mn++) + { + if (size_tok != TB_COMMAND_LEN (mn)) + continue; + + comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn)); + if (comp == 0) + /* Here we just determined the command. If this command takes + an argument, then the argument is determined later. */ + return TB_COMMAND_CODE (mn); + } + + /* Not a valid command. */ + return TB_UNUSED_COMMAND; +} + +/* Parse the input string for determining the tree code. */ + +static enum tree_code +TB_get_tree_code (char *input) +{ + unsigned int mn, size_tok; + int comp; + char *space; + + space = strchr (input, ' '); + if (space != NULL) + size_tok = strlen (input) - strlen (space); + else + size_tok = strlen (input) - 1; + + for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++) + { + if (size_tok != TB_TREE_CODE_LEN (mn)) + continue; + + comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn)); + if (comp == 0) + { + fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn)); + return TB_TREE_CODE (mn); + } + } + + /* This isn't a valid code. */ + return LAST_AND_UNUSED_TREE_CODE; +} + +/* Find a node with a given code. This function is used as an argument to + walk_tree. */ + +static tree +find_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) +{ + enum tree_code *code; + code = (enum tree_code *) data; + if (*code == TREE_CODE (*tp)) + return *tp; + + return NULL_TREE; +} + +/* Returns a pointer to the last visited node. */ + +static tree +TB_history_prev (void) +{ + if (TB_history_stack) + { + TB_history_stack = TREE_CHAIN (TB_history_stack); + if (TB_history_stack) + return TREE_VALUE (TB_history_stack); + } + return NULL_TREE; +} + +/* Read up to (and including) a '\n' from STREAM into *LINEPTR + (and null-terminate it). *LINEPTR is a pointer returned from malloc + (or NULL), pointing to *N characters of space. It is realloc'd as + necessary. Returns the number of characters read (not including the + null terminator), or -1 on error or EOF. + This function comes from sed (and is supposed to be a portable version + of getline). */ + +static long +TB_getline (char **lineptr, long *n, FILE *stream) +{ + char *line, *p; + long size, copy; + + if (lineptr == NULL || n == NULL) + { + errno = EINVAL; + return -1; + } + + if (ferror (stream)) + return -1; + + /* Make sure we have a line buffer to start with. */ + if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */ + { +#ifndef MAX_CANON +#define MAX_CANON 256 +#endif + line = (char *) xrealloc (*lineptr, MAX_CANON); + if (line == NULL) + return -1; + *lineptr = line; + *n = MAX_CANON; + } + + line = *lineptr; + size = *n; + + copy = size; + p = line; + + while (1) + { + long len; + + while (--copy > 0) + { + register int c = getc (stream); + if (c == EOF) + goto lose; + else if ((*p++ = c) == '\n') + goto win; + } + + /* Need to enlarge the line buffer. */ + len = p - line; + size *= 2; + line = (char *) xrealloc (line, size); + if (line == NULL) + goto lose; + *lineptr = line; + *n = size; + p = line + len; + copy = size - len; + } + + lose: + if (p == *lineptr) + return -1; + + /* Return a partial line since we got an error in the middle. */ + win: +#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) + if (p - 2 >= *lineptr && p[-2] == '\r') + p[-2] = p[-1], --p; +#endif + *p = '\0'; + return p - *lineptr; +} diff --git a/gcc/tree-browser.def b/gcc/tree-browser.def new file mode 100644 index 00000000000..57fb1df8044 --- /dev/null +++ b/gcc/tree-browser.def @@ -0,0 +1,98 @@ +/* Definitions and documentation for the codes used by the Tree Browser. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Sebastian Pop + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* First field in the following declarations is the code of the command + used by the tree browser. + Second field is what is parsed in order to recognize a command. + Third field is used for printing the help message. */ + + +/* Misc. commands. */ +DEFTBCODE (TB_EXIT, "x", "Exits tree-browser.") +DEFTBCODE (TB_QUIT, "q", "Exits tree-browser.") +DEFTBCODE (TB_HELP, "h", "Prints this help message.") +DEFTBCODE (TB_UPDATE_UP, "update", "Update information about parent expressions.") +DEFTBCODE (TB_VERBOSE, "verbose", "Sets/unsets verbose mode (default is on).") + +/* Walking commands. */ +DEFTBCODE (TB_FUN, "fun", "Go to the curent function declaration.") +DEFTBCODE (TB_NEXT, "nx", "Go to the next expression in a BIND_EXPR.") +DEFTBCODE (TB_PREV, "pr", "Go to the previous expression in a BIND_EXPR.") +DEFTBCODE (TB_UP, "up", "Go to the parent tree node.") +DEFTBCODE (TB_LAST, "last", "Go to the last expression in a BIND_EXPR.") +DEFTBCODE (TB_FIRST, "first","Go to the first expression in a BIND_EXPR.") +DEFTBCODE (TB_HPREV, "hpr", "Go to the previous visited node (history previous).") + +/* Fields accessors. */ +DEFTBCODE (TB_CHILD_0, "arg0", "Child 0.") +DEFTBCODE (TB_CHILD_1, "arg1", "Child 1.") +DEFTBCODE (TB_CHILD_2, "arg2", "Child 2.") +DEFTBCODE (TB_CHILD_3, "arg3", "Child 3.") +DEFTBCODE (TB_DECL_SAVED_TREE, "decl_saved_tree", "Body of a function.") +DEFTBCODE (TB_TYPE, "type", "Field accessor.") +DEFTBCODE (TB_SIZE, "size", "Field accessor.") +DEFTBCODE (TB_UNIT_SIZE, "unit_size", "Field accessor.") +DEFTBCODE (TB_OFFSET, "offset", "Field accessor.") +DEFTBCODE (TB_BIT_OFFSET, "bit_offset", "Field accessor.") +DEFTBCODE (TB_CONTEXT, "context", "Field accessor.") +DEFTBCODE (TB_ATTRIBUTES, "attributes", "Field accessor.") +DEFTBCODE (TB_ABSTRACT_ORIGIN, "abstract_origin", "Field accessor.") +DEFTBCODE (TB_ARGUMENTS, "arguments", "Field accessor.") +DEFTBCODE (TB_RESULT, "result", "Field accessor.") +DEFTBCODE (TB_INITIAL, "initial", "Field accessor.") +DEFTBCODE (TB_ARG_TYPE, "arg-type", "Field accessor.") +DEFTBCODE (TB_ARG_TYPE_AS_WRITTEN, "arg-type-as-written", "Field accessor.") +DEFTBCODE (TB_CHAIN, "chain", "Field accessor.") +DEFTBCODE (TB_VALUES, "values", "Field accessor.") +DEFTBCODE (TB_DOMAIN, "domain", "Field accessor.") +DEFTBCODE (TB_METHOD_BASE_TYPE, "method_basetype", "Field accessor.") +DEFTBCODE (TB_FIELDS, "fields", "Field accessor.") +DEFTBCODE (TB_ARG_TYPES, "arg-types", "Field accessor.") +DEFTBCODE (TB_BASETYPE, "basetype", "Field accessor.") +DEFTBCODE (TB_POINTER_TO_THIS, "pointer_to_this", "Field accessor.") +DEFTBCODE (TB_REFERENCE_TO_THIS,"reference_to_this", "Field accessor.") +DEFTBCODE (TB_VARS, "vars", "Field accessor.") +DEFTBCODE (TB_SUPERCONTEXT, "supercontext", "Field accessor.") +DEFTBCODE (TB_BODY, "body", "Field accessor.") +DEFTBCODE (TB_SUBBLOCKS, "subblocks", "Field accessor.") +DEFTBCODE (TB_BLOCK, "block", "Field accessor.") +DEFTBCODE (TB_REAL, "real", "Field accessor.") +DEFTBCODE (TB_IMAG, "imag", "Field accessor.") +DEFTBCODE (TB_PURPOSE, "purpose", "Field accessor.") +DEFTBCODE (TB_VALUE, "value", "Field accessor.") +DEFTBCODE (TB_ELT, "elt", "Field accessor.") +DEFTBCODE (TB_MIN, "min", "Field accessor.") +DEFTBCODE (TB_MAX, "max", "Field accessor.") + +/* Searching commands. */ +DEFTBCODE (TB_SEARCH_CODE, "sc", "Search a node having a TREE_CODE given as a parameter.") +DEFTBCODE (TB_SEARCH_NAME, "sn", "Search an identifier having a name given as a parameter.") + +/* Printing commands. */ +DEFTBCODE (TB_PRETTY_PRINT, "pp", "Pretty print current node.") +DEFTBCODE (TB_PRINT, "p", "Prints the current node.") + + +/* +Local variables: +mode:c +End: +*/ diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c new file mode 100644 index 00000000000..26954e4bd01 --- /dev/null +++ b/gcc/tree-cfg.c @@ -0,0 +1,4594 @@ +/* Control flow functions for trees. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "ggc.h" +#include "langhooks.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "timevar.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "toplev.h" +#include "except.h" +#include "cfgloop.h" + +/* This file contains functions for building the Control Flow Graph (CFG) + for a function tree. */ + +/* Local declarations. */ + +/* Initial capacity for the basic block array. */ +static const int initial_cfg_capacity = 20; + +/* Mapping of labels to their associated blocks. This can greatly speed up + building of the CFG in code with lots of gotos. */ +static GTY(()) varray_type label_to_block_map; + +/* CFG statistics. */ +struct cfg_stats_d +{ + long num_merged_labels; +}; + +static struct cfg_stats_d cfg_stats; + +/* Nonzero if we found a computed goto while building basic blocks. */ +static bool found_computed_goto; + +/* Basic blocks and flowgraphs. */ +static basic_block create_bb (void *, void *, basic_block); +static void create_block_annotation (basic_block); +static void free_blocks_annotations (void); +static void clear_blocks_annotations (void); +static void make_blocks (tree); +static void factor_computed_gotos (void); +static tree tree_block_label (basic_block bb); + +/* Edges. */ +static void make_edges (void); +static void make_ctrl_stmt_edges (basic_block); +static void make_exit_edges (basic_block); +static void make_cond_expr_edges (basic_block); +static void make_switch_expr_edges (basic_block); +static void make_goto_expr_edges (basic_block); +static edge tree_redirect_edge_and_branch (edge, basic_block); +static edge tree_try_redirect_by_replacing_jump (edge, basic_block); +static void split_critical_edges (void); + +/* Various helpers. */ +static inline bool stmt_starts_bb_p (tree, tree); +static int tree_verify_flow_info (void); +static void tree_make_forwarder_block (edge); +static bool thread_jumps (void); +static bool tree_forwarder_block_p (basic_block); +static void bsi_commit_edge_inserts_1 (edge e); +static void tree_cfg2vcg (FILE *); + +/* Flowgraph optimization and cleanup. */ +static void tree_merge_blocks (basic_block, basic_block); +static bool tree_can_merge_blocks_p (basic_block, basic_block); +static void remove_bb (basic_block); +static void cleanup_dead_labels (void); +static bool cleanup_control_flow (void); +static bool cleanup_control_expr_graph (basic_block, block_stmt_iterator); +static edge find_taken_edge_cond_expr (basic_block, tree); +static edge find_taken_edge_switch_expr (basic_block, tree); +static tree find_case_label_for_value (tree, tree); +static bool phi_alternatives_equal (basic_block, edge, edge); + + +/*--------------------------------------------------------------------------- + Create basic blocks +---------------------------------------------------------------------------*/ + +/* Entry point to the CFG builder for trees. TP points to the list of + statements to be added to the flowgraph. */ + +static void +build_tree_cfg (tree *tp) +{ + /* Register specific tree functions. */ + tree_register_cfg_hooks (); + + /* Initialize rbi_pool. */ + alloc_rbi_pool (); + + /* Initialize the basic block array. */ + init_flow (); + n_basic_blocks = 0; + last_basic_block = 0; + VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info"); + memset ((void *) &cfg_stats, 0, sizeof (cfg_stats)); + + /* Build a mapping of labels to their associated blocks. */ + VARRAY_BB_INIT (label_to_block_map, initial_cfg_capacity, + "label to block map"); + + ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR; + EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR; + + found_computed_goto = 0; + make_blocks (*tp); + + /* Computed gotos are hell to deal with, especially if there are + lots of them with a large number of destinations. So we factor + them to a common computed goto location before we build the + edge list. After we convert back to normal form, we will un-factor + the computed gotos since factoring introduces an unwanted jump. */ + if (found_computed_goto) + factor_computed_gotos (); + + /* Make sure there is always at least one block, even if its empty. */ + if (n_basic_blocks == 0) + create_empty_bb (ENTRY_BLOCK_PTR); + + create_block_annotation (ENTRY_BLOCK_PTR); + create_block_annotation (EXIT_BLOCK_PTR); + + /* Adjust the size of the array. */ + VARRAY_GROW (basic_block_info, n_basic_blocks); + + /* Create the edges of the flowgraph. */ + make_edges (); + + /* Debugging dumps. */ + + /* Write the flowgraph to a VCG file. */ + { + int local_dump_flags; + FILE *dump_file = dump_begin (TDI_vcg, &local_dump_flags); + if (dump_file) + { + tree_cfg2vcg (dump_file); + dump_end (TDI_vcg, dump_file); + } + } + + /* Dump a textual representation of the flowgraph. */ + if (dump_file) + dump_tree_cfg (dump_file, dump_flags); +} + +static void +execute_build_cfg (void) +{ + build_tree_cfg (&DECL_SAVED_TREE (current_function_decl)); +} + +struct tree_opt_pass pass_build_cfg = +{ + "cfg", /* name */ + NULL, /* gate */ + execute_build_cfg, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_CFG, /* tv_id */ + PROP_gimple_leh, /* properties_required */ + PROP_cfg, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_verify_stmts /* todo_flags_finish */ +}; + +/* Search the CFG for any computed gotos. If found, factor them to a + common computed goto site. Also record the location of that site so + that we can un-factor the gotos after we have converted back to + normal form. */ + +static void +factor_computed_gotos (void) +{ + basic_block bb; + tree factored_label_decl = NULL; + tree var = NULL; + tree factored_computed_goto_label = NULL; + tree factored_computed_goto = NULL; + + /* We know there are one or more computed gotos in this function. + Examine the last statement in each basic block to see if the block + ends with a computed goto. */ + + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi = bsi_last (bb); + tree last; + + if (bsi_end_p (bsi)) + continue; + last = bsi_stmt (bsi); + + /* Ignore the computed goto we create when we factor the original + computed gotos. */ + if (last == factored_computed_goto) + continue; + + /* If the last statement is a computed goto, factor it. */ + if (computed_goto_p (last)) + { + tree assignment; + + /* The first time we find a computed goto we need to create + the factored goto block and the variable each original + computed goto will use for their goto destination. */ + if (! factored_computed_goto) + { + basic_block new_bb = create_empty_bb (bb); + block_stmt_iterator new_bsi = bsi_start (new_bb); + + /* Create the destination of the factored goto. Each original + computed goto will put its desired destination into this + variable and jump to the label we create immediately + below. */ + var = create_tmp_var (ptr_type_node, "gotovar"); + + /* Build a label for the new block which will contain the + factored computed goto. */ + factored_label_decl = create_artificial_label (); + factored_computed_goto_label + = build1 (LABEL_EXPR, void_type_node, factored_label_decl); + bsi_insert_after (&new_bsi, factored_computed_goto_label, + BSI_NEW_STMT); + + /* Build our new computed goto. */ + factored_computed_goto = build1 (GOTO_EXPR, void_type_node, var); + bsi_insert_after (&new_bsi, factored_computed_goto, + BSI_NEW_STMT); + } + + /* Copy the original computed goto's destination into VAR. */ + assignment = build (MODIFY_EXPR, ptr_type_node, + var, GOTO_DESTINATION (last)); + bsi_insert_before (&bsi, assignment, BSI_SAME_STMT); + + /* And re-vector the computed goto to the new destination. */ + GOTO_DESTINATION (last) = factored_label_decl; + } + } +} + + +/* Create annotations for a single basic block. */ + +static void +create_block_annotation (basic_block bb) +{ + /* Verify that the tree_annotations field is clear. */ + if (bb->tree_annotations) + abort (); + bb->tree_annotations = ggc_alloc_cleared (sizeof (struct bb_ann_d)); +} + + +/* Free the annotations for all the basic blocks. */ + +static void free_blocks_annotations (void) +{ + clear_blocks_annotations (); +} + + +/* Clear the annotations for all the basic blocks. */ + +static void +clear_blocks_annotations (void) +{ + basic_block bb; + + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb) + bb->tree_annotations = NULL; +} + + +/* Build a flowgraph for the statement_list STMT_LIST. */ + +static void +make_blocks (tree stmt_list) +{ + tree_stmt_iterator i = tsi_start (stmt_list); + tree stmt = NULL; + bool start_new_block = true; + bool first_stmt_of_list = true; + basic_block bb = ENTRY_BLOCK_PTR; + + while (!tsi_end_p (i)) + { + tree prev_stmt; + + prev_stmt = stmt; + stmt = tsi_stmt (i); + + /* If the statement starts a new basic block or if we have determined + in a previous pass that we need to create a new block for STMT, do + so now. */ + if (start_new_block || stmt_starts_bb_p (stmt, prev_stmt)) + { + if (!first_stmt_of_list) + stmt_list = tsi_split_statement_list_before (&i); + bb = create_basic_block (stmt_list, NULL, bb); + start_new_block = false; + } + + /* Now add STMT to BB and create the subgraphs for special statement + codes. */ + set_bb_for_stmt (stmt, bb); + + if (computed_goto_p (stmt)) + found_computed_goto = true; + + /* If STMT is a basic block terminator, set START_NEW_BLOCK for the + next iteration. */ + if (stmt_ends_bb_p (stmt)) + start_new_block = true; + + tsi_next (&i); + first_stmt_of_list = false; + } +} + + +/* Create and return a new empty basic block after bb AFTER. */ + +static basic_block +create_bb (void *h, void *e, basic_block after) +{ + basic_block bb; + + if (e) + abort (); + + /* Create and initialize a new basic block. */ + bb = alloc_block (); + memset (bb, 0, sizeof (*bb)); + + bb->index = last_basic_block; + bb->flags = BB_NEW; + bb->stmt_list = h ? h : alloc_stmt_list (); + + /* Add the new block to the linked list of blocks. */ + link_block (bb, after); + + /* Grow the basic block array if needed. */ + if ((size_t) last_basic_block == VARRAY_SIZE (basic_block_info)) + { + size_t new_size = last_basic_block + (last_basic_block + 3) / 4; + VARRAY_GROW (basic_block_info, new_size); + } + + /* Add the newly created block to the array. */ + BASIC_BLOCK (last_basic_block) = bb; + + create_block_annotation (bb); + + n_basic_blocks++; + last_basic_block++; + + initialize_bb_rbi (bb); + return bb; +} + + +/*--------------------------------------------------------------------------- + Edge creation +---------------------------------------------------------------------------*/ + +/* Join all the blocks in the flowgraph. */ + +static void +make_edges (void) +{ + basic_block bb; + edge e; + + /* Create an edge from entry to the first block with executable + statements in it. */ + make_edge (ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU); + + /* Traverse basic block array placing edges. */ + FOR_EACH_BB (bb) + { + tree first = first_stmt (bb); + tree last = last_stmt (bb); + + if (first) + { + /* Edges for statements that always alter flow control. */ + if (is_ctrl_stmt (last)) + make_ctrl_stmt_edges (bb); + + /* Edges for statements that sometimes alter flow control. */ + if (is_ctrl_altering_stmt (last)) + make_exit_edges (bb); + } + + /* Finally, if no edges were created above, this is a regular + basic block that only needs a fallthru edge. */ + if (bb->succ == NULL) + make_edge (bb, bb->next_bb, EDGE_FALLTHRU); + } + + /* If there is a fallthru edge to exit out of the last block, transform it + to a return statement. */ + for (e = EXIT_BLOCK_PTR->prev_bb->succ; e; e = e->succ_next) + if (e->flags & EDGE_FALLTHRU) + break; + + if (e && e->dest == EXIT_BLOCK_PTR) + { + block_stmt_iterator bsi; + basic_block ret_bb = EXIT_BLOCK_PTR->prev_bb; + tree x; + + /* If E->SRC ends with a call that has an abnormal edge (for EH or + nonlocal goto), then we will need to split the edge to insert + an explicit return statement. */ + if (e != ret_bb->succ || e->succ_next) + { + ret_bb = split_edge (e); + e = ret_bb->succ; + } + e->flags &= ~EDGE_FALLTHRU; + + x = build (RETURN_EXPR, void_type_node, NULL_TREE); + bsi = bsi_last (ret_bb); + bsi_insert_after (&bsi, x, BSI_NEW_STMT); + } + + /* We do not care about fake edges, so remove any that the CFG + builder inserted for completeness. */ + remove_fake_edges (); + + /* To speed up statement iterator walks, we first purge dead labels. */ + cleanup_dead_labels (); + + /* Clean up the graph and warn for unreachable code. */ + cleanup_tree_cfg (); +} + + +/* Create edges for control statement at basic block BB. */ + +static void +make_ctrl_stmt_edges (basic_block bb) +{ + tree last = last_stmt (bb); + tree first = first_stmt (bb); + +#if defined ENABLE_CHECKING + if (last == NULL_TREE) + abort(); +#endif + + if (TREE_CODE (first) == LABEL_EXPR + && DECL_NONLOCAL (LABEL_EXPR_LABEL (first))) + make_edge (ENTRY_BLOCK_PTR, bb, EDGE_ABNORMAL); + + switch (TREE_CODE (last)) + { + case GOTO_EXPR: + make_goto_expr_edges (bb); + break; + + case RETURN_EXPR: + make_edge (bb, EXIT_BLOCK_PTR, 0); + break; + + case COND_EXPR: + make_cond_expr_edges (bb); + break; + + case SWITCH_EXPR: + make_switch_expr_edges (bb); + break; + + case RESX_EXPR: + make_eh_edges (last); + /* Yet another NORETURN hack. */ + if (bb->succ == NULL) + make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE); + break; + + default: + abort (); + } +} + + +/* Create exit edges for statements in block BB that alter the flow of + control. Statements that alter the control flow are 'goto', 'return' + and calls to non-returning functions. */ + +static void +make_exit_edges (basic_block bb) +{ + tree last = last_stmt (bb); + + if (last == NULL_TREE) + abort (); + + switch (TREE_CODE (last)) + { + case CALL_EXPR: + /* If this function receives a nonlocal goto, then we need to + make edges from this call site to all the nonlocal goto + handlers. */ + if (TREE_SIDE_EFFECTS (last) + && current_function_has_nonlocal_label) + make_goto_expr_edges (bb); + + /* If this statement has reachable exception handlers, then + create abnormal edges to them. */ + make_eh_edges (last); + + /* Some calls are known not to return. For such calls we create + a fake edge. + + We really need to revamp how we build edges so that it's not + such a bloody pain to avoid creating edges for this case since + all we do is remove these edges when we're done building the + CFG. */ + if (call_expr_flags (last) & (ECF_NORETURN | ECF_LONGJMP)) + { + make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE); + return; + } + + /* Don't forget the fall-thru edge. */ + make_edge (bb, bb->next_bb, EDGE_FALLTHRU); + break; + + case MODIFY_EXPR: + /* A MODIFY_EXPR may have a CALL_EXPR on its RHS and the CALL_EXPR + may have an abnormal edge. Search the RHS for this case and + create any required edges. */ + if (TREE_CODE (TREE_OPERAND (last, 1)) == CALL_EXPR + && TREE_SIDE_EFFECTS (TREE_OPERAND (last, 1)) + && current_function_has_nonlocal_label) + make_goto_expr_edges (bb); + + make_eh_edges (last); + make_edge (bb, bb->next_bb, EDGE_FALLTHRU); + break; + + default: + abort (); + } +} + + +/* Create the edges for a COND_EXPR starting at block BB. + At this point, both clauses must contain only simple gotos. */ + +static void +make_cond_expr_edges (basic_block bb) +{ + tree entry = last_stmt (bb); + basic_block then_bb, else_bb; + tree then_label, else_label; + +#if defined ENABLE_CHECKING + if (entry == NULL_TREE || TREE_CODE (entry) != COND_EXPR) + abort (); +#endif + + /* Entry basic blocks for each component. */ + then_label = GOTO_DESTINATION (COND_EXPR_THEN (entry)); + else_label = GOTO_DESTINATION (COND_EXPR_ELSE (entry)); + then_bb = label_to_block (then_label); + else_bb = label_to_block (else_label); + + make_edge (bb, then_bb, EDGE_TRUE_VALUE); + make_edge (bb, else_bb, EDGE_FALSE_VALUE); +} + + +/* Create the edges for a SWITCH_EXPR starting at block BB. + At this point, the switch body has been lowered and the + SWITCH_LABELS filled in, so this is in effect a multi-way branch. */ + +static void +make_switch_expr_edges (basic_block bb) +{ + tree entry = last_stmt (bb); + size_t i, n; + tree vec; + + vec = SWITCH_LABELS (entry); + n = TREE_VEC_LENGTH (vec); + + for (i = 0; i < n; ++i) + { + tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i)); + basic_block label_bb = label_to_block (lab); + make_edge (bb, label_bb, 0); + } +} + + +/* Return the basic block holding label DEST. */ + +basic_block +label_to_block (tree dest) +{ + return VARRAY_BB (label_to_block_map, LABEL_DECL_UID (dest)); +} + + +/* Create edges for a goto statement at block BB. */ + +static void +make_goto_expr_edges (basic_block bb) +{ + tree goto_t, dest; + basic_block target_bb; + int for_call; + block_stmt_iterator last = bsi_last (bb); + + goto_t = bsi_stmt (last); + + /* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR, + CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting + from a nonlocal goto. */ + if (TREE_CODE (goto_t) != GOTO_EXPR) + { + dest = error_mark_node; + for_call = 1; + } + else + { + dest = GOTO_DESTINATION (goto_t); + for_call = 0; + + /* A GOTO to a local label creates normal edges. */ + if (simple_goto_p (goto_t)) + { + make_edge (bb, label_to_block (dest), EDGE_FALLTHRU); + bsi_remove (&last); + return; + } + + /* Nothing more to do for nonlocal gotos. */ + if (TREE_CODE (dest) == LABEL_DECL) + return; + + /* Computed gotos remain. */ + } + + /* Look for the block starting with the destination label. In the + case of a computed goto, make an edge to any label block we find + in the CFG. */ + FOR_EACH_BB (target_bb) + { + block_stmt_iterator bsi; + + for (bsi = bsi_start (target_bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree target = bsi_stmt (bsi); + + if (TREE_CODE (target) != LABEL_EXPR) + break; + + if ( + /* Computed GOTOs. Make an edge to every label block that has + been marked as a potential target for a computed goto. */ + (FORCED_LABEL (LABEL_EXPR_LABEL (target)) && for_call == 0) + /* Nonlocal GOTO target. Make an edge to every label block + that has been marked as a potential target for a nonlocal + goto. */ + || (DECL_NONLOCAL (LABEL_EXPR_LABEL (target)) && for_call == 1)) + { + make_edge (bb, target_bb, EDGE_ABNORMAL); + break; + } + } + } + + /* Degenerate case of computed goto with no labels. */ + if (!for_call && !bb->succ) + make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE); +} + + +/*--------------------------------------------------------------------------- + Flowgraph analysis +---------------------------------------------------------------------------*/ + +/* Remove unreachable blocks and other miscellaneous clean up work. */ + +void +cleanup_tree_cfg (void) +{ + bool something_changed = true; + + timevar_push (TV_TREE_CLEANUP_CFG); + + /* These three transformations can cascade, so we iterate on them until + nothing changes. */ + while (something_changed) + { + something_changed = cleanup_control_flow (); + something_changed |= thread_jumps (); + something_changed |= delete_unreachable_blocks (); + } + + /* Merging the blocks creates no new opportunities for the other + optimizations, so do it here. */ + merge_seq_blocks (); + + compact_blocks (); + +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif + timevar_pop (TV_TREE_CLEANUP_CFG); +} + + +/* Cleanup useless labels from the flow graph. */ + +static void +cleanup_dead_labels (void) +{ + basic_block bb; + tree *label_for_bb = xcalloc (last_basic_block, sizeof (tree)); + + /* Find a suitable label for each block. We use the first user-defined + label is there is one, or otherwise just the first label we see. */ + FOR_EACH_BB (bb) + { + block_stmt_iterator i; + + for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) + { + tree label, stmt = bsi_stmt (i); + + if (TREE_CODE (stmt) != LABEL_EXPR) + break; + + label = LABEL_EXPR_LABEL (stmt); + + /* If we have not yet seen a label for the current block, + remember this one and see if there are more labels. */ + if (! label_for_bb[bb->index]) + { + label_for_bb[bb->index] = label; + continue; + } + + /* If we did see a label for the current block already, but it + is an artificially created label, replace it if the current + label is a user defined label. */ + if (! DECL_ARTIFICIAL (label) + && DECL_ARTIFICIAL (label_for_bb[bb->index])) + { + label_for_bb[bb->index] = label; + break; + } + } + } + + /* Now redirect all jumps/branches to the selected label for each block. */ + FOR_EACH_BB (bb) + { + tree stmt = last_stmt (bb); + if (!stmt) + continue; + + switch (TREE_CODE (stmt)) + { + case COND_EXPR: + { + tree true_branch, false_branch; + basic_block true_bb, false_bb; + + true_branch = COND_EXPR_THEN (stmt); + false_branch = COND_EXPR_ELSE (stmt); + true_bb = label_to_block (GOTO_DESTINATION (true_branch)); + false_bb = label_to_block (GOTO_DESTINATION (false_branch)); + + GOTO_DESTINATION (true_branch) = label_for_bb[true_bb->index]; + GOTO_DESTINATION (false_branch) = label_for_bb[false_bb->index]; + + break; + } + + case SWITCH_EXPR: + { + size_t i; + tree vec = SWITCH_LABELS (stmt); + size_t n = TREE_VEC_LENGTH (vec); + + /* Replace all destination labels. */ + for (i = 0; i < n; ++i) + { + tree label = CASE_LABEL (TREE_VEC_ELT (vec, i)); + + CASE_LABEL (TREE_VEC_ELT (vec, i)) = + label_for_bb[label_to_block (label)->index]; + } + + break; + } + + default: + break; + } + } + + /* Finally, purge dead labels. All user-defined labels and labels that + can be the target of non-local gotos are preserved. */ + FOR_EACH_BB (bb) + { + block_stmt_iterator i; + tree label_for_this_bb = label_for_bb[bb->index]; + + if (! label_for_this_bb) + continue; + + for (i = bsi_start (bb); !bsi_end_p (i); ) + { + tree label, stmt = bsi_stmt (i); + + if (TREE_CODE (stmt) != LABEL_EXPR) + break; + + label = LABEL_EXPR_LABEL (stmt); + + if (label == label_for_this_bb + || ! DECL_ARTIFICIAL (label) + || DECL_NONLOCAL (label)) + bsi_next (&i); + else + bsi_remove (&i); + } + } + + free (label_for_bb); +} + + +/* Checks whether we can merge block B into block A. */ + +static bool +tree_can_merge_blocks_p (basic_block a, basic_block b) +{ + tree stmt; + block_stmt_iterator bsi; + + if (!a->succ + || a->succ->succ_next) + return false; + + if (a->succ->flags & EDGE_ABNORMAL) + return false; + + if (a->succ->dest != b) + return false; + + if (b == EXIT_BLOCK_PTR) + return false; + + if (b->pred->pred_next) + return false; + + /* If A ends by a statement causing exceptions or something similar, we + cannot merge the blocks. */ + stmt = last_stmt (a); + if (stmt && stmt_ends_bb_p (stmt)) + return false; + + /* Do not allow a block with only a non-local label to be merged. */ + if (stmt && TREE_CODE (stmt) == LABEL_EXPR + && DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt))) + return false; + + /* There may be no phi nodes at the start of b. Most of these degenerate + phi nodes should be cleaned up by kill_redundant_phi_nodes. */ + if (phi_nodes (b)) + return false; + + /* Do not remove user labels. */ + for (bsi = bsi_start (b); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + if (TREE_CODE (stmt) != LABEL_EXPR) + break; + if (!DECL_ARTIFICIAL (LABEL_EXPR_LABEL (stmt))) + return false; + } + + return true; +} + + +/* Merge block B into block A. */ + +static void +tree_merge_blocks (basic_block a, basic_block b) +{ + block_stmt_iterator bsi; + tree_stmt_iterator last; + + if (dump_file) + fprintf (dump_file, "Merging blocks %d and %d\n", a->index, b->index); + + /* Ensure that B follows A. */ + move_block_after (b, a); + + if (!(a->succ->flags & EDGE_FALLTHRU)) + abort (); + + if (last_stmt (a) + && stmt_ends_bb_p (last_stmt (a))) + abort (); + + /* Remove labels from B and set bb_for_stmt to A for other statements. */ + for (bsi = bsi_start (b); !bsi_end_p (bsi);) + { + if (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR) + bsi_remove (&bsi); + else + { + set_bb_for_stmt (bsi_stmt (bsi), a); + bsi_next (&bsi); + } + } + + /* Merge the chains. */ + last = tsi_last (a->stmt_list); + tsi_link_after (&last, b->stmt_list, TSI_NEW_STMT); + b->stmt_list = NULL; +} + + +/* Walk the function tree removing unnecessary statements. + + * Empty statement nodes are removed + + * Unnecessary TRY_FINALLY and TRY_CATCH blocks are removed + + * Unnecessary COND_EXPRs are removed + + * Some unnecessary BIND_EXPRs are removed + + Clearly more work could be done. The trick is doing the analysis + and removal fast enough to be a net improvement in compile times. + + Note that when we remove a control structure such as a COND_EXPR + BIND_EXPR, or TRY block, we will need to repeat this optimization pass + to ensure we eliminate all the useless code. */ + +struct rus_data +{ + tree *last_goto; + bool repeat; + bool may_throw; + bool may_branch; + bool has_label; +}; + +static void remove_useless_stmts_1 (tree *, struct rus_data *); + +static bool +remove_useless_stmts_warn_notreached (tree stmt) +{ + if (EXPR_LOCUS (stmt)) + { + warning ("%Hwill never be executed", EXPR_LOCUS (stmt)); + return true; + } + + switch (TREE_CODE (stmt)) + { + case STATEMENT_LIST: + { + tree_stmt_iterator i; + for (i = tsi_start (stmt); !tsi_end_p (i); tsi_next (&i)) + if (remove_useless_stmts_warn_notreached (tsi_stmt (i))) + return true; + } + break; + + case COND_EXPR: + if (remove_useless_stmts_warn_notreached (COND_EXPR_COND (stmt))) + return true; + if (remove_useless_stmts_warn_notreached (COND_EXPR_THEN (stmt))) + return true; + if (remove_useless_stmts_warn_notreached (COND_EXPR_ELSE (stmt))) + return true; + break; + + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + if (remove_useless_stmts_warn_notreached (TREE_OPERAND (stmt, 0))) + return true; + if (remove_useless_stmts_warn_notreached (TREE_OPERAND (stmt, 1))) + return true; + break; + + case CATCH_EXPR: + return remove_useless_stmts_warn_notreached (CATCH_BODY (stmt)); + case EH_FILTER_EXPR: + return remove_useless_stmts_warn_notreached (EH_FILTER_FAILURE (stmt)); + case BIND_EXPR: + return remove_useless_stmts_warn_notreached (BIND_EXPR_BLOCK (stmt)); + + default: + /* Not a live container. */ + break; + } + + return false; +} + +static void +remove_useless_stmts_cond (tree *stmt_p, struct rus_data *data) +{ + tree then_clause, else_clause, cond; + bool save_has_label, then_has_label, else_has_label; + + save_has_label = data->has_label; + data->has_label = false; + data->last_goto = NULL; + + remove_useless_stmts_1 (&COND_EXPR_THEN (*stmt_p), data); + + then_has_label = data->has_label; + data->has_label = false; + data->last_goto = NULL; + + remove_useless_stmts_1 (&COND_EXPR_ELSE (*stmt_p), data); + + else_has_label = data->has_label; + data->has_label = save_has_label | then_has_label | else_has_label; + + fold_stmt (stmt_p); + then_clause = COND_EXPR_THEN (*stmt_p); + else_clause = COND_EXPR_ELSE (*stmt_p); + cond = COND_EXPR_COND (*stmt_p); + + /* If neither arm does anything at all, we can remove the whole IF. */ + if (!TREE_SIDE_EFFECTS (then_clause) && !TREE_SIDE_EFFECTS (else_clause)) + { + *stmt_p = build_empty_stmt (); + data->repeat = true; + } + + /* If there are no reachable statements in an arm, then we can + zap the entire conditional. */ + else if (integer_nonzerop (cond) && !else_has_label) + { + if (warn_notreached) + remove_useless_stmts_warn_notreached (else_clause); + *stmt_p = then_clause; + data->repeat = true; + } + else if (integer_zerop (cond) && !then_has_label) + { + if (warn_notreached) + remove_useless_stmts_warn_notreached (then_clause); + *stmt_p = else_clause; + data->repeat = true; + } + + /* Check a couple of simple things on then/else with single stmts. */ + else + { + tree then_stmt = expr_only (then_clause); + tree else_stmt = expr_only (else_clause); + + /* Notice branches to a common destination. */ + if (then_stmt && else_stmt + && TREE_CODE (then_stmt) == GOTO_EXPR + && TREE_CODE (else_stmt) == GOTO_EXPR + && (GOTO_DESTINATION (then_stmt) == GOTO_DESTINATION (else_stmt))) + { + *stmt_p = then_stmt; + data->repeat = true; + } + + /* If the THEN/ELSE clause merely assigns a value to a variable or + parameter which is already known to contain that value, then + remove the useless THEN/ELSE clause. */ + else if (TREE_CODE (cond) == VAR_DECL || TREE_CODE (cond) == PARM_DECL) + { + if (else_stmt + && TREE_CODE (else_stmt) == MODIFY_EXPR + && TREE_OPERAND (else_stmt, 0) == cond + && integer_zerop (TREE_OPERAND (else_stmt, 1))) + COND_EXPR_ELSE (*stmt_p) = alloc_stmt_list (); + } + else if ((TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR) + && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL + || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL) + && TREE_CONSTANT (TREE_OPERAND (cond, 1))) + { + tree stmt = (TREE_CODE (cond) == EQ_EXPR + ? then_stmt : else_stmt); + tree *location = (TREE_CODE (cond) == EQ_EXPR + ? &COND_EXPR_THEN (*stmt_p) + : &COND_EXPR_ELSE (*stmt_p)); + + if (stmt + && TREE_CODE (stmt) == MODIFY_EXPR + && TREE_OPERAND (stmt, 0) == TREE_OPERAND (cond, 0) + && TREE_OPERAND (stmt, 1) == TREE_OPERAND (cond, 1)) + *location = alloc_stmt_list (); + } + } + + /* Protect GOTOs in the arm of COND_EXPRs from being removed. They + would be re-introduced during lowering. */ + data->last_goto = NULL; +} + + +static void +remove_useless_stmts_tf (tree *stmt_p, struct rus_data *data) +{ + bool save_may_branch, save_may_throw; + bool this_may_branch, this_may_throw; + + /* Collect may_branch and may_throw information for the body only. */ + save_may_branch = data->may_branch; + save_may_throw = data->may_throw; + data->may_branch = false; + data->may_throw = false; + data->last_goto = NULL; + + remove_useless_stmts_1 (&TREE_OPERAND (*stmt_p, 0), data); + + this_may_branch = data->may_branch; + this_may_throw = data->may_throw; + data->may_branch |= save_may_branch; + data->may_throw |= save_may_throw; + data->last_goto = NULL; + + remove_useless_stmts_1 (&TREE_OPERAND (*stmt_p, 1), data); + + /* If the body is empty, then we can emit the FINALLY block without + the enclosing TRY_FINALLY_EXPR. */ + if (!TREE_SIDE_EFFECTS (TREE_OPERAND (*stmt_p, 0))) + { + *stmt_p = TREE_OPERAND (*stmt_p, 1); + data->repeat = true; + } + + /* If the handler is empty, then we can emit the TRY block without + the enclosing TRY_FINALLY_EXPR. */ + else if (!TREE_SIDE_EFFECTS (TREE_OPERAND (*stmt_p, 1))) + { + *stmt_p = TREE_OPERAND (*stmt_p, 0); + data->repeat = true; + } + + /* If the body neither throws, nor branches, then we can safely + string the TRY and FINALLY blocks together. */ + else if (!this_may_branch && !this_may_throw) + { + tree stmt = *stmt_p; + *stmt_p = TREE_OPERAND (stmt, 0); + append_to_statement_list (TREE_OPERAND (stmt, 1), stmt_p); + data->repeat = true; + } +} + + +static void +remove_useless_stmts_tc (tree *stmt_p, struct rus_data *data) +{ + bool save_may_throw, this_may_throw; + tree_stmt_iterator i; + tree stmt; + + /* Collect may_throw information for the body only. */ + save_may_throw = data->may_throw; + data->may_throw = false; + data->last_goto = NULL; + + remove_useless_stmts_1 (&TREE_OPERAND (*stmt_p, 0), data); + + this_may_throw = data->may_throw; + data->may_throw = save_may_throw; + + /* If the body cannot throw, then we can drop the entire TRY_CATCH_EXPR. */ + if (!this_may_throw) + { + if (warn_notreached) + remove_useless_stmts_warn_notreached (TREE_OPERAND (*stmt_p, 1)); + *stmt_p = TREE_OPERAND (*stmt_p, 0); + data->repeat = true; + return; + } + + /* Process the catch clause specially. We may be able to tell that + no exceptions propagate past this point. */ + + this_may_throw = true; + i = tsi_start (TREE_OPERAND (*stmt_p, 1)); + stmt = tsi_stmt (i); + data->last_goto = NULL; + + switch (TREE_CODE (stmt)) + { + case CATCH_EXPR: + for (; !tsi_end_p (i); tsi_next (&i)) + { + stmt = tsi_stmt (i); + /* If we catch all exceptions, then the body does not + propagate exceptions past this point. */ + if (CATCH_TYPES (stmt) == NULL) + this_may_throw = false; + data->last_goto = NULL; + remove_useless_stmts_1 (&CATCH_BODY (stmt), data); + } + break; + + case EH_FILTER_EXPR: + if (EH_FILTER_MUST_NOT_THROW (stmt)) + this_may_throw = false; + else if (EH_FILTER_TYPES (stmt) == NULL) + this_may_throw = false; + remove_useless_stmts_1 (&EH_FILTER_FAILURE (stmt), data); + break; + + default: + /* Otherwise this is a cleanup. */ + remove_useless_stmts_1 (&TREE_OPERAND (*stmt_p, 1), data); + + /* If the cleanup is empty, then we can emit the TRY block without + the enclosing TRY_CATCH_EXPR. */ + if (!TREE_SIDE_EFFECTS (TREE_OPERAND (*stmt_p, 1))) + { + *stmt_p = TREE_OPERAND (*stmt_p, 0); + data->repeat = true; + } + break; + } + data->may_throw |= this_may_throw; +} + + +static void +remove_useless_stmts_bind (tree *stmt_p, struct rus_data *data) +{ + tree block; + + /* First remove anything underneath the BIND_EXPR. */ + remove_useless_stmts_1 (&BIND_EXPR_BODY (*stmt_p), data); + + /* If the BIND_EXPR has no variables, then we can pull everything + up one level and remove the BIND_EXPR, unless this is the toplevel + BIND_EXPR for the current function or an inlined function. + + When this situation occurs we will want to apply this + optimization again. */ + block = BIND_EXPR_BLOCK (*stmt_p); + if (BIND_EXPR_VARS (*stmt_p) == NULL_TREE + && *stmt_p != DECL_SAVED_TREE (current_function_decl) + && (! block + || ! BLOCK_ABSTRACT_ORIGIN (block) + || (TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) + != FUNCTION_DECL))) + { + *stmt_p = BIND_EXPR_BODY (*stmt_p); + data->repeat = true; + } +} + + +static void +remove_useless_stmts_goto (tree *stmt_p, struct rus_data *data) +{ + tree dest = GOTO_DESTINATION (*stmt_p); + + data->may_branch = true; + data->last_goto = NULL; + + /* Record the last goto expr, so that we can delete it if unnecessary. */ + if (TREE_CODE (dest) == LABEL_DECL) + data->last_goto = stmt_p; +} + + +static void +remove_useless_stmts_label (tree *stmt_p, struct rus_data *data) +{ + tree label = LABEL_EXPR_LABEL (*stmt_p); + + data->has_label = true; + + /* We do want to jump across non-local label receiver code. */ + if (DECL_NONLOCAL (label)) + data->last_goto = NULL; + + else if (data->last_goto && GOTO_DESTINATION (*data->last_goto) == label) + { + *data->last_goto = build_empty_stmt (); + data->repeat = true; + } + + /* ??? Add something here to delete unused labels. */ +} + + +/* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its + decl. This allows us to eliminate redundant or useless + calls to "const" functions. + + Gimplifier already does the same operation, but we may notice functions + being const and pure once their calls has been gimplified, so we need + to update the flag. */ + +static void +update_call_expr_flags (tree call) +{ + tree decl = get_callee_fndecl (call); + if (!decl) + return; + if (call_expr_flags (call) & (ECF_CONST | ECF_PURE)) + TREE_SIDE_EFFECTS (call) = 0; + if (TREE_NOTHROW (decl)) + TREE_NOTHROW (call) = 1; +} + + +/* T is CALL_EXPR. Set current_function_calls_* flags. */ + +void +notice_special_calls (tree t) +{ + int flags = call_expr_flags (t); + + if (flags & ECF_MAY_BE_ALLOCA) + current_function_calls_alloca = true; + if (flags & ECF_RETURNS_TWICE) + current_function_calls_setjmp = true; +} + + +/* Clear flags set by notice_special_calls. Used by dead code removal + to update the flags. */ + +void +clear_special_calls (void) +{ + current_function_calls_alloca = false; + current_function_calls_setjmp = false; +} + + +static void +remove_useless_stmts_1 (tree *tp, struct rus_data *data) +{ + tree t = *tp; + + switch (TREE_CODE (t)) + { + case COND_EXPR: + remove_useless_stmts_cond (tp, data); + break; + + case TRY_FINALLY_EXPR: + remove_useless_stmts_tf (tp, data); + break; + + case TRY_CATCH_EXPR: + remove_useless_stmts_tc (tp, data); + break; + + case BIND_EXPR: + remove_useless_stmts_bind (tp, data); + break; + + case GOTO_EXPR: + remove_useless_stmts_goto (tp, data); + break; + + case LABEL_EXPR: + remove_useless_stmts_label (tp, data); + break; + + case RETURN_EXPR: + fold_stmt (tp); + data->last_goto = NULL; + data->may_branch = true; + break; + + case CALL_EXPR: + fold_stmt (tp); + data->last_goto = NULL; + notice_special_calls (t); + update_call_expr_flags (t); + if (tree_could_throw_p (t)) + data->may_throw = true; + break; + + case MODIFY_EXPR: + data->last_goto = NULL; + fold_stmt (tp); + if (TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR) + { + update_call_expr_flags (TREE_OPERAND (t, 1)); + notice_special_calls (TREE_OPERAND (t, 1)); + } + if (tree_could_throw_p (t)) + data->may_throw = true; + break; + + case STATEMENT_LIST: + { + tree_stmt_iterator i = tsi_start (t); + while (!tsi_end_p (i)) + { + t = tsi_stmt (i); + if (IS_EMPTY_STMT (t)) + { + tsi_delink (&i); + continue; + } + + remove_useless_stmts_1 (tsi_stmt_ptr (i), data); + + t = tsi_stmt (i); + if (TREE_CODE (t) == STATEMENT_LIST) + { + tsi_link_before (&i, t, TSI_SAME_STMT); + tsi_delink (&i); + } + else + tsi_next (&i); + } + } + break; + case SWITCH_EXPR: + fold_stmt (tp); + data->last_goto = NULL; + break; + + default: + data->last_goto = NULL; + break; + } +} + +static void +remove_useless_stmts (void) +{ + struct rus_data data; + + clear_special_calls (); + + do + { + memset (&data, 0, sizeof (data)); + remove_useless_stmts_1 (&DECL_SAVED_TREE (current_function_decl), &data); + } + while (data.repeat); +} + + +struct tree_opt_pass pass_remove_useless_stmts = +{ + "useless", /* name */ + NULL, /* gate */ + remove_useless_stmts, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_gimple_any, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ +}; + + +/* Remove obviously useless statements in basic block BB. */ + +static void +cfg_remove_useless_stmts_bb (basic_block bb) +{ + block_stmt_iterator bsi; + tree stmt = NULL_TREE; + tree cond, var = NULL_TREE, val = NULL_TREE; + struct var_ann_d *ann; + + /* Check whether we come here from a condition, and if so, get the + condition. */ + if (!bb->pred + || bb->pred->pred_next + || !(bb->pred->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))) + return; + + cond = COND_EXPR_COND (last_stmt (bb->pred->src)); + + if (TREE_CODE (cond) == VAR_DECL || TREE_CODE (cond) == PARM_DECL) + { + var = cond; + val = (bb->pred->flags & EDGE_FALSE_VALUE + ? boolean_false_node : boolean_true_node); + } + else if (TREE_CODE (cond) == TRUTH_NOT_EXPR + && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL + || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL)) + { + var = TREE_OPERAND (cond, 0); + val = (bb->pred->flags & EDGE_FALSE_VALUE + ? boolean_true_node : boolean_false_node); + } + else + { + if (bb->pred->flags & EDGE_FALSE_VALUE) + cond = invert_truthvalue (cond); + if (TREE_CODE (cond) == EQ_EXPR + && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL + || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL) + && (TREE_CODE (TREE_OPERAND (cond, 1)) == VAR_DECL + || TREE_CODE (TREE_OPERAND (cond, 1)) == PARM_DECL + || TREE_CONSTANT (TREE_OPERAND (cond, 1)))) + { + var = TREE_OPERAND (cond, 0); + val = TREE_OPERAND (cond, 1); + } + else + return; + } + + /* Only work for normal local variables. */ + ann = var_ann (var); + if (!ann + || ann->may_aliases + || TREE_ADDRESSABLE (var)) + return; + + if (! TREE_CONSTANT (val)) + { + ann = var_ann (val); + if (!ann + || ann->may_aliases + || TREE_ADDRESSABLE (val)) + return; + } + + /* Ignore floating point variables, since comparison behaves weird for + them. */ + if (FLOAT_TYPE_P (TREE_TYPE (var))) + return; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi);) + { + stmt = bsi_stmt (bsi); + + /* If the THEN/ELSE clause merely assigns a value to a variable/parameter + which is already known to contain that value, then remove the useless + THEN/ELSE clause. */ + if (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_OPERAND (stmt, 0) == var + && operand_equal_p (val, TREE_OPERAND (stmt, 1), 0)) + { + bsi_remove (&bsi); + continue; + } + + /* Invalidate the var if we encounter something that could modify it. */ + if (TREE_CODE (stmt) == ASM_EXPR + || TREE_CODE (stmt) == VA_ARG_EXPR + || (TREE_CODE (stmt) == MODIFY_EXPR + && (TREE_OPERAND (stmt, 0) == var + || TREE_OPERAND (stmt, 0) == val + || TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR))) + return; + + bsi_next (&bsi); + } +} + + +/* A CFG-aware version of remove_useless_stmts. */ + +void +cfg_remove_useless_stmts (void) +{ + basic_block bb; + +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif + + FOR_EACH_BB (bb) + { + cfg_remove_useless_stmts_bb (bb); + } +} + + +/* Remove PHI nodes associated with basic block BB and all edges out of BB. */ + +static void +remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb) +{ + tree phi; + + /* Since this block is no longer reachable, we can just delete all + of its PHI nodes. */ + phi = phi_nodes (bb); + while (phi) + { + tree next = TREE_CHAIN (phi); + remove_phi_node (phi, NULL_TREE, bb); + phi = next; + } + + /* Remove edges to BB's successors. */ + while (bb->succ != NULL) + ssa_remove_edge (bb->succ); +} + + +/* Remove statements of basic block BB. */ + +static void +remove_bb (basic_block bb) +{ + block_stmt_iterator i; + location_t *loc = NULL; + + if (dump_file) + { + fprintf (dump_file, "Removing basic block %d\n", bb->index); + if (dump_flags & TDF_DETAILS) + { + dump_bb (bb, dump_file, 0); + fprintf (dump_file, "\n"); + } + } + + /* Remove all the instructions in the block. */ + for (i = bsi_start (bb); !bsi_end_p (i); bsi_remove (&i)) + { + tree stmt = bsi_stmt (i); + + set_bb_for_stmt (stmt, NULL); + + /* Don't warn for removed gotos. Gotos are often removed due to + jump threading, thus resulting in bogus warnings. Not great, + since this way we lose warnings for gotos in the original + program that are indeed unreachable. */ + if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_LOCUS (stmt) && !loc) + loc = EXPR_LOCUS (stmt); + } + + /* If requested, give a warning that the first statement in the + block is unreachable. We walk statements backwards in the + loop above, so the last statement we process is the first statement + in the block. */ + if (warn_notreached && loc) + warning ("%Hwill never be executed", loc); + + remove_phi_nodes_and_edges_for_unreachable_block (bb); +} + + +/* Examine BB to determine if it is a forwarding block (a block which only + transfers control to a new destination). If BB is a forwarding block, + then return the edge leading to the ultimate destination. */ + +edge +tree_block_forwards_to (basic_block bb) +{ + block_stmt_iterator bsi; + bb_ann_t ann = bb_ann (bb); + tree stmt; + + /* If this block is not forwardable, then avoid useless work. */ + if (! ann->forwardable) + return NULL; + + /* Set this block to not be forwardable. This prevents infinite loops since + any block currently under examination is considered non-forwardable. */ + ann->forwardable = 0; + + /* No forwarding is possible if this block is a special block (ENTRY/EXIT), + this block has more than one successor, this block's single successor is + reached via an abnormal edge, this block has phi nodes, or this block's + single successor has phi nodes. */ + if (bb == EXIT_BLOCK_PTR + || bb == ENTRY_BLOCK_PTR + || !bb->succ + || bb->succ->succ_next + || bb->succ->dest == EXIT_BLOCK_PTR + || (bb->succ->flags & EDGE_ABNORMAL) != 0 + || phi_nodes (bb) + || phi_nodes (bb->succ->dest)) + return NULL; + + /* Walk past any labels at the start of this block. */ + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + if (TREE_CODE (stmt) != LABEL_EXPR) + break; + } + + /* If we reached the end of this block we may be able to optimize this + case. */ + if (bsi_end_p (bsi)) + { + edge dest; + + /* Recursive call to pick up chains of forwarding blocks. */ + dest = tree_block_forwards_to (bb->succ->dest); + + /* If none found, we forward to bb->succ at minimum. */ + if (!dest) + dest = bb->succ; + + ann->forwardable = 1; + return dest; + } + + /* No forwarding possible. */ + return NULL; +} + + +/* Try to remove superfluous control structures. */ + +static bool +cleanup_control_flow (void) +{ + basic_block bb; + block_stmt_iterator bsi; + bool retval = false; + tree stmt; + + FOR_EACH_BB (bb) + { + bsi = bsi_last (bb); + + if (bsi_end_p (bsi)) + continue; + + stmt = bsi_stmt (bsi); + if (TREE_CODE (stmt) == COND_EXPR + || TREE_CODE (stmt) == SWITCH_EXPR) + retval |= cleanup_control_expr_graph (bb, bsi); + } + return retval; +} + + +/* Disconnect an unreachable block in the control expression starting + at block BB. */ + +static bool +cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi) +{ + edge taken_edge; + bool retval = false; + tree expr = bsi_stmt (bsi), val; + + if (bb->succ->succ_next) + { + edge e, next; + + switch (TREE_CODE (expr)) + { + case COND_EXPR: + val = COND_EXPR_COND (expr); + break; + + case SWITCH_EXPR: + val = SWITCH_COND (expr); + if (TREE_CODE (val) != INTEGER_CST) + return false; + break; + + default: + abort (); + } + + taken_edge = find_taken_edge (bb, val); + if (!taken_edge) + return false; + + /* Remove all the edges except the one that is always executed. */ + for (e = bb->succ; e; e = next) + { + next = e->succ_next; + if (e != taken_edge) + { + taken_edge->probability += e->probability; + taken_edge->count += e->count; + ssa_remove_edge (e); + retval = true; + } + } + if (taken_edge->probability > REG_BR_PROB_BASE) + taken_edge->probability = REG_BR_PROB_BASE; + } + else + taken_edge = bb->succ; + + bsi_remove (&bsi); + taken_edge->flags = EDGE_FALLTHRU; + + /* We removed some paths from the cfg. */ + if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK) + dom_computed[CDI_DOMINATORS] = DOM_CONS_OK; + + return retval; +} + + +/* Given a control block BB and a constant value VAL, return the edge that + will be taken out of the block. If VAL does not match a unique edge, + NULL is returned. */ + +edge +find_taken_edge (basic_block bb, tree val) +{ + tree stmt; + + stmt = last_stmt (bb); + +#if defined ENABLE_CHECKING + if (stmt == NULL_TREE || !is_ctrl_stmt (stmt)) + abort (); +#endif + + /* If VAL is not a constant, we can't determine which edge might + be taken. */ + if (val == NULL || !really_constant_p (val)) + return NULL; + + if (TREE_CODE (stmt) == COND_EXPR) + return find_taken_edge_cond_expr (bb, val); + + if (TREE_CODE (stmt) == SWITCH_EXPR) + return find_taken_edge_switch_expr (bb, val); + + return bb->succ; +} + + +/* Given a constant value VAL and the entry block BB to a COND_EXPR + statement, determine which of the two edges will be taken out of the + block. Return NULL if either edge may be taken. */ + +static edge +find_taken_edge_cond_expr (basic_block bb, tree val) +{ + edge true_edge, false_edge; + + extract_true_false_edges_from_block (bb, &true_edge, &false_edge); + + /* If both edges of the branch lead to the same basic block, it doesn't + matter which edge is taken. */ + if (true_edge->dest == false_edge->dest) + return true_edge; + + /* Otherwise, try to determine which branch of the if() will be taken. + If VAL is a constant but it can't be reduced to a 0 or a 1, then + we don't really know which edge will be taken at runtime. This + may happen when comparing addresses (e.g., if (&var1 == 4)). */ + if (integer_nonzerop (val)) + return true_edge; + else if (integer_zerop (val)) + return false_edge; + else + return NULL; +} + + +/* Given a constant value VAL and the entry block BB to a SWITCH_EXPR + statement, determine which edge will be taken out of the block. Return + NULL if any edge may be taken. */ + +static edge +find_taken_edge_switch_expr (basic_block bb, tree val) +{ + tree switch_expr, taken_case; + basic_block dest_bb; + edge e; + + if (TREE_CODE (val) != INTEGER_CST) + return NULL; + + switch_expr = last_stmt (bb); + taken_case = find_case_label_for_value (switch_expr, val); + dest_bb = label_to_block (CASE_LABEL (taken_case)); + + e = find_edge (bb, dest_bb); + if (!e) + abort (); + return e; +} + + +/* Return the CASE_LABEL_EXPR that SWITCH_EXPR will take for VAL. */ + +static tree +find_case_label_for_value (tree switch_expr, tree val) +{ + tree vec = SWITCH_LABELS (switch_expr); + size_t i, n = TREE_VEC_LENGTH (vec); + tree default_case = NULL; + + for (i = 0; i < n; ++i) + { + tree t = TREE_VEC_ELT (vec, i); + + if (CASE_LOW (t) == NULL) + default_case = t; + else if (CASE_HIGH (t) == NULL) + { + /* A `normal' case label. */ + if (simple_cst_equal (CASE_LOW (t), val) == 1) + return t; + } + else + { + /* A case range. We can only handle integer ranges. */ + if (tree_int_cst_compare (CASE_LOW (t), val) <= 0 + && tree_int_cst_compare (CASE_HIGH (t), val) >= 0) + return t; + } + } + + if (!default_case) + abort (); + + return default_case; +} + + +/* If all the PHI nodes in DEST have alternatives for E1 and E2 and + those alternatives are equal in each of the PHI nodes, then return + true, else return false. */ + +static bool +phi_alternatives_equal (basic_block dest, edge e1, edge e2) +{ + tree phi, val1, val2; + int n1, n2; + + for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi)) + { + n1 = phi_arg_from_edge (phi, e1); + n2 = phi_arg_from_edge (phi, e2); + +#ifdef ENABLE_CHECKING + if (n1 < 0 || n2 < 0) + abort (); +#endif + + val1 = PHI_ARG_DEF (phi, n1); + val2 = PHI_ARG_DEF (phi, n2); + + if (!operand_equal_p (val1, val2, 0)) + return false; + } + + return true; +} + + +/* Computing the Dominance Frontier: + + As described in Morgan, section 3.5, this may be done simply by + walking the dominator tree bottom-up, computing the frontier for + the children before the parent. When considering a block B, + there are two cases: + + (1) A flow graph edge leaving B that does not lead to a child + of B in the dominator tree must be a block that is either equal + to B or not dominated by B. Such blocks belong in the frontier + of B. + + (2) Consider a block X in the frontier of one of the children C + of B. If X is not equal to B and is not dominated by B, it + is in the frontier of B. */ + +static void +compute_dominance_frontiers_1 (bitmap *frontiers, basic_block bb, sbitmap done) +{ + edge e; + basic_block c; + + SET_BIT (done, bb->index); + + /* Do the frontier of the children first. Not all children in the + dominator tree (blocks dominated by this one) are children in the + CFG, so check all blocks. */ + for (c = first_dom_son (CDI_DOMINATORS, bb); + c; + c = next_dom_son (CDI_DOMINATORS, c)) + { + if (! TEST_BIT (done, c->index)) + compute_dominance_frontiers_1 (frontiers, c, done); + } + + /* Find blocks conforming to rule (1) above. */ + for (e = bb->succ; e; e = e->succ_next) + { + if (e->dest == EXIT_BLOCK_PTR) + continue; + if (get_immediate_dominator (CDI_DOMINATORS, e->dest) != bb) + bitmap_set_bit (frontiers[bb->index], e->dest->index); + } + + /* Find blocks conforming to rule (2). */ + for (c = first_dom_son (CDI_DOMINATORS, bb); + c; + c = next_dom_son (CDI_DOMINATORS, c)) + { + int x; + + EXECUTE_IF_SET_IN_BITMAP (frontiers[c->index], 0, x, + { + if (get_immediate_dominator (CDI_DOMINATORS, BASIC_BLOCK (x)) != bb) + bitmap_set_bit (frontiers[bb->index], x); + }); + } +} + + +void +compute_dominance_frontiers (bitmap *frontiers) +{ + sbitmap done = sbitmap_alloc (last_basic_block); + + timevar_push (TV_DOM_FRONTIERS); + + sbitmap_zero (done); + + compute_dominance_frontiers_1 (frontiers, ENTRY_BLOCK_PTR->succ->dest, done); + + sbitmap_free (done); + + timevar_pop (TV_DOM_FRONTIERS); +} + + + +/*--------------------------------------------------------------------------- + Debugging functions +---------------------------------------------------------------------------*/ + +/* Dump tree-specific information of block BB to file OUTF. */ + +void +tree_dump_bb (basic_block bb, FILE *outf, int indent) +{ + dump_generic_bb (outf, bb, indent, TDF_VOPS); +} + + +/* Dump a basic block on stderr. */ + +void +debug_tree_bb (basic_block bb) +{ + dump_bb (bb, stderr, 0); +} + + +/* Dump basic block with index N on stderr. */ + +basic_block +debug_tree_bb_n (int n) +{ + debug_tree_bb (BASIC_BLOCK (n)); + return BASIC_BLOCK (n); +} + + +/* Dump the CFG on stderr. + + FLAGS are the same used by the tree dumping functions + (see TDF_* in tree.h). */ + +void +debug_tree_cfg (int flags) +{ + dump_tree_cfg (stderr, flags); +} + + +/* Dump the program showing basic block boundaries on the given FILE. + + FLAGS are the same used by the tree dumping functions (see TDF_* in + tree.h). */ + +void +dump_tree_cfg (FILE *file, int flags) +{ + if (flags & TDF_DETAILS) + { + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + fputc ('\n', file); + fprintf (file, ";; Function %s\n\n", funcname); + fprintf (file, ";; \n%d basic blocks, %d edges, last basic block %d.\n\n", + n_basic_blocks, n_edges, last_basic_block); + + brief_dump_cfg (file); + fprintf (file, "\n"); + } + + if (flags & TDF_STATS) + dump_cfg_stats (file); + + dump_function_to_file (current_function_decl, file, flags | TDF_BLOCKS); +} + + +/* Dump CFG statistics on FILE. */ + +void +dump_cfg_stats (FILE *file) +{ + static long max_num_merged_labels = 0; + unsigned long size, total = 0; + long n_edges; + basic_block bb; + const char * const fmt_str = "%-30s%-13s%12s\n"; + const char * const fmt_str_1 = "%-30s%13lu%11lu%c\n"; + const char * const fmt_str_3 = "%-43s%11lu%c\n"; + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + + fprintf (file, "\nCFG Statistics for %s\n\n", funcname); + + fprintf (file, "---------------------------------------------------------\n"); + fprintf (file, fmt_str, "", " Number of ", "Memory"); + fprintf (file, fmt_str, "", " instances ", "used "); + fprintf (file, "---------------------------------------------------------\n"); + + size = n_basic_blocks * sizeof (struct basic_block_def); + total += size; + fprintf (file, fmt_str_1, "Basic blocks", n_basic_blocks, SCALE (size), + LABEL (size)); + + n_edges = 0; + FOR_EACH_BB (bb) + { + edge e; + for (e = bb->succ; e; e = e->succ_next) + n_edges++; + } + size = n_edges * sizeof (struct edge_def); + total += size; + fprintf (file, fmt_str_1, "Edges", n_edges, SCALE (size), LABEL (size)); + + size = n_basic_blocks * sizeof (struct bb_ann_d); + total += size; + fprintf (file, fmt_str_1, "Basic block annotations", n_basic_blocks, + SCALE (size), LABEL (size)); + + fprintf (file, "---------------------------------------------------------\n"); + fprintf (file, fmt_str_3, "Total memory used by CFG data", SCALE (total), + LABEL (total)); + fprintf (file, "---------------------------------------------------------\n"); + fprintf (file, "\n"); + + if (cfg_stats.num_merged_labels > max_num_merged_labels) + max_num_merged_labels = cfg_stats.num_merged_labels; + + fprintf (file, "Coalesced label blocks: %ld (Max so far: %ld)\n", + cfg_stats.num_merged_labels, max_num_merged_labels); + + fprintf (file, "\n"); +} + + +/* Dump CFG statistics on stderr. Keep extern so that it's always + linked in the final executable. */ + +void +debug_cfg_stats (void) +{ + dump_cfg_stats (stderr); +} + + +/* Dump the flowgraph to a .vcg FILE. */ + +static void +tree_cfg2vcg (FILE *file) +{ + edge e; + basic_block bb; + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + /* Write the file header. */ + fprintf (file, "graph: { title: \"%s\"\n", funcname); + fprintf (file, "node: { title: \"ENTRY\" label: \"ENTRY\" }\n"); + fprintf (file, "node: { title: \"EXIT\" label: \"EXIT\" }\n"); + + /* Write blocks and edges. */ + for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next) + { + fprintf (file, "edge: { sourcename: \"ENTRY\" targetname: \"%d\"", + e->dest->index); + + if (e->flags & EDGE_FAKE) + fprintf (file, " linestyle: dotted priority: 10"); + else + fprintf (file, " linestyle: solid priority: 100"); + + fprintf (file, " }\n"); + } + fputc ('\n', file); + + FOR_EACH_BB (bb) + { + enum tree_code head_code, end_code; + const char *head_name, *end_name; + int head_line = 0; + int end_line = 0; + tree first = first_stmt (bb); + tree last = last_stmt (bb); + + if (first) + { + head_code = TREE_CODE (first); + head_name = tree_code_name[head_code]; + head_line = get_lineno (first); + } + else + head_name = "no-statement"; + + if (last) + { + end_code = TREE_CODE (last); + end_name = tree_code_name[end_code]; + end_line = get_lineno (last); + } + else + end_name = "no-statement"; + + fprintf (file, "node: { title: \"%d\" label: \"#%d\\n%s (%d)\\n%s (%d)\"}\n", + bb->index, bb->index, head_name, head_line, end_name, + end_line); + + for (e = bb->succ; e; e = e->succ_next) + { + if (e->dest == EXIT_BLOCK_PTR) + fprintf (file, "edge: { sourcename: \"%d\" targetname: \"EXIT\"", bb->index); + else + fprintf (file, "edge: { sourcename: \"%d\" targetname: \"%d\"", bb->index, e->dest->index); + + if (e->flags & EDGE_FAKE) + fprintf (file, " priority: 10 linestyle: dotted"); + else + fprintf (file, " priority: 100 linestyle: solid"); + + fprintf (file, " }\n"); + } + + if (bb->next_bb != EXIT_BLOCK_PTR) + fputc ('\n', file); + } + + fputs ("}\n\n", file); +} + + + +/*--------------------------------------------------------------------------- + Miscellaneous helpers +---------------------------------------------------------------------------*/ + +/* Return true if T represents a stmt that always transfers control. */ + +bool +is_ctrl_stmt (tree t) +{ + return (TREE_CODE (t) == COND_EXPR + || TREE_CODE (t) == SWITCH_EXPR + || TREE_CODE (t) == GOTO_EXPR + || TREE_CODE (t) == RETURN_EXPR + || TREE_CODE (t) == RESX_EXPR); +} + + +/* Return true if T is a statement that may alter the flow of control + (e.g., a call to a non-returning function). */ + +bool +is_ctrl_altering_stmt (tree t) +{ + tree call = t; + +#if defined ENABLE_CHECKING + if (t == NULL) + abort (); +#endif + + switch (TREE_CODE (t)) + { + case MODIFY_EXPR: + /* A MODIFY_EXPR with a rhs of a call has the characteristics + of the call. */ + call = TREE_OPERAND (t, 1); + if (TREE_CODE (call) != CALL_EXPR) + break; + /* FALLTHRU */ + + case CALL_EXPR: + /* A non-pure/const CALL_EXPR alters flow control if the current + function has nonlocal labels. */ + if (TREE_SIDE_EFFECTS (t) + && current_function_has_nonlocal_label) + return true; + + /* A CALL_EXPR also alters control flow if it does not return. */ + if (call_expr_flags (call) & (ECF_NORETURN | ECF_LONGJMP)) + return true; + break; + + default: + return false; + } + + /* If a statement can throw, it alters control flow. */ + return tree_can_throw_internal (t); +} + + +/* Return true if T is a computed goto. */ + +bool +computed_goto_p (tree t) +{ + return (TREE_CODE (t) == GOTO_EXPR + && TREE_CODE (GOTO_DESTINATION (t)) != LABEL_DECL); +} + + +/* Checks whether EXPR is a simple local goto. */ + +bool +simple_goto_p (tree expr) +{ + return (TREE_CODE (expr) == GOTO_EXPR + && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL + && (decl_function_context (GOTO_DESTINATION (expr)) + == current_function_decl)); +} + + +/* Return true if T should start a new basic block. PREV_T is the + statement preceding T. It is used when T is a label or a case label. + Labels should only start a new basic block if their previous statement + wasn't a label. Otherwise, sequence of labels would generate + unnecessary basic blocks that only contain a single label. */ + +static inline bool +stmt_starts_bb_p (tree t, tree prev_t) +{ + enum tree_code code; + + if (t == NULL_TREE) + return false; + + /* LABEL_EXPRs start a new basic block only if the preceding + statement wasn't a label of the same type. This prevents the + creation of consecutive blocks that have nothing but a single + label. */ + code = TREE_CODE (t); + if (code == LABEL_EXPR) + { + /* Nonlocal and computed GOTO targets always start a new block. */ + if (code == LABEL_EXPR + && (DECL_NONLOCAL (LABEL_EXPR_LABEL (t)) + || FORCED_LABEL (LABEL_EXPR_LABEL (t)))) + return true; + + if (prev_t && TREE_CODE (prev_t) == code) + { + if (DECL_NONLOCAL (LABEL_EXPR_LABEL (prev_t))) + return true; + + cfg_stats.num_merged_labels++; + return false; + } + else + return true; + } + + return false; +} + + +/* Return true if T should end a basic block. */ + +bool +stmt_ends_bb_p (tree t) +{ + return is_ctrl_stmt (t) || is_ctrl_altering_stmt (t); +} + + +/* Add gotos that used to be represented implicitly in the CFG. */ + +void +disband_implicit_edges (void) +{ + basic_block bb; + block_stmt_iterator last; + edge e; + tree stmt, label, forward; + + FOR_EACH_BB (bb) + { + last = bsi_last (bb); + stmt = last_stmt (bb); + + if (stmt && TREE_CODE (stmt) == COND_EXPR) + { + /* Remove superfluous gotos from COND_EXPR branches. Moved + from cfg_remove_useless_stmts here since it violates the + invariants for tree--cfg correspondence and thus fits better + here where we do it anyway. */ + for (e = bb->succ; e; e = e->succ_next) + { + if (e->dest != bb->next_bb) + continue; + + if (e->flags & EDGE_TRUE_VALUE) + COND_EXPR_THEN (stmt) = build_empty_stmt (); + else if (e->flags & EDGE_FALSE_VALUE) + COND_EXPR_ELSE (stmt) = build_empty_stmt (); + else + abort (); + e->flags |= EDGE_FALLTHRU; + } + + continue; + } + + if (stmt && TREE_CODE (stmt) == RETURN_EXPR) + { + /* Remove the RETURN_EXPR if we may fall though to the exit + instead. */ + if (!bb->succ + || bb->succ->succ_next + || bb->succ->dest != EXIT_BLOCK_PTR) + abort (); + + if (bb->next_bb == EXIT_BLOCK_PTR + && !TREE_OPERAND (stmt, 0)) + { + bsi_remove (&last); + bb->succ->flags |= EDGE_FALLTHRU; + } + continue; + } + + /* There can be no fallthru edge if the last statement is a control + one. */ + if (stmt && is_ctrl_stmt (stmt)) + continue; + + /* Find a fallthru edge and emit the goto if necessary. */ + for (e = bb->succ; e; e = e->succ_next) + if (e->flags & EDGE_FALLTHRU) + break; + + if (!e + || e->dest == bb->next_bb) + continue; + + if (e->dest == EXIT_BLOCK_PTR) + abort (); + + label = tree_block_label (e->dest); + + /* If this is a goto to a goto, jump to the final destination. + Handles unfactoring of the computed jumps. + ??? Why bother putting this back together when rtl is just + about to take it apart again? */ + forward = last_and_only_stmt (e->dest); + if (forward + && TREE_CODE (forward) == GOTO_EXPR) + label = GOTO_DESTINATION (forward); + + bsi_insert_after (&last, + build1 (GOTO_EXPR, void_type_node, label), + BSI_NEW_STMT); + e->flags &= ~EDGE_FALLTHRU; + } +} + + +/* Remove all the blocks and edges that make up the flowgraph. */ + +void +delete_tree_cfg (void) +{ + if (n_basic_blocks > 0) + free_blocks_annotations (); + + free_basic_block_vars (); + basic_block_info = NULL; + label_to_block_map = NULL; + free_rbi_pool (); +} + + +/* Return the first statement in basic block BB. */ + +tree +first_stmt (basic_block bb) +{ + block_stmt_iterator i = bsi_start (bb); + return !bsi_end_p (i) ? bsi_stmt (i) : NULL_TREE; +} + + +/* Return the last statement in basic block BB. */ + +tree +last_stmt (basic_block bb) +{ + block_stmt_iterator b = bsi_last (bb); + return !bsi_end_p (b) ? bsi_stmt (b) : NULL_TREE; +} + + +/* Return a pointer to the last statement in block BB. */ + +tree * +last_stmt_ptr (basic_block bb) +{ + block_stmt_iterator last = bsi_last (bb); + return !bsi_end_p (last) ? bsi_stmt_ptr (last) : NULL; +} + + +/* Return the last statement of an otherwise empty block. Return NULL + if the block is totally empty, or if it contains more than one + statement. */ + +tree +last_and_only_stmt (basic_block bb) +{ + block_stmt_iterator i = bsi_last (bb); + tree last, prev; + + if (bsi_end_p (i)) + return NULL_TREE; + + last = bsi_stmt (i); + bsi_prev (&i); + if (bsi_end_p (i)) + return last; + + /* Empty statements should no longer appear in the instruction stream. + Everything that might have appeared before should be deleted by + remove_useless_stmts, and the optimizers should just bsi_remove + instead of smashing with build_empty_stmt. + + Thus the only thing that should appear here in a block containing + one executable statement is a label. */ + prev = bsi_stmt (i); + if (TREE_CODE (prev) == LABEL_EXPR) + return last; + else + return NULL_TREE; +} + + +/* Mark BB as the basic block holding statement T. */ + +void +set_bb_for_stmt (tree t, basic_block bb) +{ + if (TREE_CODE (t) == STATEMENT_LIST) + { + tree_stmt_iterator i; + for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) + set_bb_for_stmt (tsi_stmt (i), bb); + } + else + { + stmt_ann_t ann = get_stmt_ann (t); + ann->bb = bb; + + /* If the statement is a label, add the label to block-to-labels map + so that we can speed up edge creation for GOTO_EXPRs. */ + if (TREE_CODE (t) == LABEL_EXPR) + { + int uid; + + t = LABEL_EXPR_LABEL (t); + uid = LABEL_DECL_UID (t); + if (uid == -1) + { + LABEL_DECL_UID (t) = uid = cfun->last_label_uid++; + if (VARRAY_SIZE (label_to_block_map) <= (unsigned) uid) + VARRAY_GROW (label_to_block_map, 3 * uid / 2); + } + else + { +#ifdef ENABLE_CHECKING + /* We're moving an existing label. Make sure that we've + removed it from the old block. */ + if (bb && VARRAY_BB (label_to_block_map, uid)) + abort (); +#endif + } + VARRAY_BB (label_to_block_map, uid) = bb; + } + } +} + + +/* Insert statement (or statement list) T before the statement + pointed-to by iterator I. M specifies how to update iterator I + after insertion (see enum bsi_iterator_update). */ + +void +bsi_insert_before (block_stmt_iterator *i, tree t, enum bsi_iterator_update m) +{ + set_bb_for_stmt (t, i->bb); + modify_stmt (t); + tsi_link_before (&i->tsi, t, m); +} + + +/* Insert statement (or statement list) T after the statement + pointed-to by iterator I. M specifies how to update iterator I + after insertion (see enum bsi_iterator_update). */ + +void +bsi_insert_after (block_stmt_iterator *i, tree t, enum bsi_iterator_update m) +{ + set_bb_for_stmt (t, i->bb); + modify_stmt (t); + tsi_link_after (&i->tsi, t, m); +} + + +/* Remove the statement pointed to by iterator I. The iterator is updated + to the next statement. */ + +void +bsi_remove (block_stmt_iterator *i) +{ + tree t = bsi_stmt (*i); + set_bb_for_stmt (t, NULL); + modify_stmt (t); + tsi_delink (&i->tsi); +} + + +/* Move the statement at FROM so it comes right after the statement at TO. */ + +void +bsi_move_after (block_stmt_iterator *from, block_stmt_iterator *to) +{ + tree stmt = bsi_stmt (*from); + bsi_remove (from); + bsi_insert_after (to, stmt, BSI_SAME_STMT); +} + + +/* Move the statement at FROM so it comes right before the statement at TO. */ + +void +bsi_move_before (block_stmt_iterator *from, block_stmt_iterator *to) +{ + tree stmt = bsi_stmt (*from); + bsi_remove (from); + bsi_insert_before (to, stmt, BSI_SAME_STMT); +} + + +/* Move the statement at FROM to the end of basic block BB. */ + +void +bsi_move_to_bb_end (block_stmt_iterator *from, basic_block bb) +{ + block_stmt_iterator last = bsi_last (bb); + + /* Have to check bsi_end_p because it could be an empty block. */ + if (!bsi_end_p (last) && is_ctrl_stmt (bsi_stmt (last))) + bsi_move_before (from, &last); + else + bsi_move_after (from, &last); +} + + +/* Replace the contents of the statement pointed to by iterator BSI + with STMT. If PRESERVE_EH_INFO is true, the exception handling + information of the original statement is preserved. */ + +void +bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool preserve_eh_info) +{ + int eh_region; + tree orig_stmt = bsi_stmt (*bsi); + + SET_EXPR_LOCUS (stmt, EXPR_LOCUS (orig_stmt)); + set_bb_for_stmt (stmt, bsi->bb); + + /* Preserve EH region information from the original statement, if + requested by the caller. */ + if (preserve_eh_info) + { + eh_region = lookup_stmt_eh_region (orig_stmt); + if (eh_region >= 0) + add_stmt_to_eh_region (stmt, eh_region); + } + + *bsi_stmt_ptr (*bsi) = stmt; + modify_stmt (stmt); +} + + +/* Insert the statement pointed-to by BSI into edge E. Every attempt + is made to place the statement in an existing basic block, but + sometimes that isn't possible. When it isn't possible, the edge is + split and the statement is added to the new block. + + In all cases, the returned *BSI points to the correct location. The + return value is true if insertion should be done after the location, + or false if it should be done before the location. */ + +static bool +tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi) +{ + basic_block dest, src; + tree tmp; + + dest = e->dest; + restart: + + /* If the destination has one predecessor which has no PHI nodes, + insert there. Except for the exit block. + + The requirement for no PHI nodes could be relaxed. Basically we + would have to examine the PHIs to prove that none of them used + the value set by the statement we want to insert on E. That + hardly seems worth the effort. */ + if (dest->pred->pred_next == NULL + && ! phi_nodes (dest) + && dest != EXIT_BLOCK_PTR) + { + *bsi = bsi_start (dest); + if (bsi_end_p (*bsi)) + return true; + + /* Make sure we insert after any leading labels. */ + tmp = bsi_stmt (*bsi); + while (TREE_CODE (tmp) == LABEL_EXPR) + { + bsi_next (bsi); + if (bsi_end_p (*bsi)) + break; + tmp = bsi_stmt (*bsi); + } + + if (bsi_end_p (*bsi)) + { + *bsi = bsi_last (dest); + return true; + } + else + return false; + } + + /* If the source has one successor, the edge is not abnormal and + the last statement does not end a basic block, insert there. + Except for the entry block. */ + src = e->src; + if ((e->flags & EDGE_ABNORMAL) == 0 + && src->succ->succ_next == NULL + && src != ENTRY_BLOCK_PTR) + { + *bsi = bsi_last (src); + if (bsi_end_p (*bsi)) + return true; + + tmp = bsi_stmt (*bsi); + if (!stmt_ends_bb_p (tmp)) + return true; + } + + /* Otherwise, create a new basic block, and split this edge. */ + dest = split_edge (e); + e = dest->pred; + goto restart; +} + + +/* This routine will commit all pending edge insertions, creating any new + basic blocks which are necessary. + + If specified, NEW_BLOCKS returns a count of the number of new basic + blocks which were created. */ + +void +bsi_commit_edge_inserts (int *new_blocks) +{ + basic_block bb; + edge e; + int blocks; + + blocks = n_basic_blocks; + + bsi_commit_edge_inserts_1 (ENTRY_BLOCK_PTR->succ); + + FOR_EACH_BB (bb) + for (e = bb->succ; e; e = e->succ_next) + bsi_commit_edge_inserts_1 (e); + + if (new_blocks) + *new_blocks = n_basic_blocks - blocks; +} + + +/* Commit insertions pending at edge E. */ + +static void +bsi_commit_edge_inserts_1 (edge e) +{ + if (PENDING_STMT (e)) + { + block_stmt_iterator bsi; + tree stmt = PENDING_STMT (e); + + PENDING_STMT (e) = NULL_TREE; + + if (tree_find_edge_insert_loc (e, &bsi)) + bsi_insert_after (&bsi, stmt, BSI_NEW_STMT); + else + bsi_insert_before (&bsi, stmt, BSI_NEW_STMT); + } +} + + +/* Add STMT to the pending list of edge E. No actual insertion is + made until a call to bsi_commit_edge_inserts () is made. */ + +void +bsi_insert_on_edge (edge e, tree stmt) +{ + append_to_statement_list (stmt, &PENDING_STMT (e)); +} + + +/* Specialized edge insertion for SSA-PRE. FIXME: This should + probably disappear. The only reason it's here is because PRE needs + the call to tree_find_edge_insert_loc(). */ + +void pre_insert_on_edge (edge e, tree stmt); + +void +pre_insert_on_edge (edge e, tree stmt) +{ + block_stmt_iterator bsi; + + if (PENDING_STMT (e)) + abort (); + + if (tree_find_edge_insert_loc (e, &bsi)) + bsi_insert_after (&bsi, stmt, BSI_NEW_STMT); + else + bsi_insert_before (&bsi, stmt, BSI_NEW_STMT); +} + + +/*--------------------------------------------------------------------------- + Tree specific functions for CFG manipulation +---------------------------------------------------------------------------*/ + +/* Split a (typically critical) edge EDGE_IN. Return the new block. + Abort on abnormal edges. */ + +static basic_block +tree_split_edge (edge edge_in) +{ + basic_block new_bb, after_bb, dest, src; + edge new_edge, e; + tree phi; + int i, num_elem; + + /* Abnormal edges cannot be split. */ + if (edge_in->flags & EDGE_ABNORMAL) + abort (); + + src = edge_in->src; + dest = edge_in->dest; + + /* Place the new block in the block list. Try to keep the new block + near its "logical" location. This is of most help to humans looking + at debugging dumps. */ + for (e = dest->pred; e; e = e->pred_next) + if (e->src->next_bb == dest) + break; + if (!e) + after_bb = dest->prev_bb; + else + after_bb = edge_in->src; + + new_bb = create_empty_bb (after_bb); + new_edge = make_edge (new_bb, dest, EDGE_FALLTHRU); + + /* Find all the PHI arguments on the original edge, and change them to + the new edge. Do it before redirection, so that the argument does not + get removed. */ + for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi)) + { + num_elem = PHI_NUM_ARGS (phi); + for (i = 0; i < num_elem; i++) + if (PHI_ARG_EDGE (phi, i) == edge_in) + { + PHI_ARG_EDGE (phi, i) = new_edge; + break; + } + } + + if (!redirect_edge_and_branch (edge_in, new_bb)) + abort (); + + if (PENDING_STMT (edge_in)) + abort (); + + return new_bb; +} + + +/* Return true when BB has label LABEL in it. */ + +static bool +has_label_p (basic_block bb, tree label) +{ + block_stmt_iterator bsi; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + + if (TREE_CODE (stmt) != LABEL_EXPR) + return false; + if (LABEL_EXPR_LABEL (stmt) == label) + return true; + } + return false; +} + + +/* Callback for walk_tree, check that all elements with address taken are + properly noticed as such. */ + +static tree +verify_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + tree t = *tp, x; + + if (TYPE_P (t)) + *walk_subtrees = 0; + + switch (TREE_CODE (t)) + { + case SSA_NAME: + if (SSA_NAME_IN_FREE_LIST (t)) + { + error ("SSA name in freelist but still referenced"); + return *tp; + } + break; + + case MODIFY_EXPR: + x = TREE_OPERAND (t, 0); + if (TREE_CODE (x) == BIT_FIELD_REF + && is_gimple_reg (TREE_OPERAND (x, 0))) + { + error ("GIMPLE register modified with BIT_FIELD_REF"); + return *tp; + } + break; + + case ADDR_EXPR: + x = TREE_OPERAND (t, 0); + while (TREE_CODE (x) == ARRAY_REF + || TREE_CODE (x) == COMPONENT_REF + || TREE_CODE (x) == REALPART_EXPR + || TREE_CODE (x) == IMAGPART_EXPR) + x = TREE_OPERAND (x, 0); + if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL) + return NULL; + if (!TREE_ADDRESSABLE (x)) + { + error ("address taken, but ADDRESSABLE bit not set"); + return x; + } + break; + + case COND_EXPR: + x = TREE_OPERAND (t, 0); + if (TREE_CODE (TREE_TYPE (x)) != BOOLEAN_TYPE) + { + error ("non-boolean used in condition"); + return x; + } + break; + + case NOP_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FLOAT_EXPR: + case NEGATE_EXPR: + case ABS_EXPR: + case BIT_NOT_EXPR: + case NON_LVALUE_EXPR: + case TRUTH_NOT_EXPR: + x = TREE_OPERAND (t, 0); + /* We check for constants explicitly since they are not considered + gimple invariants if they overflowed. */ + if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c' + && !is_gimple_val (x)) + { + error ("Invalid operand to unary operator"); + return x; + } + break; + + case REALPART_EXPR: + case IMAGPART_EXPR: + break; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case UNORDERED_EXPR: + case ORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case MIN_EXPR: + case MAX_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + x = TREE_OPERAND (t, 0); + /* We check for constants explicitly since they are not considered + gimple invariants if they overflowed. */ + if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c' + && !is_gimple_val (x)) + { + error ("Invalid operand to binary operator"); + return x; + } + x = TREE_OPERAND (t, 1); + /* We check for constants explicitly since they are not considered + gimple invariants if they overflowed. */ + if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c' + && !is_gimple_val (x)) + { + error ("Invalid operand to binary operator"); + return x; + } + break; + + default: + break; + } + return NULL; +} + + +/* Verify STMT, return true if STMT is not in GIMPLE form. + TODO: Implement type checking. */ + +static bool +verify_stmt (tree stmt) +{ + tree addr; + + if (!is_gimple_stmt (stmt)) + { + error ("Is not a valid GIMPLE statement."); + debug_generic_stmt (stmt); + return true; + } + + addr = walk_tree (&stmt, verify_expr, NULL, NULL); + if (addr) + { + debug_generic_stmt (addr); + return true; + } + + return false; +} + + +/* Return true when the T can be shared. */ + +static bool +tree_node_can_be_shared (tree t) +{ + if (TYPE_P (t) || DECL_P (t) + /* We check for constants explicitly since they are not considered + gimple invariants if they overflowed. */ + || TREE_CODE_CLASS (TREE_CODE (t)) == 'c' + || is_gimple_min_invariant (t) + || TREE_CODE (t) == SSA_NAME) + return true; + + while ((TREE_CODE (t) == ARRAY_REF + /* We check for constants explicitly since they are not considered + gimple invariants if they overflowed. */ + && (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 1))) == 'c' + || is_gimple_min_invariant (TREE_OPERAND (t, 1)))) + || (TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == REALPART_EXPR + || TREE_CODE (t) == IMAGPART_EXPR)) + t = TREE_OPERAND (t, 0); + + if (DECL_P (t)) + return true; + + return false; +} + + +/* Called via walk_trees. Verify tree sharing. */ + +static tree +verify_node_sharing (tree * tp, int *walk_subtrees, void *data) +{ + htab_t htab = (htab_t) data; + void **slot; + + if (tree_node_can_be_shared (*tp)) + { + *walk_subtrees = false; + return NULL; + } + + slot = htab_find_slot (htab, *tp, INSERT); + if (*slot) + return *slot; + *slot = *tp; + + return NULL; +} + + +/* Verify the GIMPLE statement chain. */ + +void +verify_stmts (void) +{ + basic_block bb; + block_stmt_iterator bsi; + bool err = false; + htab_t htab; + tree addr; + + timevar_push (TV_TREE_STMT_VERIFY); + htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); + + FOR_EACH_BB (bb) + { + tree phi; + int i; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + int phi_num_args = PHI_NUM_ARGS (phi); + + for (i = 0; i < phi_num_args; i++) + { + tree t = PHI_ARG_DEF (phi, i); + tree addr; + + /* Addressable variables do have SSA_NAMEs but they + are not considered gimple values. */ + if (TREE_CODE (t) != SSA_NAME + && TREE_CODE (t) != FUNCTION_DECL + && !is_gimple_val (t)) + { + error ("PHI def is not a GIMPLE value"); + debug_generic_stmt (phi); + debug_generic_stmt (t); + err |= true; + } + + addr = walk_tree (&t, verify_expr, NULL, NULL); + if (addr) + { + debug_generic_stmt (addr); + err |= true; + } + + addr = walk_tree (&t, verify_node_sharing, htab, NULL); + if (addr) + { + error ("Incorrect sharing of tree nodes"); + debug_generic_stmt (phi); + debug_generic_stmt (addr); + err |= true; + } + } + } + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + err |= verify_stmt (stmt); + addr = walk_tree (&stmt, verify_node_sharing, htab, NULL); + if (addr) + { + error ("Incorrect sharing of tree nodes"); + debug_generic_stmt (stmt); + debug_generic_stmt (addr); + err |= true; + } + } + } + + if (err) + internal_error ("verify_stmts failed."); + + htab_delete (htab); + timevar_pop (TV_TREE_STMT_VERIFY); +} + + +/* Verifies that the flow information is OK. */ + +static int +tree_verify_flow_info (void) +{ + int err = 0; + basic_block bb; + block_stmt_iterator bsi; + tree stmt; + edge e; + + if (ENTRY_BLOCK_PTR->stmt_list) + { + error ("ENTRY_BLOCK has a statement list associated with it\n"); + err = 1; + } + + if (EXIT_BLOCK_PTR->stmt_list) + { + error ("EXIT_BLOCK has a statement list associated with it\n"); + err = 1; + } + + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + if (e->flags & EDGE_FALLTHRU) + { + error ("Fallthru to exit from bb %d\n", e->src->index); + err = 1; + } + + FOR_EACH_BB (bb) + { + bool found_ctrl_stmt = false; + + /* Skip labels on the start of basic block. */ + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + if (TREE_CODE (bsi_stmt (bsi)) != LABEL_EXPR) + break; + + if (label_to_block (LABEL_EXPR_LABEL (bsi_stmt (bsi))) != bb) + { + error ("Label %s to block does not match in bb %d\n", + IDENTIFIER_POINTER (DECL_NAME (bsi_stmt (bsi))), + bb->index); + err = 1; + } + + if (decl_function_context (LABEL_EXPR_LABEL (bsi_stmt (bsi))) + != current_function_decl) + { + error ("Label %s has incorrect context in bb %d\n", + IDENTIFIER_POINTER (DECL_NAME (bsi_stmt (bsi))), + bb->index); + err = 1; + } + } + + /* Verify that body of basic block BB is free of control flow. */ + for (; !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + + if (found_ctrl_stmt) + { + error ("Control flow in the middle of basic block %d\n", + bb->index); + err = 1; + } + + if (stmt_ends_bb_p (stmt)) + found_ctrl_stmt = true; + + if (TREE_CODE (stmt) == LABEL_EXPR) + { + error ("Label %s in the middle of basic block %d\n", + IDENTIFIER_POINTER (DECL_NAME (stmt)), + bb->index); + err = 1; + } + } + bsi = bsi_last (bb); + if (bsi_end_p (bsi)) + continue; + + stmt = bsi_stmt (bsi); + + if (is_ctrl_stmt (stmt)) + { + for (e = bb->succ; e; e = e->succ_next) + if (e->flags & EDGE_FALLTHRU) + { + error ("Fallthru edge after a control statement in bb %d \n", + bb->index); + err = 1; + } + } + + switch (TREE_CODE (stmt)) + { + case COND_EXPR: + { + edge true_edge; + edge false_edge; + if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR + || TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR) + { + error ("Structured COND_EXPR at the end of bb %d\n", bb->index); + err = 1; + } + + extract_true_false_edges_from_block (bb, &true_edge, &false_edge); + + if (!true_edge || !false_edge + || !(true_edge->flags & EDGE_TRUE_VALUE) + || !(false_edge->flags & EDGE_FALSE_VALUE) + || (true_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL)) + || (false_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL)) + || bb->succ->succ_next->succ_next) + { + error ("Wrong outgoing edge flags at end of bb %d\n", + bb->index); + err = 1; + } + + if (!has_label_p (true_edge->dest, + GOTO_DESTINATION (COND_EXPR_THEN (stmt)))) + { + error ("`then' label does not match edge at end of bb %d\n", + bb->index); + err = 1; + } + + if (!has_label_p (false_edge->dest, + GOTO_DESTINATION (COND_EXPR_ELSE (stmt)))) + { + error ("`else' label does not match edge at end of bb %d\n", + bb->index); + err = 1; + } + } + break; + + case GOTO_EXPR: + if (simple_goto_p (stmt)) + { + error ("Explicit goto at end of bb %d\n", bb->index); + err = 1; + } + else + { + /* FIXME. We should double check that the labels in the + destination blocks have their address taken. */ + for (e = bb->succ; e; e = e->succ_next) + if ((e->flags & (EDGE_FALLTHRU | EDGE_TRUE_VALUE + | EDGE_FALSE_VALUE)) + || !(e->flags & EDGE_ABNORMAL)) + { + error ("Wrong outgoing edge flags at end of bb %d\n", + bb->index); + err = 1; + } + } + break; + + case RETURN_EXPR: + if (!bb->succ || bb->succ->succ_next + || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL + | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))) + { + error ("Wrong outgoing edge flags at end of bb %d\n", bb->index); + err = 1; + } + if (bb->succ->dest != EXIT_BLOCK_PTR) + { + error ("Return edge does not point to exit in bb %d\n", + bb->index); + err = 1; + } + break; + + case SWITCH_EXPR: + { + edge e; + size_t i, n; + tree vec; + + vec = SWITCH_LABELS (stmt); + n = TREE_VEC_LENGTH (vec); + + /* Mark all the destination basic blocks. */ + for (i = 0; i < n; ++i) + { + tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i)); + basic_block label_bb = label_to_block (lab); + + if (label_bb->aux && label_bb->aux != (void *)1) + abort (); + label_bb->aux = (void *)1; + } + + for (e = bb->succ; e; e = e->succ_next) + { + if (!e->dest->aux) + { + error ("Extra outgoing edge %d->%d\n", + bb->index, e->dest->index); + err = 1; + } + e->dest->aux = (void *)2; + if ((e->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL + | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))) + { + error ("Wrong outgoing edge flags at end of bb %d\n", + bb->index); + err = 1; + } + } + + /* Check that we have all of them. */ + for (i = 0; i < n; ++i) + { + tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i)); + basic_block label_bb = label_to_block (lab); + + if (label_bb->aux != (void *)2) + { + error ("Missing edge %i->%i\n", + bb->index, label_bb->index); + err = 1; + } + } + + for (e = bb->succ; e; e = e->succ_next) + e->dest->aux = (void *)0; + } + + default: ; + } + } + + if (dom_computed[CDI_DOMINATORS] >= DOM_NO_FAST_QUERY) + verify_dominators (CDI_DOMINATORS); + + return err; +} + + +/* Updates phi nodes after creating forwarder block joined + by edge FALLTHRU. */ + +static void +tree_make_forwarder_block (edge fallthru) +{ + edge e; + basic_block dummy, bb; + tree phi, new_phi, var; + + dummy = fallthru->src; + bb = fallthru->dest; + + if (!bb->pred->pred_next) + return; + + /* If we redirected a branch we must create new phi nodes at the + start of BB. */ + for (phi = phi_nodes (dummy); phi; phi = TREE_CHAIN (phi)) + { + var = PHI_RESULT (phi); + new_phi = create_phi_node (var, bb); + SSA_NAME_DEF_STMT (var) = new_phi; + PHI_RESULT (phi) = make_ssa_name (SSA_NAME_VAR (var), phi); + add_phi_arg (&new_phi, PHI_RESULT (phi), fallthru); + } + + /* Ensure that the PHI node chains are in the same order. */ + set_phi_nodes (bb, nreverse (phi_nodes (bb))); + + /* Add the arguments we have stored on edges. */ + for (e = bb->pred; e; e = e->pred_next) + { + if (e == fallthru) + continue; + + for (phi = phi_nodes (bb), var = PENDING_STMT (e); + phi; + phi = TREE_CHAIN (phi), var = TREE_CHAIN (var)) + add_phi_arg (&phi, TREE_VALUE (var), e); + + PENDING_STMT (e) = NULL; + } +} + + +/* Return true if basic block BB does nothing except pass control + flow to another block and that we can safely insert a label at + the start of the successor block. */ + +static bool +tree_forwarder_block_p (basic_block bb) +{ + block_stmt_iterator bsi; + edge e; + + /* If we have already determined that this block is not forwardable, + then no further checks are necessary. */ + if (! bb_ann (bb)->forwardable) + return false; + + /* BB must have a single outgoing normal edge. Otherwise it can not be + a forwarder block. */ + if (!bb->succ + || bb->succ->succ_next + || bb->succ->dest == EXIT_BLOCK_PTR + || (bb->succ->flags & EDGE_ABNORMAL) + || bb == ENTRY_BLOCK_PTR) + { + bb_ann (bb)->forwardable = 0; + return false; + } + + /* Successors of the entry block are not forwarders. */ + for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next) + if (e->dest == bb) + { + bb_ann (bb)->forwardable = 0; + return false; + } + + /* BB can not have any PHI nodes. This could potentially be relaxed + early in compilation if we re-rewrote the variables appearing in + any PHI nodes in forwarder blocks. */ + if (phi_nodes (bb)) + { + bb_ann (bb)->forwardable = 0; + return false; + } + + /* Now walk through the statements. We can ignore labels, anything else + means this is not a forwarder block. */ + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + + switch (TREE_CODE (stmt)) + { + case LABEL_EXPR: + if (DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt))) + return false; + break; + + default: + bb_ann (bb)->forwardable = 0; + return false; + } + } + + return true; +} + + +/* Thread jumps over empty statements. + + This code should _not_ thread over obviously equivalent conditions + as that requires nontrivial updates to the SSA graph. */ + +static bool +thread_jumps (void) +{ + edge e, next, last, old; + basic_block bb, dest, tmp; + tree phi; + int arg; + bool retval = false; + + FOR_EACH_BB (bb) + bb_ann (bb)->forwardable = 1; + + FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb) + { + /* Don't waste time on unreachable blocks. */ + if (!bb->pred) + continue; + + /* Nor on forwarders. */ + if (tree_forwarder_block_p (bb)) + continue; + + /* This block is now part of a forwarding path, mark it as not + forwardable so that we can detect loops. This bit will be + reset below. */ + bb_ann (bb)->forwardable = 0; + + /* Examine each of our block's successors to see if it is + forwardable. */ + for (e = bb->succ; e; e = next) + { + next = e->succ_next; + + /* If the edge is abnormal or its destination is not + forwardable, then there's nothing to do. */ + if ((e->flags & EDGE_ABNORMAL) + || !tree_forwarder_block_p (e->dest)) + continue; + + /* Now walk through as many forwarder block as possible to + find the ultimate destination we want to thread our jump + to. */ + last = e->dest->succ; + bb_ann (e->dest)->forwardable = 0; + for (dest = e->dest->succ->dest; + tree_forwarder_block_p (dest); + last = dest->succ, + dest = dest->succ->dest) + { + /* An infinite loop detected. We redirect the edge anyway, so + that the loop is shrinked into single basic block. */ + if (!bb_ann (dest)->forwardable) + break; + + if (dest->succ->dest == EXIT_BLOCK_PTR) + break; + + bb_ann (dest)->forwardable = 0; + } + + /* Reset the forwardable marks to 1. */ + for (tmp = e->dest; + tmp != dest; + tmp = tmp->succ->dest) + bb_ann (tmp)->forwardable = 1; + + if (dest == e->dest) + continue; + + old = find_edge (bb, dest); + if (old) + { + /* If there already is an edge, check whether the values + in phi nodes differ. */ + if (!phi_alternatives_equal (dest, last, old)) + { + /* The previous block is forwarder. Redirect our jump + to that target instead since we know it has no PHI + nodes that will need updating. */ + dest = last->src; + + /* That might mean that no forwarding at all is possible. */ + if (dest == e->dest) + continue; + + old = find_edge (bb, dest); + } + } + + /* Perform the redirection. */ + retval = true; + e = redirect_edge_and_branch (e, dest); + + /* TODO -- updating dominators in this case is simple. */ + free_dominance_info (CDI_DOMINATORS); + + if (!old) + { + /* Update PHI nodes. We know that the new argument should + have the same value as the argument associated with LAST. + Otherwise we would have changed our target block above. */ + for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi)) + { + arg = phi_arg_from_edge (phi, last); + if (arg < 0) + abort (); + add_phi_arg (&phi, PHI_ARG_DEF (phi, arg), e); + } + } + } + + /* Reset the forwardable bit on our block since it's no longer in + a forwarding chain path. */ + bb_ann (bb)->forwardable = 1; + } + + return retval; +} + + +/* Return a non-special label in the head of basic block BLOCK. + Create one if it doesn't exist. */ + +static tree +tree_block_label (basic_block bb) +{ + block_stmt_iterator i, s = bsi_start (bb); + bool first = true; + tree label, stmt; + + for (i = s; !bsi_end_p (i); first = false, bsi_next (&i)) + { + stmt = bsi_stmt (i); + if (TREE_CODE (stmt) != LABEL_EXPR) + break; + label = LABEL_EXPR_LABEL (stmt); + if (!DECL_NONLOCAL (label)) + { + if (!first) + bsi_move_before (&i, &s); + return label; + } + } + + label = create_artificial_label (); + stmt = build1 (LABEL_EXPR, void_type_node, label); + bsi_insert_before (&s, stmt, BSI_NEW_STMT); + return label; +} + + +/* Attempt to perform edge redirection by replacing a possibly complex + jump instruction by a goto or by removing the jump completely. + This can apply only if all edges now point to the same block. The + parameters and return values are equivalent to + redirect_edge_and_branch. */ + +static edge +tree_try_redirect_by_replacing_jump (edge e, basic_block target) +{ + basic_block src = e->src; + edge tmp; + block_stmt_iterator b; + tree stmt; + + /* Verify that all targets will be TARGET. */ + for (tmp = src->succ; tmp; tmp = tmp->succ_next) + if (tmp->dest != target && tmp != e) + break; + + if (tmp) + return NULL; + + b = bsi_last (src); + if (bsi_end_p (b)) + return NULL; + stmt = bsi_stmt (b); + + if (TREE_CODE (stmt) == COND_EXPR + || TREE_CODE (stmt) == SWITCH_EXPR) + { + bsi_remove (&b); + e = ssa_redirect_edge (e, target); + e->flags = EDGE_FALLTHRU; + return e; + } + + return NULL; +} + + +/* Redirect E to DEST. Return NULL on failure. Otherwise, return the + edge representing the redirected branch. */ + +static edge +tree_redirect_edge_and_branch (edge e, basic_block dest) +{ + basic_block bb = e->src; + block_stmt_iterator bsi; + edge ret; + tree label, stmt; + + if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH)) + return NULL; + + if (e->src != ENTRY_BLOCK_PTR + && (ret = tree_try_redirect_by_replacing_jump (e, dest))) + return ret; + + if (e->dest == dest) + return NULL; + + label = tree_block_label (dest); + + bsi = bsi_last (bb); + stmt = bsi_end_p (bsi) ? NULL : bsi_stmt (bsi); + + switch (stmt ? TREE_CODE (stmt) : ERROR_MARK) + { + case COND_EXPR: + stmt = (e->flags & EDGE_TRUE_VALUE + ? COND_EXPR_THEN (stmt) + : COND_EXPR_ELSE (stmt)); + GOTO_DESTINATION (stmt) = label; + break; + + case GOTO_EXPR: + /* No non-abnormal edges should lead from a non-simple goto, and + simple ones should be represented implicitly. */ + abort (); + + case SWITCH_EXPR: + { + tree vec = SWITCH_LABELS (stmt); + size_t i, n = TREE_VEC_LENGTH (vec); + + for (i = 0; i < n; ++i) + { + tree elt = TREE_VEC_ELT (vec, i); + if (label_to_block (CASE_LABEL (elt)) == e->dest) + CASE_LABEL (elt) = label; + } + } + break; + + case RETURN_EXPR: + bsi_remove (&bsi); + e->flags |= EDGE_FALLTHRU; + break; + + default: + /* Otherwise it must be a fallthru edge, and we don't need to + do anything besides redirecting it. */ + if (!(e->flags & EDGE_FALLTHRU)) + abort (); + break; + } + + /* Update/insert PHI nodes as necessary. */ + + /* Now update the edges in the CFG. */ + e = ssa_redirect_edge (e, dest); + + return e; +} + + +/* Simple wrapper, as we can always redirect fallthru edges. */ + +static basic_block +tree_redirect_edge_and_branch_force (edge e, basic_block dest) +{ + e = tree_redirect_edge_and_branch (e, dest); + if (!e) + abort (); + + return NULL; +} + + +/* Splits basic block BB after statement STMT (but at least after the + labels). If STMT is NULL, BB is split just after the labels. */ + +static basic_block +tree_split_block (basic_block bb, void *stmt) +{ + block_stmt_iterator bsi, bsi_tgt; + tree act; + basic_block new_bb; + edge e; + + new_bb = create_empty_bb (bb); + + /* Redirect the outgoing edges. */ + new_bb->succ = bb->succ; + bb->succ = NULL; + for (e = new_bb->succ; e; e = e->succ_next) + e->src = new_bb; + + if (stmt && TREE_CODE ((tree) stmt) == LABEL_EXPR) + stmt = NULL; + + /* Move everything from BSI to the new basic block. */ + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + act = bsi_stmt (bsi); + if (TREE_CODE (act) == LABEL_EXPR) + continue; + + if (!stmt) + break; + + if (stmt == act) + { + bsi_next (&bsi); + break; + } + } + + bsi_tgt = bsi_start (new_bb); + while (!bsi_end_p (bsi)) + { + act = bsi_stmt (bsi); + bsi_remove (&bsi); + bsi_insert_after (&bsi_tgt, act, BSI_NEW_STMT); + } + + return new_bb; +} + + +/* Moves basic block BB after block AFTER. */ + +static bool +tree_move_block_after (basic_block bb, basic_block after) +{ + if (bb->prev_bb == after) + return true; + + unlink_block (bb); + link_block (bb, after); + + return true; +} + + +/* Return true if basic_block can be duplicated. */ + +static bool +tree_can_duplicate_bb_p (basic_block bb ATTRIBUTE_UNUSED) +{ + return true; +} + + +/* Create a duplicate of the basic block BB. NOTE: This does not + preserve SSA form. */ + +static basic_block +tree_duplicate_bb (basic_block bb) +{ + basic_block new_bb; + block_stmt_iterator bsi, bsi_tgt; + + new_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb); + bsi_tgt = bsi_start (new_bb); + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + + if (TREE_CODE (stmt) == LABEL_EXPR) + continue; + + bsi_insert_after (&bsi_tgt, unshare_expr (stmt), BSI_NEW_STMT); + } + + return new_bb; +} + + +/* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree.h) */ + +void +dump_function_to_file (tree fn, FILE *file, int flags) +{ + tree arg, vars, var; + bool ignore_topmost_bind = false, any_var = false; + basic_block bb; + tree chain; + + fprintf (file, "%s (", (*lang_hooks.decl_printable_name) (fn, 2)); + + arg = DECL_ARGUMENTS (fn); + while (arg) + { + print_generic_expr (file, arg, dump_flags); + if (TREE_CHAIN (arg)) + fprintf (file, ", "); + arg = TREE_CHAIN (arg); + } + fprintf (file, ")\n"); + + if (flags & TDF_RAW) + { + dump_node (fn, TDF_SLIM | flags, file); + return; + } + + /* When GIMPLE is lowered, the variables are no longer available in + BIND_EXPRs, so display them separately. */ + if (cfun && cfun->unexpanded_var_list) + { + ignore_topmost_bind = true; + + fprintf (file, "{\n"); + for (vars = cfun->unexpanded_var_list; vars; vars = TREE_CHAIN (vars)) + { + var = TREE_VALUE (vars); + + print_generic_decl (file, var, flags); + fprintf (file, "\n"); + + any_var = true; + } + } + + if (basic_block_info) + { + /* Make a CFG based dump. */ + if (!ignore_topmost_bind) + fprintf (file, "{\n"); + + if (any_var && n_basic_blocks) + fprintf (file, "\n"); + + FOR_EACH_BB (bb) + dump_generic_bb (file, bb, 2, flags); + + fprintf (file, "}\n"); + } + else + { + int indent; + + /* Make a tree based dump. */ + chain = DECL_SAVED_TREE (fn); + + if (TREE_CODE (chain) == BIND_EXPR) + { + if (ignore_topmost_bind) + { + chain = BIND_EXPR_BODY (chain); + indent = 2; + } + else + indent = 0; + } + else + { + if (!ignore_topmost_bind) + fprintf (file, "{\n"); + indent = 2; + } + + if (any_var) + fprintf (file, "\n"); + + print_generic_stmt_indented (file, chain, flags, indent); + if (ignore_topmost_bind) + fprintf (file, "}\n"); + } + + fprintf (file, "\n\n"); +} + + +/* Pretty print of the loops intermediate representation. */ +static void print_loop (FILE *, struct loop *, int); +static void print_pred_bbs (FILE *, edge); +static void print_succ_bbs (FILE *, edge); + + +/* Print the predecessors indexes of edge E on FILE. */ + +static void +print_pred_bbs (FILE *file, edge e) +{ + if (e == NULL) + return; + + else if (e->pred_next == NULL) + fprintf (file, "bb_%d", e->src->index); + + else + { + fprintf (file, "bb_%d, ", e->src->index); + print_pred_bbs (file, e->pred_next); + } +} + + +/* Print the successors indexes of edge E on FILE. */ + +static void +print_succ_bbs (FILE *file, edge e) +{ + if (e == NULL) + return; + else if (e->succ_next == NULL) + fprintf (file, "bb_%d", e->dest->index); + else + { + fprintf (file, "bb_%d, ", e->dest->index); + print_succ_bbs (file, e->succ_next); + } +} + + +/* Pretty print LOOP on FILE, indented INDENT spaces. */ + +static void +print_loop (FILE *file, struct loop *loop, int indent) +{ + char *s_indent; + basic_block bb; + + if (loop == NULL) + return; + + s_indent = (char *) alloca ((size_t) indent + 1); + memset ((void *) s_indent, ' ', (size_t) indent); + s_indent[indent] = '\0'; + + /* Print the loop's header. */ + fprintf (file, "%sloop_%d\n", s_indent, loop->num); + + /* Print the loop's body. */ + fprintf (file, "%s{\n", s_indent); + FOR_EACH_BB (bb) + if (bb->loop_father == loop) + { + /* Print the basic_block's header. */ + fprintf (file, "%s bb_%d (preds = {", s_indent, bb->index); + print_pred_bbs (file, bb->pred); + fprintf (file, "}, succs = {"); + print_succ_bbs (file, bb->succ); + fprintf (file, "})\n"); + + /* Print the basic_block's body. */ + fprintf (file, "%s {\n", s_indent); + tree_dump_bb (bb, file, indent + 4); + fprintf (file, "%s }\n", s_indent); + } + + print_loop (file, loop->inner, indent + 2); + fprintf (file, "%s}\n", s_indent); + print_loop (file, loop->next, indent); +} + + +/* Follow a CFG edge from the entry point of the program, and on entry + of a loop, pretty print the loop structure on FILE. */ + +void +print_loop_ir (FILE *file) +{ + basic_block bb; + + bb = BASIC_BLOCK (0); + if (bb && bb->loop_father) + print_loop (file, bb->loop_father, 0); +} + + +/* Debugging loops structure at tree level. */ + +void +debug_loop_ir (void) +{ + print_loop_ir (stderr); +} + + +/* Return true if BB ends with a call, possibly followed by some + instructions that must stay with the call. Return false, + otherwise. */ + +static bool +tree_block_ends_with_call_p (basic_block bb) +{ + block_stmt_iterator bsi = bsi_last (bb); + tree t = tsi_stmt (bsi.tsi); + + if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0)) + t = TREE_OPERAND (t, 0); + + if (TREE_CODE (t) == MODIFY_EXPR) + t = TREE_OPERAND (t, 1); + + return TREE_CODE (t) == CALL_EXPR; +} + + +/* Return true if BB ends with a conditional branch. Return false, + otherwise. */ + +static bool +tree_block_ends_with_condjump_p (basic_block bb) +{ + tree stmt = tsi_stmt (bsi_last (bb).tsi); + return (TREE_CODE (stmt) == COND_EXPR); +} + + +/* Return true if we need to add fake edge to exit at statement T. + Helper function for tree_flow_call_edges_add. */ + +static bool +need_fake_edge_p (tree t) +{ + if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0)) + t = TREE_OPERAND (t, 0); + + if (TREE_CODE (t) == MODIFY_EXPR) + t = TREE_OPERAND (t, 1); + + /* NORETURN and LONGJMP calls already have an edge to exit. + CONST, PURE and ALWAYS_RETURN calls do not need one. + We don't currently check for CONST and PURE here, although + it would be a good idea, because those attributes are + figured out from the RTL in mark_constant_function, and + the counter incrementation code from -fprofile-arcs + leads to different results from -fbranch-probabilities. */ + if (TREE_CODE (t) == CALL_EXPR + && !(call_expr_flags (t) & + (ECF_NORETURN | ECF_LONGJMP | ECF_ALWAYS_RETURN))) + return true; + + if (TREE_CODE (t) == ASM_EXPR + && (ASM_VOLATILE_P (t) || ASM_INPUT_P (t))) + return true; + + return false; +} + + +/* Add fake edges to the function exit for any non constant and non + noreturn calls, volatile inline assembly in the bitmap of blocks + specified by BLOCKS or to the whole CFG if BLOCKS is zero. Return + the number of blocks that were split. + + The goal is to expose cases in which entering a basic block does + not imply that all subsequent instructions must be executed. */ + +static int +tree_flow_call_edges_add (sbitmap blocks) +{ + int i; + int blocks_split = 0; + int last_bb = last_basic_block; + bool check_last_block = false; + + if (n_basic_blocks == 0) + return 0; + + if (! blocks) + check_last_block = true; + else + check_last_block = TEST_BIT (blocks, EXIT_BLOCK_PTR->prev_bb->index); + + /* In the last basic block, before epilogue generation, there will be + a fallthru edge to EXIT. Special care is required if the last insn + of the last basic block is a call because make_edge folds duplicate + edges, which would result in the fallthru edge also being marked + fake, which would result in the fallthru edge being removed by + remove_fake_edges, which would result in an invalid CFG. + + Moreover, we can't elide the outgoing fake edge, since the block + profiler needs to take this into account in order to solve the minimal + spanning tree in the case that the call doesn't return. + + Handle this by adding a dummy instruction in a new last basic block. */ + if (check_last_block) + { + basic_block bb = EXIT_BLOCK_PTR->prev_bb; + block_stmt_iterator bsi = bsi_last (bb); + tree t = NULL_TREE; + if (!bsi_end_p (bsi)) + t = bsi_stmt (bsi); + + if (need_fake_edge_p (t)) + { + edge e; + + for (e = bb->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR) + { + bsi_insert_on_edge (e, build_empty_stmt ()); + bsi_commit_edge_inserts ((int *)NULL); + break; + } + } + } + + /* Now add fake edges to the function exit for any non constant + calls since there is no way that we can determine if they will + return or not... */ + for (i = 0; i < last_bb; i++) + { + basic_block bb = BASIC_BLOCK (i); + block_stmt_iterator bsi; + tree stmt, last_stmt; + + if (!bb) + continue; + + if (blocks && !TEST_BIT (blocks, i)) + continue; + + bsi = bsi_last (bb); + if (!bsi_end_p (bsi)) + { + last_stmt = bsi_stmt (bsi); + do + { + stmt = bsi_stmt (bsi); + if (need_fake_edge_p (stmt)) + { + edge e; + /* The handling above of the final block before the + epilogue should be enough to verify that there is + no edge to the exit block in CFG already. + Calling make_edge in such case would cause us to + mark that edge as fake and remove it later. */ +#ifdef ENABLE_CHECKING + if (stmt == last_stmt) + for (e = bb->succ; e; e = e->succ_next) + if (e->dest == EXIT_BLOCK_PTR) + abort (); +#endif + + /* Note that the following may create a new basic block + and renumber the existing basic blocks. */ + if (stmt != last_stmt) + { + e = split_block (bb, stmt); + if (e) + blocks_split++; + } + make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE); + } + bsi_prev (&bsi); + } + while (!bsi_end_p (bsi)); + } + } + + if (blocks_split) + verify_flow_info (); + + return blocks_split; +} + + +struct cfg_hooks tree_cfg_hooks = { + "tree", + tree_verify_flow_info, + tree_dump_bb, /* dump_bb */ + create_bb, /* create_basic_block */ + tree_redirect_edge_and_branch,/* redirect_edge_and_branch */ + tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force */ + remove_bb, /* delete_basic_block */ + tree_split_block, /* split_block */ + tree_move_block_after, /* move_block_after */ + tree_can_merge_blocks_p, /* can_merge_blocks_p */ + tree_merge_blocks, /* merge_blocks */ + tree_predict_edge, /* predict_edge */ + tree_predicted_by_p, /* predicted_by_p */ + tree_can_duplicate_bb_p, /* can_duplicate_block_p */ + tree_duplicate_bb, /* duplicate_block */ + tree_split_edge, /* split_edge */ + tree_make_forwarder_block, /* make_forward_block */ + NULL, /* tidy_fallthru_edge */ + tree_block_ends_with_call_p, /* block_ends_with_call_p */ + tree_block_ends_with_condjump_p, /* block_ends_with_condjump_p */ + tree_flow_call_edges_add /* flow_call_edges_add */ +}; + + +/* Split all critical edges. */ + +static void +split_critical_edges (void) +{ + basic_block bb; + edge e; + + FOR_ALL_BB (bb) + { + for (e = bb->succ; e ; e = e->succ_next) + if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL)) + { + split_edge (e); + } + } +} + +struct tree_opt_pass pass_split_crit_edges = +{ + NULL, /* name */ + NULL, /* gate */ + split_critical_edges, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_SPLIT_EDGES, /* tv_id */ + PROP_cfg, /* properties required */ + PROP_no_crit_edges, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +/* Emit return warnings. */ + +static void +execute_warn_function_return (void) +{ + location_t *locus; + tree last; + edge e; + + if (warn_missing_noreturn + && !TREE_THIS_VOLATILE (cfun->decl) + && EXIT_BLOCK_PTR->pred == NULL + && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl)) + warning ("%Jfunction might be possible candidate for attribute `noreturn'", + cfun->decl); + + /* If we have a path to EXIT, then we do return. */ + if (TREE_THIS_VOLATILE (cfun->decl) + && EXIT_BLOCK_PTR->pred != NULL) + { + locus = NULL; + for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next) + { + last = last_stmt (e->src); + if (TREE_CODE (last) == RETURN_EXPR + && (locus = EXPR_LOCUS (last)) != NULL) + break; + } + if (!locus) + locus = &cfun->function_end_locus; + warning ("%H`noreturn' function does return", locus); + } + + /* If we see "return;" in some basic block, then we do reach the end + without returning a value. */ + else if (warn_return_type + && EXIT_BLOCK_PTR->pred != NULL + && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl)))) + { + for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next) + { + tree last = last_stmt (e->src); + if (TREE_CODE (last) == RETURN_EXPR + && TREE_OPERAND (last, 0) == NULL) + { + locus = EXPR_LOCUS (last); + if (!locus) + locus = &cfun->function_end_locus; + warning ("%Hcontrol reaches end of non-void function", locus); + break; + } + } + } +} + + +/* Given a basic block B which ends with a conditional and has + precisely two successors, determine which of the edges is taken if + the conditional is true and which is taken if the conditional is + false. Set TRUE_EDGE and FALSE_EDGE appropriately. */ + +void +extract_true_false_edges_from_block (basic_block b, + edge *true_edge, + edge *false_edge) +{ + edge e = b->succ; + + if (e->flags & EDGE_TRUE_VALUE) + { + *true_edge = e; + *false_edge = e->succ_next; + } + else + { + *false_edge = e; + *true_edge = e->succ_next; + } +} + +struct tree_opt_pass pass_warn_function_return = +{ + NULL, /* name */ + NULL, /* gate */ + execute_warn_function_return, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +#include "gt-tree-cfg.h" diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c new file mode 100644 index 00000000000..fe963041a05 --- /dev/null +++ b/gcc/tree-complex.c @@ -0,0 +1,572 @@ +/* Lower complex operations to scalar operations. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tm.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-iterator.h" +#include "tree-pass.h" +#include "flags.h" + + +/* Build a temporary. Make sure and register it to be renamed. */ + +static tree +make_temp (tree type) +{ + tree t = create_tmp_var (type, NULL); + add_referenced_tmp_var (t); + bitmap_set_bit (vars_to_rename, var_ann (t)->uid); + return t; +} + +/* Force EXP to be a gimple_val. */ + +static tree +gimplify_val (block_stmt_iterator *bsi, tree type, tree exp) +{ + tree t, new_stmt, orig_stmt; + + if (is_gimple_val (exp)) + return exp; + + t = make_temp (type); + new_stmt = build (MODIFY_EXPR, type, t, exp); + + orig_stmt = bsi_stmt (*bsi); + SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt)); + TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt); + + bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT); + + return t; +} + +/* Extract the real or imaginary part of a complex variable or constant. + Make sure that it's a proper gimple_val and gimplify it if not. + Emit any new code before BSI. */ + +static tree +extract_component (block_stmt_iterator *bsi, tree t, bool imagpart_p) +{ + tree ret, inner_type; + + inner_type = TREE_TYPE (TREE_TYPE (t)); + switch (TREE_CODE (t)) + { + case COMPLEX_CST: + ret = (imagpart_p ? TREE_IMAGPART (t) : TREE_REALPART (t)); + break; + + case COMPLEX_EXPR: + ret = TREE_OPERAND (t, imagpart_p); + break; + + case VAR_DECL: + case PARM_DECL: + ret = build1 ((imagpart_p ? IMAGPART_EXPR : REALPART_EXPR), + inner_type, t); + break; + + default: + abort (); + } + + return gimplify_val (bsi, inner_type, ret); +} + +/* Build a binary operation and gimplify it. Emit code before BSI. + Return the gimple_val holding the result. */ + +static tree +do_binop (block_stmt_iterator *bsi, enum tree_code code, + tree type, tree a, tree b) +{ + tree ret; + + ret = fold (build (code, type, a, b)); + STRIP_NOPS (ret); + + return gimplify_val (bsi, type, ret); +} + +/* Build a unary operation and gimplify it. Emit code before BSI. + Return the gimple_val holding the result. */ + +static tree +do_unop (block_stmt_iterator *bsi, enum tree_code code, tree type, tree a) +{ + tree ret; + + ret = fold (build1 (code, type, a)); + STRIP_NOPS (ret); + + return gimplify_val (bsi, type, ret); +} + +/* Update an assignment to a complex variable in place. */ + +static void +update_complex_assignment (block_stmt_iterator *bsi, tree r, tree i) +{ + tree stmt = bsi_stmt (*bsi); + tree type; + + modify_stmt (stmt); + if (TREE_CODE (stmt) == RETURN_EXPR) + stmt = TREE_OPERAND (stmt, 0); + + type = TREE_TYPE (TREE_OPERAND (stmt, 1)); + TREE_OPERAND (stmt, 1) = build (COMPLEX_EXPR, type, r, i); +} + +/* Expand complex addition to scalars: + a + b = (ar + br) + i(ai + bi) + a - b = (ar - br) + i(ai + bi) +*/ + +static void +expand_complex_addition (block_stmt_iterator *bsi, tree inner_type, + tree ar, tree ai, tree br, tree bi, + enum tree_code code) +{ + tree rr, ri; + + rr = do_binop (bsi, code, inner_type, ar, br); + ri = do_binop (bsi, code, inner_type, ai, bi); + + update_complex_assignment (bsi, rr, ri); +} + +/* Expand complex multiplication to scalars: + a * b = (ar*br - ai*bi) + i(ar*bi + br*ai) +*/ + +static void +expand_complex_multiplication (block_stmt_iterator *bsi, tree inner_type, + tree ar, tree ai, tree br, tree bi) +{ + tree t1, t2, t3, t4, rr, ri; + + t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, br); + t2 = do_binop (bsi, MULT_EXPR, inner_type, ai, bi); + t3 = do_binop (bsi, MULT_EXPR, inner_type, ar, bi); + + /* Avoid expanding redundant multiplication for the common + case of squaring a complex number. */ + if (ar == br && ai == bi) + t4 = t3; + else + t4 = do_binop (bsi, MULT_EXPR, inner_type, ai, br); + + rr = do_binop (bsi, MINUS_EXPR, inner_type, t1, t2); + ri = do_binop (bsi, PLUS_EXPR, inner_type, t3, t4); + + update_complex_assignment (bsi, rr, ri); +} + +/* Expand complex division to scalars, straightforward algorithm. + a / b = ((ar*br + ai*bi)/t) + i((ai*br - ar*bi)/t) + t = br*br + bi*bi +*/ + +static void +expand_complex_div_straight (block_stmt_iterator *bsi, tree inner_type, + tree ar, tree ai, tree br, tree bi, + enum tree_code code) +{ + tree rr, ri, div, t1, t2, t3; + + t1 = do_binop (bsi, MULT_EXPR, inner_type, br, br); + t2 = do_binop (bsi, MULT_EXPR, inner_type, bi, bi); + div = do_binop (bsi, PLUS_EXPR, inner_type, t1, t2); + + t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, br); + t2 = do_binop (bsi, MULT_EXPR, inner_type, ai, bi); + t3 = do_binop (bsi, PLUS_EXPR, inner_type, t1, t2); + rr = do_binop (bsi, code, inner_type, t3, div); + + t1 = do_binop (bsi, MULT_EXPR, inner_type, ai, br); + t2 = do_binop (bsi, MULT_EXPR, inner_type, ar, bi); + t3 = do_binop (bsi, MINUS_EXPR, inner_type, t1, t2); + ri = do_binop (bsi, code, inner_type, t3, div); + + update_complex_assignment (bsi, rr, ri); +} + +/* Expand complex division to scalars, modified algorithm to minimize + overflow with wide input ranges. */ + +static void +expand_complex_div_wide (block_stmt_iterator *bsi, tree inner_type, + tree ar, tree ai, tree br, tree bi, + enum tree_code code) +{ + tree rr, ri, ratio, div, t1, t2, min, max, cond; + + /* Examine |br| < |bi|, and branch. */ + t1 = do_unop (bsi, ABS_EXPR, inner_type, br); + t2 = do_unop (bsi, ABS_EXPR, inner_type, bi); + cond = fold (build (LT_EXPR, boolean_type_node, t1, t2)); + STRIP_NOPS (cond); + + if (TREE_CONSTANT (cond)) + { + if (integer_zerop (cond)) + min = bi, max = br; + else + min = br, max = bi; + } + else + { + basic_block bb_cond, bb_true, bb_false, bb_join; + tree l1, l2, l3; + edge e; + + l1 = create_artificial_label (); + t1 = build (GOTO_EXPR, void_type_node, l1); + l2 = create_artificial_label (); + t2 = build (GOTO_EXPR, void_type_node, l2); + cond = build (COND_EXPR, void_type_node, cond, t1, t2); + bsi_insert_before (bsi, cond, BSI_SAME_STMT); + + min = make_temp (inner_type); + max = make_temp (inner_type); + l3 = create_artificial_label (); + + /* Split the original block, and create the TRUE and FALSE blocks. */ + e = split_block (bsi->bb, cond); + bb_cond = e->src; + bb_join = e->dest; + bb_true = create_empty_bb (bb_cond); + bb_false = create_empty_bb (bb_true); + + /* Wire the blocks together. */ + e->flags = EDGE_TRUE_VALUE; + redirect_edge_succ (e, bb_true); + make_edge (bb_cond, bb_false, EDGE_FALSE_VALUE); + make_edge (bb_true, bb_join, 0); + make_edge (bb_false, bb_join, 0); + + /* Update dominance info. Note that bb_join's data was + updated by split_block. */ + if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK) + { + set_immediate_dominator (CDI_DOMINATORS, bb_true, bb_cond); + set_immediate_dominator (CDI_DOMINATORS, bb_false, bb_cond); + } + + /* Compute min and max for TRUE block. */ + *bsi = bsi_start (bb_true); + t1 = build (LABEL_EXPR, void_type_node, l1); + bsi_insert_after (bsi, t1, BSI_NEW_STMT); + t1 = build (MODIFY_EXPR, inner_type, min, br); + bsi_insert_after (bsi, t1, BSI_NEW_STMT); + t1 = build (MODIFY_EXPR, inner_type, max, bi); + bsi_insert_after (bsi, t1, BSI_NEW_STMT); + + /* Compute min and max for FALSE block. */ + *bsi = bsi_start (bb_false); + t1 = build (LABEL_EXPR, void_type_node, l2); + bsi_insert_after (bsi, t1, BSI_NEW_STMT); + t1 = build (MODIFY_EXPR, inner_type, min, bi); + bsi_insert_after (bsi, t1, BSI_NEW_STMT); + t1 = build (MODIFY_EXPR, inner_type, max, br); + bsi_insert_after (bsi, t1, BSI_NEW_STMT); + + /* Insert the join label into the tail of the original block. */ + *bsi = bsi_start (bb_join); + t1 = build (LABEL_EXPR, void_type_node, l3); + bsi_insert_before (bsi, t1, BSI_SAME_STMT); + } + + /* Now we have MIN(|br|, |bi|) and MAX(|br|, |bi|). We now use the + ratio min/max to scale both the dividend and divisor. */ + ratio = do_binop (bsi, code, inner_type, min, max); + + /* Calculate the divisor: min*ratio + max. */ + t1 = do_binop (bsi, MULT_EXPR, inner_type, min, ratio); + div = do_binop (bsi, PLUS_EXPR, inner_type, t1, max); + + /* Result is now ((ar + ai*ratio)/div) + i((ai - ar*ratio)/div). */ + t1 = do_binop (bsi, MULT_EXPR, inner_type, ai, ratio); + t2 = do_binop (bsi, PLUS_EXPR, inner_type, ar, t1); + rr = do_binop (bsi, code, inner_type, t2, div); + + t1 = do_binop (bsi, MULT_EXPR, inner_type, ar, ratio); + t2 = do_binop (bsi, MINUS_EXPR, inner_type, ai, t1); + ri = do_binop (bsi, code, inner_type, t2, div); + + update_complex_assignment (bsi, rr, ri); +} + +/* Expand complex division to scalars. */ + +static void +expand_complex_division (block_stmt_iterator *bsi, tree inner_type, + tree ar, tree ai, tree br, tree bi, + enum tree_code code) +{ + switch (flag_complex_divide_method) + { + case 0: + /* straightforward implementation of complex divide acceptable. */ + expand_complex_div_straight (bsi, inner_type, ar, ai, br, bi, code); + break; + case 1: + /* wide ranges of inputs must work for complex divide. */ + expand_complex_div_wide (bsi, inner_type, ar, ai, br, bi, code); + break; + default: + /* C99-like requirements for complex divide (not yet implemented). */ + abort (); + } +} + +/* Expand complex negation to scalars: + -a = (-ar) + i(-ai) +*/ + +static void +expand_complex_negation (block_stmt_iterator *bsi, tree inner_type, + tree ar, tree ai) +{ + tree rr, ri; + + rr = do_unop (bsi, NEGATE_EXPR, inner_type, ar); + ri = do_unop (bsi, NEGATE_EXPR, inner_type, ai); + + update_complex_assignment (bsi, rr, ri); +} + +/* Expand complex conjugate to scalars: + ~a = (ar) + i(-ai) +*/ + +static void +expand_complex_conjugate (block_stmt_iterator *bsi, tree inner_type, + tree ar, tree ai) +{ + tree ri; + + ri = do_unop (bsi, NEGATE_EXPR, inner_type, ai); + + update_complex_assignment (bsi, ar, ri); +} + +/* Expand complex comparison (EQ or NE only). */ + +static void +expand_complex_comparison (block_stmt_iterator *bsi, tree ar, tree ai, + tree br, tree bi, enum tree_code code) +{ + tree cr, ci, cc, stmt, type; + + cr = do_binop (bsi, code, boolean_type_node, ar, br); + ci = do_binop (bsi, code, boolean_type_node, ai, bi); + cc = do_binop (bsi, (code == EQ_EXPR ? TRUTH_AND_EXPR : TRUTH_OR_EXPR), + boolean_type_node, cr, ci); + + stmt = bsi_stmt (*bsi); + modify_stmt (stmt); + + switch (TREE_CODE (stmt)) + { + case RETURN_EXPR: + stmt = TREE_OPERAND (stmt, 0); + /* FALLTHRU */ + case MODIFY_EXPR: + type = TREE_TYPE (TREE_OPERAND (stmt, 1)); + TREE_OPERAND (stmt, 1) = convert (type, cc); + break; + case COND_EXPR: + TREE_OPERAND (stmt, 0) = cc; + break; + default: + abort (); + } +} + +/* Process one statement. If we identify a complex operation, expand it. */ + +static void +expand_complex_operations_1 (block_stmt_iterator *bsi) +{ + tree stmt = bsi_stmt (*bsi); + tree rhs, type, inner_type; + tree ac, ar, ai, bc, br, bi; + enum tree_code code; + + switch (TREE_CODE (stmt)) + { + case RETURN_EXPR: + stmt = TREE_OPERAND (stmt, 0); + if (!stmt) + return; + if (TREE_CODE (stmt) != MODIFY_EXPR) + return; + /* FALLTHRU */ + + case MODIFY_EXPR: + rhs = TREE_OPERAND (stmt, 1); + break; + + case COND_EXPR: + rhs = TREE_OPERAND (stmt, 0); + break; + + default: + return; + } + + type = TREE_TYPE (rhs); + code = TREE_CODE (rhs); + + /* Initial filter for operations we handle. */ + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + case NEGATE_EXPR: + case CONJ_EXPR: + if (TREE_CODE (type) != COMPLEX_TYPE) + return; + inner_type = TREE_TYPE (type); + break; + + case EQ_EXPR: + case NE_EXPR: + inner_type = TREE_TYPE (TREE_OPERAND (rhs, 1)); + if (TREE_CODE (inner_type) != COMPLEX_TYPE) + return; + break; + + default: + return; + } + + /* Extract the components of the two complex values. Make sure and + handle the common case of the same value used twice specially. */ + ac = TREE_OPERAND (rhs, 0); + ar = extract_component (bsi, ac, 0); + ai = extract_component (bsi, ac, 1); + + if (TREE_CODE_CLASS (code) == '1') + bc = br = bi = NULL; + else + { + bc = TREE_OPERAND (rhs, 1); + if (ac == bc) + br = ar, bi = ai; + else + { + br = extract_component (bsi, bc, 0); + bi = extract_component (bsi, bc, 1); + } + } + + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + expand_complex_addition (bsi, inner_type, ar, ai, br, bi, code); + break; + + case MULT_EXPR: + expand_complex_multiplication (bsi, inner_type, ar, ai, br, bi); + break; + + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + expand_complex_division (bsi, inner_type, ar, ai, br, bi, code); + break; + + case NEGATE_EXPR: + expand_complex_negation (bsi, inner_type, ar, ai); + break; + + case CONJ_EXPR: + expand_complex_conjugate (bsi, inner_type, ar, ai); + break; + + case EQ_EXPR: + case NE_EXPR: + expand_complex_comparison (bsi, ar, ai, br, bi, code); + break; + + default: + abort (); + } +} + +/* Main loop to process each statement. */ +/* ??? Could use dominator bits to propagate from complex_expr at the + same time. This might reveal more constants, particularly in cases + such as (complex = complex op scalar). This may not be relevant + after SRA and subsequent cleanups. Proof of this would be if we + verify that the code generated by expand_complex_div_wide is + simplified properly to straight-line code. */ + +static void +expand_complex_operations (void) +{ + int old_last_basic_block = last_basic_block; + block_stmt_iterator bsi; + basic_block bb; + + FOR_EACH_BB (bb) + { + if (bb->index >= old_last_basic_block) + continue; + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + expand_complex_operations_1 (&bsi); + } +} + +struct tree_opt_pass pass_lower_complex = +{ + "complex", /* name */ + NULL, /* gate */ + expand_complex_operations, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_rename_vars + | TODO_ggc_collect | TODO_verify_ssa + | TODO_verify_stmts | TODO_verify_flow /* todo_flags_finish */ +}; diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c new file mode 100644 index 00000000000..cda68487efb --- /dev/null +++ b/gcc/tree-dfa.c @@ -0,0 +1,1153 @@ +/* Data flow functions for trees. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "hashtab.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "timevar.h" +#include "expr.h" +#include "ggc.h" +#include "langhooks.h" +#include "flags.h" +#include "function.h" +#include "diagnostic.h" +#include "tree-dump.h" +#include "tree-simple.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "tree-alias-common.h" +#include "tree-pass.h" +#include "convert.h" +#include "params.h" + +/* Build and maintain data flow information for trees. */ + +/* Counters used to display DFA and SSA statistics. */ +struct dfa_stats_d +{ + long num_stmt_anns; + long num_var_anns; + long num_defs; + long num_uses; + long num_phis; + long num_phi_args; + int max_num_phi_args; + long num_vdefs; + long num_vuses; +}; + + +/* State information for find_vars_r. */ +struct walk_state +{ + /* Hash table used to avoid adding the same variable more than once. */ + htab_t vars_found; +}; + + +/* Local functions. */ +static void collect_dfa_stats (struct dfa_stats_d *); +static tree collect_dfa_stats_r (tree *, int *, void *); +static void add_immediate_use (tree, tree); +static tree find_vars_r (tree *, int *, void *); +static void add_referenced_var (tree, struct walk_state *); +static void compute_immediate_uses_for_phi (tree, bool (*)(tree)); +static void compute_immediate_uses_for_stmt (tree, int, bool (*)(tree)); +static void find_hidden_use_vars (tree); +static tree find_hidden_use_vars_r (tree *, int *, void *); + + +/* Global declarations. */ + +/* Array of all variables referenced in the function. */ +varray_type referenced_vars; + + +/*--------------------------------------------------------------------------- + Dataflow analysis (DFA) routines +---------------------------------------------------------------------------*/ +/* Find all the variables referenced in the function. This function + builds the global arrays REFERENCED_VARS and CALL_CLOBBERED_VARS. + + Note that this function does not look for statement operands, it simply + determines what variables are referenced in the program and detects + various attributes for each variable used by alias analysis and the + optimizer. */ + +static void +find_referenced_vars (void) +{ + htab_t vars_found; + basic_block bb; + block_stmt_iterator si; + struct walk_state walk_state; + tree block; + + /* This is the very first pass in preparation for building the SSA + form of the function, so initialize internal data structures now. */ + init_tree_ssa (); + + /* Walk the lexical blocks in the function looking for variables that may + have been used to declare VLAs and for nested functions. Both + constructs create hidden uses of variables. + + Note that at this point we may have multiple blocks hung off + DECL_INITIAL chained through the BLOCK_CHAIN field due to + how inlining works. Egad. */ + block = DECL_INITIAL (current_function_decl); + while (block) + { + find_hidden_use_vars (block); + block = BLOCK_CHAIN (block); + } + + vars_found = htab_create (50, htab_hash_pointer, htab_eq_pointer, NULL); + memset (&walk_state, 0, sizeof (walk_state)); + walk_state.vars_found = vars_found; + + FOR_EACH_BB (bb) + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree *stmt_p = bsi_stmt_ptr (si); + walk_tree (stmt_p, find_vars_r, &walk_state, NULL); + } + + htab_delete (vars_found); +} + +struct tree_opt_pass pass_referenced_vars = +{ + NULL, /* name */ + NULL, /* gate */ + find_referenced_vars, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_gimple_leh | PROP_cfg, /* properties_required */ + PROP_referenced_vars, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + + +/* Compute immediate uses. + + CALC_FOR is an optional function pointer which indicates whether + immediate uses information should be calculated for a given SSA + variable. If NULL, then information is computed for all + variables. + + FLAGS is one of {TDFA_USE_OPS, TDFA_USE_VOPS}. It is used by + compute_immediate_uses_for_stmt to determine whether to look at + virtual and/or real operands while computing def-use chains. */ + +void +compute_immediate_uses (int flags, bool (*calc_for)(tree)) +{ + basic_block bb; + block_stmt_iterator si; + + FOR_EACH_BB (bb) + { + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + compute_immediate_uses_for_phi (phi, calc_for); + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + get_stmt_operands (stmt); + compute_immediate_uses_for_stmt (stmt, flags, calc_for); + } + } +} + + +/* Invalidates dataflow information for a statement STMT. */ + +static void +free_df_for_stmt (tree stmt) +{ + stmt_ann_t ann = stmt_ann (stmt); + + if (ann && ann->df) + { + /* If we have a varray of immediate uses, then go ahead and release + it for re-use. */ + if (ann->df->immediate_uses) + ggc_free (ann->df->immediate_uses); + + /* Similarly for the main dataflow structure. */ + ggc_free (ann->df); + ann->df = NULL; + } +} + + +/* Invalidate dataflow information for the whole function. */ + +void +free_df (void) +{ + basic_block bb; + block_stmt_iterator si; + + FOR_EACH_BB (bb) + { + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + free_df_for_stmt (phi); + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + free_df_for_stmt (stmt); + } + } +} + + +/* Helper for compute_immediate_uses. Check all the USE and/or VUSE + operands in phi node PHI and add a def-use edge between their + defining statement and PHI. CALC_FOR is as in + compute_immediate_uses. + + PHI nodes are easy, we only need to look at their arguments. */ + +static void +compute_immediate_uses_for_phi (tree phi, bool (*calc_for)(tree)) +{ + int i; + +#ifdef ENABLE_CHECKING + if (TREE_CODE (phi) != PHI_NODE) + abort (); +#endif + + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + tree arg = PHI_ARG_DEF (phi, i); + + if (TREE_CODE (arg) == SSA_NAME && (!calc_for || calc_for (arg))) + { + tree imm_rdef_stmt = SSA_NAME_DEF_STMT (PHI_ARG_DEF (phi, i)); + if (!IS_EMPTY_STMT (imm_rdef_stmt)) + add_immediate_use (imm_rdef_stmt, phi); + } + } +} + + +/* Another helper for compute_immediate_uses. Depending on the value + of FLAGS, check all the USE and/or VUSE operands in STMT and add a + def-use edge between their defining statement and STMT. CALC_FOR + is as in compute_immediate_uses. */ + +static void +compute_immediate_uses_for_stmt (tree stmt, int flags, bool (*calc_for)(tree)) +{ + size_t i; + use_optype uses; + vuse_optype vuses; + vdef_optype vdefs; + stmt_ann_t ann; + +#ifdef ENABLE_CHECKING + /* PHI nodes are handled elsewhere. */ + if (TREE_CODE (stmt) == PHI_NODE) + abort (); +#endif + + /* Look at USE_OPS or VUSE_OPS according to FLAGS. */ + ann = stmt_ann (stmt); + if (flags & TDFA_USE_OPS) + { + uses = USE_OPS (ann); + for (i = 0; i < NUM_USES (uses); i++) + { + tree use = USE_OP (uses, i); + tree imm_stmt = SSA_NAME_DEF_STMT (use); + if (!IS_EMPTY_STMT (imm_stmt) && (!calc_for || calc_for (use))) + add_immediate_use (imm_stmt, stmt); + } + } + + if (flags & TDFA_USE_VOPS) + { + vuses = VUSE_OPS (ann); + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree vuse = VUSE_OP (vuses, i); + tree imm_rdef_stmt = SSA_NAME_DEF_STMT (vuse); + if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (vuse))) + add_immediate_use (imm_rdef_stmt, stmt); + } + + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + tree vuse = VDEF_OP (vdefs, i); + tree imm_rdef_stmt = SSA_NAME_DEF_STMT (vuse); + if (!IS_EMPTY_STMT (imm_rdef_stmt) && (!calc_for || calc_for (vuse))) + add_immediate_use (imm_rdef_stmt, stmt); + } + } +} + + +/* Add statement USE_STMT to the list of statements that use definitions + made by STMT. */ + +static void +add_immediate_use (tree stmt, tree use_stmt) +{ + stmt_ann_t ann = get_stmt_ann (stmt); + struct dataflow_d *df; + + df = ann->df; + if (df == NULL) + { + df = ann->df = ggc_alloc (sizeof (struct dataflow_d)); + memset ((void *) df, 0, sizeof (struct dataflow_d)); + df->uses[0] = use_stmt; + return; + } + + if (!df->uses[1]) + { + df->uses[1] = use_stmt; + return; + } + + if (ann->df->immediate_uses == NULL) + VARRAY_TREE_INIT (ann->df->immediate_uses, 4, "immediate_uses"); + + VARRAY_PUSH_TREE (ann->df->immediate_uses, use_stmt); +} + + +/* If the immediate use of USE points to OLD, then redirect it to NEW. */ + +static void +redirect_immediate_use (tree use, tree old, tree new) +{ + tree imm_stmt = SSA_NAME_DEF_STMT (use); + struct dataflow_d *df = get_stmt_ann (imm_stmt)->df; + unsigned int num_uses = num_immediate_uses (df); + unsigned int i; + + for (i = 0; i < num_uses; i++) + { + if (immediate_use (df, i) == old) + { + if (i == 0 || i == 1) + df->uses[i] = new; + else + VARRAY_TREE (df->immediate_uses, i - 2) = new; + } + } +} + + +/* Redirect all immediate uses for operands in OLD so that they point + to NEW. This routine should have no knowledge of how immediate + uses are stored. */ + +void +redirect_immediate_uses (tree old, tree new) +{ + stmt_ann_t ann = get_stmt_ann (old); + use_optype uses = USE_OPS (ann); + vuse_optype vuses = VUSE_OPS (ann); + vdef_optype vdefs = VDEF_OPS (ann); + unsigned int i; + + /* Look at USE_OPS or VUSE_OPS according to FLAGS. */ + for (i = 0; i < NUM_USES (uses); i++) + redirect_immediate_use (USE_OP (uses, i), old, new); + + for (i = 0; i < NUM_VUSES (vuses); i++) + redirect_immediate_use (VUSE_OP (vuses, i), old, new); + + for (i = 0; i < NUM_VDEFS (vdefs); i++) + redirect_immediate_use (VDEF_OP (vdefs, i), old, new); +} + + +/*--------------------------------------------------------------------------- + Manage annotations +---------------------------------------------------------------------------*/ +/* Create a new annotation for a _DECL node T. */ + +var_ann_t +create_var_ann (tree t) +{ + var_ann_t ann; + +#if defined ENABLE_CHECKING + if (t == NULL_TREE + || !DECL_P (t) + || (t->common.ann + && t->common.ann->common.type != VAR_ANN)) + abort (); +#endif + + ann = ggc_alloc (sizeof (*ann)); + memset ((void *) ann, 0, sizeof (*ann)); + + ann->common.type = VAR_ANN; + + t->common.ann = (tree_ann) ann; + + return ann; +} + + +/* Create a new annotation for a statement node T. */ + +stmt_ann_t +create_stmt_ann (tree t) +{ + stmt_ann_t ann; + +#if defined ENABLE_CHECKING + if ((!is_gimple_stmt (t) && !is_essa_node (t)) + || (t->common.ann + && t->common.ann->common.type != STMT_ANN)) + abort (); +#endif + + ann = ggc_alloc (sizeof (*ann)); + memset ((void *) ann, 0, sizeof (*ann)); + + ann->common.type = STMT_ANN; + + /* Since we just created the annotation, mark the statement modified. */ + ann->modified = true; + + t->common.ann = (tree_ann) ann; + + return ann; +} + + +/* Create a new annotation for an SSA name T. */ + +ssa_name_ann_t +create_ssa_name_ann (tree t) +{ + ssa_name_ann_t ann; + +#if defined ENABLE_CHECKING + if (t == NULL_TREE + || (t->common.ann + && t->common.ann->common.type != SSA_NAME_ANN)) + abort (); +#endif + + ann = ggc_alloc (sizeof (*ann)); + memset ((void *) ann, 0, sizeof (*ann)); + + ann->common.type = SSA_NAME_ANN; + t->common.ann = (tree_ann) ann; + + return ann; +} + + + +/*--------------------------------------------------------------------------- + Debugging functions +---------------------------------------------------------------------------*/ +/* Dump the list of all the referenced variables in the current function to + FILE. */ + +void +dump_referenced_vars (FILE *file) +{ + size_t i; + + fprintf (file, "\nReferenced variables in %s: %u\n\n", + get_name (current_function_decl), (unsigned) num_referenced_vars); + + for (i = 0; i < num_referenced_vars; i++) + { + tree var = referenced_var (i); + fprintf (file, "Variable: "); + dump_variable (file, var); + fprintf (file, "\n"); + } +} + + +/* Dump the list of all the referenced variables to stderr. */ + +void +debug_referenced_vars (void) +{ + dump_referenced_vars (stderr); +} + + +/* Dump variable VAR and its may-aliases to FILE. */ + +void +dump_variable (FILE *file, tree var) +{ + var_ann_t ann; + + if (var == NULL_TREE) + { + fprintf (file, ""); + return; + } + + print_generic_expr (file, var, dump_flags); + + if (TREE_CODE (var) == SSA_NAME) + var = SSA_NAME_VAR (var); + + ann = var_ann (var); + + fprintf (file, ", UID %u", (unsigned) ann->uid); + + if (ann->has_hidden_use) + fprintf (file, ", has hidden uses"); + + if (ann->type_mem_tag) + { + fprintf (file, ", type memory tag: "); + print_generic_expr (file, ann->type_mem_tag, dump_flags); + } + + if (ann->is_alias_tag) + fprintf (file, ", is an alias tag"); + + if (needs_to_live_in_memory (var)) + fprintf (file, ", is %s", TREE_STATIC (var) ? "static" : "global"); + + if (is_call_clobbered (var)) + fprintf (file, ", call clobbered"); + + if (ann->default_def) + { + fprintf (file, ", default def: "); + print_generic_expr (file, ann->default_def, dump_flags); + } + + if (ann->may_aliases) + { + fprintf (file, ", may aliases: "); + dump_may_aliases_for (file, var); + } + + fprintf (file, "\n"); +} + + +/* Dump variable VAR and its may-aliases to stderr. */ + +void +debug_variable (tree var) +{ + dump_variable (stderr, var); +} + + +/* Dump def-use edges on FILE. */ + +void +dump_immediate_uses (FILE *file) +{ + basic_block bb; + block_stmt_iterator si; + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + fprintf (file, "\nDef-use edges for function %s\n", funcname); + + FOR_EACH_BB (bb) + { + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + dump_immediate_uses_for (file, phi); + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + dump_immediate_uses_for (file, bsi_stmt (si)); + } + + fprintf (file, "\n"); +} + + +/* Dump def-use edges on stderr. */ + +void +debug_immediate_uses (void) +{ + dump_immediate_uses (stderr); +} + + +/* Dump all immediate uses for STMT on FILE. */ + +void +dump_immediate_uses_for (FILE *file, tree stmt) +{ + dataflow_t df = get_immediate_uses (stmt); + int num_imm_uses = num_immediate_uses (df); + + if (num_imm_uses > 0) + { + int i; + + fprintf (file, "-> "); + print_generic_stmt (file, stmt, TDF_SLIM); + fprintf (file, "\n"); + + for (i = 0; i < num_imm_uses; i++) + { + fprintf (file, "\t"); + print_generic_stmt (file, immediate_use (df, i), TDF_SLIM); + fprintf (file, "\n"); + } + + fprintf (file, "\n"); + } +} + + +/* Dump immediate uses for STMT on stderr. */ + +void +debug_immediate_uses_for (tree stmt) +{ + dump_immediate_uses_for (stderr, stmt); +} + + +/* Dump various DFA statistics to FILE. */ + +void +dump_dfa_stats (FILE *file) +{ + struct dfa_stats_d dfa_stats; + + unsigned long size, total = 0; + const char * const fmt_str = "%-30s%-13s%12s\n"; + const char * const fmt_str_1 = "%-30s%13lu%11lu%c\n"; + const char * const fmt_str_3 = "%-43s%11lu%c\n"; + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + collect_dfa_stats (&dfa_stats); + + fprintf (file, "\nDFA Statistics for %s\n\n", funcname); + + fprintf (file, "---------------------------------------------------------\n"); + fprintf (file, fmt_str, "", " Number of ", "Memory"); + fprintf (file, fmt_str, "", " instances ", "used "); + fprintf (file, "---------------------------------------------------------\n"); + + size = num_referenced_vars * sizeof (tree); + total += size; + fprintf (file, fmt_str_1, "Referenced variables", num_referenced_vars, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_stmt_anns * sizeof (struct stmt_ann_d); + total += size; + fprintf (file, fmt_str_1, "Statements annotated", dfa_stats.num_stmt_anns, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_var_anns * sizeof (struct var_ann_d); + total += size; + fprintf (file, fmt_str_1, "Variables annotated", dfa_stats.num_var_anns, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_uses * sizeof (tree *); + total += size; + fprintf (file, fmt_str_1, "USE operands", dfa_stats.num_uses, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_defs * sizeof (tree *); + total += size; + fprintf (file, fmt_str_1, "DEF operands", dfa_stats.num_defs, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_vuses * sizeof (tree *); + total += size; + fprintf (file, fmt_str_1, "VUSE operands", dfa_stats.num_vuses, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_vdefs * sizeof (tree *); + total += size; + fprintf (file, fmt_str_1, "VDEF operands", dfa_stats.num_vdefs, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_phis * sizeof (struct tree_phi_node); + total += size; + fprintf (file, fmt_str_1, "PHI nodes", dfa_stats.num_phis, + SCALE (size), LABEL (size)); + + size = dfa_stats.num_phi_args * sizeof (struct phi_arg_d); + total += size; + fprintf (file, fmt_str_1, "PHI arguments", dfa_stats.num_phi_args, + SCALE (size), LABEL (size)); + + fprintf (file, "---------------------------------------------------------\n"); + fprintf (file, fmt_str_3, "Total memory used by DFA/SSA data", SCALE (total), + LABEL (total)); + fprintf (file, "---------------------------------------------------------\n"); + fprintf (file, "\n"); + + if (dfa_stats.num_phis) + fprintf (file, "Average number of arguments per PHI node: %.1f (max: %d)\n", + (float) dfa_stats.num_phi_args / (float) dfa_stats.num_phis, + dfa_stats.max_num_phi_args); + + fprintf (file, "\n"); +} + + +/* Dump DFA statistics on stderr. */ + +void +debug_dfa_stats (void) +{ + dump_dfa_stats (stderr); +} + + +/* Collect DFA statistics and store them in the structure pointed by + DFA_STATS_P. */ + +static void +collect_dfa_stats (struct dfa_stats_d *dfa_stats_p) +{ + htab_t htab; + basic_block bb; + block_stmt_iterator i; + + if (dfa_stats_p == NULL) + abort (); + + memset ((void *)dfa_stats_p, 0, sizeof (struct dfa_stats_d)); + + /* Walk all the trees in the function counting references. Start at + basic block 0, but don't stop at block boundaries. */ + htab = htab_create (30, htab_hash_pointer, htab_eq_pointer, NULL); + + for (i = bsi_start (BASIC_BLOCK (0)); !bsi_end_p (i); bsi_next (&i)) + walk_tree (bsi_stmt_ptr (i), collect_dfa_stats_r, (void *) dfa_stats_p, + (void *) htab); + + htab_delete (htab); + + FOR_EACH_BB (bb) + { + tree phi; + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + dfa_stats_p->num_phis++; + dfa_stats_p->num_phi_args += PHI_NUM_ARGS (phi); + if (PHI_NUM_ARGS (phi) > dfa_stats_p->max_num_phi_args) + dfa_stats_p->max_num_phi_args = PHI_NUM_ARGS (phi); + } + } +} + + +/* Callback for walk_tree to collect DFA statistics for a tree and its + children. */ + +static tree +collect_dfa_stats_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) +{ + tree t = *tp; + struct dfa_stats_d *dfa_stats_p = (struct dfa_stats_d *)data; + + if (t->common.ann) + { + switch (ann_type (t->common.ann)) + { + case STMT_ANN: + { + stmt_ann_t ann = (stmt_ann_t) t->common.ann; + dfa_stats_p->num_stmt_anns++; + dfa_stats_p->num_defs += NUM_DEFS (DEF_OPS (ann)); + dfa_stats_p->num_uses += NUM_USES (USE_OPS (ann)); + dfa_stats_p->num_vdefs += NUM_VDEFS (VDEF_OPS (ann)); + dfa_stats_p->num_vuses += NUM_VUSES (VUSE_OPS (ann)); + break; + } + + case VAR_ANN: + dfa_stats_p->num_var_anns++; + break; + + default: + break; + } + } + + return NULL; +} + + +/*--------------------------------------------------------------------------- + Miscellaneous helpers +---------------------------------------------------------------------------*/ +/* Callback for walk_tree. Used to collect variables referenced in + the function. */ + +static tree +find_vars_r (tree *tp, int *walk_subtrees, void *data) +{ + tree t = *tp; + struct walk_state *walk_state = (struct walk_state *)data; + + if (SSA_VAR_P (t)) + { + /* If T is a regular variable that the optimizers are interested + in, add it to the list of variables. */ + add_referenced_var (t, walk_state); + } + else if (DECL_P (t) + || TYPE_P (t) + || TREE_CODE_CLASS (TREE_CODE (t)) == 'c') + { + /* Type, _DECL and constant nodes have no interesting children. + Ignore them. */ + *walk_subtrees = 0; + } + + + return NULL_TREE; +} + + +/* Add VAR to the list of dereferenced variables. + + WALK_STATE contains a hash table used to avoid adding the same + variable more than once. Note that this function assumes that + VAR is a valid SSA variable. If WALK_STATE is NULL, no + duplicate checking is done. */ + +static void +add_referenced_var (tree var, struct walk_state *walk_state) +{ + void **slot; + var_ann_t v_ann; + + v_ann = get_var_ann (var); + + if (walk_state) + slot = htab_find_slot (walk_state->vars_found, (void *) var, INSERT); + else + slot = NULL; + + if (slot == NULL || *slot == NULL) + { + /* This is the first time we find this variable, add it to the + REFERENCED_VARS array and annotate it with attributes that are + intrinsic to the variable. */ + if (slot) + *slot = (void *) var; + v_ann->uid = num_referenced_vars; + VARRAY_PUSH_TREE (referenced_vars, var); + + /* Global and static variables are call-clobbered, always. */ + if (needs_to_live_in_memory (var)) + mark_call_clobbered (var); + + /* DECL_NONLOCAL variables should not be removed, as they are needed + to emit nested functions. */ + if (DECL_NONLOCAL (var)) + v_ann->used = 1; + } +} + + +/* Return the virtual variable associated to the non-scalar variable VAR. */ + +tree +get_virtual_var (tree var) +{ + enum tree_code code; + + STRIP_NOPS (var); + + if (TREE_CODE (var) == SSA_NAME) + var = SSA_NAME_VAR (var); + + code = TREE_CODE (var); + + while (code == ARRAY_REF + || code == COMPONENT_REF + || code == REALPART_EXPR + || code == IMAGPART_EXPR) + { + var = TREE_OPERAND (var, 0); + code = TREE_CODE (var); + } + +#ifdef ENABLE_CHECKING + /* Treating GIMPLE registers as virtual variables makes no sense. + Also complain if we couldn't extract a _DECL out of the original + expression. */ + if (!SSA_VAR_P (var) + || is_gimple_reg (var)) + abort (); +#endif + + return var; +} + + +/* Mark variables in BLOCK that have hidden uses. A hidden use can + occur due to VLA declarations or nested functions. */ + +static void +find_hidden_use_vars (tree block) +{ + tree sub, decl, tem; + + /* Check all the arrays declared in the block for VLAs. + While scanning the block's variables, also see if there is + a nested function at this scope. */ + for (decl = BLOCK_VARS (block); decl; decl = TREE_CHAIN (decl)) + { + int inside_vla = 0; + walk_tree (&decl, find_hidden_use_vars_r, &inside_vla, NULL); + } + + /* Now repeat the search in any sub-blocks. */ + for (sub = BLOCK_SUBBLOCKS (block); sub; sub = TREE_CHAIN (sub)) + find_hidden_use_vars (sub); + + /* A VLA parameter may use a variable which as set from another + parameter to declare the size of the VLA. We need to mark the + variable as having a hidden use since it is used to declare the + VLA parameter and that declaration is not seen by the SSA code. + + Note get_pending_sizes clears the PENDING_SIZES chain, so we + must restore it. */ + tem = get_pending_sizes (); + put_pending_sizes (tem); + for (; tem; tem = TREE_CHAIN (tem)) + { + int inside_vla = 1; + walk_tree (&TREE_VALUE (tem), find_hidden_use_vars_r, &inside_vla, NULL); + } +} + + +/* Callback for walk_tree used by find_hidden_use_vars to analyze each + variable in a lexical block. If the variable's size has a variable + size, then mark all objects needed to compute the variable's size + as having hidden uses. */ + +static tree +find_hidden_use_vars_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + int *inside_vla = (int *) data; + + /* We need to look for hidden uses due to VLAs in variable + definitions. We originally used to look for these hidden + uses in the variable's type, but that's unreliable if the + type's size contains a SAVE_EXPR for a different function + context than the variable is used within. */ + if (SSA_VAR_P (*tp) + && ((DECL_SIZE (*tp) + && ! really_constant_p (DECL_SIZE (*tp))) + || (DECL_SIZE_UNIT (*tp) + && ! really_constant_p (DECL_SIZE_UNIT (*tp))))) + { + int save = *inside_vla; + + *inside_vla = 1; + walk_tree (&DECL_SIZE (*tp), find_hidden_use_vars_r, inside_vla, NULL); + walk_tree (&DECL_SIZE_UNIT (*tp), find_hidden_use_vars_r, + inside_vla, NULL); + *inside_vla = save; + } + else if (*inside_vla && SSA_VAR_P (*tp)) + set_has_hidden_use (*tp); + + return NULL_TREE; +} + + +/* Add a temporary variable to REFERENCED_VARS. This is similar to + add_referenced_var, but is used by passes that need to add new temps to + the REFERENCED_VARS array after the program has been scanned for + variables. The variable will just receive a new UID and be added + to the REFERENCED_VARS array without checking for duplicates. */ + +void +add_referenced_tmp_var (tree var) +{ + add_referenced_var (var, NULL); +} + + +/* Return true if VDEFS_AFTER contains fewer entries than VDEFS_BEFORE. + Note that this assumes that both varrays are VDEF operands for the same + statement. */ + +static inline bool +vdefs_disappeared_p (vdef_optype vdefs_before, vdef_optype vdefs_after) +{ + /* If there was nothing before, nothing could've disappeared. */ + if (vdefs_before == NULL) + return false; + + /* All/some of them gone. */ + if (vdefs_after == NULL + || NUM_VDEFS (vdefs_before) > NUM_VDEFS (vdefs_after)) + return true; + + return false; +} + + +/* Add all the non-SSA variables found in STMT's operands to the bitmap + VARS_TO_RENAME. */ + +void +mark_new_vars_to_rename (tree stmt, bitmap vars_to_rename) +{ + def_optype defs; + use_optype uses; + vdef_optype vdefs; + vuse_optype vuses; + size_t i; + bitmap vars_in_vops_to_rename; + bool found_exposed_symbol = false; + vdef_optype vdefs_before, vdefs_after; + stmt_ann_t ann; + + vars_in_vops_to_rename = BITMAP_XMALLOC (); + + /* Before re-scanning the statement for operands, mark the existing + virtual operands to be renamed again. We do this because when new + symbols are exposed, the virtual operands that were here before due to + aliasing will probably be removed by the call to get_stmt_operand. + Therefore, we need to flag them to be renamed beforehand. + + We flag them in a separate bitmap because we don't really want to + rename them if there are not any newly exposed symbols in the + statement operands. */ + ann = stmt_ann (stmt); + vdefs_before = vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + tree var = VDEF_RESULT (vdefs, i); + if (!DECL_P (var)) + var = SSA_NAME_VAR (var); + bitmap_set_bit (vars_in_vops_to_rename, var_ann (var)->uid); + } + + vuses = VUSE_OPS (ann); + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree var = VUSE_OP (vuses, i); + if (!DECL_P (var)) + var = SSA_NAME_VAR (var); + bitmap_set_bit (vars_in_vops_to_rename, var_ann (var)->uid); + } + + /* Now force an operand re-scan on the statement and mark any newly + exposed variables. */ + modify_stmt (stmt); + get_stmt_operands (stmt); + + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree var = DEF_OP (defs, i); + if (DECL_P (var)) + { + found_exposed_symbol = true; + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + } + + uses = USE_OPS (ann); + for (i = 0; i < NUM_USES (uses); i++) + { + tree var = USE_OP (uses, i); + if (DECL_P (var)) + { + found_exposed_symbol = true; + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + } + + vdefs_after = vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + tree var = VDEF_RESULT (vdefs, i); + if (DECL_P (var)) + { + found_exposed_symbol = true; + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + } + + vuses = VUSE_OPS (ann); + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree var = VUSE_OP (vuses, i); + if (DECL_P (var)) + { + found_exposed_symbol = true; + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + } + + /* If we found any newly exposed symbols, or if there are fewer VDEF + operands in the statement, add the variables we had set in + VARS_IN_VOPS_TO_RENAME to VARS_TO_RENAME. We need to check for + vanishing VDEFs because in those cases, the names that were formerly + generated by this statement are not going to be available anymore. */ + if (found_exposed_symbol + || vdefs_disappeared_p (vdefs_before, vdefs_after)) + bitmap_a_or_b (vars_to_rename, vars_to_rename, vars_in_vops_to_rename); + + BITMAP_XFREE (vars_in_vops_to_rename); +} diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c index e0dd6f1e437..55ab9389b0b 100644 --- a/gcc/tree-dump.c +++ b/gcc/tree-dump.c @@ -36,6 +36,7 @@ static void dequeue_and_dump (dump_info_p); static void dump_new_line (dump_info_p); static void dump_maybe_newline (dump_info_p); static void dump_string_field (dump_info_p, const char *, const char *); +static void dump_enable_all (int); /* Add T to the end of the queue of nodes to dump. Returns the index assigned to T. */ @@ -573,10 +574,6 @@ dequeue_and_dump (dump_info_p di) dump_child ("init", TREE_OPERAND (t, 3)); break; - case EXPR_WITH_FILE_LOCATION: - dump_child ("expr", EXPR_WFL_NODE (t)); - break; - default: /* There are no additional fields to print. */ break; @@ -638,8 +635,8 @@ dump_node (tree t, int flags, FILE *stream) /* Define a tree dump switch. */ struct dump_file_info { - const char *const suffix; /* suffix to give output file. */ - const char *const swtch; /* command line switch */ + const char *suffix; /* suffix to give output file. */ + const char *swtch; /* command line switch */ int flags; /* user flags */ int state; /* state of play */ }; @@ -648,13 +645,23 @@ struct dump_file_info TREE_DUMP_INDEX enumeration in tree.h */ static struct dump_file_info dump_files[TDI_end] = { + {NULL, NULL, 0, 0}, {".tu", "translation-unit", 0, 0}, {".class", "class-hierarchy", 0, 0}, {".original", "tree-original", 0, 0}, - {".optimized", "tree-optimized", 0, 0}, + {".generic", "tree-generic", 0, 0}, + {".nested", "tree-nested", 0, 0}, {".inlined", "tree-inlined", 0, 0}, + {".vcg", "tree-vcg", 0, 0}, + {".xml", "call-graph", 0, 0}, + {NULL, "tree-all", 0, 0}, }; +/* Dynamically registered tree dump files and switches. */ +static struct dump_file_info *extra_dump_files; +static size_t extra_dump_files_in_use; +static size_t extra_dump_files_alloced; + /* Define a name->number mapping for a dump flag value. */ struct dump_option_value_info { @@ -668,10 +675,54 @@ static const struct dump_option_value_info dump_options[] = { {"address", TDF_ADDRESS}, {"slim", TDF_SLIM}, - {"all", ~0}, + {"raw", TDF_RAW}, + {"details", TDF_DETAILS}, + {"stats", TDF_STATS}, + {"blocks", TDF_BLOCKS}, + {"vops", TDF_VOPS}, + {"lineno", TDF_LINENO}, + {"uid", TDF_UID}, + {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)}, {NULL, 0} }; +unsigned int +dump_register (const char *suffix, const char *swtch) +{ + size_t this = extra_dump_files_in_use++; + + if (this >= extra_dump_files_alloced) + { + if (extra_dump_files_alloced == 0) + extra_dump_files_alloced = 32; + else + extra_dump_files_alloced *= 2; + extra_dump_files = xrealloc (extra_dump_files, + sizeof (struct dump_file_info) + * extra_dump_files_alloced); + } + + memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info)); + extra_dump_files[this].suffix = suffix; + extra_dump_files[this].swtch = swtch; + + return this + TDI_end; +} + +/* Return the dump_file_info for the given phase. */ + +static struct dump_file_info * +get_dump_file_info (enum tree_dump_index phase) +{ + if (phase < TDI_end) + return &dump_files[phase]; + else if (phase - TDI_end >= extra_dump_files_in_use) + abort (); + else + return extra_dump_files + (phase - TDI_end); +} + + /* Begin a tree dump for PHASE. Stores any user supplied flag in *FLAG_PTR and returns a stream to write to. If the dump is not enabled, returns NULL. @@ -682,19 +733,29 @@ dump_begin (enum tree_dump_index phase, int *flag_ptr) { FILE *stream; char *name; + char dump_id[10]; + struct dump_file_info *dfi; - if (!dump_files[phase].state) + if (phase == TDI_none) return NULL; - name = concat (dump_base_name, dump_files[phase].suffix, NULL); - stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a"); + dfi = get_dump_file_info (phase); + if (dfi->state == 0) + return NULL; + + if (snprintf (dump_id, sizeof (dump_id), ".t%02d", phase) < 0) + dump_id[0] = '\0'; + + name = concat (dump_base_name, dump_id, dfi->suffix, NULL); + stream = fopen (name, dfi->state < 0 ? "w" : "a"); if (!stream) - error ("could not open dump file `%s'", name); + error ("could not open dump file `%s': %s", name, strerror (errno)); else - dump_files[phase].state = 1; + dfi->state = 1; free (name); + if (flag_ptr) - *flag_ptr = dump_files[phase].flags; + *flag_ptr = dfi->flags; return stream; } @@ -704,7 +765,8 @@ dump_begin (enum tree_dump_index phase, int *flag_ptr) int dump_enabled_p (enum tree_dump_index phase) { - return dump_files[phase].state; + struct dump_file_info *dfi = get_dump_file_info (phase); + return dfi->state; } /* Returns the switch name of PHASE. */ @@ -712,7 +774,8 @@ dump_enabled_p (enum tree_dump_index phase) const char * dump_flag_name (enum tree_dump_index phase) { - return dump_files[phase].swtch; + struct dump_file_info *dfi = get_dump_file_info (phase); + return dfi->swtch; } /* Finish a tree dump for PHASE. STREAM is the stream created by @@ -724,52 +787,110 @@ dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream) fclose (stream); } +/* Enable all tree dumps. */ + +static void +dump_enable_all (int flags) +{ + size_t i; + + for (i = TDI_none + 1; i < (size_t) TDI_end; i++) + { + dump_files[i].state = -1; + dump_files[i].flags = flags; + } + + for (i = 0; i < extra_dump_files_in_use; i++) + { + extra_dump_files[i].state = -1; + extra_dump_files[i].flags = flags; + } + + /* FIXME -fdump-call-graph is broken. */ + dump_files[TDI_xml].state = 0; + dump_files[TDI_xml].flags = 0; +} + /* Parse ARG as a dump switch. Return nonzero if it is, and store the relevant details in the dump_files array. */ -int -dump_switch_p (const char *arg) +static int +dump_switch_p_1 (const char *arg, struct dump_file_info *dfi) { - unsigned ix; const char *option_value; + const char *ptr; + int flags; - for (ix = 0; ix != TDI_end; ix++) - if ((option_value = skip_leading_substring (arg, dump_files[ix].swtch))) - { - const char *ptr = option_value; - int flags = 0; + option_value = skip_leading_substring (arg, dfi->swtch); + if (!option_value) + return 0; - while (*ptr) + ptr = option_value; + flags = 0; + + while (*ptr) + { + const struct dump_option_value_info *option_ptr; + const char *end_ptr; + unsigned length; + + while (*ptr == '-') + ptr++; + end_ptr = strchr (ptr, '-'); + if (!end_ptr) + end_ptr = ptr + strlen (ptr); + length = end_ptr - ptr; + + for (option_ptr = dump_options; option_ptr->name; option_ptr++) + if (strlen (option_ptr->name) == length + && !memcmp (option_ptr->name, ptr, length)) { - const struct dump_option_value_info *option_ptr; - const char *end_ptr; - unsigned length; - - while (*ptr == '-') - ptr++; - end_ptr = strchr (ptr, '-'); - if (!end_ptr) - end_ptr = ptr + strlen (ptr); - length = end_ptr - ptr; - - for (option_ptr = dump_options; option_ptr->name; - option_ptr++) - if (strlen (option_ptr->name) == length - && !memcmp (option_ptr->name, ptr, length)) - { - flags |= option_ptr->value; - goto found; - } - warning ("ignoring unknown option `%.*s' in `-fdump-%s'", - length, ptr, dump_files[ix].swtch); - found:; - ptr = end_ptr; + flags |= option_ptr->value; + goto found; } + warning ("ignoring unknown option `%.*s' in `-fdump-%s'", + length, ptr, dfi->swtch); + found:; + ptr = end_ptr; + } + + dfi->state = -1; + dfi->flags = flags; + + /* Process -fdump-tree-all by enabling all the known dumps. */ + if (dfi->suffix == NULL) + dump_enable_all (flags); + + return 1; +} - dump_files[ix].state = -1; - dump_files[ix].flags = flags; +int +dump_switch_p (const char *arg) +{ + size_t i; + int any = 0; + + for (i = TDI_none + 1; i != TDI_end; i++) + any |= dump_switch_p_1 (arg, &dump_files[i]); + + for (i = 0; i < extra_dump_files_in_use; i++) + any |= dump_switch_p_1 (arg, &extra_dump_files[i]); + + return any; +} - return 1; - } - return 0; +/* Dump FUNCTION_DECL FN as tree dump PHASE. */ + +void +dump_function (enum tree_dump_index phase, tree fn) +{ + FILE *stream; + int flags; + + stream = dump_begin (phase, &flags); + if (stream) + { + dump_function_to_file (fn, stream, flags); + dump_end (phase, stream); + } } diff --git a/gcc/tree-dump.h b/gcc/tree-dump.h index 3f6497b23f8..974362b6225 100644 --- a/gcc/tree-dump.h +++ b/gcc/tree-dump.h @@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #ifndef GCC_TREE_DUMP_H #define GCC_TREE_DUMP_H +#include "splay-tree.h" + /* Flags used with queue functions. */ #define DUMP_NONE 0 #define DUMP_BINFO 1 @@ -84,5 +86,9 @@ extern void dump_stmt (dump_info_p, tree); extern void dump_next_stmt (dump_info_p, tree); extern void queue_and_dump_index (dump_info_p, const char *, tree, int); extern void queue_and_dump_type (dump_info_p, tree); +extern void dump_function (enum tree_dump_index, tree); +extern void dump_function_to_file (tree, FILE *, int); + +extern unsigned int dump_register (const char *, const char *); #endif /* ! GCC_TREE_DUMP_H */ diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c new file mode 100644 index 00000000000..1f37ac6789c --- /dev/null +++ b/gcc/tree-eh.c @@ -0,0 +1,1756 @@ +/* Exception handling semantics and decomposition for trees. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "flags.h" +#include "function.h" +#include "except.h" +#include "tree-flow.h" +#include "tree-dump.h" +#include "tree-inline.h" +#include "tree-iterator.h" +#include "tree-pass.h" +#include "timevar.h" +#include "langhooks.h" +#include "ggc.h" + +/* HACK */ +extern int using_eh_for_cleanups_p; + +/* Misc functions used in this file. */ + +/* Compare and hash for any structure which begins with a canonical + pointer. Assumes all pointers are interchangable, which is sort + of already assumed by gcc elsewhere IIRC. */ + +static int +struct_ptr_eq (const void *a, const void *b) +{ + const void * const * x = a; + const void * const * y = b; + return *x == *y; +} + +static hashval_t +struct_ptr_hash (const void *a) +{ + const void * const * x = a; + return (size_t)*x >> 4; +} + + +/* Remember and lookup EH region data for arbitrary statements. + Really this means any statement that could_throw_p. We could + stuff this information into the stmt_ann data structure, but: + + (1) We absolutely rely on this information being kept until + we get to rtl. Once we're done with lowering here, if we lose + the information there's no way to recover it! + + (2) There are many more statements that *cannot* throw as + compared to those that can. We should be saving some amount + of space by only allocating memory for those that can throw. */ + +struct throw_stmt_node GTY(()) +{ + tree stmt; + int region_nr; +}; + +static GTY((param_is (struct throw_stmt_node))) htab_t throw_stmt_table; + +static void +record_stmt_eh_region (struct eh_region *region, tree t) +{ + struct throw_stmt_node *n; + void **slot; + + if (!region) + return; + + n = ggc_alloc (sizeof (*n)); + n->stmt = t; + n->region_nr = get_eh_region_number (region); + + slot = htab_find_slot (throw_stmt_table, n, INSERT); + if (*slot) + abort (); + *slot = n; +} + +void +add_stmt_to_eh_region (tree t, int num) +{ + struct throw_stmt_node *n; + void **slot; + + if (num < 0) + abort (); + + n = ggc_alloc (sizeof (*n)); + n->stmt = t; + n->region_nr = num; + + slot = htab_find_slot (throw_stmt_table, n, INSERT); + if (*slot) + abort (); + *slot = n; +} + +int +lookup_stmt_eh_region (tree t) +{ + struct throw_stmt_node *p, n; + + if (!throw_stmt_table) + return -2; + + n.stmt = t; + p = htab_find (throw_stmt_table, &n); + + return (p ? p->region_nr : -1); +} + + + +/* First pass of EH node decomposition. Build up a tree of TRY_FINALLY_EXPR + nodes and LABEL_DECL nodes. We will use this during the second phase to + determine if a goto leaves the body of a TRY_FINALLY_EXPR node. */ + +struct finally_tree_node +{ + tree child, parent; +}; + +/* Note that this table is *not* marked GTY. It is short-lived. */ +static htab_t finally_tree; + +static void +record_in_finally_tree (tree child, tree parent) +{ + struct finally_tree_node *n; + void **slot; + + n = xmalloc (sizeof (*n)); + n->child = child; + n->parent = parent; + + slot = htab_find_slot (finally_tree, n, INSERT); + if (*slot) + abort (); + *slot = n; +} + +static void +collect_finally_tree (tree t, tree region) +{ + tailrecurse: + switch (TREE_CODE (t)) + { + case LABEL_EXPR: + record_in_finally_tree (LABEL_EXPR_LABEL (t), region); + break; + + case TRY_FINALLY_EXPR: + record_in_finally_tree (t, region); + collect_finally_tree (TREE_OPERAND (t, 0), t); + t = TREE_OPERAND (t, 1); + goto tailrecurse; + + case TRY_CATCH_EXPR: + collect_finally_tree (TREE_OPERAND (t, 0), region); + t = TREE_OPERAND (t, 1); + goto tailrecurse; + + case CATCH_EXPR: + t = CATCH_BODY (t); + goto tailrecurse; + + case EH_FILTER_EXPR: + t = EH_FILTER_FAILURE (t); + goto tailrecurse; + + case STATEMENT_LIST: + { + tree_stmt_iterator i; + for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) + collect_finally_tree (tsi_stmt (i), region); + } + break; + + default: + /* A type, a decl, or some kind of statement that we're not + interested in. Don't walk them. */ + break; + } +} + +/* Use the finally tree to determine if a jump from START to TARGET + would leave the try_finally node that START lives in. */ + +static bool +outside_finally_tree (tree start, tree target) +{ + struct finally_tree_node n, *p; + + do + { + n.child = start; + p = htab_find (finally_tree, &n); + if (!p) + return true; + start = p->parent; + } + while (start != target); + + return false; +} + +/* Second pass of EH node decomposition. Actually transform the TRY_FINALLY + and TRY_CATCH nodes into a set of gotos, magic labels, and eh regions. + The eh region creation is straight-forward, but frobbing all the gotos + and such into shape isn't. */ + +/* State of the world while lowering. */ + +struct leh_state +{ + /* What's "current" while constructing the eh region tree. These + correspond to variables of the same name in cfun->eh, which we + don't have easy access to. */ + struct eh_region *cur_region; + struct eh_region *prev_try; + + /* Processing of TRY_FINALLY requires a bit more state. This is + split out into a separate structure so that we don't have to + copy so much when processing other nodes. */ + struct leh_tf_state *tf; +}; + +struct leh_tf_state +{ + /* Pointer to the TRY_FINALLY node under discussion. The try_finally_expr + is the original TRY_FINALLY_EXPR. We need to retain this so that + outside_finally_tree can reliably reference the tree used in the + collect_finally_tree data structures. */ + tree try_finally_expr; + tree *top_p; + + /* The state outside this try_finally node. */ + struct leh_state *outer; + + /* The exception region created for it. */ + struct eh_region *region; + + /* The GOTO_QUEUE is is an array of GOTO_EXPR and RETURN_EXPR statements + that are seen to escape this TRY_FINALLY_EXPR node. */ + struct goto_queue_node { + tree stmt; + tree repl_stmt; + tree cont_stmt; + int index; + } *goto_queue; + size_t goto_queue_size; + size_t goto_queue_active; + + /* The set of unique labels seen as entries in the goto queue. */ + varray_type dest_array; + + /* A label to be added at the end of the completed transformed + sequence. It will be set if may_fallthru was true *at one time*, + though subsequent transformations may have cleared that flag. */ + tree fallthru_label; + + /* A label that has been registered with except.c to be the + landing pad for this try block. */ + tree eh_label; + + /* True if it is possible to fall out the bottom of the try block. + Cleared if the fallthru is converted to a goto. */ + bool may_fallthru; + + /* True if any entry in goto_queue is a RETURN_EXPR. */ + bool may_return; + + /* True if the finally block can receive an exception edge. + Cleared if the exception case is handled by code duplication. */ + bool may_throw; +}; + +static void lower_eh_filter (struct leh_state *, tree *); +static void lower_eh_constructs_1 (struct leh_state *, tree *); + +/* Comparison function for qsort/bsearch. We're interested in + searching goto queue elements for source statements. */ + +static int +goto_queue_cmp (const void *x, const void *y) +{ + tree a = ((const struct goto_queue_node *)x)->stmt; + tree b = ((const struct goto_queue_node *)y)->stmt; + return (a == b ? 0 : a < b ? -1 : 1); +} + +/* Search for STMT in the goto queue. Return the replacement, + or null if the statement isn't in the queue. */ + +static tree +find_goto_replacement (struct leh_tf_state *tf, tree stmt) +{ + struct goto_queue_node tmp, *ret; + tmp.stmt = stmt; + ret = bsearch (&tmp, tf->goto_queue, tf->goto_queue_active, + sizeof (struct goto_queue_node), goto_queue_cmp); + return (ret ? ret->repl_stmt : NULL); +} + +/* A subroutine of replace_goto_queue_1. Handles the sub-clauses of a + lowered COND_EXPR. If, by chance, the replacement is a simple goto, + then we can just splat it in, otherwise we add the new stmts immediately + after the COND_EXPR and redirect. */ + +static void +replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf, + tree_stmt_iterator *tsi) +{ + tree new, one, label; + + new = find_goto_replacement (tf, *tp); + if (!new) + return; + + one = expr_only (new); + if (one && TREE_CODE (one) == GOTO_EXPR) + { + *tp = one; + return; + } + + label = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + *tp = build_and_jump (&LABEL_EXPR_LABEL (label)); + + tsi_link_after (tsi, label, TSI_CONTINUE_LINKING); + tsi_link_after (tsi, new, TSI_CONTINUE_LINKING); +} + +/* The real work of replace_goto_queue. Returns with TSI updated to + point to the next statement. */ + +static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *); + +static void +replace_goto_queue_1 (tree t, struct leh_tf_state *tf, tree_stmt_iterator *tsi) +{ + switch (TREE_CODE (t)) + { + case GOTO_EXPR: + case RETURN_EXPR: + t = find_goto_replacement (tf, t); + if (t) + { + tsi_link_before (tsi, t, TSI_SAME_STMT); + tsi_delink (tsi); + return; + } + break; + + case COND_EXPR: + replace_goto_queue_cond_clause (&COND_EXPR_THEN (t), tf, tsi); + replace_goto_queue_cond_clause (&COND_EXPR_ELSE (t), tf, tsi); + break; + + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + replace_goto_queue_stmt_list (TREE_OPERAND (t, 0), tf); + replace_goto_queue_stmt_list (TREE_OPERAND (t, 1), tf); + break; + case CATCH_EXPR: + replace_goto_queue_stmt_list (CATCH_BODY (t), tf); + break; + case EH_FILTER_EXPR: + replace_goto_queue_stmt_list (EH_FILTER_FAILURE (t), tf); + break; + + case STATEMENT_LIST: + abort (); + + default: + /* These won't have gotos in them. */ + break; + } + + tsi_next (tsi); +} + +/* A subroutine of replace_goto_queue. Handles STATEMENT_LISTs. */ + +static void +replace_goto_queue_stmt_list (tree t, struct leh_tf_state *tf) +{ + tree_stmt_iterator i = tsi_start (t); + while (!tsi_end_p (i)) + replace_goto_queue_1 (tsi_stmt (i), tf, &i); +} + +/* Replace all goto queue members. */ + +static void +replace_goto_queue (struct leh_tf_state *tf) +{ + replace_goto_queue_stmt_list (*tf->top_p, tf); +} + +/* For any GOTO_EXPR or RETURN_EXPR, decide whether it leaves a try_finally + node, and if so record that fact in the goto queue associated with that + try_finally node. */ + +static void +maybe_record_in_goto_queue (struct leh_state *state, tree stmt) +{ + struct leh_tf_state *tf = state->tf; + struct goto_queue_node *q; + size_t active, size; + int index; + + if (!tf) + return; + + switch (TREE_CODE (stmt)) + { + case GOTO_EXPR: + { + tree lab = GOTO_DESTINATION (stmt); + + /* Computed and non-local gotos do not get processed. Given + their nature we can neither tell whether we've escaped the + finally block nor redirect them if we knew. */ + if (TREE_CODE (lab) != LABEL_DECL) + return; + + /* No need to record gotos that don't leave the try block. */ + if (! outside_finally_tree (lab, tf->try_finally_expr)) + return; + + if (! tf->dest_array) + { + VARRAY_TREE_INIT (tf->dest_array, 10, "dest_array"); + VARRAY_PUSH_TREE (tf->dest_array, lab); + index = 0; + } + else + { + int n = VARRAY_ACTIVE_SIZE (tf->dest_array); + for (index = 0; index < n; ++index) + if (VARRAY_TREE (tf->dest_array, index) == lab) + break; + if (index == n) + VARRAY_PUSH_TREE (tf->dest_array, lab); + } + } + break; + + case RETURN_EXPR: + tf->may_return = true; + index = -1; + break; + + default: + abort (); + } + + active = tf->goto_queue_active; + size = tf->goto_queue_size; + if (active >= size) + { + size = (size ? size * 2 : 32); + tf->goto_queue_size = size; + tf->goto_queue + = xrealloc (tf->goto_queue, size * sizeof (struct goto_queue_node)); + } + + q = &tf->goto_queue[active]; + tf->goto_queue_active = active + 1; + + memset (q, 0, sizeof (*q)); + q->stmt = stmt; + q->index = index; +} + +#ifdef ENABLE_CHECKING +/* We do not process SWITCH_EXPRs for now. As long as the original source + was in fact structured, and we've not yet done jump threading, then none + of the labels will leave outer TRY_FINALLY_EXPRs. Verify this. */ + +static void +verify_norecord_switch_expr (struct leh_state *state, tree switch_expr) +{ + struct leh_tf_state *tf = state->tf; + size_t i, n; + tree vec; + + if (!tf) + return; + + vec = SWITCH_LABELS (switch_expr); + n = TREE_VEC_LENGTH (vec); + + for (i = 0; i < n; ++i) + { + tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i)); + if (outside_finally_tree (lab, tf->try_finally_expr)) + abort (); + } +} +#else +#define verify_norecord_switch_expr(state, switch_expr) +#endif + +/* Redirect a RETURN_EXPR pointed to by STMT_P to FINLAB. Place in CONT_P + whatever is needed to finish the return. If MOD is non-null, insert it + before the new branch. RETURN_VALUE_P is a cache containing a temporary + variable to be used in manipulating the value returned from the function. */ + +static void +do_return_redirection (struct goto_queue_node *q, tree finlab, tree mod, + tree *return_value_p) +{ + tree ret_expr = TREE_OPERAND (q->stmt, 0); + tree x; + + if (ret_expr) + { + /* The nasty part about redirecting the return value is that the + return value itself is to be computed before the FINALLY block + is executed. e.g. + + int x; + int foo (void) + { + x = 0; + try { + return x; + } finally { + x++; + } + } + + should return 0, not 1. Arrange for this to happen by copying + computed the return value into a local temporary. This also + allows us to redirect multiple return statements through the + same destination block; whether this is a net win or not really + depends, I guess, but it does make generation of the switch in + lower_try_finally_switch easier. */ + + if (TREE_CODE (ret_expr) == RESULT_DECL) + { + if (!*return_value_p) + *return_value_p = ret_expr; + else if (*return_value_p != ret_expr) + abort (); + q->cont_stmt = q->stmt; + } + else if (TREE_CODE (ret_expr) == MODIFY_EXPR) + { + tree result = TREE_OPERAND (ret_expr, 0); + tree new, old = TREE_OPERAND (ret_expr, 1); + + if (!*return_value_p) + { + if (aggregate_value_p (TREE_TYPE (result), + TREE_TYPE (current_function_decl))) + /* If this function returns in memory, copy the argument + into the return slot now. Otherwise, we might need to + worry about magic return semantics, so we need to use a + temporary to hold the value until we're actually ready + to return. */ + new = result; + else + new = create_tmp_var (TREE_TYPE (old), "rettmp"); + *return_value_p = new; + } + else + new = *return_value_p; + + x = build (MODIFY_EXPR, TREE_TYPE (new), new, old); + append_to_statement_list (x, &q->repl_stmt); + + if (new == result) + x = result; + else + x = build (MODIFY_EXPR, TREE_TYPE (result), result, new); + q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x); + } + else + abort (); + } + else + { + /* If we don't return a value, all return statements are the same. */ + q->cont_stmt = q->stmt; + } + + if (mod) + append_to_statement_list (mod, &q->repl_stmt); + + x = build1 (GOTO_EXPR, void_type_node, finlab); + append_to_statement_list (x, &q->repl_stmt); +} + +/* Similar, but easier, for GOTO_EXPR. */ + +static void +do_goto_redirection (struct goto_queue_node *q, tree finlab, tree mod) +{ + tree x; + + q->cont_stmt = q->stmt; + if (mod) + append_to_statement_list (mod, &q->repl_stmt); + + x = build1 (GOTO_EXPR, void_type_node, finlab); + append_to_statement_list (x, &q->repl_stmt); +} + +/* We want to transform + try { body; } catch { stuff; } + to + body; goto over; lab: stuff; over: + + T is a TRY_FINALLY or TRY_CATCH node. LAB is the label that + should be placed before the second operand, or NULL. OVER is + an existing label that should be put at the exit, or NULL. */ + +static void +frob_into_branch_around (tree *tp, tree lab, tree over) +{ + tree x, op1; + + op1 = TREE_OPERAND (*tp, 1); + *tp = TREE_OPERAND (*tp, 0); + + if (block_may_fallthru (*tp)) + { + if (!over) + over = create_artificial_label (); + x = build1 (GOTO_EXPR, void_type_node, over); + append_to_statement_list (x, tp); + } + + if (lab) + { + x = build1 (LABEL_EXPR, void_type_node, lab); + append_to_statement_list (x, tp); + } + + append_to_statement_list (op1, tp); + + if (over) + { + x = build1 (LABEL_EXPR, void_type_node, over); + append_to_statement_list (x, tp); + } +} + +/* A subroutine of lower_try_finally. Duplicate the tree rooted at T. + Make sure to record all new labels found. */ + +static tree +lower_try_finally_dup_block (tree t, struct leh_state *outer_state) +{ + tree region = NULL; + + t = lhd_unsave_expr_now (t); + + if (outer_state->tf) + region = outer_state->tf->try_finally_expr; + collect_finally_tree (t, region); + + return t; +} + +/* A subroutine of lower_try_finally. Create a fallthru label for + the given try_finally state. The only tricky bit here is that + we have to make sure to record the label in our outer context. */ + +static tree +lower_try_finally_fallthru_label (struct leh_tf_state *tf) +{ + tree label = tf->fallthru_label; + if (!label) + { + label = create_artificial_label (); + tf->fallthru_label = label; + if (tf->outer->tf) + record_in_finally_tree (label, tf->outer->tf->try_finally_expr); + } + return label; +} + +/* A subroutine of lower_try_finally. If lang_protect_cleanup_actions + returns non-null, then the language requires that the exception path out + of a try_finally be treated specially. To wit: the code within the + finally block may not itself throw an exception. We have two choices here. + First we can duplicate the finally block and wrap it in a must_not_throw + region. Second, we can generate code like + + try { + finally_block; + } catch { + if (fintmp == eh_edge) + protect_cleanup_actions; + } + + where "fintmp" is the temporary used in the switch statement generation + alternative considered below. For the nonce, we always choose the first + option. + + THIS_STATE may be null if if this is a try-cleanup, not a try-finally. */ + +static void +honor_protect_cleanup_actions (struct leh_state *outer_state, + struct leh_state *this_state, + struct leh_tf_state *tf) +{ + tree protect_cleanup_actions, finally, x; + tree_stmt_iterator i; + bool finally_may_fallthru; + + /* First check for nothing to do. */ + if (lang_protect_cleanup_actions) + protect_cleanup_actions = lang_protect_cleanup_actions (); + else + protect_cleanup_actions = NULL; + + finally = TREE_OPERAND (*tf->top_p, 1); + + /* If the EH case of the finally block can fall through, this may be a + structure of the form + try { + try { + throw ...; + } cleanup { + try { + throw ...; + } catch (...) { + } + } + } catch (...) { + yyy; + } + E.g. with an inline destructor with an embedded try block. In this + case we must save the runtime EH data around the nested exception. + + This complication means that any time the previous runtime data might + be used (via fallthru from the finally) we handle the eh case here, + whether or not protect_cleanup_actions is active. */ + + finally_may_fallthru = block_may_fallthru (finally); + if (!finally_may_fallthru && !protect_cleanup_actions) + return; + + /* Duplicate the FINALLY block. Only need to do this for try-finally, + and not for cleanups. */ + if (this_state) + finally = lower_try_finally_dup_block (finally, outer_state); + + /* Resume execution after the exception. Adding this now lets + lower_eh_filter not add unnecessary gotos, as it is clear that + we never fallthru from this copy of the finally block. */ + if (finally_may_fallthru) + { + tree save_eptr, save_filt; + + save_eptr = create_tmp_var (ptr_type_node, "save_eptr"); + save_filt = create_tmp_var (integer_type_node, "save_filt"); + + i = tsi_start (finally); + x = build (EXC_PTR_EXPR, ptr_type_node); + x = build (MODIFY_EXPR, void_type_node, save_eptr, x); + tsi_link_before (&i, x, TSI_CONTINUE_LINKING); + + x = build (FILTER_EXPR, integer_type_node); + x = build (MODIFY_EXPR, void_type_node, save_filt, x); + tsi_link_before (&i, x, TSI_CONTINUE_LINKING); + + i = tsi_last (finally); + x = build (EXC_PTR_EXPR, ptr_type_node); + x = build (MODIFY_EXPR, void_type_node, x, save_eptr); + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + + x = build (FILTER_EXPR, integer_type_node); + x = build (MODIFY_EXPR, void_type_node, x, save_filt); + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + + x = build1 (RESX_EXPR, void_type_node, + build_int_2 (get_eh_region_number (tf->region), 0)); + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + } + + /* Wrap the block with protect_cleanup_actions as the action. */ + if (protect_cleanup_actions) + { + x = build (EH_FILTER_EXPR, void_type_node, NULL, NULL); + append_to_statement_list (protect_cleanup_actions, &EH_FILTER_FAILURE (x)); + EH_FILTER_MUST_NOT_THROW (x) = 1; + finally = build (TRY_CATCH_EXPR, void_type_node, finally, x); + lower_eh_filter (outer_state, &finally); + } + else + lower_eh_constructs_1 (outer_state, &finally); + + /* Hook this up to the end of the existing try block. If we + previously fell through the end, we'll have to branch around. + This means adding a new goto, and adding it to the queue. */ + + i = tsi_last (TREE_OPERAND (*tf->top_p, 0)); + + if (tf->may_fallthru) + { + x = lower_try_finally_fallthru_label (tf); + x = build1 (GOTO_EXPR, void_type_node, x); + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + + if (this_state) + maybe_record_in_goto_queue (this_state, x); + + tf->may_fallthru = false; + } + + x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); + tsi_link_after (&i, x, TSI_CONTINUE_LINKING); + tsi_link_after (&i, finally, TSI_CONTINUE_LINKING); + + /* Having now been handled, EH isn't to be considered with + the rest of the outgoing edges. */ + tf->may_throw = false; +} + +/* A subroutine of lower_try_finally. We have determined that there is + no fallthru edge out of the finally block. This means that there is + no outgoing edge corresponding to any incoming edge. Restructure the + try_finally node for this special case. */ + +static void +lower_try_finally_nofallthru (struct leh_state *state, struct leh_tf_state *tf) +{ + tree x, finally, lab, return_val; + struct goto_queue_node *q, *qe; + + if (tf->may_throw) + lab = tf->eh_label; + else + lab = create_artificial_label (); + + finally = TREE_OPERAND (*tf->top_p, 1); + *tf->top_p = TREE_OPERAND (*tf->top_p, 0); + + x = build1 (LABEL_EXPR, void_type_node, lab); + append_to_statement_list (x, tf->top_p); + + return_val = NULL; + q = tf->goto_queue; + qe = q + tf->goto_queue_active; + for (; q < qe; ++q) + if (q->index < 0) + do_return_redirection (q, lab, NULL, &return_val); + else + do_goto_redirection (q, lab, NULL); + + replace_goto_queue (tf); + + lower_eh_constructs_1 (state, &finally); + append_to_statement_list (finally, tf->top_p); +} + +/* A subroutine of lower_try_finally. We have determined that there is + exactly one destination of the finally block. Restructure the + try_finally node for this special case. */ + +static void +lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) +{ + struct goto_queue_node *q, *qe; + tree x, finally, finally_label; + + finally = TREE_OPERAND (*tf->top_p, 1); + *tf->top_p = TREE_OPERAND (*tf->top_p, 0); + + lower_eh_constructs_1 (state, &finally); + + if (tf->may_throw) + { + /* Only reachable via the exception edge. Add the given label to + the head of the FINALLY block. Append a RESX at the end. */ + + x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); + append_to_statement_list (x, tf->top_p); + + append_to_statement_list (finally, tf->top_p); + + x = build1 (RESX_EXPR, void_type_node, + build_int_2 (get_eh_region_number (tf->region), 0)); + append_to_statement_list (x, tf->top_p); + + return; + } + + if (tf->may_fallthru) + { + /* Only reachable via the fallthru edge. Do nothing but let + the two blocks run together; we'll fall out the bottom. */ + append_to_statement_list (finally, tf->top_p); + return; + } + + finally_label = create_artificial_label (); + x = build1 (LABEL_EXPR, void_type_node, finally_label); + append_to_statement_list (x, tf->top_p); + + append_to_statement_list (finally, tf->top_p); + + q = tf->goto_queue; + qe = q + tf->goto_queue_active; + + if (tf->may_return) + { + /* Reachable by return expressions only. Redirect them. */ + tree return_val = NULL; + for (; q < qe; ++q) + do_return_redirection (q, finally_label, NULL, &return_val); + replace_goto_queue (tf); + } + else + { + /* Reachable by goto expressions only. Redirect them. */ + for (; q < qe; ++q) + do_goto_redirection (q, finally_label, NULL); + replace_goto_queue (tf); + + if (VARRAY_TREE (tf->dest_array, 0) == tf->fallthru_label) + { + /* Reachable by goto to fallthru label only. Redirect it + to the new label (already created, sadly), and do not + emit the final branch out, or the fallthru label. */ + tf->fallthru_label = NULL; + return; + } + } + + append_to_statement_list (tf->goto_queue[0].cont_stmt, tf->top_p); + maybe_record_in_goto_queue (state, tf->goto_queue[0].cont_stmt); +} + +/* A subroutine of lower_try_finally. There are multiple edges incoming + and outgoing from the finally block. Implement this by duplicating the + finally block for every destination. */ + +static void +lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf) +{ + tree finally, new_stmt; + tree x; + + finally = TREE_OPERAND (*tf->top_p, 1); + *tf->top_p = TREE_OPERAND (*tf->top_p, 0); + + new_stmt = NULL_TREE; + + if (tf->may_fallthru) + { + x = lower_try_finally_dup_block (finally, state); + lower_eh_constructs_1 (state, &x); + append_to_statement_list (x, &new_stmt); + + x = lower_try_finally_fallthru_label (tf); + x = build1 (GOTO_EXPR, void_type_node, x); + append_to_statement_list (x, &new_stmt); + } + + if (tf->may_throw) + { + x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); + append_to_statement_list (x, &new_stmt); + + x = lower_try_finally_dup_block (finally, state); + lower_eh_constructs_1 (state, &x); + append_to_statement_list (x, &new_stmt); + + x = build1 (RESX_EXPR, void_type_node, + build_int_2 (get_eh_region_number (tf->region), 0)); + append_to_statement_list (x, &new_stmt); + } + + if (tf->goto_queue) + { + struct goto_queue_node *q, *qe; + tree return_val = NULL; + int return_index; + tree *labels; + + if (tf->dest_array) + return_index = VARRAY_ACTIVE_SIZE (tf->dest_array); + else + return_index = 0; + labels = xcalloc (sizeof (tree), return_index + 1); + + q = tf->goto_queue; + qe = q + tf->goto_queue_active; + for (; q < qe; q++) + { + int index = q->index < 0 ? return_index : q->index; + tree lab = labels[index]; + bool build_p = false; + + if (!lab) + { + labels[index] = lab = create_artificial_label (); + build_p = true; + } + + if (index == return_index) + do_return_redirection (q, lab, NULL, &return_val); + else + do_goto_redirection (q, lab, NULL); + + if (build_p) + { + x = build1 (LABEL_EXPR, void_type_node, lab); + append_to_statement_list (x, &new_stmt); + + x = lower_try_finally_dup_block (finally, state); + lower_eh_constructs_1 (state, &x); + append_to_statement_list (x, &new_stmt); + + append_to_statement_list (q->cont_stmt, &new_stmt); + maybe_record_in_goto_queue (state, q->cont_stmt); + } + } + replace_goto_queue (tf); + free (labels); + } + + /* Need to link new stmts after running replace_goto_queue due + to not wanting to process the same goto stmts twice. */ + append_to_statement_list (new_stmt, tf->top_p); +} + +/* A subroutine of lower_try_finally. There are multiple edges incoming + and outgoing from the finally block. Implement this by instrumenting + each incoming edge and creating a switch statement at the end of the + finally block that branches to the appropriate destination. */ + +static void +lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) +{ + struct goto_queue_node *q, *qe; + tree return_val = NULL; + tree finally, finally_tmp, finally_label; + int return_index, eh_index, fallthru_index; + int nlabels, ndests, j, last_case_index; + tree case_label_vec, switch_stmt, last_case, switch_body; + tree x; + + /* Mash the TRY block to the head of the chain. */ + finally = TREE_OPERAND (*tf->top_p, 1); + *tf->top_p = TREE_OPERAND (*tf->top_p, 0); + + /* Lower the finally block itself. */ + lower_eh_constructs_1 (state, &finally); + + /* Prepare for switch statement generation. */ + if (tf->dest_array) + nlabels = VARRAY_ACTIVE_SIZE (tf->dest_array); + else + nlabels = 0; + return_index = nlabels; + eh_index = return_index + tf->may_return; + fallthru_index = eh_index + tf->may_throw; + ndests = fallthru_index + tf->may_fallthru; + + finally_tmp = create_tmp_var (integer_type_node, "finally_tmp"); + finally_label = create_artificial_label (); + + case_label_vec = make_tree_vec (ndests); + switch_stmt = build (SWITCH_EXPR, integer_type_node, finally_tmp, + NULL_TREE, case_label_vec); + switch_body = NULL; + last_case = NULL; + last_case_index = 0; + + /* Begin inserting code for getting to the finally block. Things + are done in this order to correspond to the sequence the code is + layed out. */ + + if (tf->may_fallthru) + { + x = build (MODIFY_EXPR, void_type_node, finally_tmp, + build_int_2 (fallthru_index, 0)); + append_to_statement_list (x, tf->top_p); + + if (tf->may_throw) + { + x = build1 (GOTO_EXPR, void_type_node, finally_label); + append_to_statement_list (x, tf->top_p); + } + + + last_case = build (CASE_LABEL_EXPR, void_type_node, + build_int_2 (fallthru_index, 0), NULL, + create_artificial_label ()); + TREE_VEC_ELT (case_label_vec, last_case_index) = last_case; + last_case_index++; + + x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case)); + append_to_statement_list (x, &switch_body); + + x = lower_try_finally_fallthru_label (tf); + x = build1 (GOTO_EXPR, void_type_node, x); + append_to_statement_list (x, &switch_body); + } + + if (tf->may_throw) + { + x = build1 (LABEL_EXPR, void_type_node, tf->eh_label); + append_to_statement_list (x, tf->top_p); + + x = build (MODIFY_EXPR, void_type_node, finally_tmp, + build_int_2 (eh_index, 0)); + append_to_statement_list (x, tf->top_p); + + last_case = build (CASE_LABEL_EXPR, void_type_node, + build_int_2 (eh_index, 0), NULL, + create_artificial_label ()); + TREE_VEC_ELT (case_label_vec, last_case_index) = last_case; + last_case_index++; + + x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case)); + append_to_statement_list (x, &switch_body); + x = build1 (RESX_EXPR, void_type_node, + build_int_2 (get_eh_region_number (tf->region), 0)); + append_to_statement_list (x, &switch_body); + } + + x = build1 (LABEL_EXPR, void_type_node, finally_label); + append_to_statement_list (x, tf->top_p); + + append_to_statement_list (finally, tf->top_p); + + /* Redirect each incoming goto edge. */ + q = tf->goto_queue; + qe = q + tf->goto_queue_active; + j = last_case_index + tf->may_return; + last_case_index += nlabels; + for (; q < qe; ++q) + { + tree mod; + int switch_id, case_index; + + if (q->index < 0) + { + mod = build (MODIFY_EXPR, void_type_node, finally_tmp, + build_int_2 (return_index, 0)); + do_return_redirection (q, finally_label, mod, &return_val); + switch_id = return_index; + } + else + { + mod = build (MODIFY_EXPR, void_type_node, finally_tmp, + build_int_2 (q->index, 0)); + do_goto_redirection (q, finally_label, mod); + switch_id = q->index; + } + + case_index = j + q->index; + if (!TREE_VEC_ELT (case_label_vec, case_index)) + { + last_case = build (CASE_LABEL_EXPR, void_type_node, + build_int_2 (switch_id, 0), NULL, + create_artificial_label ()); + TREE_VEC_ELT (case_label_vec, case_index) = last_case; + + x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case)); + append_to_statement_list (x, &switch_body); + append_to_statement_list (q->cont_stmt, &switch_body); + maybe_record_in_goto_queue (state, q->cont_stmt); + } + } + replace_goto_queue (tf); + last_case_index += nlabels; + + /* Make sure that we have a default label, as one is required. */ + CASE_LOW (last_case) = NULL; + + /* Need to link switch_stmt after running replace_goto_queue due + to not wanting to process the same goto stmts twice. */ + append_to_statement_list (switch_stmt, tf->top_p); + append_to_statement_list (switch_body, tf->top_p); +} + +/* Decide whether or not we are going to duplicate the finally block. + There are several considerations. + + First, if this is Java, then the finally block contains code + written by the user. It has line numbers associated with it, + so duplicating the block means it's difficult to set a breakpoint. + Since controlling code generation via -g is verboten, we simply + never duplicate code without optimization. + + Second, we'd like to prevent egregious code growth. One way to + do this is to estimate the size of the finally block, multiply + that by the number of copies we'd need to make, and compare against + the estimate of the size of the switch machinery we'd have to add. */ + +static bool +decide_copy_try_finally (int ndests, tree finally) +{ + int f_estimate, sw_estimate; + + if (!optimize) + return false; + + /* Finally estimate N times, plus N gotos. */ + f_estimate = estimate_num_insns (finally); + f_estimate = (f_estimate + 1) * ndests; + + /* Switch statement (cost 10), N variable assignments, N gotos. */ + sw_estimate = 10 + 2 * ndests; + + /* Optimize for size clearly wants our best guess. */ + if (optimize_size) + return f_estimate < sw_estimate; + + /* ??? These numbers are completely made up so far. */ + if (optimize > 1) + return f_estimate < 100 || f_estimate * 2 < sw_estimate; + else + return f_estimate < 40 || f_estimate * 3 < sw_estimate * 2; +} + +/* A subroutine of lower_eh_constructs_1. Lower a TRY_FINALLY_EXPR nodes + to a sequence of labels and blocks, plus the exception region trees + that record all the magic. This is complicated by the need to + arrange for the FINALLY block to be executed on all exits. */ + +static void +lower_try_finally (struct leh_state *state, tree *tp) +{ + struct leh_tf_state this_tf; + struct leh_state this_state; + int ndests; + + /* Process the try block. */ + + memset (&this_tf, 0, sizeof (this_tf)); + this_tf.try_finally_expr = *tp; + this_tf.top_p = tp; + this_tf.outer = state; + if (using_eh_for_cleanups_p) + this_tf.region + = gen_eh_region_cleanup (state->cur_region, state->prev_try); + else + this_tf.region = NULL; + + this_state.cur_region = this_tf.region; + this_state.prev_try = state->prev_try; + this_state.tf = &this_tf; + + lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); + + /* Determine if the try block is escaped through the bottom. */ + this_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0)); + + /* Determine if any exceptions are possible within the try block. */ + if (using_eh_for_cleanups_p) + this_tf.may_throw = get_eh_region_may_contain_throw (this_tf.region); + if (this_tf.may_throw) + { + this_tf.eh_label = create_artificial_label (); + set_eh_region_tree_label (this_tf.region, this_tf.eh_label); + honor_protect_cleanup_actions (state, &this_state, &this_tf); + } + + /* Sort the goto queue for efficient searching later. */ + if (this_tf.goto_queue_active > 1) + qsort (this_tf.goto_queue, this_tf.goto_queue_active, + sizeof (struct goto_queue_node), goto_queue_cmp); + + /* Determine how many edges (still) reach the finally block. Or rather, + how many destinations are reached by the finally block. Use this to + determine how we process the finally block itself. */ + + if (this_tf.dest_array) + ndests = VARRAY_ACTIVE_SIZE (this_tf.dest_array); + else + ndests = 0; + ndests += this_tf.may_fallthru; + ndests += this_tf.may_return; + ndests += this_tf.may_throw; + + /* If the FINALLY block is not reachable, dike it out. */ + if (ndests == 0) + *tp = TREE_OPERAND (*tp, 0); + + /* If the finally block doesn't fall through, then any destination + we might try to impose there isn't reached either. There may be + some minor amount of cleanup and redirection still needed. */ + else if (!block_may_fallthru (TREE_OPERAND (*tp, 1))) + lower_try_finally_nofallthru (state, &this_tf); + + /* We can easily special-case redirection to a single destination. */ + else if (ndests == 1) + lower_try_finally_onedest (state, &this_tf); + + else if (decide_copy_try_finally (ndests, TREE_OPERAND (*tp, 1))) + lower_try_finally_copy (state, &this_tf); + else + lower_try_finally_switch (state, &this_tf); + + /* If someone requested we add a label at the end of the transformed + block, do so. */ + if (this_tf.fallthru_label) + { + tree x = build1 (LABEL_EXPR, void_type_node, this_tf.fallthru_label); + append_to_statement_list (x, tp); + } + + if (this_tf.goto_queue) + free (this_tf.goto_queue); +} + +/* A subroutine of lower_eh_constructs_1. Lower a TRY_CATCH_EXPR with a + list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the + exception region trees that record all the magic. */ + +static void +lower_catch (struct leh_state *state, tree *tp) +{ + struct eh_region *try_region; + struct leh_state this_state; + tree_stmt_iterator i; + tree out_label; + + try_region = gen_eh_region_try (state->cur_region); + this_state.cur_region = try_region; + this_state.prev_try = try_region; + this_state.tf = state->tf; + + lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); + + if (!get_eh_region_may_contain_throw (try_region)) + { + *tp = TREE_OPERAND (*tp, 0); + return; + } + + out_label = NULL; + for (i = tsi_start (TREE_OPERAND (*tp, 1)); !tsi_end_p (i); ) + { + struct eh_region *catch_region; + tree catch, x, eh_label; + + catch = tsi_stmt (i); + catch_region = gen_eh_region_catch (try_region, CATCH_TYPES (catch)); + + this_state.cur_region = catch_region; + this_state.prev_try = state->prev_try; + lower_eh_constructs_1 (&this_state, &CATCH_BODY (catch)); + + eh_label = create_artificial_label (); + set_eh_region_tree_label (catch_region, eh_label); + + x = build1 (LABEL_EXPR, void_type_node, eh_label); + tsi_link_before (&i, x, TSI_SAME_STMT); + + if (block_may_fallthru (CATCH_BODY (catch))) + { + if (!out_label) + out_label = create_artificial_label (); + + x = build1 (GOTO_EXPR, void_type_node, out_label); + append_to_statement_list (x, &CATCH_BODY (catch)); + } + + tsi_link_before (&i, CATCH_BODY (catch), TSI_SAME_STMT); + tsi_delink (&i); + } + + frob_into_branch_around (tp, NULL, out_label); +} + +/* A subroutine of lower_eh_constructs_1. Lower a TRY_CATCH_EXPR with a + EH_FILTER_EXPR to a sequence of labels and blocks, plus the exception + region trees that record all the magic. */ + +static void +lower_eh_filter (struct leh_state *state, tree *tp) +{ + struct leh_state this_state; + struct eh_region *this_region; + tree inner = expr_first (TREE_OPERAND (*tp, 1)); + tree eh_label; + + if (EH_FILTER_MUST_NOT_THROW (inner)) + this_region = gen_eh_region_must_not_throw (state->cur_region); + else + this_region = gen_eh_region_allowed (state->cur_region, + EH_FILTER_TYPES (inner)); + this_state = *state; + this_state.cur_region = this_region; + + lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); + + if (!get_eh_region_may_contain_throw (this_region)) + { + *tp = TREE_OPERAND (*tp, 0); + return; + } + + lower_eh_constructs_1 (state, &EH_FILTER_FAILURE (inner)); + TREE_OPERAND (*tp, 1) = EH_FILTER_FAILURE (inner); + + eh_label = create_artificial_label (); + set_eh_region_tree_label (this_region, eh_label); + + frob_into_branch_around (tp, eh_label, NULL); +} + +/* Implement a cleanup expression. This is similar to try-finally, + except that we only execute the cleanup block for exception edges. */ + +static void +lower_cleanup (struct leh_state *state, tree *tp) +{ + struct leh_state this_state; + struct eh_region *this_region; + struct leh_tf_state fake_tf; + + /* If not using eh, then exception-only cleanups are no-ops. */ + if (!flag_exceptions) + { + *tp = TREE_OPERAND (*tp, 0); + lower_eh_constructs_1 (state, tp); + return; + } + + this_region = gen_eh_region_cleanup (state->cur_region, state->prev_try); + this_state = *state; + this_state.cur_region = this_region; + + lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0)); + + if (!get_eh_region_may_contain_throw (this_region)) + { + *tp = TREE_OPERAND (*tp, 0); + return; + } + + /* Build enough of a try-finally state so that we can reuse + honor_protect_cleanup_actions. */ + memset (&fake_tf, 0, sizeof (fake_tf)); + fake_tf.top_p = tp; + fake_tf.outer = state; + fake_tf.region = this_region; + fake_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0)); + fake_tf.may_throw = true; + + fake_tf.eh_label = create_artificial_label (); + set_eh_region_tree_label (this_region, fake_tf.eh_label); + + honor_protect_cleanup_actions (state, NULL, &fake_tf); + + if (fake_tf.may_throw) + { + /* In this case honor_protect_cleanup_actions had nothing to do, + and we should process this normally. */ + lower_eh_constructs_1 (state, &TREE_OPERAND (*tp, 1)); + frob_into_branch_around (tp, fake_tf.eh_label, fake_tf.fallthru_label); + } + else + { + /* In this case honor_protect_cleanup_actions did nearly all of + the work. All we have left is to append the fallthru_label. */ + + *tp = TREE_OPERAND (*tp, 0); + if (fake_tf.fallthru_label) + { + tree x = build1 (LABEL_EXPR, void_type_node, fake_tf.fallthru_label); + append_to_statement_list (x, tp); + } + } +} + +/* Main loop for lowering eh constructs. */ + +static void +lower_eh_constructs_1 (struct leh_state *state, tree *tp) +{ + tree_stmt_iterator i; + tree t = *tp; + + switch (TREE_CODE (t)) + { + case COND_EXPR: + lower_eh_constructs_1 (state, &COND_EXPR_THEN (t)); + lower_eh_constructs_1 (state, &COND_EXPR_ELSE (t)); + break; + + case CALL_EXPR: + /* Look for things that can throw exceptions, and record them. */ + if (state->cur_region && tree_could_throw_p (t)) + { + record_stmt_eh_region (state->cur_region, t); + note_eh_region_may_contain_throw (state->cur_region); + } + break; + + case MODIFY_EXPR: + /* Look for things that can throw exceptions, and record them. */ + if (state->cur_region && tree_could_throw_p (t)) + { + record_stmt_eh_region (state->cur_region, t); + note_eh_region_may_contain_throw (state->cur_region); + + /* ??? For the benefit of calls.c, converting all this to rtl, + we need to record the call expression, not just the outer + modify statement. */ + if (TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR) + record_stmt_eh_region (state->cur_region, TREE_OPERAND (t, 1)); + } + break; + + case GOTO_EXPR: + case RETURN_EXPR: + maybe_record_in_goto_queue (state, t); + break; + case SWITCH_EXPR: + verify_norecord_switch_expr (state, t); + break; + + case TRY_FINALLY_EXPR: + lower_try_finally (state, tp); + break; + + case TRY_CATCH_EXPR: + i = tsi_start (TREE_OPERAND (t, 1)); + switch (TREE_CODE (tsi_stmt (i))) + { + case CATCH_EXPR: + lower_catch (state, tp); + break; + case EH_FILTER_EXPR: + lower_eh_filter (state, tp); + break; + default: + lower_cleanup (state, tp); + break; + } + break; + + case STATEMENT_LIST: + for (i = tsi_start (t); !tsi_end_p (i); ) + { + lower_eh_constructs_1 (state, tsi_stmt_ptr (i)); + t = tsi_stmt (i); + if (TREE_CODE (t) == STATEMENT_LIST) + { + tsi_link_before (&i, t, TSI_SAME_STMT); + tsi_delink (&i); + } + else + tsi_next (&i); + } + break; + + default: + /* A type, a decl, or some kind of statement that we're not + interested in. Don't walk them. */ + break; + } +} + +static void +lower_eh_constructs (void) +{ + struct leh_state null_state; + tree *tp = &DECL_SAVED_TREE (current_function_decl); + + finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free); + throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq, free); + + collect_finally_tree (*tp, NULL); + + memset (&null_state, 0, sizeof (null_state)); + lower_eh_constructs_1 (&null_state, tp); + + htab_delete (finally_tree); + + collect_eh_region_array (); +} + +struct tree_opt_pass pass_lower_eh = +{ + "eh", /* name */ + NULL, /* gate */ + lower_eh_constructs, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_EH, /* tv_id */ + PROP_gimple_lcf, /* properties_required */ + PROP_gimple_leh, /* properties_provided */ + PROP_gimple_lcf, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ +}; + + +/* Construct EH edges for STMT. */ + +static void +make_eh_edge (struct eh_region *region, void *data) +{ + tree stmt, lab; + basic_block src, dst; + + stmt = data; + lab = get_eh_region_tree_label (region); + + src = bb_for_stmt (stmt); + dst = label_to_block (lab); + + make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH); +} + +void +make_eh_edges (tree stmt) +{ + int region_nr; + bool is_resx; + + if (TREE_CODE (stmt) == RESX_EXPR) + { + region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)); + is_resx = true; + } + else + { + region_nr = lookup_stmt_eh_region (stmt); + if (region_nr < 0) + return; + is_resx = false; + } + + foreach_reachable_handler (region_nr, is_resx, make_eh_edge, stmt); +} + + + +/* Return true if the expr can trap, as in dereferencing an + invalid pointer location. */ + +bool +tree_could_trap_p (tree expr) +{ + enum tree_code code = TREE_CODE (expr); + tree t; + + switch (code) + { + case ARRAY_REF: + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + case BIT_FIELD_REF: + t = get_base_address (expr); + return !t || TREE_CODE (t) == INDIRECT_REF; + + case INDIRECT_REF: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case TRUNC_MOD_EXPR: + return true; + + default: + break; + } + + return false; +} + + +bool +tree_could_throw_p (tree t) +{ + if (!flag_exceptions) + return false; + if (TREE_CODE (t) == MODIFY_EXPR) + { + tree sub = TREE_OPERAND (t, 1); + if (TREE_CODE (sub) == CALL_EXPR) + t = sub; + else + { + if (flag_non_call_exceptions) + { + if (tree_could_trap_p (sub)) + return true; + return tree_could_trap_p (TREE_OPERAND (t, 0)); + } + return false; + } + } + + if (TREE_CODE (t) == CALL_EXPR) + return (call_expr_flags (t) & ECF_NOTHROW) == 0; + + return false; +} + +bool +tree_can_throw_internal (tree stmt) +{ + int region_nr = lookup_stmt_eh_region (stmt); + if (region_nr < 0) + return false; + return can_throw_internal_1 (region_nr); +} + +bool +tree_can_throw_external (tree stmt) +{ + int region_nr = lookup_stmt_eh_region (stmt); + if (region_nr < 0) + return false; + return can_throw_external_1 (region_nr); +} + +#include "gt-tree-eh.h" diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h new file mode 100644 index 00000000000..3505b0c4f19 --- /dev/null +++ b/gcc/tree-flow-inline.h @@ -0,0 +1,604 @@ +/* Inline functions for tree-flow.h + Copyright (C) 2001, 2003 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _TREE_FLOW_INLINE_H +#define _TREE_FLOW_INLINE_H 1 + +/* Inline functions for manipulating various data structures defined in + tree-flow.h. See tree-flow.h for documentation. */ + +static inline var_ann_t +var_ann (tree t) +{ +#if defined ENABLE_CHECKING + if (t == NULL_TREE + || !DECL_P (t) + || (t->common.ann + && t->common.ann->common.type != VAR_ANN)) + abort (); +#endif + + return (var_ann_t) t->common.ann; +} + +static inline var_ann_t +get_var_ann (tree var) +{ + var_ann_t ann = var_ann (var); + return (ann) ? ann : create_var_ann (var); +} + +static inline stmt_ann_t +stmt_ann (tree t) +{ +#if defined ENABLE_CHECKING + if (!is_gimple_stmt (t) && !is_essa_node (t)) + abort (); +#endif + + return (stmt_ann_t) t->common.ann; +} + +static inline stmt_ann_t +get_stmt_ann (tree stmt) +{ + stmt_ann_t ann = stmt_ann (stmt); + return (ann) ? ann : create_stmt_ann (stmt); +} + +static inline ssa_name_ann_t +ssa_name_ann (tree t) +{ +#if defined ENABLE_CHECKING + if (t == NULL_TREE + || TREE_CODE (t) != SSA_NAME + || (t->common.ann + && t->common.ann->common.type != SSA_NAME_ANN)) + abort (); +#endif + + return (ssa_name_ann_t) t->common.ann; +} + +static inline ssa_name_ann_t +get_ssa_name_ann (tree var) +{ + ssa_name_ann_t ann = ssa_name_ann (var); + return (ann) ? ann : create_ssa_name_ann (var); +} + + +static inline enum tree_ann_type +ann_type (tree_ann ann) +{ + return ann->common.type; +} + +static inline basic_block +bb_for_stmt (tree t) +{ + stmt_ann_t ann = stmt_ann (t); + return ann ? ann->bb : NULL; +} + +static inline varray_type +may_aliases (tree var) +{ + var_ann_t ann = var_ann (var); + return ann ? ann->may_aliases : NULL; +} + +static inline bool +has_hidden_use (tree var) +{ + var_ann_t ann = var_ann (var); + return ann ? ann->has_hidden_use : false; +} + +static inline void +set_has_hidden_use (tree var) +{ + var_ann_t ann = var_ann (var); + if (ann == NULL) + ann = create_var_ann (var); + ann->has_hidden_use = 1; +} + +static inline int +get_lineno (tree expr) +{ + if (expr == NULL_TREE) + return -1; + + if (TREE_CODE (expr) == COMPOUND_EXPR) + expr = TREE_OPERAND (expr, 0); + + if (! EXPR_LOCUS (expr)) + return -1; + + return EXPR_LINENO (expr); +} + +static inline const char * +get_filename (tree expr) +{ + if (expr == NULL_TREE) + return "???"; + + if (TREE_CODE (expr) == COMPOUND_EXPR) + expr = TREE_OPERAND (expr, 0); + + if (EXPR_LOCUS (expr) && EXPR_FILENAME (expr)) + return EXPR_FILENAME (expr); + else + return "???"; +} + +static inline void +modify_stmt (tree t) +{ + stmt_ann_t ann = stmt_ann (t); + if (ann == NULL) + ann = create_stmt_ann (t); + ann->modified = 1; +} + +static inline void +unmodify_stmt (tree t) +{ + stmt_ann_t ann = stmt_ann (t); + if (ann == NULL) + ann = create_stmt_ann (t); + ann->modified = 0; +} + +static inline bool +stmt_modified_p (tree t) +{ + stmt_ann_t ann = stmt_ann (t); + + /* Note that if the statement doesn't yet have an annotation, we consider it + modified. This will force the next call to get_stmt_operands to scan the + statement. */ + return ann ? ann->modified : true; +} + +static inline def_optype +get_def_ops (stmt_ann_t ann) +{ + return ann ? ann->def_ops : NULL; +} + +static inline use_optype +get_use_ops (stmt_ann_t ann) +{ + return ann ? ann->use_ops : NULL; +} + +static inline vdef_optype +get_vdef_ops (stmt_ann_t ann) +{ + return ann ? ann->vdef_ops : NULL; +} + +static inline vuse_optype +get_vuse_ops (stmt_ann_t ann) +{ + return ann ? ann->vuse_ops : NULL; +} + +static inline tree * +get_use_op_ptr (use_optype uses, unsigned int index) +{ +#ifdef ENABLE_CHECKING + if (index >= uses->num_uses) + abort(); +#endif + return uses->uses[index]; +} + +static inline tree * +get_def_op_ptr (def_optype defs, unsigned int index) +{ +#ifdef ENABLE_CHECKING + if (index >= defs->num_defs) + abort(); +#endif + return defs->defs[index]; +} + +static inline tree * +get_vdef_result_ptr(vdef_optype vdefs, unsigned int index) +{ +#ifdef ENABLE_CHECKING + if (index >= vdefs->num_vdefs) + abort(); +#endif + return &(vdefs->vdefs[index * 2]); +} + +static inline tree * +get_vdef_op_ptr(vdef_optype vdefs, unsigned int index) +{ +#ifdef ENABLE_CHECKING + if (index >= vdefs->num_vdefs) + abort(); +#endif + return &(vdefs->vdefs[index * 2 + 1]); +} + +static inline tree * +get_vuse_op_ptr(vuse_optype vuses, unsigned int index) +{ +#ifdef ENABLE_CHECKING + if (index >= vuses->num_vuses) + abort(); +#endif + return &(vuses->vuses[index]); +} + +static inline void +start_ssa_stmt_operands (tree stmt ATTRIBUTE_UNUSED) +{ +#ifdef ENABLE_CHECKING + verify_start_operands (stmt); +#endif +} + +static inline bitmap +addresses_taken (tree stmt) +{ + stmt_ann_t ann = stmt_ann (stmt); + return ann ? ann->addresses_taken : NULL; +} + +static dataflow_t +get_immediate_uses (tree stmt) +{ + stmt_ann_t ann = stmt_ann (stmt); + return ann ? ann->df : NULL; +} + +static inline int +num_immediate_uses (dataflow_t df) +{ + varray_type imm; + + if (!df) + return 0; + + imm = df->immediate_uses; + if (!imm) + return df->uses[1] ? 2 : 1; + + return VARRAY_ACTIVE_SIZE (imm) + 2; +} + +static inline tree +immediate_use (dataflow_t df, int num) +{ +#ifdef ENABLE_CHECKING + if (num >= num_immediate_uses (df)) + abort (); +#endif + if (num < 2) + return df->uses[num]; + return VARRAY_TREE (df->immediate_uses, num - 2); +} + +static inline bb_ann_t +bb_ann (basic_block bb) +{ + return (bb_ann_t)bb->tree_annotations; +} + +static inline tree +phi_nodes (basic_block bb) +{ + if (bb->index < 0) + return NULL; + return bb_ann (bb)->phi_nodes; +} + +/* Set list of phi nodes of a basic block BB to L. */ + +static inline void +set_phi_nodes (basic_block bb, tree l) +{ + tree phi; + + bb_ann (bb)->phi_nodes = l; + for (phi = l; phi; phi = TREE_CHAIN (phi)) + set_bb_for_stmt (phi, bb); +} + +/* Return the phi index number for an edge. */ +static inline int +phi_arg_from_edge (tree phi, edge e) +{ + int i; +#if defined ENABLE_CHECKING + if (!phi || TREE_CODE (phi) != PHI_NODE) + abort(); +#endif + + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + if (PHI_ARG_EDGE (phi, i) == e) + return i; + + return -1; +} + + +/* Return the phi argument number for an edge. */ +static inline struct phi_arg_d * +phi_element_for_edge (tree phi, edge e) +{ + int i; + + i = phi_arg_from_edge (phi, e); + if (i != -1) + return &(PHI_ARG_ELT (phi, i)); + else + return (struct phi_arg_d *)NULL; +} + +/* ----------------------------------------------------------------------- */ + +static inline bool +is_exec_stmt (tree t) +{ + return (t && !IS_EMPTY_STMT (t) && t != error_mark_node); +} + + +/* Return true if this stmt can be the target of a control transfer stmt such + as a goto. */ +static inline bool +is_label_stmt (tree t) +{ + if (t) + switch (TREE_CODE (t)) + { + case LABEL_DECL: + case LABEL_EXPR: + case CASE_LABEL_EXPR: + return true; + default: + return false; + } + return false; +} + +static inline bool +may_propagate_copy (tree dest, tree orig) +{ + /* FIXME. GIMPLE is allowing pointer assignments and comparisons of + pointers that have different alias sets. This means that these + pointers will have different memory tags associated to them. + + If we allow copy propagation in these cases, statements de-referencing + the new pointer will now have a reference to a different memory tag + with potentially incorrect SSA information. + + This was showing up in libjava/java/util/zip/ZipFile.java with code + like: + + struct java.io.BufferedInputStream *T.660; + struct java.io.BufferedInputStream *T.647; + struct java.io.InputStream *is; + struct java.io.InputStream *is.662; + [ ... ] + T.660 = T.647; + is = T.660; <-- This ought to be type-casted + is.662 = is; + + Also, f/name.c exposed a similar problem with a COND_EXPR predicate + that was causing DOM to generate and equivalence with two pointers of + alias-incompatible types: + + struct _ffename_space *n; + struct _ffename *ns; + [ ... ] + if (n == ns) + goto lab; + ... + lab: + return n; + + I think that GIMPLE should emit the appropriate type-casts. For the + time being, blocking copy-propagation in these cases is the safe thing + to do. */ + if (TREE_CODE (dest) == SSA_NAME + && TREE_CODE (orig) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (dest)) + && POINTER_TYPE_P (TREE_TYPE (orig))) + { + tree mt_dest = var_ann (SSA_NAME_VAR (dest))->type_mem_tag; + tree mt_orig = var_ann (SSA_NAME_VAR (orig))->type_mem_tag; + if (mt_dest && mt_orig && mt_dest != mt_orig) + return false; + } + + /* If the destination is a SSA_NAME for a virtual operand, then we have + some special cases to handle. */ + if (TREE_CODE (dest) == SSA_NAME && !is_gimple_reg (dest)) + { + /* If both operands are SSA_NAMEs referring to virtual operands, then + we can always propagate. */ + if (TREE_CODE (orig) == SSA_NAME) + { + if (!is_gimple_reg (orig)) + return true; + +#ifdef ENABLE_CHECKING + /* If we have one real and one virtual operand, then something has + gone terribly wrong. */ + if (is_gimple_reg (orig)) + abort (); +#endif + } + + /* We have a "copy" from something like a constant into a virtual + operand. Reject these. */ + return false; + } + + return (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest) + && (TREE_CODE (orig) != SSA_NAME + || !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig)) + && !DECL_HARD_REGISTER (SSA_NAME_VAR (dest))); +} + +static inline void +set_default_def (tree var, tree def) +{ + var_ann_t ann = var_ann (var); + if (ann == NULL) + ann = create_var_ann (var); + ann->default_def = def; +} + +static inline tree +default_def (tree var) +{ + var_ann_t ann = var_ann (var); + return ann ? ann->default_def : NULL_TREE; +} + +/* PHI nodes should contain only ssa_names and invariants. A test + for ssa_name is definitely simpler; don't let invalid contents + slip in in the meantime. */ + +static inline bool +phi_ssa_name_p (tree t) +{ + if (TREE_CODE (t) == SSA_NAME) + return true; +#ifdef ENABLE_CHECKING + if (!is_gimple_min_invariant (t)) + abort (); +#endif + return false; +} + +/* ----------------------------------------------------------------------- */ + +static inline block_stmt_iterator +bsi_start (basic_block bb) +{ + block_stmt_iterator bsi; + if (bb->stmt_list) + bsi.tsi = tsi_start (bb->stmt_list); + else + { +#ifdef ENABLE_CHECKING + if (bb->index >= 0) + abort (); +#endif + bsi.tsi.ptr = NULL; + bsi.tsi.container = NULL; + } + bsi.bb = bb; + return bsi; +} + +static inline block_stmt_iterator +bsi_last (basic_block bb) +{ + block_stmt_iterator bsi; + if (bb->stmt_list) + bsi.tsi = tsi_last (bb->stmt_list); + else + { +#ifdef ENABLE_CHECKING + if (bb->index >= 0) + abort (); +#endif + bsi.tsi.ptr = NULL; + bsi.tsi.container = NULL; + } + bsi.bb = bb; + return bsi; +} + +static inline bool +bsi_end_p (block_stmt_iterator i) +{ + return tsi_end_p (i.tsi); +} + +static inline void +bsi_next (block_stmt_iterator *i) +{ + tsi_next (&i->tsi); +} + +static inline void +bsi_prev (block_stmt_iterator *i) +{ + tsi_prev (&i->tsi); +} + +static inline tree +bsi_stmt (block_stmt_iterator i) +{ + return tsi_stmt (i.tsi); +} + +static inline tree * +bsi_stmt_ptr (block_stmt_iterator i) +{ + return tsi_stmt_ptr (i.tsi); +} + +static inline bool +may_be_aliased (tree var) +{ + return (TREE_ADDRESSABLE (var) + || decl_function_context (var) != current_function_decl); +} + +static inline bool +is_call_clobbered (tree var) +{ + return needs_to_live_in_memory (var) + || bitmap_bit_p (call_clobbered_vars, var_ann (var)->uid); +} + +static inline void +mark_call_clobbered (tree var) +{ + var_ann_t ann = var_ann (var); + /* Call-clobbered variables need to live in memory. */ + DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (var) = 1; + bitmap_set_bit (call_clobbered_vars, ann->uid); +} + +static inline void +mark_non_addressable (tree var) +{ + bitmap_clear_bit (call_clobbered_vars, var_ann (var)->uid); + DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (var) = 0; + TREE_ADDRESSABLE (var) = 0; +} + +#endif /* _TREE_FLOW_INLINE_H */ diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h new file mode 100644 index 00000000000..853eb1a41eb --- /dev/null +++ b/gcc/tree-flow.h @@ -0,0 +1,596 @@ +/* Data and Control Flow Analysis for Trees. + Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _TREE_FLOW_H +#define _TREE_FLOW_H 1 + +#include "bitmap.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "hashtab.h" +#include "tree-simple.h" +#include "tree-ssa-operands.h" + +/* Forward declare structures for the garbage collector GTY markers. */ +#ifndef GCC_BASIC_BLOCK_H +struct edge_def; +typedef struct edge_def *edge; +struct basic_block_def; +typedef struct basic_block_def *basic_block; +#endif + +/*--------------------------------------------------------------------------- + Tree annotations stored in tree_common.ann +---------------------------------------------------------------------------*/ +enum tree_ann_type { TREE_ANN_COMMON, VAR_ANN, STMT_ANN, SSA_NAME_ANN }; + +struct tree_ann_common_d GTY(()) +{ + /* Annotation type. */ + enum tree_ann_type type; +}; + +/* It is advantageous to avoid things like life analysis for variables which + do not need PHI nodes. This enum describes whether or not a particular + variable may need a PHI node. */ + +enum need_phi_state { + /* This is the default. If we are still in this state after finding + all the definition and use sites, then we will assume the variable + needs PHI nodes. This is probably an overly conservative assumption. */ + NEED_PHI_STATE_UNKNOWN, + + /* This state indicates that we have seen one or more sets of the + variable in a single basic block and that the sets dominate all + uses seen so far. If after finding all definition and use sites + we are still in this state, then the variable does not need any + PHI nodes. */ + NEED_PHI_STATE_NO, + + /* This state indicates that we have either seen multiple definitions of + the variable in multiple blocks, or that we encountered a use in a + block that was not dominated by the block containing the set(s) of + this variable. This variable is assumed to need PHI nodes. */ + NEED_PHI_STATE_MAYBE +}; + + +/* When computing aliasing information, we represent the memory pointed-to + by pointers with artificial variables called "memory tags" (MT). There + are two kinds of tags: type and name. Type tags (TMT) are used in + type-based alias analysis, they represent all the pointed-to locations + and variables of the same alias set class. Name tags (NMT) are used in + flow-sensitive points-to alias analysis, they represent the variables + and memory locations pointed-to by a specific SSA_NAME pointer. */ +enum mem_tag_kind { + /* This variable is not a memory tag. */ + NOT_A_TAG, + + /* This variable is a type memory tag (TMT). */ + TYPE_TAG, + + /* This variable is a name memory tag (NMT). */ + NAME_TAG +}; + +struct var_ann_d GTY(()) +{ + struct tree_ann_common_d common; + + /* Nonzero if this variable has uses which may not appear + in the IL. This can happen in the following cases: + + 1. If the variable is used in a variable length + array declaration. + + 2. If the variable is the return value in a C++ + function where the named return value optimization + has been performed. */ + unsigned has_hidden_use : 1; + + /* Used by the out of SSA pass to determine whether this variable has + been seen yet or not. */ + unsigned out_of_ssa_tag : 1; + + /* Used when building root_var structures in tree_ssa_live.[ch]. */ + unsigned root_var_processed : 1; + + /* If nonzero, this variable is a memory tag. */ + ENUM_BITFIELD (mem_tag_kind) mem_tag_kind : 2; + + /* Nonzero if this variable is an alias tag that represents references to + other variables (i.e., this variable appears in the MAY_ALIASES array + of other variables). */ + unsigned is_alias_tag : 1; + + /* Nonzero if this variable was used after SSA optimizations were + applied. We set this when translating out of SSA form. */ + unsigned used : 1; + + /* This field indicates whether or not the variable may need PHI nodes. + See the enum's definition for more detailed information about the + states. */ + ENUM_BITFIELD (need_phi_state) need_phi_state : 2; + + /* An artificial variable representing the memory location pointed-to by + all the pointers that TBAA (type-based alias analysis) considers + to be aliased. If the variable is not a pointer or if it is never + dereferenced, this must be NULL. */ + tree type_mem_tag; + + /* Variables that may alias this variable. */ + varray_type may_aliases; + + /* Unique ID of this variable. */ + size_t uid; + + /* Used when going out of SSA form to indicate which partition this + variable represents storage for. */ + unsigned partition; + + /* Used by the root-var object in tree-ssa-live.[ch]. */ + unsigned root_index; + + /* Default definition for this symbol. If this field is not NULL, it + means that the first reference to this variable in the function is a + USE or a VUSE. In those cases, the SSA renamer creates an SSA name + for this variable with an empty defining statement. */ + tree default_def; + + /* During into-ssa and the dominator optimizer, this field holds the + current version of this variable (an SSA_NAME). + + This was previously two varrays (one in into-ssa the other in the + dominator optimizer). That is wasteful, particularly since the + dominator optimizer calls into-ssa resulting in having two varrays + live at the same time and this can happen for each call to the + dominator optimizer. */ + tree current_def; +}; + + +struct dataflow_d GTY(()) +{ + /* Immediate uses. This is a list of all the statements and PHI nodes + that are immediately reached by the definitions made in this + statement. */ + varray_type immediate_uses; + + /* Use this array for very small numbers of uses instead of the varray. */ + tree uses[2]; + + /* Reached uses. This is a list of all the possible program statements + that may be reached directly or indirectly by definitions made in this + statement. Notice that this is a superset of IMMEDIATE_USES. + For instance, given the following piece of code: + + 1 a1 = 10; + 2 if (a1 > 3) + 3 a2 = a1 + 5; + 4 a3 = PHI (a1, a2) + 5 b1 = a3 - 2; + + IMMEDIATE_USES for statement #1 are all those statements that use a1 + directly (i.e., #2, #3 and #4). REACHED_USES for statement #1 also + includes statement #5 because 'a1' could reach 'a3' via the PHI node + at statement #4. The set of REACHED_USES is then the transitive + closure over all the PHI nodes in the IMMEDIATE_USES set. */ + + /* Reaching definitions. Similarly to REACHED_USES, the set + REACHING_DEFS is the set of all the statements that make definitions + that may reach this statement. Notice that we don't need to have a + similar entry for immediate definitions, as these are represented by + the SSA_NAME nodes themselves (each SSA_NAME node contains a pointer + to the statement that makes that definition). */ +}; + +typedef struct dataflow_d *dataflow_t; + + +struct stmt_ann_d GTY(()) +{ + struct tree_ann_common_d common; + + /* Nonzero if the statement has been modified (meaning that the operands + need to be scanned again). */ + unsigned modified : 1; + + /* Nonzero if the statement is in the CCP worklist and has not been + "cancelled". If we ever need to use this bit outside CCP, then + it should be renamed. */ + unsigned in_ccp_worklist: 1; + + /* Nonzero if the statement makes aliased loads. */ + unsigned makes_aliased_loads : 1; + + /* Nonzero if the statement makes aliased stores. */ + unsigned makes_aliased_stores : 1; + + /* Nonzero if the statement makes references to volatile storage. */ + unsigned has_volatile_ops : 1; + + /* Nonzero if the statement makes a function call that may clobber global + and local addressable variables. */ + unsigned makes_clobbering_call : 1; + + /* Basic block that contains this statement. */ + basic_block GTY ((skip (""))) bb; + + /* Statement operands. */ + struct def_optype_d * GTY (()) def_ops; + struct use_optype_d * GTY (()) use_ops; + + /* Virtual operands (VDEF and VUSE). */ + struct vdef_optype_d * GTY (()) vdef_ops; + struct vuse_optype_d * GTY (()) vuse_ops; + + /* Dataflow information. */ + dataflow_t df; + + /* Set of variables that have had their address taken in the statement. */ + bitmap addresses_taken; + + /* Unique identifier for this statement. These ID's are to be created + by each pass on an as-needed basis in any order convenient for the + pass which needs statement UIDs. */ + unsigned int uid; +}; + + +struct ssa_name_ann_d GTY(()) +{ + struct tree_ann_common_d common; + + /* Nonzero if points-to analysis couldn't determine where this pointer + is pointing to. */ + unsigned int pt_anything : 1; + + /* Nonzero if this pointer is the result of a call to malloc. */ + unsigned int pt_malloc : 1; + + /* Nonzero if the value of this pointer escapes the current function. */ + unsigned int value_escapes_p : 1; + + /* Set of variables that this pointer may point to. */ + bitmap pt_vars; + + /* If this pointer has been dereferenced, and points-to information is + more precise than type-based aliasing, indirect references to this + pointer will be represented by this memory tag, instead of the type + tag computed by TBAA. */ + tree name_mem_tag; +}; + + +union tree_ann_d GTY((desc ("ann_type ((tree_ann)&%h)"))) +{ + struct tree_ann_common_d GTY((tag ("TREE_ANN_COMMON"))) common; + struct var_ann_d GTY((tag ("VAR_ANN"))) decl; + struct stmt_ann_d GTY((tag ("STMT_ANN"))) stmt; + struct ssa_name_ann_d GTY((tag ("SSA_NAME_ANN"))) ssa_name; +}; + +typedef union tree_ann_d *tree_ann; +typedef struct var_ann_d *var_ann_t; +typedef struct stmt_ann_d *stmt_ann_t; +typedef struct ssa_name_ann_d *ssa_name_ann_t; + +static inline var_ann_t var_ann (tree); +static inline var_ann_t get_var_ann (tree); +static inline stmt_ann_t stmt_ann (tree); +static inline stmt_ann_t get_stmt_ann (tree); +static inline ssa_name_ann_t ssa_name_ann (tree); +static inline ssa_name_ann_t get_ssa_name_ann (tree); +static inline enum tree_ann_type ann_type (tree_ann); +static inline basic_block bb_for_stmt (tree); +extern void set_bb_for_stmt (tree, basic_block); +static inline void modify_stmt (tree); +static inline void unmodify_stmt (tree); +static inline bool stmt_modified_p (tree); +static inline varray_type may_aliases (tree); +static inline int get_lineno (tree); +static inline const char *get_filename (tree); +static inline bool is_exec_stmt (tree); +static inline bool is_label_stmt (tree); +static inline vdef_optype get_vdef_ops (stmt_ann_t); +static inline vuse_optype get_vuse_ops (stmt_ann_t); +static inline use_optype get_use_ops (stmt_ann_t); +static inline def_optype get_def_ops (stmt_ann_t); +static inline bitmap addresses_taken (tree); +static inline int num_immediate_uses (dataflow_t); +static inline tree immediate_use (dataflow_t, int); +static inline dataflow_t get_immediate_uses (tree); +static inline bool has_hidden_use (tree); +static inline void set_has_hidden_use (tree); +static inline void set_default_def (tree, tree); +static inline tree default_def (tree); +static inline bool may_be_aliased (tree); + +/*--------------------------------------------------------------------------- + Structure representing predictions in tree level. +---------------------------------------------------------------------------*/ +struct edge_prediction GTY((chain_next ("%h.next"))) +{ + struct edge_prediction *next; + edge edge; + enum br_predictor predictor; + int probability; +}; + +/*--------------------------------------------------------------------------- + Block annotations stored in basic_block.tree_annotations +---------------------------------------------------------------------------*/ +struct bb_ann_d GTY(()) +{ + /* Chain of PHI nodes for this block. */ + tree phi_nodes; + + /* Chain of EPHI nodes created in this block. */ + tree ephi_nodes; + + /* Number of predecessors for this block. This is only valid during + SSA rewriting. It is not maintained after conversion into SSA form. */ + int num_preds; + + /* Nonzero if this block is forwardable during cfg cleanups. This is also + used to detect loops during cfg cleanups. */ + unsigned forwardable: 1; + + /* Nonzero if this block contains an escape point (see is_escape_site). */ + unsigned has_escape_site : 1; + + struct edge_prediction *predictions; +}; + +typedef struct bb_ann_d *bb_ann_t; + +/* Accessors for basic block annotations. */ +static inline bb_ann_t bb_ann (basic_block); +static inline tree phi_nodes (basic_block); +static inline void set_phi_nodes (basic_block, tree); + +/*--------------------------------------------------------------------------- + Global declarations +---------------------------------------------------------------------------*/ +/* Array of all variables referenced in the function. */ +extern GTY(()) varray_type referenced_vars; + +#define num_referenced_vars VARRAY_ACTIVE_SIZE (referenced_vars) +#define referenced_var(i) VARRAY_TREE (referenced_vars, i) + +/* Artificial variable used to model the effects of function calls. */ +extern GTY(()) tree global_var; + +/* Call clobbered variables in the function. If bit I is set, then + REFERENCED_VARS (I) is call-clobbered. */ +extern bitmap call_clobbered_vars; + +/* 'true' after aliases have been computed (see compute_may_aliases). */ +extern bool aliases_computed_p; + +/* Macros for showing usage statistics. */ +#define SCALE(x) ((unsigned long) ((x) < 1024*10 \ + ? (x) \ + : ((x) < 1024*1024*10 \ + ? (x) / 1024 \ + : (x) / (1024*1024)))) + +#define LABEL(x) ((x) < 1024*10 ? 'b' : ((x) < 1024*1024*10 ? 'k' : 'M')) + +#define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y)) + + +/*--------------------------------------------------------------------------- + Block iterators +---------------------------------------------------------------------------*/ + +typedef struct { + tree_stmt_iterator tsi; + basic_block bb; +} block_stmt_iterator; + +static inline block_stmt_iterator bsi_start (basic_block); +static inline block_stmt_iterator bsi_last (basic_block); +static inline bool bsi_end_p (block_stmt_iterator); +static inline void bsi_next (block_stmt_iterator *); +static inline void bsi_prev (block_stmt_iterator *); +static inline tree bsi_stmt (block_stmt_iterator); +static inline tree * bsi_stmt_ptr (block_stmt_iterator); + +extern void bsi_remove (block_stmt_iterator *); +extern void bsi_move_before (block_stmt_iterator *, block_stmt_iterator *); +extern void bsi_move_after (block_stmt_iterator *, block_stmt_iterator *); +extern void bsi_move_to_bb_end (block_stmt_iterator *, basic_block); + +enum bsi_iterator_update +{ + /* Note that these are intentionally in the same order as TSI_FOO. They + mean exactly the same as their TSI_* counterparts. */ + BSI_NEW_STMT, + BSI_SAME_STMT, + BSI_CHAIN_START, + BSI_CHAIN_END, + BSI_CONTINUE_LINKING +}; + +extern void bsi_insert_before (block_stmt_iterator *, tree, + enum bsi_iterator_update); +extern void bsi_insert_after (block_stmt_iterator *, tree, + enum bsi_iterator_update); + +extern void bsi_replace (const block_stmt_iterator *, tree, bool); + +/*--------------------------------------------------------------------------- + Function prototypes +---------------------------------------------------------------------------*/ +/* In tree-cfg.c */ + +/* Location to track pending stmt for edge insertion. */ +#define PENDING_STMT(e) ((e)->insns.t) + +extern void delete_tree_cfg (void); +extern void disband_implicit_edges (void); +extern bool stmt_ends_bb_p (tree); +extern bool is_ctrl_stmt (tree); +extern bool is_ctrl_altering_stmt (tree); +extern bool computed_goto_p (tree); +extern bool simple_goto_p (tree); +extern void tree_dump_bb (basic_block, FILE *, int); +extern void debug_tree_bb (basic_block); +extern basic_block debug_tree_bb_n (int); +extern void dump_tree_cfg (FILE *, int); +extern void debug_tree_cfg (int); +extern void dump_cfg_stats (FILE *); +extern void debug_cfg_stats (void); +extern void debug_loop_ir (void); +extern void print_loop_ir (FILE *); +extern void cleanup_tree_cfg (void); +extern tree first_stmt (basic_block); +extern tree last_stmt (basic_block); +extern tree *last_stmt_ptr (basic_block); +extern tree last_and_only_stmt (basic_block); +extern edge find_taken_edge (basic_block, tree); +extern void cfg_remove_useless_stmts (void); +extern edge thread_edge (edge, basic_block); +extern basic_block label_to_block (tree); +extern void tree_optimize_tail_calls (bool, enum tree_dump_index); +extern edge tree_block_forwards_to (basic_block bb); +extern void bsi_insert_on_edge (edge, tree); +extern void bsi_commit_edge_inserts (int *); +extern void notice_special_calls (tree); +extern void clear_special_calls (void); +extern void compute_dominance_frontiers (bitmap *); +extern void verify_stmts (void); +extern void extract_true_false_edges_from_block (basic_block, edge *, edge *); + +/* In tree-pretty-print.c. */ +extern void dump_generic_bb (FILE *, basic_block, int, int); + +/* In tree-dfa.c */ +extern var_ann_t create_var_ann (tree); +extern stmt_ann_t create_stmt_ann (tree); +extern ssa_name_ann_t create_ssa_name_ann (tree); +extern tree create_phi_node (tree, basic_block); +extern void add_phi_arg (tree *, tree, edge); +extern void remove_phi_arg (tree, basic_block); +extern void remove_phi_arg_num (tree, int); +extern void remove_phi_node (tree, tree, basic_block); +extern void remove_all_phi_nodes_for (bitmap); +extern void dump_dfa_stats (FILE *); +extern void debug_dfa_stats (void); +extern void debug_referenced_vars (void); +extern void dump_referenced_vars (FILE *); +extern void dump_variable (FILE *, tree); +extern void debug_variable (tree); +extern void dump_immediate_uses (FILE *); +extern void debug_immediate_uses (void); +extern void dump_immediate_uses_for (FILE *, tree); +extern void debug_immediate_uses_for (tree); +extern void compute_immediate_uses (int, bool (*)(tree)); +extern void free_df (void); +extern tree get_virtual_var (tree); +extern void add_referenced_tmp_var (tree var); +extern void mark_new_vars_to_rename (tree, bitmap); +extern void redirect_immediate_uses (tree, tree); + +/* Flags used when computing reaching definitions and reached uses. */ +#define TDFA_USE_OPS 1 << 0 +#define TDFA_USE_VOPS 1 << 1 + +/* In gimple-low.c */ +struct lower_data; +extern void lower_stmt_body (tree, struct lower_data *); +extern void expand_used_vars (void); +extern void record_vars (tree); +extern bool block_may_fallthru (tree block); + +/* In tree-ssa-alias.c */ +extern void dump_may_aliases_for (FILE *, tree); +extern void debug_may_aliases_for (tree); +extern void dump_alias_info (FILE *); +extern void debug_alias_info (void); +extern void dump_points_to_info (FILE *); +extern void debug_points_to_info (void); + +/* Call-back function for walk_use_def_chains(). At each reaching + definition, a function with this prototype is called. */ +typedef bool (*walk_use_def_chains_fn) (tree, tree, void *); + +/* In tree-ssa.c */ +extern void init_tree_ssa (void); +extern void rewrite_vars_out_of_ssa (bitmap); +extern void dump_reaching_defs (FILE *); +extern void debug_reaching_defs (void); +extern void dump_tree_ssa (FILE *); +extern void debug_tree_ssa (void); +extern void debug_def_blocks (void); +extern void dump_tree_ssa_stats (FILE *); +extern void debug_tree_ssa_stats (void); +extern void ssa_remove_edge (edge); +extern edge ssa_redirect_edge (edge, basic_block); +extern void set_is_used (tree); +extern bool tree_ssa_useless_type_conversion (tree); +extern bool tree_ssa_useless_type_conversion_1 (tree, tree); +extern void verify_ssa (void); +extern void delete_tree_ssa (void); +extern void register_new_def (tree, varray_type *); +extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *); + +/* In tree-into-ssa.c */ +extern void rewrite_into_ssa (void); + +extern unsigned int highest_ssa_version; + +/* In tree-ssa-pre.c */ +extern void tree_perform_ssapre (tree, enum tree_dump_index); + +/* In tree-ssa-ccp.c */ +bool fold_stmt (tree *); +tree widen_bitfield (tree, tree, tree); + +/* In tree-ssa-dom.c */ +extern void dump_dominator_optimization_stats (FILE *); +extern void debug_dominator_optimization_stats (void); + +/* In tree-ssa-copy.c */ +extern void propagate_value (tree *, tree); +extern void replace_exp (tree *, tree); +extern bool cprop_into_stmt (tree, varray_type); +extern void cprop_into_successor_phis (basic_block, varray_type); + +/* In tree-flow-inline.h */ +static inline int phi_arg_from_edge (tree, edge); +static inline struct phi_arg_d *phi_element_for_edge (tree, edge); +static inline bool may_propagate_copy (tree, tree); +static inline bool is_call_clobbered (tree); +static inline void mark_call_clobbered (tree); + +/* In tree-eh.c */ +extern void make_eh_edges (tree); +extern bool tree_could_trap_p (tree); +extern bool tree_could_throw_p (tree); +extern bool tree_can_throw_internal (tree); +extern bool tree_can_throw_external (tree); +extern void add_stmt_to_eh_region (tree, int); + +#include "tree-flow-inline.h" + +#endif /* _TREE_FLOW_H */ diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 622ae18a548..feb395f5c4b 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -39,17 +39,14 @@ Boston, MA 02111-1307, USA. */ #include "langhooks.h" #include "cgraph.h" #include "intl.h" -#include "diagnostic.h" +#include "tree-mudflap.h" #include "function.h" +#include "diagnostic.h" -/* This should be eventually be generalized to other languages, but - this would require a shared function-as-trees infrastructure. */ -#ifndef INLINER_FOR_JAVA -#include "c-common.h" -#else /* INLINER_FOR_JAVA */ -#include "parse.h" -#include "java-tree.h" -#endif /* INLINER_FOR_JAVA */ +/* I'm not real happy about this, but we need to handle gimple and + non-gimple trees. */ +#include "tree-iterator.h" +#include "tree-simple.h" /* 0 if we should not perform inlining. 1 if we should expand functions calls inline at the tree level. @@ -88,6 +85,8 @@ typedef struct inline_data this value is NULL, then return statements will simply be remapped as return statements, rather than as jumps. */ tree ret_label; + /* The VAR_DECL for the return value. */ + tree retvar; /* The map from local declarations in the inlined function to equivalents in the function into which it is being inlined. */ splay_tree decl_map; @@ -110,10 +109,19 @@ typedef struct inline_data struct cgraph_node *node; /* Callgraph node of currently inlined function. */ struct cgraph_node *current_node; + /* Statement iterator. We need this so we can keep the tree in + gimple form when we insert the inlined function. It is not + used when we are not dealing with gimple trees. */ + tree_stmt_iterator tsi; } inline_data; /* Prototypes. */ +/* The approximate number of instructions per statement. This number + need not be particularly accurate; it is used only to make + decisions about when a function is too big to inline. */ +#define INSNS_PER_STMT (10) + static tree declare_return_variable (inline_data *, tree, tree *); static tree copy_body_r (tree *, int *, void *); static tree copy_body (inline_data *); @@ -122,15 +130,14 @@ static void expand_calls_inline (tree *, inline_data *); static bool inlinable_function_p (tree); static tree remap_decl (tree, inline_data *); static tree remap_type (tree, inline_data *); -#ifndef INLINER_FOR_JAVA -static tree initialize_inlined_parameters (inline_data *, tree, tree); -static void remap_block (tree, tree, inline_data *); -static void copy_scope_stmt (tree *, int *, inline_data *); -#else /* INLINER_FOR_JAVA */ -static tree initialize_inlined_parameters (inline_data *, tree, tree, tree); -static void remap_block (tree *, tree, inline_data *); -static tree add_stmt_to_compound (tree, tree, tree); -#endif /* INLINER_FOR_JAVA */ +static tree initialize_inlined_parameters (inline_data *, tree, + tree, tree, tree); +static void remap_block (tree *, inline_data *); +static tree remap_decls (tree, inline_data *); +static void copy_bind_expr (tree *, int *, inline_data *); +static tree mark_local_for_remap_r (tree *, int *, void *); +static tree unsave_r (tree *, int *, void *); +static void declare_inline_vars (tree bind_expr, tree vars); /* Insert a tree->tree mapping for ID. Despite the name suggests that the trees should be variables, it is used for more than that. */ @@ -158,8 +165,13 @@ remap_decl (tree decl, inline_data *id) /* We only remap local variables in the current function. */ fn = VARRAY_TOP_TREE (id->fns); +#if 0 + /* We need to remap statics, too, so that they get expanded even if the + inline function is never emitted out of line. We might as well also + remap extern decls so that they show up in the debug info. */ if (! lang_hooks.tree_inlining.auto_var_in_fn_p (decl, fn)) return NULL_TREE; +#endif /* See if we have remapped this declaration. */ n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl); @@ -185,7 +197,8 @@ remap_decl (tree decl, inline_data *id) walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL); walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id, NULL); -#ifndef INLINER_FOR_JAVA +#if 0 + /* FIXME handle anon aggrs. */ if (! DECL_NAME (t) && TREE_TYPE (t) && lang_hooks.tree_inlining.anon_aggr_type_p (TREE_TYPE (t))) { @@ -205,7 +218,7 @@ remap_decl (tree decl, inline_data *id) } DECL_ANON_UNION_ELEMS (t) = nreverse (members); } -#endif /* not INLINER_FOR_JAVA */ +#endif /* Remember it, so that if we encounter this local entity again we can reuse this copy. */ @@ -213,7 +226,7 @@ remap_decl (tree decl, inline_data *id) return t; } - return (tree) n->value; + return unshare_expr ((tree) n->value); } static tree @@ -320,115 +333,47 @@ remap_type (tree type, inline_data *id) return new; } -#ifndef INLINER_FOR_JAVA -/* Copy the SCOPE_STMT_BLOCK associated with SCOPE_STMT to contain - remapped versions of the variables therein. And hook the new block - into the block-tree. If non-NULL, the DECLS are declarations to - add to use instead of the BLOCK_VARS in the old block. */ -#else /* INLINER_FOR_JAVA */ -/* Copy the BLOCK to contain remapped versions of the variables - therein. And hook the new block into the block-tree. */ -#endif /* INLINER_FOR_JAVA */ - -static void -#ifndef INLINER_FOR_JAVA -remap_block (tree scope_stmt, tree decls, inline_data *id) -#else /* INLINER_FOR_JAVA */ -remap_block (tree *block, tree decls, inline_data *id) -#endif /* INLINER_FOR_JAVA */ +static tree +remap_decls (tree decls, inline_data *id) { -#ifndef INLINER_FOR_JAVA - /* We cannot do this in the cleanup for a TARGET_EXPR since we do - not know whether or not expand_expr will actually write out the - code we put there. If it does not, then we'll have more BLOCKs - than block-notes, and things will go awry. At some point, we - should make the back-end handle BLOCK notes in a tidier way, - without requiring a strict correspondence to the block-tree; then - this check can go. */ - if (id->in_target_cleanup_p) - { - SCOPE_STMT_BLOCK (scope_stmt) = NULL_TREE; - return; - } + tree old_var; + tree new_decls = NULL_TREE; - /* If this is the beginning of a scope, remap the associated BLOCK. */ - if (SCOPE_BEGIN_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt)) + /* Remap its variables. */ + for (old_var = decls; old_var; old_var = TREE_CHAIN (old_var)) { - tree old_block; - tree new_block; - tree old_var; - tree fn; - - /* Make the new block. */ - old_block = SCOPE_STMT_BLOCK (scope_stmt); - new_block = make_node (BLOCK); - TREE_USED (new_block) = TREE_USED (old_block); - BLOCK_ABSTRACT_ORIGIN (new_block) = old_block; - SCOPE_STMT_BLOCK (scope_stmt) = new_block; - - /* Remap its variables. */ - for (old_var = decls ? decls : BLOCK_VARS (old_block); - old_var; - old_var = TREE_CHAIN (old_var)) - { - tree new_var; - - /* Remap the variable. */ - new_var = remap_decl (old_var, id); - /* If we didn't remap this variable, so we can't mess with - its TREE_CHAIN. If we remapped this variable to - something other than a declaration (say, if we mapped it - to a constant), then we must similarly omit any mention - of it here. */ - if (!new_var || !DECL_P (new_var)) - ; - else - { - TREE_CHAIN (new_var) = BLOCK_VARS (new_block); - BLOCK_VARS (new_block) = new_var; - } - } - /* We put the BLOCK_VARS in reverse order; fix that now. */ - BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block)); - fn = VARRAY_TREE (id->fns, 0); - if (id->cloning_p) - /* We're building a clone; DECL_INITIAL is still - error_mark_node, and current_binding_level is the parm - binding level. */ - lang_hooks.decls.insert_block (new_block); + tree new_var; + + /* Remap the variable. */ + new_var = remap_decl (old_var, id); + + /* If we didn't remap this variable, so we can't mess with its + TREE_CHAIN. If we remapped this variable to the return slot, it's + already declared somewhere else, so don't declare it here. */ + if (!new_var || new_var == id->retvar) + ; +#ifdef ENABLE_CHECKING + else if (!DECL_P (new_var)) + abort (); +#endif else { - /* Attach this new block after the DECL_INITIAL block for the - function into which this block is being inlined. In - rest_of_compilation we will straighten out the BLOCK tree. */ - tree *first_block; - if (DECL_INITIAL (fn)) - first_block = &BLOCK_CHAIN (DECL_INITIAL (fn)); - else - first_block = &DECL_INITIAL (fn); - BLOCK_CHAIN (new_block) = *first_block; - *first_block = new_block; + TREE_CHAIN (new_var) = new_decls; + new_decls = new_var; } - /* Remember the remapped block. */ - insert_decl_map (id, old_block, new_block); } - /* If this is the end of a scope, set the SCOPE_STMT_BLOCK to be the - remapped block. */ - else if (SCOPE_END_P (scope_stmt) && SCOPE_STMT_BLOCK (scope_stmt)) - { - splay_tree_node n; - /* Find this block in the table of remapped things. */ - n = splay_tree_lookup (id->decl_map, - (splay_tree_key) SCOPE_STMT_BLOCK (scope_stmt)); - if (! n) - abort (); - SCOPE_STMT_BLOCK (scope_stmt) = (tree) n->value; - } -#else /* INLINER_FOR_JAVA */ + return nreverse (new_decls); +} + +/* Copy the BLOCK to contain remapped versions of the variables + therein. And hook the new block into the block-tree. */ + +static void +remap_block (tree *block, inline_data *id) +{ tree old_block; tree new_block; - tree old_var; tree fn; /* Make the new block. */ @@ -436,82 +381,70 @@ remap_block (tree *block, tree decls, inline_data *id) new_block = make_node (BLOCK); TREE_USED (new_block) = TREE_USED (old_block); BLOCK_ABSTRACT_ORIGIN (new_block) = old_block; - BLOCK_SUBBLOCKS (new_block) = BLOCK_SUBBLOCKS (old_block); - TREE_SIDE_EFFECTS (new_block) = TREE_SIDE_EFFECTS (old_block); - TREE_TYPE (new_block) = TREE_TYPE (old_block); *block = new_block; /* Remap its variables. */ - for (old_var = decls ? decls : BLOCK_VARS (old_block); - old_var; - old_var = TREE_CHAIN (old_var)) - { - tree new_var; + BLOCK_VARS (new_block) = remap_decls (BLOCK_VARS (old_block), id); - /* All local class initialization flags go in the outermost - scope. */ - if (LOCAL_CLASS_INITIALIZATION_FLAG_P (old_var)) - { - /* We may already have one. */ - if (! splay_tree_lookup (id->decl_map, (splay_tree_key) old_var)) - { - tree outermost_block; - new_var = remap_decl (old_var, id); - DECL_ABSTRACT_ORIGIN (new_var) = NULL; - outermost_block = DECL_SAVED_TREE (current_function_decl); - TREE_CHAIN (new_var) = BLOCK_VARS (outermost_block); - BLOCK_VARS (outermost_block) = new_var; - } - continue; - } - - /* Remap the variable. */ - new_var = remap_decl (old_var, id); - /* If we didn't remap this variable, so we can't mess with - its TREE_CHAIN. If we remapped this variable to - something other than a declaration (say, if we mapped it - to a constant), then we must similarly omit any mention - of it here. */ - if (!new_var || !DECL_P (new_var)) - ; + fn = VARRAY_TREE (id->fns, 0); +#if 1 + /* FIXME! It shouldn't be so hard to manage blocks. Rebuilding them in + rest_of_compilation is a good start. */ + if (id->cloning_p) + /* We're building a clone; DECL_INITIAL is still + error_mark_node, and current_binding_level is the parm + binding level. */ + (*lang_hooks.decls.insert_block) (new_block); + else + { + /* Attach this new block after the DECL_INITIAL block for the + function into which this block is being inlined. In + rest_of_compilation we will straighten out the BLOCK tree. */ + tree *first_block; + if (DECL_INITIAL (fn)) + first_block = &BLOCK_CHAIN (DECL_INITIAL (fn)); else - { - TREE_CHAIN (new_var) = BLOCK_VARS (new_block); - BLOCK_VARS (new_block) = new_var; - } + first_block = &DECL_INITIAL (fn); + BLOCK_CHAIN (new_block) = *first_block; + *first_block = new_block; } - /* We put the BLOCK_VARS in reverse order; fix that now. */ - BLOCK_VARS (new_block) = nreverse (BLOCK_VARS (new_block)); - fn = VARRAY_TREE (id->fns, 0); +#endif /* Remember the remapped block. */ - splay_tree_insert (id->decl_map, - (splay_tree_key) old_block, - (splay_tree_value) new_block); -#endif /* INLINER_FOR_JAVA */ + insert_decl_map (id, old_block, new_block); } -#ifndef INLINER_FOR_JAVA -/* Copy the SCOPE_STMT pointed to by TP. */ - static void -copy_scope_stmt (tree *tp, int *walk_subtrees, inline_data *id) +copy_statement_list (tree *tp) { - tree block; + tree_stmt_iterator oi, ni; + tree new; + + new = alloc_stmt_list (); + ni = tsi_start (new); + oi = tsi_start (*tp); + *tp = new; + + for (; !tsi_end_p (oi); tsi_next (&oi)) + tsi_link_after (&ni, tsi_stmt (oi), TSI_NEW_STMT); +} - /* Remember whether or not this statement was nullified. When - making a copy, copy_tree_r always sets SCOPE_NULLIFIED_P (and - doesn't copy the SCOPE_STMT_BLOCK) to free callers from having to - deal with copying BLOCKs if they do not wish to do so. */ - block = SCOPE_STMT_BLOCK (*tp); +static void +copy_bind_expr (tree *tp, int *walk_subtrees, inline_data *id) +{ + tree block = BIND_EXPR_BLOCK (*tp); /* Copy (and replace) the statement. */ copy_tree_r (tp, walk_subtrees, NULL); - /* Restore the SCOPE_STMT_BLOCK. */ - SCOPE_STMT_BLOCK (*tp) = block; + if (block) + { + remap_block (&block, id); + BIND_EXPR_BLOCK (*tp) = block; + } - /* Remap the associated block. */ - remap_block (*tp, NULL_TREE, id); + if (BIND_EXPR_VARS (*tp)) + /* This will remap a lot of the same decls again, but this should be + harmless. */ + BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), id); } -#endif /* not INLINER_FOR_JAVA */ /* Called from copy_body via walk_tree. DATA is really an `inline_data *'. */ @@ -534,60 +467,36 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) abort (); #endif -#ifdef INLINER_FOR_JAVA - if (TREE_CODE (*tp) == BLOCK) - remap_block (tp, NULL_TREE, id); -#endif - /* If this is a RETURN_STMT, change it into an EXPR_STMT and a GOTO_STMT with the RET_LABEL as its target. */ -#ifndef INLINER_FOR_JAVA - if (TREE_CODE (*tp) == RETURN_STMT && id->ret_label && !id->saving_p) -#else /* INLINER_FOR_JAVA */ - if (TREE_CODE (*tp) == RETURN_EXPR && id->ret_label && !id->saving_p) -#endif /* INLINER_FOR_JAVA */ + if (TREE_CODE (*tp) == RETURN_EXPR && id->ret_label) { tree return_stmt = *tp; tree goto_stmt; - /* Build the GOTO_STMT. */ -#ifndef INLINER_FOR_JAVA - goto_stmt = build_stmt (GOTO_STMT, id->ret_label); - TREE_CHAIN (goto_stmt) = TREE_CHAIN (return_stmt); - GOTO_FAKE_P (goto_stmt) = 1; -#else /* INLINER_FOR_JAVA */ + /* Build the GOTO_EXPR. */ tree assignment = TREE_OPERAND (return_stmt, 0); goto_stmt = build1 (GOTO_EXPR, void_type_node, id->ret_label); - TREE_SIDE_EFFECTS (goto_stmt) = 1; -#endif /* INLINER_FOR_JAVA */ + TREE_USED (id->ret_label) = 1; /* If we're returning something, just turn that into an assignment into the equivalent of the original RESULT_DECL. */ -#ifndef INLINER_FOR_JAVA - if (RETURN_STMT_EXPR (return_stmt)) - { - *tp = build_stmt (EXPR_STMT, - RETURN_STMT_EXPR (return_stmt)); - STMT_IS_FULL_EXPR_P (*tp) = 1; - /* And then jump to the end of the function. */ - TREE_CHAIN (*tp) = goto_stmt; - } -#else /* INLINER_FOR_JAVA */ if (assignment) - { - copy_body_r (&assignment, walk_subtrees, data); - *tp = build (COMPOUND_EXPR, void_type_node, assignment, goto_stmt); - TREE_SIDE_EFFECTS (*tp) = 1; - } -#endif /* INLINER_FOR_JAVA */ + { + /* Do not create a statement containing a naked RESULT_DECL. */ + if (lang_hooks.gimple_before_inlining) + if (TREE_CODE (assignment) == RESULT_DECL) + gimplify_stmt (&assignment); + + *tp = build (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE, + make_node (BLOCK)); + append_to_statement_list (assignment, &BIND_EXPR_BODY (*tp)); + append_to_statement_list (goto_stmt, &BIND_EXPR_BODY (*tp)); + } /* If we're not returning anything just do the jump. */ else *tp = goto_stmt; - - /* We can't replace return label while inlining function - because it is in the outer function. */ - insert_decl_map (id, id->ret_label, id->ret_label); } /* Local variables and labels need to be replaced by equivalent variables. We don't want to copy static variables; there's only @@ -610,18 +519,16 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) && DECL_CONTEXT (*tp) != VARRAY_TREE (id->fns, 0)) abort (); #endif + else if (TREE_CODE (*tp) == STATEMENT_LIST) + copy_statement_list (tp); else if (TREE_CODE (*tp) == SAVE_EXPR) remap_save_expr (tp, id->decl_map, VARRAY_TREE (id->fns, 0), walk_subtrees); else if (TREE_CODE (*tp) == UNSAVE_EXPR) /* UNSAVE_EXPRs should not be generated until expansion time. */ abort (); -#ifndef INLINER_FOR_JAVA - /* For a SCOPE_STMT, we must copy the associated block so that we - can write out debugging information for the inlined variables. */ - else if (TREE_CODE (*tp) == SCOPE_STMT && !id->in_target_cleanup_p) - copy_scope_stmt (tp, walk_subtrees, id); -#else /* INLINER_FOR_JAVA */ + else if (TREE_CODE (*tp) == BIND_EXPR) + copy_bind_expr (tp, walk_subtrees, id); else if (TREE_CODE (*tp) == LABELED_BLOCK_EXPR) { /* We need a new copy of this labeled block; the EXIT_BLOCK_EXPR @@ -642,7 +549,6 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) *tp = copy_node (*tp); TREE_OPERAND (*tp, 0) = (tree) n->value; } -#endif /* INLINER_FOR_JAVA */ /* Types may need remapping as well. */ else if (TYPE_P (*tp)) *tp = remap_type (*tp, id); @@ -692,7 +598,32 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) value = (tree) n->value; if (TREE_CODE (value) == INDIRECT_REF) { - *tp = convert (TREE_TYPE (*tp), TREE_OPERAND (value, 0)); + /* Assume that the argument types properly match the + parameter types. We can't compare them well enough + without a comptypes langhook, and we don't want to + call convert and introduce a NOP_EXPR to convert + between two equivalent types (i.e. that only differ + in use of typedef names). */ + *tp = TREE_OPERAND (value, 0); + return copy_body_r (tp, walk_subtrees, data); + } + } + } + else if (TREE_CODE (*tp) == INDIRECT_REF) + { + /* Get rid of *& from inline substitutions that can happen when a + pointer argument is an ADDR_EXPR. */ + tree decl = TREE_OPERAND (*tp, 0), value; + splay_tree_node n; + + n = splay_tree_lookup (id->decl_map, (splay_tree_key) decl); + if (n) + { + value = (tree) n->value; + STRIP_NOPS (value); + if (TREE_CODE (value) == ADDR_EXPR) + { + *tp = TREE_OPERAND (value, 0); return copy_body_r (tp, walk_subtrees, data); } } @@ -716,7 +647,7 @@ copy_body_r (tree *tp, int *walk_subtrees, void *data) abort (); } } - else if (!id->cloning_p) + else { struct cgraph_edge *edge; @@ -760,45 +691,142 @@ copy_body (inline_data *id) return body; } +static void +setup_one_parameter (inline_data *id, tree p, tree value, + tree fn, tree *init_stmts, tree *vars, + bool *gimplify_init_stmts_p) +{ + tree init_stmt; + tree var; + tree var_sub; + + /* If the parameter is never assigned to, we may not need to + create a new variable here at all. Instead, we may be able + to just use the argument value. */ + if (TREE_READONLY (p) + && !TREE_ADDRESSABLE (p) + && value && !TREE_SIDE_EFFECTS (value)) + { + /* We can't risk substituting complex expressions. They + might contain variables that will be assigned to later. + Theoretically, we could check the expression to see if + all of the variables that determine its value are + read-only, but we don't bother. */ + if ((TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value)) + /* We may produce non-gimple trees by adding NOPs or introduce + invalid sharing when operand is not really constant. + It is not big deal to prohibit constant propagation here as + we will constant propagate in DOM1 pass anyway. */ + && (!lang_hooks.gimple_before_inlining + || (is_gimple_min_invariant (value) + && TREE_TYPE (value) == TREE_TYPE (p)))) + { + /* If this is a declaration, wrap it a NOP_EXPR so that + we don't try to put the VALUE on the list of BLOCK_VARS. */ + if (DECL_P (value)) + value = build1 (NOP_EXPR, TREE_TYPE (value), value); + + /* If this is a constant, make sure it has the right type. */ + else if (TREE_TYPE (value) != TREE_TYPE (p)) + value = fold (build1 (NOP_EXPR, TREE_TYPE (p), value)); + + insert_decl_map (id, p, value); + return; + } + } + + /* Make an equivalent VAR_DECL. */ + var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0)); + + /* See if the frontend wants to pass this by invisible reference. If + so, our new VAR_DECL will have REFERENCE_TYPE, and we need to + replace uses of the PARM_DECL with dereferences. */ + if (TREE_TYPE (var) != TREE_TYPE (p) + && POINTER_TYPE_P (TREE_TYPE (var)) + && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p)) + { + insert_decl_map (id, var, var); + var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var); + } + else + var_sub = var; + + /* Register the VAR_DECL as the equivalent for the PARM_DECL; + that way, when the PARM_DECL is encountered, it will be + automatically replaced by the VAR_DECL. */ + insert_decl_map (id, p, var_sub); + + /* Declare this new variable. */ + TREE_CHAIN (var) = *vars; + *vars = var; + + /* Make gimplifier happy about this variable. */ + var->decl.seen_in_bind_expr = lang_hooks.gimple_before_inlining; + + /* Even if P was TREE_READONLY, the new VAR should not be. + In the original code, we would have constructed a + temporary, and then the function body would have never + changed the value of P. However, now, we will be + constructing VAR directly. The constructor body may + change its value multiple times as it is being + constructed. Therefore, it must not be TREE_READONLY; + the back-end assumes that TREE_READONLY variable is + assigned to only once. */ + if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p))) + TREE_READONLY (var) = 0; + + /* Initialize this VAR_DECL from the equivalent argument. Convert + the argument to the proper type in case it was promoted. */ + if (value) + { + tree rhs = convert (TREE_TYPE (var), value); + + if (rhs == error_mark_node) + return; + + /* We want to use MODIFY_EXPR, not INIT_EXPR here so that we + keep our trees in gimple form. */ + init_stmt = build (MODIFY_EXPR, TREE_TYPE (var), var, rhs); + append_to_statement_list (init_stmt, init_stmts); + + /* If we did not create a gimple value and we did not create a gimple + cast of a gimple value, then we will need to gimplify INIT_STMTS + at the end. Note that is_gimple_cast only checks the outer + tree code, not its operand. Thus the explicit check that it's + operand is a gimple value. */ + if (!is_gimple_val (rhs) + && (!is_gimple_cast (rhs) + || !is_gimple_val (TREE_OPERAND (rhs, 0)))) + *gimplify_init_stmts_p = true; + } +} + /* Generate code to initialize the parameters of the function at the top of the stack in ID from the ARGS (presented as a TREE_LIST). */ static tree -#ifndef INLINER_FOR_JAVA -initialize_inlined_parameters (inline_data *id, tree args, tree fn) -#else /* INLINER_FOR_JAVA */ -initialize_inlined_parameters (inline_data *id, tree args, tree fn, tree block) -#endif /* INLINER_FOR_JAVA */ +initialize_inlined_parameters (inline_data *id, tree args, tree static_chain, + tree fn, tree bind_expr) { - tree init_stmts; + tree init_stmts = NULL_TREE; tree parms; tree a; tree p; -#ifdef INLINER_FOR_JAVA tree vars = NULL_TREE; -#endif /* INLINER_FOR_JAVA */ + bool gimplify_init_stmts_p = false; int argnum = 0; /* Figure out what the parameters are. */ parms = DECL_ARGUMENTS (fn); - if (fn == current_function_decl && cfun->saved_args) + if (fn == current_function_decl) parms = cfun->saved_args; - /* Start with no initializations whatsoever. */ - init_stmts = NULL_TREE; - /* Loop through the parameter declarations, replacing each with an equivalent VAR_DECL, appropriately initialized. */ for (p = parms, a = args; p; a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p)) { -#ifndef INLINER_FOR_JAVA - tree init_stmt; - tree cleanup; -#endif /* not INLINER_FOR_JAVA */ - tree var; tree value; - tree var_sub; ++argnum; @@ -806,148 +834,34 @@ initialize_inlined_parameters (inline_data *id, tree args, tree fn, tree block) value = lang_hooks.tree_inlining.convert_parm_for_inlining (p, a ? TREE_VALUE (a) : NULL_TREE, fn, argnum); - /* If the parameter is never assigned to, we may not need to - create a new variable here at all. Instead, we may be able - to just use the argument value. */ - if (TREE_READONLY (p) - && !TREE_ADDRESSABLE (p) - && value && !TREE_SIDE_EFFECTS (value)) - { - /* Simplify the value, if possible. */ - value = fold (DECL_P (value) ? decl_constant_value (value) : value); - - /* We can't risk substituting complex expressions. They - might contain variables that will be assigned to later. - Theoretically, we could check the expression to see if - all of the variables that determine its value are - read-only, but we don't bother. */ - if (TREE_CONSTANT (value) || TREE_READONLY_DECL_P (value)) - { - /* If this is a declaration, wrap it a NOP_EXPR so that - we don't try to put the VALUE on the list of - BLOCK_VARS. */ - if (DECL_P (value)) - value = build1 (NOP_EXPR, TREE_TYPE (value), value); - - /* If this is a constant, make sure it has the right type. */ - else if (TREE_TYPE (value) != TREE_TYPE (p)) - value = fold (build1 (NOP_EXPR, TREE_TYPE (p), value)); - - insert_decl_map (id, p, value); - continue; - } - } - - /* Make an equivalent VAR_DECL. */ - var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0)); - - /* See if the frontend wants to pass this by invisible reference. If - so, our new VAR_DECL will have REFERENCE_TYPE, and we need to - replace uses of the PARM_DECL with dereferences. */ - if (TREE_TYPE (var) != TREE_TYPE (p) - && POINTER_TYPE_P (TREE_TYPE (var)) - && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p)) - var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var); - else - var_sub = var; - - /* Register the VAR_DECL as the equivalent for the PARM_DECL; - that way, when the PARM_DECL is encountered, it will be - automatically replaced by the VAR_DECL. */ - insert_decl_map (id, p, var_sub); - - /* Declare this new variable. */ -#ifndef INLINER_FOR_JAVA - init_stmt = build_stmt (DECL_STMT, var); - TREE_CHAIN (init_stmt) = init_stmts; - init_stmts = init_stmt; -#else /* INLINER_FOR_JAVA */ - TREE_CHAIN (var) = vars; - vars = var; -#endif /* INLINER_FOR_JAVA */ - - /* Initialize this VAR_DECL from the equivalent argument. If - the argument is an object, created via a constructor or copy, - this will not result in an extra copy: the TARGET_EXPR - representing the argument will be bound to VAR, and the - object will be constructed in VAR. */ - if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p))) -#ifndef INLINER_FOR_JAVA - DECL_INITIAL (var) = value; - else - { - /* Even if P was TREE_READONLY, the new VAR should not be. - In the original code, we would have constructed a - temporary, and then the function body would have never - changed the value of P. However, now, we will be - constructing VAR directly. The constructor body may - change its value multiple times as it is being - constructed. Therefore, it must not be TREE_READONLY; - the back-end assumes that TREE_READONLY variable is - assigned to only once. */ - TREE_READONLY (var) = 0; - - /* Build a run-time initialization. */ - init_stmt = build_stmt (EXPR_STMT, - build (INIT_EXPR, TREE_TYPE (p), - var, value)); - /* Add this initialization to the list. Note that we want the - declaration *after* the initialization because we are going - to reverse all the initialization statements below. */ - TREE_CHAIN (init_stmt) = init_stmts; - init_stmts = init_stmt; - } - - /* See if we need to clean up the declaration. */ - cleanup = lang_hooks.maybe_build_cleanup (var); - if (cleanup) - { - tree cleanup_stmt; - /* Build the cleanup statement. */ - cleanup_stmt = build_stmt (CLEANUP_STMT, var, cleanup); - /* Add it to the *front* of the list; the list will be - reversed below. */ - TREE_CHAIN (cleanup_stmt) = init_stmts; - init_stmts = cleanup_stmt; - } -#else /* INLINER_FOR_JAVA */ - { - tree assignment = build (MODIFY_EXPR, TREE_TYPE (p), var, value); - init_stmts = add_stmt_to_compound (init_stmts, TREE_TYPE (p), - assignment); - } - else - { - /* Java objects don't ever need constructing when being - passed as arguments because only call by reference is - supported. */ - abort (); - } -#endif /* INLINER_FOR_JAVA */ + setup_one_parameter (id, p, value, fn, &init_stmts, &vars, + &gimplify_init_stmts_p); } -#ifndef INLINER_FOR_JAVA /* Evaluate trailing arguments. */ for (; a; a = TREE_CHAIN (a)) { - tree init_stmt; tree value = TREE_VALUE (a); + append_to_statement_list (value, &init_stmts); + } - if (! value || ! TREE_SIDE_EFFECTS (value)) - continue; + /* Initialize the static chain. */ + p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl; + if (p) + { + /* No static chain? Seems like a bug in tree-nested.c. */ + if (!static_chain) + abort (); - init_stmt = build_stmt (EXPR_STMT, value); - TREE_CHAIN (init_stmt) = init_stmts; - init_stmts = init_stmt; + setup_one_parameter (id, p, static_chain, fn, &init_stmts, &vars, + &gimplify_init_stmts_p); } - /* The initialization statements have been built up in reverse - order. Straighten them out now. */ - return nreverse (init_stmts); -#else /* INLINER_FOR_JAVA */ - BLOCK_VARS (block) = nreverse (vars); + if (gimplify_init_stmts_p && lang_hooks.gimple_before_inlining) + gimplify_body (&init_stmts, fn); + + declare_inline_vars (bind_expr, vars); return init_stmts; -#endif /* INLINER_FOR_JAVA */ } /* Declare a return variable to replace the RESULT_DECL for the @@ -955,71 +869,58 @@ initialize_inlined_parameters (inline_data *id, tree args, tree fn, tree block) The USE_STMT is filled in to contain a use of the declaration to indicate the return value of the function. */ -#ifndef INLINER_FOR_JAVA -static tree -declare_return_variable (struct inline_data *id, tree return_slot_addr, - tree *use_stmt) -#else /* INLINER_FOR_JAVA */ static tree -declare_return_variable (struct inline_data *id, tree return_slot_addr, - tree *var) -#endif /* INLINER_FOR_JAVA */ +declare_return_variable (inline_data *id, tree return_slot_addr, tree *use_p) { tree fn = VARRAY_TOP_TREE (id->fns); tree result = DECL_RESULT (fn); -#ifndef INLINER_FOR_JAVA - tree var; -#endif /* not INLINER_FOR_JAVA */ int need_return_decl = 1; + tree var; /* We don't need to do anything for functions that don't return anything. */ if (!result || VOID_TYPE_P (TREE_TYPE (result))) { -#ifndef INLINER_FOR_JAVA - *use_stmt = NULL_TREE; -#else /* INLINER_FOR_JAVA */ - *var = NULL_TREE; -#endif /* INLINER_FOR_JAVA */ + *use_p = NULL_TREE; return NULL_TREE; } -#ifndef INLINER_FOR_JAVA var = (lang_hooks.tree_inlining.copy_res_decl_for_inlining (result, fn, VARRAY_TREE (id->fns, 0), id->decl_map, &need_return_decl, return_slot_addr)); + + /* Do not have the rest of GCC warn about this variable as it should + not be visible to the user. */ + TREE_NO_WARNING (var) = 1; /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that way, when the RESULT_DECL is encountered, it will be automatically replaced by the VAR_DECL. */ insert_decl_map (id, result, var); - /* Build the USE_STMT. If the return type of the function was + /* Remember this so we can ignore it in remap_decls. */ + id->retvar = var; + + /* Build the use expr. If the return type of the function was promoted, convert it back to the expected type. */ - if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE (fn))) - *use_stmt = build_stmt (EXPR_STMT, var); + if (return_slot_addr) + /* The function returns through an explicit return slot, not a normal + return value. */ + *use_p = NULL_TREE; + else if (TREE_TYPE (var) == TREE_TYPE (TREE_TYPE (fn))) + *use_p = var; + else if (TREE_CODE (var) == INDIRECT_REF) + *use_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (fn)), + TREE_OPERAND (var, 0)); + else if (TREE_ADDRESSABLE (TREE_TYPE (var))) + abort (); else - *use_stmt = build_stmt (EXPR_STMT, - build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), - var)); - TREE_ADDRESSABLE (*use_stmt) = 1; + *use_p = build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), var); /* Build the declaration statement if FN does not return an aggregate. */ if (need_return_decl) - return build_stmt (DECL_STMT, var); -#else /* INLINER_FOR_JAVA */ - *var = (lang_hooks.tree_inlining.copy_res_decl_for_inlining - (result, fn, VARRAY_TREE (id->fns, 0), id->decl_map, - &need_return_decl, return_slot_addr)); - - splay_tree_insert (id->decl_map, - (splay_tree_key) result, - (splay_tree_value) *var); - DECL_IGNORED_P (*var) = 1; - if (need_return_decl) - return *var; -#endif /* INLINER_FOR_JAVA */ + return var; /* If FN does return an aggregate, there's no need to declare the return variable; we're using a variable in our caller's frame. */ else @@ -1073,7 +974,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED, return node; } - if (DECL_BUILT_IN (t)) + if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL) switch (DECL_FUNCTION_CODE (t)) { /* We cannot inline functions that take a variable number of @@ -1082,49 +983,48 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED, case BUILT_IN_STDARG_START: case BUILT_IN_NEXT_ARG: case BUILT_IN_VA_END: - { - inline_forbidden_reason - = N_("%Jfunction '%F' can never be inlined because it " - "uses variable argument lists"); - return node; - } + inline_forbidden_reason + = N_("%Jfunction '%F' can never be inlined because it " + "uses variable argument lists"); + return node; + case BUILT_IN_LONGJMP: - { - /* We can't inline functions that call __builtin_longjmp at - all. The non-local goto machinery really requires the - destination be in a different function. If we allow the - function calling __builtin_longjmp to be inlined into the - function calling __builtin_setjmp, Things will Go Awry. */ - /* ??? Need front end help to identify "regular" non-local - goto. */ - if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL) - { - inline_forbidden_reason - = N_("%Jfunction '%F' can never be inlined because " - "it uses setjmp-longjmp exception handling"); - return node; - } - } + /* We can't inline functions that call __builtin_longjmp at + all. The non-local goto machinery really requires the + destination be in a different function. If we allow the + function calling __builtin_longjmp to be inlined into the + function calling __builtin_setjmp, Things will Go Awry. */ + inline_forbidden_reason + = N_("%Jfunction '%F' can never be inlined because " + "it uses setjmp-longjmp exception handling"); + return node; + + case BUILT_IN_NONLOCAL_GOTO: + /* Similarly. */ + inline_forbidden_reason + = N_("%Jfunction '%F' can never be inlined because " + "it uses non-local goto"); + return node; default: break; } break; -#ifndef INLINER_FOR_JAVA - case DECL_STMT: - /* We cannot inline functions that contain other functions. */ - if (TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL - && DECL_INITIAL (TREE_OPERAND (node, 0))) + case BIND_EXPR: + for (t = BIND_EXPR_VARS (node); t ; t = TREE_CHAIN (t)) { - inline_forbidden_reason - = N_("%Jfunction '%F' can never be inlined " - "because it contains a nested function"); - return node; + /* We cannot inline functions that contain other functions. */ + if (TREE_CODE (t) == FUNCTION_DECL && DECL_INITIAL (t)) + { + inline_forbidden_reason + = N_("%Jfunction '%F' can never be inlined " + "because it contains a nested function"); + return node; + } } break; - case GOTO_STMT: case GOTO_EXPR: t = TREE_OPERAND (node, 0); @@ -1139,17 +1039,19 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED, "because it contains a computed goto"); return node; } + break; - /* We cannot inline a nested function that jumps to a nonlocal - label. */ - if (TREE_CODE (t) == LABEL_DECL && DECL_CONTEXT (t) != fn) + case LABEL_EXPR: + t = TREE_OPERAND (node, 0); + if (DECL_NONLOCAL (t)) { + /* We cannot inline a function that receives a non-local goto + because we cannot remap the destination label used in the + function that is performing the non-local goto. */ inline_forbidden_reason = N_("%Jfunction '%F' can never be inlined " - "because it contains a nonlocal goto"); - return node; + "because it receives a non-local goto"); } - break; case RECORD_TYPE: @@ -1172,7 +1074,7 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED, "because it uses variable sized variables"); return node; } -#endif + default: break; } @@ -1271,6 +1173,223 @@ inlinable_function_p (tree fn) return inlinable; } +/* Used by estimate_num_insns. Estimate number of instructions seen + by given statement. */ +static tree +estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) +{ + int *count = data; + tree x = *tp; + + if (TYPE_P (x) || DECL_P (x)) + { + *walk_subtrees = 0; + return NULL; + } + /* Assume that constants and references counts nothing. These should + be majorized by amount of operations among them we count later + and are common target of CSE and similar optimizations. */ + if (TREE_CODE_CLASS (TREE_CODE (x)) == 'c' + || TREE_CODE_CLASS (TREE_CODE (x)) == 'r') + return NULL; + switch (TREE_CODE (x)) + { + /* Containers have no cost. */ + case TREE_LIST: + case TREE_VEC: + case BLOCK: + case COMPONENT_REF: + case BIT_FIELD_REF: + case INDIRECT_REF: + case BUFFER_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + case VTABLE_REF: + case EXC_PTR_EXPR: /* ??? */ + case FILTER_EXPR: /* ??? */ + case COMPOUND_EXPR: + case BIND_EXPR: + case LABELED_BLOCK_EXPR: + case WITH_CLEANUP_EXPR: + case NOP_EXPR: + case VIEW_CONVERT_EXPR: + case SAVE_EXPR: + case UNSAVE_EXPR: + case ADDR_EXPR: + case REFERENCE_EXPR: + case COMPLEX_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + case EXIT_BLOCK_EXPR: + case CASE_LABEL_EXPR: + case SSA_NAME: + case CATCH_EXPR: + case EH_FILTER_EXPR: + case STATEMENT_LIST: + case ERROR_MARK: + case NON_LVALUE_EXPR: + case ENTRY_VALUE_EXPR: + case FDESC_EXPR: + case VA_ARG_EXPR: + case TRY_CATCH_EXPR: + case TRY_FINALLY_EXPR: + case LABEL_EXPR: + case GOTO_EXPR: + case RETURN_EXPR: + case EXIT_EXPR: + case LOOP_EXPR: + case EUSE_NODE: + case EKILL_NODE: + case EPHI_NODE: + case EEXIT_NODE: + case PHI_NODE: + break; + /* We don't account constants for now. Assume that the cost is amortized + by operations that do use them. We may re-consider this decision once + we are able to optimize the tree before estimating it's size and break + out static initializers. */ + case IDENTIFIER_NODE: + case INTEGER_CST: + case REAL_CST: + case COMPLEX_CST: + case VECTOR_CST: + case STRING_CST: + *walk_subtrees = 0; + return NULL; + /* Recognize assignments of large structures and constructors of + big arrays. */ + case INIT_EXPR: + case TARGET_EXPR: + case MODIFY_EXPR: + case CONSTRUCTOR: + { + HOST_WIDE_INT size; + + size = int_size_in_bytes (TREE_TYPE (x)); + + if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO) + *count += 10; + else + *count += ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES); + } + break; + + /* Assign cost of 1 to usual operations. + ??? We may consider mapping RTL costs to this. */ + case COND_EXPR: + + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + + case NEGATE_EXPR: + case FLOAT_EXPR: + case MIN_EXPR: + case MAX_EXPR: + case ABS_EXPR: + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case BIT_NOT_EXPR: + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case TRUTH_NOT_EXPR: + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case ORDERED_EXPR: + case UNORDERED_EXPR: + + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + + case CONVERT_EXPR: + + case CONJ_EXPR: + + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + + case SWITCH_EXPR: + + case ASM_EXPR: + + case RESX_EXPR: + *count++; + break; + + /* Few special cases of expensive operations. This is usefull + to avoid inlining on functions having too many of these. */ + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case EXACT_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + *count += 10; + break; + case CALL_EXPR: + { + tree decl = get_callee_fndecl (x); + + if (decl && DECL_BUILT_IN (decl)) + switch (DECL_FUNCTION_CODE (decl)) + { + case BUILT_IN_CONSTANT_P: + *walk_subtrees = 0; + return NULL_TREE; + case BUILT_IN_EXPECT: + return NULL_TREE; + default: + break; + } + *count += 10; + break; + } + default: + /* Abort here se we know we don't miss any nodes. */ + abort (); + } + return NULL; +} + +/* Estimate number of instructions that will be created by expanding EXPR. */ +int +estimate_num_insns (tree expr) +{ + int num = 0; + walk_tree_without_duplicates (&expr, estimate_num_insns_1, &num); + return num; +} + /* If *TP is a CALL_EXPR, replace it with its inline expansion. */ static tree @@ -1280,19 +1399,16 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) tree t; tree expr; tree stmt; -#ifndef INLINER_FOR_JAVA - tree chain; - tree scope_stmt; - tree use_stmt; -#else /* INLINER_FOR_JAVA */ - tree retvar; -#endif /* INLINER_FOR_JAVA */ + tree use_retvar; + tree decl; tree fn; tree arg_inits; tree *inlined_body; + tree inline_result; splay_tree st; tree args; tree return_slot_addr; + location_t saved_location; struct cgraph_edge *edge; const char *reason; @@ -1300,11 +1416,17 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) id = (inline_data *) data; t = *tp; + /* Set input_location here so we get the right instantiation context + if we call instantiate_decl from inlinable_function_p. */ + saved_location = input_location; + if (EXPR_HAS_LOCATION (t)) + input_location = EXPR_LOCATION (t); + /* Recurse, but letting recursive invocations know that we are inside the body of a TARGET_EXPR. */ if (TREE_CODE (*tp) == TARGET_EXPR) { -#ifndef INLINER_FOR_JAVA +#if 0 int i, len = first_rtl_op (TARGET_EXPR); /* We're walking our own subtrees. */ @@ -1323,23 +1445,8 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) --id->in_target_cleanup_p; } - return NULL_TREE; -#else /* INLINER_FOR_JAVA */ - abort (); -#endif /* INLINER_FOR_JAVA */ - } - else if (TREE_CODE (t) == EXPR_WITH_FILE_LOCATION) - { - /* We're walking the subtree directly. */ - *walk_subtrees = 0; - /* Update the source position. */ - push_srcloc (EXPR_WFL_FILENAME (t), EXPR_WFL_LINENO (t)); - walk_tree (&EXPR_WFL_NODE (t), expand_call_inline, data, - id->tree_pruner); - /* Restore the original source position. */ - pop_srcloc (); - - return NULL_TREE; + goto egress; +#endif } if (TYPE_P (t)) @@ -1350,13 +1457,13 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) /* From here on, we're only interested in CALL_EXPRs. */ if (TREE_CODE (t) != CALL_EXPR) - return NULL_TREE; + goto egress; /* First, see if we can figure out what function is being called. If we cannot, then there is no hope of inlining the function. */ fn = get_callee_fndecl (t); if (!fn) - return NULL_TREE; + goto egress; /* Turn forward declarations into real ones. */ fn = cgraph_node (fn)->decl; @@ -1376,7 +1483,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) /* Objective C and fortran still calls tree_rest_of_compilation directly. Kill this check once this is fixed. */ if (!id->current_node->analyzed) - return NULL_TREE; + goto egress; edge = cgraph_edge (id->current_node, t); @@ -1386,12 +1493,15 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) { struct cgraph_node *dest = cgraph_node (fn); - /* FN must have address taken so it can be passed as argument. */ + /* We have missing edge in the callgraph. This can happen in one case + where previous inlining turned indirect call into direct call by + constant propagating arguments. In all other cases we hit a bug + (incorrect node sharing is most common reason for missing edges. */ if (!dest->needed) abort (); cgraph_create_edge (id->node, dest, t)->inline_failed = N_("originally indirect function call not considered for inlining"); - return NULL_TREE; + goto egress; } /* Don't try to inline functions that are not well-suited to @@ -1410,7 +1520,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) warning ("%Jinlining failed in call to '%F': %s", fn, fn, reason); warning ("called from here"); } - return NULL_TREE; + goto egress; } #ifdef ENABLE_CHECKING @@ -1419,36 +1529,16 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) #endif if (! lang_hooks.tree_inlining.start_inlining (fn)) - return NULL_TREE; + goto egress; - /* Set the current filename and line number to the function we are - inlining so that when we create new _STMT nodes here they get - line numbers corresponding to the function we are calling. We - wrap the whole inlined body in an EXPR_WITH_FILE_AND_LINE as well - because individual statements don't record the filename. */ - push_srcloc (DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn)); - -#ifndef INLINER_FOR_JAVA - /* Build a statement-expression containing code to initialize the - arguments, the actual inline expansion of the body, and a label - for the return statements within the function to jump to. The - type of the statement expression is the return type of the - function call. */ - expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), make_node (COMPOUND_STMT)); - /* There is no scope associated with the statement-expression. */ - STMT_EXPR_NO_SCOPE (expr) = 1; - if (lookup_attribute ("warn_unused_result", - TYPE_ATTRIBUTES (TREE_TYPE (fn)))) - STMT_EXPR_WARN_UNUSED_RESULT (expr) = 1; - stmt = STMT_EXPR_STMT (expr); -#else /* INLINER_FOR_JAVA */ /* Build a block containing code to initialize the arguments, the actual inline expansion of the body, and a label for the return statements within the function to jump to. The type of the statement expression is the return type of the function call. */ stmt = NULL; - expr = build (BLOCK, TREE_TYPE (TREE_TYPE (fn))); -#endif /* INLINER_FOR_JAVA */ + expr = build (BIND_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE, + stmt, make_node (BLOCK)); + BLOCK_ABSTRACT_ORIGIN (BIND_EXPR_BLOCK (expr)) = fn; /* Local declarations will be replaced by their equivalents in this map. */ @@ -1463,33 +1553,29 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) { return_slot_addr = TREE_VALUE (args); args = TREE_CHAIN (args); + TREE_TYPE (expr) = void_type_node; } -#ifndef INLINER_FOR_JAVA - arg_inits = initialize_inlined_parameters (id, args, fn); - /* Expand any inlined calls in the initializers. Do this before we - push FN on the stack of functions we are inlining; we want to - inline calls to FN that appear in the initializers for the - parameters. */ - expand_calls_inline (&arg_inits, id); - /* And add them to the tree. */ - COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits); -#else /* INLINER_FOR_JAVA */ - arg_inits = initialize_inlined_parameters (id, args, fn, expr); + arg_inits = initialize_inlined_parameters (id, args, TREE_OPERAND (t, 2), + fn, expr); if (arg_inits) { /* Expand any inlined calls in the initializers. Do this before we push FN on the stack of functions we are inlining; we want to inline calls to FN that appear in the initializers for the - parameters. */ + parameters. + + Note we need to save and restore the saved tree statement iterator + to avoid having it clobbered by expand_calls_inline. */ + tree_stmt_iterator save_tsi; + + save_tsi = id->tsi; expand_calls_inline (&arg_inits, id); + id->tsi = save_tsi; /* And add them to the tree. */ - BLOCK_EXPR_BODY (expr) = add_stmt_to_compound (BLOCK_EXPR_BODY (expr), - TREE_TYPE (arg_inits), - arg_inits); + append_to_statement_list (arg_inits, &BIND_EXPR_BODY (expr)); } -#endif /* INLINER_FOR_JAVA */ /* Record the function we are about to inline so that we can avoid recursing into it. */ @@ -1511,45 +1597,18 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) /* Return statements in the function body will be replaced by jumps to the RET_LABEL. */ id->ret_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); + DECL_ARTIFICIAL (id->ret_label) = 1; DECL_CONTEXT (id->ret_label) = VARRAY_TREE (id->fns, 0); + insert_decl_map (id, id->ret_label, id->ret_label); if (! DECL_INITIAL (fn) || TREE_CODE (DECL_INITIAL (fn)) != BLOCK) abort (); -#ifndef INLINER_FOR_JAVA - /* Create a block to put the parameters in. We have to do this - after the parameters have been remapped because remapping - parameters is different from remapping ordinary variables. */ - scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn)); - SCOPE_BEGIN_P (scope_stmt) = 1; - SCOPE_NO_CLEANUPS_P (scope_stmt) = 1; - remap_block (scope_stmt, DECL_ARGUMENTS (fn), id); - TREE_CHAIN (scope_stmt) = COMPOUND_BODY (stmt); - COMPOUND_BODY (stmt) = scope_stmt; - - /* Tell the debugging backends that this block represents the - outermost scope of the inlined function. */ - if (SCOPE_STMT_BLOCK (scope_stmt)) - BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn); - /* Declare the return variable for the function. */ - COMPOUND_BODY (stmt) - = chainon (COMPOUND_BODY (stmt), - declare_return_variable (id, return_slot_addr, &use_stmt)); -#else /* INLINER_FOR_JAVA */ - { - /* Declare the return variable for the function. */ - tree decl = declare_return_variable (id, return_slot_addr, &retvar); - if (retvar) - { - tree *next = &BLOCK_VARS (expr); - while (*next) - next = &TREE_CHAIN (*next); - *next = decl; - } - } -#endif /* INLINER_FOR_JAVA */ + decl = declare_return_variable (id, return_slot_addr, &use_retvar); + if (decl) + declare_inline_vars (expr, decl); /* After we've initialized the parameters, we insert the body of the function itself. */ @@ -1557,67 +1616,25 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) struct cgraph_node *old_node = id->current_node; id->current_node = edge->callee; -#ifndef INLINER_FOR_JAVA - inlined_body = &COMPOUND_BODY (stmt); - while (*inlined_body) - inlined_body = &TREE_CHAIN (*inlined_body); - *inlined_body = copy_body (id); -#else /* INLINER_FOR_JAVA */ - { - tree new_body; - java_inlining_map_static_initializers (fn, id->decl_map); - new_body = copy_body (id); - TREE_TYPE (new_body) = TREE_TYPE (TREE_TYPE (fn)); - BLOCK_EXPR_BODY (expr) - = add_stmt_to_compound (BLOCK_EXPR_BODY (expr), - TREE_TYPE (new_body), new_body); - inlined_body = &BLOCK_EXPR_BODY (expr); - } -#endif /* INLINER_FOR_JAVA */ + append_to_statement_list (copy_body (id), &BIND_EXPR_BODY (expr)); id->current_node = old_node; } + inlined_body = &BIND_EXPR_BODY (expr); /* After the body of the function comes the RET_LABEL. This must come before we evaluate the returned value below, because that evaluation may cause RTL to be generated. */ -#ifndef INLINER_FOR_JAVA - COMPOUND_BODY (stmt) - = chainon (COMPOUND_BODY (stmt), - build_stmt (LABEL_STMT, id->ret_label)); -#else /* INLINER_FOR_JAVA */ - { - tree label = build1 (LABEL_EXPR, void_type_node, id->ret_label); - BLOCK_EXPR_BODY (expr) - = add_stmt_to_compound (BLOCK_EXPR_BODY (expr), void_type_node, label); - TREE_SIDE_EFFECTS (label) = TREE_SIDE_EFFECTS (t); - } -#endif /* INLINER_FOR_JAVA */ - - /* Finally, mention the returned value so that the value of the - statement-expression is the returned value of the function. */ -#ifndef INLINER_FOR_JAVA - COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), use_stmt); - - /* Close the block for the parameters. */ - scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn)); - SCOPE_NO_CLEANUPS_P (scope_stmt) = 1; - remap_block (scope_stmt, NULL_TREE, id); - COMPOUND_BODY (stmt) - = chainon (COMPOUND_BODY (stmt), scope_stmt); -#else /* INLINER_FOR_JAVA */ - if (retvar) + if (TREE_USED (id->ret_label)) { - /* Mention the retvar. If the return type of the function was - promoted, convert it back to the expected type. */ - if (TREE_TYPE (TREE_TYPE (fn)) != TREE_TYPE (retvar)) - retvar = build1 (NOP_EXPR, TREE_TYPE (TREE_TYPE (fn)), retvar); - BLOCK_EXPR_BODY (expr) - = add_stmt_to_compound (BLOCK_EXPR_BODY (expr), - TREE_TYPE (retvar), retvar); + tree label = build1 (LABEL_EXPR, void_type_node, id->ret_label); + append_to_statement_list (label, &BIND_EXPR_BODY (expr)); } - java_inlining_merge_static_initializers (fn, id->decl_map); -#endif /* INLINER_FOR_JAVA */ + /* Finally, mention the returned value so that the value of the + statement-expression is the returned value of the function. */ + if (use_retvar) + /* Set TREE_TYPE on BIND_EXPR? */ + append_to_statement_list_force (use_retvar, &BIND_EXPR_BODY (expr)); /* Clean up. */ splay_tree_delete (id->decl_map); @@ -1626,19 +1643,54 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) /* The new expression has side-effects if the old one did. */ TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (t); - /* Replace the call by the inlined body. Wrap it in an - EXPR_WITH_FILE_LOCATION so that we'll get debugging line notes - pointing to the right place. */ -#ifndef INLINER_FOR_JAVA - chain = TREE_CHAIN (*tp); -#endif /* INLINER_FOR_JAVA */ - *tp = build_expr_wfl (expr, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn), - /*col=*/0); - EXPR_WFL_EMIT_LINE_NOTE (*tp) = 1; -#ifndef INLINER_FOR_JAVA - TREE_CHAIN (*tp) = chain; -#endif /* not INLINER_FOR_JAVA */ - pop_srcloc (); + /* If we are working with gimple form, then we need to keep the tree + in gimple form. If we are not in gimple form, we can just replace + *tp with the new BIND_EXPR. */ + if (lang_hooks.gimple_before_inlining) + { + tree save_decl; + + /* Keep the new trees in gimple form. */ + BIND_EXPR_BODY (expr) + = rationalize_compound_expr (BIND_EXPR_BODY (expr)); + + /* We want to create a new variable to hold the result of the + inlined body. This new variable needs to be added to the + function which we are inlining into, thus the saving and + restoring of current_function_decl. */ + save_decl = current_function_decl; + current_function_decl = id->node->decl; + inline_result = voidify_wrapper_expr (expr); + current_function_decl = save_decl; + + /* If the inlined function returns a result that we care about, + then we're going to need to splice in a MODIFY_EXPR. Otherwise + the call was a standalone statement and we can just replace it + with the BIND_EXPR inline representation of the called function. */ + if (TREE_CODE (tsi_stmt (id->tsi)) != CALL_EXPR) + { + tsi_link_before (&id->tsi, expr, TSI_SAME_STMT); + *tp = inline_result; + } + else + *tp = expr; + + /* When we gimplify a function call, we may clear TREE_SIDE_EFFECTS + on the call if it is to a "const" function. Thus the copy of + TREE_SIDE_EFFECTS from the CALL_EXPR to the BIND_EXPR above + with result in TREE_SIDE_EFFECTS not being set for the inlined + copy of a "const" function. + + Unfortunately, that is wrong as inlining the function + can create/expose interesting side effects (such as setting + of a return value). + + The easiest solution is to simply recalculate TREE_SIDE_EFFECTS + for the toplevel expression. */ + recalculate_side_effects (expr); + } + else + *tp = expr; /* If the value of the new expression is ignored, that's OK. We don't warn about this for CALL_EXPRs, so we shouldn't warn about @@ -1658,21 +1710,108 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) lang_hooks.tree_inlining.end_inlining (fn); /* Keep iterating. */ + egress: + input_location = saved_location; return NULL_TREE; } + +static void +gimple_expand_calls_inline (tree *stmt_p, inline_data *id) +{ + tree stmt = *stmt_p; + enum tree_code code = TREE_CODE (stmt); + int dummy; + + switch (code) + { + case STATEMENT_LIST: + { + tree_stmt_iterator i; + tree new; + + for (i = tsi_start (stmt); !tsi_end_p (i); ) + { + id->tsi = i; + gimple_expand_calls_inline (tsi_stmt_ptr (i), id); + + new = tsi_stmt (i); + if (TREE_CODE (new) == STATEMENT_LIST) + { + tsi_link_before (&i, new, TSI_SAME_STMT); + tsi_delink (&i); + } + else + tsi_next (&i); + } + } + break; + + case COND_EXPR: + gimple_expand_calls_inline (&COND_EXPR_THEN (stmt), id); + gimple_expand_calls_inline (&COND_EXPR_ELSE (stmt), id); + break; + case CATCH_EXPR: + gimple_expand_calls_inline (&CATCH_BODY (stmt), id); + break; + case EH_FILTER_EXPR: + gimple_expand_calls_inline (&EH_FILTER_FAILURE (stmt), id); + break; + case TRY_CATCH_EXPR: + case TRY_FINALLY_EXPR: + gimple_expand_calls_inline (&TREE_OPERAND (stmt, 0), id); + gimple_expand_calls_inline (&TREE_OPERAND (stmt, 1), id); + break; + case BIND_EXPR: + gimple_expand_calls_inline (&BIND_EXPR_BODY (stmt), id); + break; + + case COMPOUND_EXPR: + /* We're gimple. We should have gotten rid of all these. */ + abort (); + + case RETURN_EXPR: + stmt_p = &TREE_OPERAND (stmt, 0); + stmt = *stmt_p; + if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR) + break; + /* FALLTHRU */ + case MODIFY_EXPR: + stmt_p = &TREE_OPERAND (stmt, 1); + stmt = *stmt_p; + if (TREE_CODE (stmt) != CALL_EXPR) + break; + /* FALLTHRU */ + case CALL_EXPR: + expand_call_inline (stmt_p, &dummy, id); + break; + + default: + break; + } +} + /* Walk over the entire tree *TP, replacing CALL_EXPRs with inline expansions as appropriate. */ static void expand_calls_inline (tree *tp, inline_data *id) { - /* Search through *TP, replacing all calls to inline functions by - appropriate equivalents. Use walk_tree in no-duplicates mode - to avoid exponential time complexity. (We can't just use - walk_tree_without_duplicates, because of the special TARGET_EXPR - handling in expand_calls. The hash table is set up in - optimize_function. */ - walk_tree (tp, expand_call_inline, id, id->tree_pruner); + /* If we are not in gimple form, then we want to walk the tree + recursively as we do not know anything about the structure + of the tree. */ + + if (!lang_hooks.gimple_before_inlining) + { + walk_tree (tp, expand_call_inline, id, id->tree_pruner); + return; + } + + /* We are in gimple form. We want to stay in gimple form. Walk + the statements, inlining calls in each statement. By walking + the statements, we have enough information to keep the tree + in gimple form as we insert inline bodies. */ + + gimple_expand_calls_inline (tp, id); } /* Expand calls to inline functions in the body of FN. */ @@ -1731,6 +1870,7 @@ optimize_inline_calls (tree fn) VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree)); DECL_INLINED_FNS (fn) = ifn; } + #ifdef ENABLE_CHECKING { struct cgraph_edge *e; @@ -1800,8 +1940,6 @@ save_body (tree fn, tree *arg_copy) /* Actually copy the body. */ body = copy_body (&id); - if (lang_hooks.update_decl_after_saving) - lang_hooks.update_decl_after_saving (fn, id.decl_map); /* Clean up. */ splay_tree_delete (id.decl_map); @@ -1867,12 +2005,11 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_) code = TREE_CODE (*tp); -#ifndef INLINER_FOR_JAVA /* Even if we didn't, FUNC may have decided that there was nothing interesting below this point in the tree. */ if (!walk_subtrees) { - if (STATEMENT_CODE_P (code) || code == TREE_LIST + if (code == TREE_LIST || lang_hooks.tree_inlining.tree_chain_matters_p (*tp)) /* But we still need to check our siblings. */ WALK_SUBTREE_TAIL (TREE_CHAIN (*tp)); @@ -1880,23 +2017,18 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_) return NULL_TREE; } - /* Handle common cases up front. */ - if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) -#else /* INLINER_FOR_JAVA */ + result = (*lang_hooks.tree_inlining.walk_subtrees) (tp, &walk_subtrees, func, + data, htab); + if (result || ! walk_subtrees) + return result; + if (code != EXIT_BLOCK_EXPR && code != SAVE_EXPR + && code != BIND_EXPR && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))) -#endif /* INLINER_FOR_JAVA */ { int i, len; -#ifndef INLINER_FOR_JAVA - /* Set lineno here so we get the right instantiation context - if we call instantiate_decl from inlinable_function_p. */ - if (STATEMENT_CODE_P (code) && !STMT_LINENO_FOR_FN_P (*tp)) - input_line = STMT_LINENO (*tp); -#endif /* not INLINER_FOR_JAVA */ - /* Walk over all the sub-trees of this operand. */ len = first_rtl_op (code); /* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same. @@ -1906,147 +2038,161 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_) --len; /* Go through the subtrees. We need to do this in forward order so that the scope of a FOR_EXPR is handled properly. */ +#ifdef DEBUG_WALK_TREE for (i = 0; i < len; ++i) WALK_SUBTREE (TREE_OPERAND (*tp, i)); +#else + for (i = 0; i < len - 1; ++i) + WALK_SUBTREE (TREE_OPERAND (*tp, i)); -#ifndef INLINER_FOR_JAVA - /* For statements, we also walk the chain so that we cover the - entire statement tree. */ - if (STATEMENT_CODE_P (code)) + if (len) { - if (code == DECL_STMT - && DECL_STMT_DECL (*tp) - && DECL_P (DECL_STMT_DECL (*tp))) - { - /* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk - into declarations that are just mentioned, rather than - declared; they don't really belong to this part of the tree. - And, we can see cycles: the initializer for a declaration can - refer to the declaration itself. */ - WALK_SUBTREE (DECL_INITIAL (DECL_STMT_DECL (*tp))); - WALK_SUBTREE (DECL_SIZE (DECL_STMT_DECL (*tp))); - WALK_SUBTREE (DECL_SIZE_UNIT (DECL_STMT_DECL (*tp))); - WALK_SUBTREE (TREE_TYPE (*tp)); - } - - /* This can be tail-recursion optimized if we write it this way. */ - WALK_SUBTREE_TAIL (TREE_CHAIN (*tp)); + /* The common case is that we may tail recurse here. */ + if (code != BIND_EXPR + && !TREE_CHAIN (*tp)) + WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, len - 1)); + else + WALK_SUBTREE (TREE_OPERAND (*tp, len - 1)); } +#endif -#endif /* not INLINER_FOR_JAVA */ - /* We didn't find what we were looking for. */ - return NULL_TREE; + if ((*lang_hooks.tree_inlining.tree_chain_matters_p) (*tp)) + /* Check our siblings. */ + WALK_SUBTREE_TAIL (TREE_CHAIN (*tp)); } else if (TREE_CODE_CLASS (code) == 'd') { WALK_SUBTREE_TAIL (TREE_TYPE (*tp)); } - else if (TREE_CODE_CLASS (code) == 't') + else { - WALK_SUBTREE (TYPE_SIZE (*tp)); - WALK_SUBTREE (TYPE_SIZE_UNIT (*tp)); - /* Also examine various special fields, below. */ - } + if (TREE_CODE_CLASS (code) == 't') + { + WALK_SUBTREE (TYPE_SIZE (*tp)); + WALK_SUBTREE (TYPE_SIZE_UNIT (*tp)); + /* Also examine various special fields, below. */ + } - result = lang_hooks.tree_inlining.walk_subtrees (tp, &walk_subtrees, func, - data, htab); - if (result || ! walk_subtrees) - return result; + /* Not one of the easy cases. We must explicitly go through the + children. */ + switch (code) + { + case ERROR_MARK: + case IDENTIFIER_NODE: + case INTEGER_CST: + case REAL_CST: + case VECTOR_CST: + case STRING_CST: + case REAL_TYPE: + case COMPLEX_TYPE: + case VECTOR_TYPE: + case VOID_TYPE: + case BOOLEAN_TYPE: + case UNION_TYPE: + case ENUMERAL_TYPE: + case BLOCK: + case RECORD_TYPE: + case PLACEHOLDER_EXPR: + case SSA_NAME: + /* None of thse have subtrees other than those already walked + above. */ + break; - /* Not one of the easy cases. We must explicitly go through the - children. */ - switch (code) - { - case ERROR_MARK: - case IDENTIFIER_NODE: - case INTEGER_CST: - case REAL_CST: - case VECTOR_CST: - case STRING_CST: - case REAL_TYPE: - case COMPLEX_TYPE: - case VECTOR_TYPE: - case VOID_TYPE: - case BOOLEAN_TYPE: - case UNION_TYPE: - case ENUMERAL_TYPE: - case BLOCK: - case RECORD_TYPE: - case CHAR_TYPE: - case PLACEHOLDER_EXPR: - /* None of these have subtrees other than those already walked - above. */ - break; + case POINTER_TYPE: + case REFERENCE_TYPE: + WALK_SUBTREE_TAIL (TREE_TYPE (*tp)); + break; - case POINTER_TYPE: - case REFERENCE_TYPE: - WALK_SUBTREE_TAIL (TREE_TYPE (*tp)); - break; + case TREE_LIST: + WALK_SUBTREE (TREE_VALUE (*tp)); + WALK_SUBTREE_TAIL (TREE_CHAIN (*tp)); + break; - case TREE_LIST: - WALK_SUBTREE (TREE_VALUE (*tp)); - WALK_SUBTREE_TAIL (TREE_CHAIN (*tp)); - break; + case TREE_VEC: + { + int len = TREE_VEC_LENGTH (*tp); - case TREE_VEC: - { - int len = TREE_VEC_LENGTH (*tp); + if (len == 0) + break; - if (len == 0) - break; + /* Walk all elements but the first. */ + while (--len) + WALK_SUBTREE (TREE_VEC_ELT (*tp, len)); - /* Walk all elements but the first. */ - while (--len) - WALK_SUBTREE (TREE_VEC_ELT (*tp, len)); + /* Now walk the first one as a tail call. */ + WALK_SUBTREE_TAIL (TREE_VEC_ELT (*tp, 0)); + } - /* Now walk the first one as a tail call. */ - WALK_SUBTREE_TAIL (TREE_VEC_ELT (*tp, 0)); - } + case COMPLEX_CST: + WALK_SUBTREE (TREE_REALPART (*tp)); + WALK_SUBTREE_TAIL (TREE_IMAGPART (*tp)); - case COMPLEX_CST: - WALK_SUBTREE (TREE_REALPART (*tp)); - WALK_SUBTREE_TAIL (TREE_IMAGPART (*tp)); + case CONSTRUCTOR: + WALK_SUBTREE_TAIL (CONSTRUCTOR_ELTS (*tp)); - case CONSTRUCTOR: - WALK_SUBTREE_TAIL (CONSTRUCTOR_ELTS (*tp)); + case METHOD_TYPE: + WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp)); + /* Fall through. */ - case METHOD_TYPE: - WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp)); - /* Fall through. */ + case FUNCTION_TYPE: + WALK_SUBTREE (TREE_TYPE (*tp)); + { + tree arg = TYPE_ARG_TYPES (*tp); - case FUNCTION_TYPE: - WALK_SUBTREE (TREE_TYPE (*tp)); - { - tree arg = TYPE_ARG_TYPES (*tp); + /* We never want to walk into default arguments. */ + for (; arg; arg = TREE_CHAIN (arg)) + WALK_SUBTREE (TREE_VALUE (arg)); + } + break; - /* We never want to walk into default arguments. */ - for (; arg; arg = TREE_CHAIN (arg)) - WALK_SUBTREE (TREE_VALUE (arg)); - } - break; + case ARRAY_TYPE: + WALK_SUBTREE (TREE_TYPE (*tp)); + WALK_SUBTREE_TAIL (TYPE_DOMAIN (*tp)); - case ARRAY_TYPE: - WALK_SUBTREE (TREE_TYPE (*tp)); - WALK_SUBTREE_TAIL (TYPE_DOMAIN (*tp)); + case INTEGER_TYPE: + case CHAR_TYPE: + WALK_SUBTREE (TYPE_MIN_VALUE (*tp)); + WALK_SUBTREE_TAIL (TYPE_MAX_VALUE (*tp)); - case INTEGER_TYPE: - WALK_SUBTREE (TYPE_MIN_VALUE (*tp)); - WALK_SUBTREE_TAIL (TYPE_MAX_VALUE (*tp)); + case OFFSET_TYPE: + WALK_SUBTREE (TREE_TYPE (*tp)); + WALK_SUBTREE_TAIL (TYPE_OFFSET_BASETYPE (*tp)); - case OFFSET_TYPE: - WALK_SUBTREE (TREE_TYPE (*tp)); - WALK_SUBTREE_TAIL (TYPE_OFFSET_BASETYPE (*tp)); + case EXIT_BLOCK_EXPR: + WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 1)); -#ifdef INLINER_FOR_JAVA - case EXIT_BLOCK_EXPR: - WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 1)); + case SAVE_EXPR: + WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0)); - case SAVE_EXPR: - WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0)); -#endif /* INLINER_FOR_JAVA */ + case BIND_EXPR: + { + tree decl; + for (decl = BIND_EXPR_VARS (*tp); decl; decl = TREE_CHAIN (decl)) + { + /* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk + into declarations that are just mentioned, rather than + declared; they don't really belong to this part of the tree. + And, we can see cycles: the initializer for a declaration can + refer to the declaration itself. */ + WALK_SUBTREE (DECL_INITIAL (decl)); + WALK_SUBTREE (DECL_SIZE (decl)); + WALK_SUBTREE (DECL_SIZE_UNIT (decl)); + WALK_SUBTREE (TREE_TYPE (decl)); + } + WALK_SUBTREE_TAIL (BIND_EXPR_BODY (*tp)); + } - default: - abort (); + case STATEMENT_LIST: + { + tree_stmt_iterator i; + for (i = tsi_start (*tp); !tsi_end_p (i); tsi_next (&i)) + WALK_SUBTREE (*tsi_stmt_ptr (i)); + } + break; + + default: + abort (); + } } /* We didn't find what we were looking for. */ @@ -2089,29 +2235,34 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) /* Because the chain gets clobbered when we make a copy, we save it here. */ tree chain = TREE_CHAIN (*tp); + tree new; /* Copy the node. */ - *tp = copy_node (*tp); + new = copy_node (*tp); + + /* Propagate mudflap marked-ness. */ + if (flag_mudflap && mf_marked_p (*tp)) + mf_mark (new); + + *tp = new; /* Now, restore the chain, if appropriate. That will cause walk_tree to walk into the chain as well. */ if (code == PARM_DECL || code == TREE_LIST -#ifndef INLINER_FOR_JAVA - || lang_hooks.tree_inlining.tree_chain_matters_p (*tp) - || STATEMENT_CODE_P (code)) + || lang_hooks.tree_inlining.tree_chain_matters_p (*tp)) TREE_CHAIN (*tp) = chain; /* For now, we don't update BLOCKs when we make copies. So, we - have to nullify all scope-statements. */ - if (TREE_CODE (*tp) == SCOPE_STMT) - SCOPE_STMT_BLOCK (*tp) = NULL_TREE; -#else /* INLINER_FOR_JAVA */ - || lang_hooks.tree_inlining.tree_chain_matters_p (*tp)) - TREE_CHAIN (*tp) = chain; -#endif /* INLINER_FOR_JAVA */ + have to nullify all BIND_EXPRs. */ + if (TREE_CODE (*tp) == BIND_EXPR) + BIND_EXPR_BLOCK (*tp) = NULL_TREE; } else if (TREE_CODE_CLASS (code) == 't') *walk_subtrees = 0; + else if (TREE_CODE_CLASS (code) == 'd') + *walk_subtrees = 0; + else if (code == STATEMENT_LIST) + abort (); return NULL_TREE; } @@ -2157,19 +2308,148 @@ remap_save_expr (tree *tp, void *st_, tree fn, int *walk_subtrees) *tp = t; } -#ifdef INLINER_FOR_JAVA -/* Add STMT to EXISTING if possible, otherwise create a new - COMPOUND_EXPR and add STMT to it. */ +/* Called via walk_tree. If *TP points to a DECL_STMT for a local + declaration, copies the declaration and enters it in the splay_tree + in DATA (which is really an `inline_data *'). */ + +static tree +mark_local_for_remap_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) +{ + tree t = *tp; + inline_data *id = (inline_data *) data; + tree decl; + + /* Don't walk into types. */ + if (TYPE_P (t)) + { + *walk_subtrees = 0; + return NULL_TREE; + } + + if (TREE_CODE (t) == LABEL_EXPR) + decl = TREE_OPERAND (t, 0); + else + /* We don't need to handle anything else ahead of time. */ + decl = NULL_TREE; + + if (decl) + { + tree copy; + + /* Make a copy. */ + copy = copy_decl_for_inlining (decl, + DECL_CONTEXT (decl), + DECL_CONTEXT (decl)); + + /* Remember the copy. */ + insert_decl_map (id, decl, copy); + } + + return NULL_TREE; +} + +/* Called via walk_tree when an expression is unsaved. Using the + splay_tree pointed to by ST (which is really a `splay_tree'), + remaps all local declarations to appropriate replacements. */ static tree -add_stmt_to_compound (tree existing, tree type, tree stmt) +unsave_r (tree *tp, int *walk_subtrees, void *data) { - if (!stmt) - return existing; - else if (existing) - return build (COMPOUND_EXPR, type, existing, stmt); + inline_data *id = (inline_data *) data; + splay_tree st = id->decl_map; + splay_tree_node n; + + /* Only a local declaration (variable or label). */ + if ((TREE_CODE (*tp) == VAR_DECL && !TREE_STATIC (*tp)) + || TREE_CODE (*tp) == LABEL_DECL) + { + /* Lookup the declaration. */ + n = splay_tree_lookup (st, (splay_tree_key) *tp); + + /* If it's there, remap it. */ + if (n) + *tp = (tree) n->value; + } + else if (TREE_CODE (*tp) == STATEMENT_LIST) + copy_statement_list (tp); + else if (TREE_CODE (*tp) == BIND_EXPR) + copy_bind_expr (tp, walk_subtrees, id); + else if (TREE_CODE (*tp) == SAVE_EXPR) + remap_save_expr (tp, st, current_function_decl, walk_subtrees); else - return stmt; + { + copy_tree_r (tp, walk_subtrees, NULL); + + /* Do whatever unsaving is required. */ + unsave_expr_1 (*tp); + } + + /* Keep iterating. */ + return NULL_TREE; } -#endif /* INLINER_FOR_JAVA */ +/* Default lang hook for "unsave_expr_now". Copies everything in EXPR and + replaces variables, labels and SAVE_EXPRs local to EXPR. */ + +tree +lhd_unsave_expr_now (tree expr) +{ + inline_data id; + + /* There's nothing to do for NULL_TREE. */ + if (expr == 0) + return expr; + + /* Set up ID. */ + memset (&id, 0, sizeof (id)); + VARRAY_TREE_INIT (id.fns, 1, "fns"); + VARRAY_PUSH_TREE (id.fns, current_function_decl); + id.decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); + + /* Walk the tree once to find local labels. */ + walk_tree_without_duplicates (&expr, mark_local_for_remap_r, &id); + + /* Walk the tree again, copying, remapping, and unsaving. */ + walk_tree (&expr, unsave_r, &id, NULL); + + /* Clean up. */ + splay_tree_delete (id.decl_map); + + return expr; +} + +/* Allow someone to determine if SEARCH is a child of TOP from gdb. */ +static tree +debug_find_tree_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data) +{ + if (*tp == data) + return (tree) data; + else + return NULL; +} + +extern bool debug_find_tree (tree top, tree search); + +bool +debug_find_tree (tree top, tree search) +{ + return walk_tree_without_duplicates (&top, debug_find_tree_1, search) != 0; +} + + +/* Declare the variables created by the inliner. Add all the variables in + VARS to BIND_EXPR. */ + +static void +declare_inline_vars (tree bind_expr, tree vars) +{ + if (lang_hooks.gimple_before_inlining) + { + tree t; + for (t = vars; t; t = TREE_CHAIN (t)) + vars->decl.seen_in_bind_expr = 1; + } + + add_var_to_bind_expr (bind_expr, vars); +} diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h index 03a2b0a5ddb..142f5569f58 100644 --- a/gcc/tree-inline.h +++ b/gcc/tree-inline.h @@ -26,12 +26,11 @@ Boston, MA 02111-1307, USA. */ void optimize_inline_calls (tree); bool tree_inlinable_function_p (tree); -tree walk_tree (tree*, walk_tree_fn, void*, void*); -tree walk_tree_without_duplicates (tree*, walk_tree_fn, void*); tree copy_tree_r (tree*, int*, void*); void clone_body (tree, tree, void*); tree save_body (tree, tree *); void remap_save_expr (tree*, void*, tree, int*); +int estimate_num_insns (tree expr); /* 0 if we should not perform inlining. 1 if we should expand functions calls inline at the tree level. diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c new file mode 100644 index 00000000000..90f4aa58d8d --- /dev/null +++ b/gcc/tree-into-ssa.c @@ -0,0 +1,1179 @@ +/* Rewrite a program in Normal form into SSA. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "tm_p.h" +#include "langhooks.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "expr.h" +#include "function.h" +#include "diagnostic.h" +#include "bitmap.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "varray.h" +#include "timevar.h" +#include "tree-alias-common.h" +#include "hashtab.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "cfgloop.h" +#include "domwalk.h" + +/* This file builds the SSA form for a function as described in: + R. Cytron, J. Ferrante, B. Rosen, M. Wegman, and K. Zadeck. Efficiently + Computing Static Single Assignment Form and the Control Dependence + Graph. ACM Transactions on Programming Languages and Systems, + 13(4):451-490, October 1991. */ + + +/* Structure to map a variable VAR to the set of blocks that contain + definitions for VAR. */ +struct def_blocks_d +{ + /* The variable. */ + tree var; + + /* Blocks that contain definitions of VAR. Bit I will be set if the + Ith block contains a definition of VAR. */ + bitmap def_blocks; + + /* Blocks where VAR is live-on-entry. Similar semantics as + DEF_BLOCKS. */ + bitmap livein_blocks; +}; + +/* Each entry in DEF_BLOCKS contains an element of type STRUCT + DEF_BLOCKS_D, mapping a variable VAR to a bitmap describing all the + basic blocks where VAR is defined (assigned a new value). It also + contains a bitmap of all the blocks where VAR is live-on-entry + (i.e., there is a use of VAR in block B without a preceding + definition in B). The live-on-entry information is used when + computing PHI pruning heuristics. */ +static htab_t def_blocks; + +/* Global data to attach to the main dominator walk structure. */ +struct mark_def_sites_global_data +{ + /* This sbitmap contains the variables which are set before they + are used in a basic block. We keep it as a global variable + solely to avoid the overhead of allocating and deallocating + the bitmap. */ + sbitmap kills; +}; + +struct rewrite_block_data +{ + varray_type block_defs; +}; + + +/* Local functions. */ +static void rewrite_finalize_block (struct dom_walk_data *, basic_block); +static void rewrite_initialize_block_local_data (struct dom_walk_data *, + basic_block, bool); +static void rewrite_initialize_block (struct dom_walk_data *, basic_block); +static void rewrite_add_phi_arguments (struct dom_walk_data *, basic_block); +static void mark_def_sites (struct dom_walk_data *walk_data, + basic_block bb, block_stmt_iterator); +static void mark_def_sites_initialize_block (struct dom_walk_data *walk_data, + basic_block bb); +static void compute_global_livein (bitmap, bitmap); +static void set_def_block (tree, basic_block); +static void set_livein_block (tree, basic_block); +static bool prepare_operand_for_rename (tree *op_p, size_t *uid_p); +static void insert_phi_nodes (bitmap *); +static void rewrite_stmt (struct dom_walk_data *, basic_block, + block_stmt_iterator); +static inline void rewrite_operand (tree *); +static void insert_phi_nodes_for (tree, bitmap *, varray_type *); +static tree get_reaching_def (tree); +static hashval_t def_blocks_hash (const void *); +static int def_blocks_eq (const void *, const void *); +static void def_blocks_free (void *); +static int debug_def_blocks_r (void **, void *); +static inline struct def_blocks_d *get_def_blocks_for (tree); +static inline struct def_blocks_d *find_def_blocks_for (tree); +static void htab_statistics (FILE *, htab_t); + +/* Compute global livein information given the set of blockx where + an object is locally live at the start of the block (LIVEIN) + and the set of blocks where the object is defined (DEF_BLOCKS). + + Note: This routine augments the existing local livein information + to include global livein (i.e., it modifies the underlying bitmap + for LIVEIN). */ + +static void +compute_global_livein (bitmap livein, bitmap def_blocks) +{ + basic_block bb, *worklist, *tos; + + tos = worklist + = (basic_block *) xmalloc (sizeof (basic_block) * (last_basic_block + 1)); + + /* Initialize the worklist. */ + FOR_EACH_BB (bb) + { + if (bitmap_bit_p (livein, bb->index)) + *tos++ = bb; + } + + /* Iterate until the worklist is empty. */ + while (tos != worklist) + { + edge e; + + /* Pull a block off the worklist. */ + bb = *--tos; + + /* For each predecessor block. */ + for (e = bb->pred; e; e = e->pred_next) + { + basic_block pred = e->src; + int pred_index = pred->index; + + /* None of this is necessary for the entry block. */ + if (pred != ENTRY_BLOCK_PTR + && ! bitmap_bit_p (livein, pred_index) + && ! bitmap_bit_p (def_blocks, pred_index)) + { + *tos++ = pred; + bitmap_set_bit (livein, pred_index); + } + } + } + + free (worklist); +} + + +/* Block initialization routine for mark_def_sites. Clear the + KILLS bitmap at the start of each block. */ + +static void +mark_def_sites_initialize_block (struct dom_walk_data *walk_data, + basic_block bb ATTRIBUTE_UNUSED) +{ + struct mark_def_sites_global_data *gd = walk_data->global_data; + sbitmap kills = gd->kills; + + sbitmap_zero (kills); +} + + +/* Call back for walk_dominator_tree used to collect definition sites + for every variable in the function. For every statement S in block + BB: + + 1- Variables defined by S in DEF_OPS(S) are marked in the bitmap + WALK_DATA->GLOBAL_DATA->KILLS. + + 2- If S uses a variable VAR and there is no preceding kill of VAR, + then it is marked in marked in the LIVEIN_BLOCKS bitmap + associated with VAR. + + This information is used to determine which variables are live + across block boundaries to reduce the number of PHI nodes + we create. */ + +static void +mark_def_sites (struct dom_walk_data *walk_data, + basic_block bb, + block_stmt_iterator bsi) +{ + struct mark_def_sites_global_data *gd = walk_data->global_data; + sbitmap kills = gd->kills; + vdef_optype vdefs; + vuse_optype vuses; + def_optype defs; + use_optype uses; + size_t i, uid; + tree stmt; + stmt_ann_t ann; + + /* Mark all the blocks that have definitions for each variable in the + VARS_TO_RENAME bitmap. */ + stmt = bsi_stmt (bsi); + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + + /* If a variable is used before being set, then the variable is live + across a block boundary, so mark it live-on-entry to BB. */ + uses = USE_OPS (ann); + for (i = 0; i < NUM_USES (uses); i++) + { + tree *use_p = USE_OP_PTR (uses, i); + + if (prepare_operand_for_rename (use_p, &uid) + && !TEST_BIT (kills, uid)) + set_livein_block (*use_p, bb); + } + + /* Similarly for virtual uses. */ + vuses = VUSE_OPS (ann); + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree *use_p = VUSE_OP_PTR (vuses, i); + + if (prepare_operand_for_rename (use_p, &uid) + && !TEST_BIT (kills, uid)) + set_livein_block (*use_p, bb); + } + + /* Note that virtual definitions are irrelevant for computing KILLS + because a VDEF does not constitute a killing definition of the + variable. However, the operand of a virtual definitions is a use + of the variable, so it may cause the variable to be considered + live-on-entry. */ + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + size_t dummy; + + if (prepare_operand_for_rename (VDEF_OP_PTR (vdefs, i), &uid) + && prepare_operand_for_rename (VDEF_RESULT_PTR (vdefs, i), &dummy)) + { + VDEF_RESULT (vdefs, i) = VDEF_OP (vdefs, i); + + if (!TEST_BIT (kills, uid)) + set_livein_block (VDEF_OP (vdefs, i), bb); + set_def_block (VDEF_RESULT (vdefs, i), bb); + } + } + + /* Now process the definition made by this statement. Mark the + variables in KILLS. */ + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree *def_p = DEF_OP_PTR (defs, i); + + if (prepare_operand_for_rename (def_p, &uid)) + { + set_def_block (*def_p, bb); + SET_BIT (kills, uid); + } + } +} + + +/* Mark block BB as the definition site for variable VAR. */ + +static void +set_def_block (tree var, basic_block bb) +{ + struct def_blocks_d *db_p; + enum need_phi_state state = var_ann (var)->need_phi_state; + + db_p = get_def_blocks_for (var); + + /* Set the bit corresponding to the block where VAR is defined. */ + bitmap_set_bit (db_p->def_blocks, bb->index); + + /* Keep track of whether or not we may need to insert phi nodes. + + If we are in the UNKNOWN state, then this is the first definition + of VAR. Additionally, we have not seen any uses of VAR yet, so + we do not need a phi node for this variable at this time (i.e., + transition to NEED_PHI_STATE_NO). + + If we are in any other state, then we either have multiple definitions + of this variable occurring in different blocks or we saw a use of the + variable which was not dominated by the block containing the + definition(s). In this case we may need a PHI node, so enter + state NEED_PHI_STATE_MAYBE. */ + if (state == NEED_PHI_STATE_UNKNOWN) + var_ann (var)->need_phi_state = NEED_PHI_STATE_NO; + else + var_ann (var)->need_phi_state = NEED_PHI_STATE_MAYBE; +} + + +/* Mark block BB as having VAR live at the entry to BB. */ + +static void +set_livein_block (tree var, basic_block bb) +{ + struct def_blocks_d *db_p; + enum need_phi_state state = var_ann (var)->need_phi_state; + + db_p = get_def_blocks_for (var); + + /* Set the bit corresponding to the block where VAR is live in. */ + bitmap_set_bit (db_p->livein_blocks, bb->index); + + /* Keep track of whether or not we may need to insert phi nodes. + + If we reach here in NEED_PHI_STATE_NO, see if this use is dominated + by the single block containing the definition(s) of this variable. If + it is, then we remain in NEED_PHI_STATE_NO, otherwise we transition to + NEED_PHI_STATE_MAYBE. */ + if (state == NEED_PHI_STATE_NO) + { + int def_block_index = bitmap_first_set_bit (db_p->def_blocks); + + if (def_block_index == -1 + || ! dominated_by_p (CDI_DOMINATORS, bb, + BASIC_BLOCK (def_block_index))) + var_ann (var)->need_phi_state = NEED_PHI_STATE_MAYBE; + } + else + var_ann (var)->need_phi_state = NEED_PHI_STATE_MAYBE; +} + + +/* If the operand pointed by OP_P needs to be renamed, strip away SSA_NAME + wrappers (if needed) and return true. The unique ID for the operand's + variable will be stored in *UID_P. */ + +static bool +prepare_operand_for_rename (tree *op_p, size_t *uid_p) +{ + tree var = (TREE_CODE (*op_p) != SSA_NAME) ? *op_p : SSA_NAME_VAR (*op_p); + *uid_p = var_ann (var)->uid; + + /* Ignore variables that don't need to be renamed. */ + if (vars_to_rename && !bitmap_bit_p (vars_to_rename, *uid_p)) + return false; + + /* The variable needs to be renamed. If it already had an + SSA_NAME, strip it off. This way, the SSA rename pass + doesn't need to deal with existing SSA names. */ + if (TREE_CODE (*op_p) == SSA_NAME) + { + if (default_def (SSA_NAME_VAR (*op_p)) != *op_p) + release_ssa_name (*op_p); + *op_p = var; + } + + return true; +} + + +/* Helper for insert_phi_nodes. If VAR needs PHI nodes, insert them + at the dominance frontier (DFS) of blocks defining VAR. */ + +static inline +void insert_phi_nodes_1 (tree var, bitmap *dfs, varray_type *work_stack) +{ + var_ann_t ann = var_ann (var); + if (ann->need_phi_state != NEED_PHI_STATE_NO) + insert_phi_nodes_for (var, dfs, work_stack); +} + + +/* Insert PHI nodes at the dominance frontier of blocks with variable + definitions. DFS contains the dominance frontier information for + the flowgraph. PHI nodes will only be inserted at the dominance + frontier of definition blocks for variables whose NEED_PHI_STATE + annotation is marked as ``maybe'' or ``unknown'' (computed by + mark_def_sites). */ + +static void +insert_phi_nodes (bitmap *dfs) +{ + size_t i; + varray_type work_stack; + + timevar_push (TV_TREE_INSERT_PHI_NODES); + + /* Array WORK_STACK is a stack of CFG blocks. Each block that contains + an assignment or PHI node will be pushed to this stack. */ + VARRAY_BB_INIT (work_stack, last_basic_block, "work_stack"); + + /* Iterate over all variables in VARS_TO_RENAME. For each variable, add + to the work list all the blocks that have a definition for the + variable. PHI nodes will be added to the dominance frontier blocks of + each definition block. */ + if (vars_to_rename) + EXECUTE_IF_SET_IN_BITMAP (vars_to_rename, 0, i, + insert_phi_nodes_1 (referenced_var (i), dfs, &work_stack)); + else + for (i = 0; i < num_referenced_vars; i++) + insert_phi_nodes_1 (referenced_var (i), dfs, &work_stack); + + timevar_pop (TV_TREE_INSERT_PHI_NODES); +} + + +/* Perform a depth-first traversal of the dominator tree looking for + variables to rename. BB is the block where to start searching. + Renaming is a five step process: + + 1- Every definition made by PHI nodes at the start of the blocks is + registered as the current definition for the corresponding variable. + + 2- Every statement in BB is rewritten. USE and VUSE operands are + rewritten with their corresponding reaching definition. DEF and + VDEF targets are registered as new definitions. + + 3- All the PHI nodes in successor blocks of BB are visited. The + argument corresponding to BB is replaced with its current reaching + definition. + + 4- Recursively rewrite every dominator child block of BB. + + 5- Restore (in reverse order) the current reaching definition for every + new definition introduced in this block. This is done so that when + we return from the recursive call, all the current reaching + definitions are restored to the names that were valid in the + dominator parent of BB. */ + +/* Initialize the local stacks. + + BLOCK_DEFS is used to save all the existing reaching definitions for + the new SSA names introduced in this block. Before registering a + new definition for a variable, the existing reaching definition is + pushed into this stack so that we can restore it in Step 5. */ + +static void +rewrite_initialize_block_local_data (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED, + basic_block bb ATTRIBUTE_UNUSED, + bool recycled ATTRIBUTE_UNUSED) +{ +#ifdef ENABLE_CHECKING + struct rewrite_block_data *bd + = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + /* We get cleared memory from the allocator, so if the memory is + not cleared, then we are re-using a previously allocated entry. In + that case, we can also re-use the underlying virtal arrays. Just + make sure we clear them before using them! */ + if (recycled && bd->block_defs && VARRAY_ACTIVE_SIZE (bd->block_defs) > 0) + abort (); +#endif +} + + +/* SSA Rewriting Step 1. Initialization, create a block local stack + of reaching definitions for new SSA names produced in this block + (BLOCK_DEFS). Register new definitions for every PHI node in the + block. */ + +static void +rewrite_initialize_block (struct dom_walk_data *walk_data, basic_block bb) +{ + tree phi; + struct rewrite_block_data *bd + = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\n\nRenaming block #%d\n\n", bb->index); + + /* Step 1. Register new definitions for every PHI node in the block. + Conceptually, all the PHI nodes are executed in parallel and each PHI + node introduces a new version for the associated variable. */ + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree result = PHI_RESULT (phi); + + register_new_def (result, &bd->block_defs); + } +} + + +/* SSA Rewriting Step 3. Visit all the successor blocks of BB looking for + PHI nodes. For every PHI node found, add a new argument containing the + current reaching definition for the variable and the edge through which + that definition is reaching the PHI node. */ + +static void +rewrite_add_phi_arguments (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED, + basic_block bb) +{ + edge e; + + for (e = bb->succ; e; e = e->succ_next) + { + tree phi; + + for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi)) + { + tree currdef; + + /* If this PHI node has already been rewritten, then there is + nothing to do for this PHI or any following PHIs since we + always add new PHI nodes at the start of the PHI chain. */ + if (PHI_REWRITTEN (phi)) + break; + + currdef = get_reaching_def (SSA_NAME_VAR (PHI_RESULT (phi))); + add_phi_arg (&phi, currdef, e); + } + } +} + +/* SSA Rewriting Step 5. Restore the current reaching definition for each + variable referenced in the block (in reverse order). */ + +static void +rewrite_finalize_block (struct dom_walk_data *walk_data, + basic_block bb ATTRIBUTE_UNUSED) +{ + struct rewrite_block_data *bd + = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + /* Step 5. Restore the current reaching definition for each variable + referenced in the block (in reverse order). */ + while (bd->block_defs && VARRAY_ACTIVE_SIZE (bd->block_defs) > 0) + { + tree tmp = VARRAY_TOP_TREE (bd->block_defs); + tree saved_def, var; + + VARRAY_POP (bd->block_defs); + if (TREE_CODE (tmp) == SSA_NAME) + { + saved_def = tmp; + var = SSA_NAME_VAR (saved_def); + } + else + { + saved_def = NULL; + var = tmp; + } + + var_ann (var)->current_def = saved_def; + } +} + + +/* Dump SSA information to FILE. */ + +void +dump_tree_ssa (FILE *file) +{ + basic_block bb; + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + fprintf (file, "SSA information for %s\n\n", funcname); + + FOR_EACH_BB (bb) + { + dump_bb (bb, file, 0); + fputs (" ", file); + print_generic_stmt (file, phi_nodes (bb), dump_flags); + fputs ("\n\n", file); + } +} + + +/* Dump SSA information to stderr. */ + +void +debug_tree_ssa (void) +{ + dump_tree_ssa (stderr); +} + + +/* Dump SSA statistics on FILE. */ + +void +dump_tree_ssa_stats (FILE *file) +{ + fprintf (file, "\nHash table statistics:\n"); + + fprintf (file, " def_blocks: "); + htab_statistics (file, def_blocks); + + fprintf (file, "\n"); +} + + +/* Dump SSA statistics on stderr. */ + +void +debug_tree_ssa_stats (void) +{ + dump_tree_ssa_stats (stderr); +} + + +/* Dump statistics for the hash table HTAB. */ + +static void +htab_statistics (FILE *file, htab_t htab) +{ + fprintf (file, "size %ld, %ld elements, %f collision/search ratio\n", + (long) htab_size (htab), + (long) htab_elements (htab), + htab_collisions (htab)); +} + + +/* Insert PHI nodes for variable VAR using the dominance frontier + information given in DFS. */ + +static void +insert_phi_nodes_for (tree var, bitmap *dfs, varray_type *work_stack) +{ + struct def_blocks_d *def_map; + bitmap phi_insertion_points; + int bb_index; + + def_map = find_def_blocks_for (var); + if (def_map == NULL) + return; + + phi_insertion_points = BITMAP_XMALLOC (); + + EXECUTE_IF_SET_IN_BITMAP (def_map->def_blocks, 0, bb_index, + { + VARRAY_PUSH_BB (*work_stack, BASIC_BLOCK (bb_index)); + }); + + /* Pop a block off the worklist, add every block that appears in + the original block's dfs that we have not already processed to + the worklist. Iterate until the worklist is empty. Blocks + which are added to the worklist are potential sites for + PHI nodes. + + The iteration step could be done during PHI insertion just as + easily. We do it here for historical reasons -- we used to have + a heuristic which used the potential PHI insertion points to + determine if fully pruned or semi pruned SSA form was appropriate. + + We now always use fully pruned SSA form. */ + while (VARRAY_ACTIVE_SIZE (*work_stack) > 0) + { + basic_block bb = VARRAY_TOP_BB (*work_stack); + int bb_index = bb->index; + int dfs_index; + + VARRAY_POP (*work_stack); + + EXECUTE_IF_AND_COMPL_IN_BITMAP (dfs[bb_index], + phi_insertion_points, + 0, dfs_index, + { + basic_block bb = BASIC_BLOCK (dfs_index); + + VARRAY_PUSH_BB (*work_stack, bb); + bitmap_set_bit (phi_insertion_points, dfs_index); + }); + } + + /* Now compute global livein for this variable. Note this modifies + def_map->livein_blocks. */ + compute_global_livein (def_map->livein_blocks, def_map->def_blocks); + + /* And insert the PHI nodes. */ + EXECUTE_IF_AND_IN_BITMAP (phi_insertion_points, def_map->livein_blocks, + 0, bb_index, + { + create_phi_node (var, BASIC_BLOCK (bb_index)); + }); + + BITMAP_FREE (phi_insertion_points); +} + +/* SSA Rewriting Step 2. Rewrite every variable used in each statement in + the block with its immediate reaching definitions. Update the current + definition of a variable when a new real or virtual definition is found. */ + +static void +rewrite_stmt (struct dom_walk_data *walk_data, + basic_block bb ATTRIBUTE_UNUSED, + block_stmt_iterator si) +{ + size_t i; + stmt_ann_t ann; + tree stmt; + vuse_optype vuses; + vdef_optype vdefs; + def_optype defs; + use_optype uses; + struct rewrite_block_data *bd; + + bd = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + stmt = bsi_stmt (si); + ann = stmt_ann (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Renaming statement "); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + fprintf (dump_file, "\n"); + } + +#if defined ENABLE_CHECKING + /* We have just scanned the code for operands. No statement should + be modified. */ + if (ann->modified) + abort (); +#endif + + defs = DEF_OPS (ann); + uses = USE_OPS (ann); + vuses = VUSE_OPS (ann); + vdefs = VDEF_OPS (ann); + + /* Step 1. Rewrite USES and VUSES in the statement. */ + for (i = 0; i < NUM_USES (uses); i++) + rewrite_operand (USE_OP_PTR (uses, i)); + + /* Rewrite virtual uses in the statement. */ + for (i = 0; i < NUM_VUSES (vuses); i++) + rewrite_operand (VUSE_OP_PTR (vuses, i)); + + /* Step 2. Register the statement's DEF and VDEF operands. */ + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree *def_p = DEF_OP_PTR (defs, i); + + if (TREE_CODE (*def_p) != SSA_NAME) + *def_p = make_ssa_name (*def_p, stmt); + + /* FIXME: We shouldn't be registering new defs if the variable + doesn't need to be renamed. */ + register_new_def (*def_p, &bd->block_defs); + } + + /* Register new virtual definitions made by the statement. */ + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + rewrite_operand (VDEF_OP_PTR (vdefs, i)); + + if (TREE_CODE (VDEF_RESULT (vdefs, i)) != SSA_NAME) + *VDEF_RESULT_PTR (vdefs, i) + = make_ssa_name (VDEF_RESULT (vdefs, i), stmt); + + /* FIXME: We shouldn't be registering new defs if the variable + doesn't need to be renamed. */ + register_new_def (VDEF_RESULT (vdefs, i), &bd->block_defs); + } +} + + +/* Replace the operand pointed by OP_P with its immediate reaching + definition. */ + +static inline void +rewrite_operand (tree *op_p) +{ + if (TREE_CODE (*op_p) != SSA_NAME) + *op_p = get_reaching_def (*op_p); +} + + +/* Register DEF (an SSA_NAME) to be a new definition for its underlying + variable (SSA_NAME_VAR (DEF)) and push VAR's current reaching definition + into the stack pointed by BLOCK_DEFS_P. */ + +void +register_new_def (tree def, varray_type *block_defs_p) +{ + tree var = SSA_NAME_VAR (def); + tree currdef; + + /* If this variable is set in a single basic block and all uses are + dominated by the set(s) in that single basic block, then there is + no reason to record anything for this variable in the block local + definition stacks. Doing so just wastes time and memory. + + This is the same test to prune the set of variables which may + need PHI nodes. So we just use that information since it's already + computed and available for us to use. */ + if (var_ann (var)->need_phi_state == NEED_PHI_STATE_NO) + { + var_ann (var)->current_def = def; + return; + } + + currdef = var_ann (var)->current_def; + if (! *block_defs_p) + VARRAY_TREE_INIT (*block_defs_p, 20, "block_defs"); + + /* Push the current reaching definition into *BLOCK_DEFS_P. This stack is + later used by the dominator tree callbacks to restore the reaching + definitions for all the variables defined in the block after a recursive + visit to all its immediately dominated blocks. If there is no current + reaching definition, then just record the underlying _DECL node. */ + VARRAY_PUSH_TREE (*block_defs_p, currdef ? currdef : var); + + /* Set the current reaching definition for VAR to be DEF. */ + var_ann (var)->current_def = def; +} + + +/* Return the current definition for variable VAR. If none is found, + create a new SSA name to act as the zeroth definition for VAR. If VAR + is call clobbered and there exists a more recent definition of + GLOBAL_VAR, return the definition for GLOBAL_VAR. This means that VAR + has been clobbered by a function call since its last assignment. */ + +static tree +get_reaching_def (tree var) +{ + tree default_d, currdef_var; + + /* Lookup the current reaching definition for VAR. */ + default_d = NULL_TREE; + currdef_var = var_ann (var)->current_def; + + /* If there is no reaching definition for VAR, create and register a + default definition for it (if needed). */ + if (currdef_var == NULL_TREE) + { + default_d = default_def (var); + if (default_d == NULL_TREE) + { + default_d = make_ssa_name (var, build_empty_stmt ()); + set_default_def (var, default_d); + } + var_ann (var)->current_def = default_d; + } + + /* Return the current reaching definition for VAR, or the default + definition, if we had to create one. */ + return (currdef_var) ? currdef_var : default_d; +} + + +/* Hashing and equality functions for DEF_BLOCKS. */ + +static hashval_t +def_blocks_hash (const void *p) +{ + return htab_hash_pointer + ((const void *)((const struct def_blocks_d *)p)->var); +} + +static int +def_blocks_eq (const void *p1, const void *p2) +{ + return ((const struct def_blocks_d *)p1)->var + == ((const struct def_blocks_d *)p2)->var; +} + +/* Free memory allocated by one entry in DEF_BLOCKS. */ + +static void +def_blocks_free (void *p) +{ + struct def_blocks_d *entry = p; + BITMAP_FREE (entry->def_blocks); + BITMAP_FREE (entry->livein_blocks); + free (entry); +} + + +/* Dump the DEF_BLOCKS hash table on stderr. */ + +void +debug_def_blocks (void) +{ + htab_traverse (def_blocks, debug_def_blocks_r, NULL); +} + +/* Callback for htab_traverse to dump the DEF_BLOCKS hash table. */ + +static int +debug_def_blocks_r (void **slot, void *data ATTRIBUTE_UNUSED) +{ + unsigned long i; + struct def_blocks_d *db_p = (struct def_blocks_d *) *slot; + + fprintf (stderr, "VAR: "); + print_generic_expr (stderr, db_p->var, dump_flags); + fprintf (stderr, ", DEF_BLOCKS: { "); + EXECUTE_IF_SET_IN_BITMAP (db_p->def_blocks, 0, i, + fprintf (stderr, "%ld ", i)); + fprintf (stderr, "}"); + fprintf (stderr, ", LIVEIN_BLOCKS: { "); + EXECUTE_IF_SET_IN_BITMAP (db_p->livein_blocks, 0, i, + fprintf (stderr, "%ld ", i)); + fprintf (stderr, "}\n"); + + return 1; +} + + +/* Return the set of blocks where variable VAR is defined and the blocks + where VAR is live on entry (livein). Return NULL, if no entry is + found in DEF_BLOCKS. */ + +static inline struct def_blocks_d * +find_def_blocks_for (tree var) +{ + struct def_blocks_d dm; + dm.var = var; + return (struct def_blocks_d *) htab_find (def_blocks, &dm); +} + + +/* Return the set of blocks where variable VAR is defined and the blocks + where VAR is live on entry (livein). If no entry is found in + DEF_BLOCKS, a new one is created and returned. */ + +static inline struct def_blocks_d * +get_def_blocks_for (tree var) +{ + struct def_blocks_d db, *db_p; + void **slot; + + db.var = var; + slot = htab_find_slot (def_blocks, (void *) &db, INSERT); + if (*slot == NULL) + { + db_p = xmalloc (sizeof (*db_p)); + db_p->var = var; + db_p->def_blocks = BITMAP_XMALLOC (); + db_p->livein_blocks = BITMAP_XMALLOC (); + *slot = (void *) db_p; + } + else + db_p = (struct def_blocks_d *) *slot; + + return db_p; +} + +/* If a variable V in VARS_TO_RENAME is a pointer, the renaming + process will cause us to lose the name memory tags that may have + been associated with the various SSA_NAMEs of V. This means that + the variables aliased to those name tags also need to be renamed + again. + + FIXME 1- We should either have a better scheme for renaming + pointers that doesn't lose name tags or re-run alias + analysis to recover points-to information. + + 2- Currently we just invalidate *all* the name tags. This + should be more selective. */ + +static void +invalidate_name_tags (bitmap vars_to_rename) +{ + size_t i; + bool rename_name_tags_p; + + rename_name_tags_p = false; + EXECUTE_IF_SET_IN_BITMAP (vars_to_rename, 0, i, + if (POINTER_TYPE_P (TREE_TYPE (referenced_var (i)))) + { + rename_name_tags_p = true; + break; + }); + + if (rename_name_tags_p) + for (i = 0; i < num_referenced_vars; i++) + { + var_ann_t ann = var_ann (referenced_var (i)); + + if (ann->mem_tag_kind == NAME_TAG) + { + size_t j; + varray_type may_aliases = ann->may_aliases; + + bitmap_set_bit (vars_to_rename, ann->uid); + if (ann->may_aliases) + for (j = 0; j < VARRAY_ACTIVE_SIZE (may_aliases); j++) + { + tree var = VARRAY_TREE (may_aliases, j); + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + } + } +} + + +/* Main entry point into the SSA builder. The renaming process + proceeds in five main phases: + + 1- If VARS_TO_RENAME has any entries, any existing PHI nodes for + those variables are removed from the flow graph so that they can + be computed again. + + 2- Compute dominance frontier and immediate dominators, needed to + insert PHI nodes and rename the function in dominator tree + order. + + 3- Find and mark all the blocks that define variables + (mark_def_sites). + + 4- Insert PHI nodes at dominance frontiers (insert_phi_nodes). + + 5- Rename all the blocks (rewrite_initialize_block, + rewrite_add_phi_arguments) and statements in the program + (rewrite_stmt). + + Steps 3 and 5 are done using the dominator tree walker + (walk_dominator_tree). */ + +void +rewrite_into_ssa (void) +{ + bitmap *dfs; + basic_block bb; + struct dom_walk_data walk_data; + struct mark_def_sites_global_data mark_def_sites_global_data; + unsigned int i; + + timevar_push (TV_TREE_SSA_OTHER); + + /* Initialize the array of variables to rename. */ + if (vars_to_rename != NULL) + { + invalidate_name_tags (vars_to_rename); + + /* Now remove all the existing PHI nodes (if any) for the variables + that we are about to rename into SSA. */ + remove_all_phi_nodes_for (vars_to_rename); + } + + /* Allocate memory for the DEF_BLOCKS hash table. */ + def_blocks = htab_create (VARRAY_ACTIVE_SIZE (referenced_vars), + def_blocks_hash, def_blocks_eq, def_blocks_free); + + /* Initialize dominance frontier and immediate dominator bitmaps. + Also count the number of predecessors for each block. Doing so + can save significant time during PHI insertion for large graphs. */ + dfs = (bitmap *) xmalloc (last_basic_block * sizeof (bitmap *)); + FOR_EACH_BB (bb) + { + edge e; + int count = 0; + + for (e = bb->pred; e; e = e->pred_next) + count++; + + bb_ann (bb)->num_preds = count; + dfs[bb->index] = BITMAP_XMALLOC (); + } + + for (i = 0; i < num_referenced_vars; i++) + var_ann (referenced_var (i))->current_def = NULL; + + /* Ensure that the dominance information is OK. */ + calculate_dominance_info (CDI_DOMINATORS); + + /* Compute dominance frontiers. */ + compute_dominance_frontiers (dfs); + + /* Setup callbacks for the generic dominator tree walker to find and + mark definition sites. */ + walk_data.walk_stmts_backward = false; + walk_data.dom_direction = CDI_DOMINATORS; + walk_data.initialize_block_local_data = NULL; + walk_data.before_dom_children_before_stmts = mark_def_sites_initialize_block; + walk_data.before_dom_children_walk_stmts = mark_def_sites; + walk_data.before_dom_children_after_stmts = NULL; + walk_data.after_dom_children_before_stmts = NULL; + walk_data.after_dom_children_walk_stmts = NULL; + walk_data.after_dom_children_after_stmts = NULL; + + /* Notice that this bitmap is indexed using variable UIDs, so it must be + large enough to accommodate all the variables referenced in the + function, not just the ones we are renaming. */ + mark_def_sites_global_data.kills = sbitmap_alloc (num_referenced_vars); + walk_data.global_data = &mark_def_sites_global_data; + + /* We do not have any local data. */ + walk_data.block_local_data_size = 0; + + /* Initialize the dominator walker. */ + init_walk_dominator_tree (&walk_data); + + /* Recursively walk the dominator tree. */ + walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR); + + /* Finalize the dominator walker. */ + fini_walk_dominator_tree (&walk_data); + + /* We no longer need this bitmap, clear and free it. */ + sbitmap_free (mark_def_sites_global_data.kills); + + /* Insert PHI nodes at dominance frontiers of definition blocks. */ + insert_phi_nodes (dfs); + + /* Rewrite all the basic blocks in the program. */ + timevar_push (TV_TREE_SSA_REWRITE_BLOCKS); + + /* Setup callbacks for the generic dominator tree walker. */ + walk_data.walk_stmts_backward = false; + walk_data.dom_direction = CDI_DOMINATORS; + walk_data.initialize_block_local_data = rewrite_initialize_block_local_data; + walk_data.before_dom_children_before_stmts = rewrite_initialize_block; + walk_data.before_dom_children_walk_stmts = rewrite_stmt; + walk_data.before_dom_children_after_stmts = rewrite_add_phi_arguments; + walk_data.after_dom_children_before_stmts = NULL; + walk_data.after_dom_children_walk_stmts = NULL; + walk_data.after_dom_children_after_stmts = rewrite_finalize_block; + walk_data.global_data = NULL; + walk_data.block_local_data_size = sizeof (struct rewrite_block_data); + + /* Initialize the dominator walker. */ + init_walk_dominator_tree (&walk_data); + + /* Recursively walk the dominator tree rewriting each statement in + each basic block. */ + walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR); + + /* Finalize the dominator walker. */ + fini_walk_dominator_tree (&walk_data); + + timevar_pop (TV_TREE_SSA_REWRITE_BLOCKS); + + /* Debugging dumps. */ + if (dump_file && (dump_flags & TDF_STATS)) + { + dump_dfa_stats (dump_file); + dump_tree_ssa_stats (dump_file); + } + + /* Free allocated memory. */ + FOR_EACH_BB (bb) + BITMAP_XFREE (dfs[bb->index]); + free (dfs); + + htab_delete (def_blocks); + + timevar_pop (TV_TREE_SSA_OTHER); +} + +struct tree_opt_pass pass_build_ssa = +{ + "ssa", /* name */ + NULL, /* gate */ + rewrite_into_ssa, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg | PROP_referenced_vars, /* properties_required */ + PROP_ssa, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */ +}; diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c new file mode 100644 index 00000000000..3f0eb5c9dc3 --- /dev/null +++ b/gcc/tree-iterator.c @@ -0,0 +1,369 @@ +/* Iterator routines for manipulating GENERIC and GIMPLE tree statements. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-simple.h" +#include "tree-iterator.h" +#include "ggc.h" + + +/* This is a cache of STATEMENT_LIST nodes. We create and destroy them + fairly often during gimplification. */ + +static GTY ((deletable (""))) tree stmt_list_cache; + +tree +alloc_stmt_list (void) +{ + tree list = stmt_list_cache; + if (list) + { + stmt_list_cache = TREE_CHAIN (list); + TREE_CHAIN (list) = NULL; + TREE_SIDE_EFFECTS (list) = 0; + } + else + { + list = make_node (STATEMENT_LIST); + TREE_TYPE (list) = void_type_node; + } + return list; +} + +void +free_stmt_list (tree t) +{ +#ifdef ENABLE_CHECKING + if (STATEMENT_LIST_HEAD (t) || STATEMENT_LIST_TAIL (t)) + abort (); +#endif + TREE_CHAIN (t) = stmt_list_cache; + stmt_list_cache = t; +} + +/* Links a statement, or a chain of statements, before the current stmt. */ + +void +tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode) +{ + struct tree_statement_list_node *head, *tail, *cur; + + /* Die on looping. */ + if (t == i->container) + abort (); + + TREE_SIDE_EFFECTS (i->container) = 1; + + if (TREE_CODE (t) == STATEMENT_LIST) + { + head = STATEMENT_LIST_HEAD (t); + tail = STATEMENT_LIST_TAIL (t); + STATEMENT_LIST_HEAD (t) = NULL; + STATEMENT_LIST_TAIL (t) = NULL; + + free_stmt_list (t); + + /* Empty statement lists need no work. */ + if (!head || !tail) + { + if (head != tail) + abort (); + return; + } + } + else + { + head = ggc_alloc (sizeof (*head)); + head->prev = NULL; + head->next = NULL; + head->stmt = t; + tail = head; + } + + cur = i->ptr; + + /* Link it into the list. */ + if (cur) + { + head->prev = cur->prev; + if (head->prev) + head->prev->next = head; + else + STATEMENT_LIST_HEAD (i->container) = head; + tail->next = cur; + cur->prev = tail; + } + else + { + if (STATEMENT_LIST_TAIL (i->container)) + abort (); + STATEMENT_LIST_HEAD (i->container) = head; + STATEMENT_LIST_TAIL (i->container) = tail; + } + + /* Update the iterator, if requested. */ + switch (mode) + { + case TSI_NEW_STMT: + case TSI_CONTINUE_LINKING: + case TSI_CHAIN_START: + i->ptr = head; + break; + case TSI_CHAIN_END: + i->ptr = tail; + break; + case TSI_SAME_STMT: + if (!cur) + abort (); + break; + } +} + +/* Links a statement, or a chain of statements, after the current stmt. */ + +void +tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode) +{ + struct tree_statement_list_node *head, *tail, *cur; + + /* Die on looping. */ + if (t == i->container) + abort (); + + TREE_SIDE_EFFECTS (i->container) = 1; + + if (TREE_CODE (t) == STATEMENT_LIST) + { + head = STATEMENT_LIST_HEAD (t); + tail = STATEMENT_LIST_TAIL (t); + STATEMENT_LIST_HEAD (t) = NULL; + STATEMENT_LIST_TAIL (t) = NULL; + + free_stmt_list (t); + + /* Empty statement lists need no work. */ + if (!head || !tail) + { + if (head != tail) + abort (); + return; + } + } + else + { + head = ggc_alloc (sizeof (*head)); + head->prev = NULL; + head->next = NULL; + head->stmt = t; + tail = head; + } + + cur = i->ptr; + + /* Link it into the list. */ + if (cur) + { + tail->next = cur->next; + if (tail->next) + tail->next->prev = tail; + else + STATEMENT_LIST_TAIL (i->container) = tail; + head->prev = cur; + cur->next = head; + } + else + { + if (STATEMENT_LIST_TAIL (i->container)) + abort (); + STATEMENT_LIST_HEAD (i->container) = head; + STATEMENT_LIST_TAIL (i->container) = tail; + } + + /* Update the iterator, if requested. */ + switch (mode) + { + case TSI_NEW_STMT: + case TSI_CHAIN_START: + i->ptr = head; + break; + case TSI_CONTINUE_LINKING: + case TSI_CHAIN_END: + i->ptr = tail; + break; + case TSI_SAME_STMT: + if (!cur) + abort (); + break; + } +} + +/* Remove a stmt from the tree list. The iterator is updated to point to + the next stmt. */ + +void +tsi_delink (tree_stmt_iterator *i) +{ + struct tree_statement_list_node *cur, *next, *prev; + + cur = i->ptr; + next = cur->next; + prev = cur->prev; + + if (prev) + prev->next = next; + else + STATEMENT_LIST_HEAD (i->container) = next; + if (next) + next->prev = prev; + else + STATEMENT_LIST_TAIL (i->container) = prev; + + if (!next && !prev) + TREE_SIDE_EFFECTS (i->container) = 0; + + i->ptr = next; +} + +/* Move all statements in the statement list after I to a new + statement list. I itself is unchanged. */ + +tree +tsi_split_statement_list_after (const tree_stmt_iterator *i) +{ + struct tree_statement_list_node *cur, *next; + tree old_sl, new_sl; + + cur = i->ptr; + /* How can we possibly split after the end, or before the beginning? */ + if (cur == NULL) + abort (); + next = cur->next; + + old_sl = i->container; + new_sl = alloc_stmt_list (); + TREE_SIDE_EFFECTS (new_sl) = 1; + + STATEMENT_LIST_HEAD (new_sl) = next; + STATEMENT_LIST_TAIL (new_sl) = STATEMENT_LIST_TAIL (old_sl); + STATEMENT_LIST_TAIL (old_sl) = cur; + cur->next = NULL; + next->prev = NULL; + + return new_sl; +} + +/* Move all statements in the statement list before I to a new + statement list. I is set to the head of the new list. */ + +tree +tsi_split_statement_list_before (tree_stmt_iterator *i) +{ + struct tree_statement_list_node *cur, *prev; + tree old_sl, new_sl; + + cur = i->ptr; + /* How can we possibly split after the end, or before the beginning? */ + if (cur == NULL) + abort (); + prev = cur->prev; + + old_sl = i->container; + new_sl = alloc_stmt_list (); + TREE_SIDE_EFFECTS (new_sl) = 1; + i->container = new_sl; + + STATEMENT_LIST_HEAD (new_sl) = cur; + STATEMENT_LIST_TAIL (new_sl) = STATEMENT_LIST_TAIL (old_sl); + STATEMENT_LIST_TAIL (old_sl) = prev; + cur->prev = NULL; + prev->next = NULL; + + return new_sl; +} + +/* Return the first expression in a sequence of COMPOUND_EXPRs, + or in a STATEMENT_LIST. */ + +tree +expr_first (tree expr) +{ + if (expr == NULL_TREE) + return expr; + + if (TREE_CODE (expr) == STATEMENT_LIST) + { + struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr); + return n ? n->stmt : NULL_TREE; + } + + while (TREE_CODE (expr) == COMPOUND_EXPR) + expr = TREE_OPERAND (expr, 0); + return expr; +} + +/* Return the last expression in a sequence of COMPOUND_EXPRs, + or in a STATEMENT_LIST. */ + +tree +expr_last (tree expr) +{ + if (expr == NULL_TREE) + return expr; + + if (TREE_CODE (expr) == STATEMENT_LIST) + { + struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr); + return n ? n->stmt : NULL_TREE; + } + + while (TREE_CODE (expr) == COMPOUND_EXPR) + expr = TREE_OPERAND (expr, 1); + return expr; +} + +/* If EXPR is a single statement, naked or in a STATEMENT_LIST, then + return it. Otherwise return NULL. */ + +tree +expr_only (tree expr) +{ + if (expr == NULL_TREE) + return NULL_TREE; + + if (TREE_CODE (expr) == STATEMENT_LIST) + { + struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr); + if (n && STATEMENT_LIST_HEAD (expr) == n) + return n->stmt; + else + return NULL_TREE; + } + + if (TREE_CODE (expr) == COMPOUND_EXPR) + return NULL_TREE; + + return expr; +} + +#include "gt-tree-iterator.h" diff --git a/gcc/tree-iterator.h b/gcc/tree-iterator.h new file mode 100644 index 00000000000..9008b1b1d00 --- /dev/null +++ b/gcc/tree-iterator.h @@ -0,0 +1,120 @@ +/* Iterator routines for manipulating GENERIC and GIMPLE tree statements. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* This file is dependent upon the implementation of tree's. It provides an + abstract interface to the tree objects such that if all tree creation and + manipulations are done through this interface, we can easily change the + implementation of tree's, and not impact other code. */ + +#ifndef GCC_TREE_ITERATOR_H +#define GCC_TREE_ITERATOR_H 1 + +/* Iterator object for GENERIC or GIMPLE TREE statements. */ + +typedef struct { + struct tree_statement_list_node *ptr; + tree container; +} tree_stmt_iterator; + +static inline tree_stmt_iterator +tsi_start (tree t) +{ + tree_stmt_iterator i; + + i.ptr = STATEMENT_LIST_HEAD (t); + i.container = t; + + return i; +} + +static inline tree_stmt_iterator +tsi_last (tree t) +{ + tree_stmt_iterator i; + + i.ptr = STATEMENT_LIST_TAIL (t); + i.container = t; + + return i; +} + +static inline bool +tsi_end_p (tree_stmt_iterator i) +{ + return i.ptr == NULL; +} + +static inline bool +tsi_one_before_end_p (tree_stmt_iterator i) +{ + return i.ptr != NULL && i.ptr->next == NULL; +} + +static inline void +tsi_next (tree_stmt_iterator *i) +{ + i->ptr = i->ptr->next; +} + +static inline void +tsi_prev (tree_stmt_iterator *i) +{ + i->ptr = i->ptr->prev; +} + +static inline tree * +tsi_stmt_ptr (tree_stmt_iterator i) +{ + return &i.ptr->stmt; +} + +static inline tree +tsi_stmt (tree_stmt_iterator i) +{ + return i.ptr->stmt; +} + +enum tsi_iterator_update +{ + TSI_NEW_STMT, /* Leave the iterator at the same statement. */ + TSI_SAME_STMT, /* Only valid when single statement is added, move + iterator to it. */ + TSI_CHAIN_START, /* Only valid when chain of statements is added, move + iterator to the first statement in the chain. */ + TSI_CHAIN_END, /* Only valid when chain of statements is added, move + iterator to the last statement in the chain. */ + TSI_CONTINUE_LINKING /* Move iterator to whatever position is suitable for + linking other statements/chains of statements in + the same direction. */ +}; + +extern void tsi_link_before (tree_stmt_iterator *, tree, + enum tsi_iterator_update); +extern void tsi_link_after (tree_stmt_iterator *, tree, + enum tsi_iterator_update); + +void tsi_delink (tree_stmt_iterator *); + +tree tsi_split_statement_list_after (const tree_stmt_iterator *); +tree tsi_split_statement_list_before (tree_stmt_iterator *); + +#endif /* GCC_TREE_ITERATOR_H */ diff --git a/gcc/tree-mudflap.c b/gcc/tree-mudflap.c new file mode 100644 index 00000000000..9172541af39 --- /dev/null +++ b/gcc/tree-mudflap.c @@ -0,0 +1,1093 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" +#include "errors.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "function.h" +#include "tree-inline.h" +#include "tree-simple.h" +#include "tree-flow.h" +#include "tree-mudflap.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "hashtab.h" +#include "diagnostic.h" +#include +#include "langhooks.h" +#include "ggc.h" + +/* Internal function decls */ + +static void mf_xform_derefs (tree); +static void mf_xform_decls (tree, tree); +static void mf_init_extern_trees (void); +static void mf_decl_cache_locals (tree *); +static void mf_decl_clear_locals (void); +static tree mf_varname_tree (tree); +static tree mx_xfn_xform_decls (tree *, int *, void *); + +static void mx_register_decls (tree, tree *); + + +/* extern mudflap functions */ + +static GTY ((param_is (union tree_node))) htab_t marked_trees = NULL; + + +/* Mark and return the given tree node to prevent further mudflap + transforms. */ +tree +mf_mark (tree t) +{ + void **slot; + + if (marked_trees == NULL) + marked_trees = htab_create_ggc (31, htab_hash_pointer, htab_eq_pointer, NULL); + + slot = htab_find_slot (marked_trees, t, INSERT); + *slot = t; + return t; +} + + +int +mf_marked_p (tree t) +{ + void *entry; + + if (marked_trees == NULL) + return 0; + + entry = htab_find (marked_trees, t); + return (entry != NULL); +} + +static tree +mf_build_string (const char *string) +{ + size_t len = strlen (string); + tree result = mf_mark (build_string (len + 1, string)); + + TREE_TYPE (result) + = build_array_type (char_type_node, + build_index_type (build_int_2 (len, 0))); + TREE_CONSTANT (result) = 1; + TREE_INVARIANT (result) = 1; + TREE_READONLY (result) = 1; + TREE_STATIC (result) = 1; + + result = build1 (ADDR_EXPR, build_pointer_type (char_type_node), result); + + return mf_mark (result); +} + +/* Perform the declaration-related mudflap tree transforms on the + given function. Update its DECL_SAVED_TREE. */ + +static void +mudflap_function_decls (void) +{ + if (mf_marked_p (current_function_decl)) + return; + + push_gimplify_context (); + + mf_init_extern_trees (); + mf_xform_decls (DECL_SAVED_TREE (current_function_decl), + DECL_ARGUMENTS (current_function_decl)); + + pop_gimplify_context (NULL); +} + +static bool +gate_mudflap (void) +{ + return flag_mudflap != 0; +} + +struct tree_opt_pass pass_mudflap_1 = +{ + "mudflap1", /* name */ + gate_mudflap, /* gate */ + mudflap_function_decls, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_gimple_any, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ +}; + + +/* Same as above, for the indirection-related transforms. */ + +static void +mudflap_function_ops (void) +{ + if (mf_marked_p (current_function_decl)) + return; + + push_gimplify_context (); + + /* In multithreaded mode, don't cache the lookup cache parameters. */ + if (! flag_mudflap_threads) + mf_decl_cache_locals (&DECL_SAVED_TREE (current_function_decl)); + + mf_xform_derefs (DECL_SAVED_TREE (current_function_decl)); + + if (! flag_mudflap_threads) + mf_decl_clear_locals (); + + pop_gimplify_context (NULL); +} + +struct tree_opt_pass pass_mudflap_2 = +{ + "mudflap2", /* name */ + gate_mudflap, /* gate */ + mudflap_function_ops, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_gimple_leh, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ +}; + +/* global tree nodes */ + +/* Global tree objects for global variables and functions exported by + mudflap runtime library. mf_init_extern_trees must be called + before using these. */ + +/* uintptr_t (usually "unsigned long") */ +static GTY (()) tree mf_uintptr_type; + +/* struct __mf_cache { uintptr_t low; uintptr_t high; }; */ +static GTY (()) tree mf_cache_struct_type; + +/* struct __mf_cache * const */ +static GTY (()) tree mf_cache_structptr_type; + +/* extern struct __mf_cache __mf_lookup_cache []; */ +static GTY (()) tree mf_cache_array_decl; + +/* extern const unsigned char __mf_lc_shift; */ +static GTY (()) tree mf_cache_shift_decl; + +/* extern const uintptr_t __mf_lc_mask; */ +static GTY (()) tree mf_cache_mask_decl; + +/* Their function-scope local shadows, used in single-threaded mode only. */ + +/* auto const unsigned char __mf_lc_shift_l; */ +static GTY (()) tree mf_cache_shift_decl_l; + +/* auto const uintptr_t __mf_lc_mask_l; */ +static GTY (()) tree mf_cache_mask_decl_l; + +/* extern void __mf_check (void *ptr, size_t sz, int type, const char *); */ +static GTY (()) tree mf_check_fndecl; + +/* extern void __mf_register (void *ptr, size_t sz, int type, const char *); */ +static GTY (()) tree mf_register_fndecl; + +/* extern void __mf_unregister (void *ptr, size_t sz); */ +static GTY (()) tree mf_unregister_fndecl; + + +/* Initialize the global tree nodes that correspond to mf-runtime.h + declarations. */ +static void +mf_init_extern_trees (void) +{ + static bool done = false; + + if (done) + return; + done = true; + + mf_uintptr_type = TREE_TYPE (mflang_lookup_decl ("uintptr_t")); + mf_cache_array_decl = mf_mark (mflang_lookup_decl ("__mf_lookup_cache")); + mf_cache_struct_type = TREE_TYPE (TREE_TYPE (mf_cache_array_decl)); + mf_cache_structptr_type = build_pointer_type (mf_cache_struct_type); + mf_cache_shift_decl = mf_mark (mflang_lookup_decl ("__mf_lc_shift")); + mf_cache_mask_decl = mf_mark (mflang_lookup_decl ("__mf_lc_mask")); + mf_check_fndecl = mflang_lookup_decl ("__mf_check"); + mf_register_fndecl = mflang_lookup_decl ("__mf_register"); + mf_unregister_fndecl = mflang_lookup_decl ("__mf_unregister"); +} + + + +/* Create and initialize local shadow variables for the lookup cache + globals. Put their decls in the *_l globals for use by + mf_build_check_statement_for. */ + +static void +mf_decl_cache_locals (tree* body) +{ + tree_stmt_iterator i = tsi_start (*body); + tree t; + + mf_cache_shift_decl_l + = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_shift_decl), + "__mf_lookup_shift_l")); + + mf_cache_mask_decl_l + = mf_mark (create_tmp_var (TREE_TYPE (mf_cache_mask_decl), + "__mf_lookup_mask_l")); + + /* Build initialization nodes for them. */ + t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_shift_decl_l), + mf_cache_shift_decl_l, mf_cache_shift_decl); + annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl)); + gimplify_stmt (&t); + tsi_link_before (&i, t, TSI_NEW_STMT); + + t = build (MODIFY_EXPR, TREE_TYPE (mf_cache_mask_decl_l), + mf_cache_mask_decl_l, mf_cache_mask_decl); + annotate_with_locus (t, DECL_SOURCE_LOCATION (current_function_decl)); + gimplify_stmt (&t); + tsi_link_before (&i, t, TSI_NEW_STMT); +} + + +static void +mf_decl_clear_locals (void) +{ + /* Unset local shadows. */ + mf_cache_shift_decl_l = NULL_TREE; + mf_cache_mask_decl_l = NULL_TREE; +} + +/* Create a properly typed STRING_CST node that describes the given + declaration. It will be used as an argument for __mf_register(). + Try to construct a helpful string, including file/function/variable + name. */ + +static tree +mf_varname_tree (tree decl) +{ + static pretty_printer buf_rec; + static int initialized = 0; + pretty_printer *buf = & buf_rec; + const char *buf_contents; + tree result; + + if (decl == NULL_TREE) + abort (); + + if (!initialized) + { + pp_construct (buf, /* prefix */ NULL, /* line-width */ 0); + initialized = 1; + } + pp_clear_output_area (buf); + + /* Add FILENAME[:LINENUMBER]. */ + { + const char *sourcefile; + unsigned sourceline; + + sourcefile = DECL_SOURCE_FILE (decl); + if (sourcefile == NULL && current_function_decl != NULL_TREE) + sourcefile = DECL_SOURCE_FILE (current_function_decl); + if (sourcefile == NULL) + sourcefile = ""; + + pp_string (buf, sourcefile); + + sourceline = DECL_SOURCE_LINE (decl); + if (sourceline != 0) + { + pp_string (buf, ":"); + pp_decimal_int (buf, sourceline); + } + } + + if (current_function_decl != NULL_TREE) + { + /* Add (FUNCTION): */ + pp_string (buf, " ("); + { + const char *funcname = NULL; + if (DECL_NAME (current_function_decl)) + funcname = (*lang_hooks.decl_printable_name) (current_function_decl, 1); + if (funcname == NULL) + funcname = "anonymous fn"; + + pp_string (buf, funcname); + } + pp_string (buf, ") "); + } + else + pp_string (buf, " "); + + /* Add , possibly demangled. */ + { + const char *declname = NULL; + + if (strcmp ("GNU C++", lang_hooks.name) == 0 && + DECL_NAME (decl) != NULL) + { + /* The gcc/cp decl_printable_name hook doesn't do as good a job as + the libiberty demangler. */ + declname = cplus_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)), + DMGL_AUTO | DMGL_VERBOSE); + } + + if (declname == NULL) + declname = (*lang_hooks.decl_printable_name) (decl, 3); + + if (declname == NULL) + declname = ""; + + pp_string (buf, declname); + } + + /* Return the lot as a new STRING_CST. */ + buf_contents = pp_base_formatted_text (buf); + result = mf_build_string (buf_contents); + pp_clear_output_area (buf); + + return result; +} + + +/* And another friend, for producing a simpler message. */ + +static tree +mf_file_function_line_tree (location_t *locus) +{ + const char *file = NULL, *colon, *line, *op, *name, *cp; + char linebuf[18]; + char *string; + tree result; + + /* Add FILENAME. */ + if (locus != NULL) + file = locus->file; + if (file == NULL && current_function_decl != NULL_TREE) + file = DECL_SOURCE_FILE (current_function_decl); + if (file == NULL) + file = ""; + + /* Add :LINENUMBER. */ + if (locus != NULL && locus->line > 0) + { + sprintf (linebuf, "%d", locus->line); + colon = ":"; + line = linebuf; + } + else + colon = line = ""; + + /* Add (FUNCTION). */ + name = (*lang_hooks.decl_printable_name) (current_function_decl, 1); + if (name) + { + op = " ("; + cp = ")"; + } + else + op = name = cp = ""; + + string = concat (file, colon, line, op, name, cp, NULL); + result = mf_build_string (string); + free (string); + + return result; +} + + +static void +mf_build_check_statement_for (tree addr, tree size, tree_stmt_iterator *iter, + location_t *locus, tree dirflag) +{ + tree ptrtype = TREE_TYPE (addr); + tree stmt, cond, t, u, v; + tree mf_value; + tree mf_base; + tree mf_elem; + + /* Build our local variables. */ + mf_value = create_tmp_var (ptrtype, "__mf_value"); + mf_elem = create_tmp_var (mf_cache_structptr_type, "__mf_elem"); + mf_base = create_tmp_var (mf_uintptr_type, "__mf_base"); + + /* Build: __mf_value =
. */ + stmt = build (MODIFY_EXPR, void_type_node, mf_value, addr); + if (locus != NULL) + annotate_with_locus (stmt, *locus); + gimplify_stmt (&stmt); + tsi_link_before (iter, stmt, TSI_SAME_STMT); + + /* Build: __mf_base = (uintptr_t)__mf_value. */ + stmt = build (MODIFY_EXPR, void_type_node, mf_base, + build1 (NOP_EXPR, mf_uintptr_type, mf_value)); + if (locus != NULL) + annotate_with_locus (stmt, *locus); + gimplify_stmt (&stmt); + tsi_link_before (iter, stmt, TSI_SAME_STMT); + + /* Build: __mf_elem = &__mf_lookup_cache [(__mf_base >> __mf_shift) + & __mf_mask]. */ + t = build (RSHIFT_EXPR, mf_uintptr_type, mf_base, + (flag_mudflap_threads ? mf_cache_shift_decl : mf_cache_shift_decl_l)); + t = build (BIT_AND_EXPR, mf_uintptr_type, t, + (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l)); + t = build (ARRAY_REF, + TREE_TYPE (TREE_TYPE (mf_cache_array_decl)), + mf_cache_array_decl, t); + t = build1 (ADDR_EXPR, mf_cache_structptr_type, t); + stmt = build (MODIFY_EXPR, void_type_node, mf_elem, t); + if (locus != NULL) + annotate_with_locus (stmt, *locus); + gimplify_stmt (&stmt); + tsi_link_before (iter, stmt, TSI_SAME_STMT); + + /* Quick validity check. + if (__builtin_expect ((__mf_elem->low > __mf_base) + | (__mf_elem_high < __mf_base + sizeof(T) - 1), + 0)) + { + __mf_check (); + ... and only if single-threaded: + __mf_lookup_shift_1 = f...; + __mf_lookup_mask_l = ...; + } + */ + + /* __mf_elem->low */ + t = build (COMPONENT_REF, mf_uintptr_type, + build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), + TYPE_FIELDS (mf_cache_struct_type)); + + /* __mf_elem->high */ + u = build (COMPONENT_REF, mf_uintptr_type, + build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem), + TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type))); + + /* __mf_base + sizeof (T) - 1 */ + v = size_binop (MINUS_EXPR, size, size_one_node); + v = convert (mf_uintptr_type, v); + v = fold (build (PLUS_EXPR, mf_uintptr_type, mf_base, v)); + + t = build (TRUTH_OR_EXPR, boolean_type_node, + build (GT_EXPR, boolean_type_node, t, mf_base), + build (LT_EXPR, boolean_type_node, u, v)); + + /* Mark condition as UNLIKELY using __builtin_expect. */ + u = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE); + u = tree_cons (NULL_TREE, convert (long_integer_type_node, t), u); + cond = build_function_call_expr (built_in_decls[BUILT_IN_EXPECT], u); + + /* Build up the body of the cache-miss handling: + __mf_check(); refresh *_l vars. */ + + stmt = NULL; + + u = tree_cons (NULL_TREE, mf_file_function_line_tree (locus), NULL_TREE); + u = tree_cons (NULL_TREE, dirflag, u); + u = tree_cons (NULL_TREE, size, u); + u = tree_cons (NULL_TREE, mf_value, u); + t = build_function_call_expr (mf_check_fndecl, u); + append_to_statement_list (t, &stmt); + + if (! flag_mudflap_threads) + { + t = build (MODIFY_EXPR, void_type_node, + mf_cache_shift_decl_l, mf_cache_shift_decl); + append_to_statement_list (t, &stmt); + + t = build (MODIFY_EXPR, void_type_node, + mf_cache_mask_decl_l, mf_cache_mask_decl); + append_to_statement_list (t, &stmt); + } + + stmt = build (COND_EXPR, void_type_node, cond, stmt, build_empty_stmt ()); + if (locus != NULL) + annotate_with_locus (stmt, *locus); + gimplify_to_stmt_list (&stmt); + lower_stmt_body (stmt, NULL); + tsi_link_before (iter, stmt, TSI_SAME_STMT); +} + +static void +mf_xform_derefs_1 (tree_stmt_iterator *iter, tree *tp, + location_t *locus, tree dirflag) +{ + tree type, ptr_type, addr, size, t; + + /* Don't instrument read operations. */ + if (dirflag == integer_zero_node && flag_mudflap_ignore_reads) + return; + + t = *tp; + type = TREE_TYPE (t); + size = TYPE_SIZE_UNIT (type); + + switch (TREE_CODE (t)) + { + case ARRAY_REF: + { + /* Omit checking if we can statically determine that the access is + valid. For non-addressable local arrays this is not optional, + since we won't have called __mf_register for the object. */ + tree op0, op1; + + op0 = TREE_OPERAND (t, 0); + op1 = TREE_OPERAND (t, 1); + while (TREE_CODE (op1) == INTEGER_CST) + { + tree dom = TYPE_DOMAIN (TREE_TYPE (op0)); + + /* Test for index in range. Break if not. */ + if (!dom) + break; + if (!TYPE_MIN_VALUE (dom) || !really_constant_p (TYPE_MIN_VALUE (dom))) + break; + if (!TYPE_MAX_VALUE (dom) || !really_constant_p (TYPE_MAX_VALUE (dom))) + break; + if (tree_int_cst_lt (op1, TYPE_MIN_VALUE (dom)) + || tree_int_cst_lt (TYPE_MAX_VALUE (dom), op1)) + break; + + /* If we're looking at a non-external VAR_DECL, then the + access must be ok. */ + if (TREE_CODE (op0) == VAR_DECL && !DECL_EXTERNAL (op0)) + return; + + /* Only continue if we're still looking at an array. */ + if (TREE_CODE (op0) != ARRAY_REF) + break; + + op1 = TREE_OPERAND (op0, 1); + op0 = TREE_OPERAND (op0, 0); + } + + /* If we got here, we couldn't statically the check. */ + ptr_type = build_pointer_type (type); + addr = build1 (ADDR_EXPR, ptr_type, t); + } + break; + + case INDIRECT_REF: + addr = TREE_OPERAND (t, 0); + ptr_type = TREE_TYPE (addr); + break; + + case ARRAY_RANGE_REF: + warning ("mudflap checking not yet implemented for ARRAY_RANGE_REF"); + return; + + case COMPONENT_REF: + { + tree field; + + /* If we're not dereferencing something, then the access + must be ok. */ + if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF) + return; + + field = TREE_OPERAND (t, 1); + + /* If we're looking at a bit field, then we can't take its address + with ADDR_EXPR -- lang_hooks.mark_addressable will error. Do + things the hard way with PLUS. */ + if (DECL_BIT_FIELD_TYPE (field)) + { + size = bitsize_int (BITS_PER_UNIT); + size = size_binop (CEIL_DIV_EXPR, DECL_SIZE (field), size); + size = convert (sizetype, size); + + addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0); + addr = convert (ptr_type_node, addr); + addr = fold (build (PLUS_EXPR, ptr_type_node, + addr, byte_position (field))); + } + else + { + ptr_type = build_pointer_type (type); + addr = build1 (ADDR_EXPR, ptr_type, t); + } + } + break; + + case BIT_FIELD_REF: + { + tree ofs, rem, bpu; + + /* If we're not dereferencing something, then the access + must be ok. */ + if (TREE_CODE (TREE_OPERAND (t, 0)) != INDIRECT_REF) + return; + + bpu = bitsize_int (BITS_PER_UNIT); + ofs = convert (bitsizetype, TREE_OPERAND (t, 2)); + rem = size_binop (TRUNC_MOD_EXPR, ofs, bpu); + ofs = size_binop (TRUNC_DIV_EXPR, ofs, bpu); + + size = convert (bitsizetype, TREE_OPERAND (t, 1)); + size = size_binop (PLUS_EXPR, size, rem); + size = size_binop (CEIL_DIV_EXPR, size, bpu); + size = convert (sizetype, size); + + addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0); + addr = convert (ptr_type_node, addr); + addr = fold (build (PLUS_EXPR, ptr_type_node, addr, ofs)); + } + break; + + default: + return; + } + + mf_build_check_statement_for (addr, size, iter, locus, dirflag); +} + +static void +mf_xform_derefs (tree fnbody) +{ + tree_stmt_iterator i = tsi_start (fnbody); + + for (i = tsi_start (fnbody); !tsi_end_p (i); tsi_next (&i)) + { + tree s = tsi_stmt (i); + + /* Only a few GIMPLE statements can reference memory. */ + switch (TREE_CODE (s)) + { + case MODIFY_EXPR: /* This includes INIT_EXPR after gimplification. */ + mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s), + integer_one_node); + mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 1), EXPR_LOCUS (s), + integer_zero_node); + break; + + case RETURN_EXPR: + if (TREE_OPERAND (s, 0) != NULL_TREE) + { + if (TREE_CODE (TREE_OPERAND (s, 0)) == MODIFY_EXPR) + mf_xform_derefs_1 (&i, &TREE_OPERAND (TREE_OPERAND (s, 0), 1), EXPR_LOCUS (s), + integer_zero_node); + else + mf_xform_derefs_1 (&i, &TREE_OPERAND (s, 0), EXPR_LOCUS (s), + integer_zero_node); + } + break; + + default: + ; + } + } +} + +/* ------------------------------------------------------------------------ */ +/* ADDR_EXPR transform */ + + +/* This struct is passed between mf_xform_decls to store state needed + during the traversal searching for objects that have their + addresses taken. */ +struct mf_xform_decls_data +{ + tree param_decls; +}; + + +/* Synthesize a CALL_EXPR and a TRY_FINALLY_EXPR, for this chain of + _DECLs if appropriate. Arrange to call the __mf_register function + now, and the __mf_unregister function later for each. */ +static void +mx_register_decls (tree decl, tree *stmt_list) +{ + tree finally_stmts = NULL_TREE; + tree_stmt_iterator initially_stmts = tsi_start (*stmt_list); + + while (decl != NULL_TREE) + { + /* Eligible decl? */ + if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) && + (! TREE_STATIC (decl)) && /* auto variable */ + (! DECL_EXTERNAL (decl)) && /* not extern variable */ + (COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))) && /* complete type */ + (! mf_marked_p (decl)) && /* not already processed */ + (TREE_ADDRESSABLE (decl))) /* has address taken */ + { + tree size = NULL_TREE, variable_name; + tree unregister_fncall, unregister_fncall_params; + tree register_fncall, register_fncall_params; + + if (DECL_DEFER_OUTPUT (decl)) + { + /* Oh no ... it's probably a variable-length array (VLA). + The size and address cannot be computed by merely + looking at the DECL. See gimplfiy_decl_stmt for the + method by which VLA declarations turn into calls to + BUILT_IN_STACK_ALLOC. We assume that multiple + VLAs declared later in the same block get allocation + code later than the others. */ + tree stack_alloc_call = NULL_TREE; + + while(! tsi_end_p (initially_stmts)) + { + tree t = tsi_stmt (initially_stmts); + + tree call = NULL_TREE; + if (TREE_CODE (t) == CALL_EXPR) + call = t; + else if (TREE_CODE (t) == MODIFY_EXPR && + TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR) + call = TREE_OPERAND (t, 1); + else if (TREE_CODE (t) == TRY_FINALLY_EXPR) + { + /* We hope that this is the try/finally block sometimes + constructed by gimplify_bind_expr() for a BIND_EXPR + that contains VLAs. This very naive recursion + appears to be sufficient. */ + initially_stmts = tsi_start (TREE_OPERAND (t, 0)); + } + + if (call != NULL_TREE) + { + if (TREE_CODE (TREE_OPERAND(call, 0)) == ADDR_EXPR && + TREE_OPERAND (TREE_OPERAND (call, 0), 0) == + implicit_built_in_decls [BUILT_IN_STACK_ALLOC]) + { + tree stack_alloc_args = TREE_OPERAND (call, 1); + tree stack_alloc_op1 = TREE_VALUE (stack_alloc_args); + tree stack_alloc_op2 = TREE_VALUE (TREE_CHAIN (stack_alloc_args)); + + if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR && + TREE_OPERAND (stack_alloc_op1, 0) == decl) + { + /* Got it! */ + size = stack_alloc_op2; + stack_alloc_call = call; + /* Advance iterator to point past this allocation call. */ + tsi_next (&initially_stmts); + break; + } + } + } + + tsi_next (&initially_stmts); + } + + if (stack_alloc_call == NULL_TREE) + { + warning ("mudflap cannot handle variable-sized declaration `%s'", + IDENTIFIER_POINTER (DECL_NAME (decl))); + break; + } + } + else + { + size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl))); + } + + /* (& VARIABLE, sizeof (VARIABLE)) */ + unregister_fncall_params = + tree_cons (NULL_TREE, + convert (ptr_type_node, + mf_mark (build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (decl)), + decl))), + tree_cons (NULL_TREE, size, NULL_TREE)); + /* __mf_unregister (...) */ + unregister_fncall = build_function_call_expr (mf_unregister_fndecl, + unregister_fncall_params); + + /* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */ + variable_name = mf_varname_tree (decl); + register_fncall_params = + tree_cons (NULL_TREE, + convert (ptr_type_node, + mf_mark (build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (decl)), + decl))), + tree_cons (NULL_TREE, + size, + tree_cons (NULL_TREE, + build_int_2 (3, 0), /* __MF_TYPE_STACK */ + tree_cons (NULL_TREE, + variable_name, + NULL_TREE)))); + + /* __mf_register (...) */ + register_fncall = build_function_call_expr (mf_register_fndecl, + register_fncall_params); + + /* Accumulate the two calls. */ + /* ??? Set EXPR_LOCUS. */ + gimplify_stmt (®ister_fncall); + gimplify_stmt (&unregister_fncall); + + /* Add the __mf_register call at the current appending point. */ + if (tsi_end_p (initially_stmts)) + internal_error ("mudflap ran off end of BIND_EXPR body"); + tsi_link_before (& initially_stmts, register_fncall, TSI_SAME_STMT); + + /* Accumulate the FINALLY piece. */ + append_to_statement_list (unregister_fncall, &finally_stmts); + + mf_mark (decl); + } + + decl = TREE_CHAIN (decl); + } + + /* Actually, (initially_stmts!=NULL) <=> (finally_stmts!=NULL) */ + if (finally_stmts != NULL_TREE) + { + tree t = build (TRY_FINALLY_EXPR, void_type_node, + *stmt_list, finally_stmts); + *stmt_list = NULL; + append_to_statement_list (t, stmt_list); + } +} + + +/* Process every variable mentioned in BIND_EXPRs. */ +static tree +mx_xfn_xform_decls (tree *t, int *continue_p, void *data) +{ + struct mf_xform_decls_data* d = (struct mf_xform_decls_data*) data; + + if (*t == NULL_TREE || *t == error_mark_node) + { + *continue_p = 0; + return NULL_TREE; + } + + *continue_p = 1; + + switch (TREE_CODE (*t)) + { + case BIND_EXPR: + { + /* Process function parameters now (but only once). */ + mx_register_decls (d->param_decls, &BIND_EXPR_BODY (*t)); + d->param_decls = NULL_TREE; + + mx_register_decls (BIND_EXPR_VARS (*t), &BIND_EXPR_BODY (*t)); + } + break; + + default: + break; + } + + return NULL; +} + +/* Perform the object lifetime tracking mudflap transform on the given function + tree. The tree is mutated in place, with possibly copied subtree nodes. + + For every auto variable declared, if its address is ever taken + within the function, then supply its lifetime to the mudflap + runtime with the __mf_register and __mf_unregister calls. +*/ + +static void +mf_xform_decls (tree fnbody, tree fnparams) +{ + struct mf_xform_decls_data d; + d.param_decls = fnparams; + walk_tree_without_duplicates (&fnbody, mx_xfn_xform_decls, &d); +} + + +/* ------------------------------------------------------------------------ */ + + +/* Remember given node as a static of some kind: global data, + function-scope static, or an anonymous constant. Its assembler + label is given. +*/ + + +/* A list of globals whose incomplete declarations we encountered. + Instead of emitting the __mf_register call for them here, it's + delayed until program finish time. If they're still incomplete by + then, warnings are emitted. */ + +static GTY (()) varray_type deferred_static_decls; + +/* A list of statements for calling __mf_register() at startup time. */ +static GTY (()) tree enqueued_call_stmt_chain; + +static void +mudflap_register_call (tree obj, tree object_size, tree varname) +{ + tree arg, args, call_stmt; + + args = tree_cons (NULL_TREE, varname, NULL_TREE); + + arg = build_int_2 (4, 0); /* __MF_TYPE_STATIC */ + args = tree_cons (NULL_TREE, arg, args); + + arg = convert (size_type_node, object_size); + args = tree_cons (NULL_TREE, arg, args); + + arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (obj)), obj); + arg = convert (ptr_type_node, arg); + args = tree_cons (NULL_TREE, arg, args); + + mf_init_extern_trees (); + call_stmt = build_function_call_expr (mf_register_fndecl, args); + + append_to_statement_list (call_stmt, &enqueued_call_stmt_chain); +} + +void +mudflap_enqueue_decl (tree obj) +{ + if (mf_marked_p (obj)) + return; + + /* We don't need to process variable decls that are internally + generated extern. If we did, we'd end up with warnings for them + during mudflap_finish_file (). That would confuse the user, + since the text would refer to variables that don't show up in the + user's source code. */ + if (DECL_P (obj) && DECL_EXTERNAL (obj) && DECL_ARTIFICIAL (obj)) + return; + + if (COMPLETE_TYPE_P (TREE_TYPE (obj))) + { + tree object_size; + + mf_mark (obj); + + object_size = size_in_bytes (TREE_TYPE (obj)); + + if (dump_file) + { + fprintf (dump_file, "enqueue_decl obj=`"); + print_generic_expr (dump_file, obj, dump_flags); + fprintf (dump_file, "' size="); + print_generic_expr (dump_file, object_size, dump_flags); + fprintf (dump_file, "\n"); + } + + /* NB: the above condition doesn't require TREE_USED or + TREE_ADDRESSABLE. That's because this object may be a global + only used from other compilation units. XXX: Maybe static + objects could require those attributes being set. */ + + mudflap_register_call (obj, object_size, mf_varname_tree (obj)); + } + else + { + size_t i; + + if (! deferred_static_decls) + VARRAY_TREE_INIT (deferred_static_decls, 10, "deferred static list"); + + /* Ugh, linear search... */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++) + if (VARRAY_TREE (deferred_static_decls, i) == obj) + { + warning ("mudflap cannot track lifetime of `%s'", + IDENTIFIER_POINTER (DECL_NAME (obj))); + return; + } + + VARRAY_PUSH_TREE (deferred_static_decls, obj); + } +} + +void +mudflap_enqueue_constant (tree obj) +{ + tree object_size, varname; + + if (mf_marked_p (obj)) + return; + + if (TREE_CODE (obj) == STRING_CST) + object_size = build_int_2 (TREE_STRING_LENGTH (obj), 0); + else + object_size = size_in_bytes (TREE_TYPE (obj)); + + if (dump_file) + { + fprintf (dump_file, "enqueue_constant obj=`"); + print_generic_expr (dump_file, obj, dump_flags); + fprintf (dump_file, "' size="); + print_generic_expr (dump_file, object_size, dump_flags); + fprintf (dump_file, "\n"); + } + + if (TREE_CODE (obj) == STRING_CST) + varname = mf_build_string ("string literal"); + else + varname = mf_build_string ("constant"); + + mudflap_register_call (obj, object_size, varname); +} + + + +/* Emit any file-wide instrumentation. */ +void +mudflap_finish_file (void) +{ + /* Try to give the deferred objects one final try. */ + if (deferred_static_decls) + { + size_t i; + + for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_static_decls); i++) + { + tree obj = VARRAY_TREE (deferred_static_decls, i); + + /* Call enqueue_decl again on the same object it has previously + put into the table. (It won't modify the table this time, so + infinite iteration is not a problem.) */ + mudflap_enqueue_decl (obj); + } + + VARRAY_CLEAR (deferred_static_decls); + } + + mflang_flush_calls (enqueued_call_stmt_chain); +} + + + +#include "gt-tree-mudflap.h" diff --git a/gcc/tree-mudflap.h b/gcc/tree-mudflap.h new file mode 100644 index 00000000000..20c6ef9b1fc --- /dev/null +++ b/gcc/tree-mudflap.h @@ -0,0 +1,41 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef TREE_MUDFLAP_H +#define TREE_MUDFLAP_H + +/* Instrumentation. */ +extern void mudflap_c_function_decls (tree); +extern void mudflap_c_function_ops (tree); +extern void mudflap_enqueue_decl (tree); +extern void mudflap_enqueue_constant (tree); +extern void mudflap_finish_file (void); + +/* Tree node marking. */ +extern int mf_marked_p (tree); +extern tree mf_mark (tree); + +/* To be provided by a front-end interface module. */ +extern tree mflang_lookup_decl (const char *); +extern void mflang_flush_calls (tree); + + +#endif /* TREE_MUDFLAP_H */ diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c new file mode 100644 index 00000000000..7b92a75db30 --- /dev/null +++ b/gcc/tree-nested.c @@ -0,0 +1,1383 @@ +/* Nested function decomposition for trees. + Copyright (C) 2004 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "function.h" +#include "tree-dump.h" +#include "tree-inline.h" +#include "tree-simple.h" +#include "tree-iterator.h" +#include "tree-flow.h" +#include "cgraph.h" +#include "expr.h" +#include "langhooks.h" +#include "ggc.h" + + +/* The object of this pass is to lower the representation of a set of nested + functions in order to expose all of the gory details of the various + nonlocal references. We want to do this sooner rather than later, in + order to give us more freedom in emitting all of the functions in question. + + Back in olden times, when gcc was young, we developed an insanely + complicated scheme whereby variables which were referenced nonlocally + were forced to live in the stack of the declaring function, and then + the nested functions magically discovered where these variables were + placed. In order for this scheme to function properly, it required + that the outer function be partially expanded, then we switch to + compiling the inner function, and once done with those we switch back + to compiling the outer function. Such delicate ordering requirements + makes it difficult to do whole translation unit optimizations + involving such functions. + + The implementation here is much more direct. Everything that can be + referenced by an inner function is a member of an explicitly created + structure herein called the "nonlocal frame struct". The incomming + static chain for a nested function is a pointer to this struct in + the parent. In this way, we settle on known offsets from a known + base, and so are decoupled from the logic that places objects in the + function's stack frame. More importantly, we don't have to wait for + that to happen -- since the compilation of the inner function is no + longer tied to a real stack frame, the nonlocal frame struct can be + allocated anywhere. Which means that the outer function is now + inlinable. + + Theory of operation here is very simple. Iterate over all the + statements in all the functions (depth first) several times, + allocating structures and fields on demand. In general we want to + examine inner functions first, so that we can avoid making changes + to outer functions which are unnecessary. + + The order of the passes matters a bit, in that later passes will be + skipped if it is discovered that the functions don't actually interact + at all. That is, they're nested in the lexical sense but could have + been written as independent functions without change. */ + + +struct var_map_elt +{ + tree old; + tree new; +}; + +struct nesting_info +{ + struct nesting_info *outer; + struct nesting_info *inner; + struct nesting_info *next; + + htab_t var_map; + tree context; + tree new_local_var_chain; + tree frame_type; + tree frame_decl; + tree chain_field; + tree chain_decl; + tree nl_goto_field; + + bool any_parm_remapped; + bool any_tramp_created; +}; + + +/* Hashing and equality functions for nesting_info->var_map. */ + +static hashval_t +var_map_hash (const void *x) +{ + const struct var_map_elt *a = x; + return htab_hash_pointer (a->old); +} + +static int +var_map_eq (const void *x, const void *y) +{ + const struct var_map_elt *a = x; + const struct var_map_elt *b = y; + return a->old == b->old; +} + +/* We're working in so many different function contexts simultaneously, + that create_tmp_var is dangerous. Prevent mishap. */ +#define create_tmp_var cant_use_create_tmp_var_here_dummy + +/* Like create_tmp_var, except record the variable for registration at + the given nesting level. */ + +static tree +create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix) +{ + tree tmp_var; + +#if defined ENABLE_CHECKING + /* If the type is an array or a type which must be created by the + frontend, something is wrong. Note that we explicitly allow + incomplete types here, since we create them ourselves here. */ + if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type)) + abort (); + if (TYPE_SIZE_UNIT (type) + && TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) + abort (); +#endif + + tmp_var = create_tmp_var_raw (type, prefix); + DECL_CONTEXT (tmp_var) = info->context; + TREE_CHAIN (tmp_var) = info->new_local_var_chain; + info->new_local_var_chain = tmp_var; + + return tmp_var; +} + +/* Take the address of EXP. Mark it for addressability as necessary. */ + +static tree +build_addr (tree exp) +{ + tree base = exp; + while (TREE_CODE (base) == COMPONENT_REF || TREE_CODE (base) == ARRAY_REF) + base = TREE_OPERAND (base, 0); + if (DECL_P (base)) + TREE_ADDRESSABLE (base) = 1; + + return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp); +} + +/* Insert FIELD into TYPE, sorted by alignment requirements. */ + +static void +insert_field_into_struct (tree type, tree field) +{ + tree *p; + + DECL_CONTEXT (field) = type; + + for (p = &TYPE_FIELDS (type); *p ; p = &TREE_CHAIN (*p)) + if (DECL_ALIGN (field) >= DECL_ALIGN (*p)) + break; + + TREE_CHAIN (field) = *p; + *p = field; +} + +/* Build or return the RECORD_TYPE that describes the frame state that is + shared between INFO->CONTEXT and its nested functions. This record will + not be complete until finalize_nesting_tree; up until that point we'll + be adding fields as necessary. + + We also build the DECL that represents this frame in the function. */ + +static tree +get_frame_type (struct nesting_info *info) +{ + tree type = info->frame_type; + if (!type) + { + char *name; + + type = make_node (RECORD_TYPE); + + name = concat ("FRAME.", + IDENTIFIER_POINTER (DECL_NAME (info->context)), + NULL); + TYPE_NAME (type) = get_identifier (name); + free (name); + + info->frame_type = type; + info->frame_decl = create_tmp_var_for (info, type, "FRAME"); + } + return type; +} + +/* Return true if DECL should be referenced by pointer in the non-local + frame structure. */ + +static bool +use_pointer_in_frame (tree decl) +{ + if (TREE_CODE (decl) == PARM_DECL) + { + /* It's illegal to copy TREE_ADDRESSABLE, impossible to copy variable + sized decls, and inefficient to copy large aggregates. Don't bother + moving anything but scalar variables. */ + return AGGREGATE_TYPE_P (TREE_TYPE (decl)); + } + else + { + /* Variable sized types make things "interesting" in the frame. */ + return DECL_SIZE (decl) == NULL || !TREE_CONSTANT (DECL_SIZE (decl)); + } +} + +/* Given DECL, a non-locally accessed variable, find or create a field + in the non-local frame structure for the given nesting context. */ + +static tree +lookup_field_for_decl (struct nesting_info *info, tree decl, + enum insert_option insert) +{ + struct var_map_elt *elt, dummy; + void **slot; + tree field; + + dummy.old = decl; + slot = htab_find_slot (info->var_map, &dummy, insert); + if (!slot) + { + if (insert == INSERT) + abort (); + return NULL; + } + elt = *slot; + + if (!elt && insert == INSERT) + { + field = make_node (FIELD_DECL); + DECL_NAME (field) = DECL_NAME (decl); + + if (use_pointer_in_frame (decl)) + { + TREE_TYPE (field) = build_pointer_type (TREE_TYPE (decl)); + DECL_ALIGN (field) = TYPE_ALIGN (TREE_TYPE (field)); + DECL_NONADDRESSABLE_P (field) = 1; + } + else + { + TREE_TYPE (field) = TREE_TYPE (decl); + DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (decl); + DECL_ALIGN (field) = DECL_ALIGN (decl); + DECL_USER_ALIGN (field) = DECL_USER_ALIGN (decl); + TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (decl); + DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (decl); + TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (decl); + } + + insert_field_into_struct (get_frame_type (info), field); + + elt = xmalloc (sizeof (*elt)); + elt->old = decl; + elt->new = field; + *slot = elt; + + if (TREE_CODE (decl) == PARM_DECL) + info->any_parm_remapped = true; + } + else + field = elt ? elt->new : NULL; + + return field; +} + +/* Build or return the variable that holds the static chain within + INFO->CONTEXT. This variable may only be used within INFO->CONTEXT. */ + +static tree +get_chain_decl (struct nesting_info *info) +{ + tree decl = info->chain_decl; + if (!decl) + { + tree type; + + type = get_frame_type (info->outer); + type = build_pointer_type (type); + + /* Note that this variable is *not* entered into any BIND_EXPR; + the construction of this variable is handled specially in + expand_function_start and initialize_inlined_parameters. */ + decl = create_tmp_var_raw (type, "CHAIN"); + DECL_CONTEXT (decl) = info->context; + decl->decl.seen_in_bind_expr = 1; + + /* The initialization of CHAIN is not visible to the tree-ssa + analyzers and optimizers. Thus we do not want to issue + warnings for CHAIN. */ + TREE_NO_WARNING (decl) = 1; + + /* Tell tree-inline.c that we never write to this variable, so + it can copy-prop the replacement value immediately. */ + TREE_READONLY (decl) = 1; + + info->chain_decl = decl; + } + return decl; +} + +/* Build or return the field within the non-local frame state that holds + the static chain for INFO->CONTEXT. This is the way to walk back up + multiple nesting levels. */ + +static tree +get_chain_field (struct nesting_info *info) +{ + tree field = info->chain_field; + if (!field) + { + tree type = build_pointer_type (get_frame_type (info->outer)); + + field = make_node (FIELD_DECL); + DECL_NAME (field) = get_identifier ("__chain"); + TREE_TYPE (field) = type; + DECL_ALIGN (field) = TYPE_ALIGN (type); + DECL_NONADDRESSABLE_P (field) = 1; + + insert_field_into_struct (get_frame_type (info), field); + + info->chain_field = field; + } + return field; +} + +/* Copy EXP into a temporary. Allocate the temporary in the context of + INFO and insert the initialization statement before TSI. */ + +static tree +init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) +{ + tree t, stmt; + + t = create_tmp_var_for (info, TREE_TYPE (exp), NULL); + stmt = build (MODIFY_EXPR, TREE_TYPE (t), t, exp); + SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi))); + tsi_link_before (tsi, stmt, TSI_SAME_STMT); + + return t; +} + +/* Similarly, but only do so to force EXP to satisfy is_gimple_val. */ + +static tree +gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) +{ + if (is_gimple_val (exp)) + return exp; + else + return init_tmp_var (info, exp, tsi); +} + +/* Build or return the type used to represent a nested function trampoline. */ + +static GTY(()) tree trampoline_type; + +static tree +get_trampoline_type (void) +{ + tree record, t; + unsigned align, size; + + if (trampoline_type) + return trampoline_type; + + align = TRAMPOLINE_ALIGNMENT; + size = TRAMPOLINE_SIZE; + + /* If we won't be able to guarantee alignment simply via TYPE_ALIGN, + then allocate extra space so that we can do dynamic alignment. */ + if (align > STACK_BOUNDARY) + { + size += ((align/BITS_PER_UNIT) - 1) & -(STACK_BOUNDARY/BITS_PER_UNIT); + align = STACK_BOUNDARY; + } + + t = build_index_type (build_int_2 (size - 1, 0)); + t = build_array_type (char_type_node, t); + t = build_decl (FIELD_DECL, get_identifier ("__data"), t); + DECL_ALIGN (t) = align; + DECL_USER_ALIGN (t) = 1; + + record = make_node (RECORD_TYPE); + TYPE_NAME (record) = get_identifier ("__builtin_trampoline"); + TYPE_FIELDS (record) = t; + layout_type (record); + + return record; +} + +/* Given DECL, a nested function, find or create a field in the non-local + frame structure for a trampoline for this function. */ + +static tree +lookup_tramp_for_decl (struct nesting_info *info, tree decl, + enum insert_option insert) +{ + struct var_map_elt *elt, dummy; + void **slot; + tree field; + + dummy.old = decl; + slot = htab_find_slot (info->var_map, &dummy, insert); + if (!slot) + { + if (insert == INSERT) + abort (); + return NULL; + } + elt = *slot; + + if (!elt && insert == INSERT) + { + field = make_node (FIELD_DECL); + DECL_NAME (field) = DECL_NAME (decl); + TREE_TYPE (field) = get_trampoline_type (); + TREE_ADDRESSABLE (field) = 1; + + insert_field_into_struct (get_frame_type (info), field); + + elt = xmalloc (sizeof (*elt)); + elt->old = decl; + elt->new = field; + *slot = elt; + + info->any_tramp_created = true; + } + else + field = elt ? elt->new : NULL; + + return field; +} + +/* Build or return the field within the non-local frame state that holds + the non-local goto "jmp_buf". The buffer itself is maintained by the + rtl middle-end as dynamic stack space is allocated. */ + +static tree +get_nl_goto_field (struct nesting_info *info) +{ + tree field = info->nl_goto_field; + if (!field) + { + unsigned size; + tree type; + + /* For __builtin_nonlocal_goto, we need N words. The first is the + frame pointer, the rest is for the target's stack pointer save + area. The number of words is controled by STACK_SAVEAREA_MODE; + not the best interface, but it'll do for now. */ + if (Pmode == ptr_mode) + type = ptr_type_node; + else + type = lang_hooks.types.type_for_mode (Pmode, 1); + + size = GET_MODE_SIZE (STACK_SAVEAREA_MODE (SAVE_NONLOCAL)); + size = size / GET_MODE_SIZE (Pmode); + size = size + 1; + + type = build_array_type (type, build_index_type (build_int_2 (size, 0))); + + field = make_node (FIELD_DECL); + DECL_NAME (field) = get_identifier ("__nl_goto_buf"); + TREE_TYPE (field) = type; + DECL_ALIGN (field) = TYPE_ALIGN (type); + TREE_ADDRESSABLE (field) = 1; + + insert_field_into_struct (get_frame_type (info), field); + + info->nl_goto_field = field; + } + + return field; +} + +/* Convenience routines to walk all statements of a gimple function. + + For each statement, we invoke CALLBACK via walk_tree. The passed + data is a walk_stmt_info structure. Of note here is a TSI that + points to the current statement being walked. The VAL_ONLY flag + that indicates whether the *TP being examined may be replaced + with something that matches is_gimple_val (if true) or something + slightly more complicated (if false). "Something" technically + means the common subset of is_gimple_lvalue and is_gimple_rhs, + but we never try to form anything more complicated than that, so + we don't bother checking. */ + +struct walk_stmt_info +{ + walk_tree_fn callback; + tree_stmt_iterator tsi; + struct nesting_info *info; + bool val_only; +}; + +/* A subroutine of walk_function. Iterate over all sub-statements of *TP. */ + +static void +walk_stmts (struct walk_stmt_info *wi, tree *tp) +{ + tree t = *tp; + if (!t) + return; + + switch (TREE_CODE (t)) + { + case STATEMENT_LIST: + { + tree_stmt_iterator i; + for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) + { + wi->tsi = i; + walk_stmts (wi, tsi_stmt_ptr (i)); + } + } + break; + + case COND_EXPR: + walk_tree (&COND_EXPR_COND (t), wi->callback, wi, NULL); + walk_stmts (wi, &COND_EXPR_THEN (t)); + walk_stmts (wi, &COND_EXPR_ELSE (t)); + break; + case CATCH_EXPR: + walk_stmts (wi, &CATCH_BODY (t)); + case EH_FILTER_EXPR: + walk_stmts (wi, &EH_FILTER_FAILURE (t)); + break; + case TRY_CATCH_EXPR: + case TRY_FINALLY_EXPR: + walk_stmts (wi, &TREE_OPERAND (t, 0)); + walk_stmts (wi, &TREE_OPERAND (t, 1)); + break; + case BIND_EXPR: + walk_stmts (wi, &BIND_EXPR_BODY (t)); + break; + + case RETURN_EXPR: + walk_stmts (wi, &TREE_OPERAND (t, 0)); + break; + + case MODIFY_EXPR: + /* The immediate arguments of a MODIFY_EXPR may use COMPONENT_REF. */ + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL); + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 1), wi->callback, wi, NULL); + wi->val_only = true; + break; + + default: + wi->val_only = true; + walk_tree (tp, wi->callback, wi, NULL); + break; + } +} + +/* Invoke CALLBACK on all statements of INFO->CONTEXT. */ + +static void +walk_function (walk_tree_fn callback, struct nesting_info *info) +{ + struct walk_stmt_info wi; + + memset (&wi, 0, sizeof (wi)); + wi.callback = callback; + wi.info = info; + wi.val_only = true; + + walk_stmts (&wi, &DECL_SAVED_TREE (info->context)); +} + +/* Similarly for ROOT and all functions nested underneath, depth first. */ + +static void +walk_all_functions (walk_tree_fn callback, struct nesting_info *root) +{ + do + { + if (root->inner) + walk_all_functions (callback, root->inner); + walk_function (callback, root); + root = root->next; + } + while (root); +} + + +/* Construct our local datastructure describing the function nesting + tree rooted by CGN. */ + +static struct nesting_info * +create_nesting_tree (struct cgraph_node *cgn) +{ + struct nesting_info *info = xcalloc (1, sizeof (*info)); + info->var_map = htab_create (7, var_map_hash, var_map_eq, free); + info->context = cgn->decl; + + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + { + struct nesting_info *sub = create_nesting_tree (cgn); + sub->outer = info; + sub->next = info->inner; + info->inner = sub; + } + + return info; +} + +/* Return an expression computing the static chain for TARGET_CONTEXT + from INFO->CONTEXT. Insert any necessary computations before TSI. */ + +static tree +get_static_chain (struct nesting_info *info, tree target_context, + tree_stmt_iterator *tsi) +{ + struct nesting_info *i; + tree x; + + if (info->context == target_context) + { + x = build_addr (info->frame_decl); + } + else + { + x = get_chain_decl (info); + + for (i = info->outer; i->context != target_context; i = i->outer) + { + tree field = get_chain_field (i); + + x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); + x = build (COMPONENT_REF, TREE_TYPE (field), x, field); + x = init_tmp_var (info, x, tsi); + } + } + + return x; +} + +/* Return an expression referencing FIELD from TARGET_CONTEXT's non-local + frame as seen from INFO->CONTEXT. Insert any necessary computations + before TSI. */ + +static tree +get_frame_field (struct nesting_info *info, tree target_context, + tree field, tree_stmt_iterator *tsi) +{ + struct nesting_info *i; + tree x; + + if (info->context == target_context) + { + /* Make sure frame_decl gets created. */ + (void) get_frame_type (info); + x = info->frame_decl; + } + else + { + x = get_chain_decl (info); + + for (i = info->outer; i->context != target_context; i = i->outer) + { + tree field = get_chain_field (i); + + x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); + x = build (COMPONENT_REF, TREE_TYPE (field), x, field); + x = init_tmp_var (info, x, tsi); + } + + x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); + } + + x = build (COMPONENT_REF, TREE_TYPE (field), x, field); + return x; +} + +/* Called via walk_function+walk_tree, rewrite all references to VAR + and PARM_DECLs that belong to outer functions. + + The rewrite will involve some number of structure accesses back up + the static chain. E.g. for a variable FOO up one nesting level it'll + be CHAIN->FOO. For two levels it'll be CHAIN->__chain->FOO. Further + indirections apply to decls for which use_pointer_in_frame is true. */ + +static tree +convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = data; + struct nesting_info *info = wi->info; + tree t = *tp; + + *walk_subtrees = 0; + switch (TREE_CODE (t)) + { + case VAR_DECL: + /* Non-automatic variables are never processed. */ + if (TREE_STATIC (t) || DECL_EXTERNAL (t)) + break; + /* FALLTHRU */ + + case PARM_DECL: + if (decl_function_context (t) != info->context) + { + tree target_context = decl_function_context (t); + struct nesting_info *i; + tree x; + + for (i = info->outer; i->context != target_context; i = i->outer) + continue; + x = lookup_field_for_decl (i, t, INSERT); + x = get_frame_field (info, target_context, x, &wi->tsi); + if (use_pointer_in_frame (t)) + { + x = init_tmp_var (info, x, &wi->tsi); + x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); + } + if (wi->val_only) + x = init_tmp_var (info, x, &wi->tsi); + + *tp = x; + } + break; + + case GOTO_EXPR: + /* Don't walk non-local gotos for now. */ + if (TREE_CODE (GOTO_DESTINATION (t)) != LABEL_DECL) + { + *walk_subtrees = 1; + wi->val_only = true; + } + break; + + case LABEL_DECL: + /* We're taking the address of a label from a parent function, but + this is not itself a non-local goto. Mark the label such that it + will not be deleted, much as we would with a label address in + static storage. */ + if (decl_function_context (t) != info->context) + FORCED_LABEL (t) = 1; + break; + + case ADDR_EXPR: + { + bool save_val_only = wi->val_only; + tree save_sub = TREE_OPERAND (t, 0); + + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); + wi->val_only = true; + + if (save_sub != TREE_OPERAND (t, 0)) + { + /* If we changed anything, then TREE_INVARIANT is be wrong, + since we're no longer directly referencing a decl. */ + TREE_INVARIANT (t) = 0; + + /* If the callback converted the address argument in a context + where we only accept variables (and min_invariant, presumably), + then compute the address into a temporary. */ + if (save_val_only) + *tp = gimplify_val (wi->info, t, &wi->tsi); + } + } + break; + + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); + wi->val_only = true; + break; + + case ARRAY_REF: + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); + wi->val_only = true; + walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL); + break; + + case BIT_FIELD_REF: + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); + wi->val_only = true; + walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, NULL); + break; + + default: + if (!DECL_P (t) && !TYPE_P (t)) + { + *walk_subtrees = 1; + wi->val_only = true; + } + break; + } + + return NULL_TREE; +} + +/* Called via walk_function+walk_tree, rewrite all references to VAR + and PARM_DECLs that were referenced by inner nested functions. + The rewrite will be a structure reference to the local frame variable. */ + +static tree +convert_local_reference (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = data; + struct nesting_info *info = wi->info; + tree t = *tp, field, x, y; + + switch (TREE_CODE (t)) + { + case VAR_DECL: + /* Non-automatic variables are never processed. */ + if (TREE_STATIC (t) || DECL_EXTERNAL (t)) + break; + /* FALLTHRU */ + + case PARM_DECL: + if (decl_function_context (t) == info->context) + { + /* If we copied a pointer to the frame, then the original decl + is used unchanged in the parent function. */ + if (use_pointer_in_frame (t)) + break; + + /* No need to transform anything if no child references the + variable. */ + field = lookup_field_for_decl (info, t, NO_INSERT); + if (!field) + break; + + x = get_frame_field (info, info->context, field, &wi->tsi); + if (wi->val_only) + x = init_tmp_var (info, x, &wi->tsi); + *tp = x; + } + break; + + case ADDR_EXPR: + { + bool save_val_only = wi->val_only; + tree save_sub = TREE_OPERAND (t, 0); + + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); + wi->val_only = save_val_only; + + /* If we converted anything ... */ + if (TREE_OPERAND (t, 0) != save_sub) + { + /* Then the frame decl is now addressable. */ + TREE_ADDRESSABLE (info->frame_decl) = 1; + + /* If we are in a context where we only accept values, then + compute the address into a temporary. */ + if (save_val_only) + *tp = gimplify_val (wi->info, t, &wi->tsi); + } + } + break; + + case CALL_EXPR: + *walk_subtrees = 1; + + /* Ready for some fun? We need to recognize + __builtin_stack_alloc (&x, n) + and insert + FRAME.x = &x + after that. X should have use_pointer_in_frame set. We can't + do this any earlier, since we can't meaningfully evaluate &x. */ + + x = get_callee_fndecl (t); + if (!x || DECL_BUILT_IN_CLASS (x) != BUILT_IN_NORMAL) + break; + if (DECL_FUNCTION_CODE (x) != BUILT_IN_STACK_ALLOC) + break; + t = TREE_VALUE (TREE_OPERAND (t, 1)); + if (TREE_CODE (t) != ADDR_EXPR) + abort (); + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) != VAR_DECL) + abort (); + field = lookup_field_for_decl (info, t, NO_INSERT); + if (!field) + break; + if (!use_pointer_in_frame (t)) + abort (); + + x = build_addr (t); + y = get_frame_field (info, info->context, field, &wi->tsi); + x = build (MODIFY_EXPR, void_type_node, y, x); + SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi))); + tsi_link_after (&wi->tsi, x, TSI_SAME_STMT); + break; + + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); + wi->val_only = true; + break; + + case ARRAY_REF: + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); + wi->val_only = true; + walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL); + break; + + case BIT_FIELD_REF: + wi->val_only = false; + walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); + wi->val_only = true; + walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, NULL); + break; + + default: + if (!DECL_P (t) && !TYPE_P (t)) + { + *walk_subtrees = 1; + wi->val_only = true; + } + break; + } + + return NULL_TREE; +} + +/* Called via walk_function+walk_tree, rewrite all GOTO_EXPRs that + reference labels from outer functions. The rewrite will be a + call to __builtin_nonlocal_goto. */ + +static tree +convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = data; + struct nesting_info *info = wi->info, *i; + tree t = *tp, label, new_label, target_context, x, arg, field; + struct var_map_elt *elt; + void **slot; + + *walk_subtrees = 0; + if (TREE_CODE (t) != GOTO_EXPR) + return NULL_TREE; + label = GOTO_DESTINATION (t); + if (TREE_CODE (label) != LABEL_DECL) + return NULL_TREE; + target_context = decl_function_context (label); + if (target_context == info->context) + return NULL_TREE; + + for (i = info->outer; target_context != i->context; i = i->outer) + continue; + + /* The original user label may also be use for a normal goto, therefore + we must create a new label that will actually receive the abnormal + control transfer. This new label will be marked LABEL_NONLOCAL; this + mark will trigger proper behaviour in the cfg, as well as cause the + (hairy target-specific) non-local goto receiver code to be generated + when we expand rtl. */ + new_label = create_artificial_label (); + DECL_NONLOCAL (new_label) = 1; + + /* Enter this association into var_map so that we can insert the new + label into the IL during a second pass. */ + elt = xmalloc (sizeof (*elt)); + elt->old = label; + elt->new = new_label; + slot = htab_find_slot (i->var_map, elt, INSERT); + *slot = elt; + + /* Build: __builtin_nl_goto(new_label, &chain->nl_goto_field). */ + field = get_nl_goto_field (i); + x = get_frame_field (info, target_context, field, &wi->tsi); + x = build_addr (x); + x = gimplify_val (info, x, &wi->tsi); + arg = tree_cons (NULL, x, NULL); + x = build_addr (new_label); + arg = tree_cons (NULL, x, arg); + x = implicit_built_in_decls[BUILT_IN_NONLOCAL_GOTO]; + x = build_function_call_expr (x, arg); + + SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi))); + *tsi_stmt_ptr (wi->tsi) = x; + + return NULL_TREE; +} + +/* Called via walk_function+walk_tree, rewrite all LABEL_EXPRs that + are referenced via nonlocal goto from a nested function. The rewrite + will involve installing a newly generated DECL_NONLOCAL label, and + (potentially) a branch around the rtl gunk that is assumed to be + attached to such a label. */ + +static tree +convert_nl_goto_receiver (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = data; + struct nesting_info *info = wi->info; + tree t = *tp, label, new_label, x; + struct var_map_elt *elt, dummy; + tree_stmt_iterator tmp_tsi; + + *walk_subtrees = 0; + if (TREE_CODE (t) != LABEL_EXPR) + return NULL_TREE; + label = LABEL_EXPR_LABEL (t); + + dummy.old = label; + elt = htab_find (info->var_map, &dummy); + if (!elt) + return NULL_TREE; + new_label = elt->new; + + /* If there's any possibility that the previous statement falls through, + then we must branch around the new non-local label. */ + tmp_tsi = wi->tsi; + tsi_prev (&tmp_tsi); + if (tsi_end_p (tmp_tsi) || block_may_fallthru (tsi_stmt (tmp_tsi))) + { + x = build1 (GOTO_EXPR, void_type_node, label); + tsi_link_before (&wi->tsi, x, TSI_SAME_STMT); + } + x = build1 (LABEL_EXPR, void_type_node, new_label); + tsi_link_before (&wi->tsi, x, TSI_SAME_STMT); + + return NULL_TREE; +} + +/* Called via walk_function+walk_tree, rewrite all references to addresses + of nested functions that require the use of trampolines. The rewrite + will involve a reference a trampoline generated for the occasion. */ + +static tree +convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = data; + struct nesting_info *info = wi->info, *i; + tree t = *tp, decl, target_context, x, arg; + + *walk_subtrees = 0; + switch (TREE_CODE (t)) + { + case ADDR_EXPR: + /* Build + T.1 = &CHAIN->tramp; + T.2 = __builtin_adjust_trampoline (T.1); + T.3 = (func_type)T.2; + */ + + decl = TREE_OPERAND (t, 0); + if (TREE_CODE (decl) != FUNCTION_DECL) + break; + + /* Only need to process nested functions. */ + target_context = decl_function_context (decl); + if (!target_context) + break; + + /* If the nested function doesn't use a static chain, then + it doesn't need a trampoline. */ + if (DECL_NO_STATIC_CHAIN (decl)) + break; + + /* Lookup the immediate parent of the callee, as that's where + we need to insert the trampoline. */ + for (i = info; i->context != target_context; i = i->outer) + continue; + x = lookup_tramp_for_decl (i, decl, INSERT); + + /* Compute the address of the field holding the trampoline. */ + x = get_frame_field (info, target_context, x, &wi->tsi); + x = build_addr (x); + x = gimplify_val (info, x, &wi->tsi); + arg = tree_cons (NULL, x, NULL); + + /* Do machine-specific ugliness. Normally this will involve + computing extra alignment, but it can really be anything. */ + x = implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE]; + x = build_function_call_expr (x, arg); + x = init_tmp_var (info, x, &wi->tsi); + + /* Cast back to the proper function type. */ + x = build1 (NOP_EXPR, TREE_TYPE (t), x); + x = init_tmp_var (info, x, &wi->tsi); + + *tp = x; + break; + + case CALL_EXPR: + /* Only walk call arguments, lest we generate trampolines for + direct calls. */ + walk_tree (&TREE_OPERAND (t, 1), convert_tramp_reference, wi, NULL); + break; + + default: + if (!DECL_P (t) && !TYPE_P (t)) + *walk_subtrees = 1; + break; + } + + return NULL_TREE; +} + +/* Called via walk_function+walk_tree, rewrite all CALL_EXPRs that + reference nested functions to make sure that the static chain is + set up properly for the call. */ + +static tree +convert_call_expr (tree *tp, int *walk_subtrees, void *data) +{ + struct walk_stmt_info *wi = data; + struct nesting_info *info = wi->info; + tree t = *tp, decl, target_context; + + *walk_subtrees = 0; + switch (TREE_CODE (t)) + { + case CALL_EXPR: + decl = get_callee_fndecl (t); + if (!decl) + break; + target_context = decl_function_context (decl); + if (target_context && !DECL_NO_STATIC_CHAIN (decl)) + TREE_OPERAND (t, 2) + = get_static_chain (info, target_context, &wi->tsi); + break; + + case RETURN_EXPR: + case MODIFY_EXPR: + /* Only return and modify may contain calls. */ + *walk_subtrees = 1; + break; + + default: + break; + } + + return NULL_TREE; +} + +/* Walk the nesting tree starting with ROOT, depth first. Convert all + trampolines and call expressions. On the way back up, determine if + a nested function actually uses its static chain; if not, remember that. */ + +static void +convert_all_function_calls (struct nesting_info *root) +{ + do + { + if (root->inner) + convert_all_function_calls (root->inner); + + walk_function (convert_tramp_reference, root); + walk_function (convert_call_expr, root); + + /* If the function does not use a static chain, then remember that. */ + if (root->outer && !root->chain_decl && !root->chain_field) + DECL_NO_STATIC_CHAIN (root->context) = 1; + else + { +#ifdef ENABLE_CHECKING + if (DECL_NO_STATIC_CHAIN (root->context)) + abort (); +#endif + } + + root = root->next; + } + while (root); +} + +/* Do "everything else" to clean up or complete state collected by the + various walking passes -- lay out the types and decls, generate code + to initialize the frame decl, store critical expressions in the + struct function for rtl to find. */ + +static void +finalize_nesting_tree_1 (struct nesting_info *root) +{ + tree stmt_list = NULL; + tree context = root->context; + struct function *sf; + + /* If we created a non-local frame type or decl, we need to lay them + out at this time. */ + if (root->frame_type) + { + layout_type (root->frame_type); + layout_decl (root->frame_decl, 0); + } + + /* If any parameters were referenced non-locally, then we need to + insert a copy. Likewise, if any variables were referenced by + pointer, we need to initialize the address. */ + if (root->any_parm_remapped) + { + tree p; + for (p = DECL_ARGUMENTS (context); p ; p = TREE_CHAIN (p)) + { + tree field, x, y; + + field = lookup_field_for_decl (root, p, NO_INSERT); + if (!field) + continue; + + if (use_pointer_in_frame (p)) + x = build_addr (p); + else + x = p; + + y = build (COMPONENT_REF, TREE_TYPE (field), + root->frame_decl, field); + x = build (MODIFY_EXPR, TREE_TYPE (field), y, x); + append_to_statement_list (x, &stmt_list); + } + } + + /* If a chain_field was created, then it needs to be initialized + from chain_decl. */ + if (root->chain_field) + { + tree x; + x = build (COMPONENT_REF, TREE_TYPE (root->chain_field), + root->frame_decl, root->chain_field); + x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root)); + append_to_statement_list (x, &stmt_list); + } + + /* If trampolines were created, then we need to initialize them. */ + if (root->any_tramp_created) + { + struct nesting_info *i; + for (i = root->inner; i ; i = i->next) + { + tree arg, x, field; + + field = lookup_tramp_for_decl (root, i->context, NO_INSERT); + if (!field) + continue; + + if (DECL_NO_STATIC_CHAIN (i->context)) + x = null_pointer_node; + else + x = build_addr (root->frame_decl); + arg = tree_cons (NULL, x, NULL); + + x = build_addr (i->context); + arg = tree_cons (NULL, x, arg); + + x = build (COMPONENT_REF, TREE_TYPE (field), + root->frame_decl, field); + x = build_addr (x); + arg = tree_cons (NULL, x, arg); + + x = implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE]; + x = build_function_call_expr (x, arg); + + append_to_statement_list (x, &stmt_list); + } + } + + /* If we created initialization statements, insert them. */ + if (stmt_list) + { + annotate_all_with_locus (&stmt_list, + DECL_SOURCE_LOCATION (context)); + append_to_statement_list (BIND_EXPR_BODY (DECL_SAVED_TREE (context)), + &stmt_list); + BIND_EXPR_BODY (DECL_SAVED_TREE (context)) = stmt_list; + } + + /* If a chain_decl was created, then it needs to be registered with + struct function so that it gets initialized from the static chain + register at the beginning of the function. */ + sf = DECL_STRUCT_FUNCTION (root->context); + sf->static_chain_decl = root->chain_decl; + + /* Similarly for the non-local goto save area. */ + if (root->nl_goto_field) + { + sf->nonlocal_goto_save_area + = get_frame_field (root, context, root->nl_goto_field, NULL); + sf->has_nonlocal_label = 1; + } + + /* Make sure all new local variables get insertted into the + proper BIND_EXPR. */ + if (root->new_local_var_chain) + declare_tmp_vars (root->new_local_var_chain, + DECL_SAVED_TREE (root->context)); + + /* Dump the translated tree function. */ + dump_function (TDI_nested, root->context); +} + +static void +finalize_nesting_tree (struct nesting_info *root) +{ + do + { + if (root->inner) + finalize_nesting_tree (root->inner); + finalize_nesting_tree_1 (root); + root = root->next; + } + while (root); +} + +/* Free the data structures allocated during this pass. */ + +static void +free_nesting_tree (struct nesting_info *root) +{ + struct nesting_info *next; + do + { + if (root->inner) + free_nesting_tree (root->inner); + htab_delete (root->var_map); + next = root->next; + free (root); + root = next; + } + while (root); +} + +/* Main entry point for this pass. Process FNDECL and all of its nested + subroutines and turn them into something less tightly bound. */ + +void +lower_nested_functions (tree fndecl) +{ + struct nesting_info *root; + struct cgraph_node *cgn; + + /* If there are no nested functions, there's nothing to do. */ + cgn = cgraph_node (fndecl); + if (!cgn->nested) + return; + + root = create_nesting_tree (cgn); + walk_all_functions (convert_nonlocal_reference, root); + walk_all_functions (convert_local_reference, root); + walk_all_functions (convert_nl_goto_reference, root); + walk_all_functions (convert_nl_goto_receiver, root); + convert_all_function_calls (root); + finalize_nesting_tree (root); + free_nesting_tree (root); +} + +#include "gt-tree-nested.h" diff --git a/gcc/tree-nomudflap.c b/gcc/tree-nomudflap.c new file mode 100644 index 00000000000..420fc39a88b --- /dev/null +++ b/gcc/tree-nomudflap.c @@ -0,0 +1,127 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" +#include "errors.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tree-inline.h" +#include "c-tree.h" +#include "c-common.h" +#include "tree-simple.h" +#include "diagnostic.h" +#include "hashtab.h" +#include "output.h" +#include "varray.h" +#include "langhooks.h" +#include "tree-mudflap.h" +#include "tree-pass.h" +#include "ggc.h" + + + +/* This file contains placeholder functions, to be used only for + language processors that cannot handle tree-mudflap.c directly. + (e.g. Fortran). */ + +static void +nogo (void) +{ + internal_error ("mudflap: this language is not supported"); +} + +void +mudflap_enqueue_decl (tree obj ATTRIBUTE_UNUSED) +{ + nogo (); +} + +void +mudflap_enqueue_constant (tree obj ATTRIBUTE_UNUSED) +{ + nogo (); +} + +void +mudflap_finish_file (void) +{ + nogo (); +} + +int +mf_marked_p (tree t ATTRIBUTE_UNUSED) +{ + nogo (); + return 0; +} + +tree +mf_mark (tree t ATTRIBUTE_UNUSED) +{ + nogo (); + return NULL; +} + +/* The pass structures must exist, but need not do anything. */ + +struct tree_opt_pass pass_mudflap_1 = +{ + "mudflap1", /* name */ + NULL, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +struct tree_opt_pass pass_mudflap_2 = +{ + "mudflap2", /* name */ + NULL, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +/* Instead of: +#include "gt-tree-mudflap.h" +We prepare a little dummy struct here. +*/ + +const struct ggc_root_tab gt_ggc_r_gt_tree_mudflap_h[] = { + LAST_GGC_ROOT_TAB +}; diff --git a/gcc/tree-nrv.c b/gcc/tree-nrv.c new file mode 100644 index 00000000000..2c344967d66 --- /dev/null +++ b/gcc/tree-nrv.c @@ -0,0 +1,217 @@ +/* Language independent return value optimizations + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "function.h" +#include "basic-block.h" +#include "expr.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "timevar.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "langhooks.h" + +/* This file implements return value optimizations for functions which + return aggregate types. + + Basically this pass searches the function for return statements which + return a local aggregate. When converted to RTL such statements will + generate a copy from the local aggregate to final return value destination + mandated by the target's ABI. + + That copy can often be avoided by directly constructing the return value + into the final destination mandated by the target's ABI. + + This is basically a generic equivalent to the C++ front-end's + Named Return Value optimization. */ + +struct nrv_data +{ + /* This is the temporary (a VAR_DECL) which appears in all of + this function's RETURN_EXPR statements. */ + tree var; + + /* This is the function's RESULT_DECL. We will replace all occurences + of VAR with RESULT_DECL when we apply this optimization. */ + tree result; +}; + +static tree finalize_nrv_r (tree *, int *, void *); + +/* Callback for the tree walker. + + If TP refers to a RETURN_EXPR, then set the expression being returned + to nrv_data->result. + + If TP refers to nrv_data->var, then replace nrv_data->var with + nrv_data->result. + + If we reach a node where we know all the subtrees are uninteresting, + then set *WALK_SUBTREES to zero. */ + +static tree +finalize_nrv_r (tree *tp, int *walk_subtrees, void *data) +{ + struct nrv_data *dp = (struct nrv_data *)data; + + /* No need to walk into types. */ + if (TYPE_P (*tp)) + *walk_subtrees = 0; + /* If this is a RETURN_EXPR, then set the expression being returned + to RESULT. */ + else if (TREE_CODE (*tp) == RETURN_EXPR) + TREE_OPERAND (*tp, 0) = dp->result; + /* Replace all occurences of VAR with RESULT. */ + else if (*tp == dp->var) + *tp = dp->result; + + /* Keep iterating. */ + return NULL_TREE; +} + +/* Main entry point for return value optimizations. + + If this function always returns the same local variable, and that + local variable is an aggregate type, then replace the variable with + the function's DECL_RESULT. + + This is the equivalent of the C++ named return value optimization + applied to optimized trees in a language independent form. If we + ever encounter languages which prevent this kind of optimization, + then we could either have the languages register the optimization or + we could change the gating function to check the current language. */ + +static void +tree_nrv (void) +{ + tree result = DECL_RESULT (current_function_decl); + tree result_type = TREE_TYPE (result); + tree found = NULL; + basic_block bb; + struct nrv_data data; + + /* If this function does not return an aggregate type in memory, then + there is nothing to do. */ + if (!aggregate_value_p (result, current_function_decl)) + return; + + /* Look through each block for suitable return expressions. RETURN_EXPRs + end basic blocks, so we only have to look at the last statement in + each block. That makes this very fast. */ + FOR_EACH_BB (bb) + { + tree stmt = last_stmt (bb); + + if (stmt && TREE_CODE (stmt) == RETURN_EXPR) + { + tree ret_expr = TREE_OPERAND (stmt, 0); + + /* This probably should not happen, but just to be safe do + not perform NRV optimizations if only some of the return + statement return a value. */ + if (!ret_expr + || TREE_CODE (ret_expr) != MODIFY_EXPR + || TREE_CODE (TREE_OPERAND (ret_expr, 0)) != RESULT_DECL) + return; + + /* Now verify that this return statement uses the same value + as any previously encountered return statement. */ + if (found != NULL) + { + /* If we found a return statement using a different variable + than previous return statements, then we can not perform + NRV optimizations. */ + if (found != TREE_OPERAND (ret_expr, 1)) + return; + } + else + found = TREE_OPERAND (ret_expr, 1); + + /* The returned value must be a local automatic variable of the + same type and alignment as the function's result. */ + if (TREE_CODE (found) != VAR_DECL + || DECL_CONTEXT (found) != current_function_decl + || TREE_STATIC (found) + || TREE_ADDRESSABLE (found) + || DECL_ALIGN (found) > DECL_ALIGN (result) + || !lang_hooks.types_compatible_p (TREE_TYPE (found), + result_type)) + return; + } + } + + if (!found) + return; + + /* If dumping details, then note once and only the NRV replacement. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "NRV Replaced: "); + print_generic_expr (dump_file, found, dump_flags); + fprintf (dump_file, " with: "); + print_generic_expr (dump_file, result, dump_flags); + fprintf (dump_file, "\n"); + } + + /* At this point we know that all the return statements return the + same local which has suitable attributes for NRV. Copy debugging + information from FOUND to RESULT. */ + DECL_NAME (result) = DECL_NAME (found); + DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found); + DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found); + TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found); + + /* Now walk through the function changing all references to VAR to be + RESULT. */ + data.var = found; + data.result = result; + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + walk_tree (bsi_stmt_ptr (bsi), finalize_nrv_r, &data, 0); + } + + /* FOUND is no longer used. Ensure it gets removed. */ + var_ann (found)->used = 0; +} + +struct tree_opt_pass pass_nrv = +{ + "nrv", /* name */ + NULL, /* gate */ + tree_nrv, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_NRV, /* tv_id */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ +}; diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c index f946593dc33..80a2b41b6a1 100644 --- a/gcc/tree-optimize.c +++ b/gcc/tree-optimize.c @@ -1,5 +1,6 @@ /* Control and data flow functions for trees. Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo This file is part of GCC. @@ -21,18 +22,424 @@ Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "coretypes.h" -#include "toplev.h" +#include "tm.h" #include "tree.h" -#include "tree-inline.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "expr.h" +#include "diagnostic.h" +#include "basic-block.h" #include "flags.h" -#include "langhooks.h" -#include "cgraph.h" +#include "tree-flow.h" +#include "tree-dump.h" #include "timevar.h" -#include "tm.h" #include "function.h" +#include "langhooks.h" +#include "toplev.h" +#include "flags.h" +#include "cgraph.h" +#include "tree-inline.h" +#include "tree-mudflap.h" +#include "tree-pass.h" +#include "tree-alias-common.h" #include "ggc.h" +#include "cgraph.h" + + +/* Global variables used to communicate with passes. */ +int dump_flags; +bitmap vars_to_rename; +bool in_gimple_form; + +/* The root of the compilation pass tree, once constructed. */ +static struct tree_opt_pass *all_passes; + +/* Pass: gimplify the function if it's not been done. */ + +static void +execute_gimple (void) +{ + /* We have this test here rather than as the gate because we always + want to dump the original gimplified function. */ + if (!lang_hooks.gimple_before_inlining) + gimplify_function_tree (current_function_decl); +} + +static struct tree_opt_pass pass_gimple = +{ + "gimple", /* name */ + NULL, /* gate */ + execute_gimple, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + PROP_gimple_any, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ +}; + +/* Pass: replace the outermost BIND_EXPR. We removed all of them while + optimizing, but the tree->rtl expander requires it. */ + +static void +execute_rebuild_bind (void) +{ + DECL_SAVED_TREE (current_function_decl) + = build (BIND_EXPR, void_type_node, NULL_TREE, + DECL_SAVED_TREE (current_function_decl), NULL_TREE); +} + +static struct tree_opt_pass pass_rebuild_bind = +{ + NULL, /* name */ + NULL, /* gate */ + execute_rebuild_bind, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +/* Gate: execute, or not, all of the non-trivial optimizations. */ + +static bool +gate_all_optimizations (void) +{ + return (optimize >= 1 + /* Don't bother doing anything if the program has errors. */ + && !(errorcount || sorrycount)); +} + +static struct tree_opt_pass pass_all_optimizations = +{ + NULL, /* name */ + gate_all_optimizations, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +/* Pass: do the actions required to finish with tree-ssa optimization + passes. */ + +static void +execute_del_cfg (void) +{ + basic_block bb; + tree *chain; + + /* ??? This isn't the right place for this. Worse, it got computed + more or less at random in various passes. */ + free_dominance_info (CDI_DOMINATORS); + + /* Emit gotos for implicit jumps. */ + disband_implicit_edges (); + + /* Remove the ssa structures. Do it here since this includes statement + annotations that need to be intact during disband_implicit_edges. */ + delete_tree_ssa (); + + /* Re-chain the statements from the blocks. */ + chain = &DECL_SAVED_TREE (current_function_decl); + *chain = alloc_stmt_list (); + FOR_EACH_BB (bb) + { + append_to_statement_list_force (bb->stmt_list, chain); + } + + /* And get rid of the cfg. */ + delete_tree_cfg (); +} + +static struct tree_opt_pass pass_del_cfg = +{ + NULL, /* name */ + NULL, /* gate */ + execute_del_cfg, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + PROP_cfg, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +/* Iterate over the pass tree allocating dump file numbers. We want + to do this depth first, and independent of whether the pass is + enabled or not. */ + +static void +register_one_dump_file (struct tree_opt_pass *pass) +{ + char *dot_name, *flag_name; + char num[10]; + + if (!pass->name) + return; + + /* See below in dup_pass_1. */ + num[0] = '\0'; + if (pass->static_pass_number) + sprintf (num, "%d", ((int) pass->static_pass_number < 0 + ? 1 : pass->static_pass_number)); + + dot_name = concat (".", pass->name, num, NULL); + flag_name = concat ("tree-", pass->name, num, NULL); + + pass->static_pass_number = dump_register (dot_name, flag_name); +} + +static void +register_dump_files (struct tree_opt_pass *pass) +{ + do + { + register_one_dump_file (pass); + if (pass->sub) + register_dump_files (pass->sub); + pass = pass->next; + } + while (pass); +} + +/* Duplicate a pass that's to be run more than once. */ + +static struct tree_opt_pass * +dup_pass_1 (struct tree_opt_pass *pass) +{ + struct tree_opt_pass *new; + + new = xmalloc (sizeof (*new)); + memcpy (new, pass, sizeof (*new)); + + /* Indicate to register_dump_files that this pass has duplicates, + and so it should rename the dump file. The first instance will + be < 0, and be number of duplicates = -static_pass_number + 1. + Subsequent instances will be > 0 and just the duplicate number. */ + if (pass->name) + { + int n, p = pass->static_pass_number; + + if (p) + n = -(--p) + 1; + else + n = 2, p = -1; + + pass->static_pass_number = p; + new->static_pass_number = n; + } + + return new; +} + +/* Construct the pass tree. */ + +void +init_tree_optimization_passes (void) +{ + struct tree_opt_pass **p; + +#define NEXT_PASS(PASS) (*p = &PASS, p = &(*p)->next) +#define DUP_PASS(PASS) (*dup_pass_1 (&PASS)) + + p = &all_passes; + NEXT_PASS (pass_gimple); + NEXT_PASS (pass_remove_useless_stmts); + NEXT_PASS (pass_mudflap_1); + NEXT_PASS (pass_lower_cf); + NEXT_PASS (pass_lower_eh); + NEXT_PASS (pass_all_optimizations); + NEXT_PASS (pass_mudflap_2); + NEXT_PASS (pass_rebuild_bind); + *p = NULL; + + p = &pass_all_optimizations.sub; + NEXT_PASS (pass_build_cfg); + NEXT_PASS (pass_tree_profile); + NEXT_PASS (pass_referenced_vars); + NEXT_PASS (pass_build_pta); + NEXT_PASS (pass_build_ssa); + NEXT_PASS (pass_rename_ssa_copies); + NEXT_PASS (pass_early_warn_uninitialized); + NEXT_PASS (pass_dce); + NEXT_PASS (pass_dominator); + NEXT_PASS (pass_redundant_phi); + NEXT_PASS (DUP_PASS (pass_dce)); + NEXT_PASS (pass_forwprop); + NEXT_PASS (pass_phiopt); + NEXT_PASS (pass_may_alias); + NEXT_PASS (pass_tail_recursion); + NEXT_PASS (pass_ch); + NEXT_PASS (pass_del_pta); + NEXT_PASS (pass_profile); + NEXT_PASS (pass_lower_complex); + NEXT_PASS (pass_sra); + NEXT_PASS (DUP_PASS (pass_rename_ssa_copies)); + NEXT_PASS (DUP_PASS (pass_dominator)); + NEXT_PASS (DUP_PASS (pass_redundant_phi)); + NEXT_PASS (DUP_PASS (pass_dce)); + NEXT_PASS (pass_dse); + NEXT_PASS (DUP_PASS (pass_forwprop)); + NEXT_PASS (DUP_PASS (pass_phiopt)); + NEXT_PASS (pass_ccp); + NEXT_PASS (DUP_PASS (pass_redundant_phi)); + NEXT_PASS (pass_fold_builtins); + NEXT_PASS (pass_split_crit_edges); + NEXT_PASS (pass_pre); + NEXT_PASS (DUP_PASS (pass_dominator)); + NEXT_PASS (DUP_PASS (pass_redundant_phi)); + NEXT_PASS (pass_cd_dce); + NEXT_PASS (DUP_PASS (pass_dse)); + NEXT_PASS (DUP_PASS (pass_forwprop)); + NEXT_PASS (DUP_PASS (pass_phiopt)); + NEXT_PASS (pass_tail_calls); + NEXT_PASS (pass_late_warn_uninitialized); + NEXT_PASS (pass_warn_function_return); + NEXT_PASS (pass_del_ssa); + NEXT_PASS (pass_nrv); + NEXT_PASS (pass_remove_useless_vars); + NEXT_PASS (pass_del_cfg); + *p = NULL; + +#undef NEXT_PASS +#undef DUP_PASS + + /* Register the passes with the tree dump code. */ + register_dump_files (all_passes); +} + +static void execute_pass_list (struct tree_opt_pass *); + +static unsigned int current_properties; +static unsigned int last_verified; + +static void +execute_todo (unsigned int flags) +{ + if (flags & TODO_rename_vars) + { + if (bitmap_first_set_bit (vars_to_rename) >= 0) + rewrite_into_ssa (); + BITMAP_XFREE (vars_to_rename); + } + + if ((flags & TODO_dump_func) && dump_file) + dump_function_to_file (current_function_decl, + dump_file, dump_flags); + + if (flags & TODO_ggc_collect) + ggc_collect (); + +#ifdef ENABLE_CHECKING + if (flags & TODO_verify_ssa) + verify_ssa (); + if (flags & TODO_verify_flow) + verify_flow_info (); + if (flags & TODO_verify_stmts) + verify_stmts (); +#endif +} + +static bool +execute_one_pass (struct tree_opt_pass *pass) +{ + unsigned int todo; + + /* See if we're supposed to run this pass. */ + if (pass->gate && !pass->gate ()) + return false; + + /* Verify that all required properties are present. */ + if (pass->properties_required & ~current_properties) + abort (); + + /* Run pre-pass verification. */ + todo = pass->todo_flags_start & ~last_verified; + if (todo) + execute_todo (todo); + + /* If a dump file name is present, open it if enabled. */ + if (pass->static_pass_number) + { + dump_file = dump_begin (pass->static_pass_number, &dump_flags); + if (dump_file) + { + const char *dname, *aname; + dname = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + aname = (IDENTIFIER_POINTER + (DECL_ASSEMBLER_NAME (current_function_decl))); + fprintf (dump_file, "\n;; Function %s (%s)\n\n", dname, aname); + } + } + + /* If a timevar is present, start it. */ + if (pass->tv_id) + timevar_push (pass->tv_id); + + /* If the pass is requesting ssa variable renaming, allocate the bitmap. */ + if (pass->todo_flags_finish & TODO_rename_vars) + vars_to_rename = BITMAP_XMALLOC (); + /* Do it! */ + if (pass->execute) + pass->execute (); + /* Run post-pass cleanup and verification. */ + todo = pass->todo_flags_finish; + last_verified = todo & TODO_verify_all; + if (todo) + execute_todo (todo); + + /* Update properties. */ + current_properties &= ~pass->properties_destroyed; + current_properties |= pass->properties_provided; + + /* Close down timevar and dump file. */ + if (pass->tv_id) + timevar_pop (pass->tv_id); + if (dump_file) + { + dump_end (pass->static_pass_number, dump_file); + dump_file = NULL; + } + + return true; +} + +static void +execute_pass_list (struct tree_opt_pass *pass) +{ + do + { + if (execute_one_pass (pass) && pass->sub) + execute_pass_list (pass->sub); + pass = pass->next; + } + while (pass); +} + + /* Called to move the SAVE_EXPRs for parameter declarations in a nested function into the nested function. DATA is really the nested FUNCTION_DECL. */ @@ -52,43 +459,6 @@ set_save_expr_context (tree *tp, return NULL; } -/* Clear out the DECL_RTL for the non-static local variables in BLOCK and - its sub-blocks. DATA is the decl of the function being processed. */ - -static tree -clear_decl_rtl (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data) -{ - bool nonstatic_p, local_p; - tree t = *tp; - - switch (TREE_CODE (t)) - { - case VAR_DECL: - nonstatic_p = !TREE_STATIC (t) && !DECL_EXTERNAL (t); - local_p = decl_function_context (t) == data; - break; - - case PARM_DECL: - case LABEL_DECL: - nonstatic_p = true; - local_p = decl_function_context (t) == data; - break; - - case RESULT_DECL: - nonstatic_p = local_p = true; - break; - - default: - nonstatic_p = local_p = false; - break; - } - - if (nonstatic_p && local_p) - SET_DECL_RTL (t, NULL); - - return NULL; -} - /* For functions-as-trees languages, this performs all optimization and compilation for FNDECL. */ @@ -96,7 +466,7 @@ void tree_rest_of_compilation (tree fndecl, bool nested_p) { location_t saved_loc; - struct cgraph_node *node, *saved_node = NULL; + struct cgraph_node *saved_node = NULL, *node; timevar_push (TV_EXPAND); @@ -152,21 +522,34 @@ tree_rest_of_compilation (tree fndecl, bool nested_p) } } + /* Note that the folders should only create gimple expressions. + This is a hack until the new folder is ready. */ + in_gimple_form = true; + + /* Perform all tree transforms and optimizations. */ + execute_pass_list (all_passes); + + /* Note that the folders can create non-gimple expressions again. */ + in_gimple_form = false; + /* If the function has a variably modified type, there may be SAVE_EXPRs in the parameter types. Their context must be set to refer to this function; they cannot be expanded in the containing function. */ - if (decl_function_context (fndecl) + if (decl_function_context (fndecl) == current_function_decl && variably_modified_type_p (TREE_TYPE (fndecl))) walk_tree (&TREE_TYPE (fndecl), set_save_expr_context, fndecl, NULL); + /* Expand the variables recorded during gimple lowering. This must + occur before the call to expand_function_start to ensure that + all used variables are expanded before we expand anything on the + PENDING_SIZES list. */ + expand_used_vars (); + /* Set up parameters and prepare for return, for the function. */ expand_function_start (fndecl, 0); - /* Allow language dialects to perform special processing. */ - lang_hooks.rtl_expand.start (); - /* If this function is `main', emit a call to `__main' to run global initializers, etc. */ if (DECL_NAME (fndecl) @@ -175,7 +558,7 @@ tree_rest_of_compilation (tree fndecl, bool nested_p) expand_main_function (); /* Generate the RTL for this function. */ - lang_hooks.rtl_expand.stmt (DECL_SAVED_TREE (fndecl)); + expand_expr_stmt_value (DECL_SAVED_TREE (fndecl), 0, 0); /* We hard-wired immediate_size_expand to zero above. expand_function_end will decrement this variable. So, we set the @@ -183,9 +566,14 @@ tree_rest_of_compilation (tree fndecl, bool nested_p) zero. */ immediate_size_expand = 1; - /* Allow language dialects to perform special processing. */ - lang_hooks.rtl_expand.end (); + /* Make sure the locus is set to the end of the function, so that + epilogue line numbers and warnings are set properly. */ + if (cfun->function_end_locus.file) + input_location = cfun->function_end_locus; + /* The following insns belong to the top scope. */ + record_block_change (DECL_INITIAL (current_function_decl)); + /* Generate rtl for function exit. */ expand_function_end (); @@ -201,10 +589,30 @@ tree_rest_of_compilation (tree fndecl, bool nested_p) /* Run the optimizers and output the assembler code for this function. */ rest_of_compilation (fndecl); + /* Restore original body if still needed. */ + if (cfun->saved_tree) + { + DECL_SAVED_TREE (fndecl) = cfun->saved_tree; + DECL_ARGUMENTS (fndecl) = cfun->saved_args; - /* Undo the GC context switch. */ - if (nested_p) - ggc_pop_context (); + /* When not in unit-at-a-time mode, we must preserve out of line copy + representing node before inlining. Restore original outgoing edges + using clone we created earlier. */ + if (!flag_unit_at_a_time) + { + struct cgraph_edge *e; + while (node->callees) + cgraph_remove_edge (node->callees); + node->callees = saved_node->callees; + saved_node->callees = NULL; + for (e = saved_node->callees; e; e = e->next_callee) + e->caller = node; + cgraph_remove_node (saved_node); + } + } + else + DECL_SAVED_TREE (fndecl) = NULL; + cfun = 0; /* If requested, warn about function definitions where the function will return a value (usually of some struct or union type) which itself will @@ -230,41 +638,11 @@ tree_rest_of_compilation (tree fndecl, bool nested_p) } } - /* Since we don't need the RTL for this function anymore, stop pointing to - it. That's especially important for LABEL_DECLs, since you can reach all - the instructions in the function from the CODE_LABEL stored in the - DECL_RTL for the LABEL_DECL. Walk the BLOCK-tree, clearing DECL_RTL for - LABEL_DECLs and non-static local variables. Note that we must check the - context of the variables, otherwise processing a nested function can kill - the rtl of a variable from an outer function. */ - walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), - clear_decl_rtl, - fndecl); - /* Restore original body if still needed. */ - if (cfun->saved_tree) - { - DECL_SAVED_TREE (fndecl) = cfun->saved_tree; - DECL_ARGUMENTS (fndecl) = cfun->saved_args; - - /* When not in unit-at-a-time mode, we must preserve out of line copy - representing node before inlining. Restore original outgoing edges - using clone we created earlier. */ - if (!flag_unit_at_a_time) - { - struct cgraph_edge *e; - while (node->callees) - cgraph_remove_edge (node->callees); - node->callees = saved_node->callees; - saved_node->callees = NULL; - for (e = saved_node->callees; e; e = e->next_callee) - e->caller = node; - cgraph_remove_node (saved_node); - } - } - else + if (!nested_p && !flag_inline_trees) { DECL_SAVED_TREE (fndecl) = NULL; - if (cgraph_node (fndecl)->origin) + if (DECL_STRUCT_FUNCTION (fndecl) == 0 + && !cgraph_node (fndecl)->origin) { /* Stop pointing to the local nodes about to be freed. But DECL_INITIAL must remain nonzero so we know this @@ -275,11 +653,13 @@ tree_rest_of_compilation (tree fndecl, bool nested_p) DECL_INITIAL (fndecl) = error_mark_node; } } - free_after_compilation (cfun); - cfun = 0; - DECL_STRUCT_FUNCTION (fndecl) = 0; input_location = saved_loc; + ggc_collect (); + + /* Undo the GC context switch. */ + if (nested_p) + ggc_pop_context (); timevar_pop (TV_EXPAND); } diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c new file mode 100644 index 00000000000..30931929d43 --- /dev/null +++ b/gcc/tree-outof-ssa.c @@ -0,0 +1,2170 @@ +/* Convert a program in SSA form into Normal form. + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by Andrew Macleod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "tm_p.h" +#include "ggc.h" +#include "langhooks.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "expr.h" +#include "function.h" +#include "diagnostic.h" +#include "bitmap.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "varray.h" +#include "timevar.h" +#include "tree-alias-common.h" +#include "hashtab.h" +#include "tree-dump.h" +#include "tree-ssa-live.h" +#include "tree-pass.h" + +/* Used to hold all the components required to do SSA PHI elimination. + The node and pred/succ list is a simple linear list of nodes and + edges represented as pairs of nodes. + + The predecessor and successor list: Nodes are entered in pairs, where + [0] ->PRED, [1]->SUCC. All the even indexes in the array represent + predecessors, all the odd elements are successors. + + Rationale: + When implemented as bitmaps, very large programs SSA->Normal times were + being dominated by clearing the interference graph. + + Typically this list of edges is extremely small since it only includes + PHI results and uses from a single edge which have not coalesced with + each other. This means that no virtual PHI nodes are included, and + empirical evidence suggests that the number of edges rarely exceed + 3, and in a bootstrap of GCC, the maximum size encountered was 7. + This also limits the number of possible nodes that are involved to + rarely more than 6, and in the bootstrap of gcc, the maximum number + of nodes encountered was 12. */ + +typedef struct _elim_graph { + /* Size of the elimination vectors. */ + int size; + + /* List of nodes in the elimination graph. */ + varray_type nodes; + + /* The predecessor and successor edge list. */ + varray_type edge_list; + + /* Visited vector. */ + sbitmap visited; + + /* Stack for visited nodes. */ + varray_type stack; + + /* The variable partition map. */ + var_map map; + + /* Edge being eliminated by this graph. */ + edge e; + + /* List of constant copies to emit. These are pushed on in pairs. */ + varray_type const_copies; +} *elim_graph; + + +/* Local functions. */ +static tree create_temp (tree); +static void insert_copy_on_edge (edge, tree, tree); +static elim_graph new_elim_graph (int); +static inline void delete_elim_graph (elim_graph); +static inline void clear_elim_graph (elim_graph); +static inline int elim_graph_size (elim_graph); +static inline void elim_graph_add_node (elim_graph, tree); +static inline void elim_graph_add_edge (elim_graph, int, int); +static inline int elim_graph_remove_succ_edge (elim_graph, int); + +static inline void eliminate_name (elim_graph, tree); +static void eliminate_build (elim_graph, basic_block, int); +static void elim_forward (elim_graph, int); +static int elim_unvisited_predecessor (elim_graph, int); +static void elim_backward (elim_graph, int); +static void elim_create (elim_graph, int); +static void eliminate_phi (edge, int, elim_graph); +static tree_live_info_p coalesce_ssa_name (var_map, int); +static void assign_vars (var_map); +static bool replace_variable (var_map, tree *, tree *); +static void eliminate_virtual_phis (void); +static void coalesce_abnormal_edges (var_map, conflict_graph, root_var_p); +static void print_exprs (FILE *, const char *, tree, const char *, tree, + const char *); +static void print_exprs_edge (FILE *, edge, const char *, tree, const char *, + tree); + + +/* Create a temporary variable based on the type of variable T. Use T's name + as the prefix. */ + +static tree +create_temp (tree t) +{ + tree tmp; + const char *name = NULL; + tree type; + + if (TREE_CODE (t) == SSA_NAME) + t = SSA_NAME_VAR (t); + + if (TREE_CODE (t) != VAR_DECL + && TREE_CODE (t) != PARM_DECL) + abort (); + + type = TREE_TYPE (t); + tmp = DECL_NAME (t); + if (tmp) + name = IDENTIFIER_POINTER (tmp); + + if (name == NULL) + name = "temp"; + tmp = create_tmp_var (type, name); + DECL_ARTIFICIAL (tmp) = DECL_ARTIFICIAL (t); + add_referenced_tmp_var (tmp); + + /* add_referenced_tmp_var will create the annotation and set up some + of the flags in the annotation. However, some flags we need to + inherit from our original variable. */ + var_ann (tmp)->type_mem_tag = var_ann (t)->type_mem_tag; + if (is_call_clobbered (t)) + mark_call_clobbered (tmp); + + return tmp; +} + + +/* This helper function fill insert a copy from a constant or variable SRC to + variable DEST on edge E. */ + +static void +insert_copy_on_edge (edge e, tree dest, tree src) +{ + tree copy; + + copy = build (MODIFY_EXPR, TREE_TYPE (dest), dest, src); + set_is_used (dest); + + if (TREE_CODE (src) == ADDR_EXPR) + src = TREE_OPERAND (src, 0); + if (TREE_CODE (src) == VAR_DECL || TREE_CODE (src) == PARM_DECL) + set_is_used (src); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "Inserting a copy on edge BB%d->BB%d :", + e->src->index, + e->dest->index); + print_generic_expr (dump_file, copy, dump_flags); + fprintf (dump_file, "\n"); + } + + bsi_insert_on_edge (e, copy); +} + + +/* Create an elimination graph with SIZE nodes and associated data + structures. */ + +static elim_graph +new_elim_graph (int size) +{ + elim_graph g = (elim_graph) xmalloc (sizeof (struct _elim_graph)); + + VARRAY_TREE_INIT (g->nodes, 30, "Elimination Node List"); + VARRAY_TREE_INIT (g->const_copies, 20, "Elimination Constant Copies"); + VARRAY_INT_INIT (g->edge_list, 20, "Elimination Edge List"); + VARRAY_INT_INIT (g->stack, 30, " Elimination Stack"); + + g->visited = sbitmap_alloc (size); + + return g; +} + + +/* Empty elimination graph G. */ + +static inline void +clear_elim_graph (elim_graph g) +{ + VARRAY_POP_ALL (g->nodes); + VARRAY_POP_ALL (g->edge_list); +} + + +/* Delete elimination graph G. */ + +static inline void +delete_elim_graph (elim_graph g) +{ + sbitmap_free (g->visited); + free (g); +} + + +/* Return the number of nodes in graph G. */ + +static inline int +elim_graph_size (elim_graph g) +{ + return VARRAY_ACTIVE_SIZE (g->nodes); +} + + +/* Add NODE to graph G, if it doesn't exist already. */ + +static inline void +elim_graph_add_node (elim_graph g, tree node) +{ + int x; + for (x = 0; x < elim_graph_size (g); x++) + if (VARRAY_TREE (g->nodes, x) == node) + return; + VARRAY_PUSH_TREE (g->nodes, node); +} + + +/* Add the edge PRED->SUCC to graph G. */ + +static inline void +elim_graph_add_edge (elim_graph g, int pred, int succ) +{ + VARRAY_PUSH_INT (g->edge_list, pred); + VARRAY_PUSH_INT (g->edge_list, succ); +} + + +/* Remove an edge from graph G for which NODE is the predecessor, and + return the successor node. -1 is returned if there is no such edge. */ + +static inline int +elim_graph_remove_succ_edge (elim_graph g, int node) +{ + int y; + unsigned x; + for (x = 0; x < VARRAY_ACTIVE_SIZE (g->edge_list); x += 2) + if (VARRAY_INT (g->edge_list, x) == node) + { + VARRAY_INT (g->edge_list, x) = -1; + y = VARRAY_INT (g->edge_list, x + 1); + VARRAY_INT (g->edge_list, x + 1) = -1; + return y; + } + return -1; +} + + +/* Find all the nodes in GRAPH which are successors to NODE in the + edge list. VAR will hold the partition number found. CODE is the + code fragment executed for every node found. */ + +#define FOR_EACH_ELIM_GRAPH_SUCC(GRAPH, NODE, VAR, CODE) \ +do { \ + unsigned x_; \ + int y_; \ + for (x_ = 0; x_ < VARRAY_ACTIVE_SIZE ((GRAPH)->edge_list); x_ += 2) \ + { \ + y_ = VARRAY_INT ((GRAPH)->edge_list, x_); \ + if (y_ != (NODE)) \ + continue; \ + (VAR) = VARRAY_INT ((GRAPH)->edge_list, x_ + 1); \ + CODE; \ + } \ +} while (0) + + +/* Find all the nodes which are predecessors of NODE in the edge list for + GRAPH. VAR will hold the partition number found. CODE is the + code fragment executed for every node found. */ + +#define FOR_EACH_ELIM_GRAPH_PRED(GRAPH, NODE, VAR, CODE) \ +do { \ + unsigned x_; \ + int y_; \ + for (x_ = 0; x_ < VARRAY_ACTIVE_SIZE ((GRAPH)->edge_list); x_ += 2) \ + { \ + y_ = VARRAY_INT ((GRAPH)->edge_list, x_ + 1); \ + if (y_ != (NODE)) \ + continue; \ + (VAR) = VARRAY_INT ((GRAPH)->edge_list, x_); \ + CODE; \ + } \ +} while (0) + + +/* Add T to elimination graph G. */ + +static inline void +eliminate_name (elim_graph g, tree T) +{ + elim_graph_add_node (g, T); +} + + +/* Build elimination graph G for basic block BB on incoming PHI edge I. */ + +static void +eliminate_build (elim_graph g, basic_block B, int i) +{ + tree phi; + tree T0, Ti; + int p0, pi; + + clear_elim_graph (g); + + for (phi = phi_nodes (B); phi; phi = TREE_CHAIN (phi)) + { + T0 = var_to_partition_to_var (g->map, PHI_RESULT (phi)); + + /* Ignore results which are not in partitions. */ + if (T0 == NULL_TREE) + continue; + + if (PHI_ARG_EDGE (phi, i) == g->e) + Ti = PHI_ARG_DEF (phi, i); + else + { + /* On rare occasions, a PHI node may not have the arguments + in the same order as all of the other PHI nodes. If they don't + match, find the appropriate index here. */ + pi = phi_arg_from_edge (phi, g->e); + if (pi == -1) + abort(); + Ti = PHI_ARG_DEF (phi, pi); + } + + /* If this argument is a constant, or a SSA_NAME which is being + left in SSA form, just queue a copy to be emitted on this + edge. */ + if (!phi_ssa_name_p (Ti) + || (TREE_CODE (Ti) == SSA_NAME + && var_to_partition (g->map, Ti) == NO_PARTITION)) + { + /* Save constant copies until all other copies have been emitted + on this edge. */ + VARRAY_PUSH_TREE (g->const_copies, T0); + VARRAY_PUSH_TREE (g->const_copies, Ti); + } + else + { + Ti = var_to_partition_to_var (g->map, Ti); + if (T0 != Ti) + { + eliminate_name (g, T0); + eliminate_name (g, Ti); + p0 = var_to_partition (g->map, T0); + pi = var_to_partition (g->map, Ti); + elim_graph_add_edge (g, p0, pi); + } + } + } +} + + +/* Push successors of T onto the elimination stack for G. */ + +static void +elim_forward (elim_graph g, int T) +{ + int S; + SET_BIT (g->visited, T); + FOR_EACH_ELIM_GRAPH_SUCC (g, T, S, + { + if (!TEST_BIT (g->visited, S)) + elim_forward (g, S); + }); + VARRAY_PUSH_INT (g->stack, T); +} + + +/* Return 1 if there unvisited predecessors of T in graph G. */ + +static int +elim_unvisited_predecessor (elim_graph g, int T) +{ + int P; + FOR_EACH_ELIM_GRAPH_PRED (g, T, P, + { + if (!TEST_BIT (g->visited, P)) + return 1; + }); + return 0; +} + +/* Process predecessors first, and insert a copy. */ + +static void +elim_backward (elim_graph g, int T) +{ + int P; + SET_BIT (g->visited, T); + FOR_EACH_ELIM_GRAPH_PRED (g, T, P, + { + if (!TEST_BIT (g->visited, P)) + { + elim_backward (g, P); + insert_copy_on_edge (g->e, + partition_to_var (g->map, P), + partition_to_var (g->map, T)); + } + }); +} + +/* Insert required copies for T in graph G. Check for a strongly connected + region, and create a temporary to break the cycle if one is found. */ + +static void +elim_create (elim_graph g, int T) +{ + tree U; + int P, S; + + if (elim_unvisited_predecessor (g, T)) + { + U = create_temp (partition_to_var (g->map, T)); + insert_copy_on_edge (g->e, U, partition_to_var (g->map, T)); + FOR_EACH_ELIM_GRAPH_PRED (g, T, P, + { + if (!TEST_BIT (g->visited, P)) + { + elim_backward (g, P); + insert_copy_on_edge (g->e, partition_to_var (g->map, P), U); + } + }); + } + else + { + S = elim_graph_remove_succ_edge (g, T); + if (S != -1) + { + SET_BIT (g->visited, T); + insert_copy_on_edge (g->e, + partition_to_var (g->map, T), + partition_to_var (g->map, S)); + } + } + +} + +/* Eliminate all the phi nodes on edge E in graph G. I is the usual PHI + index that edge E's values are found on. */ + +static void +eliminate_phi (edge e, int i, elim_graph g) +{ + int num_nodes = 0; + int x; + basic_block B = e->dest; + +#if defined ENABLE_CHECKING + if (i == -1) + abort (); + if (VARRAY_ACTIVE_SIZE (g->const_copies) != 0) + abort (); +#endif + + /* Abnormal edges already have everything coalesced, or the coalescer + would have aborted. */ + if (e->flags & EDGE_ABNORMAL) + return; + + num_nodes = num_var_partitions (g->map); + g->e = e; + + eliminate_build (g, B, i); + + if (elim_graph_size (g) != 0) + { + sbitmap_zero (g->visited); + VARRAY_POP_ALL (g->stack); + + for (x = 0; x < elim_graph_size (g); x++) + { + tree var = VARRAY_TREE (g->nodes, x); + int p = var_to_partition (g->map, var); + if (!TEST_BIT (g->visited, p)) + elim_forward (g, p); + } + + sbitmap_zero (g->visited); + while (VARRAY_ACTIVE_SIZE (g->stack) > 0) + { + x = VARRAY_TOP_INT (g->stack); + VARRAY_POP (g->stack); + if (!TEST_BIT (g->visited, x)) + elim_create (g, x); + } + } + + /* If there are any pending constant copies, issue them now. */ + while (VARRAY_ACTIVE_SIZE (g->const_copies) > 0) + { + tree src, dest; + src = VARRAY_TOP_TREE (g->const_copies); + VARRAY_POP (g->const_copies); + dest = VARRAY_TOP_TREE (g->const_copies); + VARRAY_POP (g->const_copies); + insert_copy_on_edge (e, dest, src); + } +} + + +/* Shortcut routine to print messages to file F of the form: + "STR1 EXPR1 STR2 EXPR2 STR3." */ + +static void +print_exprs (FILE *f, const char *str1, tree expr1, const char *str2, + tree expr2, const char *str3) +{ + fprintf (f, "%s", str1); + print_generic_expr (f, expr1, TDF_SLIM); + fprintf (f, "%s", str2); + print_generic_expr (f, expr2, TDF_SLIM); + fprintf (f, "%s", str3); +} + + +/* Shortcut routine to print abnormal edge messages to file F of the form: + "STR1 EXPR1 STR2 EXPR2 across edge E. */ + +static void +print_exprs_edge (FILE *f, edge e, const char *str1, tree expr1, + const char *str2, tree expr2) +{ + print_exprs (f, str1, expr1, str2, expr2, " across an abnormal edge"); + fprintf (f, " from BB%d->BB%d\n", e->src->index, + e->dest->index); +} + + +/* Coalesce partitions in MAP which are live across abnormal edges in GRAPH. + RV is the root variable groupings of the partitions in MAP. Since code + cannot be inserted on these edges, failure to coalesce something across + an abnormal edge is an error. */ + +static void +coalesce_abnormal_edges (var_map map, conflict_graph graph, root_var_p rv) +{ + basic_block bb; + edge e; + tree phi, var, tmp; + int x, y; + + /* Code cannot be inserted on abnormal edges. Look for all abnormal + edges, and coalesce any PHI results with their arguments across + that edge. */ + + FOR_EACH_BB (bb) + for (e = bb->succ; e; e = e->succ_next) + if (e->dest != EXIT_BLOCK_PTR && e->flags & EDGE_ABNORMAL) + for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi)) + { + /* Visit each PHI on the destination side of this abnormal + edge, and attempt to coalesce the argument with the result. */ + var = PHI_RESULT (phi); + x = var_to_partition (map, var); + + /* Ignore results which are not relevant. */ + if (x == NO_PARTITION) + continue; + + y = phi_arg_from_edge (phi, e); + if (y == -1) + abort (); + + tmp = PHI_ARG_DEF (phi, y); + if (!phi_ssa_name_p (tmp)) + { + print_exprs_edge (stderr, e, + "\nConstant argument in PHI. Can't insert :", + var, " = ", tmp); + abort (); + } + y = var_to_partition (map, tmp); + if (x == NO_PARTITION || y == NO_PARTITION) + abort (); + if (root_var_find (rv, x) != root_var_find (rv, y)) + { + print_exprs_edge (stderr, e, "\nDifferent root vars: ", + root_var (rv, root_var_find (rv, x)), + " and ", + root_var (rv, root_var_find (rv, y))); + abort (); + } + + if (x != y) + { + if (!conflict_graph_conflict_p (graph, x, y)) + { + /* Now map the partitions back to their real variables. */ + var = partition_to_var (map, x); + tmp = partition_to_var (map, y); + if (dump_file + && (dump_flags & TDF_DETAILS)) + { + print_exprs_edge (dump_file, e, + "ABNORMAL: Coalescing ", + var, " and ", tmp); + } + if (var_union (map, var, tmp) == NO_PARTITION) + { + print_exprs_edge (stderr, e, "\nUnable to coalesce", + partition_to_var (map, x), " and ", + partition_to_var (map, y)); + abort (); + } + conflict_graph_merge_regs (graph, x, y); + } + else + { + print_exprs_edge (stderr, e, "\n Conflict ", + partition_to_var (map, x), + " and ", partition_to_var (map, y)); + abort (); + } + } + } +} + + +/* Reduce the number of live ranges in MAP. Live range information is + returned if FLAGS indicates that we are combining temporaries, otherwise + NULL is returned. The only partitions which are associated with actual + variables at this point are those which are forced to be coalesced for + various reason. (live on entry, live across abnormal edges, etc.). */ + +static tree_live_info_p +coalesce_ssa_name (var_map map, int flags) +{ + int num, x, i; + sbitmap live; + tree var, phi; + root_var_p rv; + tree_live_info_p liveinfo; + var_ann_t ann; + conflict_graph graph; + basic_block bb; + coalesce_list_p cl = NULL; + + if (num_var_partitions (map) <= 1) + return NULL; + + /* If no preference given, use cheap coalescing of all partitions. */ + if ((flags & (SSANORM_COALESCE_PARTITIONS | SSANORM_USE_COALESCE_LIST)) == 0) + flags |= SSANORM_COALESCE_PARTITIONS; + + liveinfo = calculate_live_on_entry (map); + calculate_live_on_exit (liveinfo); + rv = root_var_init (map); + + /* Remove single element variable from the list. */ + root_var_compact (rv); + + if (flags & SSANORM_USE_COALESCE_LIST) + { + cl = create_coalesce_list (map); + + /* Add all potential copies via PHI arguments to the list. */ + FOR_EACH_BB (bb) + { + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree res = PHI_RESULT (phi); + int p = var_to_partition (map, res); + if (p == NO_PARTITION) + continue; + for (x = 0; x < PHI_NUM_ARGS (phi); x++) + { + tree arg = PHI_ARG_DEF (phi, x); + int p2; + + if (TREE_CODE (arg) != SSA_NAME) + continue; + if (SSA_NAME_VAR (res) != SSA_NAME_VAR (arg)) + continue; + p2 = var_to_partition (map, PHI_ARG_DEF (phi, x)); + if (p2 != NO_PARTITION) + add_coalesce (cl, p, p2, 1); + } + } + } + + /* Coalesce all the result decls together. */ + var = NULL_TREE; + i = 0; + for (x = 0; x < num_var_partitions (map); x++) + { + tree p = partition_to_var (map, x); + if (TREE_CODE (SSA_NAME_VAR(p)) == RESULT_DECL) + { + if (var == NULL_TREE) + { + var = p; + i = x; + } + else + add_coalesce (cl, i, x, 1); + } + } + } + + /* Build a conflict graph. */ + graph = build_tree_conflict_graph (liveinfo, rv, cl); + + if (cl) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Before sorting:\n"); + dump_coalesce_list (dump_file, cl); + } + + sort_coalesce_list (cl); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nAfter sorting:\n"); + dump_coalesce_list (dump_file, cl); + } + } + + /* Put the single element variables back in. */ + root_var_decompact (rv); + + /* First, coalesce all live on entry variables to their root variable. + This will ensure the first use is coming from the correct location. */ + + live = sbitmap_alloc (num_var_partitions (map)); + sbitmap_zero (live); + + /* Set 'live' vector to indicate live on entry partitions. */ + num = num_var_partitions (map); + for (x = 0 ; x < num; x++) + { + var = partition_to_var (map, x); + if (default_def (SSA_NAME_VAR (var)) == var) + SET_BIT (live, x); + } + + if ((flags & SSANORM_COMBINE_TEMPS) == 0) + { + delete_tree_live_info (liveinfo); + liveinfo = NULL; + } + + /* Assign root variable as partition representative for each live on entry + partition. */ + EXECUTE_IF_SET_IN_SBITMAP (live, 0, x, + { + var = root_var (rv, root_var_find (rv, x)); + ann = var_ann (var); + /* If these aren't already coalesced... */ + if (partition_to_var (map, x) != var) + { + if (ann->out_of_ssa_tag) + { + /* This root variable has already been assigned to another + partition which is not coalesced with this one. */ + abort (); + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + print_exprs (dump_file, "Must coalesce ", + partition_to_var (map, x), + " with the root variable ", var, ".\n"); + } + + change_partition_var (map, var, x); + } + }); + + sbitmap_free (live); + + /* Coalesce partitions live across abnormal edges. */ + coalesce_abnormal_edges (map, graph, rv); + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_var_map (dump_file, map); + + /* Coalesce partitions. */ + if (flags & SSANORM_USE_COALESCE_LIST) + coalesce_tpa_members (rv, graph, map, cl, + ((dump_flags & TDF_DETAILS) ? dump_file + : NULL)); + + + if (flags & SSANORM_COALESCE_PARTITIONS) + coalesce_tpa_members (rv, graph, map, NULL, + ((dump_flags & TDF_DETAILS) ? dump_file + : NULL)); + if (cl) + delete_coalesce_list (cl); + root_var_delete (rv); + conflict_graph_delete (graph); + + return liveinfo; +} + + +/* Take the ssa-name var_map MAP, and assign real variables to each + partition. */ + +static void +assign_vars (var_map map) +{ + int x, i, num, rep; + tree t, var; + var_ann_t ann; + root_var_p rv; + + rv = root_var_init (map); + if (!rv) + return; + + /* Coalescing may already have forced some partitions to their root + variable. Find these and tag them. */ + + num = num_var_partitions (map); + for (x = 0; x < num; x++) + { + var = partition_to_var (map, x); + if (TREE_CODE (var) != SSA_NAME) + { + /* Coalescing will already have verified that more than one + partition doesn't have the same root variable. Simply marked + the variable as assigned. */ + ann = var_ann (var); + ann->out_of_ssa_tag = 1; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "partition %d has variable ", x); + print_generic_expr (dump_file, var, TDF_SLIM); + fprintf (dump_file, " assigned to it.\n"); + } + + } + } + + num = root_var_num (rv); + for (x = 0; x < num; x++) + { + var = root_var (rv, x); + ann = var_ann (var); + for (i = root_var_first_partition (rv, x); + i != ROOT_VAR_NONE; + i = root_var_next_partition (rv, i)) + { + t = partition_to_var (map, i); + + if (t == var || TREE_CODE (t) != SSA_NAME) + continue; + + rep = var_to_partition (map, t); + + if (!ann->out_of_ssa_tag) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + print_exprs (dump_file, "", t, " --> ", var, "\n"); + change_partition_var (map, var, rep); + continue; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + print_exprs (dump_file, "", t, " not coalesced with ", var, + ""); + + var = create_temp (t); + change_partition_var (map, var, rep); + ann = var_ann (var); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " --> New temp: '"); + print_generic_expr (dump_file, var, TDF_SLIM); + fprintf (dump_file, "'\n"); + } + } + } + + root_var_delete (rv); +} + + +/* Replace *P with whatever variable it has been rewritten to based on the + partitions in MAP. EXPR is an optional expression vector over SSA versions + which is used to replace *P with an expression instead of a variable. + If the stmt is changed, return true. */ + +static inline bool +replace_variable (var_map map, tree *p, tree *expr) +{ + tree new_var; + tree var = *p; + + /* Check if we are replacing this variable with an expression. */ + if (expr) + { + int version = SSA_NAME_VERSION (*p); + if (expr[version]) + { + tree new_expr = TREE_OPERAND (expr[version], 1); + *p = new_expr; + /* Clear the stmt's RHS, or GC might bite us. */ + TREE_OPERAND (expr[version], 1) = NULL_TREE; + return true; + } + } + + new_var = var_to_partition_to_var (map, var); + if (new_var) + { + *p = new_var; + set_is_used (new_var); + return true; + } + return false; +} + + +/* Remove any PHI node which is a virtual PHI. */ + +static void +eliminate_virtual_phis (void) +{ + basic_block bb; + tree phi, next; + + FOR_EACH_BB (bb) + { + for (phi = phi_nodes (bb); phi; phi = next) + { + next = TREE_CHAIN (phi); + if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi)))) + { +#ifdef ENABLE_CHECKING + int i; + /* There should be no arguments of this PHI which are in + the partition list, or we get incorrect results. */ + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + tree arg = PHI_ARG_DEF (phi, i); + if (TREE_CODE (arg) == SSA_NAME + && is_gimple_reg (SSA_NAME_VAR (arg))) + { + fprintf (stderr, "Argument of PHI is not virtual ("); + print_generic_expr (stderr, arg, TDF_SLIM); + fprintf (stderr, "), but the result is :"); + print_generic_stmt (stderr, phi, TDF_SLIM); + abort(); + } + } +#endif + remove_phi_node (phi, NULL_TREE, bb); + } + } + } +} + + +/* This routine will coalesce variables in MAP of the same type which do not + interfere with each other. LIVEINFO is the live range info for variables + of interest. This will both reduce the memory footprint of the stack, and + allow us to coalesce together local copies of globals and scalarized + component refs. */ + +static void +coalesce_vars (var_map map, tree_live_info_p liveinfo) +{ + basic_block bb; + type_var_p tv; + tree var; + int x, p, p2; + coalesce_list_p cl; + conflict_graph graph; + + cl = create_coalesce_list (map); + + /* Merge all the live on entry vectors for coalesced partitions. */ + for (x = 0; x < num_var_partitions (map); x++) + { + var = partition_to_var (map, x); + p = var_to_partition (map, var); + if (p != x) + live_merge_and_clear (liveinfo, p, x); + } + + /* When PHI nodes are turned into copies, the result of each PHI node + becomes live on entry to the block. Mark these now. */ + FOR_EACH_BB (bb) + { + tree phi, arg; + int p; + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + p = var_to_partition (map, PHI_RESULT (phi)); + + /* Skip virtual PHI nodes. */ + if (p == NO_PARTITION) + continue; + + make_live_on_entry (liveinfo, bb, p); + + /* Each argument is a potential copy operation. Add any arguments + which are not coalesced to the result to the coalesce list. */ + for (x = 0; x < PHI_NUM_ARGS (phi); x++) + { + arg = PHI_ARG_DEF (phi, x); + if (!phi_ssa_name_p (arg)) + continue; + p2 = var_to_partition (map, arg); + if (p2 == NO_PARTITION) + continue; + if (p != p2) + add_coalesce (cl, p, p2, 1); + } + } + } + + + /* Re-calculate live on exit info. */ + calculate_live_on_exit (liveinfo); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Live range info for variable memory coalescing.\n"); + dump_live_info (dump_file, liveinfo, LIVEDUMP_ALL); + + fprintf (dump_file, "Coalesce list from phi nodes:\n"); + dump_coalesce_list (dump_file, cl); + } + + + tv = type_var_init (map); + if (dump_file) + type_var_dump (dump_file, tv); + type_var_compact (tv); + if (dump_file) + type_var_dump (dump_file, tv); + + graph = build_tree_conflict_graph (liveinfo, tv, cl); + + type_var_decompact (tv); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "type var list now looks like:n"); + type_var_dump (dump_file, tv); + + fprintf (dump_file, "Coalesce list after conflict graph build:\n"); + dump_coalesce_list (dump_file, cl); + } + + sort_coalesce_list (cl); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Coalesce list after sorting:\n"); + dump_coalesce_list (dump_file, cl); + } + + coalesce_tpa_members (tv, graph, map, cl, + ((dump_flags & TDF_DETAILS) ? dump_file : NULL)); + + type_var_delete (tv); + delete_coalesce_list (cl); +} + + +/* Temporary Expression Replacement (TER) + + Replace SSA version variables during out-of-ssa with their defining + expression if there is only one use of the variable. + + A pass is made through the function, one block at a time. No cross block + information is tracked. + + Variables which only have one use, and whose defining stmt is considered + a replaceable expression (see check_replaceable) are entered into + consideration by adding a list of dependent partitions to the version_info + vector for that ssa_name_version. This information comes from the partition + mapping for each USE. At the same time, the partition_dep_list vector for + these partitions have this version number entered into their lists. + + When the use of a replaceable ssa_variable is encountered, the dependence + list in version_info[] is moved to the "pending_dependence" list in case + the current expression is also replaceable. (To be determined later in + processing this stmt.) version_info[] for the version is then updated to + point to the defining stmt and the 'replaceable' bit is set. + + Any partition which is defined by a statement 'kills' any expression which + is dependent on this partition. Every ssa version in the partitions' + dependence list is removed from future consideration. + + All virtual references are lumped together. Any expression which is + dependent on any virtual variable (via a VUSE) has a dependence added + to the special partition defined by VIRTUAL_PARTITION. + + Whenever a VDEF is seen, all expressions dependent this VIRTUAL_PARTITION + are removed from consideration. + + At the end of a basic block, all expression are removed from consideration + in preparation for the next block. + + The end result is a vector over SSA_NAME_VERSION which is passed back to + rewrite_out_of_ssa. As the SSA variables are being rewritten, instead of + replacing the SSA_NAME tree element with the partition it was assigned, + it is replaced with the RHS of the defining expression. */ + + +/* Dependancy list element. This can contain either a partition index or a + version number, depending on which list it is in. */ + +typedef struct value_expr_d +{ + int value; + struct value_expr_d *next; +} *value_expr_p; + + +/* Temporary Expression Replacement (TER) table information. */ + +typedef struct temp_expr_table_d +{ + var_map map; + void **version_info; + value_expr_p *partition_dep_list; + bitmap replaceable; + bool saw_replaceable; + int virtual_partition; + bitmap partition_in_use; + value_expr_p free_list; + value_expr_p pending_dependence; +} *temp_expr_table_p; + +/* Used to indicate a dependancy on VDEFs. */ +#define VIRTUAL_PARTITION(table) (table->virtual_partition) + +static temp_expr_table_p new_temp_expr_table (var_map); +static tree *free_temp_expr_table (temp_expr_table_p); +static inline value_expr_p new_value_expr (temp_expr_table_p); +static inline void free_value_expr (temp_expr_table_p, value_expr_p); +static inline value_expr_p find_value_in_list (value_expr_p, int, + value_expr_p *); +static inline void add_value_to_list (temp_expr_table_p, value_expr_p *, int); +static inline void add_info_to_list (temp_expr_table_p, value_expr_p *, + value_expr_p); +static value_expr_p remove_value_from_list (value_expr_p *, int); +static void add_dependance (temp_expr_table_p, int, tree); +static bool check_replaceable (temp_expr_table_p, tree); +static void finish_expr (temp_expr_table_p, int, bool); +static void mark_replaceable (temp_expr_table_p, tree); +static inline void kill_expr (temp_expr_table_p, int, bool); +static inline void kill_virtual_exprs (temp_expr_table_p, bool); +static void find_replaceable_in_bb (temp_expr_table_p, basic_block); +static tree *find_replaceable_exprs (var_map); +static void dump_replaceable_exprs (FILE *, tree *); + + +/* Create a new TER table for MAP. */ + +static temp_expr_table_p +new_temp_expr_table (var_map map) +{ + temp_expr_table_p t; + + t = (temp_expr_table_p) xmalloc (sizeof (struct temp_expr_table_d)); + t->map = map; + + t->version_info = xcalloc (highest_ssa_version + 1, sizeof (void *)); + t->partition_dep_list = xcalloc (num_var_partitions (map) + 1, + sizeof (value_expr_p)); + + t->replaceable = BITMAP_XMALLOC (); + t->partition_in_use = BITMAP_XMALLOC (); + + t->saw_replaceable = false; + t->virtual_partition = num_var_partitions (map); + t->free_list = NULL; + t->pending_dependence = NULL; + + return t; +} + + +/* Free TER table T. If there are valid replacements, return the expression + vector. */ + +static tree * +free_temp_expr_table (temp_expr_table_p t) +{ + value_expr_p p; + tree *ret = NULL; + +#ifdef ENABLE_CHECKING + int x; + for (x = 0; x <= num_var_partitions (t->map); x++) + if (t->partition_dep_list[x] != NULL) + abort(); +#endif + + while ((p = t->free_list)) + { + t->free_list = p->next; + free (p); + } + + BITMAP_XFREE (t->partition_in_use); + BITMAP_XFREE (t->replaceable); + + free (t->partition_dep_list); + if (t->saw_replaceable) + ret = (tree *)t->version_info; + else + free (t->version_info); + + free (t); + return ret; +} + + +/* Allocate a new value list node. Take it from the free list in TABLE if + possible. */ + +static inline value_expr_p +new_value_expr (temp_expr_table_p table) +{ + value_expr_p p; + if (table->free_list) + { + p = table->free_list; + table->free_list = p->next; + } + else + p = (value_expr_p) xmalloc (sizeof (struct value_expr_d)); + + return p; +} + + +/* Add value list node P to the free list in TABLE. */ + +static inline void +free_value_expr (temp_expr_table_p table, value_expr_p p) +{ + p->next = table->free_list; + table->free_list = p; +} + + +/* Find VALUE if its in LIST. Return a pointer to the list object if found, + else return NULL. If LAST_PTR is provided, it will point to the previous + item upon return, or NULL if this is the first item in the list. */ + +static inline value_expr_p +find_value_in_list (value_expr_p list, int value, value_expr_p *last_ptr) +{ + value_expr_p curr; + value_expr_p last = NULL; + + for (curr = list; curr; last = curr, curr = curr->next) + { + if (curr->value == value) + break; + } + if (last_ptr) + *last_ptr = last; + return curr; +} + + +/* Add VALUE to LIST, if it isn't already present. TAB is the expression + table */ + +static inline void +add_value_to_list (temp_expr_table_p tab, value_expr_p *list, int value) +{ + value_expr_p info; + + if (!find_value_in_list (*list, value, NULL)) + { + info = new_value_expr (tab); + info->value = value; + info->next = *list; + *list = info; + } +} + + +/* Add value node INFO if it's value isn't already in LIST. Free INFO if + it is already in the list. TAB is the expression table. */ + +static inline void +add_info_to_list (temp_expr_table_p tab, value_expr_p *list, value_expr_p info) +{ + if (find_value_in_list (*list, info->value, NULL)) + free_value_expr (tab, info); + else + { + info->next = *list; + *list = info; + } +} + + +/* Look for VALUE in LIST. If found, remove it from the list and return it's + pointer. */ + +static value_expr_p +remove_value_from_list (value_expr_p *list, int value) +{ + value_expr_p info, last; + + info = find_value_in_list (*list, value, &last); + if (!info) + return NULL; + if (!last) + *list = info->next; + else + last->next = info->next; + + return info; +} + + +/* Add a dependancy between the def of ssa VERSION and VAR. if VAR is + replaceable by an expression, add a dependance each of the elements of the + expression. These are contained in the pending list. TAB is the + expression table. */ + +static void +add_dependance (temp_expr_table_p tab, int version, tree var) +{ + int i, x; + value_expr_p info; + + i = SSA_NAME_VERSION (var); + if (bitmap_bit_p (tab->replaceable, i)) + { + /* This variable is being substituted, so use whatever dependences + were queued up when we marked this as replaceable earlier. */ + while ((info = tab->pending_dependence)) + { + tab->pending_dependence = info->next; + /* Get the partition this variable was dependent on. Reuse this + object to represent the current expression instead. */ + x = info->value; + info->value = version; + add_info_to_list (tab, &(tab->partition_dep_list[x]), info); + add_value_to_list (tab, + (value_expr_p *)&(tab->version_info[version]), x); + bitmap_set_bit (tab->partition_in_use, x); + } + } + else + { + i = var_to_partition (tab->map, var); +#ifdef ENABLE_CHECKING + if (i== NO_PARTITION) + abort (); +#endif + add_value_to_list (tab, &(tab->partition_dep_list[i]), version); + add_value_to_list (tab, + (value_expr_p *)&(tab->version_info[version]), i); + bitmap_set_bit (tab->partition_in_use, i); + } +} + + +/* Check if expression STMT is suitable for replacement in table TAB. If so, + create an expression entry. Return true if this stmt is replaceable. */ + +static bool +check_replaceable (temp_expr_table_p tab, tree stmt) +{ + stmt_ann_t ann; + vuse_optype vuseops; + def_optype defs; + use_optype uses; + tree var, def; + int num_use_ops, version, i; + var_map map = tab->map; + + if (TREE_CODE (stmt) != MODIFY_EXPR) + return false; + + ann = stmt_ann (stmt); + defs = DEF_OPS (ann); + + /* Punt if there is more than 1 def, or more than 1 use. */ + if (NUM_DEFS (defs) != 1) + return false; + def = DEF_OP (defs, 0); + if (version_ref_count (map, def) != 1) + return false; + + /* Assignments to variables assigned to hard registers are not + replaceable. */ + if (DECL_HARD_REGISTER (SSA_NAME_VAR (def))) + return false; + + /* There must be no VDEFS. */ + if (NUM_VDEFS (VDEF_OPS (ann)) != 0) + return false; + + /* Float expressions must go through memory if float-store is on. */ + if (flag_float_store && FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 1)))) + return false; + + uses = USE_OPS (ann); + num_use_ops = NUM_USES (uses); + vuseops = VUSE_OPS (ann); + + /* Any expression which has no virtual operands and no real operands + should have been propagated if it's possible to do anything with them. + If this happens here, it probably exists that way for a reason, so we + won't touch it. An example is: + b_4 = &tab + There are no virtual uses nor any real uses, so we just leave this + alone to be safe. */ + + if (num_use_ops == 0 && NUM_VUSES (vuseops) == 0) + return false; + + version = SSA_NAME_VERSION (def); + + /* Add this expression to the dependancy list for each use partition. */ + for (i = 0; i < num_use_ops; i++) + { + var = USE_OP (uses, i); + add_dependance (tab, version, var); + } + + /* If there are VUSES, add a dependence on virtual defs. */ + if (NUM_VUSES (vuseops) != 0) + { + add_value_to_list (tab, (value_expr_p *)&(tab->version_info[version]), + VIRTUAL_PARTITION (tab)); + add_value_to_list (tab, + &(tab->partition_dep_list[VIRTUAL_PARTITION (tab)]), + version); + bitmap_set_bit (tab->partition_in_use, VIRTUAL_PARTITION (tab)); + } + + return true; +} + + +/* This function will remove the expression for VERSION from replacement + consideration.n table TAB If 'replace' is true, it is marked as + replaceable, otherwise not. */ + +static void +finish_expr (temp_expr_table_p tab, int version, bool replace) +{ + value_expr_p info, tmp; + int partition; + + /* Remove this expression from its dependent lists. The partition dependance + list is retained and transfered later to whomever uses this version. */ + for (info = (value_expr_p) tab->version_info[version]; info; info = tmp) + { + partition = info->value; +#ifdef ENABLE_CHECKING + if (tab->partition_dep_list[partition] == NULL) + abort (); +#endif + tmp = remove_value_from_list (&(tab->partition_dep_list[partition]), + version); +#ifdef ENABLE_CHECKING + if (!tmp) + abort (); +#endif + free_value_expr (tab, tmp); + /* Only clear the bit when the dependancy list is emptied via + a replacement. Otherwise kill_expr will take care of it. */ + if (!(tab->partition_dep_list[partition]) && replace) + bitmap_clear_bit (tab->partition_in_use, partition); + tmp = info->next; + if (!replace) + free_value_expr (tab, info); + } + + if (replace) + { + tab->saw_replaceable = true; + bitmap_set_bit (tab->replaceable, version); + } + else + { +#ifdef ENABLE_CHECKING + if (bitmap_bit_p (tab->replaceable, version)) + abort (); +#endif + tab->version_info[version] = NULL; + } +} + + +/* Mark the expression associated with VAR as replaceable, and enter + the defining stmt into the version_info table TAB. */ + +static void +mark_replaceable (temp_expr_table_p tab, tree var) +{ + value_expr_p info; + int version = SSA_NAME_VERSION (var); + finish_expr (tab, version, true); + + /* Move the dependence list to the pending list. */ + if (tab->version_info[version]) + { + info = (value_expr_p) tab->version_info[version]; + for ( ; info->next; info = info->next) + continue; + info->next = tab->pending_dependence; + tab->pending_dependence = (value_expr_p)tab->version_info[version]; + } + + tab->version_info[version] = SSA_NAME_DEF_STMT (var); +} + + +/* This function marks any expression in TAB which is dependent on PARTITION + as NOT replaceable. CLEAR_BIT is used to determine whether partition_in_use + should have its bit cleared. Since this routine can be called within an + EXECUTE_IF_SET_IN_BITMAP, the bit can't always be cleared. */ + +static inline void +kill_expr (temp_expr_table_p tab, int partition, bool clear_bit) +{ + value_expr_p ptr; + + /* Mark every active expr dependant on this var as not replaceable. */ + while ((ptr = tab->partition_dep_list[partition]) != NULL) + finish_expr (tab, ptr->value, false); + + if (clear_bit) + bitmap_clear_bit (tab->partition_in_use, partition); +} + + +/* This function kills all expressions in TAB which are dependant on virtual + DEFs. CLEAR_BIT determines whether partition_in_use gets cleared. */ + +static inline void +kill_virtual_exprs (temp_expr_table_p tab, bool clear_bit) +{ + kill_expr (tab, VIRTUAL_PARTITION (tab), clear_bit); +} + + +/* This function processes basic block BB, and looks for variables which can + be replaced by their expressions. Results are stored in TAB. */ + +static void +find_replaceable_in_bb (temp_expr_table_p tab, basic_block bb) +{ + block_stmt_iterator bsi; + tree stmt, def; + stmt_ann_t ann; + int partition, num, i; + use_optype uses; + def_optype defs; + var_map map = tab->map; + value_expr_p p; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + ann = stmt_ann (stmt); + + /* Determine if this stmt finishes an existing expression. */ + uses = USE_OPS (ann); + num = NUM_USES (uses); + for (i = 0; i < num; i++) + { + def = USE_OP (uses, i); + if (tab->version_info[SSA_NAME_VERSION (def)]) + { + /* Mark expression as replaceable unless stmt is volatile. */ + if (!ann->has_volatile_ops) + mark_replaceable (tab, def); + else + finish_expr (tab, SSA_NAME_VERSION (def), false); + } + } + + /* Next, see if this stmt kills off an active expression. */ + defs = DEF_OPS (ann); + num = NUM_DEFS (defs); + for (i = 0; i < num; i++) + { + def = DEF_OP (defs, i); + partition = var_to_partition (map, def); + if (partition != NO_PARTITION && tab->partition_dep_list[partition]) + kill_expr (tab, partition, true); + } + + /* Now see if we are creating a new expression or not. */ + if (!ann->has_volatile_ops) + check_replaceable (tab, stmt); + + /* Free any unused dependancy lists. */ + while ((p = tab->pending_dependence)) + { + tab->pending_dependence = p->next; + free_value_expr (tab, p); + } + + /* A VDEF kills any expression using a virtual operand. */ + if (NUM_VDEFS (VDEF_OPS (ann)) > 0) + kill_virtual_exprs (tab, true); + } +} + + +/* This function is the driver routine for replacement of temporary expressions + in the SSA->normal phase, operating on MAP. If there are replaceable + expressions, a table is returned which maps SSA versions to the + expressions they should be replaced with. A NULL_TREE indicates no + replacement should take place. If there are no replacements at all, + NULL is returned by the function, otherwise an expression vector indexed + by SSA_NAME version numbers. */ + +static tree * +find_replaceable_exprs (var_map map) +{ + basic_block bb; + int i; + temp_expr_table_p table; + tree *ret; + + table = new_temp_expr_table (map); + FOR_EACH_BB (bb) + { + find_replaceable_in_bb (table, bb); + EXECUTE_IF_SET_IN_BITMAP ((table->partition_in_use), 0, i, + { + kill_expr (table, i, false); + }); + } + + ret = free_temp_expr_table (table); + return ret; +} + + +/* Dump TER expression table EXPR to file F. */ + +static void +dump_replaceable_exprs (FILE *f, tree *expr) +{ + tree stmt, var; + int x; + fprintf (f, "\nReplacing Expressions\n"); + for (x = 0; x < (int)highest_ssa_version + 1; x++) + if (expr[x]) + { + stmt = expr[x]; + var = DEF_OP (STMT_DEF_OPS (stmt), 0); + print_generic_expr (f, var, TDF_SLIM); + fprintf (f, " replace with --> "); + print_generic_expr (f, TREE_OPERAND (stmt, 1), TDF_SLIM); + fprintf (f, "\n"); + } + fprintf (f, "\n"); +} + + +/* Helper function for discover_nonconstant_array_refs. + Look for ARRAY_REF nodes with non-constant indexes and mark them + addressable. */ + +static tree +discover_nonconstant_array_refs_r (tree * tp, int *walk_subtrees, + void *data ATTRIBUTE_UNUSED) +{ + tree t = *tp; + + if (TYPE_P (t) || DECL_P (t)) + *walk_subtrees = 0; + else if (TREE_CODE (t) == ARRAY_REF) + { + while ((TREE_CODE (t) == ARRAY_REF + && is_gimple_min_invariant (TREE_OPERAND (t, 1))) + || (TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == BIT_FIELD_REF + || TREE_CODE (t) == REALPART_EXPR + || TREE_CODE (t) == IMAGPART_EXPR)) + t = TREE_OPERAND (t, 0); + + if (TREE_CODE (t) == ARRAY_REF) + { + t = get_base_address (t); + if (t && DECL_P (t)) + TREE_ADDRESSABLE (t) = 1; + } + + *walk_subtrees = 0; + } + + return NULL_TREE; +} + + +/* RTL expansion is not able to compile array references with variable + offsets for arrays stored in single register. Discover such + expressions and mark variables as addressable to avoid this + scenario. */ + +static void +discover_nonconstant_array_refs (void) +{ + basic_block bb; + block_stmt_iterator bsi; + + FOR_EACH_BB (bb) + { + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + walk_tree (bsi_stmt_ptr (bsi), discover_nonconstant_array_refs_r, + NULL , NULL); + } +} + + +/* This function will rewrite the current program using the variable mapping + found in MAP. If the replacement vector VALUES is provided, any + occurrences of partitions with non-null entries in the vector will be + replaced with the expression in the vector instead of its mapped + variable. */ + +static void +rewrite_trees (var_map map, tree *values) +{ + elim_graph g; + basic_block bb; + block_stmt_iterator si; + edge e; + tree phi; + bool changed; + +#ifdef ENABLE_CHECKING + /* Search for PHIs where the destination has no partition, but one + or more arguments has a partition. This should not happen and can + create incorrect code. */ + FOR_EACH_BB (bb) + { + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree T0 = var_to_partition_to_var (map, PHI_RESULT (phi)); + + if (T0 == NULL_TREE) + { + int i; + + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + tree arg = PHI_ARG_DEF (phi, i); + + if (TREE_CODE (arg) == SSA_NAME + && var_to_partition (map, arg) != NO_PARTITION) + { + fprintf (stderr, "Argument of PHI is in a partition :("); + print_generic_expr (stderr, arg, TDF_SLIM); + fprintf (stderr, "), but the result is not :"); + print_generic_stmt (stderr, phi, TDF_SLIM); + abort(); + } + } + } + } + } +#endif + + /* Replace PHI nodes with any required copies. */ + g = new_elim_graph (map->num_partitions); + g->map = map; + FOR_EACH_BB (bb) + { + for (si = bsi_start (bb); !bsi_end_p (si); ) + { + size_t i, num_uses, num_defs; + use_optype uses; + def_optype defs; + tree stmt = bsi_stmt (si); + tree *use_p = NULL; + int remove = 0, is_copy = 0; + stmt_ann_t ann; + + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + changed = false; + + if (TREE_CODE (stmt) == MODIFY_EXPR + && (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME)) + is_copy = 1; + + uses = USE_OPS (ann); + num_uses = NUM_USES (uses); + + for (i = 0; i < num_uses; i++) + { + use_p = USE_OP_PTR (uses, i); + if (replace_variable (map, use_p, values)) + changed = true; + } + + defs = DEF_OPS (ann); + num_defs = NUM_DEFS (defs); + + /* Mark this stmt for removal if it is the list of replaceable + expressions. */ + if (values && num_defs == 1) + { + tree def = DEF_OP (defs, 0); + tree val; + val = values[SSA_NAME_VERSION (def)]; + if (val) + remove = 1; + } + if (!remove) + { + for (i = 0; i < num_defs; i++) + { + tree *def_p = DEF_OP_PTR (defs, i); + + if (replace_variable (map, def_p, NULL)) + changed = true; + + /* If both SSA_NAMEs coalesce to the same variable, + mark the now redundant copy for removal. */ + if (is_copy + && num_uses == 1 + && use_p + && def_p + && (*def_p == *use_p)) + remove = 1; + } + if (changed) + modify_stmt (stmt); + } + + /* Remove any stmts marked for removal. */ + if (remove) + bsi_remove (&si); + else + bsi_next (&si); + } + + phi = phi_nodes (bb); + if (phi) + { + for (e = bb->pred; e; e = e->pred_next) + eliminate_phi (e, phi_arg_from_edge (phi, e), g); + } + } + + delete_elim_graph (g); + + /* If any copies were inserted on edges, actually insert them now. */ + bsi_commit_edge_inserts (NULL); +} + + +/* Remove the variables specified in MAP from SSA form. Any debug information + is sent to DUMP. FLAGS indicate what options should be used. */ + +void +remove_ssa_form (FILE *dump, var_map map, int flags) +{ + tree_live_info_p liveinfo; + basic_block bb; + tree phi, next; + FILE *save; + tree *values = NULL; + + save = dump_file; + dump_file = dump; + + /* If we are not combining temps, don't calculate live ranges for variables + with only one SSA version. */ + if ((flags & SSANORM_COMBINE_TEMPS) == 0) + compact_var_map (map, VARMAP_NO_SINGLE_DEFS); + else + compact_var_map (map, VARMAP_NORMAL); + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_var_map (dump_file, map); + + liveinfo = coalesce_ssa_name (map, flags); + + /* Make sure even single occurrence variables are in the list now. */ + if ((flags & SSANORM_COMBINE_TEMPS) == 0) + compact_var_map (map, VARMAP_NORMAL); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "After Coalescing:\n"); + dump_var_map (dump_file, map); + } + + if (flags & SSANORM_PERFORM_TER) + { + values = find_replaceable_exprs (map); + if (values && dump_file && (dump_flags & TDF_DETAILS)) + dump_replaceable_exprs (dump_file, values); + } + + /* Assign real variables to the partitions now. */ + assign_vars (map); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "After Root variable replacement:\n"); + dump_var_map (dump_file, map); + } + + if ((flags & SSANORM_COMBINE_TEMPS) && liveinfo) + { + coalesce_vars (map, liveinfo); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "After variable memory coalescing:\n"); + dump_var_map (dump_file, map); + } + } + + if (liveinfo) + delete_tree_live_info (liveinfo); + + rewrite_trees (map, values); + + if (values) + free (values); + + /* Remove phi nodes which have been translated back to real variables. */ + FOR_EACH_BB (bb) + { + for (phi = phi_nodes (bb); phi; phi = next) + { + next = TREE_CHAIN (phi); + if ((flags & SSANORM_REMOVE_ALL_PHIS) + || var_to_partition (map, PHI_RESULT (phi)) != NO_PARTITION) + remove_phi_node (phi, NULL_TREE, bb); + } + } + + dump_file = save; +} + + +/* Take a subset of the variables VARS in the current function out of SSA + form. */ + +void +rewrite_vars_out_of_ssa (bitmap vars) +{ + if (bitmap_first_set_bit (vars) >= 0) + { + var_map map; + basic_block bb; + tree phi; + int i; + int ssa_flags; + + /* Search for PHIs in which one of the PHI arguments is marked for + translation out of SSA form, but for which the PHI result is not + marked for translation out of SSA form. + + Our per-variable out of SSA translation can not handle that case; + however we can easily handle it here by creating a new instance + of the PHI result's underlying variable and initializing it to + the offending PHI argument on the edge associated with the + PHI argument. We then change the PHI argument to use our new + instead of the PHI's underlying variable. + + You might think we could register partitions for the out-of-ssa + translation here and avoid a second walk of the PHI nodes. No + such luck since the size of the var map will change if we have + to manually take variables out of SSA form here. */ + FOR_EACH_BB (bb) + { + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree result = SSA_NAME_VAR (PHI_RESULT (phi)); + + /* If the definition is marked for renaming, then we need + to do nothing more for this PHI node. */ + if (bitmap_bit_p (vars, var_ann (result)->uid)) + continue; + + /* Look at all the arguments and see if any of them are + marked for renaming. If so, we need to handle them + specially. */ + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + tree arg = PHI_ARG_DEF (phi, i); + + /* If the argument is not an SSA_NAME, then we can ignore + this argument. */ + if (TREE_CODE (arg) != SSA_NAME) + continue; + + /* If this argument is marked for renaming, then we need + to undo the copy propagation so that we can take + the argument out of SSA form without taking the + result out of SSA form. */ + arg = SSA_NAME_VAR (arg); + if (bitmap_bit_p (vars, var_ann (arg)->uid)) + { + tree new_name, copy; + + /* Get a new SSA_NAME for the copy, it is based on + the result, not the argument! We use the PHI + as the definition since we haven't created the + definition statement yet. */ + new_name = make_ssa_name (result, phi); + + /* Now create the copy statement. */ + copy = build (MODIFY_EXPR, TREE_TYPE (arg), + new_name, PHI_ARG_DEF (phi, i)); + + /* Now update SSA_NAME_DEF_STMT to point to the + newly created statement. */ + SSA_NAME_DEF_STMT (new_name) = copy; + + /* Now make the argument reference our new SSA_NAME. */ + PHI_ARG_DEF (phi, i) = new_name; + + /* Queue the statement for insertion. */ + bsi_insert_on_edge (PHI_ARG_EDGE (phi, i), copy); + modify_stmt (copy); + } + } + } + } + + /* If any copies were inserted on edges, actually insert them now. */ + bsi_commit_edge_inserts (NULL); + + /* Now register partitions for all instances of the variables we + are taking out of SSA form. */ + map = init_var_map (highest_ssa_version + 1); + register_ssa_partitions_for_vars (vars, map); + + /* Now that we have all the partitions registered, translate the + appropriate variables out of SSA form. */ + ssa_flags = SSANORM_COALESCE_PARTITIONS; + if (flag_tree_combine_temps) + ssa_flags |= SSANORM_COMBINE_TEMPS; + remove_ssa_form (dump_file, map, ssa_flags); + + /* And finally, reset the out_of_ssa flag for each of the vars + we just took out of SSA form. */ + EXECUTE_IF_SET_IN_BITMAP (vars, 0, i, + { + var_ann (referenced_var (i))->out_of_ssa_tag = 0; + }); + + } +} + + +/* Take the current function out of SSA form, as described in + R. Morgan, ``Building an Optimizing Compiler'', + Butterworth-Heinemann, Boston, MA, 1998. pp 176-186. */ + +static void +rewrite_out_of_ssa (void) +{ + var_map map; + int var_flags = 0; + int ssa_flags = (SSANORM_REMOVE_ALL_PHIS | SSANORM_USE_COALESCE_LIST); + + if (!flag_tree_live_range_split) + ssa_flags |= SSANORM_COALESCE_PARTITIONS; + + eliminate_virtual_phis (); + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_tree_cfg (dump_file, dump_flags & ~TDF_DETAILS); + + /* We cannot allow unssa to un-gimplify trees before we instrument them. */ + if (flag_tree_ter && !flag_mudflap) + var_flags = SSA_VAR_MAP_REF_COUNT; + + map = create_ssa_var_map (var_flags); + + if (flag_tree_combine_temps) + ssa_flags |= SSANORM_COMBINE_TEMPS; + if (flag_tree_ter && !flag_mudflap) + ssa_flags |= SSANORM_PERFORM_TER; + + remove_ssa_form (dump_file, map, ssa_flags); + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_tree_cfg (dump_file, dump_flags & ~TDF_DETAILS); + + /* Do some cleanups which reduce the amount of data the + tree->rtl expanders deal with. */ + cfg_remove_useless_stmts (); + + /* Flush out flow graph and SSA data. */ + delete_var_map (map); + + /* Mark arrays indexed with non-constant indices with TREE_ADDRESSABLE. */ + discover_nonconstant_array_refs (); +} + + +/* Define the parameters of the out of SSA pass. */ + +struct tree_opt_pass pass_del_ssa = +{ + "optimized", /* name */ + NULL, /* gate */ + rewrite_out_of_ssa, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_SSA_TO_NORMAL, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + /* ??? If TER is enabled, we also kill gimple. */ + PROP_ssa, /* properties_destroyed */ + TODO_verify_ssa | TODO_verify_flow + | TODO_verify_stmts, /* todo_flags_start */ + TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ +}; diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h new file mode 100644 index 00000000000..cdaf8efefdc --- /dev/null +++ b/gcc/tree-pass.h @@ -0,0 +1,130 @@ +/* Definitions for describing one tree-ssa optimization pass. + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by Richard Henderson + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef GCC_TREE_PASS_H +#define GCC_TREE_PASS_H 1 + +/* Global variables used to communicate with passes. */ +extern FILE *dump_file; +extern int dump_flags; + +extern struct bitmap_head_def *vars_to_rename; + +/* Describe one pass. */ +struct tree_opt_pass +{ + /* Terse name of the pass used as a fragment of the dump file name. */ + const char *name; + + /* If non-null, this pass and all sub-passes are executed only if + the function returns true. */ + bool (*gate) (void); + + /* This is the code to run. If null, then there should be sub-passes + otherwise this pass does nothing. */ + void (*execute) (void); + + /* A list of sub-passes to run, dependent on gate predicate. */ + struct tree_opt_pass *sub; + + /* Next in the list of passes to run, independent of gate predicate. */ + struct tree_opt_pass *next; + + /* Static pass number, used as a fragment of the dump file name. */ + unsigned int static_pass_number; + + /* The timevar id associated with this pass. */ + /* ??? Ideally would be dynamically assigned. */ + unsigned int tv_id; + + /* Sets of properties input and output from this pass. */ + unsigned int properties_required; + unsigned int properties_provided; + unsigned int properties_destroyed; + + /* Flags indicating common sets things to do before and after. */ + unsigned int todo_flags_start; + unsigned int todo_flags_finish; +}; + +/* Pass properties. */ +#define PROP_gimple_any (1 << 0) /* entire gimple grammar */ +#define PROP_gimple_lcf (1 << 1) /* lowered control flow */ +#define PROP_gimple_leh (1 << 2) /* lowered eh */ +#define PROP_cfg (1 << 3) +#define PROP_referenced_vars (1 << 4) +#define PROP_pta (1 << 5) +#define PROP_ssa (1 << 6) +#define PROP_no_crit_edges (1 << 7) + +/* To-do flags. */ +#define TODO_dump_func (1 << 0) /* pass doesn't dump itself */ +#define TODO_rename_vars (1 << 1) /* rewrite new vars to ssa */ +#define TODO_ggc_collect (1 << 2) /* run the collector */ +#define TODO_verify_ssa (1 << 3) +#define TODO_verify_flow (1 << 4) +#define TODO_verify_stmts (1 << 5) + +#define TODO_verify_all \ + (TODO_verify_ssa | TODO_verify_flow | TODO_verify_stmts) + + +extern struct tree_opt_pass pass_mudflap_1; +extern struct tree_opt_pass pass_mudflap_2; +extern struct tree_opt_pass pass_remove_useless_stmts; +extern struct tree_opt_pass pass_lower_cf; +extern struct tree_opt_pass pass_lower_eh; +extern struct tree_opt_pass pass_build_cfg; +extern struct tree_opt_pass pass_tree_profile; +extern struct tree_opt_pass pass_referenced_vars; +extern struct tree_opt_pass pass_build_pta; +extern struct tree_opt_pass pass_del_pta; +extern struct tree_opt_pass pass_sra; +extern struct tree_opt_pass pass_tail_recursion; +extern struct tree_opt_pass pass_tail_calls; +extern struct tree_opt_pass pass_loop; +extern struct tree_opt_pass pass_ch; +extern struct tree_opt_pass pass_ccp; +extern struct tree_opt_pass pass_build_ssa; +extern struct tree_opt_pass pass_del_ssa; +extern struct tree_opt_pass pass_dominator; +extern struct tree_opt_pass pass_dce; +extern struct tree_opt_pass pass_cd_dce; +extern struct tree_opt_pass pass_may_alias; +extern struct tree_opt_pass pass_split_crit_edges; +extern struct tree_opt_pass pass_pre; +extern struct tree_opt_pass pass_profile; +extern struct tree_opt_pass pass_lower_complex; +extern struct tree_opt_pass pass_fold_builtins; +extern struct tree_opt_pass pass_early_warn_uninitialized; +extern struct tree_opt_pass pass_late_warn_uninitialized; +extern struct tree_opt_pass pass_warn_function_return; +extern struct tree_opt_pass pass_phiopt; +extern struct tree_opt_pass pass_forwprop; +extern struct tree_opt_pass pass_redundant_phi; +extern struct tree_opt_pass pass_dse; +extern struct tree_opt_pass pass_nrv; +extern struct tree_opt_pass pass_remove_useless_vars; +extern struct tree_opt_pass pass_rename_ssa_copies; + + +#endif /* GCC_TREE_PASS_H */ diff --git a/gcc/tree-phinodes.c b/gcc/tree-phinodes.c new file mode 100644 index 00000000000..e4fc904fd4a --- /dev/null +++ b/gcc/tree-phinodes.c @@ -0,0 +1,524 @@ +/* Generic routines for manipulating PHIs + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "varray.h" +#include "ggc.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "toplev.h" + +/* Rewriting a function into SSA form can create a huge number of PHIs + many of which may be thrown away shortly after their creation if jumps + were threaded through PHI nodes. + + While our garbage collection mechanisms will handle this situation, it + is extremely wasteful to create nodes and throw them away, especially + when the nodes can be reused. + + For PR 8361, we can significantly reduce the number of nodes allocated + and thus the total amount of memory allocated by managing PHIs a + little. This additionally helps reduce the amount of work done by the + garbage collector. Similar results have been seen on a wider variety + of tests (such as the compiler itself). + + Right now we maintain our free list on a per-function basis. It may + or may not make sense to maintain the free list for the duration of + a compilation unit. + + We could also use a zone allocator for these objects since they have + a very well defined lifetime. If someone wants to experiment with that + this is the place to try it. + + PHI nodes have different sizes, so we can't have a single list of all + the PHI nodes as it would be too expensive to walk down that list to + find a PHI of a suitable size. + + Instead we have an array of lists of free PHI nodes. The array is + indexed by the number of PHI alternatives that PHI node can hold. + Except for the last array member, which holds all remaining PHI + nodes. + + So to find a free PHI node, we compute its index into the free PHI + node array and see if there are any elements with an exact match. + If so, then we are done. Otherwise, we test the next larger size + up and continue until we are in the last array element. + + We do not actually walk members of the last array element. While it + might allow us to pick up a few reusable PHI nodes, it could potentially + be very expensive if the program has released a bunch of large PHI nodes, + but keeps asking for even larger PHI nodes. Experiments have shown that + walking the elements of the last array entry would result in finding less + than .1% additional reusable PHI nodes. + + Note that we can never have less than two PHI argument slots. Thus, + the -2 on all the calculations below. */ + +#define NUM_BUCKETS 10 +static GTY ((deletable (""))) tree free_phinodes[NUM_BUCKETS - 2]; +static unsigned long free_phinode_count; + +static int ideal_phi_node_len (int); +static void resize_phi_node (tree *, int); + +#ifdef GATHER_STATISTICS +unsigned int phi_nodes_reused; +unsigned int phi_nodes_created; +#endif + +/* Initialize management of PHIs. */ + +void +init_phinodes (void) +{ + int i; + + for (i = 0; i < NUM_BUCKETS - 2; i++) + free_phinodes[i] = NULL; + free_phinode_count = 0; +} + +/* Finalize management of PHIs. */ + +void +fini_phinodes (void) +{ + int i; + + for (i = 0; i < NUM_BUCKETS - 2; i++) + free_phinodes[i] = NULL; + free_phinode_count = 0; +} + +/* Dump some simple statistics regarding the re-use of PHI nodes. */ + +#ifdef GATHER_STATISTICS +void +phinodes_print_statistics (void) +{ + fprintf (stderr, "PHI nodes allocated: %u\n", phi_nodes_created); + fprintf (stderr, "PHI nodes reused: %u\n", phi_nodes_reused); +} +#endif + +/* Given LEN, the original number of requested PHI arguments, return + a new, "ideal" length for the PHI node. The "ideal" length rounds + the total size of the PHI node up to the next power of two bytes. + + Rounding up will not result in wasting any memory since the size request + will be rounded up by the GC system anyway. [ Note this is not entirely + true since the original length might have fit on one of the special + GC pages. ] By rounding up, we may avoid the need to reallocate the + PHI node later if we increase the number of arguments for the PHI. */ + +static int +ideal_phi_node_len (int len) +{ + size_t size, new_size; + int log2, new_len; + + /* We do not support allocations of less than two PHI argument slots. */ + if (len < 2) + len = 2; + + /* Compute the number of bytes of the original request. */ + size = sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d); + + /* Round it up to the next power of two. */ + log2 = ceil_log2 (size); + new_size = 1 << log2; + + /* Now compute and return the number of PHI argument slots given an + ideal size allocation. */ + new_len = len + (new_size - size) / sizeof (struct phi_arg_d); + return new_len; +} + +/* Return a PHI node for variable VAR defined in statement STMT. + STMT may be an empty statement for artificial references (e.g., default + definitions created when a variable is used without a preceding + definition). */ + +tree +make_phi_node (tree var, int len) +{ + tree phi; + int size; + int bucket = NUM_BUCKETS - 2; + + len = ideal_phi_node_len (len); + + size = sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d); + + if (free_phinode_count) + for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++) + if (free_phinodes[bucket]) + break; + + /* If our free list has an element, then use it. */ + if (bucket < NUM_BUCKETS - 2 + && PHI_ARG_CAPACITY (free_phinodes[bucket]) >= len) + { + free_phinode_count--; + phi = free_phinodes[bucket]; + free_phinodes[bucket] = TREE_CHAIN (free_phinodes[bucket]); +#ifdef GATHER_STATISTICS + phi_nodes_reused++; +#endif + } + else + { + phi = ggc_alloc (size); +#ifdef GATHER_STATISTICS + phi_nodes_created++; + tree_node_counts[(int) phi_kind]++; + tree_node_sizes[(int) phi_kind] += size; +#endif + + } + + memset (phi, 0, size); + TREE_SET_CODE (phi, PHI_NODE); + PHI_ARG_CAPACITY (phi) = len; + if (TREE_CODE (var) == SSA_NAME) + PHI_RESULT (phi) = var; + else + PHI_RESULT (phi) = make_ssa_name (var, phi); + + return phi; +} + +/* We no longer need PHI, release it so that it may be reused. */ + +void +release_phi_node (tree phi) +{ + int bucket; + int len = PHI_ARG_CAPACITY (phi); + + bucket = len > NUM_BUCKETS - 1 ? NUM_BUCKETS - 1 : len; + bucket -= 2; + TREE_CHAIN (phi) = free_phinodes[bucket]; + free_phinodes[bucket] = phi; + free_phinode_count++; +} + +/* Resize an existing PHI node. The only way is up. Return the + possibly relocated phi. */ + +static void +resize_phi_node (tree *phi, int len) +{ + int size, old_size; + tree new_phi; + int i, old_len, bucket = NUM_BUCKETS - 2; + +#ifdef ENABLE_CHECKING + if (len < PHI_ARG_CAPACITY (*phi)) + abort (); +#endif + + /* Note that OLD_SIZE is guaranteed to be smaller than SIZE. */ + old_size = (sizeof (struct tree_phi_node) + + (PHI_ARG_CAPACITY (*phi) - 1) * sizeof (struct phi_arg_d)); + size = sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d); + + if (free_phinode_count) + for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++) + if (free_phinodes[bucket]) + break; + + /* If our free list has an element, then use it. */ + if (bucket < NUM_BUCKETS - 2 + && PHI_ARG_CAPACITY (free_phinodes[bucket]) >= len) + { + free_phinode_count--; + new_phi = free_phinodes[bucket]; + free_phinodes[bucket] = TREE_CHAIN (free_phinodes[bucket]); +#ifdef GATHER_STATISTICS + phi_nodes_reused++; +#endif + } + else + { + new_phi = ggc_alloc (size); +#ifdef GATHER_STATISTICS + phi_nodes_created++; + tree_node_counts[(int) phi_kind]++; + tree_node_sizes[(int) phi_kind] += size; +#endif + } + + memcpy (new_phi, *phi, old_size); + + old_len = PHI_ARG_CAPACITY (new_phi); + PHI_ARG_CAPACITY (new_phi) = len; + + for (i = old_len; i < len; i++) + { + PHI_ARG_DEF (new_phi, i) = NULL_TREE; + PHI_ARG_EDGE (new_phi, i) = NULL; + } + + *phi = new_phi; +} + +/* Create a new PHI node for variable VAR at basic block BB. */ + +tree +create_phi_node (tree var, basic_block bb) +{ + tree phi; + + phi = make_phi_node (var, bb_ann (bb)->num_preds); + + /* This is a new phi node, so note that is has not yet been + rewritten. */ + PHI_REWRITTEN (phi) = 0; + + /* Add the new PHI node to the list of PHI nodes for block BB. */ + TREE_CHAIN (phi) = phi_nodes (bb); + bb_ann (bb)->phi_nodes = phi; + + /* Associate BB to the PHI node. */ + set_bb_for_stmt (phi, bb); + + return phi; +} + +/* Add a new argument to PHI node PHI. DEF is the incoming reaching + definition and E is the edge through which DEF reaches PHI. The new + argument is added at the end of the argument list. + If PHI has reached its maximum capacity, add a few slots. In this case, + PHI points to the reallocated phi node when we return. */ + +void +add_phi_arg (tree *phi, tree def, edge e) +{ + int i = PHI_NUM_ARGS (*phi); + + if (i >= PHI_ARG_CAPACITY (*phi)) + { + tree old_phi = *phi; + + /* Resize the phi. Unfortunately, this may also relocate it. */ + resize_phi_node (phi, ideal_phi_node_len (i + 4)); + + /* The result of the phi is defined by this phi node. */ + SSA_NAME_DEF_STMT (PHI_RESULT (*phi)) = *phi; + + /* If the PHI was relocated, update the PHI chains appropriately and + release the old PHI node. */ + if (*phi != old_phi) + { + release_phi_node (old_phi); + + /* Update the list head if replacing the first listed phi. */ + if (phi_nodes (e->dest) == old_phi) + bb_ann (e->dest)->phi_nodes = *phi; + else + { + /* Traverse the list looking for the phi node to chain to. */ + tree p; + + for (p = phi_nodes (e->dest); + p && TREE_CHAIN (p) != old_phi; + p = TREE_CHAIN (p)) + ; + + if (!p) + abort (); + + TREE_CHAIN (p) = *phi; + } + } + } + + /* Copy propagation needs to know what object occur in abnormal + PHI nodes. This is a convenient place to record such information. */ + if (e->flags & EDGE_ABNORMAL) + { + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def) = 1; + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (*phi)) = 1; + } + + PHI_ARG_DEF (*phi, i) = def; + PHI_ARG_EDGE (*phi, i) = e; + PHI_NUM_ARGS (*phi)++; +} + +/* Remove a PHI argument from PHI. BLOCK is the predecessor block where + the PHI argument is coming from. */ + +void +remove_phi_arg (tree phi, basic_block block) +{ + int i, num_elem = PHI_NUM_ARGS (phi); + + for (i = 0; i < num_elem; i++) + { + basic_block src_bb; + + src_bb = PHI_ARG_EDGE (phi, i)->src; + + if (src_bb == block) + { + remove_phi_arg_num (phi, i); + return; + } + } +} + + +/* Remove the Ith argument from PHI's argument list. This routine assumes + ordering of alternatives in the vector is not important and implements + removal by swapping the last alternative with the alternative we want to + delete, then shrinking the vector. */ + +void +remove_phi_arg_num (tree phi, int i) +{ + int num_elem = PHI_NUM_ARGS (phi); + + /* If we are not at the last element, switch the last element + with the element we want to delete. */ + if (i != num_elem - 1) + { + PHI_ARG_DEF (phi, i) = PHI_ARG_DEF (phi, num_elem - 1); + PHI_ARG_EDGE (phi, i) = PHI_ARG_EDGE (phi, num_elem - 1); + } + + /* Shrink the vector and return. */ + PHI_ARG_DEF (phi, num_elem - 1) = NULL_TREE; + PHI_ARG_EDGE (phi, num_elem - 1) = NULL; + PHI_NUM_ARGS (phi)--; + + /* If we removed the last PHI argument, then go ahead and + remove the PHI node. */ + if (PHI_NUM_ARGS (phi) == 0) + remove_phi_node (phi, NULL, bb_for_stmt (phi)); +} + +/* Remove PHI node PHI from basic block BB. If PREV is non-NULL, it is + used as the node immediately before PHI in the linked list. */ + +void +remove_phi_node (tree phi, tree prev, basic_block bb) +{ + if (prev) + { + /* Rewire the list if we are given a PREV pointer. */ + TREE_CHAIN (prev) = TREE_CHAIN (phi); + + /* If we are deleting the PHI node, then we should release the + SSA_NAME node so that it can be reused. */ + release_ssa_name (PHI_RESULT (phi)); + release_phi_node (phi); + } + else if (phi == phi_nodes (bb)) + { + /* Update the list head if removing the first element. */ + bb_ann (bb)->phi_nodes = TREE_CHAIN (phi); + + /* If we are deleting the PHI node, then we should release the + SSA_NAME node so that it can be reused. */ + release_ssa_name (PHI_RESULT (phi)); + release_phi_node (phi); + } + else + { + /* Traverse the list looking for the node to remove. */ + tree prev, t; + prev = NULL_TREE; + for (t = phi_nodes (bb); t && t != phi; t = TREE_CHAIN (t)) + prev = t; + if (t) + remove_phi_node (t, prev, bb); + } +} + + +/* Remove all the PHI nodes for variables in the VARS bitmap. */ + +void +remove_all_phi_nodes_for (bitmap vars) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + /* Build a new PHI list for BB without variables in VARS. */ + tree phi, new_phi_list, last_phi, next; + + last_phi = new_phi_list = NULL_TREE; + for (phi = phi_nodes (bb), next = NULL; phi; phi = next) + { + tree var = SSA_NAME_VAR (PHI_RESULT (phi)); + + next = TREE_CHAIN (phi); + /* Only add PHI nodes for variables not in VARS. */ + if (!bitmap_bit_p (vars, var_ann (var)->uid)) + { + /* If we're not removing this PHI node, then it must have + been rewritten by a previous call into the SSA rewriter. + Note that fact in PHI_REWRITTEN. */ + PHI_REWRITTEN (phi) = 1; + + if (new_phi_list == NULL_TREE) + new_phi_list = last_phi = phi; + else + { + TREE_CHAIN (last_phi) = phi; + last_phi = phi; + } + } + else + { + /* If we are deleting the PHI node, then we should release the + SSA_NAME node so that it can be reused. */ + release_ssa_name (PHI_RESULT (phi)); + release_phi_node (phi); + } + } + + /* Make sure the last node in the new list has no successors. */ + if (last_phi) + TREE_CHAIN (last_phi) = NULL_TREE; + bb_ann (bb)->phi_nodes = new_phi_list; + +#if defined ENABLE_CHECKING + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree var = SSA_NAME_VAR (PHI_RESULT (phi)); + if (bitmap_bit_p (vars, var_ann (var)->uid)) + abort (); + } +#endif + } +} + + +#include "gt-tree-phinodes.h" + diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c new file mode 100644 index 00000000000..7eea529f063 --- /dev/null +++ b/gcc/tree-pretty-print.c @@ -0,0 +1,2267 @@ +/* Pretty formatting of GENERIC trees in C syntax. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + Adapted from c-pretty-print.c by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "tree.h" +#include "diagnostic.h" +#include "real.h" +#include "hashtab.h" +#include "tree-flow.h" +#include "langhooks.h" +#include "tree-iterator.h" + +/* Local functions, macros and variables. */ +static int op_prio (tree); +static const char *op_symbol (tree); +static void pretty_print_string (pretty_printer *, const char*); +static void print_call_name (pretty_printer *, tree); +static void newline_and_indent (pretty_printer *, int); +static void maybe_init_pretty_print (FILE *); +static void print_declaration (pretty_printer *, tree, int, int); +static void print_struct_decl (pretty_printer *, tree, int, int); +static void do_niy (pretty_printer *, tree); +static void dump_vops (pretty_printer *, tree, int, int); +static void dump_generic_bb_buff (pretty_printer *, basic_block, int, int); + +#define INDENT(SPACE) do { \ + int i; for (i = 0; i>>\n"); +} + +void +debug_generic_expr (tree t) +{ + print_generic_expr (stderr, t, TDF_VOPS|TDF_UID); + fprintf (stderr, "\n"); +} + +void +debug_generic_stmt (tree t) +{ + print_generic_stmt (stderr, t, TDF_VOPS|TDF_UID); + fprintf (stderr, "\n"); +} + +/* Prints declaration DECL to the FILE with details specified by FLAGS. */ +void +print_generic_decl (FILE *file, tree decl, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = true; + print_declaration (&buffer, decl, 2, flags); + pp_write_text_to_stream (&buffer); +} + +/* Print tree T, and its successors, on file FILE. FLAGS specifies details + to show in the dump. See TDF_* in tree.h. */ + +void +print_generic_stmt (FILE *file, tree t, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = true; + dump_generic_node (&buffer, t, 0, flags, true); + pp_flush (&buffer); +} + +/* Print tree T, and its successors, on file FILE. FLAGS specifies details + to show in the dump. See TDF_* in tree.h. The output is indented by + INDENT spaces. */ + +void +print_generic_stmt_indented (FILE *file, tree t, int flags, int indent) +{ + int i; + + maybe_init_pretty_print (file); + dumping_stmts = true; + + for (i = 0; i < indent; i++) + pp_space (&buffer); + dump_generic_node (&buffer, t, indent, flags, true); + pp_flush (&buffer); +} + +/* Print a single expression T on file FILE. FLAGS specifies details to show + in the dump. See TDF_* in tree.h. */ + +void +print_generic_expr (FILE *file, tree t, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = false; + dump_generic_node (&buffer, t, 0, flags, false); +} + +/* Dump the name of a _DECL node and its DECL_UID if TDF_UID is set + in FLAGS. */ + +static void +dump_decl_name (pretty_printer *buffer, tree node, int flags) +{ + if (DECL_NAME (node)) + pp_tree_identifier (buffer, DECL_NAME (node)); + + if ((flags & TDF_UID) + || DECL_NAME (node) == NULL_TREE) + { + if (TREE_CODE (node) == LABEL_DECL + && LABEL_DECL_UID (node) != -1) + pp_printf (buffer, "", + LABEL_DECL_UID (node)); + else + pp_printf (buffer, "", DECL_UID (node)); + } +} + +/* Dump the node NODE on the pretty_printer BUFFER, SPC spaces of indent. + FLAGS specifies details to show in the dump (see TDF_* in tree.h). If + IS_STMT is true, the object printed is considered to be a statement + and it is terminated by ';' if appropriate. */ + +int +dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, + bool is_stmt) +{ + tree type; + tree op0, op1; + const char* str; + bool is_expr; + + if (node == NULL_TREE) + return spc; + + is_expr = EXPR_P (node); + + if (TREE_CODE (node) != ERROR_MARK + && is_gimple_stmt (node) + && (flags & TDF_VOPS) + && stmt_ann (node)) + dump_vops (buffer, node, spc, flags); + + if (dumping_stmts + && (flags & TDF_LINENO) + && EXPR_HAS_LOCATION (node)) + { + pp_character (buffer, '['); + if (EXPR_FILENAME (node)) + { + pp_string (buffer, EXPR_FILENAME (node)); + pp_string (buffer, " : "); + } + pp_decimal_int (buffer, EXPR_LINENO (node)); + pp_string (buffer, "] "); + } + + switch (TREE_CODE (node)) + { + case ERROR_MARK: + pp_string (buffer, "<<< error >>>"); + break; + + case IDENTIFIER_NODE: + pp_tree_identifier (buffer, node); + break; + + case TREE_LIST: + while (node && node != error_mark_node) + { + if (TREE_PURPOSE (node)) + { + dump_generic_node (buffer, TREE_PURPOSE (node), spc, flags, false); + pp_space (buffer); + } + dump_generic_node (buffer, TREE_VALUE (node), spc, flags, false); + node = TREE_CHAIN (node); + if (node && TREE_CODE (node) == TREE_LIST) + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + break; + + case TREE_VEC: + dump_generic_node (buffer, BINFO_TYPE (node), spc, flags, false); + break; + + case BLOCK: + NIY; + break; + + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case VECTOR_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + { + unsigned int quals = TYPE_QUALS (node); + char class; + + if (quals & TYPE_QUAL_CONST) + pp_string (buffer, "const "); + else if (quals & TYPE_QUAL_VOLATILE) + pp_string (buffer, "volatile "); + else if (quals & TYPE_QUAL_RESTRICT) + pp_string (buffer, "restrict "); + + class = TREE_CODE_CLASS (TREE_CODE (node)); + + if (class == 'd') + { + if (DECL_NAME (node)) + dump_decl_name (buffer, node, flags); + else + pp_string (buffer, ""); + } + else if (class == 't') + { + if (TYPE_NAME (node)) + { + if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) + pp_tree_identifier (buffer, TYPE_NAME (node)); + else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (node))) + dump_decl_name (buffer, TYPE_NAME (node), flags); + else + pp_string (buffer, ""); + } + else + pp_string (buffer, ""); + } + break; + } + + case POINTER_TYPE: + case REFERENCE_TYPE: + str = (TREE_CODE (node) == POINTER_TYPE ? "*" : "&"); + + if (TREE_CODE (TREE_TYPE (node)) == FUNCTION_TYPE) + { + tree fnode = TREE_TYPE (node); + dump_generic_node (buffer, TREE_TYPE (fnode), spc, flags, false); + pp_space (buffer); + pp_character (buffer, '('); + pp_string (buffer, str); + if (TYPE_NAME (node) && DECL_NAME (TYPE_NAME (node))) + dump_decl_name (buffer, TYPE_NAME (node), flags); + else + pp_printf (buffer, "", TYPE_UID (node)); + + pp_character (buffer, ')'); + pp_space (buffer); + pp_character (buffer, '('); + /* Print the argument types. The last element in the list is a + VOID_TYPE. The following avoid to print the last element. */ + { + tree tmp = TYPE_ARG_TYPES (fnode); + while (tmp && TREE_CHAIN (tmp) && tmp != error_mark_node) + { + dump_generic_node (buffer, TREE_VALUE (tmp), spc, flags, false); + tmp = TREE_CHAIN (tmp); + if (TREE_CHAIN (tmp) && TREE_CODE (TREE_CHAIN (tmp)) == TREE_LIST) + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + } + pp_character (buffer, ')'); + } + else + { + unsigned int quals = TYPE_QUALS (node); + + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + pp_space (buffer); + pp_string (buffer, str); + + if (quals & TYPE_QUAL_CONST) + pp_string (buffer, " const"); + else if (quals & TYPE_QUAL_VOLATILE) + pp_string (buffer, "volatile"); + else if (quals & TYPE_QUAL_RESTRICT) + pp_string (buffer, " restrict"); + } + break; + + case OFFSET_TYPE: + NIY; + break; + + case METHOD_TYPE: + dump_decl_name (buffer, TYPE_NAME (TYPE_METHOD_BASETYPE (node)), flags); + pp_string (buffer, "::"); + break; + + case FILE_TYPE: + NIY; + break; + + case ARRAY_TYPE: + { + tree tmp; + + /* Print the array type. */ + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + + /* Print the dimensions. */ + tmp = node; + while (tmp && TREE_CODE (tmp) == ARRAY_TYPE) + { + pp_character (buffer, '['); + if (TYPE_SIZE (tmp)) + { + tree size = TYPE_SIZE (tmp); + if (TREE_CODE (size) == INTEGER_CST) + pp_wide_integer (buffer, + TREE_INT_CST_LOW (TYPE_SIZE (tmp)) / + TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tmp)))); + else if (TREE_CODE (size) == MULT_EXPR) + dump_generic_node (buffer, TREE_OPERAND (size, 0), spc, flags, false); + /* else punt. */ + } + pp_character (buffer, ']'); + tmp = TREE_TYPE (tmp); + } + break; + } + + case SET_TYPE: + NIY; + break; + + case RECORD_TYPE: + case UNION_TYPE: + /* Print the name of the structure. */ + if (TREE_CODE (node) == RECORD_TYPE) + pp_string (buffer, "struct "); + else if (TREE_CODE (node) == UNION_TYPE) + pp_string (buffer, "union "); + + if (TYPE_NAME (node)) + dump_generic_node (buffer, TYPE_NAME (node), spc, flags, false); + else + print_struct_decl (buffer, node, spc, flags); + break; + + case QUAL_UNION_TYPE: + NIY; + break; + + + case LANG_TYPE: + NIY; + break; + + case INTEGER_CST: + if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE) + { + /* In the case of a pointer, one may want to divide by the + size of the pointed-to type. Unfortunately, this not + straightforward. The C front-end maps expressions + + (int *) 5 + int *p; (p + 5) + + in such a way that the two INTEGER_CST nodes for "5" have + different values but identical types. In the latter + case, the 5 is multiplied by sizeof (int) in c-common.c + (pointer_int_sum) to convert it to a byte address, and + yet the type of the node is left unchanged. Argh. What + is consistent though is that the number value corresponds + to bytes (UNITS) offset. + + NB: Neither of the following divisors can be trivially + used to recover the original literal: + + TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (node))) + TYPE_PRECISION (TREE_TYPE (TREE_TYPE (node))) */ + pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); + pp_string (buffer, "B"); /* pseudo-unit */ + } + else if (! host_integerp (node, 0)) + { + tree val = node; + + if (tree_int_cst_sgn (val) < 0) + { + pp_character (buffer, '-'); + val = build_int_2 (-TREE_INT_CST_LOW (val), + ~TREE_INT_CST_HIGH (val) + + !TREE_INT_CST_LOW (val)); + } + /* Would "%x%0*x" or "%x%*0x" get zero-padding on all + systems? */ + { + static char format[10]; /* "%x%09999x\0" */ + if (!format[0]) + sprintf (format, "%%x%%0%dx", HOST_BITS_PER_INT / 4); + sprintf (pp_buffer (buffer)->digit_buffer, format, + TREE_INT_CST_HIGH (val), + TREE_INT_CST_LOW (val)); + pp_string (buffer, pp_buffer (buffer)->digit_buffer); + } + } + else + pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); + break; + + case REAL_CST: + /* Code copied from print_node. */ + { + REAL_VALUE_TYPE d; + if (TREE_OVERFLOW (node)) + pp_string (buffer, " overflow"); + +#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC) + d = TREE_REAL_CST (node); + if (REAL_VALUE_ISINF (d)) + pp_string (buffer, " Inf"); + else if (REAL_VALUE_ISNAN (d)) + pp_string (buffer, " Nan"); + else + { + char string[100]; + real_to_decimal (string, &d, sizeof (string), 0, 1); + pp_string (buffer, string); + } +#else + { + HOST_WIDE_INT i; + unsigned char *p = (unsigned char *) &TREE_REAL_CST (node); + pp_string (buffer, "0x"); + for (i = 0; i < sizeof TREE_REAL_CST (node); i++) + output_formatted_integer (buffer, "%02x", *p++); + } +#endif + break; + } + + case COMPLEX_CST: + pp_string (buffer, "__complex__ ("); + dump_generic_node (buffer, TREE_REALPART (node), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_IMAGPART (node), spc, flags, false); + pp_string (buffer, ")"); + break; + + case STRING_CST: + pp_string (buffer, "\""); + pretty_print_string (buffer, TREE_STRING_POINTER (node)); + pp_string (buffer, "\""); + break; + + case VECTOR_CST: + { + tree elt; + pp_string (buffer, "{ "); + for (elt = TREE_VECTOR_CST_ELTS (node); elt; elt = TREE_CHAIN (elt)) + { + dump_generic_node (buffer, TREE_VALUE (elt), spc, flags, false); + if (TREE_CHAIN (elt)) + pp_string (buffer, ", "); + } + pp_string (buffer, " }"); + } + break; + + case FUNCTION_TYPE: + break; + + case FUNCTION_DECL: + case CONST_DECL: + dump_decl_name (buffer, node, flags); + break; + + case LABEL_DECL: + if (DECL_NAME (node)) + dump_decl_name (buffer, node, flags); + else if (LABEL_DECL_UID (node) != -1) + pp_printf (buffer, "", + LABEL_DECL_UID (node)); + else + pp_printf (buffer, "", DECL_UID (node)); + break; + + case TYPE_DECL: + if (strcmp (DECL_SOURCE_FILE (node), "") == 0) + { + /* Don't print the declaration of built-in types. */ + break; + } + if (DECL_NAME (node)) + { + dump_decl_name (buffer, node, flags); + } + else + { + if (TYPE_METHODS (TREE_TYPE (node))) + { + /* The type is a c++ class: all structures have at least + 4 methods. */ + pp_string (buffer, "class "); + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + } + else + { + pp_string (buffer, "struct "); + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + pp_character (buffer, ';'); + pp_newline (buffer); + } + } + break; + + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case NAMESPACE_DECL: + dump_decl_name (buffer, node, flags); + break; + + case RESULT_DECL: + pp_string (buffer, ""); + break; + + case COMPONENT_REF: + op0 = TREE_OPERAND (node, 0); + str = "."; + if (TREE_CODE (op0) == INDIRECT_REF) + { + op0 = TREE_OPERAND (op0, 0); + str = "->"; + } + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, ')'); + pp_string (buffer, str); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + break; + + case BIT_FIELD_REF: + pp_string (buffer, "BIT_FIELD_REF <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); + pp_string (buffer, ">"); + break; + + case BUFFER_REF: + NIY; + break; + + case ARRAY_REF: + op0 = TREE_OPERAND (node, 0); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, ')'); + pp_character (buffer, '['); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, ']'); + break; + + case ARRAY_RANGE_REF: + NIY; + break; + + case CONSTRUCTOR: + { + tree lnode; + bool is_struct_init = FALSE; + pp_character (buffer, '{'); + lnode = CONSTRUCTOR_ELTS (node); + if (TREE_CODE (TREE_TYPE (node)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (node)) == UNION_TYPE) + is_struct_init = TRUE; + while (lnode && lnode != error_mark_node) + { + tree val; + if (TREE_PURPOSE (lnode) && is_struct_init) + { + pp_character (buffer, '.'); + dump_generic_node (buffer, TREE_PURPOSE (lnode), spc, flags, false); + pp_string (buffer, "="); + } + val = TREE_VALUE (lnode); + if (val && TREE_CODE (val) == ADDR_EXPR) + if (TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL) + val = TREE_OPERAND (val, 0); + if (val && TREE_CODE (val) == FUNCTION_DECL) + { + dump_decl_name (buffer, val, flags); + } + else + { + dump_generic_node (buffer, TREE_VALUE (lnode), spc, flags, false); + } + lnode = TREE_CHAIN (lnode); + if (lnode && TREE_CODE (lnode) == TREE_LIST) + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + pp_character (buffer, '}'); + } + break; + + case COMPOUND_EXPR: + { + tree *tp; + if (flags & TDF_SLIM) + { + pp_string (buffer, ""); + break; + } + + dump_generic_node (buffer, TREE_OPERAND (node, 0), + spc, flags, dumping_stmts); + if (dumping_stmts) + newline_and_indent (buffer, spc); + else + { + pp_character (buffer, ','); + pp_space (buffer); + } + + for (tp = &TREE_OPERAND (node, 1); + TREE_CODE (*tp) == COMPOUND_EXPR; + tp = &TREE_OPERAND (*tp, 1)) + { + dump_generic_node (buffer, TREE_OPERAND (*tp, 0), + spc, flags, dumping_stmts); + if (dumping_stmts) + newline_and_indent (buffer, spc); + else + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + + dump_generic_node (buffer, *tp, spc, flags, dumping_stmts); + } + break; + + case STATEMENT_LIST: + { + tree_stmt_iterator si; + bool first = true; + + if ((flags & TDF_SLIM) || !dumping_stmts) + { + pp_string (buffer, ""); + break; + } + + for (si = tsi_start (node); !tsi_end_p (si); tsi_next (&si)) + { + if (!first) + newline_and_indent (buffer, spc); + else + first = false; + dump_generic_node (buffer, tsi_stmt (si), spc, flags, true); + } + } + break; + + case MODIFY_EXPR: + case INIT_EXPR: + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_space (buffer); + pp_character (buffer, '='); + pp_space (buffer); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + break; + + case TARGET_EXPR: + dump_generic_node (buffer, TYPE_NAME (TREE_TYPE (node)), spc, flags, false); + pp_character (buffer, '('); + dump_generic_node (buffer, TARGET_EXPR_INITIAL (node), spc, flags, false); + pp_character (buffer, ')'); + break; + + case COND_EXPR: + if (TREE_TYPE (node) == void_type_node) + { + pp_string (buffer, "if ("); + dump_generic_node (buffer, COND_EXPR_COND (node), spc, flags, false); + pp_character (buffer, ')'); + /* The lowered cond_exprs should always be printed in full. */ + if (COND_EXPR_THEN (node) + && TREE_CODE (COND_EXPR_THEN (node)) == GOTO_EXPR + && COND_EXPR_ELSE (node) + && TREE_CODE (COND_EXPR_ELSE (node)) == GOTO_EXPR) + { + pp_space (buffer); + dump_generic_node (buffer, COND_EXPR_THEN (node), 0, flags, true); + pp_string (buffer, " else "); + dump_generic_node (buffer, COND_EXPR_ELSE (node), 0, flags, true); + } + else if (!(flags & TDF_SLIM)) + { + /* Output COND_EXPR_THEN. */ + if (COND_EXPR_THEN (node)) + { + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, COND_EXPR_THEN (node), spc+4, + flags, true); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + + /* Output COND_EXPR_ELSE. */ + if (COND_EXPR_ELSE (node)) + { + newline_and_indent (buffer, spc); + pp_string (buffer, "else"); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, COND_EXPR_ELSE (node), spc+4, + flags, true); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + } + is_expr = false; + } + else + { + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_space (buffer); + pp_character (buffer, '?'); + pp_space (buffer); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_space (buffer); + pp_character (buffer, ':'); + pp_space (buffer); + dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); + } + break; + + case BIND_EXPR: + pp_character (buffer, '{'); + if (!(flags & TDF_SLIM)) + { + if (BIND_EXPR_VARS (node)) + { + pp_newline (buffer); + + for (op0 = BIND_EXPR_VARS (node); op0; op0 = TREE_CHAIN (op0)) + { + print_declaration (buffer, op0, spc+2, flags); + pp_newline (buffer); + } + } + + newline_and_indent (buffer, spc+2); + dump_generic_node (buffer, BIND_EXPR_BODY (node), spc+2, flags, true); + newline_and_indent (buffer, spc); + pp_character (buffer, '}'); + } + is_expr = false; + break; + + case CALL_EXPR: + print_call_name (buffer, node); + + /* Print parameters. */ + pp_space (buffer); + pp_character (buffer, '('); + op1 = TREE_OPERAND (node, 1); + if (op1) + dump_generic_node (buffer, op1, spc, flags, false); + pp_character (buffer, ')'); + + op1 = TREE_OPERAND (node, 2); + if (op1) + { + pp_string (buffer, " [static-chain: "); + dump_generic_node (buffer, op1, spc, flags, false); + pp_character (buffer, ']'); + } + + if (CALL_EXPR_TAILCALL (node)) + pp_string (buffer, " [tail call]"); + break; + + case WITH_CLEANUP_EXPR: + NIY; + break; + + case CLEANUP_POINT_EXPR: + pp_string (buffer, "<>"); + break; + + case PLACEHOLDER_EXPR: + NIY; + break; + + /* Binary arithmetic and logic expressions. */ + case MULT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + { + const char *op = op_symbol (node); + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + /* When the operands are expressions with less priority, + keep semantics of the tree representation. */ + if (op_prio (op0) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, op0, spc, flags, false); + + pp_space (buffer); + pp_string (buffer, op); + pp_space (buffer); + + /* When the operands are expressions with less priority, + keep semantics of the tree representation. */ + if (op_prio (op1) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, op1, spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, op1, spc, flags, false); + } + break; + + /* Unary arithmetic and logic expressions. */ + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case ADDR_EXPR: + case REFERENCE_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case INDIRECT_REF: + if (TREE_CODE (node) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (node, 0)) == STRING_CST + || TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL)) + ; /* Do not output '&' for strings and function pointers. */ + else + pp_string (buffer, op_symbol (node)); + + if (op_prio (TREE_OPERAND (node, 0)) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + break; + + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + if (op_prio (TREE_OPERAND (node, 0)) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, op_symbol (node)); + break; + + case MIN_EXPR: + pp_string (buffer, "MIN_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, '>'); + break; + + case MAX_EXPR: + pp_string (buffer, "MAX_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, '>'); + break; + + case ABS_EXPR: + pp_string (buffer, "ABS_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case UNORDERED_EXPR: + NIY; + break; + + case ORDERED_EXPR: + NIY; + break; + + case IN_EXPR: + NIY; + break; + + case SET_LE_EXPR: + NIY; + break; + + case CARD_EXPR: + NIY; + break; + + case RANGE_EXPR: + NIY; + break; + + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FLOAT_EXPR: + case CONVERT_EXPR: + case NOP_EXPR: + type = TREE_TYPE (node); + op0 = TREE_OPERAND (node, 0); + if (type != TREE_TYPE (op0)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, type, spc, flags, false); + pp_string (buffer, ")"); + } + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, ')'); + break; + + case VIEW_CONVERT_EXPR: + pp_string (buffer, "VIEW_CONVERT_EXPR<"); + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + pp_string (buffer, ">("); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, ')'); + break; + + case NON_LVALUE_EXPR: + pp_string (buffer, "NON_LVALUE_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case SAVE_EXPR: + pp_string (buffer, "SAVE_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case UNSAVE_EXPR: + pp_string (buffer, "UNSAVE_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case RTL_EXPR: + NIY; + break; + + case ENTRY_VALUE_EXPR: + NIY; + break; + + case COMPLEX_EXPR: + pp_string (buffer, "COMPLEX_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_string (buffer, ">"); + break; + + case CONJ_EXPR: + pp_string (buffer, "CONJ_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case REALPART_EXPR: + pp_string (buffer, "REALPART_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case IMAGPART_EXPR: + pp_string (buffer, "IMAGPART_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case VA_ARG_EXPR: + pp_string (buffer, "VA_ARG_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + pp_string (buffer, "try"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + newline_and_indent (buffer, spc); + pp_string (buffer, + (TREE_CODE (node) == TRY_CATCH_EXPR) ? "catch" : "finally"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + is_expr = false; + break; + + case CATCH_EXPR: + pp_string (buffer, "catch ("); + dump_generic_node (buffer, CATCH_TYPES (node), spc+2, flags, false); + pp_string (buffer, ")"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, CATCH_BODY (node), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + is_expr = false; + break; + + case EH_FILTER_EXPR: + pp_string (buffer, "<<>>"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, EH_FILTER_FAILURE (node), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + is_expr = false; + break; + + case GOTO_SUBROUTINE_EXPR: + NIY; + break; + + case LABEL_EXPR: + op0 = TREE_OPERAND (node, 0); + /* If this is for break or continue, don't bother printing it. */ + if (DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + break; + } + dump_generic_node (buffer, op0, spc, flags, false); + pp_character (buffer, ':'); + if (DECL_NONLOCAL (op0)) + pp_string (buffer, " [non-local]"); + break; + + case LABELED_BLOCK_EXPR: + op0 = LABELED_BLOCK_LABEL (node); + /* If this is for break or continue, don't bother printing it. */ + if (DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + { + dump_generic_node (buffer, LABELED_BLOCK_BODY (node), spc, flags, false); + break; + } + } + dump_generic_node (buffer, LABELED_BLOCK_LABEL (node), spc, flags, false); + pp_string (buffer, ": {"); + if (!(flags & TDF_SLIM)) + newline_and_indent (buffer, spc+2); + dump_generic_node (buffer, LABELED_BLOCK_BODY (node), spc+2, flags, true); + if (!flags) + newline_and_indent (buffer, spc); + pp_character (buffer, '}'); + is_expr = false; + break; + + case EXIT_BLOCK_EXPR: + op0 = LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (node)); + /* If this is for a break or continue, print it accordingly. */ + if (DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + { + pp_string (buffer, name); + break; + } + } + pp_string (buffer, "<<>>"); + break; + + case EXC_PTR_EXPR: + pp_string (buffer, "<<>>"); + break; + + case FILTER_EXPR: + pp_string (buffer, "<<>>"); + break; + + case LOOP_EXPR: + pp_string (buffer, "while (1)"); + if (!(flags & TDF_SLIM)) + { + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, LOOP_EXPR_BODY (node), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + is_expr = false; + break; + + case RETURN_EXPR: + pp_string (buffer, "return"); + op0 = TREE_OPERAND (node, 0); + if (op0) + { + pp_space (buffer); + if (TREE_CODE (op0) == MODIFY_EXPR) + dump_generic_node (buffer, TREE_OPERAND (op0, 1), spc, flags, false); + else + dump_generic_node (buffer, op0, spc, flags, false); + } + break; + + case EXIT_EXPR: + pp_string (buffer, "if ("); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ") break"); + break; + + case SWITCH_EXPR: + pp_string (buffer, "switch ("); + dump_generic_node (buffer, SWITCH_COND (node), spc, flags, false); + pp_character (buffer, ')'); + if (!(flags & TDF_SLIM)) + { + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + if (SWITCH_BODY (node)) + { + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, SWITCH_BODY (node), spc+4, flags, true); + } + else + { + tree vec = SWITCH_LABELS (node); + size_t i, n = TREE_VEC_LENGTH (vec); + for (i = 0; i < n; ++i) + { + tree elt = TREE_VEC_ELT (vec, i); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, elt, spc+4, flags, false); + pp_string (buffer, " goto "); + dump_generic_node (buffer, CASE_LABEL (elt), spc+4, flags, true); + pp_semicolon (buffer); + } + } + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + is_expr = false; + break; + + case GOTO_EXPR: + op0 = GOTO_DESTINATION (node); + if (TREE_CODE (op0) != SSA_NAME + && DECL_P (op0) + && DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + { + pp_string (buffer, name); + break; + } + } + pp_string (buffer, "goto "); + dump_generic_node (buffer, op0, spc, flags, false); + break; + + case RESX_EXPR: + pp_string (buffer, "resx"); + /* ??? Any sensible way to present the eh region? */ + break; + + case ASM_EXPR: + pp_string (buffer, "__asm__"); + if (ASM_VOLATILE_P (node)) + pp_string (buffer, " __volatile__"); + pp_character (buffer, '('); + dump_generic_node (buffer, ASM_STRING (node), spc, flags, false); + pp_character (buffer, ':'); + dump_generic_node (buffer, ASM_OUTPUTS (node), spc, flags, false); + pp_character (buffer, ':'); + dump_generic_node (buffer, ASM_INPUTS (node), spc, flags, false); + if (ASM_CLOBBERS (node)) + { + pp_character (buffer, ':'); + dump_generic_node (buffer, ASM_CLOBBERS (node), spc, flags, false); + } + pp_string (buffer, ")"); + break; + + case CASE_LABEL_EXPR: + if (CASE_LOW (node) && CASE_HIGH (node)) + { + pp_string (buffer, "case "); + dump_generic_node (buffer, CASE_LOW (node), spc, flags, false); + pp_string (buffer, " ... "); + dump_generic_node (buffer, CASE_HIGH (node), spc, flags, false); + } + else if (CASE_LOW (node)) + { + pp_string (buffer, "case "); + dump_generic_node (buffer, CASE_LOW (node), spc, flags, false); + } + else + pp_string (buffer, "default "); + pp_character (buffer, ':'); + break; + + case VTABLE_REF: + pp_string (buffer, "VTABLE_REF <("); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, "),"); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, ','); + dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); + pp_character (buffer, '>'); + break; + + case EPHI_NODE: + { + int i; + + pp_string (buffer, " EPHI ("); + dump_generic_node (buffer, EREF_NAME (node), spc, flags, false); + pp_string (buffer, ") "); + pp_character (buffer, '['); + pp_string (buffer, " class:"); + pp_decimal_int (buffer, EREF_CLASS (node)); + if (EPHI_DOWNSAFE (node)) + pp_string (buffer, " downsafe"); + if (EPHI_CANT_BE_AVAIL (node)) + pp_string (buffer, " cant_be_avail"); + if (EPHI_STOPS (node)) + pp_string (buffer, " stops"); + pp_string (buffer, " bb:"); + pp_decimal_int (buffer, bb_for_stmt (node)->index); + pp_character (buffer, ']'); + if (! (flags & TDF_SLIM)) + { + pp_string (buffer, " <"); + for (i = 0; i < EPHI_NUM_ARGS (node); i++) + { + if (EPHI_ARG_DEF (node, i)) + { + newline_and_indent (buffer, spc + 2); + pp_string (buffer, " edge "); + pp_decimal_int (buffer, EPHI_ARG_EDGE (node, i)->src->index); + pp_string (buffer, "->"); + pp_decimal_int (buffer, EPHI_ARG_EDGE (node, i)->dest->index); + pp_string (buffer, " [ "); + if (EPHI_ARG_HAS_REAL_USE (node, i)) + pp_string (buffer, " real use"); + if (EPHI_ARG_INJURED (node, i)) + pp_string (buffer, " injured"); + if (EPHI_ARG_STOPS (node, i)) + pp_string (buffer, " stops"); + pp_string (buffer, " ] "); + pp_string (buffer, " defined by:"); + dump_generic_node (buffer, EPHI_ARG_DEF (node, i), + spc + 4, flags | TDF_SLIM, false); + } + } + } + pp_string (buffer, " >"); + } + break; + case EEXIT_NODE: + case EKILL_NODE: + if (TREE_CODE (node) == EEXIT_NODE) + pp_string (buffer, "EEXIT ("); + else if (TREE_CODE (node) == EKILL_NODE) + pp_string (buffer, "EKILL ("); + dump_generic_node (buffer, EREF_NAME (node), spc, flags, false); + pp_string (buffer, ") "); + pp_character (buffer, '['); + pp_string (buffer, "class:"); + pp_decimal_int (buffer, EREF_CLASS (node)); + pp_string (buffer, " bb:"); + pp_decimal_int (buffer, bb_for_stmt (node)->index); + pp_character (buffer, ']'); + break; + case EUSE_NODE: + pp_string (buffer, " EUSE ("); + dump_generic_node (buffer, EREF_NAME (node), spc, flags, false); + + pp_string (buffer, ") "); + pp_character (buffer, '['); + pp_string (buffer, "class:"); + pp_decimal_int (buffer, EREF_CLASS (node)); + pp_string (buffer, " phiop:"); + pp_decimal_int (buffer, EUSE_PHIOP (node)); + pp_string (buffer, " bb:"); + pp_decimal_int (buffer, bb_for_stmt (node)->index); + if (EUSE_LVAL (node)) + pp_string (buffer, " left-occurrence"); + pp_string (buffer, " ]"); + + break; + case PHI_NODE: + { + int i; + + dump_generic_node (buffer, PHI_RESULT (node), spc, flags, false); + pp_string (buffer, " = PHI <"); + for (i = 0; i < PHI_NUM_ARGS (node); i++) + { + dump_generic_node (buffer, PHI_ARG_DEF (node, i), spc, flags, false); + pp_string (buffer, "("); + pp_decimal_int (buffer, PHI_ARG_EDGE (node, i)->src->index); + pp_string (buffer, ")"); + if (i < PHI_NUM_ARGS (node) - 1) + pp_string (buffer, ", "); + } + pp_string (buffer, ">;"); + } + break; + + case SSA_NAME: + dump_generic_node (buffer, SSA_NAME_VAR (node), spc, flags, false); + pp_string (buffer, "_"); + pp_decimal_int (buffer, SSA_NAME_VERSION (node)); + break; + + default: + NIY; + } + + if (is_stmt && is_expr) + pp_semicolon (buffer); + pp_write_text_to_stream (buffer); + + return spc; +} + +/* Print the declaration of a variable. */ + +static void +print_declaration (pretty_printer *buffer, tree t, int spc, int flags) +{ + /* Don't print type declarations. */ + if (TREE_CODE (t) == TYPE_DECL) + return; + + INDENT (spc); + + if (DECL_REGISTER (t)) + pp_string (buffer, "register "); + + if (TREE_PUBLIC (t) && DECL_EXTERNAL (t)) + pp_string (buffer, "extern "); + else if (TREE_STATIC (t)) + pp_string (buffer, "static "); + + /* Print the type and name. */ + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + { + tree tmp; + + /* Print array's type. */ + tmp = TREE_TYPE (t); + while (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) + tmp = TREE_TYPE (tmp); + dump_generic_node (buffer, TREE_TYPE (tmp), spc, flags, false); + + /* Print variable's name. */ + pp_space (buffer); + dump_generic_node (buffer, t, spc, flags, false); + + /* Print the dimensions. */ + tmp = TREE_TYPE (t); + while (TREE_CODE (tmp) == ARRAY_TYPE) + { + pp_character (buffer, '['); + if (TYPE_DOMAIN (tmp)) + { + if (TREE_CODE (TYPE_SIZE (tmp)) == INTEGER_CST) + pp_wide_integer (buffer, + TREE_INT_CST_LOW (TYPE_SIZE (tmp)) / + TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tmp)))); + else + dump_generic_node (buffer, TYPE_SIZE_UNIT (tmp), spc, flags, + false); + } + pp_character (buffer, ']'); + tmp = TREE_TYPE (tmp); + } + } + else + { + /* Print type declaration. */ + dump_generic_node (buffer, TREE_TYPE (t), spc, flags, false); + + /* Print variable's name. */ + pp_space (buffer); + dump_generic_node (buffer, t, spc, flags, false); + } + + /* The initial value of a function serves to determine wether the function + is declared or defined. So the following does not apply to function + nodes. */ + if (TREE_CODE (t) != FUNCTION_DECL) + { + /* Print the initial value. */ + if (DECL_INITIAL (t)) + { + pp_space (buffer); + pp_character (buffer, '='); + pp_space (buffer); + dump_generic_node (buffer, DECL_INITIAL (t), spc, flags, false); + } + } + + pp_character (buffer, ';'); +} + + +/* Prints a structure: name, fields, and methods. + FIXME: Still incomplete. */ + +static void +print_struct_decl (pretty_printer *buffer, tree node, int spc, int flags) +{ + /* Print the name of the structure. */ + if (TYPE_NAME (node)) + { + INDENT (spc); + if (TREE_CODE (node) == RECORD_TYPE) + pp_string (buffer, "struct "); + else if (TREE_CODE (node) == UNION_TYPE) + pp_string (buffer, "union "); + else + NIY; + dump_generic_node (buffer, TYPE_NAME (node), spc, 0, false); + } + + /* Print the contents of the structure. */ + pp_newline (buffer); + INDENT (spc); + pp_character (buffer, '{'); + pp_newline (buffer); + + /* Print the fields of the structure. */ + { + tree tmp; + tmp = TYPE_FIELDS (node); + while (tmp) + { + /* Avoid to print recursively the structure. */ + /* FIXME : Not implemented correctly..., + what about the case when we have a cycle in the contain graph? ... + Maybe this could be solved by looking at the scope in which the + structure was declared. */ + if (TREE_TYPE (tmp) != node + || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE && + TREE_TYPE (TREE_TYPE (tmp)) != node)) + { + print_declaration (buffer, tmp, spc+2, flags); + pp_newline (buffer); + } + else + { + + } + tmp = TREE_CHAIN (tmp); + } + } + INDENT (spc); + pp_character (buffer, '}'); +} + +/* Return the priority of the operator OP. + + From lowest to highest precedence with either left-to-right (L-R) + or right-to-left (R-L) associativity]: + + 1 [L-R] , + 2 [R-L] = += -= *= /= %= &= ^= |= <<= >>= + 3 [R-L] ?: + 4 [L-R] || + 5 [L-R] && + 6 [L-R] | + 7 [L-R] ^ + 8 [L-R] & + 9 [L-R] == != + 10 [L-R] < <= > >= + 11 [L-R] << >> + 12 [L-R] + - + 13 [L-R] * / % + 14 [R-L] ! ~ ++ -- + - * & (type) sizeof + 15 [L-R] fn() [] -> . + + unary +, - and * have higher precedence than the corresponding binary + operators. */ + +static int +op_prio (tree op) +{ + if (op == NULL) + return 9999; + + switch (TREE_CODE (op)) + { + case TREE_LIST: + case COMPOUND_EXPR: + case BIND_EXPR: + return 1; + + case MODIFY_EXPR: + case INIT_EXPR: + return 2; + + case COND_EXPR: + return 3; + + case TRUTH_OR_EXPR: + case TRUTH_ORIF_EXPR: + return 4; + + case TRUTH_AND_EXPR: + case TRUTH_ANDIF_EXPR: + return 5; + + case BIT_IOR_EXPR: + return 6; + + case BIT_XOR_EXPR: + case TRUTH_XOR_EXPR: + return 7; + + case BIT_AND_EXPR: + return 8; + + case EQ_EXPR: + case NE_EXPR: + return 9; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + return 10; + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + return 11; + + case PLUS_EXPR: + case MINUS_EXPR: + return 12; + + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + return 13; + + case TRUTH_NOT_EXPR: + case BIT_NOT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case NEGATE_EXPR: + case INDIRECT_REF: + case ADDR_EXPR: + case FLOAT_EXPR: + case NOP_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case TARGET_EXPR: + return 14; + + case CALL_EXPR: + case ARRAY_REF: + case COMPONENT_REF: + return 15; + + /* Special expressions. */ + case MIN_EXPR: + case MAX_EXPR: + case ABS_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + return 16; + + case SAVE_EXPR: + case NON_LVALUE_EXPR: + return op_prio (TREE_OPERAND (op, 0)); + + default: + /* Return an arbitrarily high precedence to avoid surrounding single + VAR_DECLs in ()s. */ + return 9999; + } +} + + +/* Return the symbol associated with operator OP. */ + +static const char * +op_symbol (tree op) +{ + if (op == NULL) + abort (); + + switch (TREE_CODE (op)) + { + case MODIFY_EXPR: + return "="; + + case TRUTH_OR_EXPR: + case TRUTH_ORIF_EXPR: + return "||"; + + case TRUTH_AND_EXPR: + case TRUTH_ANDIF_EXPR: + return "&&"; + + case BIT_IOR_EXPR: + return "|"; + + case TRUTH_XOR_EXPR: + case BIT_XOR_EXPR: + return "^"; + + case ADDR_EXPR: + case BIT_AND_EXPR: + return "&"; + + case EQ_EXPR: + case UNEQ_EXPR: + return "=="; + + case NE_EXPR: + return "!="; + + case LT_EXPR: + case UNLT_EXPR: + return "<"; + + case LE_EXPR: + case UNLE_EXPR: + return "<="; + + case GT_EXPR: + case UNGT_EXPR: + return ">"; + + case GE_EXPR: + case UNGE_EXPR: + return ">="; + + case LSHIFT_EXPR: + return "<<"; + + case RSHIFT_EXPR: + return ">>"; + + case PLUS_EXPR: + return "+"; + + case NEGATE_EXPR: + case MINUS_EXPR: + return "-"; + + case BIT_NOT_EXPR: + return "~"; + + case TRUTH_NOT_EXPR: + return "!"; + + case MULT_EXPR: + case INDIRECT_REF: + return "*"; + + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + return "/"; + + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + return "%"; + + case PREDECREMENT_EXPR: + return " --"; + + case PREINCREMENT_EXPR: + return " ++"; + + case POSTDECREMENT_EXPR: + return "-- "; + + case POSTINCREMENT_EXPR: + return "++ "; + + case REFERENCE_EXPR: + return ""; + + default: + return "<<< ??? >>>"; + } +} + +/* Prints the name of a CALL_EXPR. */ + +static void +print_call_name (pretty_printer *buffer, tree node) +{ + tree op0; + + if (TREE_CODE (node) != CALL_EXPR) + abort (); + + op0 = TREE_OPERAND (node, 0); + + if (TREE_CODE (op0) == NON_LVALUE_EXPR) + op0 = TREE_OPERAND (op0, 0); + + switch (TREE_CODE (op0)) + { + case VAR_DECL: + case PARM_DECL: + PRINT_FUNCTION_NAME (op0); + break; + + case ADDR_EXPR: + case INDIRECT_REF: + case NOP_EXPR: + dump_generic_node (buffer, TREE_OPERAND (op0, 0), 0, 0, false); + break; + + case COND_EXPR: + pp_string (buffer, "("); + dump_generic_node (buffer, TREE_OPERAND (op0, 0), 0, 0, false); + pp_string (buffer, ") ? "); + dump_generic_node (buffer, TREE_OPERAND (op0, 1), 0, 0, false); + pp_string (buffer, " : "); + dump_generic_node (buffer, TREE_OPERAND (op0, 2), 0, 0, false); + break; + + case COMPONENT_REF: + /* The function is a pointer contained in a structure. */ + if (TREE_CODE (TREE_OPERAND (op0, 0)) == INDIRECT_REF || + TREE_CODE (TREE_OPERAND (op0, 0)) == VAR_DECL) + PRINT_FUNCTION_NAME (TREE_OPERAND (op0, 1)); + else + dump_generic_node (buffer, TREE_OPERAND (op0, 0), 0, 0, false); + /* else + We can have several levels of structures and a function + pointer inside. This is not implemented yet... */ + /* NIY;*/ + break; + + case ARRAY_REF: + if (TREE_CODE (TREE_OPERAND (op0, 0)) == VAR_DECL) + PRINT_FUNCTION_NAME (TREE_OPERAND (op0, 0)); + else + dump_generic_node (buffer, op0, 0, 0, false); + break; + + case SSA_NAME: + dump_generic_node (buffer, op0, 0, 0, false); + break; + + default: + NIY; + } +} + +/* Parses the string STR and replaces new-lines by '\n', tabs by '\t', ... */ + +static void +pretty_print_string (pretty_printer *buffer, const char *str) +{ + if (str == NULL) + return; + + while (*str) + { + switch (str[0]) + { + case '\b': + pp_string (buffer, "\\b"); + break; + + case '\f': + pp_string (buffer, "\\f"); + break; + + case '\n': + pp_string (buffer, "\\n"); + break; + + case '\r': + pp_string (buffer, "\\r"); + break; + + case '\t': + pp_string (buffer, "\\t"); + break; + + case '\v': + pp_string (buffer, "\\v"); + break; + + case '\\': + pp_string (buffer, "\\\\"); + break; + + case '\"': + pp_string (buffer, "\\\""); + break; + + case '\'': + pp_string (buffer, "\\'"); + break; + + case '\0': + pp_string (buffer, "\\0"); + break; + + case '\1': + pp_string (buffer, "\\1"); + break; + + case '\2': + pp_string (buffer, "\\2"); + break; + + case '\3': + pp_string (buffer, "\\3"); + break; + + case '\4': + pp_string (buffer, "\\4"); + break; + + case '\5': + pp_string (buffer, "\\5"); + break; + + case '\6': + pp_string (buffer, "\\6"); + break; + + case '\7': + pp_string (buffer, "\\7"); + break; + + default: + pp_character (buffer, str[0]); + break; + } + str++; + } +} + +static void +maybe_init_pretty_print (FILE *file) +{ + if (!initialized) + { + pp_construct (&buffer, /* prefix */NULL, /* line-width */0); + pp_needs_newline (&buffer) = true; + initialized = 1; + } + + buffer.buffer->stream = file; +} + +static void +newline_and_indent (pretty_printer *buffer, int spc) +{ + pp_newline (buffer); + INDENT (spc); +} + +static void +dump_vops (pretty_printer *buffer, tree stmt, int spc, int flags) +{ + size_t i; + stmt_ann_t ann = stmt_ann (stmt); + vdef_optype vdefs = VDEF_OPS (ann); + vuse_optype vuses = VUSE_OPS (ann); + + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + pp_string (buffer, "# "); + dump_generic_node (buffer, VDEF_RESULT (vdefs, i), spc + 2, flags, false); + pp_string (buffer, " = VDEF <"); + dump_generic_node (buffer, VDEF_OP (vdefs, i), spc + 2, flags, false); + pp_string (buffer, ">;"); + newline_and_indent (buffer, spc); + } + + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree vuse = VUSE_OP (vuses, i); + pp_string (buffer, "# VUSE <"); + dump_generic_node (buffer, vuse, spc + 2, flags, false); + pp_string (buffer, ">;"); + newline_and_indent (buffer, spc); + } +} + +/* Dumps basic block BB to FILE with details described by FLAGS and + indented by INDENT spaces. */ + +void +dump_generic_bb (FILE *file, basic_block bb, int indent, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = true; + dump_generic_bb_buff (&buffer, bb, indent, flags); + pp_flush (&buffer); +} + +/* Dumps header of basic block BB to buffer BUFFER indented by INDENT + spaces and details described by flags. */ + +static void +dump_bb_header (pretty_printer *buffer, basic_block bb, int indent, int flags) +{ + edge e; + tree stmt; + + if (flags & TDF_BLOCKS) + { + INDENT (indent); + pp_string (buffer, "# BLOCK "); + pp_decimal_int (buffer, bb->index); + + if (flags & TDF_LINENO) + { + block_stmt_iterator bsi; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + if (get_lineno (bsi_stmt (bsi)) != -1) + { + pp_string (buffer, ", starting at line "); + pp_decimal_int (buffer, get_lineno (bsi_stmt (bsi))); + break; + } + } + newline_and_indent (buffer, indent); + + pp_string (buffer, "# PRED:"); + pp_write_text_to_stream (buffer); + for (e = bb->pred; e; e = e->pred_next) + if (flags & TDF_SLIM) + { + pp_string (buffer, " "); + if (e->src == ENTRY_BLOCK_PTR) + pp_string (buffer, "ENTRY"); + else + pp_decimal_int (buffer, e->src->index); + } + else + dump_edge_info (buffer->buffer->stream, e, 0); + pp_newline (buffer); + } + else + { + stmt = first_stmt (bb); + if (!stmt || TREE_CODE (stmt) != LABEL_EXPR) + { + INDENT (indent - 2); + pp_string (buffer, "index); + pp_string (buffer, ">:"); + pp_newline (buffer); + } + } +} + +/* Dumps end of basic block BB to buffer BUFFER indented by INDENT + spaces. */ + +static void +dump_bb_end (pretty_printer *buffer, basic_block bb, int indent, int flags) +{ + edge e; + + INDENT (indent); + pp_string (buffer, "# SUCC:"); + pp_write_text_to_stream (buffer); + for (e = bb->succ; e; e = e->succ_next) + if (flags & TDF_SLIM) + { + pp_string (buffer, " "); + if (e->dest == EXIT_BLOCK_PTR) + pp_string (buffer, "EXIT"); + else + pp_decimal_int (buffer, e->dest->index); + } + else + dump_edge_info (buffer->buffer->stream, e, 1); + pp_newline (buffer); +} + +/* Dumps phi nodes of basic block BB to buffer BUFFER with details described by + FLAGS indented by INDENT spaces. */ + +static void +dump_phi_nodes (pretty_printer *buffer, basic_block bb, int indent, int flags) +{ + tree phi = phi_nodes (bb); + if (!phi) + return; + + for (; phi; phi = TREE_CHAIN (phi)) + { + if (is_gimple_reg (PHI_RESULT (phi)) || (flags & TDF_VOPS)) + { + INDENT (indent); + pp_string (buffer, "# "); + dump_generic_node (buffer, phi, indent, flags, false); + pp_newline (buffer); + } + } +} + +/* Dump jump to basic block BB that is represented implicitly in the cfg + to BUFFER. */ + +static void +pp_cfg_jump (pretty_printer *buffer, basic_block bb) +{ + tree stmt; + + stmt = first_stmt (bb); + + pp_string (buffer, "goto index); + pp_string (buffer, ">"); + if (stmt && TREE_CODE (stmt) == LABEL_EXPR) + { + pp_string (buffer, " ("); + dump_generic_node (buffer, LABEL_EXPR_LABEL (stmt), 0, 0, false); + pp_string (buffer, ")"); + } + pp_semicolon (buffer); +} + +/* Dump edges represented implicitly in basic block BB to BUFFER, indented + by INDENT spaces, with details given by FLAGS. */ + +static void +dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent) +{ + edge e; + + /* If there is a fallthru edge, we may need to add an artificial goto to the + dump. */ + for (e = bb->succ; e; e = e->succ_next) + if (e->flags & EDGE_FALLTHRU) + break; + if (e && e->dest != bb->next_bb) + { + INDENT (indent); + pp_cfg_jump (buffer, e->dest); + pp_newline (buffer); + } +} + +/* Dumps basic block BB to buffer BUFFER with details described by FLAGS and + indented by INDENT spaces. */ + +static void +dump_generic_bb_buff (pretty_printer *buffer, basic_block bb, + int indent, int flags) +{ + block_stmt_iterator bsi; + tree stmt; + int label_indent = indent - 2; + + if (label_indent < 0) + label_indent = 0; + + dump_bb_header (buffer, bb, indent, flags); + + if (bb_ann (bb)) + dump_phi_nodes (buffer, bb, indent, flags); + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + int curr_indent; + + stmt = bsi_stmt (bsi); + + curr_indent = TREE_CODE (stmt) == LABEL_EXPR ? label_indent : indent; + + INDENT (curr_indent); + dump_generic_node (buffer, stmt, curr_indent, flags, true); + pp_newline (buffer); + } + + dump_implicit_edges (buffer, bb, indent); + + if (flags & TDF_BLOCKS) + dump_bb_end (buffer, bb, indent, flags); +} diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c new file mode 100644 index 00000000000..c1498ea8d5c --- /dev/null +++ b/gcc/tree-profile.c @@ -0,0 +1,188 @@ +/* Calculate branch probabilities, and basic block execution counts. + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by James E. Wilson, UC Berkeley/Cygnus Support; + based on some ideas from Dain Samples of UC Berkeley. + Further mangling by Bob Manson, Cygnus Support. + Converted to use trees by Dale Johannesen, Apple Computer. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Generate basic block profile instrumentation and auxiliary files. + Profile generation is optimized, so that not all arcs in the basic + block graph need instrumenting. First, the BB graph is closed with + one entry (function start), and one exit (function exit). Any + ABNORMAL_EDGE cannot be instrumented (because there is no control + path to place the code). We close the graph by inserting fake + EDGE_FAKE edges to the EXIT_BLOCK, from the sources of abnormal + edges that do not go to the exit_block. We ignore such abnormal + edges. Naturally these fake edges are never directly traversed, + and so *cannot* be directly instrumented. Some other graph + massaging is done. To optimize the instrumentation we generate the + BB minimal span tree, only edges that are not on the span tree + (plus the entry point) need instrumenting. From that information + all other edge counts can be deduced. By construction all fake + edges must be on the spanning tree. We also attempt to place + EDGE_CRITICAL edges on the spanning tree. + + The auxiliary file generated is .bbg. The format is + described in full in gcov-io.h. */ + +/* ??? Register allocation should use basic block execution counts to + give preference to the most commonly executed blocks. */ + +/* ??? Should calculate branch probabilities before instrumenting code, since + then we can use arc counts to help decide which arcs to instrument. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "flags.h" +#include "output.h" +#include "regs.h" +#include "expr.h" +#include "function.h" +#include "toplev.h" +#include "coverage.h" +#include "tree.h" +#include "tree-flow.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "timevar.h" +#include "value-prof.h" + + +/* Output instructions as GIMPLE trees to increment the edge + execution count, and insert them on E. We rely on + bsi_insert_on_edge to preserve the order. */ + +static void +tree_gen_edge_profiler (int edgeno, edge e) +{ + tree tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF"); + tree tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF"); + tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); + tree stmt1 = build (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref); + tree stmt2 = build (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2, + build (PLUS_EXPR, GCOV_TYPE_NODE, + tmp1, integer_one_node)); + tree stmt3 = build (MODIFY_EXPR, GCOV_TYPE_NODE, ref, tmp2); + bsi_insert_on_edge (e, stmt1); + bsi_insert_on_edge (e, stmt2); + bsi_insert_on_edge (e, stmt3); +} + +/* Output instructions as GIMPLE trees to increment the interval histogram + counter. VALUE is the expression whose value is profiled. TAG is the + tag of the section for counters, BASE is offset of the counter position. */ + +static void +tree_gen_interval_profiler (struct histogram_value *value ATTRIBUTE_UNUSED, + unsigned tag ATTRIBUTE_UNUSED, + unsigned base ATTRIBUTE_UNUSED) +{ + /* FIXME implement this. */ + abort (); +} + +/* Output instructions as GIMPLE trees to increment the power of two histogram + counter. VALUE is the expression whose value is profiled. TAG is the tag + of the section for counters, BASE is offset of the counter position. */ + +static void +tree_gen_pow2_profiler (struct histogram_value *value ATTRIBUTE_UNUSED, + unsigned tag ATTRIBUTE_UNUSED, + unsigned base ATTRIBUTE_UNUSED) +{ + /* FIXME implement this. */ + abort (); +} + +/* Output instructions as GIMPLE trees for code to find the most common value. + VALUE is the expression whose value is profiled. TAG is the tag of the + section for counters, BASE is offset of the counter position. */ + +static void +tree_gen_one_value_profiler (struct histogram_value *value ATTRIBUTE_UNUSED, + unsigned tag ATTRIBUTE_UNUSED, + unsigned base ATTRIBUTE_UNUSED) +{ + /* FIXME implement this. */ + abort (); +} + +/* Output instructions as GIMPLE trees for code to find the most common value + of a difference between two evaluations of an expression. + VALUE is the expression whose value is profiled. TAG is the tag of the + section for counters, BASE is offset of the counter position. */ + +static void +tree_gen_const_delta_profiler (struct histogram_value *value ATTRIBUTE_UNUSED, + unsigned tag ATTRIBUTE_UNUSED, + unsigned base ATTRIBUTE_UNUSED) +{ + /* FIXME implement this. */ + abort (); +} + +/* Return 1 if tree-based profiling is in effect, else 0. + If it is, set up hooks for tree-based profiling. + Gate for pass_tree_profile. */ + +static bool do_tree_profiling (void) { + if (flag_tree_based_profiling) + { + tree_register_profile_hooks (); + tree_register_value_prof_hooks (); + } + return flag_tree_based_profiling; +} + +/* Return the file on which profile dump output goes, if any. */ + +static FILE *tree_profile_dump_file (void) { + return dump_file; +} + +struct tree_opt_pass pass_tree_profile = +{ + "tree_profile", /* name */ + do_tree_profiling, /* gate */ + branch_prob, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_BRANCH_PROB, /* tv_id */ + PROP_gimple_leh | PROP_cfg, /* properties_required */ + PROP_gimple_leh | PROP_cfg, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_verify_stmts /* todo_flags_finish */ +}; + +struct profile_hooks tree_profile_hooks = +{ + tree_gen_edge_profiler, /* gen_edge_profiler */ + tree_gen_interval_profiler, /* gen_interval_profiler */ + tree_gen_pow2_profiler, /* gen_pow2_profiler */ + tree_gen_one_value_profiler, /* gen_one_value_profiler */ + tree_gen_const_delta_profiler,/* gen_const_delta_profiler */ + tree_profile_dump_file /* profile_dump_file */ +}; diff --git a/gcc/tree-simple.c b/gcc/tree-simple.c new file mode 100644 index 00000000000..0215088deca --- /dev/null +++ b/gcc/tree-simple.c @@ -0,0 +1,642 @@ +/* Functions to analyze and validate GIMPLE trees. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Diego Novillo + Rewritten by Jason Merrill + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "ggc.h" +#include "tm.h" +#include "tree.h" +#include "tree-simple.h" +#include "output.h" +#include "rtl.h" +#include "expr.h" +#include "bitmap.h" + +/* GCC GIMPLE structure + + Inspired by the SIMPLE C grammar at + + http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html + + function: + FUNCTION_DECL + DECL_SAVED_TREE -> block + block: + BIND_EXPR + BIND_EXPR_VARS -> DECL chain + BIND_EXPR_BLOCK -> BLOCK + BIND_EXPR_BODY -> compound-stmt + compound-stmt: + COMPOUND_EXPR + op0 -> non-compound-stmt + op1 -> stmt + | EXPR_VEC + (or other alternate solution) + stmt: compound-stmt | non-compound-stmt + non-compound-stmt: + block + | if-stmt + | switch-stmt + | jump-stmt + | label-stmt + | try-stmt + | modify-stmt + | call-stmt + if-stmt: + COND_EXPR + op0 -> condition + op1 -> stmt + op2 -> stmt + switch-stmt: + SWITCH_EXPR + op0 -> val + op1 -> stmt + op2 -> array of case labels (as LABEL_DECLs?) + FIXME: add case value info + jump-stmt: + GOTO_EXPR + op0 -> LABEL_DECL | '*' ID + | RETURN_EXPR + op0 -> modify-stmt | NULL_TREE + (maybe -> RESULT_DECL | NULL_TREE? seems like some of expand_return + depends on getting a MODIFY_EXPR.) + | THROW_EXPR? do we need/want such a thing for opts, perhaps + to generate an ERT_THROW region? I think so. + Hmm...this would only work at the GIMPLE level, where we know that + the call args don't have any EH impact. Perhaps + annotation of the CALL_EXPR would work better. + | RESX_EXPR + label-stmt: + LABEL_EXPR + op0 -> LABEL_DECL + | CASE_LABEL_EXPR + CASE_LOW -> val | NULL_TREE + CASE_HIGH -> val | NULL_TREE + CASE_LABEL -> LABEL_DECL FIXME + try-stmt: + TRY_CATCH_EXPR + op0 -> stmt + op1 -> handler + | TRY_FINALLY_EXPR + op0 -> stmt + op1 -> stmt + handler: + catch-seq + | EH_FILTER_EXPR + | stmt + modify-stmt: + MODIFY_EXPR + op0 -> lhs + op1 -> rhs + call-stmt: CALL_EXPR + op0 -> ID | '&' ID + op1 -> arglist + + addr-expr-arg : compref | ID + lhs: addr-expr-arg | '*' ID | bitfieldref + min-lval: ID | '*' ID + bitfieldref : + BIT_FIELD_REF + op0 -> compref | min-lval + op1 -> CONST + op2 -> CONST + compref : + COMPONENT_REF + op0 -> compref | min-lval + | ARRAY_REF + op0 -> compref | min-lval + op1 -> val + | REALPART_EXPR + | IMAGPART_EXPR + + condition : val | val relop val + val : ID | CONST + + rhs : varname | CONST + | '*' ID + | '&' addr-expr-arg + | call_expr + | unop val + | val binop val + | '(' cast ')' val + + (cast here stands for all valid C typecasts) + + unop + : '+' + | '-' + | '!' + | '~' + + binop + : relop | '-' + | '+' + | '/' + | '*' + | '%' + | '&' + | '|' + | '<<' + | '>>' + | '^' + + relop + : '<' + | '<=' + | '>' + | '>=' + | '==' + | '!=' + +*/ + +static inline bool is_gimple_id (tree); + +/* Validation of GIMPLE expressions. */ + +/* Return nonzero if T is a GIMPLE RHS: + + rhs : varname | CONST + | '*' ID + | '&' varname_or_temp + | call_expr + | unop val + | val binop val + | '(' cast ')' val + | > + + The last option is only valid GIMPLE for vector and complex types; + aggregate types should have their constructors decomposed. */ + +bool +is_gimple_rhs (tree t) +{ + enum tree_code code = TREE_CODE (t); + + switch (TREE_CODE_CLASS (code)) + { + case '1': + case '2': + case '<': + return 1; + + default: + break; + } + + switch (code) + { + case TRUTH_NOT_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case ADDR_EXPR: + case CALL_EXPR: + case CONSTRUCTOR: + case COMPLEX_EXPR: + /* FIXME lower VA_ARG_EXPR. */ + case VA_ARG_EXPR: + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + return 1; + + default: + break; + } + + if (is_gimple_lvalue (t) || is_gimple_val (t)) + return 1; + + return 0; +} + +/* Returns nonzero if T is a valid CONSTRUCTOR component in GIMPLE, either + a val or another CONSTRUCTOR. */ + +bool +is_gimple_constructor_elt (tree t) +{ + return (is_gimple_val (t) + || TREE_CODE (t) == CONSTRUCTOR); +} + +/* Return nonzero if T is a valid LHS for a GIMPLE assignment expression. */ + +bool +is_gimple_lvalue (tree t) +{ + return (is_gimple_addr_expr_arg (t) + || TREE_CODE (t) == INDIRECT_REF + /* These are complex lvalues, but don't have addresses, so they + go here. */ + || TREE_CODE (t) == BIT_FIELD_REF); +} + + +/* Return nonzero if T is a GIMPLE condition: + + condexpr + : val + | val relop val */ + +bool +is_gimple_condexpr (tree t) +{ + return (is_gimple_val (t) + || TREE_CODE_CLASS (TREE_CODE (t)) == '<'); +} + + +/* Return nonzero if T is a valid operand for '&': + + varname + : arrayref + | compref + | ID */ + +bool +is_gimple_addr_expr_arg (tree t) +{ + return (is_gimple_id (t) + || TREE_CODE (t) == ARRAY_REF + || TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == REALPART_EXPR + || TREE_CODE (t) == IMAGPART_EXPR); +} + +/* Return nonzero if T is function invariant. Or rather a restricted + form of function invariant. */ + +bool +is_gimple_min_invariant (tree t) +{ + switch (TREE_CODE (t)) + { + case ADDR_EXPR: + return TREE_INVARIANT (t); + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + return !TREE_OVERFLOW (t); + + default: + return false; + } +} + +/* Return nonzero if T looks like a valid GIMPLE statement. */ + +bool +is_gimple_stmt (tree t) +{ + enum tree_code code = TREE_CODE (t); + + if (IS_EMPTY_STMT (t)) + return 1; + + switch (code) + { + case BIND_EXPR: + case COND_EXPR: + /* These are only valid if they're void. */ + return VOID_TYPE_P (TREE_TYPE (t)); + + case SWITCH_EXPR: + case GOTO_EXPR: + case RETURN_EXPR: + case LABEL_EXPR: + case CASE_LABEL_EXPR: + case TRY_CATCH_EXPR: + case TRY_FINALLY_EXPR: + case EH_FILTER_EXPR: + case CATCH_EXPR: + case ASM_EXPR: + case RESX_EXPR: + case PHI_NODE: + case STATEMENT_LIST: + /* These are always void. */ + return 1; + + case VA_ARG_EXPR: + /* FIXME this should be lowered. */ + return 1; + + case COMPOUND_EXPR: + /* FIXME should we work harder to make COMPOUND_EXPRs void? */ + case CALL_EXPR: + case MODIFY_EXPR: + /* These are valid regardless of their type. */ + return 1; + + default: + return 0; + } +} + +/* Return nonzero if T is a variable. */ + +bool +is_gimple_variable (tree t) +{ + return (TREE_CODE (t) == VAR_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == RESULT_DECL + || TREE_CODE (t) == SSA_NAME); +} + +/* Return nonzero if T is a GIMPLE identifier (something with an address). */ + +static inline bool +is_gimple_id (tree t) +{ + return (is_gimple_variable (t) + || TREE_CODE (t) == FUNCTION_DECL + || TREE_CODE (t) == LABEL_DECL + /* Allow string constants, since they are addressable. */ + || TREE_CODE (t) == STRING_CST); +} + +/* Return nonzero if TYPE is a suitable type for a scalar register + variable. */ + +bool +is_gimple_reg_type (tree type) +{ + return (!AGGREGATE_TYPE_P (type) + && TREE_CODE (type) != COMPLEX_TYPE); +} + + +/* Return nonzero if T is a scalar register variable. */ + +bool +is_gimple_reg (tree t) +{ + if (TREE_CODE (t) == SSA_NAME) + t = SSA_NAME_VAR (t); + + return (is_gimple_variable (t) + && is_gimple_reg_type (TREE_TYPE (t)) + /* A volatile decl is not acceptable because we can't reuse it as + needed. We need to copy it into a temp first. */ + && ! TREE_THIS_VOLATILE (t) + && ! TREE_ADDRESSABLE (t) + && ! needs_to_live_in_memory (t)); +} + +/* Return nonzero if T is a GIMPLE variable whose address is not needed. */ + +bool +is_gimple_non_addressable (tree t) +{ + if (TREE_CODE (t) == SSA_NAME) + t = SSA_NAME_VAR (t); + + return (is_gimple_variable (t) + && ! TREE_ADDRESSABLE (t) + && ! needs_to_live_in_memory (t)); +} + +/* Return nonzero if T is a GIMPLE rvalue, i.e. an identifier or a + constant. */ + +bool +is_gimple_val (tree t) +{ + /* Make loads from volatiles and memory vars explicit. */ + if (is_gimple_variable (t) + && is_gimple_reg_type (TREE_TYPE (t)) + && !is_gimple_reg (t)) + return 0; + + /* FIXME make these decls. That can happen only when we expose the + entire landing-pad construct at the tree level. */ + if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR) + return 1; + + return (is_gimple_variable (t) || is_gimple_min_invariant (t)); +} + + +/* Return true if T is a GIMPLE minimal lvalue, of the form + + min_lval: ID | '(' '*' ID ')' + + This never actually appears in the original SIMPLE grammar, but is + repeated in several places. */ + +bool +is_gimple_min_lval (tree t) +{ + return (is_gimple_id (t) + || TREE_CODE (t) == INDIRECT_REF); +} + +/* Return nonzero if T is a typecast operation of the form + '(' cast ')' val. */ + +bool +is_gimple_cast (tree t) +{ + return (TREE_CODE (t) == NOP_EXPR + || TREE_CODE (t) == CONVERT_EXPR + || TREE_CODE (t) == FIX_TRUNC_EXPR + || TREE_CODE (t) == FIX_CEIL_EXPR + || TREE_CODE (t) == FIX_FLOOR_EXPR + || TREE_CODE (t) == FIX_ROUND_EXPR); +} + + +/* If T makes a function call, return the corresponding CALL_EXPR operand. + Otherwise, return NULL_TREE. */ + +tree +get_call_expr_in (tree t) +{ + if (TREE_CODE (t) == CALL_EXPR) + return t; + else if (TREE_CODE (t) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR) + return TREE_OPERAND (t, 1); + else if (TREE_CODE (t) == RETURN_EXPR + && TREE_OPERAND (t, 0) + && TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == CALL_EXPR) + return TREE_OPERAND (TREE_OPERAND (t, 0), 1); + + return NULL_TREE; +} + + +/* Given an _EXPR TOP, reorganize all of the nested _EXPRs with the same + code so that they only appear as the second operand. This should only + be used for tree codes which are truly associative, such as + COMPOUND_EXPR and TRUTH_ANDIF_EXPR. Arithmetic is not associative + enough, due to the limited precision of arithmetic data types. + + This transformation is conservative; the operand 0 of a matching tree + node will only change if it is also a matching node. */ + +tree +right_assocify_expr (tree top) +{ + tree *p = ⊤ + enum tree_code code = TREE_CODE (*p); + while (TREE_CODE (*p) == code) + { + tree cur = *p; + tree lhs = TREE_OPERAND (cur, 0); + if (TREE_CODE (lhs) == code) + { + /* There's a left-recursion. If we have ((a, (b, c)), d), we + want to rearrange to (a, (b, (c, d))). */ + tree *q; + + /* Replace cur with the lhs; move (a, *) up. */ + *p = lhs; + + if (code == COMPOUND_EXPR) + { + /* We need to give (b, c) the type of c; previously lhs had + the type of b. */ + TREE_TYPE (lhs) = TREE_TYPE (cur); + if (TREE_SIDE_EFFECTS (cur)) + TREE_SIDE_EFFECTS (lhs) = 1; + } + + /* Walk through the op1 chain from there until we find something + with a different code. In this case, c. */ + for (q = &TREE_OPERAND (lhs, 1); TREE_CODE (*q) == code; + q = &TREE_OPERAND (*q, 1)) + TREE_TYPE (*q) = TREE_TYPE (cur); + + /* Change (*, d) into (c, d). */ + TREE_OPERAND (cur, 0) = *q; + + /* And plug it in where c used to be. */ + *q = cur; + } + else + p = &TREE_OPERAND (cur, 1); + } + return top; +} + +/* Normalize the statement TOP. If it is a COMPOUND_EXPR, reorganize it so + that we can traverse it without recursion. If it is null, replace it + with a nop. */ + +tree +rationalize_compound_expr (tree top) +{ + if (top == NULL_TREE) + top = build_empty_stmt (); + else if (TREE_CODE (top) == COMPOUND_EXPR) + top = right_assocify_expr (top); + + return top; +} + +/* Given a memory reference expression, return the base address. Note that, + in contrast with get_base_var, this will not recurse inside INDIRECT_REF + expressions. Therefore, given the reference PTR->FIELD, this function + will return *PTR. Whereas get_base_var would've returned PTR. */ + +tree +get_base_address (tree t) +{ + do + { + if (SSA_VAR_P (t) + || TREE_CODE (t) == INDIRECT_REF) + return t; + + switch (TREE_CODE (t)) + { + case ARRAY_REF: + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + case BIT_FIELD_REF: + t = TREE_OPERAND (t, 0); + break; + + default: + return NULL_TREE; + } + } + while (t); + + return t; +} + + +void +recalculate_side_effects (tree t) +{ + enum tree_code code = TREE_CODE (t); + int fro = first_rtl_op (code); + int i; + + switch (TREE_CODE_CLASS (code)) + { + case 'e': + switch (code) + { + case INIT_EXPR: + case MODIFY_EXPR: + case VA_ARG_EXPR: + case RTL_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + /* All of these have side-effects, no matter what their + operands are. */ + return; + + default: + break; + } + /* Fall through. */ + + case '<': /* a comparison expression */ + case '1': /* a unary arithmetic expression */ + case '2': /* a binary arithmetic expression */ + case 'r': /* a reference */ + TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t); + for (i = 0; i < fro; ++i) + { + tree op = TREE_OPERAND (t, i); + if (op && TREE_SIDE_EFFECTS (op)) + TREE_SIDE_EFFECTS (t) = 1; + } + break; + } +} diff --git a/gcc/tree-simple.h b/gcc/tree-simple.h new file mode 100644 index 00000000000..d2c91032031 --- /dev/null +++ b/gcc/tree-simple.h @@ -0,0 +1,127 @@ +/* Functions to analyze and validate GIMPLE trees. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _TREE_SIMPLE_H +#define _TREE_SIMPLE_H 1 + + +#include "tree-iterator.h" + +extern tree create_tmp_var_raw (tree, const char *); +extern tree create_tmp_var (tree, const char *); +extern bool is_gimple_tmp_var (tree); +extern tree get_initialized_tmp_var (tree, tree *, tree *); +extern tree get_formal_tmp_var (tree, tree *); +extern void declare_tmp_vars (tree, tree); + +extern tree rationalize_compound_expr (tree); +extern tree right_assocify_expr (tree); +extern void annotate_all_with_locus (tree *, location_t); + +/* Validation of GIMPLE expressions. Note that these predicates only check + the basic form of the expression, they don't recurse to make sure that + underlying nodes are also of the right form. */ + +/* Returns true iff T is a valid GIMPLE statement. */ +bool is_gimple_stmt (tree); + +/* Returns true iff TYPE is a valid type for a scalar register variable. */ +bool is_gimple_reg_type (tree); +/* Returns true iff T is a scalar register variable. */ +bool is_gimple_reg (tree); +/* Returns true iff T is any sort of variable. */ +bool is_gimple_variable (tree); +/* Returns true iff T is a variable or an INDIRECT_REF (of a variable). */ +bool is_gimple_min_lval (tree); +/* Returns true iff T is an lvalue other than an INDIRECT_REF. */ +bool is_gimple_addr_expr_arg (tree); +/* Returns true iff T is any valid GIMPLE lvalue. */ +bool is_gimple_lvalue (tree); + +/* Returns true iff T is a GIMPLE restricted function invariant. */ +bool is_gimple_min_invariant (tree); +/* Returns true iff T is a GIMPLE rvalue. */ +bool is_gimple_val (tree); +/* Returns true iff T is a valid rhs for a MODIFY_EXPR. */ +bool is_gimple_rhs (tree); + +/* Returns true iff T is a valid if-statement condition. */ +bool is_gimple_condexpr (tree); + +/* Returns true iff T is a type conversion. */ +bool is_gimple_cast (tree); +/* Returns true iff T is a valid CONSTRUCTOR element (either an rvalue or + another CONSTRUCTOR). */ +bool is_gimple_constructor_elt (tree); +/* Returns true iff T is a variable that does not need to live in memory. */ +bool is_gimple_non_addressable (tree t); + +/* If T makes a function call, returns the CALL_EXPR operand. */ +tree get_call_expr_in (tree t); + +void recalculate_side_effects (tree); + +void append_to_statement_list (tree, tree *); +void append_to_statement_list_force (tree, tree *); +void append_to_compound_expr (tree, tree *); + +/* FIXME we should deduce this from the predicate. */ +typedef enum fallback_t { + fb_none = 0, + fb_rvalue = 1, + fb_lvalue = 2, + fb_mayfail = 4, + fb_either= fb_rvalue | fb_lvalue +} fallback_t; + +enum gimplify_status { + GS_ERROR = -2, /* Something Bad Seen. */ + GS_UNHANDLED = -1, /* A langhook result for "I dunno". */ + GS_OK = 0, /* We did something, maybe more to do. */ + GS_ALL_DONE = 1 /* The expression is fully gimplified. */ +}; + +enum gimplify_status gimplify_expr (tree *, tree *, tree *, + bool (*) (tree), fallback_t); +void gimplify_stmt (tree *); +void gimplify_to_stmt_list (tree *); +void gimplify_body (tree *, tree); +void push_gimplify_context (void); +void pop_gimplify_context (tree); + +/* Miscellaneous helpers. */ +tree get_base_address (tree t); +void gimple_add_tmp_var (tree); +tree gimple_current_bind_expr (void); +void gimple_push_bind_expr (tree); +void gimple_pop_bind_expr (void); +void unshare_all_trees (tree); +tree voidify_wrapper_expr (tree); +tree gimple_build_eh_filter (tree, tree, tree); +tree build_and_jump (tree *); +tree alloc_stmt_list (void); +void free_stmt_list (tree); +tree force_labels_r (tree *, int *, void *); + +/* In tree-nested.c. */ +extern void lower_nested_functions (tree); + +#endif /* _TREE_SIMPLE_H */ diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c new file mode 100644 index 00000000000..2131d0047f2 --- /dev/null +++ b/gcc/tree-sra.c @@ -0,0 +1,1193 @@ +/* Scalar Replacement of Aggregates (SRA) converts some structure + references into scalar references, exposing them to the scalar + optimizers. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" +#include "tree.h" + +/* These RTL headers are needed for basic-block.h. */ +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "tree-inline.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "timevar.h" +#include "flags.h" +#include "bitmap.h" + + +/* Maximum number of fields that a structure should have to be scalarized. + FIXME This limit has been arbitrarily set to 5. Experiment to find a + sensible setting. */ +#define MAX_NFIELDS_FOR_SRA 5 + +/* Codes indicating how to copy one structure into another. */ +enum sra_copy_mode { SCALAR_SCALAR, FIELD_SCALAR, SCALAR_FIELD }; + +/* Local functions. */ +static inline bool can_be_scalarized_p (tree); +static inline void insert_edge_copies (tree stmt, basic_block bb); +static tree create_scalar_copies (tree lhs, tree rhs, enum sra_copy_mode mode); +static inline void scalarize_component_ref (tree, tree *tp); +static void scalarize_structures (void); +static void scalarize_stmt (block_stmt_iterator *); +static void scalarize_modify_expr (block_stmt_iterator *); +static void scalarize_call_expr (block_stmt_iterator *); +static void scalarize_asm_expr (block_stmt_iterator *); +static void scalarize_return_expr (block_stmt_iterator *); + +/* The set of aggregate variables that are candidates for scalarization. */ +static bitmap sra_candidates; + +/* Set of scalarizable PARM_DECLs that need copy-in operations at the + beginning of the function. */ +static bitmap needs_copy_in; + +/* This structure holds the mapping between and element of an aggregate + and the scalar replacement variable. */ +struct sra_elt +{ + enum tree_code kind; + tree base; + tree field; + tree replace; +}; + +static htab_t sra_map; + +static hashval_t +sra_elt_hash (const void *x) +{ + const struct sra_elt *e = x; + hashval_t h = (size_t) e->base * e->kind; + if (e->kind == COMPONENT_REF) + h ^= (size_t) e->field; + return h; +} + +static int +sra_elt_eq (const void *x, const void *y) +{ + const struct sra_elt *a = x; + const struct sra_elt *b = y; + + if (a->kind != b->kind) + return false; + if (a->base != b->base) + return false; + if (a->kind == COMPONENT_REF) + if (a->field != b->field) + return false; + + return true; +} + +/* Build a temporary. Make sure and register it to be renamed. */ + +static tree +make_temp (tree type, const char *prefix) +{ + tree t = create_tmp_var (type, prefix); + add_referenced_tmp_var (t); + bitmap_set_bit (vars_to_rename, var_ann (t)->uid); + return t; +} + +/* Mark all the variables in VDEF operands for STMT for renaming. + This becomes necessary when we modify all of a non-scalar. */ + +static void +mark_all_vdefs (tree stmt) +{ + vdef_optype vdefs; + size_t i, n; + + get_stmt_operands (stmt); + vdefs = VDEF_OPS (stmt_ann (stmt)); + n = NUM_VDEFS (vdefs); + + for (i = 0; i < n; i++) + { + tree sym = VDEF_RESULT (vdefs, i); + bitmap_set_bit (vars_to_rename, var_ann (sym)->uid); + } +} + +/* Return true if DECL is an SRA candidate. */ + +static bool +is_sra_candidate_decl (tree decl) +{ + return DECL_P (decl) && bitmap_bit_p (sra_candidates, var_ann (decl)->uid); +} + +/* Return true if EXP is of the form , where REF is one of the + field access references we handle and DECL is an SRA candidate. + + Set ALLOW_BIT_FIELD_REF to accept BIT_FIELD_REF as well. This is + normally false, except when we're trying to work around it. */ + +static bool +is_sra_candidate_ref (tree exp, bool allow_bit_field_ref) +{ + switch (TREE_CODE (exp)) + { + case BIT_FIELD_REF: + if (!allow_bit_field_ref) + break; + /* FALLTHRU */ + + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + return is_sra_candidate_decl (TREE_OPERAND (exp, 0)); + + default: + break; + } + + return false; +} + +/* Return the scalar in SRA_MAP[VAR_IX][FIELD_IX]. If none exists, create + a new scalar with type TYPE. */ + +static tree +lookup_scalar (struct sra_elt *key, tree type) +{ + struct sra_elt **slot, *res; + + slot = (struct sra_elt **) htab_find_slot (sra_map, key, INSERT); + res = *slot; + if (!res) + { + res = xmalloc (sizeof (*res)); + *slot = res; + *res = *key; + res->replace = make_temp (type, "SR"); + + if (DECL_NAME (key->base) && !DECL_IGNORED_P (key->base)) + { + char *name = NULL; + switch (key->kind) + { + case COMPONENT_REF: + if (!DECL_NAME (key->field)) + break; + name = concat (IDENTIFIER_POINTER (DECL_NAME (key->base)), + "$", + IDENTIFIER_POINTER (DECL_NAME (key->field)), + NULL); + break; + case REALPART_EXPR: + name = concat (IDENTIFIER_POINTER (DECL_NAME (key->base)), + "$real", NULL); + break; + case IMAGPART_EXPR: + name = concat (IDENTIFIER_POINTER (DECL_NAME (key->base)), + "$imag", NULL); + break; + default: + abort (); + } + if (name) + { + DECL_NAME (res->replace) = get_identifier (name); + free (name); + } + } + + DECL_SOURCE_LOCATION (res->replace) = DECL_SOURCE_LOCATION (key->base); + TREE_NO_WARNING (res->replace) = TREE_NO_WARNING (key->base); + DECL_ARTIFICIAL (res->replace) = DECL_ARTIFICIAL (key->base); + } + + return res->replace; +} + + +/* Given a structure reference VAR.FIELD, return a scalar representing it. + If no scalar is found, a new one is created and added to the SRA_MAP + matrix. */ + +static tree +get_scalar_for_field (tree var, tree field) +{ + struct sra_elt key; + +#ifdef ENABLE_CHECKING + /* Validate that FIELD actually exists in VAR's type. */ + { + tree f; + for (f = TYPE_FIELDS (TREE_TYPE (var)); f ; f = TREE_CHAIN (f)) + if (f == field) + goto found; + abort (); + found:; + } +#endif + + key.kind = COMPONENT_REF; + key.base = var; + key.field = field; + + return lookup_scalar (&key, TREE_TYPE (field)); +} + + +/* Similarly for the parts of a complex type. */ + +static tree +get_scalar_for_complex_part (tree var, enum tree_code part) +{ + struct sra_elt key; + + key.kind = part; + key.base = var; + + return lookup_scalar (&key, TREE_TYPE (TREE_TYPE (var))); +} + +/* Return true if the fields of VAR can be replaced by scalar temporaries. + This only happens if VAR is not call-clobbered and it contains less + than MAX_NFIELDS_FOR_SRA scalar fields. */ + +static inline bool +can_be_scalarized_p (tree var) +{ + tree field, type; + int nfields; + + if (!is_gimple_non_addressable (var)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Cannot scalarize variable "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, " because it must live in memory\n"); + } + return false; + } + + if (TREE_THIS_VOLATILE (var)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Cannot scalarize variable "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, " because it is declared volatile\n"); + } + return false; + } + + /* Any COMPLEX_TYPE that has reached this point can be scalarized. */ + if (TREE_CODE (TREE_TYPE (var)) == COMPLEX_TYPE) + return true; + + type = TREE_TYPE (var); + nfields = 0; + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + /* FIXME: We really should recurse down the type hierarchy and + scalarize the fields at the leaves. */ + if (AGGREGATE_TYPE_P (TREE_TYPE (field))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Cannot scalarize variable "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, + " because it contains an aggregate type field, "); + print_generic_expr (dump_file, field, dump_flags); + fprintf (dump_file, "\n"); + } + return false; + } + + /* FIXME: Similarly. Indeed, considering that we treat complex + as an aggregate, this is exactly the same problem. + Structures with __complex__ fields are tested in the libstdc++ + testsuite: 26_numerics/complex_inserters_extractors.cc. */ + if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Cannot scalarize variable "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, + " because it contains a __complex__ field, "); + print_generic_expr (dump_file, field, dump_flags); + fprintf (dump_file, "\n"); + } + return false; + } + + /* FIXME. We don't scalarize structures with bit fields yet. To + support this, we should make sure that all the fields fit in one + word and modify every operation done on the scalarized bit fields + to mask them properly. */ + if (DECL_BIT_FIELD (field)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Cannot scalarize variable "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, + " because it contains a bit-field, "); + print_generic_expr (dump_file, field, dump_flags); + fprintf (dump_file, "\n"); + } + return false; + } + + nfields++; + if (nfields > MAX_NFIELDS_FOR_SRA) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Cannot scalarize variable "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, + " because it contains more than %d fields\n", + MAX_NFIELDS_FOR_SRA); + } + return false; + } + } + + /* If the structure had no FIELD_DECLs, then don't bother + scalarizing it. */ + return nfields > 0; +} + + +/* Replace the COMPONENT_REF, REALPART_EXPR or IMAGPART_EXPR pointed-to by + TP inside STMT with the corresponding scalar replacement from SRA_MAP. */ + +static inline void +scalarize_component_ref (tree stmt, tree *tp) +{ + tree t = *tp, obj = TREE_OPERAND (t, 0); + + /* When scalarizing a function argument, we will need to insert copy-in + operations from the original PARM_DECLs. Note that these copy-in + operations may end up being dead, but we won't know until we rename + the new variables into SSA. */ + if (TREE_CODE (obj) == PARM_DECL) + bitmap_set_bit (needs_copy_in, var_ann (obj)->uid); + + switch (TREE_CODE (t)) + { + case COMPONENT_REF: + t = get_scalar_for_field (obj, TREE_OPERAND (t, 1)); + break; + case REALPART_EXPR: + case IMAGPART_EXPR: + t = get_scalar_for_complex_part (obj, TREE_CODE (t)); + break; + default: + abort (); + } + + *tp = t; + modify_stmt (stmt); +} + + +/* Scalarize the structure assignment for the statement pointed by SI_P. */ + +static void +scalarize_structure_assignment (block_stmt_iterator *si_p) +{ + var_ann_t lhs_ann, rhs_ann; + tree lhs, rhs, list, orig_stmt; + bool lhs_can, rhs_can; + + orig_stmt = bsi_stmt (*si_p); + lhs = TREE_OPERAND (orig_stmt, 0); + rhs = TREE_OPERAND (orig_stmt, 1); + list = NULL_TREE; + +#if defined ENABLE_CHECKING + if (TREE_CODE (orig_stmt) != MODIFY_EXPR) + abort (); +#endif + + /* Remove all type casts from RHS. This may seem heavy handed but + it's actually safe and it is necessary in the presence of C++ + reinterpret_cast<> where structure assignments of different + structures will be present in the IL. This was the case of PR + 13347 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13347) which + had something like this: + + struct A f; + struct B g; + f = (struct A)g; + + Both 'f' and 'g' were scalarizable, but the presence of the type + cast was causing SRA to not replace the RHS of the assignment + with g's scalar replacements. Furthermore, the fact that this + assignment reached this point without causing syntax errors means + that the type cast is safe and that a field-by-field assignment + from 'g' into 'f' is the right thing to do. */ + STRIP_NOPS (rhs); + + lhs_ann = DECL_P (lhs) ? var_ann (lhs) : NULL; + rhs_ann = DECL_P (rhs) ? var_ann (rhs) : NULL; + +#if defined ENABLE_CHECKING + /* Two different variables should not have the same UID. */ + if (lhs_ann + && rhs_ann + && lhs != rhs + && lhs_ann->uid == rhs_ann->uid) + abort (); +#endif + + lhs_can = lhs_ann && bitmap_bit_p (sra_candidates, lhs_ann->uid); + rhs_can = rhs_ann && bitmap_bit_p (sra_candidates, rhs_ann->uid); + + /* Both LHS and RHS are scalarizable. */ + if (lhs_can && rhs_can) + list = create_scalar_copies (lhs, rhs, SCALAR_SCALAR); + + /* Only RHS is scalarizable. */ + else if (rhs_can) + list = create_scalar_copies (lhs, rhs, FIELD_SCALAR); + + /* Only LHS is scalarizable. */ + else if (lhs_can) + list = create_scalar_copies (lhs, rhs, SCALAR_FIELD); + + /* If neither side is scalarizable, do nothing else. */ + else + return; + + /* Set line number information for our replacements. */ + if (EXPR_HAS_LOCATION (orig_stmt)) + annotate_all_with_locus (&list, EXPR_LOCATION (orig_stmt)); + + /* Replace the existing statement with the newly created list of + scalarized copies. When replacing the original statement, the first + copy replaces it and the remaining copies are inserted either after + the first copy or on the outgoing edges of the original statement's + block. */ + { + tree_stmt_iterator tsi = tsi_start (list); + bsi_replace (si_p, tsi_stmt (tsi), true); + tsi_delink (&tsi); + if (stmt_ends_bb_p (orig_stmt)) + insert_edge_copies (list, bb_for_stmt (orig_stmt)); + else + bsi_insert_after (si_p, list, BSI_CONTINUE_LINKING); + } +} + + +/* Traverse all the referenced variables in the program looking for + structures that could be replaced with scalars. */ + +static bool +find_candidates_for_sra (void) +{ + size_t i; + bool any_set = false; + + for (i = 0; i < num_referenced_vars; i++) + { + tree var = referenced_var (i); + + if ((TREE_CODE (TREE_TYPE (var)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (var)) == COMPLEX_TYPE) + && can_be_scalarized_p (var)) + { + bitmap_set_bit (sra_candidates, var_ann (var)->uid); + any_set = true; + } + } + + return any_set; +} + + +/* Insert STMT on all the outgoing edges out of BB. Note that if BB + has more than one edge, STMT will be replicated for each edge. Also, + abnormal edges will be ignored. */ + +static inline void +insert_edge_copies (tree stmt, basic_block bb) +{ + edge e; + bool first_copy; + + first_copy = true; + for (e = bb->succ; e; e = e->succ_next) + { + /* We don't need to insert copies on abnormal edges. The + value of the scalar replacement is not guaranteed to + be valid through an abnormal edge. */ + if (!(e->flags & EDGE_ABNORMAL)) + { + if (first_copy) + { + bsi_insert_on_edge (e, stmt); + first_copy = false; + } + else + bsi_insert_on_edge (e, lhd_unsave_expr_now (stmt)); + } + } +} + + +/* Append a new assignment statement to TSI. */ + +static tree +csc_assign (tree_stmt_iterator *tsi, tree lhs, tree rhs) +{ + tree stmt = build (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs); + modify_stmt (stmt); + tsi_link_after (tsi, stmt, TSI_NEW_STMT); + return stmt; +} + +/* A subroutine of create_scalar_copies. Construct a COMPONENT_REF + expression for BASE referencing FIELD. INDEX is the field index. */ + +static tree +csc_build_component_ref (tree base, tree field) +{ + switch (TREE_CODE (base)) + { + case CONSTRUCTOR: + /* Only appears on RHS. The only remaining CONSTRUCTORS for + record types that should remain are empty, and imply that + the entire structure should be zeroed. */ + if (CONSTRUCTOR_ELTS (base)) + abort (); + return convert (TREE_TYPE (field), integer_zero_node); + + default: + /* Avoid sharing BASE when building the different COMPONENT_REFs. + We let the first field have the original version. */ + if (field != TYPE_FIELDS (TREE_TYPE (base))) + base = unshare_expr (base); + break; + + case VAR_DECL: + case PARM_DECL: + /* Special case for the above -- decls are always shared. */ + break; + } + + return build (COMPONENT_REF, TREE_TYPE (field), base, field); +} + +/* Similarly for REALPART_EXPR and IMAGPART_EXPR for complex types. */ + +static tree +csc_build_complex_part (tree base, enum tree_code part) +{ + switch (TREE_CODE (base)) + { + case COMPLEX_CST: + if (part == REALPART_EXPR) + return TREE_REALPART (base); + else + return TREE_IMAGPART (base); + + case COMPLEX_EXPR: + if (part == REALPART_EXPR) + return TREE_OPERAND (base, 0); + else + return TREE_OPERAND (base, 1); + + default: + /* Avoid sharing BASE when building the different references. + We let the real part have the original version. */ + if (part != REALPART_EXPR) + base = unshare_expr (base); + break; + + case VAR_DECL: + case PARM_DECL: + /* Special case for the above -- decls are always shared. */ + break; + } + + return build1 (part, TREE_TYPE (TREE_TYPE (base)), base); +} + +/* Create and return a list of assignments to perform a scalarized + structure assignment 'LHS = RHS'. Both LHS and RHS are assumed to be + of an aggregate or complex type. Three types of copies may be specified: + + SCALAR_SCALAR will emit assignments for all the scalar temporaries + corresponding to the fields of LHS and RHS. + + FIELD_SCALAR will emit assignments from the scalar replacements of + RHS into each of the fields of the LHS. + + SCALAR_FIELD will emit assignments from each field of the RHS into + the scalar replacements of the LHS. */ + +static tree +create_scalar_copies (tree lhs, tree rhs, enum sra_copy_mode mode) +{ + tree type, list; + tree_stmt_iterator tsi; + +#if defined ENABLE_CHECKING + /* Sanity checking. Check that we are not trying to scalarize a + non-decl. */ + if (!DECL_P (lhs) && (mode == SCALAR_FIELD || mode == SCALAR_SCALAR)) + abort (); + if (!DECL_P (rhs) && (mode == FIELD_SCALAR || mode == SCALAR_SCALAR)) + abort (); +#endif + + type = TREE_TYPE (lhs); + list = alloc_stmt_list (); + tsi = tsi_start (list); + + /* VA_ARG_EXPRs have side effects, so we need to copy it first to a + temporary before scalarizing. FIXME: This should disappear once + VA_ARG_EXPRs are properly lowered. */ + if (TREE_CODE (rhs) == VA_ARG_EXPR) + { + tree stmt, tmp; + + /* Add TMP = VA_ARG_EXPR <> */ + tmp = make_temp (TREE_TYPE (rhs), NULL); + stmt = csc_assign (&tsi, tmp, rhs); + + /* Mark all the variables in VDEF operands for renaming, because + the VA_ARG_EXPR will now be in a different statement. */ + mark_all_vdefs (stmt); + + /* Set RHS to be the new temporary TMP. */ + rhs = tmp; + } + + /* When making *_SCALAR copies from PARM_DECLs, we will need to insert + copy-in operations from the original PARM_DECLs. Note that these + copy-in operations may end up being dead, but we won't know until + we rename the new variables into SSA. */ + if ((mode == SCALAR_SCALAR || mode == FIELD_SCALAR) + && TREE_CODE (rhs) == PARM_DECL) + bitmap_set_bit (needs_copy_in, var_ann (rhs)->uid); + + /* Now create scalar copies for each individual field according to MODE. */ + if (TREE_CODE (type) == COMPLEX_TYPE) + { + /* Create scalar copies of both the real and imaginary parts. */ + tree real_lhs, real_rhs, imag_lhs, imag_rhs; + + if (mode == SCALAR_FIELD) + { + real_rhs = csc_build_complex_part (rhs, REALPART_EXPR); + imag_rhs = csc_build_complex_part (rhs, IMAGPART_EXPR); + } + else + { + real_rhs = get_scalar_for_complex_part (rhs, REALPART_EXPR); + imag_rhs = get_scalar_for_complex_part (rhs, IMAGPART_EXPR); + } + + if (mode == FIELD_SCALAR) + { + /* In this case we do not need to create but one statement, + since we can create a new complex value whole. */ + + if (TREE_CONSTANT (real_rhs) && TREE_CONSTANT (imag_rhs)) + rhs = build_complex (type, real_rhs, imag_rhs); + else + rhs = build (COMPLEX_EXPR, type, real_rhs, imag_rhs); + csc_assign (&tsi, lhs, rhs); + } + else + { + real_lhs = get_scalar_for_complex_part (lhs, REALPART_EXPR); + imag_lhs = get_scalar_for_complex_part (lhs, IMAGPART_EXPR); + + csc_assign (&tsi, real_lhs, real_rhs); + csc_assign (&tsi, imag_lhs, imag_rhs); + } + } + else + { + tree lf, rf; + + /* ??? C++ generates copies between different pointer-to-member + structures of different types. To combat this, we must track + the field of both the left and right structures, so that we + index the variables with fields of their own type. */ + + for (lf = TYPE_FIELDS (type), rf = TYPE_FIELDS (TREE_TYPE (rhs)); + lf; + lf = TREE_CHAIN (lf), rf = TREE_CHAIN (rf)) + { + tree lhs_var, rhs_var; + + /* Only copy FIELD_DECLs. */ + if (TREE_CODE (lf) != FIELD_DECL) + continue; + + if (mode == FIELD_SCALAR) + lhs_var = csc_build_component_ref (lhs, lf); + else + lhs_var = get_scalar_for_field (lhs, lf); + + if (mode == SCALAR_FIELD) + rhs_var = csc_build_component_ref (rhs, rf); + else + rhs_var = get_scalar_for_field (rhs, rf); + + csc_assign (&tsi, lhs_var, rhs_var); + } + } + + /* All the scalar copies just created will either create new definitions + or remove existing definitions of LHS, so we need to mark it for + renaming. */ + if (TREE_SIDE_EFFECTS (list)) + { + if (mode == SCALAR_FIELD || mode == SCALAR_SCALAR) + { + /* If the LHS has been scalarized, mark it for renaming. */ + bitmap_set_bit (vars_to_rename, var_ann (lhs)->uid); + } + else if (mode == FIELD_SCALAR) + { + /* Otherwise, mark all the symbols in the VDEFs for the last + scalarized statement just created. Since all the statements + introduce the same VDEFs, we only need to check the last one. */ + mark_all_vdefs (tsi_stmt (tsi)); + } + else + abort (); + } + + return list; +} + +/* A helper function that creates the copies, updates line info, + and emits the code either before or after BSI. */ + +static void +emit_scalar_copies (block_stmt_iterator *bsi, tree lhs, tree rhs, + enum sra_copy_mode mode) +{ + tree list = create_scalar_copies (lhs, rhs, mode); + tree stmt = bsi_stmt (*bsi); + + if (EXPR_HAS_LOCATION (stmt)) + annotate_all_with_locus (&list, EXPR_LOCATION (stmt)); + + bsi_insert_before (bsi, list, BSI_SAME_STMT); +} + +/* Traverse all the statements in the function replacing references to + scalarizable structures with their corresponding scalar temporaries. */ + +static void +scalarize_structures (void) +{ + basic_block bb; + block_stmt_iterator si; + size_t i; + + FOR_EACH_BB (bb) + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt; + stmt_ann_t ann; + + stmt = bsi_stmt (si); + ann = stmt_ann (stmt); + + /* If the statement has no virtual operands, then it doesn't make + structure references that we care about. */ + if (NUM_VDEFS (VDEF_OPS (ann)) == 0 + && NUM_VUSES (VUSE_OPS (ann)) == 0) + continue; + + /* Structure references may only appear in certain statements. */ + if (TREE_CODE (stmt) != MODIFY_EXPR + && TREE_CODE (stmt) != CALL_EXPR + && TREE_CODE (stmt) != RETURN_EXPR + && TREE_CODE (stmt) != ASM_EXPR) + continue; + + scalarize_stmt (&si); + } + + /* Initialize the scalar replacements for every structure that is a + function argument. */ + EXECUTE_IF_SET_IN_BITMAP (needs_copy_in, 0, i, + { + tree var = referenced_var (i); + tree list = create_scalar_copies (var, var, SCALAR_FIELD); + bsi_insert_on_edge (ENTRY_BLOCK_PTR->succ, list); + }); + + /* Commit edge insertions. */ + bsi_commit_edge_inserts (NULL); +} + + +/* Scalarize structure references in the statement pointed by SI_P. */ + +static void +scalarize_stmt (block_stmt_iterator *si_p) +{ + tree stmt = bsi_stmt (*si_p); + + /* Handle assignments. */ + if (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 1)) != CALL_EXPR) + scalarize_modify_expr (si_p); + + /* Handle RETURN_EXPR. */ + else if (TREE_CODE (stmt) == RETURN_EXPR) + scalarize_return_expr (si_p); + + /* Handle function calls (note that this must be handled after + MODIFY_EXPR and RETURN_EXPR because a function call can appear in + both). */ + else if (get_call_expr_in (stmt) != NULL_TREE) + scalarize_call_expr (si_p); + + /* Handle ASM_EXPRs. */ + else if (TREE_CODE (stmt) == ASM_EXPR) + scalarize_asm_expr (si_p); +} + + +/* Helper for scalarize_stmt to handle assignments. */ + +static void +scalarize_modify_expr (block_stmt_iterator *si_p) +{ + tree stmt = bsi_stmt (*si_p); + tree lhs = TREE_OPERAND (stmt, 0); + tree rhs = TREE_OPERAND (stmt, 1); + + /* Found AGGREGATE.FIELD = ... */ + if (is_sra_candidate_ref (lhs, false)) + { + tree sym; + vdef_optype vdefs; + + scalarize_component_ref (stmt, &TREE_OPERAND (stmt, 0)); + + /* Mark the LHS to be renamed, as we have just removed the previous + VDEF for AGGREGATE. The statement should have exactly one VDEF + for variable AGGREGATE. */ + vdefs = STMT_VDEF_OPS (stmt); + if (NUM_VDEFS (vdefs) != 1) + abort (); + sym = SSA_NAME_VAR (VDEF_RESULT (vdefs, 0)); + bitmap_set_bit (vars_to_rename, var_ann (sym)->uid); + } + + /* Found ... = AGGREGATE.FIELD */ + else if (is_sra_candidate_ref (rhs, false)) + scalarize_component_ref (stmt, &TREE_OPERAND (stmt, 1)); + + /* Found ... = BIT_FIELD_REF <>. This is similar to a CALL_EXPR, if the + operand of the BIT_FIELD_REF is a scalarizable structure, we need to + copy from its scalar replacements before doing the bitfield operation. + + FIXME: BIT_FIELD_REFs are often generated by fold-const.c. This is + not always desirable because they obfuscate the original predicates, + limiting what the tree optimizers may do. For instance, in + testsuite/g++.dg/opt/nrv4.C the use of SRA allows the optimizers to + optimize function main() to 'return 0;'. However, the folder + generates a BIT_FIELD_REF operation for one of the comparisons, + preventing the optimizers from removing all the redundant + operations. */ + else if (is_sra_candidate_ref (rhs, true)) + { + tree var = TREE_OPERAND (rhs, 0); + emit_scalar_copies (si_p, var, var, FIELD_SCALAR); + } + + /* Found AGGREGATE = ... or ... = AGGREGATE */ + else if (DECL_P (lhs) || DECL_P (rhs)) + scalarize_structure_assignment (si_p); +} + + +/* Scalarize structure references in LIST. Use DONE to avoid duplicates. */ + +static inline void +scalarize_tree_list (tree list, block_stmt_iterator *si_p, bitmap done) +{ + tree op; + + for (op = list; op; op = TREE_CHAIN (op)) + { + tree arg = TREE_VALUE (op); + + if (is_sra_candidate_decl (arg)) + { + int index = var_ann (arg)->uid; + if (!bitmap_bit_p (done, index)) + { + emit_scalar_copies (si_p, arg, arg, FIELD_SCALAR); + bitmap_set_bit (done, index); + } + } + else if (is_sra_candidate_ref (arg, false)) + { + tree stmt = bsi_stmt (*si_p); + scalarize_component_ref (stmt, &TREE_VALUE (op)); + } + } +} + + +/* Helper for scalarize_stmt to handle function calls. */ + +static void +scalarize_call_expr (block_stmt_iterator *si_p) +{ + tree stmt = bsi_stmt (*si_p); + tree call = (TREE_CODE (stmt) == MODIFY_EXPR) ? TREE_OPERAND (stmt, 1) : stmt; + struct bitmap_head_def done_head; + + /* First scalarize the arguments. Order is important, because the copy + operations for the arguments need to go before the call. + Scalarization of the return value needs to go after the call. */ + bitmap_initialize (&done_head, 1); + scalarize_tree_list (TREE_OPERAND (call, 1), si_p, &done_head); + bitmap_clear (&done_head); + + /* Scalarize the return value, if any. */ + if (TREE_CODE (stmt) == MODIFY_EXPR) + { + tree var = TREE_OPERAND (stmt, 0); + + /* If the LHS of the assignment is a scalarizable structure, insert + copies into the scalar replacements after the call. */ + if (is_sra_candidate_decl (var)) + { + tree list = create_scalar_copies (var, var, SCALAR_FIELD); + if (EXPR_HAS_LOCATION (stmt)) + annotate_all_with_locus (&list, EXPR_LOCATION (stmt)); + if (stmt_ends_bb_p (stmt)) + insert_edge_copies (list, bb_for_stmt (stmt)); + else + bsi_insert_after (si_p, list, BSI_NEW_STMT); + } + } +} + + +/* Helper for scalarize_stmt to handle ASM_EXPRs. */ + +static void +scalarize_asm_expr (block_stmt_iterator *si_p) +{ + tree stmt = bsi_stmt (*si_p); + struct bitmap_head_def done_head; + + bitmap_initialize (&done_head, 1); + scalarize_tree_list (ASM_INPUTS (stmt), si_p, &done_head); + scalarize_tree_list (ASM_OUTPUTS (stmt), si_p, &done_head); + bitmap_clear (&done_head); + + /* ??? Process outputs after the asm. */ +} + + +/* Helper for scalarize_stmt to handle return expressions. */ + +static void +scalarize_return_expr (block_stmt_iterator *si_p) +{ + tree stmt = bsi_stmt (*si_p); + tree op = TREE_OPERAND (stmt, 0); + + if (op == NULL_TREE) + return; + + /* Handle a bare RESULT_DECL. This will handle for types needed + constructors, or possibly after NRV type optimizations. */ + if (is_sra_candidate_decl (op)) + emit_scalar_copies (si_p, op, op, FIELD_SCALAR); + else if (TREE_CODE (op) == MODIFY_EXPR) + { + tree *rhs_p = &TREE_OPERAND (op, 1); + tree rhs = *rhs_p; + + /* Handle 'return STRUCTURE;' */ + if (is_sra_candidate_decl (rhs)) + emit_scalar_copies (si_p, rhs, rhs, FIELD_SCALAR); + + /* Handle 'return STRUCTURE.FIELD;' */ + else if (is_sra_candidate_ref (rhs, false)) + scalarize_component_ref (stmt, rhs_p); + + /* Handle 'return CALL_EXPR;' */ + else if (TREE_CODE (rhs) == CALL_EXPR) + { + struct bitmap_head_def done_head; + bitmap_initialize (&done_head, 1); + scalarize_tree_list (TREE_OPERAND (rhs, 1), si_p, &done_head); + bitmap_clear (&done_head); + } + } +} + + +/* Debugging dump for the scalar replacement map. */ + +static int +dump_sra_map_trav (void **slot, void *data) +{ + struct sra_elt *e = *slot; + FILE *f = data; + + switch (e->kind) + { + case REALPART_EXPR: + fputs ("__real__ ", f); + print_generic_expr (dump_file, e->base, dump_flags); + fprintf (f, " -> %s\n", get_name (e->replace)); + break; + case IMAGPART_EXPR: + fputs ("__imag__ ", f); + print_generic_expr (dump_file, e->base, dump_flags); + fprintf (f, " -> %s\n", get_name (e->replace)); + break; + case COMPONENT_REF: + print_generic_expr (dump_file, e->base, dump_flags); + fprintf (f, ".%s -> %s\n", get_name (e->field), get_name (e->replace)); + break; + default: + abort (); + } + + return 1; +} + +static void +dump_sra_map (FILE *f) +{ + fputs ("Scalar replacements:\n", f); + htab_traverse_noresize (sra_map, dump_sra_map_trav, f); + fputs ("\n\n", f); +} + +/* Main entry point to Scalar Replacement of Aggregates (SRA). This pass + re-writes non-aliased structure references into scalar temporaries. The + goal is to expose some/all structures to the scalar optimizers. + + FNDECL is the function to process. + + VARS_TO_RENAME_P is a pointer to the set of variables that need to be + renamed into SSA after this pass is done. These are going to be all the + new scalars created by the SRA process. Notice that since this pass + creates new variables, the bitmap representing all the variables in the + program will be re-sized here. + + PHASE indicates which dump file from the DUMP_FILES array to use when + dumping debugging information. + + TODO + + 1- Scalarize COMPLEX_TYPEs + 2- Scalarize ARRAY_REFs that are always referenced with a + constant index. + 3- Timings to determine when scalarization is not profitable. + 4- Determine what's a good value for MAX_NFIELDS_FOR_SRA. */ + +static void +tree_sra (void) +{ + /* Initialize local variables. */ + sra_candidates = BITMAP_XMALLOC (); + sra_map = NULL; + needs_copy_in = NULL; + + /* Find structures to be scalarized. */ + if (!find_candidates_for_sra ()) + { + BITMAP_XFREE (sra_candidates); + return; + } + + /* If we found any, re-write structure references with their + corresponding scalar replacement. */ + sra_map = htab_create (101, sra_elt_hash, sra_elt_eq, free); + needs_copy_in = BITMAP_XMALLOC (); + + scalarize_structures (); + + if (dump_file) + dump_sra_map (dump_file); + + /* Free allocated memory. */ + htab_delete (sra_map); + sra_map = NULL; + BITMAP_XFREE (needs_copy_in); + BITMAP_XFREE (sra_candidates); +} + +static bool +gate_sra (void) +{ + return flag_tree_sra != 0; +} + +struct tree_opt_pass pass_sra = +{ + "sra", /* name */ + gate_sra, /* gate */ + tree_sra, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_SRA, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_rename_vars + | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ +}; diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c new file mode 100644 index 00000000000..6746f4e5ac5 --- /dev/null +++ b/gcc/tree-ssa-alias.c @@ -0,0 +1,2118 @@ +/* Alias analysis for trees. + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "timevar.h" +#include "expr.h" +#include "ggc.h" +#include "langhooks.h" +#include "flags.h" +#include "function.h" +#include "diagnostic.h" +#include "tree-dump.h" +#include "tree-simple.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "tree-alias-common.h" +#include "tree-pass.h" +#include "convert.h" +#include "params.h" + + +/* Structure to map a variable to its alias set and keep track of the + virtual operands that will be needed to represent it. */ +struct alias_map_d +{ + /* Variable and its alias set. */ + tree var; + HOST_WIDE_INT set; + + /* Total number of virtual operands that will be needed to represent + all the aliases of VAR. */ + long total_alias_vops; + + /* Nonzero if the aliases for this memory tag have been grouped + already. Used in group_aliases. */ + unsigned int grouped_p : 1; + + /* Set of variables aliased with VAR. This is the exact same + information contained in VAR_ANN (VAR)->MAY_ALIASES, but in + bitmap form to speed up alias grouping. */ + sbitmap may_aliases; +}; + + +/* Alias information used by compute_may_aliases and its helpers. */ +struct alias_info +{ + /* SSA names visited while collecting points-to information. If bit I + is set, it means that SSA variable with version I has already been + visited. */ + bitmap ssa_names_visited; + + /* Array of SSA_NAME pointers processed by the points-to collector. */ + varray_type processed_ptrs; + + /* Variables whose address is still needed. */ + bitmap addresses_needed; + + /* ADDRESSABLE_VARS contains all the global variables and locals that + have had their address taken. */ + struct alias_map_d **addressable_vars; + size_t num_addressable_vars; + + /* POINTERS contains all the _DECL pointers with unique memory tags + that have been referenced in the program. */ + struct alias_map_d **pointers; + size_t num_pointers; + + /* Number of function calls found in the program. */ + size_t num_calls_found; + + /* Array of counters to keep track of how many times each pointer has + been dereferenced in the program. This is used by the alias grouping + heuristic in compute_flow_insensitive_aliasing. */ + varray_type num_references; + + /* Total number of virtual operands that will be needed to represent + all the aliases of all the pointers found in the program. */ + long total_alias_vops; + + /* Variables that have been written to. */ + bitmap written_vars; + + /* Pointers that have been used in an indirect store operation. */ + bitmap dereferenced_ptrs_store; + + /* Pointers that have been used in an indirect load operation. */ + bitmap dereferenced_ptrs_load; +}; + + +/* Counters used to display statistics on alias analysis. */ +struct alias_stats_d +{ + unsigned int alias_queries; + unsigned int alias_mayalias; + unsigned int alias_noalias; + unsigned int simple_queries; + unsigned int simple_resolved; + unsigned int tbaa_queries; + unsigned int tbaa_resolved; + unsigned int pta_queries; + unsigned int pta_resolved; +}; + + +/* Local variables. */ +static struct alias_stats_d alias_stats; + +/* Local functions. */ +static void compute_flow_insensitive_aliasing (struct alias_info *); +static void dump_alias_stats (FILE *); +static bool may_alias_p (tree, HOST_WIDE_INT, tree, HOST_WIDE_INT); +static tree create_memory_tag (tree type, bool is_type_tag); +static tree get_tmt_for (tree, struct alias_info *); +static tree get_nmt_for (tree); +static void add_may_alias (tree, tree); +static struct alias_info *init_alias_info (void); +static void delete_alias_info (struct alias_info *); +static void compute_points_to_and_addr_escape (struct alias_info *); +static void compute_flow_sensitive_aliasing (struct alias_info *); +static void setup_pointers_and_addressables (struct alias_info *); +static bool collect_points_to_info_r (tree, tree, void *); +static bool is_escape_site (tree, size_t *); +static void add_pointed_to_var (struct alias_info *, tree, tree); +static void add_pointed_to_expr (tree, tree); +static void create_global_var (void); +static void collect_points_to_info_for (struct alias_info *, tree); +static bool ptr_is_dereferenced_by (tree, tree, bool *); +static void maybe_create_global_var (struct alias_info *ai); +static void group_aliases (struct alias_info *); + +/* Global declarations. */ + +/* Call clobbered variables in the function. If bit I is set, then + REFERENCED_VARS (I) is call-clobbered. */ +bitmap call_clobbered_vars; + +/* 'true' after aliases have been computed (see compute_may_aliases). This + is used by get_stmt_operands and its helpers to determine what to do + when scanning an operand for a variable that may be aliased. If + may-alias information is still not available, the statement is marked as + having volatile operands. */ +bool aliases_computed_p; + +/* When the program has too many call-clobbered variables and call-sites, + this variable is used to represent the clobbering effects of function + calls. In these cases, all the call clobbered variables in the program + are forced to alias this variable. This reduces compile times by not + having to keep track of too many VDEF expressions at call sites. */ +tree global_var; + + +/* Compute may-alias information for every variable referenced in function + FNDECL. + + Alias analysis proceeds in 3 main phases: + + 1- Points-to and escape analysis. + + This phase walks the use-def chains in the SSA web looking for three + things: + + * Assignments of the form P_i = &VAR + * Assignments of the form P_i = malloc() + * Pointers and ADDR_EXPR that escape the current function. + + The concept of 'escaping' is the same one used in the Java world. When + a pointer or an ADDR_EXPR escapes, it means that it has been exposed + outside of the current function. So, assignment to global variables, + function arguments and returning a pointer are all escape sites. + + This is where we are currently limited. Since not everything is renamed + into SSA, we lose track of escape properties when a pointer is stashed + inside a field in a structure, for instance. In those cases, we are + assuming that the pointer does escape. + + We use escape analysis to determine whether a variable is + call-clobbered. Simply put, if an ADDR_EXPR escapes, then the variable + is call-clobbered. If a pointer P_i escapes, then all the variables + pointed-to by P_i (and its memory tag) also escape. + + 2- Compute flow-sensitive aliases + + We have two classes of memory tags. Memory tags associated with the + pointed-to data type of the pointers in the program. These tags are + called "type memory tag" (TMT). The other class are those associated + with SSA_NAMEs, called "name memory tag" (NMT). The basic idea is that + when adding operands for an INDIRECT_REF *P_i, we will first check + whether P_i has a name tag, if it does we use it, because that will have + more precise aliasing information. Otherwise, we use the standard type + tag. + + In this phase, we go through all the pointers we found in points-to + analysis and create alias sets for the name memory tags associated with + each pointer P_i. If P_i escapes, we mark call-clobbered the variables + it points to and its tag. + + + 3- Compute flow-insensitive aliases + + This pass will compare the alias set of every type memory tag and every + addressable variable found in the program. Given a type memory tag TMT + and an addressable variable V. If the alias sets of TMT and V conflict + (as computed by may_alias_p), then V is marked as an alias tag and added + to the alias set of TMT. + + For instance, consider the following function: + + foo (int i) + { + int *p, *q, a, b; + + if (i > 10) + p = &a; + else + q = &b; + + *p = 3; + *q = 5; + a = b + 2; + return *p; + } + + After aliasing analysis has finished, the type memory tag for pointer + 'p' will have two aliases, namely variables 'a' and 'b'. Every time + pointer 'p' is dereferenced, we want to mark the operation as a + potential reference to 'a' and 'b'. + + foo (int i) + { + int *p, a, b; + + if (i_2 > 10) + p_4 = &a; + else + p_6 = &b; + # p_1 = PHI ; + + # a_7 = VDEF ; + # b_8 = VDEF ; + *p_1 = 3; + + # a_9 = VDEF + # VUSE + a_9 = b_8 + 2; + + # VUSE ; + # VUSE ; + return *p_1; + } + + In certain cases, the list of may aliases for a pointer may grow too + large. This may cause an explosion in the number of virtual operands + inserted in the code. Resulting in increased memory consumption and + compilation time. + + When the number of virtual operands needed to represent aliased + loads and stores grows too large (configurable with @option{--param + max-aliased-vops}), alias sets are grouped to avoid severe + compile-time slow downs and memory consumption. See group_aliases. */ + +static void +compute_may_aliases (void) +{ + struct alias_info *ai; + + memset (&alias_stats, 0, sizeof (alias_stats)); + + /* Initialize aliasing information. */ + ai = init_alias_info (); + + /* For each pointer P_i, determine the sets of variables that P_i may + point-to. For every addressable variable V, determine whether the + address of V escapes the current function, making V call-clobbered + (i.e., whether &V is stored in a global variable or if its passed as a + function call argument). */ + compute_points_to_and_addr_escape (ai); + + /* Collect all pointers and addressable variables, compute alias sets, + create memory tags for pointers and promote variables whose address is + not needed anymore. */ + setup_pointers_and_addressables (ai); + + /* Compute flow-sensitive, points-to based aliasing for all the name + memory tags. Note that this pass needs to be done before flow + insensitive analysis because it uses the points-to information + gathered before to mark call-clobbered type tags. */ + compute_flow_sensitive_aliasing (ai); + + /* Compute type-based flow-insensitive aliasing for all the type + memory tags. */ + compute_flow_insensitive_aliasing (ai); + + /* If the program has too many call-clobbered variables and/or function + calls, create .GLOBAL_VAR and use it to model call-clobbering + semantics at call sites. This reduces the number of virtual operands + considerably, improving compile times at the expense of lost + aliasing precision. */ + maybe_create_global_var (ai); + + /* Debugging dumps. */ + if (dump_file) + { + dump_referenced_vars (dump_file); + if (dump_flags & TDF_STATS) + dump_alias_stats (dump_file); + dump_points_to_info (dump_file); + dump_alias_info (dump_file); + } + + /* Deallocate memory used by aliasing data structures. */ + delete_alias_info (ai); + + /* Indicate that may-alias information is now available. */ + aliases_computed_p = true; +} + +struct tree_opt_pass pass_may_alias = +{ + "alias", /* name */ + NULL, /* gate */ + compute_may_aliases, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_MAY_ALIAS, /* tv_id */ + PROP_cfg | PROP_ssa | PROP_pta, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_rename_vars + | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ +}; + + +/* Initialize the data structures used for alias analysis. */ + +static struct alias_info * +init_alias_info (void) +{ + struct alias_info *ai; + + ai = xcalloc (1, sizeof (struct alias_info)); + ai->ssa_names_visited = BITMAP_XMALLOC (); + VARRAY_TREE_INIT (ai->processed_ptrs, 50, "processed_ptrs"); + ai->addresses_needed = BITMAP_XMALLOC (); + VARRAY_UINT_INIT (ai->num_references, num_referenced_vars, "num_references"); + ai->written_vars = BITMAP_XMALLOC (); + ai->dereferenced_ptrs_store = BITMAP_XMALLOC (); + ai->dereferenced_ptrs_load = BITMAP_XMALLOC (); + + return ai; +} + + +/* Deallocate memory used by alias analysis. */ + +static void +delete_alias_info (struct alias_info *ai) +{ + size_t i; + + BITMAP_FREE (ai->ssa_names_visited); + ai->processed_ptrs = NULL; + BITMAP_FREE (ai->addresses_needed); + + for (i = 0; i < ai->num_addressable_vars; i++) + { + sbitmap_free (ai->addressable_vars[i]->may_aliases); + free (ai->addressable_vars[i]); + } + free (ai->addressable_vars); + + for (i = 0; i < ai->num_pointers; i++) + { + sbitmap_free (ai->pointers[i]->may_aliases); + free (ai->pointers[i]); + } + free (ai->pointers); + + ai->num_references = NULL; + BITMAP_FREE (ai->written_vars); + BITMAP_FREE (ai->dereferenced_ptrs_store); + BITMAP_FREE (ai->dereferenced_ptrs_load); + + free (ai); +} + + +/* Walk use-def chains for pointer PTR to determine what variables is PTR + pointing to. */ + +static void +collect_points_to_info_for (struct alias_info *ai, tree ptr) +{ +#if defined ENABLE_CHECKING + if (!POINTER_TYPE_P (TREE_TYPE (ptr))) + abort (); +#endif + + if (!bitmap_bit_p (ai->ssa_names_visited, SSA_NAME_VERSION (ptr))) + { + ssa_name_ann_t ann; + + bitmap_set_bit (ai->ssa_names_visited, SSA_NAME_VERSION (ptr)); + walk_use_def_chains (ptr, collect_points_to_info_r, ai); + + VARRAY_PUSH_TREE (ai->processed_ptrs, ptr); + + /* If we could not determine where PTR was pointing to, clear all the + other points-to information. */ + ann = ssa_name_ann (ptr); + if (ann->pt_anything) + { + ann->pt_malloc = 0; + ann->pt_vars = NULL; + } + } +} + + +/* Helper for ptr_is_dereferenced_by. Called by walk_tree to look for + INDIRECT_REF nodes for the pointer passed in DATA. */ + +static tree +find_ptr_dereference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data) +{ + tree ptr = (tree) data; + + if (TREE_CODE (*tp) == INDIRECT_REF + && TREE_OPERAND (*tp, 0) == ptr) + return *tp; + + return NULL_TREE; +} + + +/* Return true if STMT contains INDIRECT_REF . *IS_STORE is set + to 'true' if the dereference is on the LHS of an assignment. */ + +static bool +ptr_is_dereferenced_by (tree ptr, tree stmt, bool *is_store) +{ + *is_store = false; + + if (TREE_CODE (stmt) == MODIFY_EXPR + || (TREE_CODE (stmt) == RETURN_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)) + { + tree e, lhs, rhs; + + e = (TREE_CODE (stmt) == RETURN_EXPR) ? TREE_OPERAND (stmt, 0) : stmt; + lhs = TREE_OPERAND (e, 0); + rhs = TREE_OPERAND (e, 1); + + if (EXPR_P (lhs) + && walk_tree (&lhs, find_ptr_dereference, ptr, NULL)) + { + *is_store = true; + return true; + } + else if (EXPR_P (rhs) + && walk_tree (&rhs, find_ptr_dereference, ptr, NULL)) + { + return true; + } + } + else if (TREE_CODE (stmt) == ASM_EXPR) + { + if (walk_tree (&ASM_OUTPUTS (stmt), find_ptr_dereference, ptr, NULL) + || walk_tree (&ASM_CLOBBERS (stmt), find_ptr_dereference, ptr, NULL)) + { + *is_store = true; + return true; + } + else if (walk_tree (&ASM_INPUTS (stmt), find_ptr_dereference, ptr, NULL)) + { + return true; + } + } + + return false; +} + + +/* Traverse use-def links for all the pointers in the program to collect + address escape and points-to information. + + This is loosely based on the same idea described in R. Hasti and S. + Horwitz, ``Using static single assignment form to improve + flow-insensitive pointer analysis,'' in SIGPLAN Conference on + Programming Language Design and Implementation, pp. 97-105, 1998. */ + +static void +compute_points_to_and_addr_escape (struct alias_info *ai) +{ + basic_block bb; + size_t i; + + timevar_push (TV_TREE_PTA); + + FOR_EACH_BB (bb) + { + bb_ann_t block_ann = bb_ann (bb); + block_stmt_iterator si; + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + use_optype uses; + def_optype defs; + vdef_optype vdefs; + stmt_ann_t ann; + bitmap addr_taken; + tree stmt = bsi_stmt (si); + bool stmt_escapes_p = is_escape_site (stmt, &ai->num_calls_found); + + /* Mark all the variables whose address are taken by the + statement. Note that this will miss all the addresses taken + in PHI nodes (those are discovered while following the use-def + chains). */ + get_stmt_operands (stmt); + addr_taken = addresses_taken (stmt); + if (addr_taken) + EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, + { + tree var = referenced_var (i); + bitmap_set_bit (ai->addresses_needed, var_ann (var)->uid); + if (stmt_escapes_p) + mark_call_clobbered (var); + }); + + if (stmt_escapes_p) + block_ann->has_escape_site = 1; + + /* Special case for silly ADDR_EXPR tricks. If this + statement is an assignment to a non-pointer variable and + the RHS takes the address of a variable, assume that the + variable on the RHS is call-clobbered. We could add the + LHS to the list of "pointers" and follow it to see if it + really escapes, but it's not worth the pain. */ + if (addr_taken + && TREE_CODE (stmt) == MODIFY_EXPR + && !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 0)))) + EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, + { + tree var = referenced_var (i); + mark_call_clobbered (var); + }); + + ann = stmt_ann (stmt); + uses = USE_OPS (ann); + for (i = 0; i < NUM_USES (uses); i++) + { + tree op = USE_OP (uses, i); + var_ann_t v_ann = var_ann (SSA_NAME_VAR (op)); + ssa_name_ann_t ptr_ann; + bool is_store; + + /* If the operand's variable may be aliased, keep track + of how many times we've referenced it. This is used + for alias grouping in compute_flow_sensitive_aliasing. + Note that we don't need to grow AI->NUM_REFERENCES + because we are processing regular variables, not + memory tags (the array's initial size is set to + NUM_REFERENCED_VARS). */ + if (may_be_aliased (SSA_NAME_VAR (op))) + (VARRAY_UINT (ai->num_references, v_ann->uid))++; + + if (!POINTER_TYPE_P (TREE_TYPE (op))) + continue; + + collect_points_to_info_for (ai, op); + + ptr_ann = ssa_name_ann (op); + if (ptr_is_dereferenced_by (op, stmt, &is_store)) + { + /* If we found OP to point to a set of variables or + malloc, then create a name memory tag for it. This + gives more precise aliasing information, which helps + the optimizers. + + FIXME: Cycles in the SSA web and the lack of SSA + information for structures will prevent the creation + of name tags. Find ways around this limitation. */ + if (ptr_ann->pt_malloc || ptr_ann->pt_vars) + ptr_ann->name_mem_tag = get_nmt_for (op); + + /* Keep track of how many time we've dereferenced each + pointer. Again, we don't need to grow + AI->NUM_REFERENCES because we're processing + existing program variables. */ + (VARRAY_UINT (ai->num_references, v_ann->uid))++; + + /* If this is a store operation, mark OP as being + dereferenced to store, otherwise mark it as being + dereferenced to load. */ + if (is_store) + bitmap_set_bit (ai->dereferenced_ptrs_store, v_ann->uid); + else + bitmap_set_bit (ai->dereferenced_ptrs_load, v_ann->uid); + } + else if (stmt_escapes_p) + { + /* Note that even if STMT is an escape point, pointer OP + will not escape if it is being dereferenced. That's + why we only check for escape points if OP is not + dereferenced by STMT. */ + ptr_ann->value_escapes_p = 1; + + /* If the statement makes a function call, assume + that pointer OP will be dereferenced in a store + operation inside the called function. */ + if (get_call_expr_in (stmt)) + bitmap_set_bit (ai->dereferenced_ptrs_store, v_ann->uid); + } + } + + /* Update reference counter for definitions to any + potentially aliased variable. This is used in the alias + grouping heuristics. */ + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree op = DEF_OP (defs, i); + tree var = SSA_NAME_VAR (op); + var_ann_t ann = var_ann (var); + bitmap_set_bit (ai->written_vars, ann->uid); + if (may_be_aliased (var)) + (VARRAY_UINT (ai->num_references, ann->uid))++; + } + + /* Mark variables in VDEF operands as being written to. */ + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + tree op = VDEF_OP (vdefs, i); + tree var = SSA_NAME_VAR (op); + var_ann_t ann = var_ann (var); + bitmap_set_bit (ai->written_vars, ann->uid); + } + + /* After promoting variables and computing aliasing we will + need to re-scan most statements. FIXME: Try to minimize the + number of statements re-scanned. It's not really necessary to + re-scan *all* statements. */ + modify_stmt (stmt); + } + } + + timevar_pop (TV_TREE_PTA); +} + + +/* For every pointer P_i in AI->PROCESSED_PTRS, create may-alias sets for + the name memory tag (NMT) associated with P_i. If P_i escapes, then its + name tag and the variables it points-to are call-clobbered. Finally, if + P_i escapes and we could not determine where it points to, then all the + variables in the same alias set as *P_i are marked call-clobbered. This + is necessary because we must assume that P_i may take the address of any + variable in the same alias set. */ + +static void +compute_flow_sensitive_aliasing (struct alias_info *ai) +{ + size_t i; + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ai->processed_ptrs); i++) + { + size_t j; + tree ptr = VARRAY_TREE (ai->processed_ptrs, i); + ssa_name_ann_t ann = ssa_name_ann (ptr); + var_ann_t v_ann = var_ann (SSA_NAME_VAR (ptr)); + + if (ann->value_escapes_p || ann->pt_anything) + { + /* If PTR escapes or may point to anything, then its associated + memory tags are call-clobbered. */ + if (ann->name_mem_tag) + mark_call_clobbered (ann->name_mem_tag); + + if (v_ann->type_mem_tag) + mark_call_clobbered (v_ann->type_mem_tag); + + /* If PTR may point to anything, mark call-clobbered all the + addressables with the same alias set as the type pointed-to by + PTR. */ + if (ann->pt_anything) + { + HOST_WIDE_INT ptr_set; + ptr_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr))); + for (j = 0; j < ai->num_addressable_vars; j++) + { + struct alias_map_d *alias_map = ai->addressable_vars[j]; + if (alias_map->set == ptr_set) + mark_call_clobbered (alias_map->var); + } + } + + /* If PTR's value may escape and PTR is never dereferenced, we + need to mark all the variables PTR points-to as + call-clobbered. Note that we only need do this it PTR is + never dereferenced. If PTR is dereferenced, it will have a + name memory tag, which will have been marked call-clobbered. + This will in turn mark the pointed-to variables as + call-clobbered when we call add_may_alias below. */ + if (ann->value_escapes_p && !ann->name_mem_tag && ann->pt_vars) + EXECUTE_IF_SET_IN_BITMAP (ann->pt_vars, 0, j, + mark_call_clobbered (referenced_var (j))); + } + + /* Set up aliasing information for PTR's name memory tag (if it has + one). Note that only pointers that have been dereferenced will + have a name memory tag. */ + if (ann->name_mem_tag && ann->pt_vars) + EXECUTE_IF_SET_IN_BITMAP (ann->pt_vars, 0, j, + add_may_alias (ann->name_mem_tag, referenced_var (j))); + + /* If the name tag is call clobbered, so is the type tag + associated with the base VAR_DECL. */ + if (ann->name_mem_tag + && v_ann->type_mem_tag + && is_call_clobbered (ann->name_mem_tag)) + mark_call_clobbered (v_ann->type_mem_tag); + } +} + + +/* Compute type-based alias sets. Traverse all the pointers and + addressable variables found in setup_pointers_and_addressables. + + For every pointer P in AI->POINTERS and addressable variable V in + AI->ADDRESSABLE_VARS, add V to the may-alias sets of P's type + memory tag (TMT) if their alias sets conflict. V is then marked as + an alias tag so that the operand scanner knows that statements + containing V have aliased operands. */ + +static void +compute_flow_insensitive_aliasing (struct alias_info *ai) +{ + size_t i; + + /* Initialize counter for the total number of virtual operands that + aliasing will introduce. When AI->TOTAL_ALIAS_VOPS goes beyond the + threshold set by --params max-alias-vops, we enable alias + grouping. */ + ai->total_alias_vops = 0; + + /* For every pointer P, determine which addressable variables may alias + with P's type memory tag. */ + for (i = 0; i < ai->num_pointers; i++) + { + size_t j; + struct alias_map_d *p_map = ai->pointers[i]; + tree tag = var_ann (p_map->var)->type_mem_tag; + var_ann_t tag_ann = var_ann (tag); + + p_map->total_alias_vops = 0; + p_map->may_aliases = sbitmap_alloc (num_referenced_vars); + sbitmap_zero (p_map->may_aliases); + + for (j = 0; j < ai->num_addressable_vars; j++) + { + struct alias_map_d *v_map; + var_ann_t v_ann; + tree var; + bool tag_stored_p, var_stored_p; + + v_map = ai->addressable_vars[j]; + var = v_map->var; + v_ann = var_ann (var); + + /* Skip memory tags and variables that have never been + written to. We also need to check if the variables are + call-clobbered because they may be overwritten by + function calls. */ + tag_stored_p = bitmap_bit_p (ai->written_vars, tag_ann->uid) + || is_call_clobbered (tag); + var_stored_p = bitmap_bit_p (ai->written_vars, v_ann->uid) + || is_call_clobbered (var); + if (!tag_stored_p && !var_stored_p) + continue; + + if (may_alias_p (p_map->var, p_map->set, var, v_map->set)) + { + size_t num_tag_refs, num_var_refs; + + num_tag_refs = VARRAY_UINT (ai->num_references, tag_ann->uid); + num_var_refs = VARRAY_UINT (ai->num_references, v_ann->uid); + + /* Add VAR to TAG's may-aliases set. */ + add_may_alias (tag, var); + + /* Update the total number of virtual operands due to + aliasing. Since we are adding one more alias to TAG's + may-aliases set, the total number of virtual operands due + to aliasing will be increased by the number of references + made to VAR and TAG (every reference to TAG will also + count as a reference to VAR). */ + ai->total_alias_vops += (num_var_refs + num_tag_refs); + p_map->total_alias_vops += (num_var_refs + num_tag_refs); + + /* Update the bitmap used to represent TAG's alias set + in case we need to group aliases. */ + SET_BIT (p_map->may_aliases, var_ann (var)->uid); + } + } + } + + if (dump_file) + fprintf (dump_file, "%s: Total number of aliased vops: %ld\n", + get_name (current_function_decl), + ai->total_alias_vops); + + /* Determine if we need to enable alias grouping. */ + if (ai->total_alias_vops >= MAX_ALIASED_VOPS) + group_aliases (ai); +} + + +/* Comparison function for qsort used in group_aliases. */ + +static int +total_alias_vops_cmp (const void *p, const void *q) +{ + const struct alias_map_d **p1 = (const struct alias_map_d **)p; + const struct alias_map_d **p2 = (const struct alias_map_d **)q; + long n1 = (*p1)->total_alias_vops; + long n2 = (*p2)->total_alias_vops; + + /* We want to sort in descending order. */ + return (n1 > n2 ? -1 : (n1 == n2) ? 0 : 1); +} + +/* Group all the aliases for TAG to make TAG represent all the + variables in its alias set. Update the total number + of virtual operands due to aliasing (AI->TOTAL_ALIAS_VOPS). This + function will make TAG be the unique alias tag for all the + variables in its may-aliases. So, given: + + may-aliases(TAG) = { V1, V2, V3 } + + This function will group the variables into: + + may-aliases(V1) = { TAG } + may-aliases(V2) = { TAG } + may-aliases(V2) = { TAG } */ + +static void +group_aliases_into (tree tag, sbitmap tag_aliases, struct alias_info *ai) +{ + size_t i; + var_ann_t tag_ann = var_ann (tag); + size_t num_tag_refs = VARRAY_UINT (ai->num_references, tag_ann->uid); + + EXECUTE_IF_SET_IN_SBITMAP (tag_aliases, 0, i, + { + tree var = referenced_var (i); + var_ann_t ann = var_ann (var); + + /* Make TAG the unique alias of VAR. */ + ann->is_alias_tag = 0; + ann->may_aliases = NULL; + + /* Note that VAR and TAG may be the same if the function has no + addressable variables (see the discussion at the end of + setup_pointers_and_addressables). */ + if (var != tag) + add_may_alias (var, tag); + + /* Reduce total number of virtual operands contributed + by TAG on behalf of VAR. Notice that the references to VAR + itself won't be removed. We will merely replace them with + references to TAG. */ + ai->total_alias_vops -= num_tag_refs; + }); + + /* We have reduced the number of virtual operands that TAG makes on + behalf of all the variables formerly aliased with it. However, + we have also "removed" all the virtual operands for TAG itself, + so we add them back. */ + ai->total_alias_vops += num_tag_refs; + + /* TAG no longer has any aliases. */ + tag_ann->may_aliases = NULL; +} + + +/* Group may-aliases sets to reduce the number of virtual operands due + to aliasing. + + 1- Sort the list of pointers in decreasing number of contributed + virtual operands. + + 2- Take the first entry in AI->POINTERS and revert the role of + the memory tag and its aliases. Usually, whenever an aliased + variable Vi is found to alias with a memory tag T, we add Vi + to the may-aliases set for T. Meaning that after alias + analysis, we will have: + + may-aliases(T) = { V1, V2, V3, ..., Vn } + + This means that every statement that references T, will get 'n' + virtual operands for each of the Vi tags. But, when alias + grouping is enabled, we make T an alias tag and add it to the + alias set of all the Vi variables: + + may-aliases(V1) = { T } + may-aliases(V2) = { T } + ... + may-aliases(Vn) = { T } + + This has two effects: (a) statements referencing T will only get + a single virtual operand, and, (b) all the variables Vi will now + appear to alias each other. So, we lose alias precision to + improve compile time. But, in theory, a program with such a high + level of aliasing should not be very optimizable in the first + place. + + 3- Since variables may be in the alias set of more than one + memory tag, the grouping done in step (2) needs to be extended + to all the memory tags that have a non-empty intersection with + the may-aliases set of tag T. For instance, if we originally + had these may-aliases sets: + + may-aliases(T) = { V1, V2, V3 } + may-aliases(R) = { V2, V4 } + + In step (2) we would have reverted the aliases for T as: + + may-aliases(V1) = { T } + may-aliases(V2) = { T } + may-aliases(V3) = { T } + + But note that now V2 is no longer aliased with R. We could + add R to may-aliases(V2), but we are in the process of + grouping aliases to reduce virtual operands so what we do is + add V4 to the grouping to obtain: + + may-aliases(V1) = { T } + may-aliases(V2) = { T } + may-aliases(V3) = { T } + may-aliases(V4) = { T } + + 4- If the total number of virtual operands due to aliasing is + still above the threshold set by max-alias-vops, go back to (2). */ + +static void +group_aliases (struct alias_info *ai) +{ + size_t i; + sbitmap res; + + /* Sort the POINTERS array in descending order of contributed + virtual operands. */ + qsort (ai->pointers, ai->num_pointers, sizeof (struct alias_map_d *), + total_alias_vops_cmp); + + res = sbitmap_alloc (num_referenced_vars); + + /* For every pointer in AI->POINTERS, reverse the roles of its tag + and the tag's may-aliases set. */ + for (i = 0; i < ai->num_pointers; i++) + { + size_t j; + tree tag1 = var_ann (ai->pointers[i]->var)->type_mem_tag; + sbitmap tag1_aliases = ai->pointers[i]->may_aliases; + + /* Skip tags that have been grouped already. */ + if (ai->pointers[i]->grouped_p) + continue; + + /* See if TAG1 had any aliases in common with other type tags. + If we find a TAG2 with common aliases with TAG1, add TAG2's + aliases into TAG1. */ + for (j = i + 1; j < ai->num_pointers; j++) + { + sbitmap tag2_aliases = ai->pointers[j]->may_aliases; + + sbitmap_a_and_b (res, tag1_aliases, tag2_aliases); + if (sbitmap_first_set_bit (res) >= 0) + { + tree tag2 = var_ann (ai->pointers[j]->var)->type_mem_tag; + + sbitmap_a_or_b (tag1_aliases, tag1_aliases, tag2_aliases); + + /* TAG2 does not need its aliases anymore. */ + sbitmap_zero (tag2_aliases); + var_ann (tag2)->may_aliases = NULL; + + /* TAG1 is the unique alias of TAG2. */ + add_may_alias (tag2, tag1); + + ai->pointers[j]->grouped_p = true; + } + } + + /* Now group all the aliases we collected into TAG1. */ + group_aliases_into (tag1, tag1_aliases, ai); + + /* If we've reduced total number of virtual operands below the + threshold, stop. */ + if (ai->total_alias_vops < MAX_ALIASED_VOPS) + break; + } + + /* Finally, all the variables that have been grouped cannot be in + the may-alias set of name memory tags. Suppose that we have + grouped the aliases in this code so that may-aliases(a) = TMT.20 + + p_5 = &a; + ... + # a_9 = VDEF + p_5->field = 0 + ... Several modifications to TMT.20 ... + # VUSE + x_30 = p_5->field + + Since p_5 points to 'a', the optimizers will try to propagate 0 + into p_5->field, but that is wrong because there have been + modifications to 'TMT.20' in between. To prevent this we have to + replace 'a' with 'TMT.20' in the name tag of p_5. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (ai->processed_ptrs); i++) + { + size_t j; + tree ptr = VARRAY_TREE (ai->processed_ptrs, i); + tree name_tag = ssa_name_ann (ptr)->name_mem_tag; + varray_type aliases; + + if (name_tag == NULL_TREE) + continue; + + aliases = var_ann (name_tag)->may_aliases; + for (j = 0; aliases && j < VARRAY_ACTIVE_SIZE (aliases); j++) + { + tree alias = VARRAY_TREE (aliases, j); + var_ann_t ann = var_ann (alias); + if (ann->may_aliases) + { +#if defined ENABLE_CHECKING + if (VARRAY_ACTIVE_SIZE (ann->may_aliases) != 1) + abort (); +#endif + VARRAY_TREE (aliases, j) = VARRAY_TREE (ann->may_aliases, 0); + } + } + } + + sbitmap_free (res); + + if (dump_file) + fprintf (dump_file, + "%s: Total number of aliased vops after grouping: %ld%s\n", + get_name (current_function_decl), + ai->total_alias_vops, + (ai->total_alias_vops < 0) ? " (negative values are OK)" : ""); +} + + +/* Create a new alias set entry for VAR in AI->ADDRESSABLE_VARS. */ + +static void +create_alias_map_for (tree var, struct alias_info *ai) +{ + struct alias_map_d *alias_map; + alias_map = xcalloc (1, sizeof (*alias_map)); + alias_map->var = var; + + if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE) + alias_map->set = get_alias_set (TREE_TYPE (TREE_TYPE (var))); + else + alias_map->set = get_alias_set (var); + ai->addressable_vars[ai->num_addressable_vars++] = alias_map; +} + + +/* Create memory tags for all the dereferenced pointers and build the + ADDRESSABLE_VARS and POINTERS arrays used for building the may-alias + sets. Based on the address escape and points-to information collected + earlier, this pass will also clear the TREE_ADDRESSABLE flag from those + variables whose address is not needed anymore. */ + +static void +setup_pointers_and_addressables (struct alias_info *ai) +{ + size_t i, n_vars, num_addressable_vars, num_pointers; + + /* Size up the arrays ADDRESSABLE_VARS and POINTERS. */ + num_addressable_vars = num_pointers = 0; + for (i = 0; i < num_referenced_vars; i++) + { + tree var = referenced_var (i); + + if (may_be_aliased (var)) + num_addressable_vars++; + + if (POINTER_TYPE_P (TREE_TYPE (var))) + { + /* Since we don't keep track of volatile variables nor + variables with hidden uses, assume that these pointers + are used in indirect store operations. */ + var_ann_t ann = var_ann (var); + if (TREE_THIS_VOLATILE (var) || ann->has_hidden_use) + bitmap_set_bit (ai->dereferenced_ptrs_store, ann->uid); + + num_pointers++; + } + } + + /* Create ADDRESSABLE_VARS and POINTERS. Note that these arrays are + always going to be slightly bigger than we actually need them + because some TREE_ADDRESSABLE variables will be marked + non-addressable below and only pointers with unique type tags are + going to be added to POINTERS. */ + ai->addressable_vars = xcalloc (num_addressable_vars, + sizeof (struct alias_map_d *)); + ai->pointers = xcalloc (num_pointers, sizeof (struct alias_map_d *)); + ai->num_addressable_vars = 0; + ai->num_pointers = 0; + + /* Since we will be creating type memory tags within this loop, cache the + value of NUM_REFERENCED_VARS to avoid processing the additional tags + unnecessarily. */ + n_vars = num_referenced_vars; + + for (i = 0; i < n_vars; i++) + { + tree var = referenced_var (i); + var_ann_t v_ann = var_ann (var); + + /* Name memory tags already have flow-sensitive aliasing information, so + they need not be processed by compute_may_aliases. Similarly, + type memory tags are already accounted for when we process their + associated pointer. */ + if (v_ann->mem_tag_kind != NOT_A_TAG) + continue; + + /* Remove the ADDRESSABLE flag from every addressable variable whose + address is not needed anymore. This is caused by the propagation + of ADDR_EXPR constants into INDIRECT_REF expressions and the + removal of dead pointer assignments done by the early scalar + cleanup passes. */ + if (TREE_ADDRESSABLE (var)) + { + if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid) + && !v_ann->has_hidden_use + && v_ann->mem_tag_kind == NOT_A_TAG + && !needs_to_live_in_memory (var)) + { + /* The address of VAR is not needed, remove the addressable bit, + so that it can be optimized as a regular variable. */ + mark_non_addressable (var); + + /* Since VAR is now a regular GIMPLE register, we will need + to rename VAR into SSA afterwards. */ + bitmap_set_bit (vars_to_rename, v_ann->uid); + } + } + + /* Global variables and addressable locals may be aliased. Create an + entry in ADDRESSABLE_VARS for VAR. */ + if (may_be_aliased (var)) + { + create_alias_map_for (var, ai); + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + + /* Add pointer variables that have been dereferenced to the POINTERS + array and create a type memory tag for them. */ + if (POINTER_TYPE_P (TREE_TYPE (var)) + && (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid) + || bitmap_bit_p (ai->dereferenced_ptrs_load, v_ann->uid))) + { + tree tag = v_ann->type_mem_tag; + var_ann_t t_ann; + + /* If pointer VAR still doesn't have a memory tag associated with it, + create it now or re-use an existing one. */ + if (tag == NULL_TREE) + tag = get_tmt_for (var, ai); + t_ann = var_ann (tag); + + /* Associate the tag with pointer VAR. */ + v_ann->type_mem_tag = tag; + + /* If pointer VAR has been used in a store operation, then its + memory tag must be marked as written-to. */ + if (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid)) + bitmap_set_bit (ai->written_vars, t_ann->uid); + + /* If pointer VAR is a global variable or a PARM_DECL, then its + memory tag should be considered a global variable. */ + if (TREE_CODE (var) == PARM_DECL || needs_to_live_in_memory (var)) + mark_call_clobbered (tag); + + /* All the dereferences of pointer VAR count as references of + TAG. Since TAG can be associated with several pointers, add + the dereferences of VAR to the TAG. We may need to grow + AI->NUM_REFERENCES because we have been adding name and + type tags. */ + if (t_ann->uid >= VARRAY_SIZE (ai->num_references)) + VARRAY_GROW (ai->num_references, t_ann->uid + 10); + + VARRAY_UINT (ai->num_references, t_ann->uid) + += VARRAY_UINT (ai->num_references, v_ann->uid); + } + } + + /* If we found no addressable variables, but we have more than one + pointer, we will need to check for conflicts between the + pointers. Otherwise, we would miss alias relations as in + testsuite/gcc.dg/tree-ssa/20040319-1.c: + + struct bar { int count; int *arr;}; + + void foo (struct bar *b) + { + b->count = 0; + *(b->arr) = 2; + if (b->count == 0) + abort (); + } + + b->count and *(b->arr) could be aliased if b->arr == &b->count. + To do this, we add all the memory tags for the pointers in + AI->POINTERS to AI->ADDRESSABLE_VARS, so that + compute_flow_insensitive_aliasing will naturally compare every + pointer to every type tag. */ + if (ai->num_addressable_vars == 0 + && ai->num_pointers > 1) + { + free (ai->addressable_vars); + ai->addressable_vars = xcalloc (ai->num_pointers, + sizeof (struct alias_map_d *)); + ai->num_addressable_vars = 0; + for (i = 0; i < ai->num_pointers; i++) + { + struct alias_map_d *p = ai->pointers[i]; + tree tag = var_ann (p->var)->type_mem_tag; + create_alias_map_for (tag, ai); + } + } +} + + +/* Determine whether to use .GLOBAL_VAR to model call clobbering semantics. At + every call site, we need to emit VDEF expressions to represent the + clobbering effects of the call for variables whose address escapes the + current function. + + One approach is to group all call-clobbered variables into a single + representative that is used as an alias of every call-clobbered variable + (.GLOBAL_VAR). This works well, but it ties the optimizer hands because + references to any call clobbered variable is a reference to .GLOBAL_VAR. + + The second approach is to emit a clobbering VDEF for every call-clobbered + variable at call sites. This is the preferred way in terms of optimization + opportunities but it may create too many VDEF operands if there are many + call clobbered variables and function calls in the function. + + To decide whether or not to use .GLOBAL_VAR we multiply the number of + function calls found by the number of call-clobbered variables. If that + product is beyond a certain threshold, as determined by the parameterized + values shown below, we use .GLOBAL_VAR. + + FIXME. This heuristic should be improved. One idea is to use several + .GLOBAL_VARs of different types instead of a single one. The thresholds + have been derived from a typical bootstrap cycle, including all target + libraries. Compile times were found increase by ~1% compared to using + .GLOBAL_VAR. */ + +static void +maybe_create_global_var (struct alias_info *ai) +{ + size_t i, n_clobbered; + + /* Count all the call-clobbered variables. */ + n_clobbered = 0; + EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, n_clobbered++); + + /* Create .GLOBAL_VAR if we have too many call-clobbered variables. + We also create .GLOBAL_VAR when there no call-clobbered variables + to prevent code motion transformations from re-arranging function + calls that may have side effects. For instance, + + foo () + { + int a = f (); + g (); + h (a); + } + + There are no call-clobbered variables in foo(), so it would be + entirely possible for a pass to want to move the call to f() + after the call to g(). If f() has side effects, that would be + wrong. Creating .GLOBAL_VAR in this case will insert VDEFs for + it and prevent such transformations. */ + if (n_clobbered == 0 + || ai->num_calls_found * n_clobbered >= (size_t) GLOBAL_VAR_THRESHOLD) + create_global_var (); + + /* If the function has calls to clobbering functions and .GLOBAL_VAR has + been created, make it an alias for all call-clobbered variables. */ + if (global_var) + EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, + { + tree var = referenced_var (i); + if (var != global_var) + { + add_may_alias (var, global_var); + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + }); +} + + +/* Return TRUE if pointer PTR may point to variable VAR. + + MEM_ALIAS_SET is the alias set for the memory location pointed-to by PTR + This is needed because when checking for type conflicts we are + interested in the alias set of the memory location pointed-to by + PTR. The alias set of PTR itself is irrelevant. + + VAR_ALIAS_SET is the alias set for VAR. */ + +static bool +may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set, + tree var, HOST_WIDE_INT var_alias_set) +{ + tree mem; + var_ann_t v_ann, m_ann; + + alias_stats.alias_queries++; + alias_stats.simple_queries++; + + /* By convention, a variable cannot alias itself. */ + mem = var_ann (ptr)->type_mem_tag; + if (mem == var) + { + alias_stats.alias_noalias++; + alias_stats.simple_resolved++; + return false; + } + + v_ann = var_ann (var); + m_ann = var_ann (mem); + +#if defined ENABLE_CHECKING + if (m_ann->mem_tag_kind != TYPE_TAG) + abort (); +#endif + + alias_stats.tbaa_queries++; + + /* If VAR is a pointer with the same alias set as PTR, then dereferencing + PTR can't possibly affect VAR. Note, that we are specifically testing + for PTR's alias set here, not its pointed-to type. We also can't + do this check with relaxed aliasing enabled. */ + if (POINTER_TYPE_P (TREE_TYPE (var)) + && var_alias_set != 0) + { + HOST_WIDE_INT ptr_alias_set = get_alias_set (ptr); + if (ptr_alias_set == var_alias_set) + { + alias_stats.alias_noalias++; + alias_stats.tbaa_resolved++; + return false; + } + } + + /* If the alias sets don't conflict then MEM cannot alias VAR. */ + if (!alias_sets_conflict_p (mem_alias_set, var_alias_set)) + { + /* Handle aliases to structure fields. If either VAR or MEM are + aggregate types, they may not have conflicting types, but one of + the structures could contain a pointer to the other one. + + For instance, given + + MEM -> struct P *p; + VAR -> struct Q *q; + + It may happen that '*p' and '*q' can't alias because 'struct P' + and 'struct Q' have non-conflicting alias sets. However, it could + happen that one of the fields in 'struct P' is a 'struct Q *' or + vice-versa. + + Therefore, we also need to check if 'struct P' aliases 'struct Q *' + or 'struct Q' aliases 'struct P *'. Notice, that since GIMPLE + does not have more than one-level pointers, we don't need to + recurse into the structures. */ + if (AGGREGATE_TYPE_P (TREE_TYPE (mem)) + || AGGREGATE_TYPE_P (TREE_TYPE (var))) + { + tree ptr_to_var; + + if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE) + ptr_to_var = TYPE_POINTER_TO (TREE_TYPE (TREE_TYPE (var))); + else + ptr_to_var = TYPE_POINTER_TO (TREE_TYPE (var)); + + /* If no pointer-to VAR exists, then MEM can't alias VAR. */ + if (ptr_to_var == NULL_TREE) + { + alias_stats.alias_noalias++; + alias_stats.tbaa_resolved++; + return false; + } + + /* If MEM doesn't alias a pointer to VAR and VAR doesn't alias + PTR, then PTR can't alias VAR. */ + if (!alias_sets_conflict_p (mem_alias_set, get_alias_set (ptr_to_var)) + && !alias_sets_conflict_p (var_alias_set, get_alias_set (ptr))) + { + alias_stats.alias_noalias++; + alias_stats.tbaa_resolved++; + return false; + } + } + else + { + alias_stats.alias_noalias++; + alias_stats.tbaa_resolved++; + return false; + } + } + + if (flag_tree_points_to != PTA_NONE) + alias_stats.pta_queries++; + + /* If -ftree-points-to is given, check if PTR may point to VAR. */ + if (flag_tree_points_to == PTA_ANDERSEN + && !ptr_may_alias_var (ptr, var)) + { + alias_stats.alias_noalias++; + alias_stats.pta_resolved++; + return false; + } + + alias_stats.alias_mayalias++; + return true; +} + + +/* Add ALIAS to the set of variables that may alias VAR. */ + +static void +add_may_alias (tree var, tree alias) +{ + size_t i; + var_ann_t v_ann = get_var_ann (var); + var_ann_t a_ann = get_var_ann (alias); + +#if defined ENABLE_CHECKING + if (var == alias) + abort (); +#endif + + if (v_ann->may_aliases == NULL) + VARRAY_TREE_INIT (v_ann->may_aliases, 2, "aliases"); + + /* Avoid adding duplicates. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (v_ann->may_aliases); i++) + if (alias == VARRAY_TREE (v_ann->may_aliases, i)) + return; + + /* If VAR is a call-clobbered variable, so is its new ALIAS. */ + if (is_call_clobbered (var)) + mark_call_clobbered (alias); + + /* Likewise. If ALIAS is call-clobbered, so is VAR. */ + else if (is_call_clobbered (alias)) + mark_call_clobbered (var); + + VARRAY_PUSH_TREE (v_ann->may_aliases, alias); + a_ann->is_alias_tag = 1; +} + + +/* Given two pointers DEST and ORIG. Merge the points-to information in + ORIG into DEST. AI is as in collect_points_to_info. */ + +static void +merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig) +{ + ssa_name_ann_t dest_ann, orig_ann; + + /* Make sure we have points-to information for ORIG. */ + collect_points_to_info_for (ai, orig); + + dest_ann = get_ssa_name_ann (dest); + orig_ann = ssa_name_ann (orig); + + if (orig_ann) + { + dest_ann->pt_anything |= orig_ann->pt_anything; + dest_ann->pt_malloc |= orig_ann->pt_malloc; + + if (orig_ann->pt_vars) + { + if (dest_ann->pt_vars == NULL) + { + dest_ann->pt_vars = BITMAP_GGC_ALLOC (); + bitmap_copy (dest_ann->pt_vars, orig_ann->pt_vars); + } + else + bitmap_a_or_b (dest_ann->pt_vars, + dest_ann->pt_vars, + orig_ann->pt_vars); + } + } +} + + +/* Add VALUE to the list of expressions pointed-to by PTR. */ + +static void +add_pointed_to_expr (tree ptr, tree value) +{ + ssa_name_ann_t ann; + +#if defined ENABLE_CHECKING + /* Pointer variables should have been handled by merge_pointed_to_info. */ + if (TREE_CODE (value) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (value))) + abort (); +#endif + + ann = get_ssa_name_ann (ptr); + + /* If VALUE is the result of a malloc-like call, then the area pointed to + PTR is guaranteed to not alias with anything else. */ + if (TREE_CODE (value) == CALL_EXPR + && (call_expr_flags (value) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))) + ann->pt_malloc = 1; + else + ann->pt_anything = 1; + + if (dump_file) + { + fprintf (dump_file, "Pointer "); + print_generic_expr (dump_file, ptr, dump_flags); + fprintf (dump_file, " points to "); + if (ann->pt_malloc) + fprintf (dump_file, "malloc space: "); + else + fprintf (dump_file, "an arbitrary address: "); + print_generic_expr (dump_file, value, dump_flags); + fprintf (dump_file, "\n"); + } +} + + +/* If VALUE is of the form &DECL, add DECL to the set of variables + pointed-to by PTR. Otherwise, add VALUE as a pointed-to expression by + PTR. AI is as in collect_points_to_info. */ + +static void +add_pointed_to_var (struct alias_info *ai, tree ptr, tree value) +{ + if (TREE_CODE (value) == ADDR_EXPR) + { + tree pt_var; + ssa_name_ann_t ann; + size_t uid; + + pt_var = TREE_OPERAND (value, 0); + if (TREE_CODE_CLASS (TREE_CODE (pt_var)) == 'r') + pt_var = get_base_address (pt_var); + + if (pt_var && SSA_VAR_P (pt_var)) + { + ann = get_ssa_name_ann (ptr); + uid = var_ann (pt_var)->uid; + if (ann->pt_vars == NULL) + ann->pt_vars = BITMAP_GGC_ALLOC (); + bitmap_set_bit (ann->pt_vars, uid); + bitmap_set_bit (ai->addresses_needed, uid); + } + else + add_pointed_to_expr (ptr, value); + } + else + add_pointed_to_expr (ptr, value); +} + + +/* Callback for walk_use_def_chains to gather points-to information from the + SSA web. + + VAR is an SSA variable or a GIMPLE expression. + + STMT is the statement that generates the SSA variable or, if STMT is a + PHI_NODE, VAR is one of the PHI arguments. + + DATA is a pointer to a structure of type ALIAS_INFO. */ + +static bool +collect_points_to_info_r (tree var, tree stmt, void *data) +{ + struct alias_info *ai = (struct alias_info *) data; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Visiting use-def links for "); + print_generic_expr (dump_file, var, dump_flags); + fprintf (dump_file, "\n"); + } + + if (TREE_CODE (stmt) == MODIFY_EXPR) + { + tree rhs = TREE_OPERAND (stmt, 1); + STRIP_NOPS (rhs); + + /* Found P_i = CONST. */ + if (is_gimple_min_invariant (rhs)) + add_pointed_to_var (ai, var, rhs); + + /* Found P_i = Q_j. */ + else if (TREE_CODE (rhs) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (rhs))) + merge_pointed_to_info (ai, var, rhs); + + /* Found P_i = PLUS_EXPR or P_i = MINUS_EXPR */ + else if (TREE_CODE (rhs) == PLUS_EXPR + || TREE_CODE (rhs) == MINUS_EXPR) + { + tree op0 = TREE_OPERAND (rhs, 0); + tree op1 = TREE_OPERAND (rhs, 1); + + if (TREE_CODE (op0) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (op0))) + merge_pointed_to_info (ai, var, op0); + else if (TREE_CODE (op1) == SSA_NAME + && POINTER_TYPE_P (TREE_TYPE (op1))) + merge_pointed_to_info (ai, var, op1); + else if (is_gimple_min_invariant (op0)) + add_pointed_to_var (ai, var, op0); + else if (is_gimple_min_invariant (op1)) + add_pointed_to_var (ai, var, op1); + else + add_pointed_to_expr (var, rhs); + } + + /* Something else. */ + else + add_pointed_to_expr (var, rhs); + } + else if (TREE_CODE (stmt) == ASM_EXPR) + { + /* Pointers defined by __asm__ statements can point anywhere. */ + ssa_name_ann_t ann = get_ssa_name_ann (var); + ann->pt_anything = 1; + } + else if (IS_EMPTY_STMT (stmt)) + { + tree decl = SSA_NAME_VAR (var); + + if (TREE_CODE (decl) == PARM_DECL) + add_pointed_to_expr (var, decl); + else if (DECL_INITIAL (decl)) + add_pointed_to_var (ai, var, DECL_INITIAL (decl)); + else + add_pointed_to_expr (var, decl); + } + else if (TREE_CODE (stmt) == PHI_NODE) + { + tree lhs = PHI_RESULT (stmt); + + if (is_gimple_min_invariant (var)) + add_pointed_to_var (ai, lhs, var); + else if (TREE_CODE (var) == SSA_NAME) + merge_pointed_to_info (ai, lhs, var); + else + abort (); + } + else + abort (); + + return false; +} + + +/* Return true if STMT is an "escape" site from the current function. Escape + sites those statements which might expose the address of a variable + outside the current function. STMT is an escape site iff: + + 1- STMT is a function call, or + 2- STMT is an __asm__ expression, or + 3- STMT is an assignment to a non-local variable, or + 4- STMT is a return statement. + + If NUM_CALLS_P is not NULL, the counter is incremented if STMT contains + a function call. */ + +static bool +is_escape_site (tree stmt, size_t *num_calls_p) +{ + if (get_call_expr_in (stmt) != NULL_TREE) + { + if (num_calls_p) + (*num_calls_p)++; + + return true; + } + else if (TREE_CODE (stmt) == ASM_EXPR) + return true; + else if (TREE_CODE (stmt) == MODIFY_EXPR) + { + tree lhs = TREE_OPERAND (stmt, 0); + + /* Get to the base of _REF nodes. */ + if (TREE_CODE (lhs) != SSA_NAME) + lhs = get_base_address (lhs); + + /* If we couldn't recognize the LHS of the assignment, assume that it + is a non-local store. */ + if (lhs == NULL_TREE) + return true; + + /* If the LHS is an SSA name, it can't possibly represent a non-local + memory store. */ + if (TREE_CODE (lhs) == SSA_NAME) + return false; + + /* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a + local variables we cannot be sure if it will escape, because we + don't have information about objects not in SSA form. Need to + implement something along the lines of + + J.-D. Choi, M. Gupta, M. J. Serrano, V. C. Sreedhar, and S. P. + Midkiff, ``Escape analysis for java,'' in Proceedings of the + Conference on Object-Oriented Programming Systems, Languages, and + Applications (OOPSLA), pp. 1-19, 1999. */ + return true; + } + else if (TREE_CODE (stmt) == RETURN_EXPR) + return true; + + return false; +} + + +/* Create a new memory tag of type TYPE. If IS_TYPE_TAG is true, the tag + is considered to represent all the pointers whose pointed-to types are + in the same alias set class. Otherwise, the tag represents a single + SSA_NAME pointer variable. */ + +static tree +create_memory_tag (tree type, bool is_type_tag) +{ + var_ann_t ann; + tree tag = create_tmp_var_raw (type, (is_type_tag) ? "TMT" : "NMT"); + + /* By default, memory tags are local variables. Alias analysis will + determine whether they should be considered globals. */ + DECL_CONTEXT (tag) = current_function_decl; + + /* If the pointed-to type is volatile, so is the tag. */ + TREE_THIS_VOLATILE (tag) = TREE_THIS_VOLATILE (type); + + /* Memory tags are by definition addressable. This also prevents + is_gimple_ref frome confusing memory tags with optimizable + variables. */ + TREE_ADDRESSABLE (tag) = 1; + + ann = get_var_ann (tag); + ann->mem_tag_kind = (is_type_tag) ? TYPE_TAG : NAME_TAG; + ann->type_mem_tag = NULL_TREE; + + /* Add the tag to the symbol table and mark it for renaming. */ + add_referenced_tmp_var (tag); + bitmap_set_bit (vars_to_rename, ann->uid); + + return tag; +} + + +/* Create a name memory tag to represent a specific SSA_NAME pointer P_i. + This is used if P_i has been found to point to a specific set of + variables or to a non-aliased memory location like the address returned + by malloc functions. */ + +static tree +get_nmt_for (tree ptr) +{ + ssa_name_ann_t ptr_ann = ssa_name_ann (ptr); + tree tag = ptr_ann->name_mem_tag; + + if (tag == NULL_TREE) + { + tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false); + + /* If PTR is a PARM_DECL, its memory tag should be considered a + global variable. */ + if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL) + mark_call_clobbered (tag); + + /* Similarly, if PTR points to malloc, then TAG is a global. */ + if (ptr_ann->pt_malloc) + mark_call_clobbered (tag); + } + + return tag; +} + + +/* Return the type memory tag associated to pointer PTR. A memory tag is an + artificial variable that represents the memory location pointed-to by + PTR. It is used to model the effects of pointer de-references on + addressable variables. + + AI points to the data gathered during alias analysis. This function + populates the array AI->POINTERS. */ + +static tree +get_tmt_for (tree ptr, struct alias_info *ai) +{ + size_t i; + tree tag; + tree tag_type = TREE_TYPE (TREE_TYPE (ptr)); + HOST_WIDE_INT tag_set = get_alias_set (tag_type); + + /* To avoid creating unnecessary memory tags, only create one memory tag + per alias set class. Note that it may be tempting to group + memory tags based on conflicting alias sets instead of + equivalence. That would be wrong because alias sets are not + necessarily transitive (as demonstrated by the libstdc++ test + 23_containers/vector/cons/4.cc). Given three alias sets A, B, C + such that conflicts (A, B) == true and conflicts (A, C) == true, + it does not necessarily follow that conflicts (B, C) == true. */ + for (i = 0, tag = NULL_TREE; i < ai->num_pointers; i++) + { + struct alias_map_d *curr = ai->pointers[i]; + if (tag_set == curr->set + && (flag_tree_points_to == PTA_NONE + || same_points_to_set (curr->var, ptr))) + { + tag = var_ann (curr->var)->type_mem_tag; + break; + } + } + + /* If VAR cannot alias with any of the existing memory tags, create a new + tag for PTR and add it to the POINTERS array. */ + if (tag == NULL_TREE) + { + struct alias_map_d *alias_map; + + /* Create a new MT.* artificial variable representing the memory + location pointed-to by PTR. */ + tag = create_memory_tag (tag_type, true); + + /* Add PTR to the POINTERS array. Note that we are not interested in + PTR's alias set. Instead, we cache the alias set for the memory that + PTR points to. */ + alias_map = xcalloc (1, sizeof (*alias_map)); + alias_map->var = ptr; + alias_map->set = tag_set; + ai->pointers[ai->num_pointers++] = alias_map; + } + + return tag; +} + + +/* Create GLOBAL_VAR, an artificial global variable to act as a + representative of all the variables that may be clobbered by function + calls. */ + +static void +create_global_var (void) +{ + global_var = build_decl (VAR_DECL, get_identifier (".GLOBAL_VAR"), + size_type_node); + DECL_ARTIFICIAL (global_var) = 1; + TREE_READONLY (global_var) = 0; + DECL_EXTERNAL (global_var) = 0; + TREE_STATIC (global_var) = 1; + TREE_USED (global_var) = 1; + DECL_CONTEXT (global_var) = NULL_TREE; + TREE_THIS_VOLATILE (global_var) = 0; + TREE_ADDRESSABLE (global_var) = 0; + + add_referenced_tmp_var (global_var); + bitmap_set_bit (vars_to_rename, var_ann (global_var)->uid); +} + + +/* Dump alias statistics on FILE. */ + +static void +dump_alias_stats (FILE *file) +{ + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + fprintf (file, "\nAlias statistics for %s\n\n", funcname); + fprintf (file, "Total alias queries:\t%u\n", alias_stats.alias_queries); + fprintf (file, "Total alias mayalias results:\t%u\n", + alias_stats.alias_mayalias); + fprintf (file, "Total alias noalias results:\t%u\n", + alias_stats.alias_noalias); + fprintf (file, "Total simple queries:\t%u\n", + alias_stats.simple_queries); + fprintf (file, "Total simple resolved:\t%u\n", + alias_stats.simple_resolved); + fprintf (file, "Total TBAA queries:\t%u\n", + alias_stats.tbaa_queries); + fprintf (file, "Total TBAA resolved:\t%u\n", + alias_stats.tbaa_resolved); + fprintf (file, "Total PTA queries:\t%u\n", + alias_stats.pta_queries); + fprintf (file, "Total PTA resolved:\t%u\n", + alias_stats.pta_resolved); +} + + +/* Dump alias information on FILE. */ + +void +dump_alias_info (FILE *file) +{ + size_t i; + const char *funcname + = (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + fprintf (file, "\nAlias information for %s\n\n", funcname); + + for (i = 0; i < num_referenced_vars; i++) + { + tree var = referenced_var (i); + var_ann_t ann = var_ann (var); + if (ann->may_aliases + || ann->type_mem_tag + || ann->is_alias_tag + || ann->mem_tag_kind != NOT_A_TAG) + dump_variable (file, var); + } + + fprintf (file, "\n"); +} + + +/* Dump alias information on stderr. */ + +void +debug_alias_info (void) +{ + dump_alias_info (stderr); +} + + +/* Dump points-to information for SSA_NAME PTR into FILE. */ + +static void +dump_points_to_info_for (FILE *file, tree ptr) +{ + ssa_name_ann_t ann = ssa_name_ann (ptr); + + fprintf (file, "Pointer "); + print_generic_expr (file, ptr, dump_flags); + + if (ann == NULL) + return; + + if (ann->name_mem_tag) + { + fprintf (file, ", name memory tag: "); + print_generic_expr (file, ann->name_mem_tag, dump_flags); + } + + if (ann->value_escapes_p) + fprintf (file, ", its value escapes"); + + if (ann->pt_anything) + fprintf (file, ", points-to anything"); + + if (ann->pt_malloc) + fprintf (file, ", points-to malloc"); + + if (ann->pt_vars) + { + unsigned ix; + + fprintf (file, ", points-to vars: { "); + EXECUTE_IF_SET_IN_BITMAP (ann->pt_vars, 0, ix, + { + print_generic_expr (file, referenced_var (ix), dump_flags); + fprintf (file, " "); + }); + fprintf (file, "}"); + } + + fprintf (file, "\n"); +} + + +/* Dump points-to information into FILE. NOTE: This function is slow, as + it needs to traverse the whole CFG looking for pointer SSA_NAMEs. */ + +void +dump_points_to_info (FILE *file) +{ + basic_block bb; + block_stmt_iterator si; + size_t i; + const char *fname = + (*lang_hooks.decl_printable_name) (current_function_decl, 2); + + fprintf (file, "\n\nPointed-to sets for pointers in %s\n\n", fname); + + /* First dump points-to information for the default definitions of + pointer variables. This is necessary because default definitions are + not part of the code. */ + for (i = 0; i < num_referenced_vars; i++) + { + tree var = referenced_var (i); + if (POINTER_TYPE_P (TREE_TYPE (var))) + { + var_ann_t ann = var_ann (var); + if (ann->default_def) + dump_points_to_info_for (file, ann->default_def); + } + } + + /* Dump points-to information for every pointer defined in the program. */ + FOR_EACH_BB (bb) + { + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree ptr = PHI_RESULT (phi); + if (POINTER_TYPE_P (TREE_TYPE (ptr))) + dump_points_to_info_for (file, ptr); + } + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + stmt_ann_t ann = stmt_ann (bsi_stmt (si)); + def_optype defs = DEF_OPS (ann); + if (defs) + for (i = 0; i < NUM_DEFS (defs); i++) + if (POINTER_TYPE_P (TREE_TYPE (DEF_OP (defs, i)))) + dump_points_to_info_for (file, DEF_OP (defs, i)); + } + } + + fprintf (file, "\n"); +} + + +/* Dump points-to info pointed by PTO into STDERR. */ + +void +debug_points_to_info (void) +{ + dump_points_to_info (stderr); +} + +/* Dump to FILE the list of variables that may be aliasing VAR. */ + +void +dump_may_aliases_for (FILE *file, tree var) +{ + varray_type aliases; + + if (TREE_CODE (var) == SSA_NAME) + var = SSA_NAME_VAR (var); + + aliases = var_ann (var)->may_aliases; + if (aliases) + { + size_t i; + fprintf (file, "{ "); + for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++) + { + print_generic_expr (file, VARRAY_TREE (aliases, i), dump_flags); + fprintf (file, " "); + } + fprintf (file, "}"); + } +} + + +/* Dump to stderr the list of variables that may be aliasing VAR. */ + +void +debug_may_aliases_for (tree var) +{ + dump_may_aliases_for (stderr, var); +} diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c new file mode 100644 index 00000000000..ef655629abd --- /dev/null +++ b/gcc/tree-ssa-ccp.c @@ -0,0 +1,2393 @@ +/* Conditional constant propagation pass for the GNU compiler. + Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Adapted from original RTL SSA-CCP by Daniel Berlin + Adapted to GIMPLE trees by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Conditional constant propagation. + + References: + + Constant propagation with conditional branches, + Wegman and Zadeck, ACM TOPLAS 13(2):181-210. + + Building an Optimizing Compiler, + Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9. + + Advanced Compiler Design and Implementation, + Steven Muchnick, Morgan Kaufmann, 1997, Section 12.6 */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" +#include "tree.h" +#include "langhooks.h" + +/* These RTL headers are needed for basic-block.h. */ +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" + +#include "diagnostic.h" +#include "tree-inline.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "timevar.h" +#include "expr.h" +#include "flags.h" + + +/* Possible lattice values. */ +typedef enum +{ + UNINITIALIZED = 0, + UNDEFINED, + CONSTANT, + VARYING +} latticevalue; + +/* Use the TREE_VISITED bitflag to mark statements and PHI nodes that have + been deemed VARYING and shouldn't be simulated again. */ +#define DONT_SIMULATE_AGAIN(T) TREE_VISITED (T) + +/* Main structure for CCP. Contains the lattice value and, if it's a + constant, the constant value. */ +typedef struct +{ + latticevalue lattice_val; + tree const_val; +} value; + +/* A bitmap to keep track of executable blocks in the CFG. */ +static sbitmap executable_blocks; + +/* Array of control flow edges on the worklist. */ +static GTY(()) varray_type cfg_blocks = NULL; + +static unsigned int cfg_blocks_num = 0; +static int cfg_blocks_tail; +static int cfg_blocks_head; + +static sbitmap bb_in_list; + +/* This is used to track the current value of each variable. */ +static value *value_vector; + +/* Worklist of SSA edges which will need reexamination as their definition + has changed. SSA edges are def-use edges in the SSA web. For each + edge, we store the definition statement or PHI node D. The destination + nodes that need to be visited are accessed using immediate_uses (D). */ +static GTY(()) varray_type ssa_edges; + +static void initialize (void); +static void finalize (void); +static void visit_phi_node (tree); +static tree ccp_fold (tree); +static value cp_lattice_meet (value, value); +static void visit_stmt (tree); +static void visit_cond_stmt (tree); +static void visit_assignment (tree); +static void add_var_to_ssa_edges_worklist (tree); +static void add_outgoing_control_edges (basic_block); +static void add_control_edge (edge); +static void def_to_varying (tree); +static void set_lattice_value (tree, value); +static void simulate_block (basic_block); +static void simulate_stmt (tree); +static void substitute_and_fold (void); +static value evaluate_stmt (tree); +static void dump_lattice_value (FILE *, const char *, value); +static bool replace_uses_in (tree, bool *); +static latticevalue likely_value (tree); +static tree get_rhs (tree); +static void set_rhs (tree *, tree); +static value *get_value (tree); +static value get_default_value (tree); +static tree ccp_fold_builtin (tree, tree); +static bool get_strlen (tree, tree *, bitmap); +static inline bool cfg_blocks_empty_p (void); +static void cfg_blocks_add (basic_block); +static basic_block cfg_blocks_get (void); +static bool need_imm_uses_for (tree var); + +/* Main entry point for SSA Conditional Constant Propagation. FNDECL is + the declaration for the function to optimize. + + On exit, VARS_TO_RENAME will contain the symbols that have been exposed by + the propagation of ADDR_EXPR expressions into pointer dereferences and need + to be renamed into SSA. + + PHASE indicates which dump file from the DUMP_FILES array to use when + dumping debugging information. */ + +static void +tree_ssa_ccp (void) +{ + initialize (); + + /* Iterate until the worklists are empty. */ + while (!cfg_blocks_empty_p () || VARRAY_ACTIVE_SIZE (ssa_edges) > 0) + { + if (!cfg_blocks_empty_p ()) + { + /* Pull the next block to simulate off the worklist. */ + basic_block dest_block = cfg_blocks_get (); + simulate_block (dest_block); + } + + /* The SSA_EDGES worklist can get rather large. Go ahead and + drain the entire worklist each iteration through this loop. */ + while (VARRAY_ACTIVE_SIZE (ssa_edges) > 0) + { + /* Pull the statement to simulate off the worklist. */ + tree stmt = VARRAY_TOP_TREE (ssa_edges); + stmt_ann_t ann = stmt_ann (stmt); + VARRAY_POP (ssa_edges); + + /* visit_stmt can "cancel" reevaluation of some statements. + If it does, then in_ccp_worklist will be zero. */ + if (ann->in_ccp_worklist) + { + ann->in_ccp_worklist = 0; + simulate_stmt (stmt); + } + } + } + + /* Now perform substitutions based on the known constant values. */ + substitute_and_fold (); + + /* Now cleanup any unreachable code. */ + cleanup_tree_cfg (); + + /* Free allocated memory. */ + finalize (); + + /* Debugging dumps. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + dump_referenced_vars (dump_file); + fprintf (dump_file, "\n\n"); + } +} + +static bool +gate_ccp (void) +{ + return flag_tree_ccp != 0; +} + +struct tree_opt_pass pass_ccp = +{ + "ccp", /* name */ + gate_ccp, /* gate */ + tree_ssa_ccp, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_CCP, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_rename_vars + | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ +}; + + +/* Get the constant value associated with variable VAR. */ + +static value * +get_value (tree var) +{ + value *val; + +#if defined ENABLE_CHECKING + if (TREE_CODE (var) != SSA_NAME) + abort (); +#endif + + val = &value_vector[SSA_NAME_VERSION (var)]; + if (val->lattice_val == UNINITIALIZED) + *val = get_default_value (var); + + return val; +} + + +/* Simulate the execution of BLOCK. Evaluate the statement associated + with each variable reference inside the block. */ + +static void +simulate_block (basic_block block) +{ + tree phi; + + /* There is nothing to do for the exit block. */ + if (block == EXIT_BLOCK_PTR) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\nSimulating block %d\n", block->index); + + /* Always simulate PHI nodes, even if we have simulated this block + before. */ + for (phi = phi_nodes (block); phi; phi = TREE_CHAIN (phi)) + visit_phi_node (phi); + + /* If this is the first time we've simulated this block, then we + must simulate each of its statements. */ + if (!TEST_BIT (executable_blocks, block->index)) + { + block_stmt_iterator j; + unsigned int normal_edge_count; + edge e, normal_edge; + + /* Note that we have simulated this block. */ + SET_BIT (executable_blocks, block->index); + + for (j = bsi_start (block); !bsi_end_p (j); bsi_next (&j)) + visit_stmt (bsi_stmt (j)); + + /* We can not predict when abnormal edges will be executed, so + once a block is considered executable, we consider any + outgoing abnormal edges as executable. + + At the same time, if this block has only one successor that is + reached by non-abnormal edges, then add that successor to the + worklist. */ + normal_edge_count = 0; + normal_edge = NULL; + for (e = block->succ; e; e = e->succ_next) + { + if (e->flags & EDGE_ABNORMAL) + { + add_control_edge (e); + } + else + { + normal_edge_count++; + normal_edge = e; + } + } + + if (normal_edge_count == 1) + add_control_edge (normal_edge); + } +} + + +/* Follow the def-use edges for statement DEF_STMT and simulate all the + statements reached by it. */ + +static void +simulate_stmt (tree use_stmt) +{ + basic_block use_bb = bb_for_stmt (use_stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nSimulating statement (from ssa_edges): "); + print_generic_stmt (dump_file, use_stmt, dump_flags); + } + + if (TREE_CODE (use_stmt) == PHI_NODE) + { + /* PHI nodes are always visited, regardless of whether or not the + destination block is executable. */ + visit_phi_node (use_stmt); + } + else if (TEST_BIT (executable_blocks, use_bb->index)) + { + /* Otherwise, visit the statement containing the use reached by + DEF, only if the destination block is marked executable. */ + visit_stmt (use_stmt); + } +} + + +/* Perform final substitution and folding. After this pass the program + should still be in SSA form. */ + +static void +substitute_and_fold (void) +{ + basic_block bb; + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + "\nSubstituing constants and folding statements\n\n"); + + /* Substitute constants in every statement of every basic block. */ + FOR_EACH_BB (bb) + { + block_stmt_iterator i; + tree phi; + + /* Propagate our known constants into PHI nodes. */ + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + int i; + + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + value *new_val; + tree *orig_p = &PHI_ARG_DEF (phi, i); + + if (! SSA_VAR_P (*orig_p)) + break; + + new_val = get_value (*orig_p); + if (new_val->lattice_val == CONSTANT + && may_propagate_copy (*orig_p, new_val->const_val)) + *orig_p = new_val->const_val; + } + } + + for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) + { + bool replaced_address; + tree stmt = bsi_stmt (i); + + /* Skip statements that have been folded already. */ + if (stmt_modified_p (stmt) || !is_exec_stmt (stmt)) + continue; + + /* Replace the statement with its folded version and mark it + folded. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Line %d: replaced ", get_lineno (stmt)); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + } + + if (replace_uses_in (stmt, &replaced_address)) + { + bool changed = fold_stmt (bsi_stmt_ptr (i)); + stmt = bsi_stmt(i); + modify_stmt (stmt); + /* If we folded a builtin function, we'll likely + need to rename VDEFs. */ + if (replaced_address || changed) + mark_new_vars_to_rename (stmt, vars_to_rename); + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " with "); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + fprintf (dump_file, "\n"); + } + } + } +} + + +/* Loop through the PHI_NODE's parameters for BLOCK and compare their + lattice values to determine PHI_NODE's lattice value. The value of a + PHI node is determined calling cp_lattice_meet() with all the arguments + of the PHI node that are incoming via executable edges. */ + +static void +visit_phi_node (tree phi) +{ + bool short_circuit = 0; + value phi_val, *curr_val; + int i; + + /* If the PHI node has already been deemed to be VARYING, don't simulate + it again. */ + if (DONT_SIMULATE_AGAIN (phi)) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nVisiting PHI node: "); + print_generic_expr (dump_file, phi, dump_flags); + } + + curr_val = get_value (PHI_RESULT (phi)); + switch (curr_val->lattice_val) + { + case VARYING: + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\n Shortcircuit. Default of VARYING."); + short_circuit = 1; + break; + + case CONSTANT: + phi_val = *curr_val; + break; + + case UNDEFINED: + case UNINITIALIZED: + phi_val.lattice_val = UNDEFINED; + phi_val.const_val = NULL_TREE; + break; + + default: + abort (); + } + + /* If the variable is volatile or the variable is never referenced in a + real operand, then consider the PHI node VARYING. */ + if (short_circuit || TREE_THIS_VOLATILE (SSA_NAME_VAR (PHI_RESULT (phi)))) + { + phi_val.lattice_val = VARYING; + phi_val.const_val = NULL; + } + else + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + /* Compute the meet operator over all the PHI arguments. */ + edge e = PHI_ARG_EDGE (phi, i); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "\n Argument #%d (%d -> %d %sexecutable)\n", + i, e->src->index, e->dest->index, + (e->flags & EDGE_EXECUTABLE) ? "" : "not "); + } + + /* If the incoming edge is executable, Compute the meet operator for + the existing value of the PHI node and the current PHI argument. */ + if (e->flags & EDGE_EXECUTABLE) + { + tree rdef = PHI_ARG_DEF (phi, i); + value *rdef_val, val; + + if (is_gimple_min_invariant (rdef)) + { + val.lattice_val = CONSTANT; + val.const_val = rdef; + rdef_val = &val; + } + else + rdef_val = get_value (rdef); + + phi_val = cp_lattice_meet (phi_val, *rdef_val); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\t"); + print_generic_expr (dump_file, rdef, dump_flags); + dump_lattice_value (dump_file, "\tValue: ", *rdef_val); + fprintf (dump_file, "\n"); + } + + if (phi_val.lattice_val == VARYING) + break; + } + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + dump_lattice_value (dump_file, "\n PHI node value: ", phi_val); + fprintf (dump_file, "\n\n"); + } + + set_lattice_value (PHI_RESULT (phi), phi_val); + if (phi_val.lattice_val == VARYING) + DONT_SIMULATE_AGAIN (phi) = 1; +} + + +/* Compute the meet operator between VAL1 and VAL2: + + any M UNDEFINED = any + any M VARYING = VARYING + Ci M Cj = Ci if (i == j) + Ci M Cj = VARYING if (i != j) */ +static value +cp_lattice_meet (value val1, value val2) +{ + value result; + + /* any M UNDEFINED = any. */ + if (val1.lattice_val == UNDEFINED) + return val2; + else if (val2.lattice_val == UNDEFINED) + return val1; + + /* any M VARYING = VARYING. */ + if (val1.lattice_val == VARYING || val2.lattice_val == VARYING) + { + result.lattice_val = VARYING; + result.const_val = NULL_TREE; + return result; + } + + /* Ci M Cj = Ci if (i == j) + Ci M Cj = VARYING if (i != j) */ + if (simple_cst_equal (val1.const_val, val2.const_val) == 1) + { + result.lattice_val = CONSTANT; + result.const_val = val1.const_val; + } + else + { + result.lattice_val = VARYING; + result.const_val = NULL_TREE; + } + + return result; +} + + +/* Evaluate statement STMT. If the statement produces an output value and + its evaluation changes the lattice value of its output, do the following: + + - If the statement is an assignment, add all the SSA edges starting at + this definition. + + - If the statement is a conditional branch: + . If the statement evaluates to non-constant, add all edges to + worklist. + . If the statement is constant, add the edge executed as the + result of the branch. */ + +static void +visit_stmt (tree stmt) +{ + size_t i; + stmt_ann_t ann; + def_optype defs; + vdef_optype vdefs; + + /* If the statement has already been deemed to be VARYING, don't simulate + it again. */ + if (DONT_SIMULATE_AGAIN (stmt)) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nVisiting statement: "); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + fprintf (dump_file, "\n"); + } + + ann = stmt_ann (stmt); + + /* If this statement is already in the worklist then "cancel" it. The + reevaluation implied by the worklist entry will produce the same + value we generate here and thus reevaluating it again from the + worklist is pointless. */ + if (ann->in_ccp_worklist) + ann->in_ccp_worklist = 0; + + /* Now examine the statement. If the statement is an assignment that + produces a single output value, evaluate its RHS to see if the lattice + value of its output has changed. */ + if (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME) + visit_assignment (stmt); + + /* Definitions made by statements other than assignments to SSA_NAMEs + represent unknown modifications to their outputs. Mark them VARYING. */ + else if (NUM_DEFS (defs = DEF_OPS (ann)) != 0) + { + DONT_SIMULATE_AGAIN (stmt) = 1; + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree def = DEF_OP (defs, i); + def_to_varying (def); + } + } + + /* If STMT is a conditional branch, see if we can determine which branch + will be taken. */ + else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR) + visit_cond_stmt (stmt); + + /* Any other kind of statement is not interesting for constant + propagation and, therefore, not worth simulating. */ + else + { + DONT_SIMULATE_AGAIN (stmt) = 1; + + /* If STMT is a computed goto, then mark all the output edges + executable. */ + if (computed_goto_p (stmt)) + add_outgoing_control_edges (bb_for_stmt (stmt)); + } + + /* Mark all VDEF operands VARYING. */ + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + def_to_varying (VDEF_RESULT (vdefs, i)); +} + + +/* Visit the assignment statement STMT. Set the value of its LHS to the + value computed by the RHS. */ + +static void +visit_assignment (tree stmt) +{ + value val; + tree lhs, rhs; + + lhs = TREE_OPERAND (stmt, 0); + rhs = TREE_OPERAND (stmt, 1); + + if (TREE_THIS_VOLATILE (SSA_NAME_VAR (lhs))) + { + /* Volatile variables are always VARYING. */ + val.lattice_val = VARYING; + val.const_val = NULL_TREE; + } + else if (TREE_CODE (rhs) == SSA_NAME) + { + /* For a simple copy operation, we copy the lattice values. */ + value *nval = get_value (rhs); + val = *nval; + } + else + { + /* Evaluate the statement. */ + val = evaluate_stmt (stmt); + } + + /* FIXME: Hack. If this was a definition of a bitfield, we need to widen + the constant value into the type of the destination variable. This + should not be necessary if GCC represented bitfields properly. */ + { + tree lhs = TREE_OPERAND (stmt, 0); + if (val.lattice_val == CONSTANT + && TREE_CODE (lhs) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (lhs, 1))) + { + tree w = widen_bitfield (val.const_val, TREE_OPERAND (lhs, 1), lhs); + + if (w && is_gimple_min_invariant (w)) + val.const_val = w; + else + { + val.lattice_val = VARYING; + val.const_val = NULL; + } + } + } + + /* Set the lattice value of the statement's output. */ + set_lattice_value (lhs, val); + if (val.lattice_val == VARYING) + DONT_SIMULATE_AGAIN (stmt) = 1; +} + + +/* Visit the conditional statement STMT. If it evaluates to a constant value, + mark outgoing edges appropriately. */ + +static void +visit_cond_stmt (tree stmt) +{ + edge e; + value val; + basic_block block; + + block = bb_for_stmt (stmt); + val = evaluate_stmt (stmt); + + /* Find which edge out of the conditional block will be taken and add it + to the worklist. If no single edge can be determined statically, add + all outgoing edges from BLOCK. */ + e = find_taken_edge (block, val.const_val); + if (e) + add_control_edge (e); + else + { + DONT_SIMULATE_AGAIN (stmt) = 1; + add_outgoing_control_edges (block); + } +} + + +/* Add all the edges coming out of BB to the control flow worklist. */ + +static void +add_outgoing_control_edges (basic_block bb) +{ + edge e; + + for (e = bb->succ; e; e = e->succ_next) + add_control_edge (e); +} + + +/* Add edge E to the control flow worklist. */ + +static void +add_control_edge (edge e) +{ + basic_block bb = e->dest; + if (bb == EXIT_BLOCK_PTR) + return; + + /* If the edge had already been executed, skip it. */ + if (e->flags & EDGE_EXECUTABLE) + return; + + e->flags |= EDGE_EXECUTABLE; + + /* If the block is already in the list, we're done. */ + if (TEST_BIT (bb_in_list, bb->index)) + return; + + cfg_blocks_add (bb); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Adding Destination of edge (%d -> %d) to worklist\n\n", + e->src->index, e->dest->index); +} + + +/* CCP specific front-end to the non-destructive constant folding routines. + + Attempt to simplify the RHS of STMT knowing that one or more + operands are constants. + + If simplification is possible, return the simplified RHS, + otherwise return the original RHS. */ + +static tree +ccp_fold (tree stmt) +{ + tree rhs = get_rhs (stmt); + enum tree_code code = TREE_CODE (rhs); + int kind = TREE_CODE_CLASS (code); + tree retval = NULL_TREE; + + /* If the RHS is just a variable, then that variable must now have + a constant value that we can return directly. */ + if (TREE_CODE (rhs) == SSA_NAME) + return get_value (rhs)->const_val; + + /* Unary operators. Note that we know the single operand must + be a constant. So this should almost always return a + simplified RHS. */ + if (kind == '1') + { + /* Handle unary operators which can appear in GIMPLE form. */ + tree op0 = TREE_OPERAND (rhs, 0); + + /* Simplify the operand down to a constant. */ + if (TREE_CODE (op0) == SSA_NAME) + { + value *val = get_value (op0); + if (val->lattice_val == CONSTANT) + op0 = get_value (op0)->const_val; + } + + retval = nondestructive_fold_unary_to_constant (code, + TREE_TYPE (rhs), + op0); + + /* If we folded, but did not create an invariant, then we can not + use this expression. */ + if (retval && ! is_gimple_min_invariant (retval)) + return NULL; + + /* If we could not fold the expression, but the arguments are all + constants and gimple values, then build and return the new + expression. + + In some cases the new expression is still something we can + use as a replacement for an argument. This happens with + NOP conversions of types for example. + + In other cases the new expression can not be used as a + replacement for an argument (as it would create non-gimple + code). But the new expression can still be used to derive + other constants. */ + if (! retval && is_gimple_min_invariant (op0)) + return build1 (code, TREE_TYPE (rhs), op0); + } + + /* Binary and comparison operators. We know one or both of the + operands are constants. */ + else if (kind == '2' + || kind == '<' + || code == TRUTH_AND_EXPR + || code == TRUTH_OR_EXPR + || code == TRUTH_XOR_EXPR) + { + /* Handle binary and comparison operators that can appear in + GIMPLE form. */ + tree op0 = TREE_OPERAND (rhs, 0); + tree op1 = TREE_OPERAND (rhs, 1); + + /* Simplify the operands down to constants when appropriate. */ + if (TREE_CODE (op0) == SSA_NAME) + { + value *val = get_value (op0); + if (val->lattice_val == CONSTANT) + op0 = val->const_val; + } + + if (TREE_CODE (op1) == SSA_NAME) + { + value *val = get_value (op1); + if (val->lattice_val == CONSTANT) + op1 = val->const_val; + } + + retval = nondestructive_fold_binary_to_constant (code, + TREE_TYPE (rhs), + op0, op1); + + /* If we folded, but did not create an invariant, then we can not + use this expression. */ + if (retval && ! is_gimple_min_invariant (retval)) + return NULL; + + /* If we could not fold the expression, but the arguments are all + constants and gimple values, then build and return the new + expression. + + In some cases the new expression is still something we can + use as a replacement for an argument. This happens with + NOP conversions of types for example. + + In other cases the new expression can not be used as a + replacement for an argument (as it would create non-gimple + code). But the new expression can still be used to derive + other constants. */ + if (! retval + && is_gimple_min_invariant (op0) + && is_gimple_min_invariant (op1)) + return build (code, TREE_TYPE (rhs), op0, op1); + } + + /* We may be able to fold away calls to builtin functions if their + arguments are constants. */ + else if (code == CALL_EXPR + && TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0)) + == FUNCTION_DECL) + && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (rhs, 0), 0))) + { + use_optype uses = STMT_USE_OPS (stmt); + if (NUM_USES (uses) != 0) + { + tree *orig; + size_t i; + + /* Preserve the original values of every operand. */ + orig = xmalloc (sizeof (tree) * NUM_USES (uses)); + for (i = 0; i < NUM_USES (uses); i++) + orig[i] = USE_OP (uses, i); + + /* Substitute operands with their values and try to fold. */ + replace_uses_in (stmt, NULL); + retval = fold_builtin (rhs); + + /* Restore operands to their original form. */ + for (i = 0; i < NUM_USES (uses); i++) + *(USE_OP_PTR (uses, i)) = orig[i]; + free (orig); + } + } + else + return rhs; + + /* If we got a simplified form, see if we need to convert its type. */ + if (retval) + { + if (TREE_TYPE (retval) != TREE_TYPE (rhs)) + retval = convert (TREE_TYPE (rhs), retval); + + if (TREE_TYPE (retval) == TREE_TYPE (rhs)) + return retval; + } + + /* No simplification was possible. */ + return rhs; +} + + +/* Evaluate statement STMT. */ + +static value +evaluate_stmt (tree stmt) +{ + value val; + tree simplified; + latticevalue likelyvalue = likely_value (stmt); + + /* If the statement is likely to have a CONSTANT result, then try + to fold the statement to determine the constant value. */ + if (likelyvalue == CONSTANT) + simplified = ccp_fold (stmt); + /* If the statement is likely to have a VARYING result, then do not + bother folding the statement. */ + else if (likelyvalue == VARYING) + simplified = get_rhs (stmt); + /* Otherwise the statement is likely to have an UNDEFINED value and + there will be nothing to do. */ + else + simplified = NULL_TREE; + + if (simplified && is_gimple_min_invariant (simplified)) + { + /* The statement produced a constant value. */ + val.lattice_val = CONSTANT; + val.const_val = simplified; + } + else + { + /* The statement produced a nonconstant value. If the statement + had undefined operands, then the result of the statement should + be undefined. Else the result of the statement is VARYING. */ + val.lattice_val = (likelyvalue == UNDEFINED ? UNDEFINED : VARYING); + val.const_val = NULL_TREE; + } + + return val; +} + + +/* Debugging dumps. */ + +static void +dump_lattice_value (FILE *outf, const char *prefix, value val) +{ + switch (val.lattice_val) + { + case UNDEFINED: + fprintf (outf, "%sUNDEFINED", prefix); + break; + case VARYING: + fprintf (outf, "%sVARYING", prefix); + break; + case CONSTANT: + fprintf (outf, "%sCONSTANT ", prefix); + print_generic_expr (outf, val.const_val, dump_flags); + break; + default: + abort (); + } +} + +/* Given a constant value VAL for bitfield FIELD, and a destination + variable VAR, return VAL appropriately widened to fit into VAR. If + FIELD is wider than HOST_WIDE_INT, NULL is returned. */ + +tree +widen_bitfield (tree val, tree field, tree var) +{ + unsigned var_size, field_size; + tree wide_val; + unsigned HOST_WIDE_INT mask; + unsigned i; + + var_size = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE ((var)))); + field_size = TREE_INT_CST_LOW (DECL_SIZE (field)); + + /* Give up if either the bitfield or the variable are too wide. */ + if (field_size > HOST_BITS_PER_WIDE_INT || var_size > HOST_BITS_PER_WIDE_INT) + return NULL; + +#if defined ENABLE_CHECKING + if (var_size < field_size) + abort (); +#endif + + /* If VAL is not an integer constant, then give up. */ + if (TREE_CODE (val) != INTEGER_CST) + return NULL; + + /* If the sign bit of the value is not set, or the field's type is + unsigned, then just mask off the high order bits of the value. */ + if ((TREE_INT_CST_LOW (val) & (1 << (field_size - 1))) == 0 + || DECL_UNSIGNED (field)) + { + /* Zero extension. Build a mask with the lower 'field_size' bits + set and a BIT_AND_EXPR node to clear the high order bits of + the value. */ + for (i = 0, mask = 0; i < field_size; i++) + mask |= 1 << i; + + wide_val = build (BIT_AND_EXPR, TREE_TYPE (var), val, + build_int_2 (mask, 0)); + } + else + { + /* Sign extension. Create a mask with the upper 'field_size' + bits set and a BIT_IOR_EXPR to set the high order bits of the + value. */ + for (i = 0, mask = 0; i < (var_size - field_size); i++) + mask |= 1 << (var_size - i - 1); + + wide_val = build (BIT_IOR_EXPR, TREE_TYPE (var), val, + build_int_2 (mask, 0)); + } + + return fold (wide_val); +} + + +/* Function indicating whether we ought to include information for 'var' + when calculating immediate uses. */ + +static bool +need_imm_uses_for (tree var) +{ + return get_value (var)->lattice_val != VARYING; +} + + +/* Initialize local data structures and worklists for CCP. */ + +static void +initialize (void) +{ + edge e; + basic_block bb; + sbitmap virtual_var; + + /* Worklist of SSA edges. */ + VARRAY_TREE_INIT (ssa_edges, 20, "ssa_edges"); + + executable_blocks = sbitmap_alloc (last_basic_block); + sbitmap_zero (executable_blocks); + + bb_in_list = sbitmap_alloc (last_basic_block); + sbitmap_zero (bb_in_list); + + value_vector = (value *) xmalloc (highest_ssa_version * sizeof (value)); + memset (value_vector, 0, highest_ssa_version * sizeof (value)); + + /* 1 if ssa variable is used in a virtual variable context. */ + virtual_var = sbitmap_alloc (highest_ssa_version); + sbitmap_zero (virtual_var); + + /* Initialize default values and simulation flags for PHI nodes, statements + and edges. */ + FOR_EACH_BB (bb) + { + block_stmt_iterator i; + tree stmt; + stmt_ann_t ann; + def_optype defs; + vdef_optype vdefs; + size_t x; + int vary; + + /* Get the default value for each definition. */ + for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) + { + vary = 0; + stmt = bsi_stmt (i); + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + defs = DEF_OPS (ann); + for (x = 0; x < NUM_DEFS (defs); x++) + { + tree def = DEF_OP (defs, x); + if (get_value (def)->lattice_val == VARYING) + vary = 1; + } + DONT_SIMULATE_AGAIN (stmt) = vary; + + /* Mark all VDEF operands VARYING. */ + vdefs = VDEF_OPS (ann); + for (x = 0; x < NUM_VDEFS (vdefs); x++) + { + tree res = VDEF_RESULT (vdefs, x); + get_value (res)->lattice_val = VARYING; + SET_BIT (virtual_var, SSA_NAME_VERSION (res)); + } + } + + for (e = bb->succ; e; e = e->succ_next) + e->flags &= ~EDGE_EXECUTABLE; + } + + /* Now process PHI nodes. */ + FOR_EACH_BB (bb) + { + tree phi, var; + int x; + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + value *val; + val = get_value (PHI_RESULT (phi)); + if (val->lattice_val != VARYING) + { + for (x = 0; x < PHI_NUM_ARGS (phi); x++) + { + var = PHI_ARG_DEF (phi, x); + /* If one argument is virtual, the result is virtual, and + therefore varying. */ + if (TREE_CODE (var) == SSA_NAME) + { + if (TEST_BIT (virtual_var, SSA_NAME_VERSION (var))) + { + val->lattice_val = VARYING; + SET_BIT (virtual_var, + SSA_NAME_VERSION (PHI_RESULT (phi))); + break; + } + } + } + } + DONT_SIMULATE_AGAIN (phi) = ((val->lattice_val == VARYING) ? 1 : 0); + } + } + + sbitmap_free (virtual_var); + /* Compute immediate uses for variables we care about. */ + compute_immediate_uses (TDFA_USE_OPS, need_imm_uses_for); + + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_immediate_uses (dump_file); + + VARRAY_BB_INIT (cfg_blocks, 20, "cfg_blocks"); + + /* Seed the algorithm by adding the successors of the entry block to the + edge worklist. */ + for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next) + { + if (e->dest != EXIT_BLOCK_PTR) + { + e->flags |= EDGE_EXECUTABLE; + cfg_blocks_add (e->dest); + } + } +} + + +/* Free allocated storage. */ + +static void +finalize (void) +{ + ssa_edges = NULL; + cfg_blocks = NULL; + free (value_vector); + sbitmap_free (bb_in_list); + sbitmap_free (executable_blocks); + free_df (); +} + +/* Is the block worklist empty. */ + +static inline bool +cfg_blocks_empty_p (void) +{ + return (cfg_blocks_num == 0); +} + +/* Add a basic block to the worklist. */ + +static void +cfg_blocks_add (basic_block bb) +{ + if (bb == ENTRY_BLOCK_PTR || bb == EXIT_BLOCK_PTR) + return; + + if (TEST_BIT (bb_in_list, bb->index)) + return; + + if (cfg_blocks_empty_p ()) + { + cfg_blocks_tail = cfg_blocks_head = 0; + cfg_blocks_num = 1; + } + else + { + cfg_blocks_num++; + if (cfg_blocks_num > VARRAY_SIZE (cfg_blocks)) + { + /* We have to grow the array now. Adjust to queue to occupy the + full space of the original array. */ + cfg_blocks_tail = VARRAY_SIZE (cfg_blocks); + cfg_blocks_head = 0; + VARRAY_GROW (cfg_blocks, 2 * VARRAY_SIZE (cfg_blocks)); + } + else + cfg_blocks_tail = (cfg_blocks_tail + 1) % VARRAY_SIZE (cfg_blocks); + } + VARRAY_BB (cfg_blocks, cfg_blocks_tail) = bb; + SET_BIT (bb_in_list, bb->index); +} + +/* Remove a block from the worklist. */ + +static basic_block +cfg_blocks_get (void) +{ + basic_block bb; + + bb = VARRAY_BB (cfg_blocks, cfg_blocks_head); + +#ifdef ENABLE_CHECKING + if (cfg_blocks_empty_p () || !bb) + abort (); +#endif + + cfg_blocks_head = (cfg_blocks_head + 1) % VARRAY_SIZE (cfg_blocks); + --cfg_blocks_num; + RESET_BIT (bb_in_list, bb->index); + + return bb; +} + +/* We have just defined a new value for VAR. Add all immediate uses + of VAR to the ssa_edges worklist. */ +static void +add_var_to_ssa_edges_worklist (tree var) +{ + tree stmt = SSA_NAME_DEF_STMT (var); + dataflow_t df = get_immediate_uses (stmt); + int num_uses = num_immediate_uses (df); + int i; + + for (i = 0; i < num_uses; i++) + { + tree use = immediate_use (df, i); + + if (!DONT_SIMULATE_AGAIN (use)) + { + stmt_ann_t ann = stmt_ann (use); + if (ann->in_ccp_worklist == 0) + { + ann->in_ccp_worklist = 1; + VARRAY_PUSH_TREE (ssa_edges, use); + } + } + } +} + +/* Set the lattice value for the variable VAR to VARYING. */ + +static void +def_to_varying (tree var) +{ + value val; + val.lattice_val = VARYING; + val.const_val = NULL_TREE; + set_lattice_value (var, val); +} + +/* Set the lattice value for variable VAR to VAL. */ + +static void +set_lattice_value (tree var, value val) +{ + value *old = get_value (var); + +#ifdef ENABLE_CHECKING + if (val.lattice_val == UNDEFINED) + { + /* CONSTANT->UNDEFINED is never a valid state transition. */ + if (old->lattice_val == CONSTANT) + abort (); + + /* VARYING->UNDEFINED is generally not a valid state transition, + except for values which are initialized to VARYING. */ + if (old->lattice_val == VARYING + && get_default_value (var).lattice_val != VARYING) + abort (); + } + else if (val.lattice_val == CONSTANT) + { + /* VARYING -> CONSTANT is an invalid state transition, except + for objects which start off in a VARYING state. */ + if (old->lattice_val == VARYING + && get_default_value (var).lattice_val != VARYING) + abort (); + } +#endif + + /* If the constant for VAR has changed, then this VAR is really varying. */ + if (old->lattice_val == CONSTANT && val.lattice_val == CONSTANT + && !simple_cst_equal (old->const_val, val.const_val)) + { + val.lattice_val = VARYING; + val.const_val = NULL_TREE; + } + + if (old->lattice_val != val.lattice_val) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + dump_lattice_value (dump_file, + "Lattice value changed to ", val); + fprintf (dump_file, ". Adding definition to SSA edges.\n"); + } + + add_var_to_ssa_edges_worklist (var); + *old = val; + } +} + +/* Replace USE references in statement STMT with their immediate reaching + definition. Return true if at least one reference was replaced. If + REPLACED_ADDRESSES_P is given, it will be set to true if an address + constant was replaced. */ + +static bool +replace_uses_in (tree stmt, bool *replaced_addresses_p) +{ + bool replaced = false; + use_optype uses; + size_t i; + + if (replaced_addresses_p) + *replaced_addresses_p = false; + + get_stmt_operands (stmt); + + uses = STMT_USE_OPS (stmt); + for (i = 0; i < NUM_USES (uses); i++) + { + tree *use = USE_OP_PTR (uses, i); + value *val = get_value (*use); + + if (val->lattice_val == CONSTANT) + { + *use = val->const_val; + replaced = true; + if (POINTER_TYPE_P (TREE_TYPE (*use)) && replaced_addresses_p) + *replaced_addresses_p = true; + } + } + + return replaced; +} + +/* Return the likely latticevalue for STMT. + + If STMT has no operands, then return CONSTANT. + + Else if any operands of STMT are undefined, then return UNDEFINED. + + Else if any operands of STMT are constants, then return CONSTANT. + + Else return VARYING. */ + +static latticevalue +likely_value (tree stmt) +{ + use_optype uses; + size_t i; + int found_constant = 0; + stmt_ann_t ann; + + /* If the statement makes aliased loads or has volatile operands, it + won't fold to a constant value. */ + ann = stmt_ann (stmt); + if (ann->makes_aliased_loads || ann->has_volatile_ops) + return VARYING; + + /* A CALL_EXPR is assumed to be varying. This may be overly conservative, + in the presence of const and pure calls. */ + if (get_call_expr_in (stmt) != NULL_TREE) + return VARYING; + + get_stmt_operands (stmt); + + uses = USE_OPS (ann); + for (i = 0; i < NUM_USES (uses); i++) + { + tree use = USE_OP (uses, i); + value *val = get_value (use); + + if (val->lattice_val == UNDEFINED) + return UNDEFINED; + + if (val->lattice_val == CONSTANT) + found_constant = 1; + } + + return ((found_constant || !uses) ? CONSTANT : VARYING); +} + +/* A subroutine of fold_stmt_r. Attempts to fold *(A+O) to A[X]. + BASE is an array type. OFFSET is a byte displacement. ORIG_TYPE + is the desired result type. */ + +static tree +maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type) +{ + unsigned HOST_WIDE_INT lquo, lrem; + HOST_WIDE_INT hquo, hrem; + tree elt_size, min_idx, idx; + tree array_type, elt_type; + + /* Ignore stupid user tricks of indexing non-array variables. */ + array_type = TREE_TYPE (base); + if (TREE_CODE (array_type) != ARRAY_TYPE) + return NULL_TREE; + elt_type = TREE_TYPE (array_type); + if (!lang_hooks.types_compatible_p (orig_type, elt_type)) + return NULL_TREE; + + /* Whee. Ignore indexing of variable sized types. */ + elt_size = TYPE_SIZE_UNIT (elt_type); + if (TREE_CODE (elt_size) != INTEGER_CST) + return NULL_TREE; + + /* If the division isn't exact, then don't do anything. Equally + invalid as the above indexing of non-array variables. */ + if (div_and_round_double (TRUNC_DIV_EXPR, 1, + TREE_INT_CST_LOW (offset), + TREE_INT_CST_HIGH (offset), + TREE_INT_CST_LOW (elt_size), + TREE_INT_CST_HIGH (elt_size), + &lquo, &hquo, &lrem, &hrem) + || lrem || hrem) + return NULL_TREE; + idx = build_int_2_wide (lquo, hquo); + + /* Re-bias the index by the min index of the array type. */ + min_idx = TYPE_DOMAIN (TREE_TYPE (base)); + if (min_idx) + { + min_idx = TYPE_MIN_VALUE (min_idx); + if (min_idx) + { + idx = convert (TREE_TYPE (min_idx), idx); + if (!integer_zerop (min_idx)) + idx = int_const_binop (PLUS_EXPR, idx, min_idx, 1); + } + } + + return build (ARRAY_REF, orig_type, base, idx); +} + +/* A subroutine of fold_stmt_r. Attempts to fold *(S+O) to S.X. + BASE is a record type. OFFSET is a byte displacement. ORIG_TYPE + is the desired result type. */ +/* ??? This doesn't handle class inheritance. */ + +static tree +maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset, + tree orig_type, bool base_is_ptr) +{ + tree f, t, field_type, tail_array_field; + + if (TREE_CODE (record_type) != RECORD_TYPE + && TREE_CODE (record_type) != UNION_TYPE + && TREE_CODE (record_type) != QUAL_UNION_TYPE) + return NULL_TREE; + + /* Short-circuit silly cases. */ + if (lang_hooks.types_compatible_p (record_type, orig_type)) + return NULL_TREE; + + tail_array_field = NULL_TREE; + for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f)) + { + int cmp; + + if (TREE_CODE (f) != FIELD_DECL) + continue; + if (DECL_BIT_FIELD (f)) + continue; + if (TREE_CODE (DECL_FIELD_OFFSET (f)) != INTEGER_CST) + continue; + + /* ??? Java creates "interesting" fields for representing base classes. + They have no name, and have no context. With no context, we get into + trouble with nonoverlapping_component_refs_p. Skip them. */ + if (!DECL_FIELD_CONTEXT (f)) + continue; + + /* The previous array field isn't at the end. */ + tail_array_field = NULL_TREE; + + /* Check to see if this offset overlaps with the field. */ + cmp = tree_int_cst_compare (DECL_FIELD_OFFSET (f), offset); + if (cmp > 0) + continue; + + field_type = TREE_TYPE (f); + if (cmp < 0) + { + /* Don't care about offsets into the middle of scalars. */ + if (!AGGREGATE_TYPE_P (field_type)) + continue; + + /* Check for array at the end of the struct. This is often + used as for flexible array members. We should be able to + turn this into an array access anyway. */ + if (TREE_CODE (field_type) == ARRAY_TYPE) + tail_array_field = f; + + /* Check the end of the field against the offset. */ + if (!DECL_SIZE_UNIT (f) + || TREE_CODE (DECL_SIZE_UNIT (f)) != INTEGER_CST) + continue; + t = int_const_binop (MINUS_EXPR, offset, DECL_FIELD_OFFSET (f), 1); + if (!tree_int_cst_lt (t, DECL_SIZE_UNIT (f))) + continue; + + /* If we matched, then set offset to the displacement into + this field. */ + offset = t; + } + + /* Here we exactly match the offset being checked. If the types match, + then we can return that field. */ + else if (lang_hooks.types_compatible_p (orig_type, field_type)) + { + if (base_is_ptr) + base = build1 (INDIRECT_REF, record_type, base); + t = build (COMPONENT_REF, field_type, base, f); + return t; + } + + /* Don't care about type-punning of scalars. */ + else if (!AGGREGATE_TYPE_P (field_type)) + return NULL_TREE; + + goto found; + } + + if (!tail_array_field) + return NULL_TREE; + + f = tail_array_field; + field_type = TREE_TYPE (f); + + found: + /* If we get here, we've got an aggregate field, and a possibly + non-zero offset into them. Recurse and hope for a valid match. */ + if (base_is_ptr) + base = build1 (INDIRECT_REF, record_type, base); + base = build (COMPONENT_REF, field_type, base, f); + + t = maybe_fold_offset_to_array_ref (base, offset, orig_type); + if (t) + return t; + return maybe_fold_offset_to_component_ref (field_type, base, offset, + orig_type, false); +} + +/* A subroutine of fold_stmt_r. Attempt to simplify *(BASE+OFFSET). + Return the simplified expression, or NULL if nothing could be done. */ + +static tree +maybe_fold_stmt_indirect (tree expr, tree base, tree offset) +{ + tree t; + + /* We may well have constructed a double-nested PLUS_EXPR via multiple + substitutions. Fold that down to one. Remove NON_LVALUE_EXPRs that + are sometimes added. */ + base = fold (base); + STRIP_NOPS (base); + TREE_OPERAND (expr, 0) = base; + + /* One possibility is that the address reduces to a string constant. */ + t = fold_read_from_constant_string (expr); + if (t) + return t; + + /* Add in any offset from a PLUS_EXPR. */ + if (TREE_CODE (base) == PLUS_EXPR) + { + tree offset2; + + offset2 = TREE_OPERAND (base, 1); + if (TREE_CODE (offset2) != INTEGER_CST) + return NULL_TREE; + base = TREE_OPERAND (base, 0); + + offset = int_const_binop (PLUS_EXPR, offset, offset2, 1); + } + + if (TREE_CODE (base) == ADDR_EXPR) + { + /* Strip the ADDR_EXPR. */ + base = TREE_OPERAND (base, 0); + + /* Try folding *(&B+O) to B[X]. */ + t = maybe_fold_offset_to_array_ref (base, offset, TREE_TYPE (expr)); + if (t) + return t; + + /* Try folding *(&B+O) to B.X. */ + t = maybe_fold_offset_to_component_ref (TREE_TYPE (base), base, offset, + TREE_TYPE (expr), false); + if (t) + return t; + + /* Fold *&B to B. */ + if (integer_zerop (offset)) + return base; + } + else + { + /* We can get here for out-of-range string constant accesses, + such as "_"[3]. Bail out of the entire substitution search + and arrange for the entire statement to be replaced by a + call to __builtin_trap. In all likelyhood this will all be + constant-folded away, but in the meantime we can't leave with + something that get_expr_operands can't understand. */ + + t = base; + STRIP_NOPS (t); + if (TREE_CODE (t) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST) + { + /* FIXME: Except that this causes problems elsewhere with dead + code not being deleted, and we abort in the rtl expanders + because we failed to remove some ssa_name. In the meantime, + just return zero. */ + /* FIXME2: This condition should be signaled by + fold_read_from_constant_string directly, rather than + re-checking for it here. */ + return integer_zero_node; + } + + /* Try folding *(B+O) to B->X. Still an improvement. */ + if (POINTER_TYPE_P (TREE_TYPE (base))) + { + t = maybe_fold_offset_to_component_ref (TREE_TYPE (TREE_TYPE (base)), + base, offset, + TREE_TYPE (expr), true); + if (t) + return t; + } + } + + /* Otherwise we had an offset that we could not simplify. */ + return NULL_TREE; +} + +/* A subroutine of fold_stmt_r. EXPR is a PLUS_EXPR. + + A quaint feature extant in our address arithmetic is that there + can be hidden type changes here. The type of the result need + not be the same as the type of the input pointer. + + What we're after here is an expression of the form + (T *)(&array + const) + where the cast doesn't actually exist, but is implicit in the + type of the PLUS_EXPR. We'd like to turn this into + &array[x] + which may be able to propagate further. */ + +static tree +maybe_fold_stmt_addition (tree expr) +{ + tree op0 = TREE_OPERAND (expr, 0); + tree op1 = TREE_OPERAND (expr, 1); + tree ptr_type = TREE_TYPE (expr); + tree ptd_type; + tree t; + bool subtract = (TREE_CODE (expr) == MINUS_EXPR); + + /* We're only interested in pointer arithmetic. */ + if (!POINTER_TYPE_P (ptr_type)) + return NULL_TREE; + /* Canonicalize the integral operand to op1. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (op0))) + { + if (subtract) + return NULL_TREE; + t = op0, op0 = op1, op1 = t; + } + /* It had better be a constant. */ + if (TREE_CODE (op1) != INTEGER_CST) + return NULL_TREE; + /* The first operand should be an ADDR_EXPR. */ + if (TREE_CODE (op0) != ADDR_EXPR) + return NULL_TREE; + op0 = TREE_OPERAND (op0, 0); + + /* If the first operand is an ARRAY_REF, expand it so that we can fold + the offset into it. */ + while (TREE_CODE (op0) == ARRAY_REF) + { + tree array_obj = TREE_OPERAND (op0, 0); + tree array_idx = TREE_OPERAND (op0, 1); + tree elt_type = TREE_TYPE (op0); + tree elt_size = TYPE_SIZE_UNIT (elt_type); + tree min_idx; + + if (TREE_CODE (array_idx) != INTEGER_CST) + break; + if (TREE_CODE (elt_size) != INTEGER_CST) + break; + + /* Un-bias the index by the min index of the array type. */ + min_idx = TYPE_DOMAIN (TREE_TYPE (array_obj)); + if (min_idx) + { + min_idx = TYPE_MIN_VALUE (min_idx); + if (min_idx) + { + array_idx = convert (TREE_TYPE (min_idx), array_idx); + if (!integer_zerop (min_idx)) + array_idx = int_const_binop (MINUS_EXPR, array_idx, + min_idx, 0); + } + } + + /* Convert the index to a byte offset. */ + array_idx = convert (sizetype, array_idx); + array_idx = int_const_binop (MULT_EXPR, array_idx, elt_size, 0); + + /* Update the operands for the next round, or for folding. */ + /* If we're manipulating unsigned types, then folding into negative + values can produce incorrect results. Particularly if the type + is smaller than the width of the pointer. */ + if (subtract + && TYPE_UNSIGNED (TREE_TYPE (op1)) + && tree_int_cst_lt (array_idx, op1)) + return NULL; + op1 = int_const_binop (subtract ? MINUS_EXPR : PLUS_EXPR, + array_idx, op1, 0); + subtract = false; + op0 = array_obj; + } + + /* If we weren't able to fold the subtraction into another array reference, + canonicalize the integer for passing to the array and component ref + simplification functions. */ + if (subtract) + { + if (TYPE_UNSIGNED (TREE_TYPE (op1))) + return NULL; + op1 = fold (build1 (NEGATE_EXPR, TREE_TYPE (op1), op1)); + /* ??? In theory fold should always produce another integer. */ + if (TREE_CODE (op1) != INTEGER_CST) + return NULL; + } + + ptd_type = TREE_TYPE (ptr_type); + + /* At which point we can try some of the same things as for indirects. */ + t = maybe_fold_offset_to_array_ref (op0, op1, ptd_type); + if (!t) + t = maybe_fold_offset_to_component_ref (TREE_TYPE (op0), op0, op1, + ptd_type, false); + if (t) + t = build1 (ADDR_EXPR, ptr_type, t); + + return t; +} + +/* Subroutine of fold_stmt called via walk_tree. We perform several + simplifications of EXPR_P, mostly having to do with pointer arithmetic. */ + +static tree +fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data) +{ + bool *changed_p = data; + tree expr = *expr_p, t; + + /* ??? It'd be nice if walk_tree had a pre-order option. */ + switch (TREE_CODE (expr)) + { + case INDIRECT_REF: + t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL); + if (t) + return t; + *walk_subtrees = 0; + + t = maybe_fold_stmt_indirect (expr, TREE_OPERAND (expr, 0), + integer_zero_node); + break; + + /* ??? Could handle ARRAY_REF here, as a variant of INDIRECT_REF. + We'd only want to bother decomposing an existing ARRAY_REF if + the base array is found to have another offset contained within. + Otherwise we'd be wasting time. */ + + case ADDR_EXPR: + t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL); + if (t) + return t; + *walk_subtrees = 0; + + /* Set TREE_INVARIANT properly so that the value is properly + considered constant, and so gets propagated as expected. */ + if (*changed_p) + recompute_tree_invarant_for_addr_expr (expr); + return NULL_TREE; + + case PLUS_EXPR: + case MINUS_EXPR: + t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL); + if (t) + return t; + t = walk_tree (&TREE_OPERAND (expr, 1), fold_stmt_r, data, NULL); + if (t) + return t; + *walk_subtrees = 0; + + t = maybe_fold_stmt_addition (expr); + break; + + case COMPONENT_REF: + t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL); + if (t) + return t; + *walk_subtrees = 0; + + /* Make sure the FIELD_DECL is actually a field in the type on + the lhs. In cases with IMA it is possible that it came + from another, equivalent type at this point. We have + already checked the equivalence in this case. + Match on type plus offset, to allow for unnamed fields. + We won't necessarily get the corresponding field for + unions; this is believed to be harmless. */ + + if ((current_file_decl && TREE_CHAIN (current_file_decl)) + && (DECL_FIELD_CONTEXT (TREE_OPERAND (expr, 1)) != + TREE_TYPE (TREE_OPERAND (expr, 0)))) + { + tree f; + tree orig_field = TREE_OPERAND (expr, 1); + tree orig_type = TREE_TYPE (orig_field); + for (f = TYPE_FIELDS (TREE_TYPE (TREE_OPERAND (expr, 0))); + f; f = TREE_CHAIN (f)) + { + if (lang_hooks.types_compatible_p (TREE_TYPE (f), orig_type) + && tree_int_cst_compare (DECL_FIELD_BIT_OFFSET (f), + DECL_FIELD_BIT_OFFSET (orig_field)) + == 0 + && tree_int_cst_compare (DECL_FIELD_OFFSET (f), + DECL_FIELD_OFFSET (orig_field)) + == 0) + { + TREE_OPERAND (expr, 1) = f; + break; + } + } + /* Fall through is an error; it will be detected in tree-sra. */ + } + break; + + default: + return NULL_TREE; + } + + if (t) + { + *expr_p = t; + *changed_p = true; + } + + return NULL_TREE; +} + +/* Fold the statement pointed by STMT_P. In some cases, this function may + replace the whole statement with a new one. Returns true iff folding + makes any changes. */ + +bool +fold_stmt (tree *stmt_p) +{ + tree rhs, result, stmt; + bool changed = false; + + stmt = *stmt_p; + + /* If we replaced constants and the statement makes pointer dereferences, + then we may need to fold instances of *&VAR into VAR, etc. */ + if (walk_tree (stmt_p, fold_stmt_r, &changed, NULL)) + { + *stmt_p + = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP], + NULL); + return true; + } + + rhs = get_rhs (stmt); + if (!rhs) + return changed; + result = NULL_TREE; + + /* Check for builtins that CCP can handle using information not + available in the generic fold routines. */ + if (TREE_CODE (rhs) == CALL_EXPR) + { + tree callee = get_callee_fndecl (rhs); + if (callee && DECL_BUILT_IN (callee)) + result = ccp_fold_builtin (stmt, rhs); + } + + /* If we couldn't fold the RHS, hand over to the generic fold routines. */ + if (result == NULL_TREE) + result = fold (rhs); + + /* Strip away useless type conversions. Both the NON_LVALUE_EXPR that + may have been added by fold, and "useless" type conversions that might + now be apparent due to propagation. */ + STRIP_MAIN_TYPE_NOPS (result); + STRIP_USELESS_TYPE_CONVERSION (result); + + if (result != rhs) + { + changed = true; + set_rhs (stmt_p, result); + } + + return changed; +} + +/* Get the main expression from statement STMT. */ + +static tree +get_rhs (tree stmt) +{ + enum tree_code code = TREE_CODE (stmt); + + if (code == MODIFY_EXPR) + return TREE_OPERAND (stmt, 1); + if (code == COND_EXPR) + return COND_EXPR_COND (stmt); + else if (code == SWITCH_EXPR) + return SWITCH_COND (stmt); + else if (code == RETURN_EXPR) + { + if (!TREE_OPERAND (stmt, 0)) + return NULL_TREE; + if (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR) + return TREE_OPERAND (TREE_OPERAND (stmt, 0), 1); + else + return TREE_OPERAND (stmt, 0); + } + else if (code == GOTO_EXPR) + return GOTO_DESTINATION (stmt); + else if (code == LABEL_EXPR) + return LABEL_EXPR_LABEL (stmt); + else + return stmt; +} + + +/* Set the main expression of *STMT_P to EXPR. */ + +static void +set_rhs (tree *stmt_p, tree expr) +{ + tree stmt = *stmt_p; + enum tree_code code = TREE_CODE (stmt); + + if (code == MODIFY_EXPR) + TREE_OPERAND (stmt, 1) = expr; + else if (code == COND_EXPR) + COND_EXPR_COND (stmt) = expr; + else if (code == SWITCH_EXPR) + SWITCH_COND (stmt) = expr; + else if (code == RETURN_EXPR) + { + if (TREE_OPERAND (stmt, 0) + && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR) + TREE_OPERAND (TREE_OPERAND (stmt, 0), 1) = expr; + else + TREE_OPERAND (stmt, 0) = expr; + } + else if (code == GOTO_EXPR) + GOTO_DESTINATION (stmt) = expr; + else if (code == LABEL_EXPR) + LABEL_EXPR_LABEL (stmt) = expr; + else + { + /* Replace the whole statement with EXPR. If EXPR has no side + effects, then replace *STMT_P with an empty statement. */ + stmt_ann_t ann = stmt_ann (stmt); + *stmt_p = TREE_SIDE_EFFECTS (expr) ? expr : build_empty_stmt (); + (*stmt_p)->common.ann = (tree_ann) ann; + + if (TREE_SIDE_EFFECTS (expr)) + { + def_optype defs; + vdef_optype vdefs; + size_t i; + + /* Fix all the SSA_NAMEs created by *STMT_P to point to its new + replacement. */ + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree var = DEF_OP (defs, i); + if (TREE_CODE (var) == SSA_NAME) + SSA_NAME_DEF_STMT (var) = *stmt_p; + } + + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + tree var = VDEF_RESULT (vdefs, i); + if (TREE_CODE (var) == SSA_NAME) + SSA_NAME_DEF_STMT (var) = *stmt_p; + } + } + } +} + + +/* Return a default value for variable VAR using the following rules: + + 1- Global and static variables are considered VARYING, unless they are + declared const. + + 2- Function arguments are considered VARYING. + + 3- Any other value is considered UNDEFINED. This is useful when + considering PHI nodes. PHI arguments that are undefined do not + change the constant value of the PHI node, which allows for more + constants to be propagated. */ + +static value +get_default_value (tree var) +{ + value val; + tree sym; + + if (TREE_CODE (var) == SSA_NAME) + sym = SSA_NAME_VAR (var); + else + { +#ifdef ENABLE_CHECKING + if (!DECL_P (var)) + abort (); +#endif + sym = var; + } + + val.lattice_val = UNDEFINED; + val.const_val = NULL_TREE; + + if (TREE_CODE (sym) == PARM_DECL || TREE_THIS_VOLATILE (sym)) + { + /* Function arguments and volatile variables are considered VARYING. */ + val.lattice_val = VARYING; + } + else if (decl_function_context (sym) != current_function_decl + || TREE_STATIC (sym)) + { + /* Globals and static variables are considered VARYING, unless they + are declared 'const'. */ + val.lattice_val = VARYING; + + if (TREE_READONLY (sym) + && DECL_INITIAL (sym) + && is_gimple_min_invariant (DECL_INITIAL (sym))) + { + val.lattice_val = CONSTANT; + val.const_val = DECL_INITIAL (sym); + } + } + else + { + enum tree_code code; + tree stmt = SSA_NAME_DEF_STMT (var); + + if (!IS_EMPTY_STMT (stmt)) + { + code = TREE_CODE (stmt); + if (code != MODIFY_EXPR && code != PHI_NODE) + val.lattice_val = VARYING; + } + } + + return val; +} + + +/* Fold builtin call FN in statement STMT. If it cannot be folded into a + constant, return NULL_TREE. Otherwise, return its constant value. */ + +static tree +ccp_fold_builtin (tree stmt, tree fn) +{ + tree result, strlen_val[2]; + tree arglist = TREE_OPERAND (fn, 1), a; + tree callee = get_callee_fndecl (fn); + bitmap visited; + int strlen_arg, i; + + /* Ignore MD builtins. */ + if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD) + return NULL_TREE; + + /* First try the generic builtin folder. If that succeeds, return the + result directly. */ + result = fold_builtin (fn); + if (result) + return result; + + /* If the builtin could not be folded, and it has no argument list, + we're done. */ + if (!arglist) + return NULL_TREE; + + /* Limit the work only for builtins we know how to simplify. */ + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_STRLEN: + case BUILT_IN_FPUTS: + case BUILT_IN_FPUTS_UNLOCKED: + strlen_arg = 1; + break; + case BUILT_IN_STRCPY: + case BUILT_IN_STRNCPY: + strlen_arg = 2; + break; + default: + return NULL_TREE; + } + + /* Try to use the dataflow information gathered by the CCP process. */ + visited = BITMAP_XMALLOC (); + + memset (strlen_val, 0, sizeof (strlen_val)); + for (i = 0, a = arglist; + strlen_arg; + i++, strlen_arg >>= 1, a = TREE_CHAIN (a)) + if (strlen_arg & 1) + { + bitmap_clear (visited); + if (!get_strlen (TREE_VALUE (a), &strlen_val[i], visited)) + strlen_val[i] = NULL_TREE; + } + + BITMAP_XFREE (visited); + + /* FIXME. All this code looks dangerous in the sense that it might + create non-gimple expressions. */ + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_STRLEN: + /* Convert from the internal "sizetype" type to "size_t". */ + if (strlen_val[0] + && size_type_node) + { + tree new = convert (size_type_node, strlen_val[0]); + + /* If the result is not a valid gimple value, or not a cast + of a valid gimple value, then we can not use the result. */ + if (is_gimple_val (new) + || (is_gimple_cast (new) + && is_gimple_val (TREE_OPERAND (new, 0)))) + return new; + else + return NULL_TREE; + } + return strlen_val[0]; + case BUILT_IN_STRCPY: + if (strlen_val[1] + && is_gimple_val (strlen_val[1])) + return simplify_builtin_strcpy (arglist, strlen_val[1]); + case BUILT_IN_STRNCPY: + if (strlen_val[1] + && is_gimple_val (strlen_val[1])) + return simplify_builtin_strncpy (arglist, strlen_val[1]); + case BUILT_IN_FPUTS: + return simplify_builtin_fputs (arglist, + TREE_CODE (stmt) != MODIFY_EXPR, 0, + strlen_val[0]); + case BUILT_IN_FPUTS_UNLOCKED: + return simplify_builtin_fputs (arglist, + TREE_CODE (stmt) != MODIFY_EXPR, 1, + strlen_val[0]); + + default: + abort (); + } + + return NULL_TREE; +} + + +/* Return the string length of ARG in LENGTH. If ARG is an SSA name variable, + follow its use-def chains. If LENGTH is not NULL and its value is not + equal to the length we determine, or if we are unable to determine the + length, return false. VISITED is a bitmap of visited variables. */ + +static bool +get_strlen (tree arg, tree *length, bitmap visited) +{ + tree var, def_stmt, val; + + if (TREE_CODE (arg) != SSA_NAME) + { + val = c_strlen (arg, 1); + if (!val) + return false; + + if (*length && simple_cst_equal (val, *length) != 1) + return false; + + *length = val; + return true; + } + + /* If we were already here, break the infinite cycle. */ + if (bitmap_bit_p (visited, SSA_NAME_VERSION (arg))) + return true; + bitmap_set_bit (visited, SSA_NAME_VERSION (arg)); + + var = arg; + def_stmt = SSA_NAME_DEF_STMT (var); + + switch (TREE_CODE (def_stmt)) + { + case MODIFY_EXPR: + { + tree len, rhs; + + /* The RHS of the statement defining VAR must either have a + constant length or come from another SSA_NAME with a constant + length. */ + rhs = TREE_OPERAND (def_stmt, 1); + STRIP_NOPS (rhs); + if (TREE_CODE (rhs) == SSA_NAME) + return get_strlen (rhs, length, visited); + + /* See if the RHS is a constant length. */ + len = c_strlen (rhs, 1); + if (len) + { + if (*length && simple_cst_equal (len, *length) != 1) + return false; + + *length = len; + return true; + } + + break; + } + + case PHI_NODE: + { + /* All the arguments of the PHI node must have the same constant + length. */ + int i; + + for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++) + { + tree arg = PHI_ARG_DEF (def_stmt, i); + + /* If this PHI has itself as an argument, we cannot + determine the string length of this argument. However, + if we can find a constant string length for the other + PHI args then we can still be sure that this is a + constant string length. So be optimistic and just + continue with the next argument. */ + if (arg == PHI_RESULT (def_stmt)) + continue; + + if (!get_strlen (arg, length, visited)) + return false; + } + + return true; + } + + default: + break; + } + + + return false; +} + + +/* A simple pass that attempts to fold all builtin functions. This pass + is run after we've propagated as many constants as we can. */ + +static void +execute_fold_all_builtins (void) +{ + basic_block bb; + FOR_EACH_BB (bb) + { + block_stmt_iterator i; + for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) + { + tree *stmtp = bsi_stmt_ptr (i); + tree call = get_rhs (*stmtp); + tree callee, result; + + if (!call || TREE_CODE (call) != CALL_EXPR) + continue; + callee = get_callee_fndecl (call); + if (!callee || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL) + continue; + + result = ccp_fold_builtin (*stmtp, call); + if (!result) + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_CONSTANT_P: + /* Resolve __builtin_constant_p. If it hasn't been + folded to integer_one_node by now, it's fairly + certain that the value simply isn't constant. */ + result = integer_zero_node; + break; + + default: + continue; + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Simplified\n "); + print_generic_stmt (dump_file, *stmtp, dump_flags); + } + + set_rhs (stmtp, result); + modify_stmt (*stmtp); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "to\n "); + print_generic_stmt (dump_file, *stmtp, dump_flags); + fprintf (dump_file, "\n"); + } + } + } +} + +struct tree_opt_pass pass_fold_builtins = +{ + "fab", /* name */ + NULL, /* gate */ + execute_fold_all_builtins, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */ +}; + + +#include "gt-tree-ssa-ccp.h" diff --git a/gcc/tree-ssa-copy.c b/gcc/tree-ssa-copy.c new file mode 100644 index 00000000000..ca9f0cce81a --- /dev/null +++ b/gcc/tree-ssa-copy.c @@ -0,0 +1,355 @@ +/* Const/copy propagation and SSA_NAME replacement support routines. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "tm_p.h" +#include "ggc.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "expr.h" +#include "function.h" +#include "diagnostic.h" +#include "timevar.h" +#include "tree-dump.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "langhooks.h" + +/* This file provides a handful of interfaces for performing const/copy + propagation and simple expression replacement which keep variable + annotations up-to-date. + + We require that for any copy operation where the RHS and LHS have + a non-null memory tag that the memory tag be the same. It is OK + for one or both of the memory tags to be NULL. + + We also require tracking if a variable is dereferenced in a load or + store operation. + + We enforce these requirements by having all copy propagation and + replacements of one SSA_NAME with a different SSA_NAME to use the + APIs defined in this file. */ + +/* Given two SSA_NAMEs, replace the one pointed to by OP_P with VAR. + + If *OP_P is a pointer, copy the memory tag used originally by *OP_P into + VAR. This is needed in cases where VAR had never been dereferenced in the + program. + + If FOR_PROPAGATION is true, then perform additional checks to ensure + that const/copy propagation of var for *OP_P is valid. */ + +static void +replace_ssa_names (tree *op_p, + tree var, + bool for_propagation ATTRIBUTE_UNUSED) +{ +#if defined ENABLE_CHECKING + if (for_propagation && !may_propagate_copy (*op_p, var)) + abort (); +#endif + + /* If VAR doesn't have a memory tag, copy the one from the original + operand. Also copy the dereferenced flags. */ + if (POINTER_TYPE_P (TREE_TYPE (*op_p))) + { + var_ann_t new_ann = var_ann (SSA_NAME_VAR (var)); + var_ann_t orig_ann = var_ann (SSA_NAME_VAR (*op_p)); + + if (new_ann->type_mem_tag == NULL_TREE) + new_ann->type_mem_tag = orig_ann->type_mem_tag; + else if (orig_ann->type_mem_tag == NULL_TREE) + orig_ann->type_mem_tag = new_ann->type_mem_tag; + else if (new_ann->type_mem_tag != orig_ann->type_mem_tag) + abort (); + } + + *op_p = var; +} + +/* Common code for propagate_value and replace_exp. + + Replace *OP_P with VAL. FOR_PROPAGATION indicates if the replacement + is done to propagate a value or not. */ + +static void +replace_exp_1 (tree *op_p, tree val, bool for_propagation) +{ + if (TREE_CODE (val) == SSA_NAME) + { + if (TREE_CODE (*op_p) == SSA_NAME) + replace_ssa_names (op_p, val, for_propagation); + else + *op_p = val; + } + else + *op_p = lhd_unsave_expr_now (val); +} + +/* Propagate the value VAL (assumed to be a constant or another SSA_NAME) + into the operand pointed by OP_P. + + Use this version for const/copy propagation as it will perform additional + checks to ensure validity of the const/copy propagation. */ + +void +propagate_value (tree *op_p, tree val) +{ + replace_exp_1 (op_p, val, true); +} + +/* Replace *OP_P with value VAL (assumed to be a constant or another SSA_NAME). + + Use this version when not const/copy propagating values. For example, + PRE uses this version when building expressions as they would appear + in specific blocks taking into account actions of PHI nodes. */ + +void +replace_exp (tree *op_p, tree val) +{ + replace_exp_1 (op_p, val, false); +} + +/* Replace *OP_P in STMT with any known equivalent value for *OP_P from + CONST_AND_COPIES. */ + +static bool +cprop_operand (stmt_ann_t ann, tree *op_p, varray_type const_and_copies) +{ + bool may_have_exposed_new_symbols = false; + tree val; + + /* If the operand has a known constant value or it is known to be a + copy of some other variable, use the value or copy stored in + CONST_AND_COPIES. */ + val = VARRAY_TREE (const_and_copies, SSA_NAME_VERSION (*op_p)); + if (val) + { + tree op_type, val_type; + + /* Do not change the base variable in the virtual operand + tables. That would make it impossible to reconstruct + the renamed virtual operand if we later modify this + statement. Also only allow the new value to be an SSA_NAME + for propagation into virtual operands. */ + if (!is_gimple_reg (*op_p) + && (get_virtual_var (val) != get_virtual_var (*op_p) + || TREE_CODE (val) != SSA_NAME)) + return false; + + /* Get the toplevel type of each operand. */ + op_type = TREE_TYPE (*op_p); + val_type = TREE_TYPE (val); + + /* While both types are pointers, get the type of the object + pointed to. */ + while (POINTER_TYPE_P (op_type) && POINTER_TYPE_P (val_type)) + { + op_type = TREE_TYPE (op_type); + val_type = TREE_TYPE (val_type); + } + + /* Make sure underlying types match before propagating a + constant by converting the constant to the proper type. Note + that convert may return a non-gimple expression, in which case + we ignore this propagation opportunity. */ + if (!lang_hooks.types_compatible_p (op_type, val_type) + && TREE_CODE (val) != SSA_NAME) + { + val = convert (TREE_TYPE (*op_p), val); + if (!is_gimple_min_invariant (val) + && TREE_CODE (val) != SSA_NAME) + return false; + } + + /* Certain operands are not allowed to be copy propagated due + to their interaction with exception handling and some GCC + extensions. */ + if (TREE_CODE (val) == SSA_NAME + && !may_propagate_copy (*op_p, val)) + return false; + + /* Dump details. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Replaced '"); + print_generic_expr (dump_file, *op_p, dump_flags); + fprintf (dump_file, "' with %s '", + (TREE_CODE (val) != SSA_NAME ? "constant" : "variable")); + print_generic_expr (dump_file, val, dump_flags); + fprintf (dump_file, "'\n"); + } + + /* If VAL is an ADDR_EXPR or a constant of pointer type, note + that we may have exposed a new symbol for SSA renaming. */ + if (TREE_CODE (val) == ADDR_EXPR + || (POINTER_TYPE_P (TREE_TYPE (*op_p)) + && is_gimple_min_invariant (val))) + may_have_exposed_new_symbols = true; + + propagate_value (op_p, val); + + /* And note that we modified this statement. This is now + safe, even if we changed virtual operands since we will + rescan the statement and rewrite its operands again. */ + ann->modified = 1; + } + return may_have_exposed_new_symbols; +} + +/* CONST_AND_COPIES is a table which maps an SSA_NAME to the current + known value for that SSA_NAME (or NULL if no value is known). + + Propagate values from CONST_AND_COPIES into the uses, vuses and + vdef_ops of STMT. */ + +bool +cprop_into_stmt (tree stmt, varray_type const_and_copies) +{ + bool may_have_exposed_new_symbols = false; + stmt_ann_t ann = stmt_ann (stmt); + size_t i, num_uses, num_vuses, num_vdefs; + vuse_optype vuses; + vdef_optype vdefs; + use_optype uses; + + uses = USE_OPS (ann); + num_uses = NUM_USES (uses); + for (i = 0; i < num_uses; i++) + { + tree *op_p = USE_OP_PTR (uses, i); + if (TREE_CODE (*op_p) == SSA_NAME) + may_have_exposed_new_symbols + |= cprop_operand (ann, op_p, const_and_copies); + } + + vuses = VUSE_OPS (ann); + num_vuses = NUM_VUSES (vuses); + for (i = 0; i < num_vuses; i++) + { + tree *op_p = VUSE_OP_PTR (vuses, i); + if (TREE_CODE (*op_p) == SSA_NAME) + may_have_exposed_new_symbols + |= cprop_operand (ann, op_p, const_and_copies); + } + + vdefs = VDEF_OPS (ann); + num_vdefs = NUM_VDEFS (vdefs); + for (i = 0; i < num_vdefs; i++) + { + tree *op_p = VDEF_OP_PTR (vdefs, i); + if (TREE_CODE (*op_p) == SSA_NAME) + may_have_exposed_new_symbols + |= cprop_operand (ann, op_p, const_and_copies); + } + return may_have_exposed_new_symbols; +} + +/* CONST_AND_COPIES is a table which maps an SSA_NAME to the current + known value for that SSA_NAME (or NULL if no value is known). + + Propagate values from CONST_AND_COPIES into the PHI nodes of the + successors of BB. */ + +void +cprop_into_successor_phis (basic_block bb, varray_type const_and_copies) +{ + edge e; + + /* This can get rather expensive if the implementation is naive in + how it finds the phi alternative associated with a particular edge. */ + for (e = bb->succ; e; e = e->succ_next) + { + tree phi; + int phi_num_args; + int hint; + + /* If this is an abnormal edge, then we do not want to copy propagate + into the PHI alternative associated with this edge. */ + if (e->flags & EDGE_ABNORMAL) + continue; + + phi = phi_nodes (e->dest); + if (! phi) + continue; + + /* There is no guarantee that for any two PHI nodes in a block that + the phi alternative associated with a particular edge will be + at the same index in the phi alternative array. + + However, it is very likely they will be the same. So we keep + track of the index of the alternative where we found the edge in + the previous phi node and check that index first in the next + phi node. If that hint fails, then we actually search all + the entries. */ + phi_num_args = PHI_NUM_ARGS (phi); + hint = phi_num_args; + for ( ; phi; phi = TREE_CHAIN (phi)) + { + int i; + tree new; + tree *orig_p; + + /* If the hint is valid (!= phi_num_args), see if it points + us to the desired phi alternative. */ + if (hint != phi_num_args && PHI_ARG_EDGE (phi, hint) == e) + ; + else + { + /* The hint was either invalid or did not point to the + correct phi alternative. Search all the alternatives + for the correct one. Update the hint. */ + for (i = 0; i < phi_num_args; i++) + if (PHI_ARG_EDGE (phi, i) == e) + break; + hint = i; + } + +#ifdef ENABLE_CHECKING + /* If we did not find the proper alternative, then something is + horribly wrong. */ + if (hint == phi_num_args) + abort (); +#endif + + /* The alternative may be associated with a constant, so verify + it is an SSA_NAME before doing anything with it. */ + orig_p = &PHI_ARG_DEF (phi, hint); + if (TREE_CODE (*orig_p) != SSA_NAME) + continue; + + /* If we have *ORIG_P in our constant/copy table, then replace + ORIG_P with its value in our constant/copy table. */ + new = VARRAY_TREE (const_and_copies, SSA_NAME_VERSION (*orig_p)); + if (new + && (TREE_CODE (new) == SSA_NAME + || is_gimple_min_invariant (new)) + && may_propagate_copy (*orig_p, new)) + propagate_value (orig_p, new); + } + } +} diff --git a/gcc/tree-ssa-copyrename.c b/gcc/tree-ssa-copyrename.c new file mode 100644 index 00000000000..91c0f74ac55 --- /dev/null +++ b/gcc/tree-ssa-copyrename.c @@ -0,0 +1,388 @@ +/* Rename SSA copies. + Copyright (C) 2004 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "basic-block.h" +#include "function.h" +#include "diagnostic.h" +#include "bitmap.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "timevar.h" +#include "tree-alias-common.h" +#include "hashtab.h" +#include "tree-dump.h" +#include "tree-ssa-live.h" +#include "tree-pass.h" + +extern void rename_ssa_copies (void); + +/* The following routines implement the SSA copy renaming phase. + + This optimization looks for copies between 2 SSA_NAMES, either through a + direct copy, or an implicit one via a PHI node result and its arguments. + + Each copy is examined to determine if it is possible to rename the base + variable of one of the operands to the same variable as the other operand. + ie. + T.3_5 = + a_1 = T.3_5 + + If this copy couldn't be copy propagated, it could possibly remain in the + program throughout the optimization phases. After SSA->normal, it would + become: + + T.3 = + a = T.3 + + Since T.3_5 is distinct from all other SSA versions of T.3, there is no + fundamental reason why the base variable needs to be T.3, subject to + certain restrictions. This optimization attempts to determine if we can + change the base variable on copies like this, and result in code such as: + + a_5 = + a_1 = a_5 + + This gives the SSA->normal pass a shot at coalescing a_1 and a_5. If it is + possible, the copy goes away completely. If it isn't possible, a new temp + will be created for a_5, and you will end up with the exact same code: + + a.8 = + a = a.8 + + The other benefit of performing this optimization relates to what variables + are chosen in copies. Gimplification of the program uses temporaries for + a lot of things. expressions like + + a_1 = + = a_1 + + get turned into + + T.3_5 = + a_1 = T.3_5 + = a_1 + + Copy propagation is done in a forward direction, and if we can propagate + through the copy, we end up with: + + T.3_5 = + = T.3_5 + + The copy is gone, but so is all reference to the user variable 'a'. By + performing this optimization, we would see the sequence: + + a_5 = + a_1 = a_5 + = a_1 + + which copy propagation would then turn into: + + a_5 = + = a_5 + + and so we still retain the user variable whenever possible. */ + + +/* Coalesce the partitions in MAP representing VAR1 and VAR2 if it is valid. + Choose a representative for the partition, and send debug info to DEBUG. */ + +static void +copy_rename_partition_coalesce (var_map map, tree var1, tree var2, FILE *debug) +{ + int p1, p2, p3; + tree root1, root2; + var_ann_t ann1, ann2, ann3; + bool gimp1, gimp2; + +#ifdef ENABLE_CHECKING + if (TREE_CODE (var1) != SSA_NAME || TREE_CODE (var2) != SSA_NAME) + abort (); +#endif + + register_ssa_partition (map, var1, false); + register_ssa_partition (map, var2, true); + + p1 = partition_find (map->var_partition, SSA_NAME_VERSION (var1)); + p2 = partition_find (map->var_partition, SSA_NAME_VERSION (var2)); + + if (debug) + { + fprintf (debug, "Try : "); + print_generic_expr (debug, var1, TDF_SLIM); + fprintf (debug, "(P%d) & ", p1); + print_generic_expr (debug, var2, TDF_SLIM); + fprintf (debug, "(P%d)", p2); + } + +#ifdef ENABLE_CHECKING + if (p1 == NO_PARTITION || p2 == NO_PARTITION) + abort (); +#endif + + root1 = SSA_NAME_VAR (partition_to_var (map, p1)); + root2 = SSA_NAME_VAR (partition_to_var (map, p2)); + + if (DECL_HARD_REGISTER (root1) || DECL_HARD_REGISTER (root2)) + { + if (debug) + { + if (DECL_HARD_REGISTER (root1)) + print_generic_expr (debug, var1, TDF_SLIM); + else + print_generic_expr (debug, var2, TDF_SLIM); + fprintf (debug, " is a hardware register. No Coalescing.\n"); + } + return; + } + + ann1 = var_ann (root1); + ann2 = var_ann (root2); + + if (p1 == p2) + { + if (debug) + fprintf (debug, " : Already coalesced.\n"); + return; + } + + /* Partitions already have the same root, simply merge them. */ + if (root1 == root2) + { + p1 = partition_union (map->var_partition, p1, p2); + if (debug) + fprintf (debug, " : Same root, coalesced --> P%d.\n", p1); + return; + } + + /* Never attempt to coalesce 2 difference parameters. */ + if (TREE_CODE (root1) == PARM_DECL && TREE_CODE (root2) == PARM_DECL) + { + if (debug) + fprintf (debug, " : 2 different PARM_DECLS. No coalesce.\n"); + return; + } + + gimp1 = is_gimple_tmp_var (root1); + gimp2 = is_gimple_tmp_var (root2); + + /* Never attempt to coalesce 2 user variables unless one is an inline + variable. */ + if (!gimp1 && !gimp2) + { + if (DECL_FROM_INLINE (root2)) + gimp2 = true; + else + if (DECL_FROM_INLINE (root1)) + gimp1 = true; + else + { + if (debug) + fprintf (debug, " : 2 different USER vars. No coalesce.\n"); + return; + } + } + + + /* Don't coalesce if there are two different memory tags. */ + if (ann1->type_mem_tag && ann2->type_mem_tag + && ann1->type_mem_tag != ann2->type_mem_tag) + { + if (debug) + fprintf (debug, " : 2 memory tags. No coalesce.\n"); + return; + } + + /* If both values have default defs, we can't coalesce. If only one has a + tag, make sure that variable is the new root partition. */ + if (default_def (root1)) + { + if (default_def (root2)) + { + if (debug) + fprintf (debug, " : 2 default defs. No coalesce.\n"); + return; + } + else + { + gimp2 = true; + gimp1 = false; + } + } + else + if (default_def (root2)) + { + gimp1 = true; + gimp2 = false; + } + + /* Merge the two partitions. */ + p3 = partition_union (map->var_partition, p1, p2); + + /* Set the root variable of the partition to the better choice, if there is + one. */ + if (!gimp2) + SSA_NAME_VAR (partition_to_var (map, p3)) = root2; + else + if (!gimp1) + SSA_NAME_VAR (partition_to_var (map, p3)) = root1; + + /* Update the various flag widgitry of the current base representative. */ + ann3 = var_ann (SSA_NAME_VAR (partition_to_var (map, p3))); + if (ann1->type_mem_tag) + ann3->type_mem_tag = ann1->type_mem_tag; + else + ann3->type_mem_tag = ann2->type_mem_tag; + + if (debug) + { + fprintf (debug, " --> P%d ", p3); + print_generic_expr (debug, SSA_NAME_VAR (partition_to_var (map, p3)), + TDF_SLIM); + fprintf (debug, "\n"); + } +} + + +/* This function will make a pass through the IL, and attempt to coalesce any + SSA versions which occur in PHI's or copies. Coalescing is accomplished by + changing the underlying root variable of all coalesced version. This will + then cause the SSA->normal pass to attempt to coalesce them all to the same + variable. */ + +void +rename_ssa_copies (void) +{ + var_map map; + basic_block bb; + block_stmt_iterator bsi; + tree phi, stmt, var, part_var; + unsigned x; + FILE *debug; + + if (dump_file && (dump_flags & TDF_DETAILS)) + debug = dump_file; + else + debug = NULL; + + map = init_var_map (highest_ssa_version + 1); + + FOR_EACH_BB (bb) + { + /* Scan for real copies. */ + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + if (TREE_CODE (stmt) == MODIFY_EXPR) + { + tree lhs = TREE_OPERAND (stmt, 0); + tree rhs = TREE_OPERAND (stmt, 1); + + if (TREE_CODE (lhs) == SSA_NAME + && !has_hidden_use (SSA_NAME_VAR (lhs)) + && TREE_CODE (rhs) == SSA_NAME) + copy_rename_partition_coalesce (map, lhs, rhs, debug); + } + } + } + + FOR_EACH_BB (bb) + { + /* Treat PHI nodes as copies between the result and each argument. */ + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + int i; + tree res = PHI_RESULT (phi); + + /* Do not process virtual SSA_NAMES or variables which have + hidden uses. */ + if (!is_gimple_reg (SSA_NAME_VAR (res)) + || has_hidden_use (SSA_NAME_VAR (res))) + continue; + + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + tree arg = PHI_ARG_DEF (phi, i); + if (TREE_CODE (arg) == SSA_NAME) + copy_rename_partition_coalesce (map, res, arg, debug); + } + } + } + + if (debug) + dump_var_map (debug, map); + + /* Now one more pass to make all elements of a partition share the same + root variable. */ + + for (x = 1; x <= highest_ssa_version; x++) + { + part_var = partition_to_var (map, x); + if (!part_var) + continue; + var = map->partition_to_var[x]; + if (debug) + { + if (SSA_NAME_VAR (var) != SSA_NAME_VAR (part_var)) + { + fprintf (debug, "Coalesced "); + print_generic_expr (debug, var, TDF_SLIM); + fprintf (debug, " to "); + print_generic_expr (debug, part_var, TDF_SLIM); + fprintf (debug, "\n"); + } + } + SSA_NAME_VAR (var) = SSA_NAME_VAR (part_var); + } + + delete_var_map (map); +} + +/* Return true if copy rename is to be performed. */ + +static bool +gate_copyrename (void) +{ + return flag_tree_copyrename != 0; +} + +struct tree_opt_pass pass_rename_ssa_copies = +{ + "copyrename", /* name */ + gate_copyrename, /* gate */ + rename_ssa_copies, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_COPY_RENAME, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */ +}; + diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c new file mode 100644 index 00000000000..dc11ca102c6 --- /dev/null +++ b/gcc/tree-ssa-dce.c @@ -0,0 +1,911 @@ +/* Dead code elimination pass for the GNU compiler. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Ben Elliston + and Andrew MacLeod + Adapted to use control dependence by Steven Bosscher, SUSE Labs. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Dead code elimination. + + References: + + Building an Optimizing Compiler, + Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9. + + Advanced Compiler Design and Implementation, + Steven Muchnick, Morgan Kaufmann, 1997, Section 18.10. + + Dead-code elimination is the removal of statements which have no + impact on the program's output. "Dead statements" have no impact + on the program's output, while "necessary statements" may have + impact on the output. + + The algorithm consists of three phases: + 1. Marking as necessary all statements known to be necessary, + e.g. most function calls, writing a value to memory, etc; + 2. Propagating necessary statements, e.g., the statements + giving values to operands in necessary statements; and + 3. Removing dead statements. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" + +/* These RTL headers are needed for basic-block.h. */ +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" + +#include "tree.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "timevar.h" +#include "flags.h" + +static struct stmt_stats +{ + int total; + int total_phis; + int removed; + int removed_phis; +} stats; + +static varray_type worklist; + +/* Vector indicating an SSA name has already been processed and marked + as necessary. */ +static sbitmap processed; + +/* Vector indicating that last_stmt if a basic block has already been + marked as necessary. */ +static sbitmap last_stmt_necessary; + +/* Before we can determine whether a control branch is dead, we need to + compute which blocks are control dependent on which edges. + + We expect each block to be control dependent on very few edges so we + use a bitmap for each block recording its edges. An array holds the + bitmap. The Ith bit in the bitmap is set if that block is dependent + on the Ith edge. */ +bitmap *control_dependence_map; + +/* Execute CODE for each edge (given number EDGE_NUMBER within the CODE) + for which the block with index N is control dependent. */ +#define EXECUTE_IF_CONTROL_DEPENDENT(N, EDGE_NUMBER, CODE) \ + EXECUTE_IF_SET_IN_BITMAP (control_dependence_map[N], 0, EDGE_NUMBER, CODE) + +/* Local function prototypes. */ +static inline void set_control_dependence_map_bit (basic_block, int); +static inline void clear_control_dependence_bitmap (basic_block); +static void find_all_control_dependences (struct edge_list *); +static void find_control_dependence (struct edge_list *, int); +static inline basic_block find_pdom (basic_block); + +static inline void mark_stmt_necessary (tree, bool); +static inline void mark_operand_necessary (tree); + +static bool need_to_preserve_store (tree); +static void mark_stmt_if_obviously_necessary (tree, bool); +static void find_obviously_necessary_stmts (struct edge_list *); + +static void mark_control_dependent_edges_necessary (basic_block, struct edge_list *); +static void propagate_necessity (struct edge_list *); + +static void eliminate_unnecessary_stmts (void); +static void remove_dead_phis (basic_block); +static void remove_dead_stmt (block_stmt_iterator *, basic_block); + +static void print_stats (void); +static void tree_dce_init (bool); +static void tree_dce_done (bool); + +/* Indicate block BB is control dependent on an edge with index EDGE_INDEX. */ +static inline void +set_control_dependence_map_bit (basic_block bb, int edge_index) +{ + if (bb == ENTRY_BLOCK_PTR) + return; + if (bb == EXIT_BLOCK_PTR) + abort (); + bitmap_set_bit (control_dependence_map[bb->index], edge_index); +} + +/* Clear all control dependences for block BB. */ +static inline +void clear_control_dependence_bitmap (basic_block bb) +{ + bitmap_clear (control_dependence_map[bb->index]); +} + +/* Record all blocks' control dependences on all edges in the edge + list EL, ala Morgan, Section 3.6. */ + +static void +find_all_control_dependences (struct edge_list *el) +{ + int i; + + for (i = 0; i < NUM_EDGES (el); ++i) + find_control_dependence (el, i); +} + +/* Determine all blocks' control dependences on the given edge with edge_list + EL index EDGE_INDEX, ala Morgan, Section 3.6. */ + +static void +find_control_dependence (struct edge_list *el, int edge_index) +{ + basic_block current_block; + basic_block ending_block; + +#ifdef ENABLE_CHECKING + if (INDEX_EDGE_PRED_BB (el, edge_index) == EXIT_BLOCK_PTR) + abort (); +#endif + + if (INDEX_EDGE_PRED_BB (el, edge_index) == ENTRY_BLOCK_PTR) + ending_block = ENTRY_BLOCK_PTR->next_bb; + else + ending_block = find_pdom (INDEX_EDGE_PRED_BB (el, edge_index)); + + for (current_block = INDEX_EDGE_SUCC_BB (el, edge_index); + current_block != ending_block && current_block != EXIT_BLOCK_PTR; + current_block = find_pdom (current_block)) + { + edge e = INDEX_EDGE (el, edge_index); + + /* For abnormal edges, we don't make current_block control + dependent because instructions that throw are always necessary + anyway. */ + if (e->flags & EDGE_ABNORMAL) + continue; + + set_control_dependence_map_bit (current_block, edge_index); + } +} + +/* Find the immediate postdominator PDOM of the specified basic block BLOCK. + This function is necessary because some blocks have negative numbers. */ + +static inline basic_block +find_pdom (basic_block block) +{ + if (block == ENTRY_BLOCK_PTR) + abort (); + else if (block == EXIT_BLOCK_PTR) + return EXIT_BLOCK_PTR; + else + { + basic_block bb = get_immediate_dominator (CDI_POST_DOMINATORS, block); + if (! bb) + return EXIT_BLOCK_PTR; + return bb; + } +} + +#define NECESSARY(stmt) stmt->common.asm_written_flag + +/* If STMT is not already marked necessary, mark it, and add it to the + worklist if ADD_TO_WORKLIST is true. */ +static inline void +mark_stmt_necessary (tree stmt, bool add_to_worklist) +{ +#ifdef ENABLE_CHECKING + if (stmt == NULL + || stmt == error_mark_node + || (stmt && DECL_P (stmt))) + abort (); +#endif + + if (NECESSARY (stmt)) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Marking useful stmt: "); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + fprintf (dump_file, "\n"); + } + + NECESSARY (stmt) = 1; + if (add_to_worklist) + VARRAY_PUSH_TREE (worklist, stmt); +} + +/* Mark the statement defining operand OP as necessary. */ + +static inline void +mark_operand_necessary (tree op) +{ + tree stmt; + int ver; + +#ifdef ENABLE_CHECKING + if (op == NULL) + abort (); +#endif + + ver = SSA_NAME_VERSION (op); + if (TEST_BIT (processed, ver)) + return; + SET_BIT (processed, ver); + + stmt = SSA_NAME_DEF_STMT (op); +#ifdef ENABLE_CHECKING + if (stmt == NULL) + abort (); +#endif + + if (NECESSARY (stmt) + || IS_EMPTY_STMT (stmt)) + return; + + NECESSARY (stmt) = 1; + VARRAY_PUSH_TREE (worklist, stmt); +} + +/* Return true if a store to a variable needs to be preserved. */ + +static inline bool +need_to_preserve_store (tree ssa_name) +{ + return (needs_to_live_in_memory (SSA_NAME_VAR (ssa_name))); +} + + +/* Mark STMT as necessary if it is obviously is. Add it to the worklist if + it can make other statements necessary. + + If AGGRESSIVE is false, control statements are conservatively marked as + necessary. */ + +static void +mark_stmt_if_obviously_necessary (tree stmt, bool aggressive) +{ + def_optype defs; + vdef_optype vdefs; + stmt_ann_t ann; + size_t i; + + /* Statements that are implicitly live. Most function calls, asm and return + statements are required. Labels and BIND_EXPR nodes are kept because + they are control flow, and we have no way of knowing whether they can be + removed. DCE can eliminate all the other statements in a block, and CFG + can then remove the block and labels. */ + switch (TREE_CODE (stmt)) + { + case BIND_EXPR: + case LABEL_EXPR: + case CASE_LABEL_EXPR: + mark_stmt_necessary (stmt, false); + return; + + case ASM_EXPR: + case RESX_EXPR: + case RETURN_EXPR: + mark_stmt_necessary (stmt, true); + return; + + case CALL_EXPR: + /* Most, but not all function calls are required. Function calls that + produce no result and have no side effects (i.e. const pure + functions) are unnecessary. */ + if (TREE_SIDE_EFFECTS (stmt)) + mark_stmt_necessary (stmt, true); + return; + + case MODIFY_EXPR: + if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR + && TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1))) + { + mark_stmt_necessary (stmt, true); + return; + } + + /* These values are mildly magic bits of the EH runtime. We can't + see the entire lifetime of these values until landing pads are + generated. */ + if (TREE_CODE (TREE_OPERAND (stmt, 0)) == EXC_PTR_EXPR + || TREE_CODE (TREE_OPERAND (stmt, 0)) == FILTER_EXPR) + { + mark_stmt_necessary (stmt, true); + return; + } + break; + + case GOTO_EXPR: + if (! simple_goto_p (stmt)) + mark_stmt_necessary (stmt, true); + return; + + case COND_EXPR: + if (GOTO_DESTINATION (COND_EXPR_THEN (stmt)) + == GOTO_DESTINATION (COND_EXPR_ELSE (stmt))) + { + /* A COND_EXPR is obviously dead if the target labels are the same. + We cannot kill the statement at this point, so to prevent the + statement from being marked necessary, we replace the condition + with a constant. The stmt is killed later on in cfg_cleanup. */ + COND_EXPR_COND (stmt) = integer_zero_node; + modify_stmt (stmt); + return; + } + /* Fall through. */ + + case SWITCH_EXPR: + if (! aggressive) + mark_stmt_necessary (stmt, true); + break; + + default: + break; + } + + ann = stmt_ann (stmt); + /* If the statement has volatile operands, it needs to be preserved. Same + for statements that can alter control flow in unpredictable ways. */ + if (ann->has_volatile_ops + || is_ctrl_altering_stmt (stmt)) + { + mark_stmt_necessary (stmt, true); + return; + } + + get_stmt_operands (stmt); + + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree def = DEF_OP (defs, i); + if (need_to_preserve_store (def)) + { + mark_stmt_necessary (stmt, true); + return; + } + } + + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + tree vdef = VDEF_RESULT (vdefs, i); + if (need_to_preserve_store (vdef)) + { + mark_stmt_necessary (stmt, true); + return; + } + } + + return; +} + +/* Find obviously necessary statements. These are things like most function + calls, and stores to file level variables. + + If EL is NULL, control statements are conservatively marked as + necessary. Otherwise it contains the list of edges used by control + dependence analysis. */ + +static void +find_obviously_necessary_stmts (struct edge_list *el) +{ + basic_block bb; + block_stmt_iterator i; + edge e; + + FOR_EACH_BB (bb) + { + tree phi; + + /* Check any PHI nodes in the block. */ + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + NECESSARY (phi) = 0; + + /* PHIs for virtual variables do not directly affect code + generation and need not be considered inherently necessary + regardless of the bits set in their decl. + + Thus, we only need to mark PHIs for real variables which + need their result preserved as being inherently necessary. */ + if (is_gimple_reg (PHI_RESULT (phi)) + && need_to_preserve_store (PHI_RESULT (phi))) + mark_stmt_necessary (phi, true); + } + + /* Check all statements in the block. */ + for (i = bsi_start (bb); ! bsi_end_p (i); bsi_next (&i)) + { + tree stmt = bsi_stmt (i); + NECESSARY (stmt) = 0; + mark_stmt_if_obviously_necessary (stmt, el != NULL); + } + + /* Mark this basic block as `not visited'. A block will be marked + visited when the edges that it is control dependent on have been + marked. */ + bb->flags &= ~BB_VISITED; + } + + if (el) + { + /* Prevent the loops from being removed. We must keep the infinite loops, + and we currently do not have a means to recognize the finite ones. */ + FOR_EACH_BB (bb) + { + for (e = bb->succ; e; e = e->succ_next) + if (e->flags & EDGE_DFS_BACK) + mark_control_dependent_edges_necessary (e->dest, el); + } + } +} + +/* Make corresponding control dependent edges necessary. We only + have to do this once for each basic block, so we clear the bitmap + after we're done. */ +static void +mark_control_dependent_edges_necessary (basic_block bb, struct edge_list *el) +{ + int edge_number; + + EXECUTE_IF_CONTROL_DEPENDENT (bb->index, edge_number, + { + tree t; + basic_block cd_bb = INDEX_EDGE_PRED_BB (el, edge_number); + + if (TEST_BIT (last_stmt_necessary, cd_bb->index)) + continue; + SET_BIT (last_stmt_necessary, cd_bb->index); + + t = last_stmt (cd_bb); + if (is_ctrl_stmt (t)) + mark_stmt_necessary (t, true); + }); +} + +/* Propagate necessity using the operands of necessary statements. Process + the uses on each statement in the worklist, and add all feeding statements + which contribute to the calculation of this value to the worklist. + + In conservative mode, EL is NULL. */ + +static void +propagate_necessity (struct edge_list *el) +{ + tree i; + bool aggressive = (el ? true : false); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\nProcessing worklist:\n"); + + while (VARRAY_ACTIVE_SIZE (worklist) > 0) + { + /* Take `i' from worklist. */ + i = VARRAY_TOP_TREE (worklist); + VARRAY_POP (worklist); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "processing: "); + print_generic_stmt (dump_file, i, TDF_SLIM); + fprintf (dump_file, "\n"); + } + + if (aggressive) + { + /* Mark the last statements of the basic blocks that the block + containing `i' is control dependent on, but only if we haven't + already done so. */ + basic_block bb = bb_for_stmt (i); + if (! (bb->flags & BB_VISITED)) + { + bb->flags |= BB_VISITED; + mark_control_dependent_edges_necessary (bb, el); + } + } + + if (TREE_CODE (i) == PHI_NODE) + { + /* PHI nodes are somewhat special in that each PHI alternative has + data and control dependencies. All the statements feeding the + PHI node's arguments are always necessary. In aggressive mode, + we also consider the control dependent edges leading to the + predecessor block associated with each PHI alternative as + necessary. */ + int k; + for (k = 0; k < PHI_NUM_ARGS (i); k++) + { + tree arg = PHI_ARG_DEF (i, k); + if (TREE_CODE (arg) == SSA_NAME) + mark_operand_necessary (arg); + } + + if (aggressive) + { + for (k = 0; k < PHI_NUM_ARGS (i); k++) + { + basic_block arg_bb = PHI_ARG_EDGE (i, k)->src; + if (! (arg_bb->flags & BB_VISITED)) + { + arg_bb->flags |= BB_VISITED; + mark_control_dependent_edges_necessary (arg_bb, el); + } + } + } + } + else + { + /* Propagate through the operands. Examine all the USE, VUSE and + VDEF operands in this statement. Mark all the statements which + feed this statement's uses as necessary. */ + vuse_optype vuses; + vdef_optype vdefs; + use_optype uses; + stmt_ann_t ann; + size_t k; + + get_stmt_operands (i); + ann = stmt_ann (i); + + uses = USE_OPS (ann); + for (k = 0; k < NUM_USES (uses); k++) + mark_operand_necessary (USE_OP (uses, k)); + + vuses = VUSE_OPS (ann); + for (k = 0; k < NUM_VUSES (vuses); k++) + mark_operand_necessary (VUSE_OP (vuses, k)); + + /* The operands of VDEF expressions are also needed as they + represent potential definitions that may reach this + statement (VDEF operands allow us to follow def-def links). */ + vdefs = VDEF_OPS (ann); + for (k = 0; k < NUM_VDEFS (vdefs); k++) + mark_operand_necessary (VDEF_OP (vdefs, k)); + } + } +} + +/* Eliminate unnecessary statements. Any instruction not marked as necessary + contributes nothing to the program, and can be deleted. */ + +static void +eliminate_unnecessary_stmts (void) +{ + basic_block bb; + block_stmt_iterator i; + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\nEliminating unnecessary statements:\n"); + + clear_special_calls (); + FOR_EACH_BB (bb) + { + /* Remove dead PHI nodes. */ + remove_dead_phis (bb); + + /* Remove dead statements. */ + for (i = bsi_start (bb); ! bsi_end_p (i) ; ) + { + tree t = bsi_stmt (i); + + stats.total++; + + /* If `i' is not necessary then remove it. */ + if (! NECESSARY (t)) + remove_dead_stmt (&i, bb); + else + { + if (TREE_CODE (t) == CALL_EXPR) + notice_special_calls (t); + else if (TREE_CODE (t) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR) + notice_special_calls (TREE_OPERAND (t, 1)); + bsi_next (&i); + } + } + } +} + +/* Remove dead PHI nodes from block BB. */ + +static void +remove_dead_phis (basic_block bb) +{ + tree prev, phi; + + prev = NULL_TREE; + phi = phi_nodes (bb); + while (phi) + { + stats.total_phis++; + + if (! NECESSARY (phi)) + { + tree next = TREE_CHAIN (phi); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Deleting : "); + print_generic_stmt (dump_file, phi, TDF_SLIM); + fprintf (dump_file, "\n"); + } + + remove_phi_node (phi, prev, bb); + stats.removed_phis++; + phi = next; + } + else + { + prev = phi; + phi = TREE_CHAIN (phi); + } + } +} + +/* Remove dead statement pointed by iterator I. Receives the basic block BB + containing I so that we don't have to look it up. */ + +static void +remove_dead_stmt (block_stmt_iterator *i, basic_block bb) +{ + tree t = bsi_stmt (*i); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Deleting : "); + print_generic_stmt (dump_file, t, TDF_SLIM); + fprintf (dump_file, "\n"); + } + + stats.removed++; + + /* If we have determined that a conditional branch statement contributes + nothing to the program, then we not only remove it, but we also change + the flow graph so that the current block will simply fall-thru to its + immediate post-dominator. The blocks we are circumventing will be + removed by cleaup_cfg if this change in the flow graph makes them + unreachable. */ + if (is_ctrl_stmt (t)) + { + basic_block post_dom_bb; + edge e; +#ifdef ENABLE_CHECKING + /* The post dominance info has to be up-to-date. */ + if (dom_computed[CDI_POST_DOMINATORS] != DOM_OK) + abort (); +#endif + /* Get the immediate post dominator of bb. */ + post_dom_bb = get_immediate_dominator (CDI_POST_DOMINATORS, bb); + /* Some blocks don't have an immediate post dominator. This can happen + for example with infinite loops. Removing an infinite loop is an + inappropriate transformation anyway... */ + if (! post_dom_bb) + { + bsi_next (i); + return; + } + + /* Redirect the first edge out of BB to reach POST_DOM_BB. */ + redirect_edge_and_branch (bb->succ, post_dom_bb); + PENDING_STMT (bb->succ) = NULL; + + /* The edge is no longer associated with a conditional, so it does + not have TRUE/FALSE flags. */ + bb->succ->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); + + /* If the edge reaches any block other than the exit, then it is a + fallthru edge; if it reaches the exit, then it is not a fallthru + edge. */ + if (post_dom_bb != EXIT_BLOCK_PTR) + bb->succ->flags |= EDGE_FALLTHRU; + else + bb->succ->flags &= ~EDGE_FALLTHRU; + + /* Remove the remaining the outgoing edges. */ + for (e = bb->succ->succ_next; e != NULL;) + { + edge tmp = e; + e = e->succ_next; + remove_edge (tmp); + } + } + + bsi_remove (i); +} + +/* Print out removed statement statistics. */ + +static void +print_stats (void) +{ + if (dump_file && (dump_flags & (TDF_STATS|TDF_DETAILS))) + { + float percg; + + percg = ((float) stats.removed / (float) stats.total) * 100; + fprintf (dump_file, "Removed %d of %d statements (%d%%)\n", + stats.removed, stats.total, (int) percg); + + if (stats.total_phis == 0) + percg = 0; + else + percg = ((float) stats.removed_phis / (float) stats.total_phis) * 100; + + fprintf (dump_file, "Removed %d of %d PHI nodes (%d%%)\n", + stats.removed_phis, stats.total_phis, (int) percg); + } +} + +/* Initialization for this pass. Set up the used data structures. */ + +static void +tree_dce_init (bool aggressive) +{ + memset ((void *) &stats, 0, sizeof (stats)); + + if (aggressive) + { + int i; + + control_dependence_map + = xmalloc (last_basic_block * sizeof (bitmap)); + for (i = 0; i < last_basic_block; ++i) + control_dependence_map[i] = BITMAP_XMALLOC (); + + last_stmt_necessary = sbitmap_alloc (last_basic_block); + sbitmap_zero (last_stmt_necessary); + } + + processed = sbitmap_alloc (highest_ssa_version + 1); + sbitmap_zero (processed); + + VARRAY_TREE_INIT (worklist, 64, "work list"); +} + +/* Cleanup after this pass. */ + +static void +tree_dce_done (bool aggressive) +{ + if (aggressive) + { + int i; + + for (i = 0; i < last_basic_block; ++i) + BITMAP_XFREE (control_dependence_map[i]); + free (control_dependence_map); + + sbitmap_free (last_stmt_necessary); + } + + sbitmap_free (processed); +} + +/* Main routine to eliminate dead code. + + AGGRESSIVE controls the aggressiveness of the algorithm. + In conservative mode, we ignore control dependence and simply declare + all but the most trivially dead branches necessary. This mode is fast. + In aggressive mode, control dependences are taken into account, which + results in more dead code elimination, but at the cost of some time. + + FIXME: Aggressive mode before PRE doesn't work currently because + the dominance info is not invalidated after DCE1. This is + not an issue right now because we only run aggressive DCE + as the last tree SSA pass, but keep this in mind when you + start experimenting with pass ordering. */ + +static void +perform_tree_ssa_dce (bool aggressive) +{ + struct edge_list *el = NULL; + + tree_dce_init (aggressive); + + if (aggressive) + { + /* Compute control dependence. */ + timevar_push (TV_CONTROL_DEPENDENCES); + calculate_dominance_info (CDI_POST_DOMINATORS); + el = create_edge_list (); + find_all_control_dependences (el); + timevar_pop (TV_CONTROL_DEPENDENCES); + + mark_dfs_back_edges (); + } + + find_obviously_necessary_stmts (el); + + propagate_necessity (el); + + eliminate_unnecessary_stmts (); + + if (aggressive) + free_dominance_info (CDI_POST_DOMINATORS); + + cleanup_tree_cfg (); + + /* Debugging dumps. */ + if (dump_file) + { + dump_function_to_file (current_function_decl, dump_file, dump_flags); + print_stats (); + } + + tree_dce_done (aggressive); +} + +/* Pass entry points. */ +static void +tree_ssa_dce (void) +{ + perform_tree_ssa_dce (/*aggressive=*/false); +} + +static void +tree_ssa_cd_dce (void) +{ + perform_tree_ssa_dce (/*aggressive=*/optimize >= 2); +} + +static bool +gate_dce (void) +{ + return flag_tree_dce != 0; +} + +struct tree_opt_pass pass_dce = +{ + "dce", /* name */ + gate_dce, /* gate */ + tree_ssa_dce, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_DCE, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ +}; + +struct tree_opt_pass pass_cd_dce = +{ + "cddce", /* name */ + gate_dce, /* gate */ + tree_ssa_cd_dce, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_CD_DCE, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_ggc_collect | TODO_verify_ssa | TODO_verify_flow + /* todo_flags_finish */ +}; + diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c new file mode 100644 index 00000000000..0daf59b47cd --- /dev/null +++ b/gcc/tree-ssa-dom.c @@ -0,0 +1,3121 @@ +/* SSA Dominator optimizations for trees + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Diego Novillo + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "tm_p.h" +#include "ggc.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "expr.h" +#include "function.h" +#include "diagnostic.h" +#include "timevar.h" +#include "tree-dump.h" +#include "tree-flow.h" +#include "domwalk.h" +#include "real.h" +#include "tree-pass.h" +#include "flags.h" +#include "langhooks.h" + +/* This file implements optimizations on the dominator tree. */ + +/* Hash table with expressions made available during the renaming process. + When an assignment of the form X_i = EXPR is found, the statement is + stored in this table. If the same expression EXPR is later found on the + RHS of another statement, it is replaced with X_i (thus performing + global redundancy elimination). Similarly as we pass through conditionals + we record the conditional itself as having either a true or false value + in this table. */ +static htab_t avail_exprs; + +/* Structure for entries in the expression hash table. + + This requires more memory for the hash table entries, but allows us + to avoid creating silly tree nodes and annotations for conditionals, + eliminates 2 global hash tables and two block local varrays. + + It also allows us to reduce the number of hash table lookups we + have to perform in lookup_avail_expr and finally it allows us to + significantly reduce the number of calls into the hashing routine + itself. */ +struct expr_hash_elt +{ + /* The value (lhs) of this expression. */ + tree lhs; + + /* The expression (rhs) we want to record. */ + tree rhs; + + /* The annotation if this element corresponds to a statement. */ + stmt_ann_t ann; + + /* The hash value for RHS/ann. */ + hashval_t hash; +}; + +/* Table of constant values and copies indexed by SSA name. When the + renaming pass finds an assignment of a constant (X_i = C) or a copy + assignment from another SSA variable (X_i = Y_j), it creates a mapping + between X_i and the RHS in this table. This mapping is used later on, + when renaming uses of X_i. If an assignment to X_i is found in this + table, instead of using X_i, we use the RHS of the statement stored in + this table (thus performing very simplistic copy and constant + propagation). */ +static varray_type const_and_copies; + +/* Bitmap of SSA_NAMEs known to have a nonzero value, even if we do not + know their exact value. */ +static bitmap nonzero_vars; + +/* Track whether or not we have changed the control flow graph. */ +static bool cfg_altered; + +/* Statistics for dominator optimizations. */ +struct opt_stats_d +{ + long num_stmts; + long num_exprs_considered; + long num_re; +}; + +/* Value range propagation record. Each time we encounter a conditional + of the form SSA_NAME COND CONST we create a new vrp_element to record + how the condition affects the possible values SSA_NAME may have. + + Each record contains the condition tested (COND), and the the range of + values the variable may legitimately have if COND is true. Note the + range of values may be a smaller range than COND specifies if we have + recorded other ranges for this variable. Each record also contains the + block in which the range was recorded for invalidation purposes. + + Note that the current known range is computed lazily. This allows us + to avoid the overhead of computing ranges which are never queried. + + When we encounter a conditional, we look for records which constrain + the SSA_NAME used in the condition. In some cases those records allow + us to determine the condition's result at compile time. In other cases + they may allow us to simplify the condition. + + We also use value ranges to do things like transform signed div/mod + operations into unsigned div/mod or to simplify ABS_EXPRs. + + Simple experiments have shown these optimizations to not be all that + useful on switch statements (much to my surprise). So switch statement + optimizations are not performed. + + Note carefully we do not propagate information through each statement + in the block. ie, if we know variable X has a value defined of + [0, 25] and we encounter Y = X + 1, we do not track a value range + for Y (which would be [1, 26] if we cared). Similarly we do not + constrain values as we encounter narrowing typecasts, etc. */ + +struct vrp_element +{ + /* The highest and lowest values the variable in COND may contain when + COND is true. Note this may not necessarily be the same values + tested by COND if the same variable was used in earlier conditionals. + + Note this is computed lazily and thus can be NULL indicating that + the values have not been computed yet. */ + tree low; + tree high; + + /* The actual conditional we recorded. This is needed since we compute + ranges lazily. */ + tree cond; + + /* The basic block where this record was created. We use this to determine + when to remove records. */ + basic_block bb; +}; + +static struct opt_stats_d opt_stats; + +/* This virtual array holds pairs of edges which describe a scheduled + edge redirection from jump threading. + + The first entry in each pair is the edge we are going to redirect. + + The second entry in each pair is the edge leading to our final + destination block. By providing this as an edge rather than the + final target block itself we can correctly handle redirections + when the target block had PHIs which required edge insertions/splitting + to remove the PHIs. */ +static GTY(()) varray_type redirection_edges; + +/* A virtual array holding value range records for the variable identified + by the index, SSA_VERSION. */ +static varray_type vrp_data; + +/* Datastructure for block local data used during the dominator walk. + We maintain a stack of these as we recursively walk down the + dominator tree. */ + +struct dom_walk_block_data +{ + /* Array of all the expressions entered into the global expression + hash table by this block. During finalization we use this array to + know what expressions to remove from the global expression hash + table. */ + varray_type avail_exprs; + + /* Array of dest, src pairs that need to be restored during finalization + into the global const/copies table during finalization. */ + varray_type const_and_copies; + + /* Similarly for the nonzero state of variables that needs to be + restored during finalization. */ + varray_type nonzero_vars; + + /* Array of statements we need to rescan during finalization for newly + exposed variables. */ + varray_type stmts_to_rescan; + + /* Array of variables which have their values constrained by operations + in this basic block. We use this during finalization to know + which variables need their VRP data updated. */ + varray_type vrp_variables; + + /* Array of tree pairs used to restore the global currdefs to its + original state after completing optimization of a block and its + dominator children. */ + varray_type block_defs; +}; + +struct eq_expr_value +{ + tree src; + tree dst; +}; + +/* Local functions. */ +static void optimize_stmt (struct dom_walk_data *, + basic_block bb, + block_stmt_iterator); +static inline tree get_value_for (tree, varray_type table); +static inline void set_value_for (tree, tree, varray_type table); +static tree lookup_avail_expr (tree, varray_type *, bool); +static struct eq_expr_value get_eq_expr_value (tree, int, varray_type *, + basic_block, varray_type *); +static hashval_t avail_expr_hash (const void *); +static int avail_expr_eq (const void *, const void *); +static void htab_statistics (FILE *, htab_t); +static void record_cond (tree, tree, varray_type *); +static void record_const_or_copy (tree, tree, varray_type *); +static void record_equality (tree, tree, varray_type *); +static tree update_rhs_and_lookup_avail_expr (tree, tree, varray_type *, + stmt_ann_t, bool); +static tree simplify_rhs_and_lookup_avail_expr (struct dom_walk_data *, + tree, stmt_ann_t, int); +static tree simplify_cond_and_lookup_avail_expr (tree, varray_type *, + stmt_ann_t, int); +static tree simplify_switch_and_lookup_avail_expr (tree, varray_type *, + stmt_ann_t, int); +static tree find_equivalent_equality_comparison (tree); +static void record_range (tree, basic_block, varray_type *); +static bool extract_range_from_cond (tree, tree *, tree *, int *); +static void record_equivalences_from_phis (struct dom_walk_data *, basic_block); +static void record_equivalences_from_incoming_edge (struct dom_walk_data *, + basic_block); +static bool eliminate_redundant_computations (struct dom_walk_data *, + tree, stmt_ann_t); +static void record_equivalences_from_stmt (tree, varray_type *, varray_type *, + int, stmt_ann_t); +static void thread_across_edge (struct dom_walk_data *, edge); +static void dom_opt_finalize_block (struct dom_walk_data *, basic_block); +static void dom_opt_initialize_block_local_data (struct dom_walk_data *, + basic_block, bool); +static void dom_opt_initialize_block (struct dom_walk_data *, basic_block); +static void cprop_into_phis (struct dom_walk_data *, basic_block); +static void remove_local_expressions_from_table (varray_type locals, + unsigned limit, + htab_t table); +static void restore_vars_to_original_value (varray_type locals, + unsigned limit, + varray_type table); +static void restore_currdefs_to_original_value (varray_type locals, + unsigned limit); +static void register_definitions_for_stmt (stmt_ann_t, varray_type *); +static void redirect_edges_and_update_ssa_graph (varray_type); + +/* Local version of fold that doesn't introduce cruft. */ + +static tree +local_fold (tree t) +{ + t = fold (t); + + /* Strip away useless type conversions. Both the NON_LVALUE_EXPR that + may have been added by fold, and "useless" type conversions that might + now be apparent due to propagation. */ + STRIP_MAIN_TYPE_NOPS (t); + STRIP_USELESS_TYPE_CONVERSION (t); + + return t; +} + +/* Return the value associated with variable VAR in TABLE. */ + +static inline tree +get_value_for (tree var, varray_type table) +{ + return VARRAY_TREE (table, SSA_NAME_VERSION (var)); +} + +/* Associate VALUE to variable VAR in TABLE. */ + +static inline void +set_value_for (tree var, tree value, varray_type table) +{ + VARRAY_TREE (table, SSA_NAME_VERSION (var)) = value; +} + +/* REDIRECTION_EDGES contains edge pairs where we want to revector the + destination of the first edge to the destination of the second edge. + + These redirections may significantly change the SSA graph since we + allow redirection through blocks with PHI nodes and blocks with + real instructions in some cases. + + This routine will perform the requested redirections and incrementally + update the SSA graph. + + Note in some cases requested redirections may be ignored as they can + not be safely implemented. */ + +static void +redirect_edges_and_update_ssa_graph (varray_type redirection_edges) +{ + basic_block tgt; + unsigned int i; + size_t old_num_referenced_vars = num_referenced_vars; + + /* First note any variables which we are going to have to take + out of SSA form. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (redirection_edges); i += 2) + { + block_stmt_iterator bsi; + edge e; + basic_block tgt; + tree phi; + + e = VARRAY_EDGE (redirection_edges, i); + tgt = VARRAY_EDGE (redirection_edges, i + 1)->dest; + + /* All variables referenced in PHI nodes we bypass must be + renamed. */ + for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi)) + { + tree result = SSA_NAME_VAR (PHI_RESULT (phi)); + bitmap_set_bit (vars_to_rename, var_ann (result)->uid); + } + + /* Any variables set by statements at the start of the block we + are bypassing must also be taken our of SSA form. */ + for (bsi = bsi_start (e->dest); ! bsi_end_p (bsi); bsi_next (&bsi)) + { + unsigned int j; + def_optype defs; + vdef_optype vdefs; + tree stmt = bsi_stmt (bsi); + stmt_ann_t ann = stmt_ann (stmt); + + if (TREE_CODE (stmt) == COND_EXPR) + break; + + get_stmt_operands (stmt); + + defs = DEF_OPS (ann); + for (j = 0; j < NUM_DEFS (defs); j++) + { + tree op = SSA_NAME_VAR (DEF_OP (defs, j)); + bitmap_set_bit (vars_to_rename, var_ann (op)->uid); + } + + vdefs = VDEF_OPS (ann); + for (j = 0; j < NUM_VDEFS (vdefs); j++) + { + tree op = VDEF_RESULT (vdefs, j); + bitmap_set_bit (vars_to_rename, var_ann (op)->uid); + } + } + + /* Finally, any variables in PHI nodes at our final destination + must also be taken our of SSA form. */ + for (phi = phi_nodes (tgt); phi; phi = TREE_CHAIN (phi)) + { + tree result = SSA_NAME_VAR (PHI_RESULT (phi)); + int j; + + bitmap_set_bit (vars_to_rename, var_ann (result)->uid); + + for (j = 0; j < PHI_NUM_ARGS (phi); j++) + { + tree arg = PHI_ARG_DEF (phi, j); + + if (TREE_CODE (arg) != SSA_NAME) + continue; + + arg = SSA_NAME_VAR (arg); + bitmap_set_bit (vars_to_rename, var_ann (arg)->uid); + } + } + } + + /* Take those selected variables out of SSA form. This must be + done before we start redirecting edges. */ + if (bitmap_first_set_bit (vars_to_rename) >= 0) + rewrite_vars_out_of_ssa (vars_to_rename); + + /* The out of SSA translation above may split the edge from + E->src to E->dest. This could potentially cause us to lose + an assignment leading to invalid warnings about uninitialized + variables or incorrect code. + + Luckily, we can detect this by looking at the last statement + in E->dest. If it is not a COND_EXPR or SWITCH_EXPR, then + the edge was split and instead of E, we want E->dest->succ. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (redirection_edges); i += 2) + { + edge e = VARRAY_EDGE (redirection_edges, i); + tree last = last_stmt (e->dest); + + if (last + && TREE_CODE (last) != COND_EXPR + && TREE_CODE (last) != SWITCH_EXPR) + { + e = e->dest->succ; + +#ifdef ENABLE_CHECKING + /* There should only be a single successor if the + original edge was split. */ + if (e->succ_next) + abort (); +#endif + /* Replace the edge in REDIRECTION_EDGES for the + loop below. */ + VARRAY_EDGE (redirection_edges, i) = e; + } + } + + /* If we created any new variables as part of the out-of-ssa + translation, then any jump threads must be invalidated if they + bypass a block in which we skipped instructions. + + This is necessary as instructions which appeared to be NOPS + may be necessary after the out-of-ssa translation. */ + if (num_referenced_vars != old_num_referenced_vars) + { + for (i = 0; i < VARRAY_ACTIVE_SIZE (redirection_edges); i += 2) + { + block_stmt_iterator bsi; + edge e; + + e = VARRAY_EDGE (redirection_edges, i); + for (bsi = bsi_start (e->dest); ! bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + + if (IS_EMPTY_STMT (stmt) + || TREE_CODE (stmt) == LABEL_EXPR) + continue; + + if (TREE_CODE (stmt) == COND_EXPR) + break; + + /* Invalidate the jump thread. */ + VARRAY_EDGE (redirection_edges, i) = NULL; + VARRAY_EDGE (redirection_edges, i + 1) = NULL; + break; + } + } + } + + /* Now redirect the edges. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (redirection_edges); i += 2) + { + basic_block src; + edge e; + + e = VARRAY_EDGE (redirection_edges, i); + if (!e) + continue; + + tgt = VARRAY_EDGE (redirection_edges, i + 1)->dest; + + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " Threaded jump %d --> %d to %d\n", + e->src->index, e->dest->index, tgt->index); + + src = e->src; + + e = redirect_edge_and_branch (e, tgt); + PENDING_STMT (e) = NULL_TREE; + + /* Updating the dominance information would be nontrivial. */ + free_dominance_info (CDI_DOMINATORS); + + if ((dump_file && (dump_flags & TDF_DETAILS)) + && e->src != src) + fprintf (dump_file, " basic block %d created\n", + e->src->index); + + cfg_altered = true; + } + + VARRAY_CLEAR (redirection_edges); + + for (i = old_num_referenced_vars; i < num_referenced_vars; i++) + { + bitmap_set_bit (vars_to_rename, i); + var_ann (referenced_var (i))->out_of_ssa_tag = 0; + } +} + +/* Jump threading, redundancy elimination and const/copy propagation. + + Optimize function FNDECL based on a walk through the dominator tree. + + This pass may expose new symbols that need to be renamed into SSA. For + every new symbol exposed, its corresponding bit will be set in + VARS_TO_RENAME. + + PHASE indicates which dump file from the DUMP_FILES array to use when + dumping debugging information. */ + +static void +tree_ssa_dominator_optimize (void) +{ + basic_block bb; + struct dom_walk_data walk_data; + unsigned int i; + + for (i = 0; i < num_referenced_vars; i++) + var_ann (referenced_var (i))->current_def = NULL; + + /* Mark loop edges so we avoid threading across loop boundaries. + This may result in transforming natural loop into irreducible + region. */ + mark_dfs_back_edges (); + + /* Create our hash tables. */ + avail_exprs = htab_create (1024, avail_expr_hash, avail_expr_eq, free); + VARRAY_TREE_INIT (const_and_copies, highest_ssa_version, "const_and_copies"); + nonzero_vars = BITMAP_XMALLOC (); + VARRAY_EDGE_INIT (redirection_edges, 20, "redirection_edges"); + VARRAY_GENERIC_PTR_INIT (vrp_data, highest_ssa_version, "vrp_data"); + + /* Setup callbacks for the generic dominator tree walker. */ + walk_data.walk_stmts_backward = false; + walk_data.dom_direction = CDI_DOMINATORS; + walk_data.initialize_block_local_data = dom_opt_initialize_block_local_data; + walk_data.before_dom_children_before_stmts = dom_opt_initialize_block; + walk_data.before_dom_children_walk_stmts = optimize_stmt; + walk_data.before_dom_children_after_stmts = cprop_into_phis; + walk_data.after_dom_children_before_stmts = NULL; + walk_data.after_dom_children_walk_stmts = NULL; + walk_data.after_dom_children_after_stmts = dom_opt_finalize_block; + /* Right now we only attach a dummy COND_EXPR to the global data pointer. + When we attach more stuff we'll need to fill this out with a real + structure. */ + walk_data.global_data = NULL; + walk_data.block_local_data_size = sizeof (struct dom_walk_block_data); + + /* Now initialize the dominator walker. */ + init_walk_dominator_tree (&walk_data); + + /* Reset block_forwardable in each block's annotation. We use that + attribute when threading through COND_EXPRs. */ + FOR_EACH_BB (bb) + bb_ann (bb)->forwardable = 1; + + calculate_dominance_info (CDI_DOMINATORS); + + /* If we prove certain blocks are unreachable, then we want to + repeat the dominator optimization process as PHI nodes may + have turned into copies which allows better propagation of + values. So we repeat until we do not identify any new unreachable + blocks. */ + do + { + /* Optimize the dominator tree. */ + cfg_altered = false; + + /* Recursively walk the dominator tree optimizing statements. */ + walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR); + + /* Wipe the hash tables. */ + + if (VARRAY_ACTIVE_SIZE (redirection_edges) > 0) + redirect_edges_and_update_ssa_graph (redirection_edges); + + /* We may have made some basic blocks unreachable, remove them. */ + cfg_altered |= delete_unreachable_blocks (); + + /* If the CFG was altered, then recompute the dominator tree. This + is not strictly needed if we only removed unreachable blocks, but + may produce better results. If we threaded jumps, then rebuilding + the dominator tree is strictly necessary. */ + if (cfg_altered) + { + cleanup_tree_cfg (); + calculate_dominance_info (CDI_DOMINATORS); + } + + /* If we are going to iterate (CFG_ALTERED is true), then we must + perform any queued renaming before the next iteration. */ + if (cfg_altered + && bitmap_first_set_bit (vars_to_rename) >= 0) + { + rewrite_into_ssa (); + bitmap_clear (vars_to_rename); + + /* The into SSA translation may have created new SSA_NAMES whic + affect the size of CONST_AND_COPIES and VRP_DATA. */ + VARRAY_GROW (const_and_copies, highest_ssa_version); + VARRAY_GROW (vrp_data, highest_ssa_version); + } + + /* Reinitialize the various tables. */ + bitmap_clear (nonzero_vars); + htab_empty (avail_exprs); + VARRAY_CLEAR (const_and_copies); + VARRAY_CLEAR (vrp_data); + + for (i = 0; i < num_referenced_vars; i++) + var_ann (referenced_var (i))->current_def = NULL; + } + while (cfg_altered); + + /* Remove any unreachable blocks left behind and linearize the CFG. */ + cleanup_tree_cfg (); + + /* Debugging dumps. */ + if (dump_file && (dump_flags & TDF_STATS)) + dump_dominator_optimization_stats (dump_file); + + /* We emptyed the hash table earlier, now delete it completely. */ + htab_delete (avail_exprs); + + /* It is not nocessary to clear CURRDEFS, REDIRECTION_EDGES, VRP_DATA, + CONST_AND_COPIES, and NONZERO_VARS as they all get cleared at the bottom + of the do-while loop above. */ + + /* And finalize the dominator walker. */ + fini_walk_dominator_tree (&walk_data); +} + +static bool +gate_dominator (void) +{ + return flag_tree_dom != 0; +} + +struct tree_opt_pass pass_dominator = +{ + "dom", /* name */ + gate_dominator, /* gate */ + tree_ssa_dominator_optimize, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_SSA_DOMINATOR_OPTS, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_rename_vars + | TODO_verify_ssa /* todo_flags_finish */ +}; + + +/* We are exiting BB, see if the target block begins with a conditional + jump which has a known value when reached via BB. */ + +static void +thread_across_edge (struct dom_walk_data *walk_data, edge e) +{ + struct dom_walk_block_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + block_stmt_iterator bsi; + tree stmt = NULL; + tree phi; + + /* Each PHI creates a temporary equivalence, record them. */ + for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi)) + { + tree src = PHI_ARG_DEF (phi, phi_arg_from_edge (phi, e)); + tree dst = PHI_RESULT (phi); + record_const_or_copy (dst, src, &bd->const_and_copies); + register_new_def (dst, &bd->block_defs); + } + + for (bsi = bsi_start (e->dest); ! bsi_end_p (bsi); bsi_next (&bsi)) + { + tree lhs, cached_lhs; + + stmt = bsi_stmt (bsi); + + /* Ignore empty statements and labels. */ + if (IS_EMPTY_STMT (stmt) || TREE_CODE (stmt) == LABEL_EXPR) + continue; + + /* If this is not a MODIFY_EXPR which sets an SSA_NAME to a new + value, then stop our search here. Ideally when we stop a + search we stop on a COND_EXPR or SWITCH_EXPR. */ + if (TREE_CODE (stmt) != MODIFY_EXPR + || TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME) + break; + + /* At this point we have a statement which assigns an RHS to an + SSA_VAR on the LHS. We want to prove that the RHS is already + available and that its value is held in the current definition + of the LHS -- meaning that this assignment is a NOP when + reached via edge E. */ + if (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME) + cached_lhs = TREE_OPERAND (stmt, 1); + else + cached_lhs = lookup_avail_expr (stmt, NULL, false); + + lhs = TREE_OPERAND (stmt, 0); + + /* This can happen if we thread around to the start of a loop. */ + if (lhs == cached_lhs) + break; + + /* If we did not find RHS in the hash table, then try again after + temporarily const/copy propagating the operands. */ + if (!cached_lhs) + { + /* Copy the operands. */ + stmt_ann_t ann = stmt_ann (stmt); + use_optype uses = USE_OPS (ann); + vuse_optype vuses = VUSE_OPS (ann); + tree *uses_copy = xcalloc (NUM_USES (uses), sizeof (tree)); + tree *vuses_copy = xcalloc (NUM_VUSES (vuses), sizeof (tree)); + unsigned int i; + + /* Make a copy of the uses into USES_COPY, then cprop into + the use operands. */ + for (i = 0; i < NUM_USES (uses); i++) + { + tree tmp = NULL; + + uses_copy[i] = USE_OP (uses, i); + if (TREE_CODE (USE_OP (uses, i)) == SSA_NAME) + tmp = get_value_for (USE_OP (uses, i), const_and_copies); + if (tmp) + *USE_OP_PTR (uses, i) = tmp; + } + + /* Similarly for virtual uses. */ + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree tmp = NULL; + + vuses_copy[i] = VUSE_OP (vuses, i); + if (TREE_CODE (VUSE_OP (vuses, i)) == SSA_NAME) + tmp = get_value_for (VUSE_OP (vuses, i), const_and_copies); + if (tmp) + VUSE_OP (vuses, i) = tmp; + } + + /* Try to lookup the new expression. */ + cached_lhs = lookup_avail_expr (stmt, NULL, false); + + /* Restore the statement's original uses/defs. */ + for (i = 0; i < NUM_USES (uses); i++) + *USE_OP_PTR (uses, i) = uses_copy[i]; + + for (i = 0; i < NUM_VUSES (vuses); i++) + VUSE_OP (vuses, i) = vuses_copy[i]; + + free (uses_copy); + free (vuses_copy); + + /* If we still did not find the expression in the hash table, + then we can not ignore this statement. */ + if (! cached_lhs) + break; + } + + /* If the expression in the hash table was not assigned to an + SSA_NAME, then we can not ignore this statement. */ + if (TREE_CODE (cached_lhs) != SSA_NAME) + break; + + /* If we have different underlying variables, then we can not + ignore this statement. */ + if (SSA_NAME_VAR (cached_lhs) != SSA_NAME_VAR (lhs)) + break; + + /* If CACHED_LHS does not represent the current value of the undering + variable in CACHED_LHS/LHS, then we can not ignore this statement. */ + if (var_ann (SSA_NAME_VAR (lhs))->current_def != cached_lhs) + break; + + /* If we got here, then we can ignore this statement and continue + walking through the statements in the block looking for a threadable + COND_EXPR. + + We want to record an equivalence lhs = cache_lhs so that if + the result of this statement is used later we can copy propagate + suitably. */ + record_const_or_copy (lhs, cached_lhs, &bd->const_and_copies); + register_new_def (lhs, &bd->block_defs); + } + + /* If we stopped at a COND_EXPR or SWITCH_EXPR, then see if we know which + arm will be taken. */ + if (stmt + && (TREE_CODE (stmt) == COND_EXPR + || TREE_CODE (stmt) == SWITCH_EXPR)) + { + tree cond, cached_lhs; + edge e1; + + /* Do not forward entry edges into the loop. In the case loop + has multiple entry edges we may end up in constructing irreducible + region. + ??? We may consider forwarding the edges in the case all incoming + edges forward to the same destination block. */ + if (!e->flags & EDGE_DFS_BACK) + { + for (e1 = e->dest->pred; e; e = e->pred_next) + if (e1->flags & EDGE_DFS_BACK) + break; + if (e1) + return; + } + + /* Now temporarily cprop the operands and try to find the resulting + expression in the hash tables. */ + if (TREE_CODE (stmt) == COND_EXPR) + cond = COND_EXPR_COND (stmt); + else + cond = SWITCH_COND (stmt); + + if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<') + { + tree dummy_cond, op0, op1; + enum tree_code cond_code; + + op0 = TREE_OPERAND (cond, 0); + op1 = TREE_OPERAND (cond, 1); + cond_code = TREE_CODE (cond); + + /* Get the current value of both operands. */ + if (TREE_CODE (op0) == SSA_NAME) + { + tree tmp = get_value_for (op0, const_and_copies); + if (tmp) + op0 = tmp; + } + + if (TREE_CODE (op1) == SSA_NAME) + { + tree tmp = get_value_for (op1, const_and_copies); + if (tmp) + op1 = tmp; + } + + /* Stuff the operator and operands into our dummy conditional + expression, creating the dummy conditional if necessary. */ + dummy_cond = walk_data->global_data; + if (! dummy_cond) + { + dummy_cond = build (cond_code, boolean_type_node, op0, op1); + dummy_cond = build (COND_EXPR, void_type_node, + dummy_cond, NULL, NULL); + walk_data->global_data = dummy_cond; + } + else + { + TREE_SET_CODE (TREE_OPERAND (dummy_cond, 0), cond_code); + TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 0) = op0; + TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 1) = op1; + } + + /* If the conditional folds to an invariant, then we are done, + otherwise look it up in the hash tables. */ + cached_lhs = local_fold (COND_EXPR_COND (dummy_cond)); + if (! is_gimple_min_invariant (cached_lhs)) + cached_lhs = lookup_avail_expr (dummy_cond, NULL, false); + if (!cached_lhs || ! is_gimple_min_invariant (cached_lhs)) + { + stmt_ann_t ann = get_stmt_ann (dummy_cond); + cached_lhs = simplify_cond_and_lookup_avail_expr (dummy_cond, + NULL, + ann, + false); + } + } + /* We can have conditionals which just test the state of a + variable rather than use a relational operator. These are + simpler to handle. */ + else if (TREE_CODE (cond) == SSA_NAME) + { + cached_lhs = cond; + cached_lhs = get_value_for (cached_lhs, const_and_copies); + if (cached_lhs && ! is_gimple_min_invariant (cached_lhs)) + cached_lhs = 0; + } + else + cached_lhs = lookup_avail_expr (stmt, NULL, false); + + if (cached_lhs) + { + edge taken_edge = find_taken_edge (e->dest, cached_lhs); + basic_block dest = (taken_edge ? taken_edge->dest : NULL); + + if (dest == e->src) + return; + + /* If we have a known destination for the conditional, then + we can perform this optimization, which saves at least one + conditional jump each time it applies since we get to + bypass the conditional at our original destination. + + Note that we can either thread through a block with PHIs + or to a block with PHIs, but not both. At this time the + bookkeeping to keep the CFG & SSA up-to-date has proven + difficult. */ + if (dest) + { + int saved_forwardable = bb_ann (e->src)->forwardable; + edge tmp_edge; + + bb_ann (e->src)->forwardable = 0; + tmp_edge = tree_block_forwards_to (dest); + taken_edge = (tmp_edge ? tmp_edge : taken_edge); + bb_ann (e->src)->forwardable = saved_forwardable; + VARRAY_PUSH_EDGE (redirection_edges, e); + VARRAY_PUSH_EDGE (redirection_edges, taken_edge); + } + } + } +} + + +/* Initialize the local stacks. + + AVAIL_EXPRS stores all the expressions made available in this block. + + CONST_AND_COPIES stores var/value pairs to restore at the end of this + block. + + NONZERO_VARS stores the vars which have a nonzero value made in this + block. + + STMTS_TO_RESCAN is a list of statements we will rescan for operands. + + VRP_VARIABLES is the list of variables which have had their values + constrained by an operation in this block. + + These stacks are cleared in the finalization routine run for each + block. */ + +static void +dom_opt_initialize_block_local_data (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED, + basic_block bb ATTRIBUTE_UNUSED, + bool recycled ATTRIBUTE_UNUSED) +{ +#ifdef ENABLE_CHECKING + struct dom_walk_block_data *bd + = (struct dom_walk_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + /* We get cleared memory from the allocator, so if the memory is not + cleared, then we are re-using a previously allocated entry. In + that case, we can also re-use the underlying virtual arrays. Just + make sure we clear them before using them! */ + if (recycled) + { + if (bd->avail_exprs && VARRAY_ACTIVE_SIZE (bd->avail_exprs) > 0) + abort (); + if (bd->const_and_copies && VARRAY_ACTIVE_SIZE (bd->const_and_copies) > 0) + abort (); + if (bd->nonzero_vars && VARRAY_ACTIVE_SIZE (bd->nonzero_vars) > 0) + abort (); + if (bd->stmts_to_rescan && VARRAY_ACTIVE_SIZE (bd->stmts_to_rescan) > 0) + abort (); + if (bd->vrp_variables && VARRAY_ACTIVE_SIZE (bd->vrp_variables) > 0) + abort (); + if (bd->block_defs && VARRAY_ACTIVE_SIZE (bd->block_defs) > 0) + abort (); + } +#endif +} + +/* Initialize local stacks for this optimizer and record equivalences + upon entry to BB. Equivalences can come from the edge traversed to + reach BB or they may come from PHI nodes at the start of BB. */ + +static void +dom_opt_initialize_block (struct dom_walk_data *walk_data, basic_block bb) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\n\nOptimizing block #%d\n\n", bb->index); + + record_equivalences_from_incoming_edge (walk_data, bb); + + /* PHI nodes can create equivalences too. */ + record_equivalences_from_phis (walk_data, bb); +} + +/* Given an expression EXPR (a relational expression or a statement), + initialize the hash table element pointed by by ELEMENT. */ + +static void +initialize_hash_element (tree expr, tree lhs, struct expr_hash_elt *element) +{ + /* Hash table elements may be based on conditional expressions or statements. + + For the former case, we have no annotation and we want to hash the + conditional expression. In the latter case we have an annotation and + we want to record the expression the statement evaluates. */ + if (TREE_CODE_CLASS (TREE_CODE (expr)) == '<' + || TREE_CODE (expr) == TRUTH_NOT_EXPR) + { + element->ann = NULL; + element->rhs = expr; + } + else if (TREE_CODE (expr) == COND_EXPR) + { + element->ann = stmt_ann (expr); + element->rhs = COND_EXPR_COND (expr); + } + else if (TREE_CODE (expr) == SWITCH_EXPR) + { + element->ann = stmt_ann (expr); + element->rhs = SWITCH_COND (expr); + } + else if (TREE_CODE (expr) == RETURN_EXPR && TREE_OPERAND (expr, 0)) + { + element->ann = stmt_ann (expr); + element->rhs = TREE_OPERAND (TREE_OPERAND (expr, 0), 1); + } + else + { + element->ann = stmt_ann (expr); + element->rhs = TREE_OPERAND (expr, 1); + } + + element->lhs = lhs; + element->hash = avail_expr_hash (element); +} + +/* Remove all the expressions in LOCALS from TABLE, stopping when there are + LIMIT entries left in LOCALs. */ + +static void +remove_local_expressions_from_table (varray_type locals, + unsigned limit, + htab_t table) +{ + if (! locals) + return; + + /* Remove all the expressions made available in this block. */ + while (VARRAY_ACTIVE_SIZE (locals) > limit) + { + struct expr_hash_elt element; + tree expr = VARRAY_TOP_TREE (locals); + VARRAY_POP (locals); + + initialize_hash_element (expr, NULL, &element); + htab_remove_elt_with_hash (table, &element, element.hash); + } +} + +/* Use the SSA_NAMES in LOCALS to restore TABLE to its original + state, stopping when there are LIMIT entires left in LOCALs. */ + +static void +restore_nonzero_vars_to_original_value (varray_type locals, + unsigned limit, + bitmap table) +{ + if (!locals) + return; + + while (VARRAY_ACTIVE_SIZE (locals) > limit) + { + tree name = VARRAY_TOP_TREE (locals); + VARRAY_POP (locals); + bitmap_clear_bit (table, SSA_NAME_VERSION (name)); + } +} + +/* Use the source/dest pairs in LOCALS to restore TABLE to its original + state, stopping when there are LIMIT entires left in LOCALs. */ + +static void +restore_vars_to_original_value (varray_type locals, + unsigned limit, + varray_type table) +{ + if (! locals) + return; + + while (VARRAY_ACTIVE_SIZE (locals) > limit) + { + tree prev_value, dest; + + prev_value = VARRAY_TOP_TREE (locals); + VARRAY_POP (locals); + dest = VARRAY_TOP_TREE (locals); + VARRAY_POP (locals); + + set_value_for (dest, prev_value, table); + } +} + +/* Similar to restore_vars_to_original_value, except that it restores + CURRDEFS to its original value. */ +static void +restore_currdefs_to_original_value (varray_type locals, unsigned limit) +{ + if (!locals) + return; + + /* Restore CURRDEFS to its original state. */ + while (VARRAY_ACTIVE_SIZE (locals) > limit) + { + tree tmp = VARRAY_TOP_TREE (locals); + tree saved_def, var; + + VARRAY_POP (locals); + + /* If we recorded an SSA_NAME, then make the SSA_NAME the current + definition of its underlying variable. If we recorded anything + else, it must have been an _DECL node and its current reaching + definition must have been NULL. */ + if (TREE_CODE (tmp) == SSA_NAME) + { + saved_def = tmp; + var = SSA_NAME_VAR (saved_def); + } + else + { + saved_def = NULL; + var = tmp; + } + + var_ann (var)->current_def = saved_def; + } +} + +/* We have finished processing the dominator children of BB, perform + any finalization actions in preparation for leaving this node in + the dominator tree. */ + +static void +dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb) +{ + struct dom_walk_block_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + tree last; + + /* If we are at a leaf node in the dominator graph, see if we can thread + the edge from BB through its successor. + + Do this before we remove entries from our equivalence tables. */ + if (bb->succ + && ! bb->succ->succ_next + && (bb->succ->flags & EDGE_ABNORMAL) == 0 + && (get_immediate_dominator (CDI_DOMINATORS, bb->succ->dest) != bb + || phi_nodes (bb->succ->dest))) + + { + thread_across_edge (walk_data, bb->succ); + } + else if ((last = last_stmt (bb)) + && TREE_CODE (last) == COND_EXPR + && (TREE_CODE_CLASS (TREE_CODE (COND_EXPR_COND (last))) == '<' + || TREE_CODE (COND_EXPR_COND (last)) == SSA_NAME) + && bb->succ + && (bb->succ->flags & EDGE_ABNORMAL) == 0 + && bb->succ->succ_next + && (bb->succ->succ_next->flags & EDGE_ABNORMAL) == 0 + && ! bb->succ->succ_next->succ_next) + { + edge true_edge, false_edge; + tree cond, inverted = NULL; + enum tree_code cond_code; + + extract_true_false_edges_from_block (bb, &true_edge, &false_edge); + + cond = COND_EXPR_COND (last); + cond_code = TREE_CODE (cond); + + if (TREE_CODE_CLASS (cond_code) == '<') + inverted = invert_truthvalue (cond); + + /* If the THEN arm is the end of a dominator tree or has PHI nodes, + then try to thread through its edge. */ + if (get_immediate_dominator (CDI_DOMINATORS, true_edge->dest) != bb + || phi_nodes (true_edge->dest)) + { + unsigned avail_expr_limit; + unsigned const_and_copies_limit; + unsigned currdefs_limit; + + avail_expr_limit + = bd->avail_exprs ? VARRAY_ACTIVE_SIZE (bd->avail_exprs) : 0; + const_and_copies_limit + = bd->const_and_copies ? VARRAY_ACTIVE_SIZE (bd->const_and_copies) + : 0; + currdefs_limit + = bd->block_defs ? VARRAY_ACTIVE_SIZE (bd->block_defs) : 0; + + /* Record any equivalences created by following this edge. */ + if (TREE_CODE_CLASS (cond_code) == '<') + { + record_cond (cond, boolean_true_node, &bd->avail_exprs); + record_cond (inverted, boolean_false_node, &bd->avail_exprs); + } + else if (cond_code == SSA_NAME) + record_const_or_copy (cond, boolean_true_node, + &bd->const_and_copies); + + /* Now thread the edge. */ + thread_across_edge (walk_data, true_edge); + + /* And restore the various tables to their state before + we threaded this edge. */ + remove_local_expressions_from_table (bd->avail_exprs, + avail_expr_limit, + avail_exprs); + restore_vars_to_original_value (bd->const_and_copies, + const_and_copies_limit, + const_and_copies); + restore_currdefs_to_original_value (bd->block_defs, currdefs_limit); + } + + /* Similarly for the ELSE arm. */ + if (get_immediate_dominator (CDI_DOMINATORS, false_edge->dest) != bb + || phi_nodes (false_edge->dest)) + { + /* Record any equivalences created by following this edge. */ + if (TREE_CODE_CLASS (cond_code) == '<') + { + record_cond (cond, boolean_false_node, &bd->avail_exprs); + record_cond (inverted, boolean_true_node, &bd->avail_exprs); + } + else if (cond_code == SSA_NAME) + record_const_or_copy (cond, boolean_false_node, + &bd->const_and_copies); + + thread_across_edge (walk_data, false_edge); + + /* No need to remove local expressions from our tables + or restore vars to their original value as that will + be done immediately below. */ + } + } + + remove_local_expressions_from_table (bd->avail_exprs, 0, avail_exprs); + restore_nonzero_vars_to_original_value (bd->nonzero_vars, 0, nonzero_vars); + restore_vars_to_original_value (bd->const_and_copies, 0, const_and_copies); + restore_currdefs_to_original_value (bd->block_defs, 0); + + /* Remove VRP records associated with this basic block. They are no + longer valid. + + To be efficient, we note which variables have had their values + constrained in this block. So walk over each variable in the + VRP_VARIABLEs array. */ + while (bd->vrp_variables && VARRAY_ACTIVE_SIZE (bd->vrp_variables) > 0) + { + tree var = VARRAY_TOP_TREE (bd->vrp_variables); + + /* Each variable has a stack of value range records. We want to + invalidate those associated with our basic block. So we walk + the array backwards popping off records associated with our + block. Once we hit a record not associated with our block + we are done. */ + varray_type var_vrp_records = VARRAY_GENERIC_PTR (vrp_data, + SSA_NAME_VERSION (var)); + + while (VARRAY_ACTIVE_SIZE (var_vrp_records) > 0) + { + struct vrp_element *element + = (struct vrp_element *)VARRAY_TOP_GENERIC_PTR (var_vrp_records); + + if (element->bb != bb) + break; + + VARRAY_POP (var_vrp_records); + } + + VARRAY_POP (bd->vrp_variables); + } + + /* Re-scan operands in all statements that may have had new symbols + exposed. */ + while (bd->stmts_to_rescan && VARRAY_ACTIVE_SIZE (bd->stmts_to_rescan) > 0) + { + tree stmt = VARRAY_TOP_TREE (bd->stmts_to_rescan); + VARRAY_POP (bd->stmts_to_rescan); + mark_new_vars_to_rename (stmt, vars_to_rename); + } +} + +/* PHI nodes can create equivalences too. + + Ignoring any alternatives which are the same as the result, if + all the alternatives are equal, then the PHI node creates an + equivalence. */ +static void +record_equivalences_from_phis (struct dom_walk_data *walk_data, basic_block bb) +{ + struct dom_walk_block_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree lhs = PHI_RESULT (phi); + tree rhs = NULL; + int i; + + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + tree t = PHI_ARG_DEF (phi, i); + + if (TREE_CODE (t) == SSA_NAME || is_gimple_min_invariant (t)) + { + /* Ignore alternatives which are the same as our LHS. */ + if (operand_equal_p (lhs, t, 0)) + continue; + + /* If we have not processed an alternative yet, then set + RHS to this alternative. */ + if (rhs == NULL) + rhs = t; + /* If we have processed an alternative (stored in RHS), then + see if it is equal to this one. If it isn't, then stop + the search. */ + else if (! operand_equal_p (rhs, t, 0)) + break; + } + else + break; + } + + /* If we had no interesting alternatives, then all the RHS alternatives + must have been the same as LHS. */ + if (!rhs) + rhs = lhs; + + /* If we managed to iterate through each PHI alternative without + breaking out of the loop, then we have a PHI which may create + a useful equivalence. We do not need to record unwind data for + this, since this is a true assignment and not an equivalence + infered from a comparison. All uses of this ssa name are dominated + by this assignment, so unwinding just costs time and space. */ + if (i == PHI_NUM_ARGS (phi) + && may_propagate_copy (lhs, rhs)) + set_value_for (lhs, rhs, const_and_copies); + + register_new_def (lhs, &bd->block_defs); + } +} + +/* Record any equivalences created by the incoming edge to BB. If BB + has more than one incoming edge, then no equivalence is created. */ + +static void +record_equivalences_from_incoming_edge (struct dom_walk_data *walk_data, + basic_block bb) +{ + int edge_flags; + basic_block parent; + struct eq_expr_value eq_expr_value; + tree parent_block_last_stmt = NULL; + struct dom_walk_block_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + /* If our parent block ended with a control statment, then we may be + able to record some equivalences based on which outgoing edge from + the parent was followed. */ + parent = get_immediate_dominator (CDI_DOMINATORS, bb); + if (parent) + { + parent_block_last_stmt = last_stmt (parent); + if (parent_block_last_stmt && !is_ctrl_stmt (parent_block_last_stmt)) + parent_block_last_stmt = NULL; + } + + eq_expr_value.src = NULL; + eq_expr_value.dst = NULL; + + /* If we have a single predecessor, then extract EDGE_FLAGS from + our single incoming edge. Otherwise clear EDGE_FLAGS and + PARENT_BLOCK_LAST_STMT since they're not needed. */ + if (bb->pred + && ! bb->pred->pred_next + && parent_block_last_stmt + && bb_for_stmt (parent_block_last_stmt) == bb->pred->src) + { + edge_flags = bb->pred->flags; + } + else + { + edge_flags = 0; + parent_block_last_stmt = NULL; + } + + /* If our parent block ended in a COND_EXPR, add any equivalences + created by the COND_EXPR to the hash table and initialize + EQ_EXPR_VALUE appropriately. + + EQ_EXPR_VALUE is an assignment expression created when BB's immediate + dominator ends in a COND_EXPR statement whose predicate is of the form + 'VAR == VALUE', where VALUE may be another variable or a constant. + This is used to propagate VALUE on the THEN_CLAUSE of that + conditional. This assignment is inserted in CONST_AND_COPIES so that + the copy and constant propagator can find more propagation + opportunities. */ + if (parent_block_last_stmt + && bb->pred->pred_next == NULL + && TREE_CODE (parent_block_last_stmt) == COND_EXPR + && (edge_flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))) + eq_expr_value = get_eq_expr_value (parent_block_last_stmt, + (edge_flags & EDGE_TRUE_VALUE) != 0, + &bd->avail_exprs, + bb, + &bd->vrp_variables); + /* Similarly when the parent block ended in a SWITCH_EXPR. */ + else if (parent_block_last_stmt + && bb->pred->pred_next == NULL + && TREE_CODE (parent_block_last_stmt) == SWITCH_EXPR) + { + tree switch_cond = SWITCH_COND (parent_block_last_stmt); + + /* If the switch's condition is an SSA variable, then we may + know its value at each of the case labels. */ + if (TREE_CODE (switch_cond) == SSA_NAME) + { + tree switch_vec = SWITCH_LABELS (parent_block_last_stmt); + size_t i, n = TREE_VEC_LENGTH (switch_vec); + int case_count = 0; + tree match_case = NULL_TREE; + + /* Search the case labels for those whose destination is + the current basic block. */ + for (i = 0; i < n; ++i) + { + tree elt = TREE_VEC_ELT (switch_vec, i); + if (label_to_block (CASE_LABEL (elt)) == bb) + { + if (++case_count > 1) + break; + match_case = elt; + } + } + + /* If we encountered precisely one CASE_LABEL_EXPR and it + was not the default case, or a case range, then we know + the exact value of SWITCH_COND which caused us to get to + this block. Record that equivalence in EQ_EXPR_VALUE. */ + if (case_count == 1 + && CASE_LOW (match_case) + && !CASE_HIGH (match_case)) + { + eq_expr_value.dst = switch_cond; + eq_expr_value.src = CASE_LOW (match_case); + } + } + } + + /* If EQ_EXPR_VALUE (VAR == VALUE) is given, register the VALUE as a + new value for VAR, so that occurrences of VAR can be replaced with + VALUE while re-writing the THEN arm of a COND_EXPR. */ + if (eq_expr_value.src && eq_expr_value.dst) + record_equality (eq_expr_value.dst, eq_expr_value.src, + &bd->const_and_copies); +} + +/* Dump SSA statistics on FILE. */ + +void +dump_dominator_optimization_stats (FILE *file) +{ + long n_exprs; + + fprintf (file, "Total number of statements: %6ld\n\n", + opt_stats.num_stmts); + fprintf (file, "Exprs considered for dominator optimizations: %6ld\n", + opt_stats.num_exprs_considered); + + n_exprs = opt_stats.num_exprs_considered; + if (n_exprs == 0) + n_exprs = 1; + + fprintf (file, " Redundant expressions eliminated: %6ld (%.0f%%)\n", + opt_stats.num_re, PERCENT (opt_stats.num_re, + n_exprs)); + + fprintf (file, "\nHash table statistics:\n"); + + fprintf (file, " avail_exprs: "); + htab_statistics (file, avail_exprs); +} + + +/* Dump SSA statistics on stderr. */ + +void +debug_dominator_optimization_stats (void) +{ + dump_dominator_optimization_stats (stderr); +} + + +/* Dump statistics for the hash table HTAB. */ + +static void +htab_statistics (FILE *file, htab_t htab) +{ + fprintf (file, "size %ld, %ld elements, %f collision/search ratio\n", + (long) htab_size (htab), + (long) htab_elements (htab), + htab_collisions (htab)); +} + +/* Record the fact that VAR has a nonzero value, though we may not know + its exact value. Note that if VAR is already known to have a nonzero + value, then we do nothing. */ + +static void +record_var_is_nonzero (tree var, varray_type *block_nonzero_vars_p) +{ + int indx = SSA_NAME_VERSION (var); + + if (bitmap_bit_p (nonzero_vars, indx)) + return; + + /* Mark it in the global table. */ + bitmap_set_bit (nonzero_vars, indx); + + /* Record this SSA_NAME so that we can reset the global table + when we leave this block. */ + if (! *block_nonzero_vars_p) + VARRAY_TREE_INIT (*block_nonzero_vars_p, 2, "block_nonzero_vars"); + VARRAY_PUSH_TREE (*block_nonzero_vars_p, var); +} + +/* Enter a statement into the true/false expression hash table indicating + that the condition COND has the value VALUE. */ + +static void +record_cond (tree cond, tree value, varray_type *block_avail_exprs_p) +{ + struct expr_hash_elt *element = xmalloc (sizeof (struct expr_hash_elt)); + void **slot; + + initialize_hash_element (cond, value, element); + + slot = htab_find_slot_with_hash (avail_exprs, (void *)element, + element->hash, true); + if (*slot == NULL) + { + *slot = (void *) element; + if (! *block_avail_exprs_p) + VARRAY_TREE_INIT (*block_avail_exprs_p, 20, "block_avail_exprs"); + VARRAY_PUSH_TREE (*block_avail_exprs_p, cond); + } + else + free (element); +} + +/* A helper function for record_const_or_copy and record_equality. + Do the work of recording the value and undo info. */ + +static void +record_const_or_copy_1 (tree x, tree y, tree prev_x, + varray_type *block_const_and_copies_p) +{ + set_value_for (x, y, const_and_copies); + + if (!*block_const_and_copies_p) + VARRAY_TREE_INIT (*block_const_and_copies_p, 2, "block_const_and_copies"); + VARRAY_PUSH_TREE (*block_const_and_copies_p, x); + VARRAY_PUSH_TREE (*block_const_and_copies_p, prev_x); +} + +/* Record that X is equal to Y in const_and_copies. Record undo + information in the block-local varray. */ + +static void +record_const_or_copy (tree x, tree y, varray_type *block_const_and_copies_p) +{ + tree prev_x = get_value_for (x, const_and_copies); + + if (TREE_CODE (y) == SSA_NAME) + { + tree tmp = get_value_for (y, const_and_copies); + if (tmp) + y = tmp; + } + + record_const_or_copy_1 (x, y, prev_x, block_const_and_copies_p); +} + +/* Similarly, but assume that X and Y are the two operands of an EQ_EXPR. + This constrains the cases in which we may treat this as assignment. */ + +static void +record_equality (tree x, tree y, varray_type *block_const_and_copies_p) +{ + tree prev_x = NULL, prev_y = NULL; + + if (TREE_CODE (x) == SSA_NAME) + prev_x = get_value_for (x, const_and_copies); + if (TREE_CODE (y) == SSA_NAME) + prev_y = get_value_for (y, const_and_copies); + + /* If one of the previous values is invariant, then use that. + Otherwise it doesn't matter which value we choose, just so + long as we canonicalize on one value. */ + if (TREE_INVARIANT (y)) + ; + else if (TREE_INVARIANT (x)) + prev_x = x, x = y, y = prev_x, prev_x = prev_y; + else if (prev_x && TREE_INVARIANT (prev_x)) + x = y, y = prev_x, prev_x = prev_y; + else if (prev_y) + y = prev_y; + + /* After the swapping, we must have one SSA_NAME. */ + if (TREE_CODE (x) != SSA_NAME) + return; + + /* For IEEE, -0.0 == 0.0, so we don't necessarily know the sign of a + variable compared against zero. If we're honoring signed zeros, + then we cannot record this value unless we know that the value is + non-zero. */ + if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (x))) + && (TREE_CODE (y) != REAL_CST + || REAL_VALUES_EQUAL (dconst0, TREE_REAL_CST (y)))) + return; + + record_const_or_copy_1 (x, y, prev_x, block_const_and_copies_p); +} + +/* STMT is a MODIFY_EXPR for which we were unable to find RHS in the + hash tables. Try to simplify the RHS using whatever equivalences + we may have recorded. + + If we are able to simplify the RHS, then lookup the simplified form in + the hash table and return the result. Otherwise return NULL. */ + +static tree +simplify_rhs_and_lookup_avail_expr (struct dom_walk_data *walk_data, + tree stmt, + stmt_ann_t ann, + int insert) +{ + tree rhs = TREE_OPERAND (stmt, 1); + enum tree_code rhs_code = TREE_CODE (rhs); + tree result = NULL; + struct dom_walk_block_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + /* If we have lhs = ~x, look and see if we earlier had x = ~y. + In which case we can change this statement to be lhs = y. + Which can then be copy propagated. + + Similarly for negation. */ + if ((rhs_code == BIT_NOT_EXPR || rhs_code == NEGATE_EXPR) + && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) + { + /* Get the definition statement for our RHS. */ + tree rhs_def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0)); + + /* See if the RHS_DEF_STMT has the same form as our statement. */ + if (TREE_CODE (rhs_def_stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (rhs_def_stmt, 1)) == rhs_code) + { + tree rhs_def_operand; + + rhs_def_operand = TREE_OPERAND (TREE_OPERAND (rhs_def_stmt, 1), 0); + + /* Verify that RHS_DEF_OPERAND is a suitable SSA variable. */ + if (TREE_CODE (rhs_def_operand) == SSA_NAME + && ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs_def_operand)) + result = update_rhs_and_lookup_avail_expr (stmt, + rhs_def_operand, + &bd->avail_exprs, + ann, + insert); + } + } + + /* If we have z = (x OP C1), see if we earlier had x = y OP C2. + If OP is associative, create and fold (y OP C2) OP C1 which + should result in (y OP C3), use that as the RHS for the + assignment. Add minus to this, as we handle it specially below. */ + if ((associative_tree_code (rhs_code) || rhs_code == MINUS_EXPR) + && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME + && is_gimple_min_invariant (TREE_OPERAND (rhs, 1))) + { + tree rhs_def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0)); + + /* See if the RHS_DEF_STMT has the same form as our statement. */ + if (TREE_CODE (rhs_def_stmt) == MODIFY_EXPR) + { + tree rhs_def_rhs = TREE_OPERAND (rhs_def_stmt, 1); + enum tree_code rhs_def_code = TREE_CODE (rhs_def_rhs); + + if (rhs_code == rhs_def_code + || (rhs_code == PLUS_EXPR && rhs_def_code == MINUS_EXPR) + || (rhs_code == MINUS_EXPR && rhs_def_code == PLUS_EXPR)) + { + tree def_stmt_op0 = TREE_OPERAND (rhs_def_rhs, 0); + tree def_stmt_op1 = TREE_OPERAND (rhs_def_rhs, 1); + + if (TREE_CODE (def_stmt_op0) == SSA_NAME + && ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def_stmt_op0) + && is_gimple_min_invariant (def_stmt_op1)) + { + tree outer_const = TREE_OPERAND (rhs, 1); + tree type = TREE_TYPE (TREE_OPERAND (stmt, 0)); + tree t; + + /* Ho hum. So fold will only operate on the outermost + thingy that we give it, so we have to build the new + expression in two pieces. This requires that we handle + combinations of plus and minus. */ + if (rhs_def_code != rhs_code) + { + if (rhs_def_code == MINUS_EXPR) + t = build (MINUS_EXPR, type, outer_const, def_stmt_op1); + else + t = build (MINUS_EXPR, type, def_stmt_op1, outer_const); + rhs_code = PLUS_EXPR; + } + else if (rhs_def_code == MINUS_EXPR) + t = build (PLUS_EXPR, type, def_stmt_op1, outer_const); + else + t = build (rhs_def_code, type, def_stmt_op1, outer_const); + t = local_fold (t); + t = build (rhs_code, type, def_stmt_op0, t); + t = local_fold (t); + + /* If the result is a suitable looking gimple expression, + then use it instead of the original for STMT. */ + if (TREE_CODE (t) == SSA_NAME + || (TREE_CODE_CLASS (TREE_CODE (t)) == '1' + && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME) + || ((TREE_CODE_CLASS (TREE_CODE (t)) == '2' + || TREE_CODE_CLASS (TREE_CODE (t)) == '<') + && TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME + && is_gimple_val (TREE_OPERAND (t, 1)))) + result = update_rhs_and_lookup_avail_expr + (stmt, t, &bd->avail_exprs, ann, insert); + } + } + } + } + + /* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR + and BIT_AND_EXPR respectively if the first operand is greater + than zero and the second operand is an exact power of two. */ + if ((rhs_code == TRUNC_DIV_EXPR || rhs_code == TRUNC_MOD_EXPR) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0))) + && integer_pow2p (TREE_OPERAND (rhs, 1))) + { + tree val; + tree op = TREE_OPERAND (rhs, 0); + + if (TYPE_UNSIGNED (TREE_TYPE (op))) + { + val = integer_one_node; + } + else + { + tree dummy_cond = walk_data->global_data; + + if (! dummy_cond) + { + dummy_cond = build (GT_EXPR, boolean_type_node, + op, integer_zero_node); + dummy_cond = build (COND_EXPR, void_type_node, + dummy_cond, NULL, NULL); + walk_data->global_data = dummy_cond; + } + else + { + TREE_SET_CODE (TREE_OPERAND (dummy_cond, 0), GT_EXPR); + TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 0) = op; + TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 1) + = integer_zero_node; + } + val = simplify_cond_and_lookup_avail_expr (dummy_cond, + &bd->avail_exprs, + NULL, false); + } + + if (val && integer_onep (val)) + { + tree t; + tree op0 = TREE_OPERAND (rhs, 0); + tree op1 = TREE_OPERAND (rhs, 1); + + if (rhs_code == TRUNC_DIV_EXPR) + t = build (RSHIFT_EXPR, TREE_TYPE (op0), op0, + build_int_2 (tree_log2 (op1), 0)); + else + t = build (BIT_AND_EXPR, TREE_TYPE (op0), op0, + local_fold (build (MINUS_EXPR, TREE_TYPE (op1), + op1, integer_one_node))); + + result = update_rhs_and_lookup_avail_expr (stmt, t, + &bd->avail_exprs, + ann, insert); + } + } + + /* Transform ABS (X) into X or -X as appropriate. */ + if (rhs_code == ABS_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0)))) + { + tree val; + tree op = TREE_OPERAND (rhs, 0); + tree type = TREE_TYPE (op); + + if (TYPE_UNSIGNED (type)) + { + val = integer_zero_node; + } + else + { + tree dummy_cond = walk_data->global_data; + + if (! dummy_cond) + { + dummy_cond = build (LT_EXPR, boolean_type_node, + op, integer_zero_node); + dummy_cond = build (COND_EXPR, void_type_node, + dummy_cond, NULL, NULL); + walk_data->global_data = dummy_cond; + } + else + { + TREE_SET_CODE (TREE_OPERAND (dummy_cond, 0), LT_EXPR); + TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 0) = op; + TREE_OPERAND (TREE_OPERAND (dummy_cond, 0), 1) + = convert (type, integer_zero_node); + } + val = simplify_cond_and_lookup_avail_expr (dummy_cond, + &bd->avail_exprs, + NULL, false); + } + + if (val + && (integer_onep (val) || integer_zerop (val))) + { + tree t; + + if (integer_onep (val)) + t = build1 (NEGATE_EXPR, TREE_TYPE (op), op); + else + t = op; + + result = update_rhs_and_lookup_avail_expr (stmt, t, + &bd->avail_exprs, + ann, insert); + } + } + + /* Optimize *"foo" into 'f'. This is done here rather than + in fold to avoid problems with stuff like &*"foo". */ + if (TREE_CODE (rhs) == INDIRECT_REF || TREE_CODE (rhs) == ARRAY_REF) + { + tree t = fold_read_from_constant_string (rhs); + + if (t) + result = update_rhs_and_lookup_avail_expr (stmt, t, + &bd->avail_exprs, + ann, insert); + } + + return result; +} + +/* COND is a condition of the form: + + x == const or x != const + + Look back to x's defining statement and see if x is defined as + + x = (type) y; + + If const is unchanged if we convert it to type, then we can build + the equivalent expression: + + + y == const or y != const + + Which may allow further optimizations. + + Return the equivalent comparison or NULL if no such equivalent comparison + was found. */ + +static tree +find_equivalent_equality_comparison (tree cond) +{ + tree op0 = TREE_OPERAND (cond, 0); + tree op1 = TREE_OPERAND (cond, 1); + tree def_stmt = SSA_NAME_DEF_STMT (op0); + + /* OP0 might have been a parameter, so first make sure it + was defined by a MODIFY_EXPR. */ + if (def_stmt && TREE_CODE (def_stmt) == MODIFY_EXPR) + { + tree def_rhs = TREE_OPERAND (def_stmt, 1); + + /* Now make sure the RHS of the MODIFY_EXPR is a typecast. */ + if ((TREE_CODE (def_rhs) == NOP_EXPR + || TREE_CODE (def_rhs) == CONVERT_EXPR) + && TREE_CODE (TREE_OPERAND (def_rhs, 0)) == SSA_NAME) + { + tree def_rhs_inner = TREE_OPERAND (def_rhs, 0); + tree def_rhs_inner_type = TREE_TYPE (def_rhs_inner); + tree new; + + if (TYPE_PRECISION (def_rhs_inner_type) + > TYPE_PRECISION (TREE_TYPE (def_rhs))) + return NULL; + + /* What we want to prove is that if we convert OP1 to + the type of the object inside the NOP_EXPR that the + result is still equivalent to SRC. + + If that is true, the build and return new equivalent + condition which uses the source of the typecast and the + new constant (which has only changed its type). */ + new = build1 (TREE_CODE (def_rhs), def_rhs_inner_type, op1); + new = local_fold (new); + if (is_gimple_val (new) && tree_int_cst_equal (new, op1)) + return build (TREE_CODE (cond), TREE_TYPE (cond), + def_rhs_inner, new); + } + } + return NULL; +} + +/* STMT is a COND_EXPR for which we could not trivially determine its + result. This routine attempts to find equivalent forms of the + condition which we may be able to optimize better. It also + uses simple value range propagation to optimize conditionals. */ + +static tree +simplify_cond_and_lookup_avail_expr (tree stmt, + varray_type *block_avail_exprs_p, + stmt_ann_t ann, + int insert) +{ + tree cond = COND_EXPR_COND (stmt); + + if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<') + { + tree op0 = TREE_OPERAND (cond, 0); + tree op1 = TREE_OPERAND (cond, 1); + + if (TREE_CODE (op0) == SSA_NAME && is_gimple_min_invariant (op1)) + { + int limit; + tree low, high, cond_low, cond_high; + int lowequal, highequal, swapped, no_overlap, subset, cond_inverted; + varray_type vrp_records; + struct vrp_element *element; + + /* First see if we have test of an SSA_NAME against a constant + where the SSA_NAME is defined by an earlier typecast which + is irrelevant when performing tests against the given + constant. */ + if (TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR) + { + tree new_cond = find_equivalent_equality_comparison (cond); + + if (new_cond) + { + /* Update the statement to use the new equivalent + condition. */ + COND_EXPR_COND (stmt) = new_cond; + ann->modified = 1; + + /* Lookup the condition and return its known value if it + exists. */ + new_cond = lookup_avail_expr (stmt, block_avail_exprs_p, + insert); + if (new_cond) + return new_cond; + + /* The operands have changed, so update op0 and op1. */ + op0 = TREE_OPERAND (cond, 0); + op1 = TREE_OPERAND (cond, 1); + } + } + + /* Consult the value range records for this variable (if they exist) + to see if we can eliminate or simplify this conditional. + + Note two tests are necessary to determine no records exist. + First we have to see if the virtual array exists, if it + exists, then we have to check its active size. + + Also note the vast majority of conditionals are not testing + a variable which has had its range constrained by an earlier + conditional. So this filter avoids a lot of unnecessary work. */ + vrp_records = VARRAY_GENERIC_PTR (vrp_data, SSA_NAME_VERSION (op0)); + if (vrp_records == NULL) + return NULL; + + limit = VARRAY_ACTIVE_SIZE (vrp_records); + + /* If we have no value range records for this variable, or we are + unable to extract a range for this condition, then there is + nothing to do. */ + if (limit == 0 + || ! extract_range_from_cond (cond, &cond_high, + &cond_low, &cond_inverted)) + return NULL; + + /* We really want to avoid unnecessary computations of range + info. So all ranges are computed lazily; this avoids a + lot of unnecessary work. ie, we record the conditional, + but do not process how it constrains the variable's + potential values until we know that processing the condition + could be helpful. + + However, we do not want to have to walk a potentially long + list of ranges, nor do we want to compute a variable's + range more than once for a given path. + + Luckily, each time we encounter a conditional that can not + be otherwise optimized we will end up here and we will + compute the necessary range information for the variable + used in this condition. + + Thus you can conclude that there will never be more than one + conditional associated with a variable which has not been + processed. So we never need to merge more than one new + conditional into the current range. + + These properties also help us avoid unnecessary work. */ + element + = (struct vrp_element *)VARRAY_GENERIC_PTR (vrp_records, limit - 1); + + if (element->high && element->low) + { + /* The last element has been processed, so there is no range + merging to do, we can simply use the high/low values + recorded in the last element. */ + low = element->low; + high = element->high; + } + else + { + tree tmp_high, tmp_low; + int dummy; + + /* The last element has not been processed. Process it now. */ + extract_range_from_cond (element->cond, &tmp_high, + &tmp_low, &dummy); + + /* If this is the only element, then no merging is necessary, + the high/low values from extract_range_from_cond are all + we need. */ + if (limit == 1) + { + low = tmp_low; + high = tmp_high; + } + else + { + /* Get the high/low value from the previous element. */ + struct vrp_element *prev + = (struct vrp_element *)VARRAY_GENERIC_PTR (vrp_records, + limit - 2); + low = prev->low; + high = prev->high; + + /* Merge in this element's range with the range from the + previous element. + + The low value for the merged range is the maximum of + the previous low value and the low value of this record. + + Similarly the high value for the merged range is the + minimum of the previous high value and the high value of + this record. */ + low = (tree_int_cst_compare (low, tmp_low) == 1 + ? low : tmp_low); + high = (tree_int_cst_compare (high, tmp_high) == -1 + ? high : tmp_high); + } + + /* And record the computed range. */ + element->low = low; + element->high = high; + + } + + /* After we have constrained this variable's potential values, + we try to determine the result of the given conditional. + + To simplify later tests, first determine if the current + low value is the same low value as the conditional. + Similarly for the current high value and the high value + for the conditional. */ + lowequal = tree_int_cst_equal (low, cond_low); + highequal = tree_int_cst_equal (high, cond_high); + + if (lowequal && highequal) + return (cond_inverted ? boolean_false_node : boolean_true_node); + + /* To simplify the overlap/subset tests below we may want + to swap the two ranges so that the larger of the two + ranges occurs "first". */ + swapped = 0; + if (tree_int_cst_compare (low, cond_low) == 1 + || (lowequal + && tree_int_cst_compare (cond_high, high) == 1)) + { + tree temp; + + swapped = 1; + temp = low; + low = cond_low; + cond_low = temp; + temp = high; + high = cond_high; + cond_high = temp; + } + + /* Now determine if there is no overlap in the ranges + or if the second range is a subset of the first range. */ + no_overlap = tree_int_cst_lt (high, cond_low); + subset = tree_int_cst_compare (cond_high, high) != 1; + + /* If there was no overlap in the ranges, then this conditional + always has a false value (unless we had to invert this + conditional, in which case it always has a true value). */ + if (no_overlap) + return (cond_inverted ? boolean_true_node : boolean_false_node); + + /* If the current range is a subset of the condition's range, + then this conditional always has a true value (unless we + had to invert this conditional, in which case it always + has a true value). */ + if (subset && swapped) + return (cond_inverted ? boolean_false_node : boolean_true_node); + + /* We were unable to determine the result of the conditional. + However, we may be able to simplify the conditional. First + merge the ranges in the same manner as range merging above. */ + low = tree_int_cst_compare (low, cond_low) == 1 ? low : cond_low; + high = tree_int_cst_compare (high, cond_high) == -1 ? high : cond_high; + + /* If the range has converged to a single point, then turn this + into an equality comparison. */ + if (TREE_CODE (cond) != EQ_EXPR + && TREE_CODE (cond) != NE_EXPR + && tree_int_cst_equal (low, high)) + { + TREE_SET_CODE (cond, EQ_EXPR); + TREE_OPERAND (cond, 1) = high; + } + } + } + return 0; +} + +/* STMT is a SWITCH_EXPR for which we could not trivially determine its + result. This routine attempts to find equivalent forms of the + condition which we may be able to optimize better. */ + +static tree +simplify_switch_and_lookup_avail_expr (tree stmt, + varray_type *block_avail_exprs_p, + stmt_ann_t ann, + int insert) +{ + tree cond = SWITCH_COND (stmt); + tree def, to, ti; + + /* The optimization that we really care about is removing unnecessary + casts. That will let us do much better in propagating the inferred + constant at the switch target. */ + if (TREE_CODE (cond) == SSA_NAME) + { + def = SSA_NAME_DEF_STMT (cond); + if (TREE_CODE (def) == MODIFY_EXPR) + { + def = TREE_OPERAND (def, 1); + if (TREE_CODE (def) == NOP_EXPR) + { + def = TREE_OPERAND (def, 0); + to = TREE_TYPE (cond); + ti = TREE_TYPE (def); + + /* If we have an extension that preserves sign, then we + can copy the source value into the switch. */ + if (TYPE_UNSIGNED (to) == TYPE_UNSIGNED (ti) + && TYPE_PRECISION (to) >= TYPE_PRECISION (ti) + && is_gimple_val (def)) + { + SWITCH_COND (stmt) = def; + ann->modified = 1; + + return lookup_avail_expr (stmt, block_avail_exprs_p, insert); + } + } + } + } + + return 0; +} + +/* Propagate known constants/copies into PHI nodes of BB's successor + blocks. */ + +static void +cprop_into_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED, + basic_block bb) +{ + cprop_into_successor_phis (bb, const_and_copies); +} + +/* Search for redundant computations in STMT. If any are found, then + replace them with the variable holding the result of the computation. + + If safe, record this expression into the available expression hash + table. */ + +static bool +eliminate_redundant_computations (struct dom_walk_data *walk_data, + tree stmt, stmt_ann_t ann) +{ + vdef_optype vdefs = VDEF_OPS (ann); + tree *expr_p, def = NULL_TREE; + bool insert = true; + tree cached_lhs; + bool retval = false; + struct dom_walk_block_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + if (TREE_CODE (stmt) == MODIFY_EXPR) + def = TREE_OPERAND (stmt, 0); + + /* Certain expressions on the RHS can be optimized away, but can not + themselves be entered into the hash tables. */ + if (ann->makes_aliased_stores + || ! def + || TREE_CODE (def) != SSA_NAME + || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def) + || NUM_VDEFS (vdefs) != 0) + insert = false; + + /* Check if the expression has been computed before. */ + cached_lhs = lookup_avail_expr (stmt, &bd->avail_exprs, insert); + + /* If this is an assignment and the RHS was not in the hash table, + then try to simplify the RHS and lookup the new RHS in the + hash table. */ + if (! cached_lhs && TREE_CODE (stmt) == MODIFY_EXPR) + cached_lhs = simplify_rhs_and_lookup_avail_expr (walk_data, + stmt, + ann, + insert); + /* Similarly if this is a COND_EXPR and we did not find its + expression in the hash table, simplify the condition and + try again. */ + else if (! cached_lhs && TREE_CODE (stmt) == COND_EXPR) + cached_lhs = simplify_cond_and_lookup_avail_expr (stmt, + &bd->avail_exprs, + ann, + insert); + /* Similarly for a SWITCH_EXPR. */ + else if (!cached_lhs && TREE_CODE (stmt) == SWITCH_EXPR) + cached_lhs = simplify_switch_and_lookup_avail_expr (stmt, + &bd->avail_exprs, + ann, + insert); + + opt_stats.num_exprs_considered++; + + /* Get a pointer to the expression we are trying to optimize. */ + if (TREE_CODE (stmt) == COND_EXPR) + expr_p = &COND_EXPR_COND (stmt); + else if (TREE_CODE (stmt) == SWITCH_EXPR) + expr_p = &SWITCH_COND (stmt); + else if (TREE_CODE (stmt) == RETURN_EXPR && TREE_OPERAND (stmt, 0)) + expr_p = &TREE_OPERAND (TREE_OPERAND (stmt, 0), 1); + else + expr_p = &TREE_OPERAND (stmt, 1); + + /* It is safe to ignore types here since we have already done + type checking in the hashing and equality routines. In fact + type checking here merely gets in the way of constant + propagation. Also, make sure that it is safe to propagate + CACHED_LHS into *EXPR_P. */ + if (cached_lhs + && (TREE_CODE (cached_lhs) != SSA_NAME + || may_propagate_copy (cached_lhs, *expr_p))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Replaced redundant expr '"); + print_generic_expr (dump_file, *expr_p, dump_flags); + fprintf (dump_file, "' with '"); + print_generic_expr (dump_file, cached_lhs, dump_flags); + fprintf (dump_file, "'\n"); + } + + opt_stats.num_re++; + +#if defined ENABLE_CHECKING + if (TREE_CODE (cached_lhs) != SSA_NAME + && !is_gimple_min_invariant (cached_lhs)) + abort (); +#endif + + if (TREE_CODE (cached_lhs) == ADDR_EXPR + || (POINTER_TYPE_P (TREE_TYPE (*expr_p)) + && is_gimple_min_invariant (cached_lhs))) + retval = true; + + propagate_value (expr_p, cached_lhs); + ann->modified = 1; + } + return retval; +} + +/* STMT, a MODIFY_EXPR, may create certain equivalences, in either + the available expressions table or the const_and_copies table. + Detect and record those equivalences. */ + +static void +record_equivalences_from_stmt (tree stmt, + varray_type *block_avail_exprs_p, + varray_type *block_nonzero_vars_p, + int may_optimize_p, + stmt_ann_t ann) +{ + tree lhs = TREE_OPERAND (stmt, 0); + enum tree_code lhs_code = TREE_CODE (lhs); + int i; + + if (lhs_code == SSA_NAME) + { + tree rhs = TREE_OPERAND (stmt, 1); + + /* Strip away any useless type conversions. */ + STRIP_USELESS_TYPE_CONVERSION (rhs); + + /* If the RHS of the assignment is a constant or another variable that + may be propagated, register it in the CONST_AND_COPIES table. We + do not need to record unwind data for this, since this is a true + assignment and not an equivalence infered from a comparison. All + uses of this ssa name are dominated by this assignment, so unwinding + just costs time and space. */ + if (may_optimize_p + && (TREE_CODE (rhs) == SSA_NAME + || is_gimple_min_invariant (rhs))) + set_value_for (lhs, rhs, const_and_copies); + + /* alloca never returns zero and the address of a non-weak symbol + is never zero. NOP_EXPRs and CONVERT_EXPRs can be completely + stripped as they do not affect this equivalence. */ + while (TREE_CODE (rhs) == NOP_EXPR + || TREE_CODE (rhs) == CONVERT_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + if (alloca_call_p (rhs) + || (TREE_CODE (rhs) == ADDR_EXPR + && DECL_P (TREE_OPERAND (rhs, 0)) + && ! DECL_WEAK (TREE_OPERAND (rhs, 0)))) + record_var_is_nonzero (lhs, block_nonzero_vars_p); + + /* IOR of any value with a nonzero value will result in a nonzero + value. Even if we do not know the exact result recording that + the result is nonzero is worth the effort. */ + if (TREE_CODE (rhs) == BIT_IOR_EXPR + && integer_nonzerop (TREE_OPERAND (rhs, 1))) + record_var_is_nonzero (lhs, block_nonzero_vars_p); + } + + /* Look at both sides for pointer dereferences. If we find one, then + the pointer must be nonnull and we can enter that equivalence into + the hash tables. */ + for (i = 0; i < 2; i++) + { + tree t = TREE_OPERAND (stmt, i); + + /* Strip away any COMPONENT_REFs. */ + while (TREE_CODE (t) == COMPONENT_REF) + t = TREE_OPERAND (t, 0); + + /* Now see if this is a pointer dereference. */ + if (TREE_CODE (t) == INDIRECT_REF) + { + tree op = TREE_OPERAND (t, 0); + + /* If the pointer is a SSA variable, then enter new + equivalences into the hash table. */ + if (TREE_CODE (op) == SSA_NAME) + record_var_is_nonzero (op, block_nonzero_vars_p); + } + } + + /* A memory store, even an aliased store, creates a useful + equivalence. By exchanging the LHS and RHS, creating suitable + vops and recording the result in the available expression table, + we may be able to expose more redundant loads. */ + if (!ann->has_volatile_ops + && (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME + || is_gimple_min_invariant (TREE_OPERAND (stmt, 1))) + && !is_gimple_reg (lhs)) + { + tree rhs = TREE_OPERAND (stmt, 1); + tree new; + size_t j; + + /* FIXME: If the LHS of the assignment is a bitfield and the RHS + is a constant, we need to adjust the constant to fit into the + type of the LHS. If the LHS is a bitfield and the RHS is not + a constant, then we can not record any equivalences for this + statement since we would need to represent the widening or + narrowing of RHS. This fixes gcc.c-torture/execute/921016-1.c + and should not be necessary if GCC represented bitfields + properly. */ + if (lhs_code == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (lhs, 1))) + { + if (TREE_CONSTANT (rhs)) + rhs = widen_bitfield (rhs, TREE_OPERAND (lhs, 1), lhs); + else + rhs = NULL; + + /* If the value overflowed, then we can not use this equivalence. */ + if (rhs && ! is_gimple_min_invariant (rhs)) + rhs = NULL; + } + + if (rhs) + { + vdef_optype vdefs = VDEF_OPS (ann); + + /* Build a new statement with the RHS and LHS exchanged. */ + new = build (MODIFY_EXPR, TREE_TYPE (stmt), rhs, lhs); + + /* Get an annotation and set up the real operands. */ + get_stmt_ann (new); + get_stmt_operands (new); + + /* Clear out the virtual operands on the new statement, we are + going to set them explicitly below. */ + remove_vuses (new); + remove_vdefs (new); + + start_ssa_stmt_operands (new); + /* For each VDEF on the original statement, we want to create a + VUSE of the VDEF result on the new statement. */ + for (j = 0; j < NUM_VDEFS (vdefs); j++) + { + tree op = VDEF_RESULT (vdefs, j); + add_vuse (op, new); + } + + finalize_ssa_stmt_operands (new); + + /* Finally enter the statement into the available expression + table. */ + lookup_avail_expr (new, block_avail_exprs_p, true); + } + } +} + +/* Optimize the statement pointed by iterator SI. + + We try to perform some simplistic global redundancy elimination and + constant propagation: + + 1- To detect global redundancy, we keep track of expressions that have + been computed in this block and its dominators. If we find that the + same expression is computed more than once, we eliminate repeated + computations by using the target of the first one. + + 2- Constant values and copy assignments. This is used to do very + simplistic constant and copy propagation. When a constant or copy + assignment is found, we map the value on the RHS of the assignment to + the variable in the LHS in the CONST_AND_COPIES table. */ + +static void +optimize_stmt (struct dom_walk_data *walk_data, + basic_block bb ATTRIBUTE_UNUSED, + block_stmt_iterator si) +{ + stmt_ann_t ann; + tree stmt; + vdef_optype vdefs; + bool may_optimize_p; + bool may_have_exposed_new_symbols = false; + struct dom_walk_block_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + stmt = bsi_stmt (si); + + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + vdefs = VDEF_OPS (ann); + opt_stats.num_stmts++; + may_have_exposed_new_symbols = false; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Optimizing statement "); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + } + + /* Const/copy propagate into USES, VUSES and the RHS of VDEFs. */ + may_have_exposed_new_symbols = cprop_into_stmt (stmt, const_and_copies); + + /* If the statement has been modified with constant replacements, + fold its RHS before checking for redundant computations. */ + if (ann->modified) + { + /* Try to fold the statement making sure that STMT is kept + up to date. */ + if (fold_stmt (bsi_stmt_ptr (si))) + { + stmt = bsi_stmt (si); + ann = stmt_ann (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Folded to: "); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + } + } + + /* Constant/copy propagation above may change the set of + virtual operands associated with this statement. Folding + may remove the need for some virtual operands. + + Indicate we will need to rescan and rewrite the statement. */ + may_have_exposed_new_symbols = true; + } + + /* Check for redundant computations. Do this optimization only + for assignments that have no volatile ops and conditionals. */ + may_optimize_p = (!ann->has_volatile_ops + && ((TREE_CODE (stmt) == RETURN_EXPR + && TREE_OPERAND (stmt, 0) + && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR + && ! (TREE_SIDE_EFFECTS + (TREE_OPERAND (TREE_OPERAND (stmt, 0), 1)))) + || (TREE_CODE (stmt) == MODIFY_EXPR + && ! TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1))) + || TREE_CODE (stmt) == COND_EXPR + || TREE_CODE (stmt) == SWITCH_EXPR)); + + if (may_optimize_p) + may_have_exposed_new_symbols + |= eliminate_redundant_computations (walk_data, stmt, ann); + + /* Record any additional equivalences created by this statement. */ + if (TREE_CODE (stmt) == MODIFY_EXPR) + record_equivalences_from_stmt (stmt, + &bd->avail_exprs, + &bd->nonzero_vars, + may_optimize_p, + ann); + + register_definitions_for_stmt (ann, &bd->block_defs); + + /* If STMT is a COND_EXPR and it was modified, then we may know + where it goes. If that is the case, then mark the CFG as altered. + + This will cause us to later call remove_unreachable_blocks and + cleanup_tree_cfg when it is safe to do so. It is not safe to + clean things up here since removal of edges and such can trigger + the removal of PHI nodes, which in turn can release SSA_NAMEs to + the manager. + + That's all fine and good, except that once SSA_NAMEs are released + to the manager, we must not call create_ssa_name until all references + to released SSA_NAMEs have been eliminated. + + All references to the deleted SSA_NAMEs can not be eliminated until + we remove unreachable blocks. + + We can not remove unreachable blocks until after we have completed + any queued jump threading. + + We can not complete any queued jump threads until we have taken + appropriate variables out of SSA form. Taking variables out of + SSA form can call create_ssa_name and thus we lose. + + Ultimately I suspect we're going to need to change the interface + into the SSA_NAME manager. */ + + if (ann->modified) + { + tree val = NULL; + + if (TREE_CODE (stmt) == COND_EXPR) + val = COND_EXPR_COND (stmt); + else if (TREE_CODE (stmt) == SWITCH_EXPR) + val = SWITCH_COND (stmt); + + if (val && TREE_CODE (val) == INTEGER_CST + && find_taken_edge (bb_for_stmt (stmt), val)) + cfg_altered = true; + } + + if (may_have_exposed_new_symbols) + { + if (! bd->stmts_to_rescan) + VARRAY_TREE_INIT (bd->stmts_to_rescan, 20, "stmts_to_rescan"); + VARRAY_PUSH_TREE (bd->stmts_to_rescan, bsi_stmt (si)); + } +} + +/* Replace the RHS of STMT with NEW_RHS. If RHS can be found in the + available expression hashtable, then return the LHS from the hash + table. + + If INSERT is true, then we also update the available expression + hash table to account for the changes made to STMT. */ + +static tree +update_rhs_and_lookup_avail_expr (tree stmt, tree new_rhs, + varray_type *block_avail_exprs_p, + stmt_ann_t ann, + bool insert) +{ + tree cached_lhs = NULL; + + /* Remove the old entry from the hash table. */ + if (insert) + { + struct expr_hash_elt element; + + initialize_hash_element (stmt, NULL, &element); + htab_remove_elt_with_hash (avail_exprs, &element, element.hash); + } + + /* Now update the RHS of the assignment. */ + TREE_OPERAND (stmt, 1) = new_rhs; + + /* Now lookup the updated statement in the hash table. */ + cached_lhs = lookup_avail_expr (stmt, block_avail_exprs_p, insert); + + /* We have now called lookup_avail_expr twice with two different + versions of this same statement, once in optimize_stmt, once here. + + We know the call in optimize_stmt did not find an existing entry + in the hash table, so a new entry was created. At the same time + this statement was pushed onto the BLOCK_AVAIL_EXPRS varray. + + If this call failed to find an existing entry on the hash table, + then the new version of this statement was entered into the + hash table. And this statement was pushed onto BLOCK_AVAIL_EXPR + for the second time. So there are two copies on BLOCK_AVAIL_EXPRs + + If this call succeeded, we still have one copy of this statement + on the BLOCK_AVAIL_EXPRs varray. + + For both cases, we need to pop the most recent entry off the + BLOCK_AVAIL_EXPRs varray. For the case where we never found this + statement in the hash tables, that will leave precisely one + copy of this statement on BLOCK_AVAIL_EXPRs. For the case where + we found a copy of this statement in the second hash table lookup + we want _no_ copies of this statement in BLOCK_AVAIL_EXPRs. */ + if (insert) + VARRAY_POP (*block_avail_exprs_p); + + /* And make sure we record the fact that we modified this + statement. */ + ann->modified = 1; + + return cached_lhs; +} + +/* Search for an existing instance of STMT in the AVAIL_EXPRS table. If + found, return its LHS. Otherwise insert STMT in the table and return + NULL_TREE. + + Also, when an expression is first inserted in the AVAIL_EXPRS table, it + is also added to the stack pointed by BLOCK_AVAIL_EXPRS_P, so that they + can be removed when we finish processing this block and its children. + + NOTE: This function assumes that STMT is a MODIFY_EXPR node that + contains no CALL_EXPR on its RHS and makes no volatile nor + aliased references. */ + +static tree +lookup_avail_expr (tree stmt, varray_type *block_avail_exprs_p, bool insert) +{ + void **slot; + tree lhs; + tree temp; + struct expr_hash_elt *element = xcalloc (sizeof (struct expr_hash_elt), 1); + + lhs = TREE_CODE (stmt) == MODIFY_EXPR ? TREE_OPERAND (stmt, 0) : NULL; + + initialize_hash_element (stmt, lhs, element); + + /* Don't bother remembering constant assignments and copy operations. + Constants and copy operations are handled by the constant/copy propagator + in optimize_stmt. */ + if (TREE_CODE (element->rhs) == SSA_NAME + || is_gimple_min_invariant (element->rhs)) + { + free (element); + return NULL_TREE; + } + + /* If this is an equality test against zero, see if we have recorded a + nonzero value for the variable in question. */ + if ((TREE_CODE (element->rhs) == EQ_EXPR + || TREE_CODE (element->rhs) == NE_EXPR) + && TREE_CODE (TREE_OPERAND (element->rhs, 0)) == SSA_NAME + && integer_zerop (TREE_OPERAND (element->rhs, 1))) + { + int indx = SSA_NAME_VERSION (TREE_OPERAND (element->rhs, 0)); + + if (bitmap_bit_p (nonzero_vars, indx)) + { + tree t = element->rhs; + free (element); + + if (TREE_CODE (t) == EQ_EXPR) + return boolean_false_node; + else + return boolean_true_node; + } + } + + /* Finally try to find the expression in the main expression hash table. */ + slot = htab_find_slot_with_hash (avail_exprs, element, element->hash, + (insert ? INSERT : NO_INSERT)); + if (slot == NULL) + { + free (element); + return NULL_TREE; + } + + if (*slot == NULL) + { + *slot = (void *) element; + if (! *block_avail_exprs_p) + VARRAY_TREE_INIT (*block_avail_exprs_p, 20, "block_avail_exprs"); + VARRAY_PUSH_TREE (*block_avail_exprs_p, stmt ? stmt : element->rhs); + return NULL_TREE; + } + + /* Extract the LHS of the assignment so that it can be used as the current + definition of another variable. */ + lhs = ((struct expr_hash_elt *)*slot)->lhs; + + /* See if the LHS appears in the CONST_AND_COPIES table. If it does, then + use the value from the const_and_copies table. */ + if (TREE_CODE (lhs) == SSA_NAME) + { + temp = get_value_for (lhs, const_and_copies); + if (temp) + lhs = temp; + } + + free (element); + return lhs; +} + +/* Given a condition COND, record into HI_P, LO_P and INVERTED_P the + range of values that result in the conditional having a true value. + + Return true if we are successful in extracting a range from COND and + false if we are unsuccessful. */ + +static bool +extract_range_from_cond (tree cond, tree *hi_p, tree *lo_p, int *inverted_p) +{ + tree op1 = TREE_OPERAND (cond, 1); + tree high, low, type; + int inverted; + + /* Experiments have shown that it's rarely, if ever useful to + record ranges for enumerations. Presumably this is due to + the fact that they're rarely used directly. They are typically + cast into an integer type and used that way. */ + if (TREE_CODE (TREE_TYPE (op1)) != INTEGER_TYPE) + return 0; + + type = TREE_TYPE (op1); + + switch (TREE_CODE (cond)) + { + case EQ_EXPR: + high = low = op1; + inverted = 0; + break; + + case NE_EXPR: + high = low = op1; + inverted = 1; + break; + + case GE_EXPR: + low = op1; + high = TYPE_MAX_VALUE (type); + inverted = 0; + break; + + case GT_EXPR: + low = int_const_binop (PLUS_EXPR, op1, integer_one_node, 1); + high = TYPE_MAX_VALUE (type); + inverted = 0; + break; + + case LE_EXPR: + high = op1; + low = TYPE_MIN_VALUE (type); + inverted = 0; + break; + + case LT_EXPR: + high = int_const_binop (MINUS_EXPR, op1, integer_one_node, 1); + low = TYPE_MIN_VALUE (type); + inverted = 0; + break; + + default: + return 0; + } + + *hi_p = high; + *lo_p = low; + *inverted_p = inverted; + return 1; +} + +/* Record a range created by COND for basic block BB. */ + +static void +record_range (tree cond, basic_block bb, varray_type *vrp_variables_p) +{ + /* We explicitly ignore NE_EXPRs. They rarely allow for meaningful + range optimizations and significantly complicate the implementation. */ + if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<' + && TREE_CODE (cond) != NE_EXPR + && TREE_CODE (TREE_TYPE (TREE_OPERAND (cond, 1))) == INTEGER_TYPE) + { + struct vrp_element *element = ggc_alloc (sizeof (struct vrp_element)); + int ssa_version = SSA_NAME_VERSION (TREE_OPERAND (cond, 0)); + + varray_type *vrp_records_p + = (varray_type *)&VARRAY_GENERIC_PTR (vrp_data, ssa_version); + + element->low = NULL; + element->high = NULL; + element->cond = cond; + element->bb = bb; + + if (*vrp_records_p == NULL) + { + VARRAY_GENERIC_PTR_INIT (*vrp_records_p, 2, "vrp records"); + VARRAY_GENERIC_PTR (vrp_data, ssa_version) = *vrp_records_p; + } + + VARRAY_PUSH_GENERIC_PTR (*vrp_records_p, element); + if (! *vrp_variables_p) + VARRAY_TREE_INIT (*vrp_variables_p, 2, "vrp_variables"); + VARRAY_PUSH_TREE (*vrp_variables_p, TREE_OPERAND (cond, 0)); + } +} + +/* Given a conditional statement IF_STMT, return the assignment 'X = Y' + known to be true depending on which arm of IF_STMT is taken. + + Not all conditional statements will result in a useful assignment. + Return NULL_TREE in that case. + + Also enter into the available expression table statements of + the form: + + TRUE ARM FALSE ARM + 1 = cond 1 = cond' + 0 = cond' 0 = cond + + This allows us to lookup the condition in a dominated block and + get back a constant indicating if the condition is true. */ + +static struct eq_expr_value +get_eq_expr_value (tree if_stmt, + int true_arm, + varray_type *block_avail_exprs_p, + basic_block bb, + varray_type *vrp_variables_p) +{ + tree cond; + struct eq_expr_value retval; + + cond = COND_EXPR_COND (if_stmt); + retval.src = NULL; + retval.dst = NULL; + + /* If the conditional is a single variable 'X', return 'X = 1' for + the true arm and 'X = 0' on the false arm. */ + if (TREE_CODE (cond) == SSA_NAME) + { + retval.dst = cond; + retval.src = (true_arm ? integer_one_node : integer_zero_node); + return retval; + } + + /* If we have a comparison expression, then record its result into + the available expression table. */ + if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<') + { + tree op0 = TREE_OPERAND (cond, 0); + tree op1 = TREE_OPERAND (cond, 1); + + /* Special case comparing booleans against a constant as we know + the value of OP0 on both arms of the branch. ie, we can record + an equivalence for OP0 rather than COND. */ + if ((TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR) + && TREE_CODE (op0) == SSA_NAME + && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE + && is_gimple_min_invariant (op1)) + { + if ((TREE_CODE (cond) == EQ_EXPR && true_arm) + || (TREE_CODE (cond) == NE_EXPR && ! true_arm)) + { + retval.src = op1; + } + else + { + if (integer_zerop (op1)) + retval.src = boolean_true_node; + else + retval.src = boolean_false_node; + } + retval.dst = op0; + return retval; + } + + if (TREE_CODE (op0) == SSA_NAME + && (is_gimple_min_invariant (op1) || TREE_CODE (op1) == SSA_NAME)) + { + tree inverted = invert_truthvalue (cond); + + /* When we find an available expression in the hash table, we replace + the expression with the LHS of the statement in the hash table. + + So, we want to build statements such as "1 = " on the + true arm and "0 = " on the false arm. That way if we + find the expression in the table, we will replace it with its + known constant value. Also insert inversions of the result and + condition into the hash table. */ + if (true_arm) + { + record_cond (cond, boolean_true_node, block_avail_exprs_p); + record_cond (inverted, boolean_false_node, block_avail_exprs_p); + + if (TREE_CONSTANT (op1)) + record_range (cond, bb, vrp_variables_p); + + /* If the conditional is of the form 'X == Y', return 'X = Y' + for the true arm. */ + if (TREE_CODE (cond) == EQ_EXPR) + { + retval.dst = op0; + retval.src = op1; + return retval; + } + } + else + { + + record_cond (inverted, boolean_true_node, block_avail_exprs_p); + record_cond (cond, boolean_false_node, block_avail_exprs_p); + + if (TREE_CONSTANT (op1)) + record_range (inverted, bb, vrp_variables_p); + + /* If the conditional is of the form 'X != Y', return 'X = Y' + for the false arm. */ + if (TREE_CODE (cond) == NE_EXPR) + { + retval.dst = op0; + retval.src = op1; + return retval; + } + } + } + } + + return retval; +} + +/* Hashing and equality functions for AVAIL_EXPRS. The table stores + MODIFY_EXPR statements. We compute a value number for expressions using + the code of the expression and the SSA numbers of its operands. */ + +static hashval_t +avail_expr_hash (const void *p) +{ + stmt_ann_t ann = ((struct expr_hash_elt *)p)->ann; + tree rhs = ((struct expr_hash_elt *)p)->rhs; + hashval_t val = 0; + size_t i; + vuse_optype vuses; + + /* iterative_hash_expr knows how to deal with any expression and + deals with commutative operators as well, so just use it instead + of duplicating such complexities here. */ + val = iterative_hash_expr (rhs, val); + + /* If the hash table entry is not associated with a statement, then we + can just hash the expression and not worry about virtual operands + and such. */ + if (!ann) + return val; + + /* Add the SSA version numbers of every vuse operand. This is important + because compound variables like arrays are not renamed in the + operands. Rather, the rename is done on the virtual variable + representing all the elements of the array. */ + vuses = VUSE_OPS (ann); + for (i = 0; i < NUM_VUSES (vuses); i++) + val = iterative_hash_expr (VUSE_OP (vuses, i), val); + + return val; +} + + +static int +avail_expr_eq (const void *p1, const void *p2) +{ + stmt_ann_t ann1 = ((struct expr_hash_elt *)p1)->ann; + tree rhs1 = ((struct expr_hash_elt *)p1)->rhs; + stmt_ann_t ann2 = ((struct expr_hash_elt *)p2)->ann; + tree rhs2 = ((struct expr_hash_elt *)p2)->rhs; + + /* If they are the same physical expression, return true. */ + if (rhs1 == rhs2 && ann1 == ann2) + return true; + + /* If their codes are not equal, then quit now. */ + if (TREE_CODE (rhs1) != TREE_CODE (rhs2)) + return false; + + /* In case of a collision, both RHS have to be identical and have the + same VUSE operands. */ + if ((TREE_TYPE (rhs1) == TREE_TYPE (rhs2) + || lang_hooks.types_compatible_p (TREE_TYPE (rhs1), TREE_TYPE (rhs2))) + && operand_equal_p (rhs1, rhs2, OEP_PURE_SAME)) + { + vuse_optype ops1 = NULL; + vuse_optype ops2 = NULL; + size_t num_ops1 = 0; + size_t num_ops2 = 0; + size_t i; + + if (ann1) + { + ops1 = VUSE_OPS (ann1); + num_ops1 = NUM_VUSES (ops1); + } + + if (ann2) + { + ops2 = VUSE_OPS (ann2); + num_ops2 = NUM_VUSES (ops2); + } + + /* If the number of virtual uses is different, then we consider + them not equal. */ + if (num_ops1 != num_ops2) + return false; + + for (i = 0; i < num_ops1; i++) + if (VUSE_OP (ops1, i) != VUSE_OP (ops2, i)) + return false; + +#ifdef ENABLE_CHECKING + if (((struct expr_hash_elt *)p1)->hash + != ((struct expr_hash_elt *)p2)->hash) + abort (); +#endif + return true; + } + + return false; +} + +/* Given STMT and a pointer to the block local defintions BLOCK_DEFS_P, + register register all objects set by this statement into BLOCK_DEFS_P + and CURRDEFS. */ + +static void +register_definitions_for_stmt (stmt_ann_t ann, varray_type *block_defs_p) +{ + def_optype defs; + vdef_optype vdefs; + unsigned int i; + + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree def = DEF_OP (defs, i); + + /* FIXME: We shouldn't be registering new defs if the variable + doesn't need to be renamed. */ + register_new_def (def, block_defs_p); + } + + /* Register new virtual definitions made by the statement. */ + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + /* FIXME: We shouldn't be registering new defs if the variable + doesn't need to be renamed. */ + register_new_def (VDEF_RESULT (vdefs, i), block_defs_p); + } +} + diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c new file mode 100644 index 00000000000..fca08ac6519 --- /dev/null +++ b/gcc/tree-ssa-dse.c @@ -0,0 +1,445 @@ +/* Dead store elimination + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "basic-block.h" +#include "timevar.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "tree-dump.h" +#include "domwalk.h" +#include "flags.h" + +/* This file implements dead store elimination. + + A dead store is a store into a memory location which will later be + overwritten by another store without any intervening loads. In this + case the earlier store can be deleted. + + In our SSA + virtual operand world we use immediate uses of virtual + operands to detect dead stores. If a store's virtual definition + is used precisely once by a later store to the same location which + post dominates the first store, then the first store is dead. + + The single use of the store's virtual definition ensures that + there are no intervening aliased loads and the requirement that + the second load post dominate the first ensures that if the earlier + store executes, then the later stores will execute before the function + exits. + + It may help to think of this as first moving the earlier store to + the point immediately before the later store. Again, the single + use of the virtual defintion and the post-dominance relationship + ensure that such movement would be safe. Clearly if there are + back to back stores, then the second is redundant. + + Reviewing section 10.7.2 in Morgan's "Building an Optimizing Compiler" + may also help in understanding this code since it discusses the + relationship between dead store and redundant load elimination. In + fact, they are the same transformation applied to different views of + the CFG. */ + + +struct dse_global_data +{ + /* This is the global bitmap for store statements. + + Each statement has a unique ID. When we encounter a store statement + that we want to record, set the bit corresponding to the statement's + unique ID in this bitmap. */ + bitmap stores; +}; + +/* We allocate a bitmap-per-block for stores which are encountered + during the scan of that block. This allows us to restore the + global bitmap of stores when we finish processing a block. */ +struct dse_block_local_data +{ + bitmap stores; +}; + +static bool gate_dse (void); +static void tree_ssa_dse (void); +static void dse_initialize_block_local_data (struct dom_walk_data *, + basic_block, + bool); +static void dse_optimize_stmt (struct dom_walk_data *, + basic_block, + block_stmt_iterator); +static void dse_record_phis (struct dom_walk_data *, basic_block); +static void dse_finalize_block (struct dom_walk_data *, basic_block); +static void fix_phi_uses (tree, tree); +static void fix_stmt_vdefs (tree, tree); +static void record_voperand_set (bitmap, bitmap *, unsigned int); + +/* Function indicating whether we ought to include information for 'var' + when calculating immediate uses. For this pass we only want use + information for virtual variables. */ + +static bool +need_imm_uses_for (tree var) +{ + return !is_gimple_reg (var); +} + + +/* Replace uses in PHI which match VDEF_RESULTs in STMT with the + corresponding VDEF_OP in STMT. */ + +static void +fix_phi_uses (tree phi, tree stmt) +{ + stmt_ann_t ann = stmt_ann (stmt); + vdef_optype vdefs; + unsigned int i; + int j; + + get_stmt_operands (stmt); + vdefs = VDEF_OPS (ann); + + /* Walk each VDEF in STMT. */ + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + tree vdef = VDEF_RESULT (vdefs, i); + + /* Find any uses in the PHI which match VDEF and replace + them with the appropriate VDEF_OP. */ + for (j = 0; j < PHI_NUM_ARGS (phi); j++) + if (vdef == PHI_ARG_DEF (phi, j)) + PHI_ARG_DEF (phi, j) = VDEF_OP (vdefs, i); + } +} + +/* Replace the VDEF_OPs in STMT1 which match VDEF_RESULTs in STMT2 with + the appropriate VDEF_OPs from STMT2. */ + +static void +fix_stmt_vdefs (tree stmt1, tree stmt2) +{ + stmt_ann_t ann1 = stmt_ann (stmt1); + stmt_ann_t ann2 = stmt_ann (stmt2); + vdef_optype vdefs1; + vdef_optype vdefs2; + unsigned int i, j; + + get_stmt_operands (stmt1); + get_stmt_operands (stmt2); + vdefs1 = VDEF_OPS (ann1); + vdefs2 = VDEF_OPS (ann2); + + /* Walk each VDEF_OP in stmt1. */ + for (i = 0; i < NUM_VDEFS (vdefs1); i++) + { + tree vdef1 = VDEF_OP (vdefs1, i); + + /* Find the appropriate VDEF_RESULT in STMT2. */ + for (j = 0; j < NUM_VDEFS (vdefs2); j++) + { + if (vdef1 == VDEF_RESULT (vdefs2, j)) + { + /* Update. */ + *VDEF_OP_PTR (vdefs1, i) = VDEF_OP (vdefs2, j); + break; + } + } + +#ifdef ENABLE_CHECKING + /* If we did not find a corresponding VDEF_RESULT, then something + has gone terribly wrong. */ + if (j == NUM_VDEFS (vdefs2)) + abort (); +#endif + + } +} + + +/* Set bit UID in bitmaps GLOBAL and *LOCAL, creating *LOCAL as needed. */ +static void +record_voperand_set (bitmap global, bitmap *local, unsigned int uid) +{ + /* Lazily allocate the bitmap. Note that we do not get a notification + when the block local data structures die, so we allocate the local + bitmap backed by the GC system. */ + if (*local == NULL) + *local = BITMAP_GGC_ALLOC (); + + /* Set the bit in the local and global bitmaps. */ + bitmap_set_bit (*local, uid); + bitmap_set_bit (global, uid); +} +/* Initialize block local data structures. */ + +static void +dse_initialize_block_local_data (struct dom_walk_data *walk_data, + basic_block bb ATTRIBUTE_UNUSED, + bool recycled) +{ + struct dse_block_local_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + + /* If we are given a recycled block local data structure, ensure any + bitmap associated with the block is cleared. */ + if (recycled) + { + if (bd->stores) + bitmap_clear (bd->stores); + } +} + +/* Attempt to eliminate dead stores in the statement referenced by BSI. + + A dead store is a store into a memory location which will later be + overwritten by another store without any intervening loads. In this + case the earlier store can be deleted. + + In our SSA + virtual operand world we use immediate uses of virtual + operands to detect dead stores. If a store's virtual definition + is used precisely once by a later store to the same location which + post dominates the first store, then the first store is dead. */ + +static void +dse_optimize_stmt (struct dom_walk_data *walk_data, + basic_block bb ATTRIBUTE_UNUSED, + block_stmt_iterator bsi) +{ + struct dse_block_local_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + struct dse_global_data *dse_gd = walk_data->global_data; + tree stmt = bsi_stmt (bsi); + stmt_ann_t ann = stmt_ann (stmt); + vdef_optype vdefs; + + get_stmt_operands (stmt); + vdefs = VDEF_OPS (ann); + + /* If this statement has no virtual uses, then there is nothing + to do. */ + if (NUM_VDEFS (vdefs) == 0) + return; + + /* We know we have virtual definitions. If this is a MODIFY_EXPR, then + record it into our table. */ + if (TREE_CODE (stmt) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (stmt, 1)) != CALL_EXPR) + { + dataflow_t df = get_immediate_uses (stmt); + unsigned int num_uses = num_immediate_uses (df); + tree use; + tree skipped_phi; + + + /* If there are no uses then there is nothing left to do. */ + if (num_uses == 0) + { + record_voperand_set (dse_gd->stores, &bd->stores, ann->uid); + return; + } + + use = immediate_use (df, 0); + skipped_phi = NULL; + + /* Skip through any PHI nodes we have already seen if the PHI + represents the only use of this store. + + Note this does not handle the case where the store has + multiple VDEFs which all reach a set of PHI nodes in the + same block. */ + while (num_uses == 1 + && TREE_CODE (use) == PHI_NODE + && bitmap_bit_p (dse_gd->stores, stmt_ann (use)->uid)) + { + /* Record the first PHI we skip so that we can fix its + uses if we find that STMT is a dead store. */ + if (!skipped_phi) + skipped_phi = use; + + /* Skip past this PHI and loop again in case we had a PHI + chain. */ + df = get_immediate_uses (use); + num_uses = num_immediate_uses (df); + use = immediate_use (df, 0); + } + + /* If we have precisely one immediate use at this point, then we may + have found redundant store. */ + if (num_uses == 1 + && bitmap_bit_p (dse_gd->stores, stmt_ann (use)->uid) + && operand_equal_p (TREE_OPERAND (stmt, 0), + TREE_OPERAND (use, 0), 0)) + { + /* We need to fix the operands if either the first PHI we + skipped, or the store which we are not deleting if we did + not skip any PHIs. */ + if (skipped_phi) + fix_phi_uses (skipped_phi, stmt); + else + fix_stmt_vdefs (use, stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Deleted dead store '"); + print_generic_expr (dump_file, bsi_stmt (bsi), dump_flags); + fprintf (dump_file, "'\n"); + } + + /* Any immediate uses which reference STMT need to instead + reference the new consumer, either SKIPPED_PHI or USE. + This allows us to cascade dead stores. */ + redirect_immediate_uses (stmt, skipped_phi ? skipped_phi : use); + + /* Finally remove the dead store. */ + bsi_remove (&bsi); + } + + record_voperand_set (dse_gd->stores, &bd->stores, ann->uid); + } +} + +/* Record that we have seen the PHIs at the start of BB which correspond + to virtual operands. */ +static void +dse_record_phis (struct dom_walk_data *walk_data, basic_block bb) +{ + struct dse_block_local_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + struct dse_global_data *dse_gd = walk_data->global_data; + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + if (need_imm_uses_for (PHI_RESULT (phi))) + record_voperand_set (dse_gd->stores, + &bd->stores, + get_stmt_ann (phi)->uid); +} + +static void +dse_finalize_block (struct dom_walk_data *walk_data, + basic_block bb ATTRIBUTE_UNUSED) +{ + struct dse_block_local_data *bd + = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack); + struct dse_global_data *dse_gd = walk_data->global_data; + bitmap stores = dse_gd->stores; + unsigned int i; + + /* Unwind the stores noted in this basic block. */ + if (bd->stores) + EXECUTE_IF_SET_IN_BITMAP (bd->stores, 0, i, bitmap_clear_bit (stores, i);); +} + +static void +tree_ssa_dse (void) +{ + struct dom_walk_data walk_data; + struct dse_global_data dse_gd; + unsigned int uid = 0; + basic_block bb; + + /* Create a UID for each statement in the function. Ordering of the + UIDs is not important for this pass. */ + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + tree phi; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + stmt_ann (bsi_stmt (bsi))->uid = uid++; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + stmt_ann (phi)->uid = uid++; + } + + /* We might consider making this a property of each pass so that it + can be [re]computed on an as-needed basis. Particularly since + this pass could be seen as an extension of DCE which needs post + dominators. */ + calculate_dominance_info (CDI_POST_DOMINATORS); + + /* We also need immediate use information for virtual operands. */ + compute_immediate_uses (TDFA_USE_VOPS, need_imm_uses_for); + + /* Dead store elimination is fundamentally a walk of the post-dominator + tree and a backwards walk of statements within each block. */ + walk_data.walk_stmts_backward = true; + walk_data.dom_direction = CDI_POST_DOMINATORS; + walk_data.initialize_block_local_data = dse_initialize_block_local_data; + walk_data.before_dom_children_before_stmts = NULL; + walk_data.before_dom_children_walk_stmts = dse_optimize_stmt; + walk_data.before_dom_children_after_stmts = dse_record_phis; + walk_data.after_dom_children_before_stmts = NULL; + walk_data.after_dom_children_walk_stmts = NULL; + walk_data.after_dom_children_after_stmts = dse_finalize_block; + + walk_data.block_local_data_size = sizeof (struct dse_block_local_data); + + /* This is the main hash table for the dead store elimination pass. */ + dse_gd.stores = BITMAP_XMALLOC (); + walk_data.global_data = &dse_gd; + + /* Initialize the dominator walker. */ + init_walk_dominator_tree (&walk_data); + + /* Recursively walk the dominator tree. */ + walk_dominator_tree (&walk_data, EXIT_BLOCK_PTR); + + /* Finalize the dominator walker. */ + fini_walk_dominator_tree (&walk_data); + + /* Release the main bitmap. */ + BITMAP_XFREE (dse_gd.stores); + + /* Free dataflow information. It's probably out of date now anyway. */ + free_df (); + + /* For now, just wipe the post-dominator information. */ + free_dominance_info (CDI_POST_DOMINATORS); +} + +static bool +gate_dse (void) +{ + return flag_tree_dse != 0; +} + +struct tree_opt_pass pass_dse = { + "dse", /* name */ + gate_dse, /* gate */ + tree_ssa_dse, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_DSE, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ + | TODO_verify_ssa +}; diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c new file mode 100644 index 00000000000..c50e879e975 --- /dev/null +++ b/gcc/tree-ssa-forwprop.c @@ -0,0 +1,445 @@ +/* Forward propagation of single use variables. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "basic-block.h" +#include "timevar.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "tree-dump.h" + +/* This pass performs simple forward propagation of single use variables + from their definition site into their single use site. + + Right now we only bother forward propagating into COND_EXPRs since those + are relatively common cases where forward propagation creates valid + gimple code without the expression needing to fold. ie + + bb0: + x = a COND b; + if (x) goto ... else goto ... + + Will be transformed into: + + bb0: + if (a COND b) goto ... else goto ... + + Similarly for the tests (x == 0), (x != 0), (x == 1) and (x != 1). + + Or (assuming c1 and c2 are constants): + + bb0: + x = a + c1; + if (x EQ/NEQ c2) goto ... else goto ... + + Will be transformed into: + + bb0: + if (a EQ/NEQ (c2 - c1)) goto ... else goto ... + + Similarly for x = a - c1. + + Or + + bb0: + x = !a + if (x) goto ... else goto ... + + Will be transformed into: + + bb0: + if (a == 0) goto ... else goto ... + + Similarly for the tests (x == 0), (x != 0), (x == 1) and (x != 1). + For these cases, we propagate A into all, possibly more than one, + COND_EXPRs that use X. + + In addition to eliminating the variable and the statement which assigns + a value to the variable, we may be able to later thread the jump without + adding insane complexity in the dominator optimizer. + + This will (of course) be extended as other needs arise. */ + +/* Bitmap of variables for which we want immediate uses. This is set + by record_single_argument_cond_exprs and tested in need_imm_uses_for. */ +static bitmap vars; + +static bool need_imm_uses_for (tree); +static void tree_ssa_forward_propagate_single_use_vars (void); +static varray_type record_single_argument_cond_exprs (void); +static void substitute_single_use_vars (varray_type); + +/* Function indicating whether we ought to include information for 'var' + when calculating immediate uses. */ + +static bool +need_imm_uses_for (tree var) +{ + return bitmap_bit_p (vars, SSA_NAME_VERSION (var)); +} + +/* Find all COND_EXPRs with a condition that is a naked SSA_NAME or + an equality comparison against a constant. + + Record the identified COND_EXPRs and the SSA_NAME used in the COND_EXPR + into a virtual array, which is returned to the caller. Also record + into VARS that we will need immediate uses for the identified SSA_NAME. + + The more uninteresting COND_EXPRs and associated SSA_NAMEs we can + filter out here, the faster this pass will run since its runtime is + dominated by the time to build immediate uses. */ + +static varray_type +record_single_argument_cond_exprs (void) +{ + basic_block bb; + varray_type retval; + + vars = BITMAP_XMALLOC (); + + VARRAY_TREE_INIT (retval, 10, "forward propagation vars"); + + /* The first pass over the blocks gathers the set of variables we need + immediate uses for as well as the set of interesting COND_EXPRs. + + A simpler implementation may be appropriate if/when we have a lower + overhead means of getting immediate use information. */ + FOR_EACH_BB (bb) + { + tree last = last_stmt (bb); + + /* See if this block ends in a COND_EXPR. */ + if (last && TREE_CODE (last) == COND_EXPR) + { + tree cond = COND_EXPR_COND (last); + enum tree_code cond_code = TREE_CODE (cond); + + /* If the condition is a lone variable or an equality test of + an SSA_NAME against an integral constant, then we may have an + optimizable case. + + Note these conditions also ensure the COND_EXPR has no + virtual operands or other side effects. */ + if (cond_code == SSA_NAME + || ((cond_code == EQ_EXPR || cond_code == NE_EXPR) + && TREE_CODE (TREE_OPERAND (cond, 0)) == SSA_NAME + && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (cond, 1))) == 'c' + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (cond, 1))))) + { + tree def; + tree test_var; + + /* Extract the single variable used in the test into TEST_VAR. */ + if (cond_code == SSA_NAME) + test_var = cond; + else + test_var = TREE_OPERAND (cond, 0); + + /* If we have already recorded this SSA_NAME as interesting, + do not do so again. */ + if (bitmap_bit_p (vars, SSA_NAME_VERSION (test_var))) + continue; + + /* Now get the defining statement for TEST_VAR and see if it + something we are interested in. */ + def = SSA_NAME_DEF_STMT (test_var); + if (TREE_CODE (def) == MODIFY_EXPR) + { + tree def_rhs = TREE_OPERAND (def, 1); + + /* If TEST_VAR is set by adding or subtracting a constant + from an SSA_NAME, then it is interesting to us as we + can adjust the constant in the conditional and thus + eliminate the arithmetic operation. */ + if (TREE_CODE (def_rhs) == PLUS_EXPR + || TREE_CODE (def_rhs) == MINUS_EXPR) + { + tree op0 = TREE_OPERAND (def_rhs, 0); + tree op1 = TREE_OPERAND (def_rhs, 1); + + /* The first operand must be an SSA_NAME and the second + operand must be a constant. */ + if (TREE_CODE (op0) != SSA_NAME + || TREE_CODE_CLASS (TREE_CODE (op1)) != 'c' + || !INTEGRAL_TYPE_P (TREE_TYPE (op1))) + continue; + } + + /* These cases require comparisons of a naked SSA_NAME or + comparison of an SSA_NAME against zero or one. */ + else if (TREE_CODE (cond) == SSA_NAME + || integer_zerop (TREE_OPERAND (cond, 1)) + || integer_onep (TREE_OPERAND (cond, 1))) + { + /* If TEST_VAR is set from a relational operation + between two SSA_NAMEs or a combination of an SSA_NAME + and a constant, then it is interesting. */ + if (TREE_CODE_CLASS (TREE_CODE (def_rhs)) == '<') + { + tree op0 = TREE_OPERAND (def_rhs, 0); + tree op1 = TREE_OPERAND (def_rhs, 1); + + /* Both operands of DEF_RHS must be SSA_NAMEs or + constants. */ + if ((TREE_CODE (op0) != SSA_NAME + && !is_gimple_min_invariant (op0)) + || (TREE_CODE (op1) != SSA_NAME + && !is_gimple_min_invariant (op1))) + continue; + } + + /* If TEST_VAR is set from a TRUTH_NOT_EXPR, then it + is interesting. */ + else if (TREE_CODE (def_rhs) == TRUTH_NOT_EXPR) + { + def_rhs = TREE_OPERAND (def_rhs, 0); + + /* DEF_RHS must be an SSA_NAME or constant. */ + if (TREE_CODE (def_rhs) != SSA_NAME + && !is_gimple_min_invariant (def_rhs)) + continue; + } + else + continue; + } + else + continue; + + /* All the tests passed, record TEST_VAR as interesting. */ + VARRAY_PUSH_TREE (retval, test_var); + bitmap_set_bit (vars, SSA_NAME_VERSION (test_var)); + } + } + } + } + return retval; +} + +/* Given FORWPROP_DATA containing SSA_NAMEs which are used in COND_EXPRs + that we may be able to optimize, attempt to rewrite the condition + in each COND_EXPR to use the RHS of the statement which defines the + SSA_NAME used in the COND_EXPR. */ + +static void +substitute_single_use_vars (varray_type forwprop_data) +{ + unsigned int i; + + for (i = 0; i < VARRAY_ACTIVE_SIZE (forwprop_data); i++) + { + tree test_var = VARRAY_TREE (forwprop_data, i); + tree def = SSA_NAME_DEF_STMT (test_var); + dataflow_t df; + int j, num_uses, propagated_uses; + block_stmt_iterator bsi; + + /* Now compute the immediate uses of TEST_VAR. */ + df = get_immediate_uses (def); + num_uses = num_immediate_uses (df); + propagated_uses = 0; + + /* If TEST_VAR is used more than once and is not a boolean set + via TRUTH_NOT_EXPR with another SSA_NAME as its argument, then + we can not optimize. */ + if (num_uses == 1 + || (TREE_CODE (TREE_TYPE (test_var)) == BOOLEAN_TYPE + && TREE_CODE (TREE_OPERAND (def, 1)) == TRUTH_NOT_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (def, 1), 0)) + == SSA_NAME))) + ; + else + continue; + + /* Walk over each use and try to forward propagate the RHS of + DEF into the use. */ + for (j = 0; j < num_uses; j++) + { + tree cond_stmt; + tree cond; + enum tree_code cond_code; + tree def_rhs; + enum tree_code def_rhs_code; + tree new_cond; + + cond_stmt = immediate_use (df, j); + + /* For now we can only propagate into COND_EXPRs. */ + if (TREE_CODE (cond_stmt) != COND_EXPR) + continue; + + cond = COND_EXPR_COND (cond_stmt); + cond_code = TREE_CODE (cond); + def_rhs = TREE_OPERAND (def, 1); + def_rhs_code = TREE_CODE (def_rhs); + + /* If the definition of the single use variable was from an + arithmetic operation, then we just need to adjust the + constant in the COND_EXPR_COND and update the variable tested. */ + if (def_rhs_code == PLUS_EXPR || def_rhs_code == MINUS_EXPR) + { + tree op0 = TREE_OPERAND (def_rhs, 0); + tree op1 = TREE_OPERAND (def_rhs, 1); + enum tree_code new_code; + tree t; + + /* If the variable was defined via X + C, then we must subtract + C from the constant in the conditional. Otherwise we add + C to the constant in the conditional. The result must fold + into a valid gimple operand to be optimizable. */ + new_code = def_rhs_code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR; + t = int_const_binop (new_code, TREE_OPERAND (cond, 1), op1, 0); + if (!is_gimple_val (t)) + continue; + + new_cond = build (cond_code, boolean_type_node, op0, t); + } + /* If the variable is defined by a conditional expression... */ + else if (TREE_CODE_CLASS (def_rhs_code) == '<') + { + /* TEST_VAR was set from a relational operator. */ + tree op0 = TREE_OPERAND (def_rhs, 0); + tree op1 = TREE_OPERAND (def_rhs, 1); + + new_cond = build (def_rhs_code, boolean_type_node, op0, op1); + + /* Invert the conditional if necessary. */ + if ((cond_code == EQ_EXPR + && integer_zerop (TREE_OPERAND (cond, 1))) + || (cond_code == NE_EXPR + && integer_onep (TREE_OPERAND (cond, 1)))) + { + new_cond = invert_truthvalue (new_cond); + + /* If we did not get a simple relational expression or + bare SSA_NAME, then we can not optimize this case. */ + if (TREE_CODE_CLASS (TREE_CODE (new_cond)) != '<' + && TREE_CODE (new_cond) != SSA_NAME) + continue; + } + } + else + { + /* TEST_VAR was set from a TRUTH_NOT_EXPR. */ + if (cond_code == SSA_NAME + || (cond_code == NE_EXPR + && integer_zerop (TREE_OPERAND (cond, 1))) + || (cond_code == EQ_EXPR + && integer_onep (TREE_OPERAND (cond, 1)))) + new_cond = build (EQ_EXPR, boolean_type_node, + TREE_OPERAND (def_rhs, 0), + convert (TREE_TYPE (def_rhs), + integer_zero_node)); + else + new_cond = build (NE_EXPR, boolean_type_node, + TREE_OPERAND (def_rhs, 0), + convert (TREE_TYPE (def_rhs), + integer_zero_node)); + } + + /* Dump details. */ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Replaced '"); + print_generic_expr (dump_file, cond, dump_flags); + fprintf (dump_file, "' with '"); + print_generic_expr (dump_file, new_cond, dump_flags); + fprintf (dump_file, "'\n"); + } + + /* Replace the condition. */ + COND_EXPR_COND (cond_stmt) = new_cond; + modify_stmt (cond_stmt); + propagated_uses++; + } + + /* If we propagated into all the uses, then we can delete DEF. + Unfortunately, we have to find the defining statement in + whatever block it might be in. */ + if (num_uses && num_uses == propagated_uses) + for (bsi = bsi_start (bb_for_stmt (def)); + !bsi_end_p (bsi); + bsi_next (&bsi)) + { + if (def == bsi_stmt (bsi)) + { + bsi_remove (&bsi); + break; + } + } + } +} + +/* Main entry point for the forward propagation optimizer. */ + +static void +tree_ssa_forward_propagate_single_use_vars (void) +{ + varray_type forwprop_data; + + /* First get a list of all the interesting COND_EXPRs and potential single + use variables which feed those COND_EXPRs. */ + forwprop_data = record_single_argument_cond_exprs (); + + /* Now compute immediate uses for all the variables we care about. */ + compute_immediate_uses (TDFA_USE_OPS, need_imm_uses_for); + + /* We are done with the VARS bitmap and other dataflow information. */ + BITMAP_XFREE (vars); + vars = NULL; + + /* And optimize. */ + substitute_single_use_vars (forwprop_data); + + /* All done. Clean up. */ + free_df (); + VARRAY_CLEAR (forwprop_data); +} + + +static bool +gate_forwprop (void) +{ + return 1; +} + +struct tree_opt_pass pass_forwprop = { + "forwprop", /* name */ + gate_forwprop, /* gate */ + tree_ssa_forward_propagate_single_use_vars, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_FORWPROP, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ + | TODO_verify_ssa +}; diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c new file mode 100644 index 00000000000..931ec780279 --- /dev/null +++ b/gcc/tree-ssa-live.c @@ -0,0 +1,1912 @@ +/* Liveness for SSA trees. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "basic-block.h" +#include "function.h" +#include "diagnostic.h" +#include "bitmap.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "varray.h" +#include "timevar.h" +#include "tree-alias-common.h" +#include "hashtab.h" +#include "tree-dump.h" +#include "tree-ssa-live.h" + +static void live_worklist (tree_live_info_p, varray_type, int); +static tree_live_info_p new_tree_live_info (var_map); +static inline void set_if_valid (var_map, bitmap, tree); +static inline void add_livein_if_notdef (tree_live_info_p, bitmap, + tree, basic_block); +static inline void register_ssa_partition (var_map, tree, bool); +static inline void add_conflicts_if_valid (tpa_p, conflict_graph, + var_map, bitmap, tree); +static partition_pair_p find_partition_pair (coalesce_list_p, int, int, bool); + +/* This is where the mapping from SSA version number to real storage variable + is tracked. + + All SSA versions of the same variable may not ultimately be mapped back to + the same real variable. In that instance, we need to detect the live + range overlap, and give one of the variable new storage. The vector + 'partition_to_var' tracks which partition maps to which variable. + + Given a VAR, it is sometimes desirable to know which partition that VAR + represents. There is an additional field in the variable annotation to + track that information. */ + +/* Create a variable partition map of SIZE, initialize and return it. */ + +var_map +init_var_map (int size) +{ + var_map map; + + map = (var_map) xmalloc (sizeof (struct _var_map)); + map->var_partition = partition_new (size); + map->partition_to_var + = (tree *)xmalloc (size * sizeof (tree)); + memset (map->partition_to_var, 0, size * sizeof (tree)); + + map->partition_to_compact = NULL; + map->compact_to_partition = NULL; + map->num_partitions = size; + map->partition_size = size; + map->ref_count = NULL; + return map; +} + + +/* Free memory associated with MAP. */ + +void +delete_var_map (var_map map) +{ + free (map->partition_to_var); + partition_delete (map->var_partition); + if (map->partition_to_compact) + free (map->partition_to_compact); + if (map->compact_to_partition) + free (map->compact_to_partition); + if (map->ref_count) + free (map->ref_count); + free (map); +} + + +/* This function will combine the partitions in MAP for VAR1 and VAR2. It + Returns the partition which represents the new partition. If the two + partitions cannot be combined, NO_PARTITION is returned. */ + +int +var_union (var_map map, tree var1, tree var2) +{ + int p1, p2, p3; + tree root_var = NULL_TREE; + tree other_var = NULL_TREE; + + /* This is independent of partition_to_compact. If partition_to_compact is + on, then whichever one of these partitions is absorbed will never have a + dereference into the partition_to_compact array any more. */ + + if (TREE_CODE (var1) == SSA_NAME) + p1 = partition_find (map->var_partition, SSA_NAME_VERSION (var1)); + else + { + p1 = var_to_partition (map, var1); + if (map->compact_to_partition) + p1 = map->compact_to_partition[p1]; + root_var = var1; + } + + if (TREE_CODE (var2) == SSA_NAME) + p2 = partition_find (map->var_partition, SSA_NAME_VERSION (var2)); + else + { + p2 = var_to_partition (map, var2); + if (map->compact_to_partition) + p2 = map->compact_to_partition[p2]; + + /* If there is no root_var set, or its not a user variable, set the + root_var to this one. */ + if (!root_var || is_gimple_tmp_var (root_var)) + { + other_var = root_var; + root_var = var2; + } + else + other_var = var2; + } + + if (p1 == NO_PARTITION || p2 == NO_PARTITION) + abort (); + + if (p1 == p2) + p3 = p1; + else + p3 = partition_union (map->var_partition, p1, p2); + + if (map->partition_to_compact) + p3 = map->partition_to_compact[p3]; + + if (root_var) + change_partition_var (map, root_var, p3); + if (other_var) + change_partition_var (map, other_var, p3); + + return p3; +} + + +/* Compress the partition numbers in MAP such that they fall in the range + 0..(num_partitions-1) instead of wherever they turned out during + the partitioning exercise. This removes any references to unused + partitions, thereby allowing bitmaps and other vectors to be much + denser. Compression type is controlled by FLAGS. + + This is implemented such that compaction doesn't affect partitioning. + Ie., once partitions are created and possibly merged, running one + or more different kind of compaction will not affect the partitions + themselves. Their index might change, but all the same variables will + still be members of the same partition group. This allows work on reduced + sets, and no loss of information when a larger set is later desired. + + In particular, coalescing can work on partitions which have 2 or more + definitions, and then 'recompact' later to include all the single + definitions for assignment to program variables. */ + +void +compact_var_map (var_map map, int flags) +{ + sbitmap used; + int x, limit, count, tmp, root, root_i; + tree var; + root_var_p rv = NULL; + + limit = map->partition_size; + used = sbitmap_alloc (limit); + sbitmap_zero (used); + + /* Already compressed? Abandon the old one. */ + if (map->partition_to_compact) + { + free (map->partition_to_compact); + map->partition_to_compact = NULL; + } + if (map->compact_to_partition) + { + free (map->compact_to_partition); + map->compact_to_partition = NULL; + } + + map->num_partitions = map->partition_size; + + if (flags & VARMAP_NO_SINGLE_DEFS) + rv = root_var_init (map); + + map->partition_to_compact = (int *)xmalloc (limit * sizeof (int)); + memset (map->partition_to_compact, 0xff, (limit * sizeof (int))); + + /* Find out which partitions are actually referenced. */ + count = 0; + for (x = 0; x < limit; x++) + { + tmp = partition_find (map->var_partition, x); + if (!TEST_BIT (used, tmp) && map->partition_to_var[tmp] != NULL_TREE) + { + /* It is referenced, check to see if there is more than one version + in the root_var table, if one is available. */ + if (rv) + { + root = root_var_find (rv, tmp); + root_i = root_var_first_partition (rv, root); + /* If there is only one, don't include this in the compaction. */ + if (root_var_next_partition (rv, root_i) == ROOT_VAR_NONE) + continue; + } + SET_BIT (used, tmp); + count++; + } + } + + /* Build a compacted partitioning. */ + if (count != limit) + { + map->compact_to_partition = (int *)xmalloc (count * sizeof (int)); + count = 0; + /* SSA renaming begins at 1, so skip 0 when compacting. */ + EXECUTE_IF_SET_IN_SBITMAP (used, 1, x, + { + map->partition_to_compact[x] = count; + map->compact_to_partition[count] = x; + var = map->partition_to_var[x]; + if (TREE_CODE (var) != SSA_NAME) + change_partition_var (map, var, count); + count++; + }); + } + else + { + free (map->partition_to_compact); + map->partition_to_compact = NULL; + } + + map->num_partitions = count; + + if (rv) + root_var_delete (rv); + sbitmap_free (used); +} + + +/* This function is used to change the representative variable in MAP for VAR's + partition from an SSA_NAME variable to a regular variable. This allows + partitions to be mapped back to real variables. */ + +void +change_partition_var (var_map map, tree var, int part) +{ + var_ann_t ann; + + if (TREE_CODE (var) == SSA_NAME) + abort(); + + ann = var_ann (var); + ann->out_of_ssa_tag = 1; + VAR_ANN_PARTITION (ann) = part; + if (map->compact_to_partition) + map->partition_to_var[map->compact_to_partition[part]] = var; +} + + +/* This function looks through the program and uses FLAGS to determine what + SSA versioned variables are given entries in a new partition table. This + new partition map is returned. */ + +var_map +create_ssa_var_map (int flags) +{ + block_stmt_iterator bsi; + basic_block bb; + tree *dest, *use; + tree stmt; + stmt_ann_t ann; + vuse_optype vuses; + vdef_optype vdefs; + use_optype uses; + def_optype defs; + unsigned x; + var_map map; +#if defined ENABLE_CHECKING + sbitmap used_in_real_ops; + sbitmap used_in_virtual_ops; +#endif + + map = init_var_map (highest_ssa_version + 1); + +#if defined ENABLE_CHECKING + used_in_real_ops = sbitmap_alloc (num_referenced_vars); + sbitmap_zero (used_in_real_ops); + + used_in_virtual_ops = sbitmap_alloc (num_referenced_vars); + sbitmap_zero (used_in_virtual_ops); +#endif + + if (flags & SSA_VAR_MAP_REF_COUNT) + { + map->ref_count + = (int *)xmalloc (((highest_ssa_version + 1) * sizeof (int))); + memset (map->ref_count, 0, (highest_ssa_version + 1) * sizeof (int)); + } + + FOR_EACH_BB (bb) + { + tree phi, arg; + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + int i; + register_ssa_partition (map, PHI_RESULT (phi), false); + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + arg = PHI_ARG_DEF (phi, i); + if (TREE_CODE (arg) == SSA_NAME) + register_ssa_partition (map, arg, true); + } + } + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + + /* Register USE and DEF operands in each statement. */ + uses = USE_OPS (ann); + for (x = 0; x < NUM_USES (uses); x++) + { + use = USE_OP_PTR (uses, x); + register_ssa_partition (map, *use, true); + +#if defined ENABLE_CHECKING + SET_BIT (used_in_real_ops, var_ann (SSA_NAME_VAR (*use))->uid); +#endif + } + + defs = DEF_OPS (ann); + for (x = 0; x < NUM_DEFS (defs); x++) + { + dest = DEF_OP_PTR (defs, x); + register_ssa_partition (map, *dest, false); + +#if defined ENABLE_CHECKING + SET_BIT (used_in_real_ops, var_ann (SSA_NAME_VAR (*dest))->uid); +#endif + } + + /* While we do not care about virtual operands for + out of SSA, we do need to look at them to make sure + we mark all the variables which are used. */ + vuses = VUSE_OPS (ann); + for (x = 0; x < NUM_VUSES (vuses); x++) + { + tree var = VUSE_OP (vuses, x); + set_is_used (var); + +#if defined ENABLE_CHECKING + SET_BIT (used_in_virtual_ops, var_ann (SSA_NAME_VAR (var))->uid); +#endif + } + + vdefs = VDEF_OPS (ann); + for (x = 0; x < NUM_VDEFS (vdefs); x++) + { + tree var = VDEF_OP (vdefs, x); + set_is_used (var); + +#if defined ENABLE_CHECKING + SET_BIT (used_in_virtual_ops, var_ann (SSA_NAME_VAR (var))->uid); +#endif + } + } + } + +#if defined ENABLE_CHECKING + { + unsigned i; + sbitmap both = sbitmap_alloc (num_referenced_vars); + sbitmap_a_and_b (both, used_in_real_ops, used_in_virtual_ops); + if (sbitmap_first_set_bit (both) >= 0) + { + EXECUTE_IF_SET_IN_SBITMAP (both, 0, i, + fprintf (stderr, "Variable %s used in real and virtual operands\n", + get_name (referenced_var (i)))); + abort (); + } + + sbitmap_free (used_in_real_ops); + sbitmap_free (used_in_virtual_ops); + sbitmap_free (both); + } +#endif + + return map; +} + + +/* Allocate and return a new live range information object base on MAP. */ + +static tree_live_info_p +new_tree_live_info (var_map map) +{ + tree_live_info_p live; + int x; + + live = (tree_live_info_p) xmalloc (sizeof (struct tree_live_info_d)); + live->map = map; + live->num_blocks = last_basic_block; + + live->global = BITMAP_XMALLOC (); + + live->livein = (bitmap *)xmalloc (num_var_partitions (map) * sizeof (bitmap)); + for (x = 0; x < num_var_partitions (map); x++) + live->livein[x] = BITMAP_XMALLOC (); + + /* liveout is deferred until it is actually requested. */ + live->liveout = NULL; + return live; +} + + +/* Free storage for live range info object LIVE. */ + +void +delete_tree_live_info (tree_live_info_p live) +{ + int x; + if (live->liveout) + { + for (x = live->num_blocks - 1; x >= 0; x--) + BITMAP_XFREE (live->liveout[x]); + free (live->liveout); + } + if (live->livein) + { + for (x = num_var_partitions (live->map) - 1; x >= 0; x--) + BITMAP_XFREE (live->livein[x]); + free (live->livein); + } + if (live->global) + BITMAP_XFREE (live->global); + + free (live); +} + + +/* Using LIVE, fill in all the live-on-entry blocks between the defs and uses + for partition I. STACK is a varray used for temporary memory which is + passed in rather than being allocated on every call. */ + +static void +live_worklist (tree_live_info_p live, varray_type stack, int i) +{ + int b; + tree var; + basic_block def_bb = NULL; + edge e; + var_map map = live->map; + + var = partition_to_var (map, i); + if (SSA_NAME_DEF_STMT (var)) + def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (var)); + + EXECUTE_IF_SET_IN_BITMAP (live->livein[i], 0, b, + { + VARRAY_PUSH_INT (stack, b); + }); + + while (VARRAY_ACTIVE_SIZE (stack) > 0) + { + b = VARRAY_TOP_INT (stack); + VARRAY_POP (stack); + + for (e = BASIC_BLOCK (b)->pred; e; e = e->pred_next) + if (e->src != ENTRY_BLOCK_PTR) + { + /* Its not live on entry to the block its defined in. */ + if (e->src == def_bb) + continue; + if (!bitmap_bit_p (live->livein[i], e->src->index)) + { + bitmap_set_bit (live->livein[i], e->src->index); + VARRAY_PUSH_INT (stack, e->src->index); + } + } + } +} + + +/* If VAR is in a partition of MAP, set the bit for that partition in VEC. */ + +static inline void +set_if_valid (var_map map, bitmap vec, tree var) +{ + int p = var_to_partition (map, var); + if (p != NO_PARTITION) + bitmap_set_bit (vec, p); +} + + +/* If VAR is in a partition and it isn't defined in DEF_VEC, set the livein and + global bit for it in the LIVE object. BB is the block being processed. */ + +static inline void +add_livein_if_notdef (tree_live_info_p live, bitmap def_vec, + tree var, basic_block bb) +{ + int p = var_to_partition (live->map, var); + if (p == NO_PARTITION || bb == ENTRY_BLOCK_PTR) + return; + if (!bitmap_bit_p (def_vec, p)) + { + bitmap_set_bit (live->livein[p], bb->index); + bitmap_set_bit (live->global, p); + } +} + + +/* Given partition map MAP, calculate all the live on entry bitmaps for + each basic block. Return a live info object. */ + +tree_live_info_p +calculate_live_on_entry (var_map map) +{ + tree_live_info_p live; + int num, i; + basic_block bb; + bitmap saw_def; + tree phi, var, stmt; + tree *vec; + edge e; + varray_type stack; + block_stmt_iterator bsi; + vuse_optype vuses; + vdef_optype vdefs; + use_optype uses; + def_optype defs; + stmt_ann_t ann; + + saw_def = BITMAP_XMALLOC (); + + live = new_tree_live_info (map); + + FOR_EACH_BB (bb) + { + bitmap_clear (saw_def); + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + var = PHI_ARG_DEF (phi, i); + if (!phi_ssa_name_p (var)) + continue; + stmt = SSA_NAME_DEF_STMT (var); + e = PHI_ARG_EDGE (phi, i); + + /* Any uses in PHIs which either don't have def's or are not + defined in the block from which the def comes, will be live + on entry to that block. */ + if (!stmt || e->src != bb_for_stmt (stmt)) + add_livein_if_notdef (live, saw_def, var, e->src); + } + } + + /* Don't mark PHI results as defined until all the PHI nodes have + been processed. If the PHI sequence is: + a_3 = PHI + b_3 = PHI + The a_3 referred to in b_3's PHI node is the one incoming on the + edge, *not* the PHI node just seen. */ + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + var = PHI_RESULT (phi); + set_if_valid (map, saw_def, var); + } + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + + uses = USE_OPS (ann); + num = NUM_USES (uses); + for (i = 0; i < num; i++) + { + vec = USE_OP_PTR (uses, i); + add_livein_if_notdef (live, saw_def, *vec, bb); + } + + vuses = VUSE_OPS (ann); + num = NUM_VUSES (vuses); + for (i = 0; i < num; i++) + { + var = VUSE_OP (vuses, i); + add_livein_if_notdef (live, saw_def, var, bb); + } + + vdefs = VDEF_OPS (ann); + num = NUM_VDEFS (vdefs); + for (i = 0; i < num; i++) + { + var = VDEF_OP (vdefs, i); + add_livein_if_notdef (live, saw_def, var, bb); + } + + defs = DEF_OPS (ann); + num = NUM_DEFS (defs); + for (i = 0; i < num; i++) + { + vec = DEF_OP_PTR (defs, i); + set_if_valid (map, saw_def, *vec); + } + + num = NUM_VDEFS (vdefs); + for (i = 0; i < num; i++) + { + var = VDEF_RESULT (vdefs, i); + set_if_valid (map, saw_def, var); + } + } + } + + VARRAY_INT_INIT (stack, last_basic_block, "stack"); + EXECUTE_IF_SET_IN_BITMAP (live->global, 0, i, + { + live_worklist (live, stack, i); + }); + +#ifdef ENABLE_CHECKING + /* Check for live on entry partitions and report those with a DEF in + the program. This will typically mean an optimization has done + something wrong. */ + + bb = ENTRY_BLOCK_PTR; + num = 0; + for (e = bb->succ; e; e = e->succ_next) + { + int entry_block = e->dest->index; + if (e->dest == EXIT_BLOCK_PTR) + continue; + for (i = 0; i < num_var_partitions (map); i++) + { + basic_block tmp; + tree d; + var = partition_to_var (map, i); + stmt = SSA_NAME_DEF_STMT (var); + tmp = bb_for_stmt (stmt); + d = default_def (SSA_NAME_VAR (var)); + + if (bitmap_bit_p (live_entry_blocks (live, i), entry_block)) + { + if (!IS_EMPTY_STMT (stmt)) + { + num++; + print_generic_expr (stderr, var, TDF_SLIM); + fprintf (stderr, " is defined "); + if (tmp) + fprintf (stderr, " in BB%d, ", tmp->index); + fprintf (stderr, "by:\n"); + print_generic_expr (stderr, stmt, TDF_SLIM); + fprintf (stderr, "\nIt is also live-on-entry to entry BB %d", + entry_block); + fprintf (stderr, " So it appears to have multiple defs.\n"); + } + else + { + if (d != var) + { + num++; + print_generic_expr (stderr, var, TDF_SLIM); + fprintf (stderr, " is live-on-entry to BB%d ",entry_block); + if (d) + { + fprintf (stderr, " but is not the default def of "); + print_generic_expr (stderr, d, TDF_SLIM); + fprintf (stderr, "\n"); + } + else + fprintf (stderr, " and there is no default def.\n"); + } + } + } + else + if (d == var) + { + /* The only way this var shouldn't be marked live on entry is + if it occurs in a PHI argument of the block. */ + int z, ok = 0; + for (phi = phi_nodes (e->dest); + phi && !ok; + phi = TREE_CHAIN (phi)) + { + for (z = 0; z < PHI_NUM_ARGS (phi); z++) + if (var == PHI_ARG_DEF (phi, z)) + { + ok = 1; + break; + } + } + if (ok) + continue; + num++; + print_generic_expr (stderr, var, TDF_SLIM); + fprintf (stderr, " is not marked live-on-entry to entry BB%d ", + entry_block); + fprintf (stderr, "but it is a default def so it should be.\n"); + } + } + } + if (num > 0) + abort (); +#endif + + return live; +} + + +/* Calculate the live on exit vectors based on the entry info in LIVEINFO. */ + +void +calculate_live_on_exit (tree_live_info_p liveinfo) +{ + unsigned b; + int i, x; + bitmap *on_exit; + basic_block bb; + edge e; + tree t, phi; + bitmap on_entry; + var_map map = liveinfo->map; + + on_exit = (bitmap *)xmalloc (last_basic_block * sizeof (bitmap)); + for (x = 0; x < last_basic_block; x++) + on_exit[x] = BITMAP_XMALLOC (); + + /* Set all the live-on-exit bits for uses in PHIs. */ + FOR_EACH_BB (bb) + { + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + t = PHI_ARG_DEF (phi, i); + e = PHI_ARG_EDGE (phi, i); + if (!phi_ssa_name_p (t) || e->src == ENTRY_BLOCK_PTR) + continue; + set_if_valid (map, on_exit[e->src->index], t); + } + } + + /* Set live on exit for all predecessors of live on entry's. */ + for (i = 0; i < num_var_partitions (map); i++) + { + on_entry = live_entry_blocks (liveinfo, i); + EXECUTE_IF_SET_IN_BITMAP (on_entry, 0, b, + { + for (e = BASIC_BLOCK(b)->pred; e; e = e->pred_next) + if (e->src != ENTRY_BLOCK_PTR) + bitmap_set_bit (on_exit[e->src->index], i); + }); + } + + liveinfo->liveout = on_exit; +} + + +/* Initialize a tree_partition_associator object using MAP. */ + +tpa_p +tpa_init (var_map map) +{ + tpa_p tpa; + int num_partitions = num_var_partitions (map); + int x; + + if (num_partitions == 0) + return NULL; + + tpa = (tpa_p) xmalloc (sizeof (struct tree_partition_associator_d)); + tpa->num_trees = 0; + tpa->uncompressed_num = -1; + tpa->map = map; + tpa->next_partition = (int *)xmalloc (num_partitions * sizeof (int)); + memset (tpa->next_partition, TPA_NONE, num_partitions * sizeof (int)); + + tpa->partition_to_tree_map = (int *)xmalloc (num_partitions * sizeof (int)); + memset (tpa->partition_to_tree_map, TPA_NONE, num_partitions * sizeof (int)); + + x = MAX (40, (num_partitions / 20)); + VARRAY_TREE_INIT (tpa->trees, x, "trees"); + VARRAY_INT_INIT (tpa->first_partition, x, "first_partition"); + + return tpa; + +} + + +/* Remove PARTITION_INDEX from TREE_INDEX's list in the tpa structure TPA. */ + +void +tpa_remove_partition (tpa_p tpa, int tree_index, int partition_index) +{ + int i; + + i = tpa_first_partition (tpa, tree_index); + if (i == partition_index) + { + VARRAY_INT (tpa->first_partition, tree_index) = tpa->next_partition[i]; + } + else + { + for ( ; i != TPA_NONE; i = tpa_next_partition (tpa, i)) + { + if (tpa->next_partition[i] == partition_index) + { + tpa->next_partition[i] = tpa->next_partition[partition_index]; + break; + } + } + } +} + + +/* Free the memory used by tree_partition_associator object TPA. */ + +void +tpa_delete (tpa_p tpa) +{ + if (!tpa) + return; + + free (tpa->partition_to_tree_map); + free (tpa->next_partition); + free (tpa); +} + + +/* This function will remove any tree entires from TPA which have only a single + element. This will help keep the size of the conflict graph down. The + function returns the number of remaining tree lists. */ + +int +tpa_compact (tpa_p tpa) +{ + int last, x, y, first, swap_i; + tree swap_t; + + /* Find the last list which has more than 1 partition. */ + for (last = tpa->num_trees - 1; last > 0; last--) + { + first = tpa_first_partition (tpa, last); + if (tpa_next_partition (tpa, first) != NO_PARTITION) + break; + } + + x = 0; + while (x < last) + { + first = tpa_first_partition (tpa, x); + + /* If there is not more than one partition, swap with the current end + of the tree list. */ + if (tpa_next_partition (tpa, first) == NO_PARTITION) + { + swap_t = VARRAY_TREE (tpa->trees, last); + swap_i = VARRAY_INT (tpa->first_partition, last); + + /* Update the last entry. Since it is known to only have one + partition, there is nothing else to update. */ + VARRAY_TREE (tpa->trees, last) = VARRAY_TREE (tpa->trees, x); + VARRAY_INT (tpa->first_partition, last) + = VARRAY_INT (tpa->first_partition, x); + tpa->partition_to_tree_map[tpa_first_partition (tpa, last)] = last; + + /* Since this list is known to have more than one partition, update + the list owner entries. */ + VARRAY_TREE (tpa->trees, x) = swap_t; + VARRAY_INT (tpa->first_partition, x) = swap_i; + for (y = tpa_first_partition (tpa, x); + y != NO_PARTITION; + y = tpa_next_partition (tpa, y)) + tpa->partition_to_tree_map[y] = x; + + /* Ensure last is a list with more than one partition. */ + last--; + for (; last > x; last--) + { + first = tpa_first_partition (tpa, last); + if (tpa_next_partition (tpa, first) != NO_PARTITION) + break; + } + } + x++; + } + + first = tpa_first_partition (tpa, x); + if (tpa_next_partition (tpa, first) != NO_PARTITION) + x++; + tpa->uncompressed_num = tpa->num_trees; + tpa->num_trees = x; + return last; +} + + +/* Initialize a root_var object with SSA partitions from MAP which are based + on each root variable. */ + +root_var_p +root_var_init (var_map map) +{ + root_var_p rv; + int num_partitions = num_var_partitions (map); + int x, p; + tree t; + var_ann_t ann; + sbitmap seen; + + rv = tpa_init (map); + if (!rv) + return NULL; + + seen = sbitmap_alloc (num_partitions); + sbitmap_zero (seen); + + /* Start at the end and work towards the front. This will provide a list + that is ordered from smallest to largest. */ + for (x = num_partitions - 1; x >= 0; x--) + { + t = partition_to_var (map, x); + + /* The var map may not be compacted yet, so check for NULL. */ + if (!t) + continue; + + p = var_to_partition (map, t); + +#ifdef ENABLE_CHECKING + if (p == NO_PARTITION) + abort (); +#endif + + /* Make sure we only put coalesced partitions into the list once. */ + if (TEST_BIT (seen, p)) + continue; + SET_BIT (seen, p); + if (TREE_CODE (t) == SSA_NAME) + t = SSA_NAME_VAR (t); + ann = var_ann (t); + if (ann->root_var_processed) + { + rv->next_partition[p] = VARRAY_INT (rv->first_partition, + VAR_ANN_ROOT_INDEX (ann)); + VARRAY_INT (rv->first_partition, VAR_ANN_ROOT_INDEX (ann)) = p; + } + else + { + ann->root_var_processed = 1; + VAR_ANN_ROOT_INDEX (ann) = rv->num_trees++; + VARRAY_PUSH_TREE (rv->trees, t); + VARRAY_PUSH_INT (rv->first_partition, p); + } + rv->partition_to_tree_map[p] = VAR_ANN_ROOT_INDEX (ann); + } + + /* Reset the out_of_ssa_tag flag on each variable for later use. */ + for (x = 0; x < rv->num_trees; x++) + { + t = VARRAY_TREE (rv->trees, x); + var_ann (t)->root_var_processed = 0; + } + + sbitmap_free (seen); + return rv; +} + + +/* Initialize a type_var structure which associates all the partitions in MAP + of the same type to the type node's index. Volatiles are ignored. */ + +type_var_p +type_var_init (var_map map) +{ + type_var_p tv; + int x, y, p; + int num_partitions = num_var_partitions (map); + tree t; + sbitmap seen; + + seen = sbitmap_alloc (num_partitions); + sbitmap_zero (seen); + + tv = tpa_init (map); + if (!tv) + return NULL; + + for (x = num_partitions - 1; x >= 0; x--) + { + t = partition_to_var (map, x); + + /* Disallow coalescing of these types of variables. */ + if (!t + || TREE_THIS_VOLATILE (t) + || TREE_CODE (t) == RESULT_DECL + || TREE_CODE (t) == PARM_DECL + || (DECL_P (t) + && (DECL_REGISTER (t) + || !DECL_ARTIFICIAL (t) + || DECL_RTL_SET_P (t)))) + continue; + + p = var_to_partition (map, t); + +#ifdef ENABLE_CHECKING + if (p == NO_PARTITION) + abort (); +#endif + + /* If partitions have been coalesced, only add the representative + for the partition to the list once. */ + if (TEST_BIT (seen, p)) + continue; + SET_BIT (seen, p); + t = TREE_TYPE (t); + + /* Find the list for this type. */ + for (y = 0; y < tv->num_trees; y++) + if (t == VARRAY_TREE (tv->trees, y)) + break; + if (y == tv->num_trees) + { + tv->num_trees++; + VARRAY_PUSH_TREE (tv->trees, t); + VARRAY_PUSH_INT (tv->first_partition, p); + } + else + { + tv->next_partition[p] = VARRAY_INT (tv->first_partition, y); + VARRAY_INT (tv->first_partition, y) = p; + } + tv->partition_to_tree_map[p] = y; + } + sbitmap_free (seen); + return tv; +} + + +/* Create a new coalesce list object from MAP and return it. */ + +coalesce_list_p +create_coalesce_list (var_map map) +{ + coalesce_list_p list; + + list = (coalesce_list_p) xmalloc (sizeof (struct coalesce_list_d)); + + list->map = map; + list->add_mode = true; + list->list = (partition_pair_p *) xcalloc (num_var_partitions (map), + sizeof (struct partition_pair_d)); + return list; +} + + +/* Delete coalesce list CL. */ + +void +delete_coalesce_list (coalesce_list_p cl) +{ + free (cl->list); + free (cl); +} + + +/* Find a matching coalesce pair object in CL for partitions P1 and P2. If + one isn't found, return NULL if CREATE is false, otherwise create a new + coalesce pair object and return it. */ + +static partition_pair_p +find_partition_pair (coalesce_list_p cl, int p1, int p2, bool create) +{ + partition_pair_p node, tmp; + int s; + + /* Normalize so that p1 is the smaller value. */ + if (p2 < p1) + { + s = p1; + p1 = p2; + p2 = s; + } + + tmp = NULL; + + /* The list is sorted such that if we find a value greater than p2, + p2 is not in the list. */ + for (node = cl->list[p1]; node; node = node->next) + { + if (node->second_partition == p2) + return node; + else + if (node->second_partition > p2) + break; + tmp = node; + } + + if (!create) + return NULL; + + node = (partition_pair_p) xmalloc (sizeof (struct partition_pair_d)); + node->first_partition = p1; + node->second_partition = p2; + node->cost = 0; + + if (tmp != NULL) + { + node->next = tmp->next; + tmp->next = node; + } + else + { + /* This is now the first node in the list. */ + node->next = cl->list[p1]; + cl->list[p1] = node; + } + + return node; +} + + +/* Add a potential coalesce between P1 and P2 in CL with a cost of VALUE. */ + +void +add_coalesce (coalesce_list_p cl, int p1, int p2, int value) +{ + partition_pair_p node; + +#ifdef ENABLE_CHECKING + if (!cl->add_mode) + abort(); +#endif + + if (p1 == p2) + return; + + node = find_partition_pair (cl, p1, p2, true); + + node->cost += value; +} + + +/* Comparison function to allow qsort to sort P1 and P2 in descending order. */ + +static +int compare_pairs (const void *p1, const void *p2) +{ + return (*(partition_pair_p *)p2)->cost - (*(partition_pair_p *)p1)->cost; +} + + +/* Prepare CL for removal of preferred pairs. When finished, list element + 0 has all the coalesce pairs, sorted in order from most important coalesce + to least important. */ + +void +sort_coalesce_list (coalesce_list_p cl) +{ + int x, num, count; + partition_pair_p chain, p; + partition_pair_p *list; + + if (!cl->add_mode) + abort(); + + cl->add_mode = false; + + /* Compact the array of lists to a single list, and count the elements. */ + num = 0; + chain = NULL; + for (x = 0; x < num_var_partitions (cl->map); x++) + if (cl->list[x] != NULL) + { + for (p = cl->list[x]; p->next != NULL; p = p->next) + num++; + num++; + p->next = chain; + chain = cl->list[x]; + cl->list[x] = NULL; + } + + /* Only call qsort if there are more than 2 items. */ + if (num > 2) + { + list = xmalloc (sizeof (partition_pair_p) * num); + count = 0; + for (p = chain; p != NULL; p = p->next) + list[count++] = p; + +#ifdef ENABLE_CHECKING + if (count != num) + abort (); +#endif + + qsort (list, count, sizeof (partition_pair_p), compare_pairs); + + p = list[0]; + for (x = 1; x < num; x++) + { + p->next = list[x]; + p = list[x]; + } + p->next = NULL; + cl->list[0] = list[0]; + free (list); + } + else + { + cl->list[0] = chain; + if (num == 2) + { + /* Simply swap the two elements if they are in the wrong order. */ + if (chain->cost < chain->next->cost) + { + cl->list[0] = chain->next; + cl->list[0]->next = chain; + chain->next = NULL; + } + } + } +} + + +/* Retrieve the best remaining pair to coalesce from CL. Returns the 2 + partitions via P1 and P2. Their calculated cost is returned by the function. + NO_BEST_COALESCE is returned if the coalesce list is empty. */ + +int +pop_best_coalesce (coalesce_list_p cl, int *p1, int *p2) +{ + partition_pair_p node; + int ret; + + if (cl->add_mode) + abort(); + + node = cl->list[0]; + if (!node) + return NO_BEST_COALESCE; + + cl->list[0] = node->next; + + *p1 = node->first_partition; + *p2 = node->second_partition; + ret = node->cost; + free (node); + + return ret; +} + + +/* If variable VAR is in a partition in MAP, add a conflict in GRAPH between + VAR and any other live partitions in VEC which are associated via TPA. + Reset the live bit in VEC. */ + +static inline void +add_conflicts_if_valid (tpa_p tpa, conflict_graph graph, + var_map map, bitmap vec, tree var) +{ + int p, y, first; + p = var_to_partition (map, var); + if (p != NO_PARTITION) + { + bitmap_clear_bit (vec, p); + first = tpa_find_tree (tpa, p); + /* If find returns nothing, this object isn't interesting. */ + if (first == TPA_NONE) + return; + /* Only add interferences between objects in the same list. */ + for (y = tpa_first_partition (tpa, first); + y != TPA_NONE; + y = tpa_next_partition (tpa, y)) + { + if (bitmap_bit_p (vec, y)) + conflict_graph_add (graph, p, y); + } + } +} + + +/* Return a conflict graph for the information contained in LIVE_INFO. Only + conflicts between items in the same TPA list are added. If optional + coalesce list CL is passed in, any copies encountered are added. */ + +conflict_graph +build_tree_conflict_graph (tree_live_info_p liveinfo, tpa_p tpa, + coalesce_list_p cl) +{ + conflict_graph graph; + var_map map; + bitmap live; + int num, x, y, i; + basic_block bb; + varray_type partition_link, tpa_to_clear, tpa_nodes; + def_optype defs; + use_optype uses; + unsigned l; + + map = live_var_map (liveinfo); + graph = conflict_graph_new (num_var_partitions (map)); + + if (tpa_num_trees (tpa) == 0) + return graph; + + live = BITMAP_XMALLOC (); + + VARRAY_INT_INIT (partition_link, num_var_partitions (map) + 1, "part_link"); + VARRAY_INT_INIT (tpa_nodes, tpa_num_trees (tpa), "tpa nodes"); + VARRAY_INT_INIT (tpa_to_clear, 50, "tpa to clear"); + + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + tree phi; + + /* Start with live on exit temporaries. */ + bitmap_copy (live, live_on_exit (liveinfo, bb)); + + for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi)) + { + bool is_a_copy = false; + tree stmt = bsi_stmt (bsi); + stmt_ann_t ann; + + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + + /* A copy between 2 partitions does not introduce an interference + by itself. If they did, you would never be able to coalesce + two things which are copied. If the two variables really do + conflict, they will conflict elsewhere in the program. + + This is handled specially here since we may also be interested + in copies between real variables and SSA_NAME variables. We may + be interested in trying to coalesce SSA_NAME variables with + root variables in some cases. */ + + if (TREE_CODE (stmt) == MODIFY_EXPR) + { + tree lhs = TREE_OPERAND (stmt, 0); + tree rhs = TREE_OPERAND (stmt, 1); + int p1, p2; + int bit; + + if (DECL_P (lhs) || TREE_CODE (lhs) == SSA_NAME) + p1 = var_to_partition (map, lhs); + else + p1 = NO_PARTITION; + + if (DECL_P (rhs) || TREE_CODE (rhs) == SSA_NAME) + p2 = var_to_partition (map, rhs); + else + p2 = NO_PARTITION; + + if (p1 != NO_PARTITION && p2 != NO_PARTITION) + { + is_a_copy = true; + bit = bitmap_bit_p (live, p2); + /* If the RHS is live, make it not live while we add + the conflicts, then make it live again. */ + if (bit) + bitmap_clear_bit (live, p2); + add_conflicts_if_valid (tpa, graph, map, live, lhs); + if (bit) + bitmap_set_bit (live, p2); + if (cl) + add_coalesce (cl, p1, p2, 1); + set_if_valid (map, live, rhs); + } + } + + if (!is_a_copy) + { + tree *var_p; + + defs = DEF_OPS (ann); + num = NUM_DEFS (defs); + for (x = 0; x < num; x++) + { + var_p = DEF_OP_PTR (defs, x); + add_conflicts_if_valid (tpa, graph, map, live, *var_p); + } + + uses = USE_OPS (ann); + num = NUM_USES (uses); + for (x = 0; x < num; x++) + { + var_p = USE_OP_PTR (uses, x); + set_if_valid (map, live, *var_p); + } + } + } + + /* If result of a PHI is unused, then the loops over the statements + will not record any conflicts. However, since the PHI node is + going to be translated out of SSA form we must record a conflict + between the result of the PHI and any variables with are live. + Otherwise the out-of-ssa translation may create incorrect code. */ + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree result = PHI_RESULT (phi); + int p = var_to_partition (map, result); + + if (p != NO_PARTITION && ! bitmap_bit_p (live, p)) + add_conflicts_if_valid (tpa, graph, map, live, result); + } + + /* Anything which is still live at this point interferes. + In order to implement this efficiently, only conflicts between + partitions which have the same TPA root need be added. + TPA roots which have been seen are tracked in 'tpa_nodes'. A non-zero + entry points to an index into 'partition_link', which then indexes + into itself forming a linked list of partitions sharing a tpa root + which have been seen as live up to this point. Since partitions start + at index zero, all entries in partition_link are (partition + 1). + + Conflicts are added between the current partition and any already seen. + tpa_clear contains all the tpa_roots processed, and these are the only + entries which need to be zero'd out for a clean restart. */ + + EXECUTE_IF_SET_IN_BITMAP (live, 0, x, + { + i = tpa_find_tree (tpa, x); + if (i != TPA_NONE) + { + int start = VARRAY_INT (tpa_nodes, i); + /* If start is 0, a new root reference list is being started. + Register it to be cleared. */ + if (!start) + VARRAY_PUSH_INT (tpa_to_clear, i); + + /* Add interferences to other tpa members seen. */ + for (y = start; y != 0; y = VARRAY_INT (partition_link, y)) + conflict_graph_add (graph, x, y - 1); + VARRAY_INT (tpa_nodes, i) = x + 1; + VARRAY_INT (partition_link, x + 1) = start; + } + }); + + /* Now clear the used tpa root references. */ + for (l = 0; l < VARRAY_ACTIVE_SIZE (tpa_to_clear); l++) + VARRAY_INT (tpa_nodes, VARRAY_INT (tpa_to_clear, l)) = 0; + VARRAY_POP_ALL (tpa_to_clear); + } + + BITMAP_XFREE (live); + return graph; +} + + +/* This routine will attempt to coalesce the elements in TPA subject to the + conflicts found in GRAPH. If optional coalesce_list CL is provided, + only coalesces specified within the coalesce list are attempted. Otherwise + an attempt is made to coalesce as many partitions within each TPA grouping + as possible. If DEBUG is provided, debug output will be sent there. */ + +void +coalesce_tpa_members (tpa_p tpa, conflict_graph graph, var_map map, + coalesce_list_p cl, FILE *debug) +{ + int x, y, z, w; + tree var, tmp; + + /* Attempt to coalesce any items in a coalesce list. */ + if (cl) + { + while (pop_best_coalesce (cl, &x, &y) != NO_BEST_COALESCE) + { + if (debug) + { + fprintf (debug, "Coalesce list: (%d)", x); + print_generic_expr (debug, partition_to_var (map, x), TDF_SLIM); + fprintf (debug, " & (%d)", y); + print_generic_expr (debug, partition_to_var (map, y), TDF_SLIM); + } + + w = tpa_find_tree (tpa, x); + z = tpa_find_tree (tpa, y); + if (w != z || w == TPA_NONE || z == TPA_NONE) + { + if (debug) + { + if (w != z) + fprintf (debug, ": Fail, Non-matching TPA's\n"); + if (w == TPA_NONE) + fprintf (debug, ": Fail %d non TPA.\n", x); + else + fprintf (debug, ": Fail %d non TPA.\n", y); + } + continue; + } + var = partition_to_var (map, x); + tmp = partition_to_var (map, y); + x = var_to_partition (map, var); + y = var_to_partition (map, tmp); + if (debug) + fprintf (debug, " [map: %d, %d] ", x, y); + if (x == y) + { + if (debug) + fprintf (debug, ": Already Coalesced.\n"); + continue; + } + if (!conflict_graph_conflict_p (graph, x, y)) + { + z = var_union (map, var, tmp); + if (z == NO_PARTITION) + { + if (debug) + fprintf (debug, ": Unable to perform partition union.\n"); + continue; + } + + /* z is the new combined partition. We need to remove the other + partition from the list. Set x to be that other partition. */ + if (z == x) + { + conflict_graph_merge_regs (graph, x, y); + w = tpa_find_tree (tpa, y); + tpa_remove_partition (tpa, w, y); + } + else + { + conflict_graph_merge_regs (graph, y, x); + w = tpa_find_tree (tpa, x); + tpa_remove_partition (tpa, w, x); + } + + if (debug) + fprintf (debug, ": Success -> %d\n", z); + } + else + if (debug) + fprintf (debug, ": Fail due to conflict\n"); + } + /* If using a coalesce list, don't try to coalesce anything else. */ + return; + } + + for (x = 0; x < tpa_num_trees (tpa); x++) + { + while (tpa_first_partition (tpa, x) != TPA_NONE) + { + int p1, p2; + /* Coalesce first partition with anything that doesn't conflict. */ + y = tpa_first_partition (tpa, x); + tpa_remove_partition (tpa, x, y); + + var = partition_to_var (map, y); + /* p1 is the partition representative to which y belongs. */ + p1 = var_to_partition (map, var); + + for (z = tpa_next_partition (tpa, y); + z != TPA_NONE; + z = tpa_next_partition (tpa, z)) + { + tmp = partition_to_var (map, z); + /* p2 is the partition representative to which z belongs. */ + p2 = var_to_partition (map, tmp); + if (debug) + { + fprintf (debug, "Coalesce : "); + print_generic_expr (debug, var, TDF_SLIM); + fprintf (debug, " &"); + print_generic_expr (debug, tmp, TDF_SLIM); + fprintf (debug, " (%d ,%d)", p1, p2); + } + + /* If partitions are already merged, don't check for conflict. */ + if (tmp == var) + { + tpa_remove_partition (tpa, x, z); + if (debug) + fprintf (debug, ": Already coalesced\n"); + } + else + if (!conflict_graph_conflict_p (graph, p1, p2)) + { + int v; + if (tpa_find_tree (tpa, y) == TPA_NONE + || tpa_find_tree (tpa, z) == TPA_NONE) + { + if (debug) + fprintf (debug, ": Fail non-TPA member\n"); + continue; + } + if ((v = var_union (map, var, tmp)) == NO_PARTITION) + { + if (debug) + fprintf (debug, ": Fail cannot combine partitions\n"); + continue; + } + + tpa_remove_partition (tpa, x, z); + if (v == p1) + conflict_graph_merge_regs (graph, v, z); + else + { + /* Update the first partition's representative. */ + conflict_graph_merge_regs (graph, v, y); + p1 = v; + } + + /* The root variable of the partition may be changed + now. */ + var = partition_to_var (map, p1); + + if (debug) + fprintf (debug, ": Success -> %d\n", v); + } + else + if (debug) + fprintf (debug, ": Fail, Conflict\n"); + } + } + } +} + + +/* Send debug info for coalesce list CL to file F. */ + +void +dump_coalesce_list (FILE *f, coalesce_list_p cl) +{ + partition_pair_p node; + int x, num; + tree var; + + if (cl->add_mode) + { + fprintf (f, "Coalesce List:\n"); + num = num_var_partitions (cl->map); + for (x = 0; x < num; x++) + { + node = cl->list[x]; + if (node) + { + fprintf (f, "["); + print_generic_expr (f, partition_to_var (cl->map, x), TDF_SLIM); + fprintf (f, "] - "); + for ( ; node; node = node->next) + { + var = partition_to_var (cl->map, node->second_partition); + print_generic_expr (f, var, TDF_SLIM); + fprintf (f, "(%1d), ", node->cost); + } + fprintf (f, "\n"); + } + } + } + else + { + fprintf (f, "Sorted Coalesce list:\n"); + for (node = cl->list[0]; node; node = node->next) + { + fprintf (f, "(%d) ", node->cost); + var = partition_to_var (cl->map, node->first_partition); + print_generic_expr (f, var, TDF_SLIM); + fprintf (f, " : "); + var = partition_to_var (cl->map, node->second_partition); + print_generic_expr (f, var, TDF_SLIM); + fprintf (f, "\n"); + } + } +} + + +/* Output tree_partition_associator object TPA to file F.. */ + +void +tpa_dump (FILE *f, tpa_p tpa) +{ + int x, i; + + if (!tpa) + return; + + for (x = 0; x < tpa_num_trees (tpa); x++) + { + print_generic_expr (f, tpa_tree (tpa, x), TDF_SLIM); + fprintf (f, " : ("); + for (i = tpa_first_partition (tpa, x); + i != TPA_NONE; + i = tpa_next_partition (tpa, i)) + { + fprintf (f, "(%d)",i); + print_generic_expr (f, partition_to_var (tpa->map, i), TDF_SLIM); + fprintf (f, " "); + +#ifdef ENABLE_CHECKING + if (tpa_find_tree (tpa, i) != x) + fprintf (f, "**find tree incorrectly set** "); +#endif + + } + fprintf (f, ")\n"); + } + fflush (f); +} + + +/* Output partition map MAP to file F. */ + +void +dump_var_map (FILE *f, var_map map) +{ + int t; + unsigned x, y; + int p; + + fprintf (f, "\nPartition map \n\n"); + + for (x = 0; x < map->num_partitions; x++) + { + if (map->compact_to_partition != NULL) + p = map->compact_to_partition[x]; + else + p = x; + + if (map->partition_to_var[p] == NULL_TREE) + continue; + + t = 0; + for (y = 1; y < highest_ssa_version; y++) + { + p = partition_find (map->var_partition, y); + if (map->partition_to_compact) + p = map->partition_to_compact[p]; + if (p == (int)x) + { + if (t++ == 0) + { + fprintf(f, "Partition %d (", x); + print_generic_expr (f, partition_to_var (map, p), TDF_SLIM); + fprintf (f, " - "); + } + fprintf (f, "%d ", y); + } + } + if (t != 0) + fprintf (f, ")\n"); + } + fprintf (f, "\n"); +} + + +/* Output live range info LIVE to file F, controlled by FLAG. */ + +void +dump_live_info (FILE *f, tree_live_info_p live, int flag) +{ + basic_block bb; + int i; + var_map map = live->map; + + if ((flag & LIVEDUMP_ENTRY) && live->livein) + { + FOR_EACH_BB (bb) + { + fprintf (f, "\nLive on entry to BB%d : ", bb->index); + for (i = 0; i < num_var_partitions (map); i++) + { + if (bitmap_bit_p (live_entry_blocks (live, i), bb->index)) + { + print_generic_expr (f, partition_to_var (map, i), TDF_SLIM); + fprintf (f, " "); + } + } + fprintf (f, "\n"); + } + } + + if ((flag & LIVEDUMP_EXIT) && live->liveout) + { + FOR_EACH_BB (bb) + { + fprintf (f, "\nLive on exit from BB%d : ", bb->index); + EXECUTE_IF_SET_IN_BITMAP (live->liveout[bb->index], 0, i, + { + print_generic_expr (f, partition_to_var (map, i), TDF_SLIM); + fprintf (f, " "); + }); + fprintf (f, "\n"); + } + } +} + +/* Register partitions in MAP so that we can take VARS out of SSA form. + This requires a walk over all the PHI nodes and all the statements. */ + +void +register_ssa_partitions_for_vars (bitmap vars, var_map map) +{ + basic_block bb; + + if (bitmap_first_set_bit (vars) >= 0) + { + + /* Find every instance (SSA_NAME) of variables in VARs and + register a new partition for them. This requires examining + every statement and every PHI node once. */ + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + tree next; + tree phi; + + /* Register partitions for SSA_NAMEs appearing in the PHI + nodes in this basic block. + + Note we delete PHI nodes in this loop if they are + associated with virtual vars which are going to be + renamed. */ + for (phi = phi_nodes (bb); phi; phi = next) + { + tree result = SSA_NAME_VAR (PHI_RESULT (phi)); + + next = TREE_CHAIN (phi); + if (bitmap_bit_p (vars, var_ann (result)->uid)) + { + if (! is_gimple_reg (result)) + remove_phi_node (phi, NULL_TREE, bb); + else + { + int i; + + /* Register a partition for the result. */ + register_ssa_partition (map, PHI_RESULT (phi), 0); + + /* Register a partition for each argument as needed. */ + for (i = 0; i < PHI_NUM_ARGS (phi); i++) + { + tree arg = PHI_ARG_DEF (phi, i); + + if (TREE_CODE (arg) != SSA_NAME) + continue; + if (!bitmap_bit_p (vars, + var_ann (SSA_NAME_VAR (arg))->uid)) + continue; + + register_ssa_partition (map, arg, 1); + } + } + } + } + + /* Now register partitions for SSA_NAMEs appearing in each + statement in this block. */ + for (bsi = bsi_start (bb); ! bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt_ann_t ann = stmt_ann (bsi_stmt (bsi)); + use_optype uses = USE_OPS (ann); + def_optype defs = DEF_OPS (ann); + unsigned int i; + + for (i = 0; i < NUM_USES (uses); i++) + { + tree op = USE_OP (uses, i); + + if (TREE_CODE (op) == SSA_NAME + && bitmap_bit_p (vars, var_ann (SSA_NAME_VAR (op))->uid)) + register_ssa_partition (map, op, 1); + } + + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree op = DEF_OP (defs, i); + + if (TREE_CODE (op) == SSA_NAME + && bitmap_bit_p (vars, + var_ann (SSA_NAME_VAR (op))->uid)) + register_ssa_partition (map, op, 0); + } + } + } + } +} + diff --git a/gcc/tree-ssa-live.h b/gcc/tree-ssa-live.h new file mode 100644 index 00000000000..2d97a93cfe8 --- /dev/null +++ b/gcc/tree-ssa-live.h @@ -0,0 +1,747 @@ +/* Routines for liveness in SSA trees. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef _TREE_SSA_LIVE_H +#define _TREE_SSA_LIVE_H 1 + +/* Used to create the variable mapping when we go out of SSA form. */ +typedef struct _var_map +{ + /* The partition of all variables. */ + partition var_partition; + + /* Vector for compacting partitions. */ + int *partition_to_compact; + int *compact_to_partition; + + /* Mapping of partition numbers to vars. */ + tree *partition_to_var; + + /* Current number of partitions. */ + unsigned int num_partitions; + + /* Original partition size. */ + unsigned int partition_size; + + /* Reference count, if required. */ + int *ref_count; +} *var_map; + +#define VAR_ANN_PARTITION(ann) (ann->partition) +#define VAR_ANN_ROOT_INDEX(ann) (ann->root_index) + +#define NO_PARTITION -1 + +/* Flags to pass to compact_var_map */ + +#define VARMAP_NORMAL 0 +#define VARMAP_NO_SINGLE_DEFS 1 + +/* Flags to pass to remove_ssa_form. */ + +#define SSANORM_PERFORM_TER 0x1 +#define SSANORM_COMBINE_TEMPS 0x2 +#define SSANORM_REMOVE_ALL_PHIS 0x4 +#define SSANORM_COALESCE_PARTITIONS 0x8 +#define SSANORM_USE_COALESCE_LIST 0x10 + +extern var_map init_var_map (int); +extern void delete_var_map (var_map); +extern void dump_var_map (FILE *, var_map); +extern int var_union (var_map, tree, tree); +extern void change_partition_var (var_map, tree, int); +extern void compact_var_map (var_map, int); +extern void remove_ssa_form (FILE *, var_map, int); +extern void register_ssa_partitions_for_vars (bitmap vars, var_map map); + +static inline int num_var_partitions (var_map); +static inline tree var_to_partition_to_var (var_map, tree); +static inline tree partition_to_var (var_map, int); +static inline int var_to_partition (var_map, tree); +static inline tree version_to_var (var_map, int); +static inline int version_ref_count (var_map, tree); +static inline void register_ssa_partition (var_map, tree, bool); + +#define SSA_VAR_MAP_REF_COUNT 0x01 +extern var_map create_ssa_var_map (int); + + +/* Number of partitions in MAP. */ + +static inline int +num_var_partitions (var_map map) +{ + return map->num_partitions; +} + + +/* Return the reference count for SSA_VAR's partition in MAP. */ + +static inline int +version_ref_count (var_map map, tree ssa_var) +{ + int version = SSA_NAME_VERSION (ssa_var); +#ifdef ENABLE_CHECKING + if (!map->ref_count) + abort (); +#endif + return map->ref_count[version]; +} + + +/* Given partition index I from MAP, return the variable which represents that + partition. */ + +static inline tree +partition_to_var (var_map map, int i) +{ + if (map->compact_to_partition) + i = map->compact_to_partition[i]; + i = partition_find (map->var_partition, i); + return map->partition_to_var[i]; +} + + +/* Given ssa_name VERSION, if it has a partition in MAP, return the var it + is associated with. Otherwise return NULL. */ + +static inline tree version_to_var (var_map map, int version) +{ + int part; + part = partition_find (map->var_partition, version); + if (map->partition_to_compact) + part = map->partition_to_compact[part]; + if (part == NO_PARTITION) + return NULL_TREE; + + return partition_to_var (map, part); +} + + +/* Given VAR, return the partition number in MAP which contains it. + NO_PARTITION is returned if its not in any partition. */ + +static inline int +var_to_partition (var_map map, tree var) +{ + var_ann_t ann; + int part; + + if (TREE_CODE (var) == SSA_NAME) + { + part = partition_find (map->var_partition, SSA_NAME_VERSION (var)); + if (map->partition_to_compact) + part = map->partition_to_compact[part]; + } + else + { + ann = var_ann (var); + if (ann->out_of_ssa_tag) + part = VAR_ANN_PARTITION (ann); + else + part = NO_PARTITION; + } + return part; +} + + +/* Given VAR, return the variable which represents the entire partition + it is a member of in MAP. NULL is returned if it is not in a partition. */ + +static inline tree +var_to_partition_to_var (var_map map, tree var) +{ + int part; + + part = var_to_partition (map, var); + if (part == NO_PARTITION) + return NULL_TREE; + return partition_to_var (map, part); +} + + +/* This routine registers a partition for SSA_VAR with MAP. IS_USE is used + to count references. Any unregistered partitions may be compacted out + later. */ + +static inline void +register_ssa_partition (var_map map, tree ssa_var, bool is_use) +{ + int version; + +#if defined ENABLE_CHECKING + if (TREE_CODE (ssa_var) != SSA_NAME) + abort (); + + if (!is_gimple_reg (SSA_NAME_VAR (ssa_var))) + { + fprintf (stderr, "Illegally registering a virtual SSA name :"); + print_generic_expr (stderr, ssa_var, TDF_SLIM); + fprintf (stderr, " in the SSA->Normal phase.\n"); + abort(); + } +#endif + + version = SSA_NAME_VERSION (ssa_var); + if (is_use && map->ref_count) + map->ref_count[version]++; + + if (map->partition_to_var[version] == NULL_TREE) + map->partition_to_var[SSA_NAME_VERSION (ssa_var)] = ssa_var; +} + + +/* ---------------- live on entry/exit info ------------------------------ + + This structure is used to represent live range information on SSA based + trees. A partition map must be provided, and based on the active partitions, + live-on-entry information and live-on-exit information can be calculated. + As well, partitions are marked as to whether they are global (live + outside the basic block they are defined in). + + The live-on-entry information is per variable. It provide a bitmap for + each variable which has a bit set for each basic block that the variable + is live on entry to that block. + + The live-on-exit information is per block. It provides a bitmap for each + block indicating which partitions are live on exit from the block. + + For the purposes of this implementation, we treat the elements of a PHI + as follows: + + Uses in a PHI are considered LIVE-ON-EXIT to the block from which they + originate. They are *NOT* considered live on entry to the block + containing the PHI node. + + The Def of a PHI node is *not* considered live on entry to the block. + It is considered to be "define early" in the block. Picture it as each + block having a stmt (or block-preheader) before the first real stmt in + the block which defines all the variables that are defined by PHIs. + + ----------------------------------------------------------------------- */ + + +typedef struct tree_live_info_d +{ + /* Var map this relates to. */ + var_map map; + + /* Bitmap indicating which partitions are global. */ + bitmap global; + + /* Bitmap of live on entry blocks for partition elements. */ + bitmap *livein; + + /* Number of basic blocks when live on exit calculated. */ + int num_blocks; + + /* Bitmap of what variables are live on exit for a basic blocks. */ + bitmap *liveout; +} *tree_live_info_p; + + +extern tree_live_info_p calculate_live_on_entry (var_map); +extern void calculate_live_on_exit (tree_live_info_p); +extern void delete_tree_live_info (tree_live_info_p); + +#define LIVEDUMP_ENTRY 0x01 +#define LIVEDUMP_EXIT 0x02 +#define LIVEDUMP_ALL (LIVEDUMP_ENTRY | LIVEDUMP_EXIT) +extern void dump_live_info (FILE *, tree_live_info_p, int); + +static inline int partition_is_global (tree_live_info_p, int); +static inline bitmap live_entry_blocks (tree_live_info_p, int); +static inline bitmap live_on_exit (tree_live_info_p, basic_block); +static inline var_map live_var_map (tree_live_info_p); +static inline void live_merge_and_clear (tree_live_info_p, int, int); +static inline void make_live_on_entry (tree_live_info_p, basic_block, int); + + +/* Return TRUE if P is marked as a global in LIVE. */ + +static inline int +partition_is_global (tree_live_info_p live, int p) +{ + if (!live->global) + abort (); + + return bitmap_bit_p (live->global, p); +} + + +/* Return the bitmap from LIVE representing the live on entry blocks for + partition P. */ + +static inline bitmap +live_entry_blocks (tree_live_info_p live, int p) +{ + if (!live->livein) + abort (); + + return live->livein[p]; +} + + +/* Return the bitmap from LIVE representing the live on exit partitions from + block BB. */ + +static inline bitmap +live_on_exit (tree_live_info_p live, basic_block bb) +{ + if (!live->liveout) + abort(); + + if (bb == ENTRY_BLOCK_PTR || bb == EXIT_BLOCK_PTR) + abort (); + + return live->liveout[bb->index]; +} + + +/* Return the partition map which the information in LIVE utilizes. */ + +static inline var_map +live_var_map (tree_live_info_p live) +{ + return live->map; +} + + +/* Merge the live on entry information in LIVE for partitions P1 and P2. Place + the result into P1. Clear P2. */ + +static inline void +live_merge_and_clear (tree_live_info_p live, int p1, int p2) +{ + bitmap_a_or_b (live->livein[p1], live->livein[p1], live->livein[p2]); + bitmap_zero (live->livein[p2]); +} + + +/* Mark partition P as live on entry to basic block BB in LIVE. */ + +static inline void +make_live_on_entry (tree_live_info_p live, basic_block bb , int p) +{ + bitmap_set_bit (live->livein[p], bb->index); + bitmap_set_bit (live->global, p); +} + + +/* A tree_partition_associator (TPA)object is a base structure which allows + partitions to be associated with a tree object. + + A varray of tree elements represent each distinct tree item. + A parallel int array represents the first partition number associated with + the tree. + This partition number is then used as in index into the next_partition + array, which returns the index of the next partition which is associated + with the tree. TPA_NONE indicates the end of the list. + A varray paralleling the partition list 'partition_to_tree_map' is used + to indicate which tree index the partition is in. */ + +typedef struct tree_partition_associator_d +{ + varray_type trees; + varray_type first_partition; + int *next_partition; + int *partition_to_tree_map; + int num_trees; + int uncompressed_num; + var_map map; +} *tpa_p; + +/* Value returned when there are no more partitions associated with a tree. */ +#define TPA_NONE -1 + +static inline tree tpa_tree (tpa_p, int); +static inline int tpa_first_partition (tpa_p, int); +static inline int tpa_next_partition (tpa_p, int); +static inline int tpa_num_trees (tpa_p); +static inline int tpa_find_tree (tpa_p, int); +static inline void tpa_decompact (tpa_p); +extern tpa_p tpa_init (var_map); +extern void tpa_delete (tpa_p); +extern void tpa_dump (FILE *, tpa_p); +extern void tpa_remove_partition (tpa_p, int, int); +extern int tpa_compact (tpa_p); + + +/* Return the number of distinct tree nodes in TPA. */ + +static inline int +tpa_num_trees (tpa_p tpa) +{ + return tpa->num_trees; +} + + +/* Return the tree node for index I in TPA. */ + +static inline tree +tpa_tree (tpa_p tpa, int i) +{ + return VARRAY_TREE (tpa->trees, i); +} + + +/* Return the first partition associated with tree list I in TPA. */ + +static inline int +tpa_first_partition (tpa_p tpa, int i) +{ + return VARRAY_INT (tpa->first_partition, i); +} + + +/* Return the next partition after partition I in TPA's list. */ + +static inline int +tpa_next_partition (tpa_p tpa, int i) +{ + return tpa->next_partition[i]; +} + + +/* Return the tree index from TPA whose list contains partition I. + TPA_NONE is returned if I is not associated with any list. */ + +static inline int +tpa_find_tree (tpa_p tpa, int i) +{ + int index; + + index = tpa->partition_to_tree_map[i]; + /* When compressed, any index higher than the number of tree elements is + a compressed element, so return TPA_NONE. */ + if (index != TPA_NONE && index >= tpa_num_trees (tpa)) + { +#ifdef ENABLE_CHECKING + if (tpa->uncompressed_num == -1) + abort (); +#endif + index = TPA_NONE; + } + + return index; +} + + +/* This function removes any compaction which was performed on TPA. */ + +static inline void +tpa_decompact(tpa_p tpa) +{ +#ifdef ENABLE_CHECKING + if (tpa->uncompressed_num == -1) + abort (); +#endif + tpa->num_trees = tpa->uncompressed_num; +} + + +/* Once a var_map has been created and compressed, a complimentary root_var + object can be built. This creates a list of all the root variables from + which ssa version names are derived. Each root variable has a list of + which partitions are versions of that root. + + This is implemented using the tree_partition_associator. + + The tree vector is used to represent the root variable. + The list of partitions represent SSA versions of the root variable. */ + +typedef tpa_p root_var_p; + +static inline tree root_var (root_var_p, int); +static inline int root_var_first_partition (root_var_p, int); +static inline int root_var_next_partition (root_var_p, int); +static inline int root_var_num (root_var_p); +static inline void root_var_dump (FILE *, root_var_p); +static inline void root_var_remove_partition (root_var_p, int, int); +static inline void root_var_delete (root_var_p); +static inline int root_var_find (root_var_p, int); +static inline int root_var_compact (root_var_p); +static inline void root_var_decompact (tpa_p); + +extern root_var_p root_var_init (var_map); + +/* Value returned when there are no more partitions associated with a root + variable. */ +#define ROOT_VAR_NONE TPA_NONE + + +/* Return the number of distinct root variables in RV. */ + +static inline int +root_var_num (root_var_p rv) +{ + return tpa_num_trees (rv); +} + + +/* Return root variable I from RV. */ + +static inline tree +root_var (root_var_p rv, int i) +{ + return tpa_tree (rv, i); +} + + +/* Return the first partition in RV belonging to root variable list I. */ + +static inline int +root_var_first_partition (root_var_p rv, int i) +{ + return tpa_first_partition (rv, i); +} + + +/* Return the next partition after partition I in a root list from RV. */ + +static inline int +root_var_next_partition (root_var_p rv, int i) +{ + return tpa_next_partition (rv, i); +} + + +/* Send debug info for root_var list RV to file F. */ + +static inline void +root_var_dump (FILE *f, root_var_p rv) +{ + fprintf (f, "\nRoot Var dump\n"); + tpa_dump (f, rv); + fprintf (f, "\n"); +} + + +/* Destroy root_var object RV. */ + +static inline void +root_var_delete (root_var_p rv) +{ + tpa_delete (rv); +} + + +/* Remove partition PARTITION_INDEX from root_var list ROOT_INDEX in RV. */ + +static inline void +root_var_remove_partition (root_var_p rv, int root_index, int partition_index) +{ + tpa_remove_partition (rv, root_index, partition_index); +} + + +/* Return the root_var list index for partition I in RV. */ + +static inline int +root_var_find (root_var_p rv, int i) +{ + return tpa_find_tree (rv, i); +} + + +/* Hide single element lists in RV. */ + +static inline int +root_var_compact (root_var_p rv) +{ + return tpa_compact (rv); +} + + +/* Expose the single element lists in RV. */ + +static inline void +root_var_decompact (root_var_p rv) +{ + tpa_decompact (rv); +} + + +/* A TYPE_VAR object is similar to a root_var object, except this associates + partitions with their type rather than their root variable. This is used to + coalesce memory locations based on type. */ + +typedef tpa_p type_var_p; + +static inline tree type_var (type_var_p, int); +static inline int type_var_first_partition (type_var_p, int); +static inline int type_var_next_partition (type_var_p, int); +static inline int type_var_num (type_var_p); +static inline void type_var_dump (FILE *, type_var_p); +static inline void type_var_remove_partition (type_var_p, int, int); +static inline void type_var_delete (type_var_p); +static inline int type_var_find (type_var_p, int); +static inline int type_var_compact (type_var_p); +static inline void type_var_decompact (type_var_p); + +extern type_var_p type_var_init (var_map); + +/* Value returned when there is no partitions associated with a list. */ +#define TYPE_VAR_NONE TPA_NONE + + +/* Return the number of distinct type lists in TV. */ + +static inline int +type_var_num (type_var_p tv) +{ + return tpa_num_trees (tv); +} + + +/* Return the type of list I in TV. */ + +static inline tree +type_var (type_var_p tv, int i) +{ + return tpa_tree (tv, i); +} + + +/* Return the first partition belonging to type list I in TV. */ + +static inline int +type_var_first_partition (type_var_p tv, int i) +{ + return tpa_first_partition (tv, i); +} + + +/* Return the next partition after partition I in a type list within TV. */ + +static inline int +type_var_next_partition (type_var_p tv, int i) +{ + return tpa_next_partition (tv, i); +} + + +/* Send debug info for type_var object TV to file F. */ + +static inline void +type_var_dump (FILE *f, type_var_p tv) +{ + fprintf (f, "\nType Var dump\n"); + tpa_dump (f, tv); + fprintf (f, "\n"); +} + + +/* Delete type_var object TV. */ + +static inline void +type_var_delete (type_var_p tv) +{ + tpa_delete (tv); +} + + +/* Remove partition PARTITION_INDEX from type list TYPE_INDEX in TV. */ + +static inline void +type_var_remove_partition (type_var_p tv, int type_index, int partition_index) +{ + tpa_remove_partition (tv, type_index, partition_index); +} + + +/* Return the type index in TV for the list partition I is in. */ + +static inline int +type_var_find (type_var_p tv, int i) +{ + return tpa_find_tree (tv, i); +} + + +/* Hide single element lists in TV. */ + +static inline int +type_var_compact (type_var_p tv) +{ + return tpa_compact (tv); +} + + +/* Expose single element lists in TV. */ + +static inline void +type_var_decompact (type_var_p tv) +{ + tpa_decompact (tv); +} + +/* This set of routines implements a coalesce_list. This is an object which + is used to track pairs of partitions which are desirable to coalesce + together at some point. Costs are associated with each pair, and when + all desired information has been collected, the object can be used to + order the pairs for processing. */ + +/* This structure defines a pair for coalescing. */ + +typedef struct partition_pair_d +{ + int first_partition; + int second_partition; + int cost; + struct partition_pair_d *next; +} *partition_pair_p; + +/* This structure maintains the list of coalesce pairs. + When add_mode is true, list is a triangular shaped list of coalesce pairs. + The smaller partition number is used to index the list, and the larger is + index is located in a partition_pair_p object. These lists are sorted from + smallest to largest by 'second_partition'. New coalesce pairs are allowed + to be added in this mode. + When add_mode is false, the lists have all been merged into list[0]. The + rest of the lists are not used. list[0] is ordered from most desirable + coalesce to least desirable. pop_best_coalesce() retrieves the pairs + one at a time. */ + +typedef struct coalesce_list_d +{ + var_map map; + partition_pair_p *list; + bool add_mode; +} *coalesce_list_p; + +extern coalesce_list_p create_coalesce_list (var_map); +extern void add_coalesce (coalesce_list_p, int, int, int); +extern void sort_coalesce_list (coalesce_list_p); +extern void dump_coalesce_list (FILE *, coalesce_list_p); +extern void delete_coalesce_list (coalesce_list_p); + +#define NO_BEST_COALESCE -1 +extern int pop_best_coalesce (coalesce_list_p, int *, int *); + +extern conflict_graph build_tree_conflict_graph (tree_live_info_p, tpa_p, + coalesce_list_p); +extern void coalesce_tpa_members (tpa_p tpa, conflict_graph graph, var_map map, + coalesce_list_p cl, FILE *); + + +#endif /* _TREE_SSA_LIVE_H */ diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c new file mode 100644 index 00000000000..c35b6a9633c --- /dev/null +++ b/gcc/tree-ssa-loop.c @@ -0,0 +1,365 @@ +/* Loop optimizations over tree-ssa. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "diagnostic.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-dump.h" +#include "tree-pass.h" +#include "timevar.h" +#include "cfgloop.h" +#include "flags.h" +#include "tree-inline.h" + + +/* Check whether we should duplicate HEADER of LOOP. At most *LIMIT + instructions should be duplicated, limit is decreased by the actual + amount. */ + +static bool +should_duplicate_loop_header_p (basic_block header, struct loop *loop, + int *limit) +{ + block_stmt_iterator bsi; + tree last; + + /* Do not copy one block more than once (we do not really want to do + loop peeling here). */ + if (header->aux) + return false; + + if (!header->succ) + abort (); + if (!header->succ->succ_next) + return false; + if (header->succ->succ_next->succ_next) + return false; + if (flow_bb_inside_loop_p (loop, header->succ->dest) + && flow_bb_inside_loop_p (loop, header->succ->succ_next->dest)) + return false; + + /* If this is not the original loop header, we want it to have just + one predecessor in order to match the && pattern. */ + if (header != loop->header + && header->pred->pred_next) + return false; + + last = last_stmt (header); + if (TREE_CODE (last) != COND_EXPR) + return false; + + /* Approximately copy the conditions that used to be used in jump.c -- + at most 20 insns and no calls. */ + for (bsi = bsi_start (header); !bsi_end_p (bsi); bsi_next (&bsi)) + { + last = bsi_stmt (bsi); + + if (TREE_CODE (last) == LABEL_EXPR) + continue; + + if (get_call_expr_in (last)) + return false; + + *limit -= estimate_num_insns (last); + if (*limit < 0) + return false; + } + + return true; +} + +/* Marks variables defined in basic block BB for rewriting. */ + +static void +mark_defs_for_rewrite (basic_block bb) +{ + tree stmt, var; + block_stmt_iterator bsi; + stmt_ann_t ann; + def_optype defs; + vdef_optype vdefs; + vuse_optype vuses; + unsigned i; + + for (stmt = phi_nodes (bb); stmt; stmt = TREE_CHAIN (stmt)) + { + var = SSA_NAME_VAR (PHI_RESULT (stmt)); + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + + /* If we have a type_mem_tag, add it as well. Due to rewriting the + variable out of ssa, we lose its name tag, so we use type_mem_tag + instead. */ + var = var_ann (var)->type_mem_tag; + if (var) + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + + defs = DEF_OPS (ann); + for (i = 0; i < NUM_DEFS (defs); i++) + { + var = SSA_NAME_VAR (DEF_OP (defs, i)); + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + + /* If we have a type_mem_tag, add it as well. Due to rewriting the + variable out of ssa, we lose its name tag, so we use type_mem_tag + instead. */ + var = var_ann (var)->type_mem_tag; + if (var) + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + var = SSA_NAME_VAR (VDEF_RESULT (vdefs, i)); + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + + /* We also need to rewrite vuses, since we will copy the statements + and the ssa versions could not be recovered in the copy. We do + not have to do this for operands of VDEFS explicitly, since + they have the same underlying variable as the results. */ + vuses = VUSE_OPS (ann); + for (i = 0; i < NUM_VUSES (vuses); i++) + { + var = SSA_NAME_VAR (VUSE_OP (vuses, i)); + bitmap_set_bit (vars_to_rename, var_ann (var)->uid); + } + } +} + +/* Duplicates destinations of edges in BBS_TO_DUPLICATE. */ + +static void +duplicate_blocks (varray_type bbs_to_duplicate) +{ + unsigned i; + edge preheader_edge, e, e1; + basic_block header, new_header; + tree phi; + size_t old_num_referenced_vars = num_referenced_vars; + + for (i = 0; i < VARRAY_ACTIVE_SIZE (bbs_to_duplicate); i++) + { + preheader_edge = VARRAY_GENERIC_PTR_NOGC (bbs_to_duplicate, i); + header = preheader_edge->dest; + + /* It is sufficient to rewrite the definitions, since the uses of + the operands defined outside of the duplicated basic block are + still valid (every basic block that dominates the original block + also dominates the duplicate). */ + mark_defs_for_rewrite (header); + } + + rewrite_vars_out_of_ssa (vars_to_rename); + + for (i = old_num_referenced_vars; i < num_referenced_vars; i++) + { + bitmap_set_bit (vars_to_rename, i); + var_ann (referenced_var (i))->out_of_ssa_tag = 0; + } + + for (i = 0; i < VARRAY_ACTIVE_SIZE (bbs_to_duplicate); i++) + { + preheader_edge = VARRAY_GENERIC_PTR_NOGC (bbs_to_duplicate, i); + header = preheader_edge->dest; + + /* We might have split the edge into the loop header when we have + eliminated the phi nodes, so find the edge to that we want to + copy the header. */ + while (!header->aux) + { + preheader_edge = header->succ; + header = preheader_edge->dest; + } + header->aux = NULL; + + new_header = duplicate_block (header, preheader_edge); + + /* Add the phi arguments to the outgoing edges. */ + for (e = header->succ; e; e = e->succ_next) + { + for (e1 = new_header->succ; e1->dest != e->dest; e1 = e1->succ_next) + continue; + + for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi)) + { + tree def = phi_element_for_edge (phi, e)->def; + add_phi_arg (&phi, def, e1); + } + } + } +} + +/* Checks whether LOOP is a do-while style loop. */ + +static bool +do_while_loop_p (struct loop *loop) +{ + tree stmt = last_stmt (loop->latch); + + /* If the latch of the loop is not empty, it is not a do-while loop. */ + if (stmt + && TREE_CODE (stmt) != LABEL_EXPR) + return false; + + /* If the header contains just a condition, it is not a do-while loop. */ + stmt = last_and_only_stmt (loop->header); + if (stmt + && TREE_CODE (stmt) == COND_EXPR) + return false; + + return true; +} + +/* For all loops, copy the condition at the end of the loop body in front + of the loop. This is beneficial since it increases effectivity of + code motion optimizations. It also saves one jump on entry to the loop. */ + +static void +copy_loop_headers (void) +{ + struct loops *loops; + unsigned i; + struct loop *loop; + basic_block header; + edge preheader_edge; + varray_type bbs_to_duplicate = NULL; + + loops = loop_optimizer_init (dump_file); + if (!loops) + return; + + /* We are not going to need or update dominators. */ + free_dominance_info (CDI_DOMINATORS); + + create_preheaders (loops, CP_SIMPLE_PREHEADERS); + + /* We do not try to keep the information about irreductible regions + up-to-date. */ + loops->state &= ~LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS; + +#ifdef ENABLE_CHECKING + verify_loop_structure (loops); +#endif + + for (i = 1; i < loops->num; i++) + { + /* Copy at most 20 insns. */ + int limit = 20; + + loop = loops->parray[i]; + preheader_edge = loop_preheader_edge (loop); + header = preheader_edge->dest; + + /* If the loop is already a do-while style one (either because it was + written as such, or because jump threading transformed it into one), + we might be in fact peeling the first iteration of the loop. This + in general is not a good idea. */ + if (do_while_loop_p (loop)) + continue; + + /* Iterate the header copying up to limit; this takes care of the cases + like while (a && b) {...}, where we want to have both of the conditions + copied. TODO -- handle while (a || b) - like cases, by not requiring + the header to have just a single successor and copying up to + postdominator. + + We do not really copy the blocks immediately, so that we do not have + to worry about updating loop structures, and also so that we do not + have to rewrite variables out of and into ssa form for each block. + Instead we just record the block into worklist and duplicate all of + them at once. */ + while (should_duplicate_loop_header_p (header, loop, &limit)) + { + if (!bbs_to_duplicate) + VARRAY_GENERIC_PTR_NOGC_INIT (bbs_to_duplicate, 10, + "bbs_to_duplicate"); + VARRAY_PUSH_GENERIC_PTR_NOGC (bbs_to_duplicate, preheader_edge); + header->aux = &header->aux; + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + "Scheduled basic block %d for duplication.\n", + header->index); + + /* Find a successor of header that is inside a loop; i.e. the new + header after the condition is copied. */ + if (flow_bb_inside_loop_p (loop, header->succ->dest)) + preheader_edge = header->succ; + else + preheader_edge = header->succ->succ_next; + header = preheader_edge->dest; + } + } + + loop_optimizer_finalize (loops, NULL); + + if (bbs_to_duplicate) + { + duplicate_blocks (bbs_to_duplicate); + VARRAY_FREE (bbs_to_duplicate); + } + + /* Run cleanup_tree_cfg here regardless of whether we have done anything, so + that we cleanup the blocks created in order to get the loops into a + canonical shape. */ + cleanup_tree_cfg (); +} + +static bool +gate_ch (void) +{ + return flag_tree_ch != 0; +} + +struct tree_opt_pass pass_ch = +{ + "ch", /* name */ + gate_ch, /* gate */ + copy_loop_headers, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_CH, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + (TODO_rename_vars + | TODO_dump_func + | TODO_verify_ssa) /* todo_flags_finish */ +}; diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c new file mode 100644 index 00000000000..a399e1d2ec9 --- /dev/null +++ b/gcc/tree-ssa-operands.c @@ -0,0 +1,1318 @@ +/* SSA operands management for trees. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "function.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "tree-pass.h" +#include "ggc.h" +#include "timevar.h" + +/* Flags to describe operand properties in get_stmt_operands and helpers. */ + +/* By default, operands are loaded. */ +#define opf_none 0 + +/* Operand is the target of an assignment expression. */ +#define opf_is_def (1 << 0) + +/* No virtual operands should be created in the expression. This is used + when traversing ADDR_EXPR nodes which have different semantics than + other expressions. Inside an ADDR_EXPR node, the only operands that we + need to consider are indices into arrays. For instance, &a.b[i] should + generate a USE of 'i' but it should not generate a VUSE for 'a' nor a + VUSE for 'b'. */ +#define opf_no_vops (1 << 1) + +/* Array for building all the def operands. */ +static GTY (()) varray_type build_defs; + +/* Array for building all the use operands. */ +static GTY (()) varray_type build_uses; + +/* Array for building all the vdef operands. */ +static GTY (()) varray_type build_vdefs; + +/* Array for building all the vuse operands. */ +static GTY (()) varray_type build_vuses; + +#ifdef ENABLE_CHECKING +tree check_build_stmt; +#endif + +typedef struct voperands_d +{ + vdef_optype vdef_ops; + vuse_optype vuse_ops; +} *voperands_t; + +static void note_addressable (tree, stmt_ann_t); +static void get_expr_operands (tree, tree *, int, voperands_t); +static inline void append_def (tree *, tree); +static inline void append_use (tree *, tree); +static void append_vdef (tree, tree, voperands_t); +static void add_call_clobber_ops (tree, voperands_t); +static void add_call_read_ops (tree, voperands_t); +static void add_stmt_operand (tree *, tree, int, voperands_t); + + +struct freelist_d GTY((chain_next ("%h.next"))) +{ + struct freelist_d *next; +}; + +#define NUM_FREE 4 +static GTY ((length ("NUM_FREE"))) struct freelist_d optype_freelist[NUM_FREE] = { {0}, {0}, {0}, {0} }; + + +static inline void * +check_optype_freelist (size_t num ATTRIBUTE_UNUSED) +{ + return NULL; +#if 0 + void *vec = NULL; + + if (num <= NUM_FREE && optype_freelist[num - 1].next) + { + vec = (void *)optype_freelist[num - 1].next; + optype_freelist[num - 1].next = optype_freelist[num - 1].next->next; + } + return vec; +#endif +} +/* Return a vector of contiguous memory of a specified size. */ + + +static inline void +add_optype_freelist (void *vec ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED) +{ +#if 0 + struct freelist_d *ptr; +#ifdef ENABLE_CHECKING + if (size == 0) + abort (); +#endif + + /* if its bigger than one of our lists, simply let it go and let GC + collect it. */ + if (size > NUM_FREE) + return; + + ptr = vec; + ptr->next = optype_freelist[size - 1].next;; + optype_freelist[size - 1].next = ptr; +#endif +} + + +static inline def_optype +allocate_def_optype (unsigned num) +{ + def_optype def_ops; + unsigned size; + size = sizeof (struct def_optype_d) + sizeof (tree *) * (num - 1); + def_ops = check_optype_freelist (num); + if (!def_ops) + def_ops = ggc_alloc (size); + def_ops->num_defs = num; + return def_ops; +} + +static inline use_optype +allocate_use_optype (unsigned num) +{ + use_optype use_ops; + unsigned size; + size = sizeof (struct use_optype_d) + sizeof (tree *) * (num - 1); + use_ops = check_optype_freelist (num); + if (!use_ops) + use_ops = ggc_alloc (size); + use_ops->num_uses = num; + return use_ops; +} + +static inline vdef_optype +allocate_vdef_optype (unsigned num) +{ + vdef_optype vdef_ops; + unsigned size; + size = sizeof (struct vdef_optype_d) + sizeof (tree) * ((num * 2) - 1); + vdef_ops = check_optype_freelist (num * 2); + if (!vdef_ops) + vdef_ops = ggc_alloc (size); + vdef_ops->num_vdefs = num; + return vdef_ops; +} + +static inline vuse_optype +allocate_vuse_optype (unsigned num) +{ + vuse_optype vuse_ops; + unsigned size; + size = sizeof (struct vuse_optype_d) + sizeof (tree) * (num - 1); + vuse_ops = check_optype_freelist (num); + if (!vuse_ops) + vuse_ops = ggc_alloc (size); + vuse_ops->num_vuses = num; + return vuse_ops; +} + +static inline void +free_uses (use_optype *uses, bool dealloc) +{ + if (*uses) + { + if (dealloc) + add_optype_freelist (*uses, (*uses)->num_uses); + *uses = NULL; + } +} + +static inline void +free_defs (def_optype *defs, bool dealloc) +{ + if (*defs) + { + if (dealloc) + add_optype_freelist (*defs, (*defs)->num_defs); + *defs = NULL; + } +} + +static inline void +free_vuses (vuse_optype *vuses, bool dealloc) +{ + if (*vuses) + { + if (dealloc) + add_optype_freelist (*vuses, (*vuses)->num_vuses); + *vuses = NULL; + } +} + +static inline void +free_vdefs (vdef_optype *vdefs, bool dealloc) +{ + if (*vdefs) + { + if (dealloc) + add_optype_freelist (*vdefs, (*vdefs)->num_vdefs); + *vdefs = NULL; + } +} + +void +remove_vuses (tree stmt) +{ + stmt_ann_t ann; + + ann = stmt_ann (stmt); + if (ann) + free_vuses (&(ann->vuse_ops), true); +} + +void +remove_vdefs (tree stmt) +{ + stmt_ann_t ann; + + ann = stmt_ann (stmt); + if (ann) + free_vdefs (&(ann->vdef_ops), true); +} + + +void +init_ssa_operands (void) +{ + int x; + + VARRAY_TREE_PTR_INIT (build_defs, 5, "build defs"); + VARRAY_TREE_PTR_INIT (build_uses, 10, "build uses"); + VARRAY_TREE_INIT (build_vdefs, 10, "build vdefs"); + VARRAY_TREE_INIT (build_vuses, 10, "build vuses"); + + for (x = 0; x < NUM_FREE; x++) + optype_freelist[x].next = NULL; +} + +void +fini_ssa_operands (void) +{ + int x; + for (x = 0; x < NUM_FREE; x++) + optype_freelist[x].next = NULL; +} + +static void +finalize_ssa_defs (tree stmt) +{ + unsigned num, x; + stmt_ann_t ann; + def_optype def_ops; + + num = VARRAY_ACTIVE_SIZE (build_defs); + if (num == 0) + return; + +#ifdef ENABLE_CHECKING + /* There should only be a single real definition per assignment. */ + if (TREE_CODE (stmt) == MODIFY_EXPR && num > 1) + abort (); +#endif + + def_ops = allocate_def_optype (num); + for (x = 0; x < num ; x++) + def_ops->defs[x] = VARRAY_TREE_PTR (build_defs, x); + VARRAY_POP_ALL (build_defs); + + ann = stmt_ann (stmt); + ann->def_ops = def_ops; +} + +static void +finalize_ssa_uses (tree stmt) +{ + unsigned num, x; + use_optype use_ops; + stmt_ann_t ann; + + num = VARRAY_ACTIVE_SIZE (build_uses); + if (num == 0) + return; + +#ifdef ENABLE_CHECKING + { + unsigned x; + /* If the pointer to the operand is the statement itself, something is + wrong. It means that we are pointing to a local variable (the + initial call to get_stmt_operands does not pass a pointer to a + statement). */ + for (x = 0; x < num; x++) + if (*(VARRAY_TREE_PTR (build_uses, x)) == stmt) + abort (); + } +#endif + + use_ops = allocate_use_optype (num); + for (x = 0; x < num ; x++) + use_ops->uses[x] = VARRAY_TREE_PTR (build_uses, x); + VARRAY_POP_ALL (build_uses); + + ann = stmt_ann (stmt); + ann->use_ops = use_ops; +} + +static void +finalize_ssa_vdefs (tree stmt) +{ + unsigned num, x; + vdef_optype vdef_ops; + stmt_ann_t ann; + + num = VARRAY_ACTIVE_SIZE (build_vdefs); + if (num == 0) + return; + +#ifdef ENABLE_CHECKING + /* VDEFs must be entered in pairs of result/uses. */ + if (num % 2 != 0) + abort(); +#endif + + vdef_ops = allocate_vdef_optype (num / 2); + for (x = 0; x < num; x++) + vdef_ops->vdefs[x] = VARRAY_TREE (build_vdefs, x); + VARRAY_CLEAR (build_vdefs); + + ann = stmt_ann (stmt); + ann->vdef_ops = vdef_ops; +} + +static inline void +finalize_ssa_vuses (tree stmt) +{ + unsigned num, x; + stmt_ann_t ann; + vuse_optype vuse_ops; + vdef_optype vdefs; + +#ifdef ENABLE_CHECKING + if (VARRAY_ACTIVE_SIZE (build_vdefs) > 0) + { + fprintf (stderr, "Please finalize VDEFs before finalize VUSES.\n"); + abort (); + } +#endif + + num = VARRAY_ACTIVE_SIZE (build_vuses); + if (num == 0) + return; + + /* Remove superfluous VUSE operands. If the statement already has a + VDEF operation for a variable 'a', then a VUSE for 'a' is not + needed because VDEFs imply a VUSE of the variable. For instance, + suppose that variable 'a' is aliased: + + # VUSE + # a_3 = VDEF + a = a + 1; + + The VUSE is superfluous because it is implied by the VDEF + operation. */ + + ann = stmt_ann (stmt); + vdefs = VDEF_OPS (ann); + if (NUM_VDEFS (vdefs) > 0) + { + size_t i, j; + for (i = 0; i < VARRAY_ACTIVE_SIZE (build_vuses); i++) + { + bool found = false; + for (j = 0; j < NUM_VDEFS (vdefs); j++) + { + tree vuse_var, vdef_var; + tree vuse = VARRAY_TREE (build_vuses, i); + tree vdef = VDEF_OP (vdefs, j); + + if (TREE_CODE (vuse) == SSA_NAME) + vuse_var = SSA_NAME_VAR (vuse); + else + vuse_var = vuse; + + if (TREE_CODE (vdef) == SSA_NAME) + vdef_var = SSA_NAME_VAR (vdef); + else + vdef_var = vdef; + + if (vuse_var == vdef_var) + { + found = true; + break; + } + } + + /* If we found a useless VUSE operand, remove it from the + operand array by replacing it with the last active element + in the operand array (unless the useless VUSE was the + last operand, in which case we simply remove it. */ + if (found) + { + if (i != VARRAY_ACTIVE_SIZE (build_vuses) - 1) + { + VARRAY_TREE (build_vuses, i) + = VARRAY_TREE (build_vuses, + VARRAY_ACTIVE_SIZE (build_vuses) - 1); + } + VARRAY_POP (build_vuses); + + /* We want to rescan the element at this index, unless + this was the last element, in which case the loop + terminates. */ + i--; + } + } + } + + num = VARRAY_ACTIVE_SIZE (build_vuses); + /* We could have reduced the size to zero now, however. */ + if (num == 0) + return; + + vuse_ops = allocate_vuse_optype (num); + for (x = 0; x < num; x++) + vuse_ops->vuses[x] = VARRAY_TREE (build_vuses, x); + VARRAY_CLEAR (build_vuses); + ann->vuse_ops = vuse_ops; +} + +extern void +finalize_ssa_stmt_operands (tree stmt) +{ +#ifdef ENABLE_CHECKING + if (check_build_stmt == NULL) + abort(); +#endif + + finalize_ssa_defs (stmt); + finalize_ssa_uses (stmt); + finalize_ssa_vdefs (stmt); + finalize_ssa_vuses (stmt); + +#ifdef ENABLE_CHECKING + check_build_stmt = NULL; +#endif +} + + +extern void +verify_start_operands (tree stmt ATTRIBUTE_UNUSED) +{ +#ifdef ENABLE_CHECKING + if (VARRAY_ACTIVE_SIZE (build_defs) > 0 + || VARRAY_ACTIVE_SIZE (build_uses) > 0 + || VARRAY_ACTIVE_SIZE (build_vuses) > 0 + || VARRAY_ACTIVE_SIZE (build_vdefs) > 0) + abort (); + if (check_build_stmt != NULL) + abort(); + check_build_stmt = stmt; +#endif +} + + +/* Add DEF_P to the list of pointers to operands defined by STMT. */ + +static inline void +append_def (tree *def_p, tree stmt ATTRIBUTE_UNUSED) +{ +#ifdef ENABLE_CHECKING + if (check_build_stmt != stmt) + abort(); +#endif + VARRAY_PUSH_TREE_PTR (build_defs, def_p); +} + + +/* Add USE_P to the list of pointers to operands used by STMT. */ + +static inline void +append_use (tree *use_p, tree stmt ATTRIBUTE_UNUSED) +{ +#ifdef ENABLE_CHECKING + if (check_build_stmt != stmt) + abort(); +#endif + VARRAY_PUSH_TREE_PTR (build_uses, use_p); +} + + +/* Add a new virtual def for variable VAR to statement STMT. If PREV_VOPS + is not NULL, the existing entries are preserved and no new entries are + added here. This is done to preserve the SSA numbering of virtual + operands. */ + +static void +append_vdef (tree var, tree stmt, voperands_t prev_vops) +{ + stmt_ann_t ann; + size_t i; + tree result, source; + +#ifdef ENABLE_CHECKING + if (check_build_stmt != stmt) + abort(); +#endif + + ann = stmt_ann (stmt); + + /* Don't allow duplicate entries. */ + + for (i = 0; i < VARRAY_ACTIVE_SIZE (build_vdefs); i += 2) + { + tree result = VARRAY_TREE (build_vdefs, i); + if (var == result + || (TREE_CODE (result) == SSA_NAME + && var == SSA_NAME_VAR (result))) + return; + } + + /* If the statement already had virtual definitions, see if any of the + existing VDEFs matches VAR. If so, re-use it, otherwise add a new + VDEF for VAR. */ + result = NULL_TREE; + source = NULL_TREE; + if (prev_vops) + for (i = 0; i < NUM_VDEFS (prev_vops->vdef_ops); i++) + { + result = VDEF_RESULT (prev_vops->vdef_ops, i); + if (result == var + || (TREE_CODE (result) == SSA_NAME + && SSA_NAME_VAR (result) == var)) + { + source = VDEF_OP (prev_vops->vdef_ops, i); + break; + } + } + + /* If no previous VDEF operand was found for VAR, create one now. */ + if (source == NULL_TREE) + { + result = var; + source = var; + } + + VARRAY_PUSH_TREE (build_vdefs, result); + VARRAY_PUSH_TREE (build_vdefs, source); +} + + +/* Add VAR to the list of virtual uses for STMT. If PREV_VOPS + is not NULL, the existing entries are preserved and no new entries are + added here. This is done to preserve the SSA numbering of virtual + operands. */ + +static void +append_vuse (tree var, tree stmt, voperands_t prev_vops) +{ + stmt_ann_t ann; + size_t i; + bool found; + tree vuse; + +#ifdef ENABLE_CHECKING + if (check_build_stmt != stmt) + abort(); +#endif + + ann = stmt_ann (stmt); + + /* Don't allow duplicate entries. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (build_vuses); i++) + { + tree vuse_var = VARRAY_TREE (build_vuses, i); + if (var == vuse_var + || (TREE_CODE (vuse_var) == SSA_NAME + && var == SSA_NAME_VAR (vuse_var))) + return; + } + + /* If the statement already had virtual uses, see if any of the + existing VUSEs matches VAR. If so, re-use it, otherwise add a new + VUSE for VAR. */ + found = false; + vuse = NULL_TREE; + if (prev_vops) + for (i = 0; i < NUM_VUSES (prev_vops->vuse_ops); i++) + { + vuse = VUSE_OP (prev_vops->vuse_ops, i); + if (vuse == var + || (TREE_CODE (vuse) == SSA_NAME + && SSA_NAME_VAR (vuse) == var)) + { + found = true; + break; + } + } + + /* If VAR existed already in PREV_VOPS, re-use it. */ + if (found) + var = vuse; + + VARRAY_PUSH_TREE (build_vuses, var); +} + + +/* External entry point which by-passes the previous vops mechanism. */ +void +add_vuse (tree var, tree stmt) +{ + append_vuse (var, stmt, NULL); +} + + +/* Get the operands of statement STMT. Note that repeated calls to + get_stmt_operands for the same statement will do nothing until the + statement is marked modified by a call to modify_stmt(). */ + +void +get_stmt_operands (tree stmt) +{ + enum tree_code code; + stmt_ann_t ann; + struct voperands_d prev_vops; + +#if defined ENABLE_CHECKING + /* The optimizers cannot handle statements that are nothing but a + _DECL. This indicates a bug in the gimplifier. */ + if (SSA_VAR_P (stmt)) + abort (); +#endif + + /* Ignore error statements. */ + if (TREE_CODE (stmt) == ERROR_MARK) + return; + + ann = get_stmt_ann (stmt); + + /* If the statement has not been modified, the operands are still valid. */ + if (!ann->modified) + return; + + timevar_push (TV_TREE_OPS); + + /* Initially assume that the statement has no volatile operands. + Statements marked with 'has_volatile_ops' are not processed by the + optimizers. */ + ann->has_volatile_ops = false; + + /* Remove any existing operands as they will be scanned again. */ + free_defs (&(ann->def_ops), true); + free_uses (&(ann->use_ops), true); + + /* Before removing existing virtual operands, save them in PREV_VOPS so + that we can re-use their SSA versions. */ + prev_vops.vdef_ops = VDEF_OPS (ann); + prev_vops.vuse_ops = VUSE_OPS (ann); + + /* Dont free the previous values to memory since we're still using them. */ + free_vdefs (&(ann->vdef_ops), false); + free_vuses (&(ann->vuse_ops), false); + + start_ssa_stmt_operands (stmt); + + code = TREE_CODE (stmt); + switch (code) + { + case MODIFY_EXPR: + get_expr_operands (stmt, &TREE_OPERAND (stmt, 1), opf_none, &prev_vops); + get_expr_operands (stmt, &TREE_OPERAND (stmt, 0), opf_is_def, &prev_vops); + break; + + case COND_EXPR: + get_expr_operands (stmt, &COND_EXPR_COND (stmt), opf_none, &prev_vops); + break; + + case SWITCH_EXPR: + get_expr_operands (stmt, &SWITCH_COND (stmt), opf_none, &prev_vops); + break; + + case ASM_EXPR: + { + int noutputs = list_length (ASM_OUTPUTS (stmt)); + const char **oconstraints + = (const char **) alloca ((noutputs) * sizeof (const char *)); + int i; + tree link; + const char *constraint; + bool allows_mem, allows_reg, is_inout; + + for (i=0, link = ASM_OUTPUTS (stmt); link; + ++i, link = TREE_CHAIN (link)) + { + oconstraints[i] = constraint + = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); + parse_output_constraint (&constraint, i, 0, 0, + &allows_mem, &allows_reg, &is_inout); + if (allows_reg && is_inout) + /* This should have been split in gimplify_asm_expr. */ + abort (); + + if (!allows_reg && allows_mem) + { + tree t = get_base_address (TREE_VALUE (link)); + if (t && DECL_P (t)) + mark_call_clobbered (t); + } + + get_expr_operands (stmt, &TREE_VALUE (link), opf_is_def, + &prev_vops); + } + + for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link)) + { + constraint + = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); + parse_input_constraint (&constraint, 0, 0, noutputs, 0, + oconstraints, &allows_mem, &allows_reg); + + if (!allows_reg && allows_mem) + { + tree t = get_base_address (TREE_VALUE (link)); + if (t && DECL_P (t)) + mark_call_clobbered (t); + } + + get_expr_operands (stmt, &TREE_VALUE (link), 0, &prev_vops); + } + + /* Clobber memory for asm ("" : : : "memory"); */ + for (link = ASM_CLOBBERS (stmt); link; link = TREE_CHAIN (link)) + if (!strcmp (TREE_STRING_POINTER (TREE_VALUE (link)), "memory")) + add_call_clobber_ops (stmt, &prev_vops); + } + break; + + case RETURN_EXPR: + get_expr_operands (stmt, &TREE_OPERAND (stmt, 0), opf_none, &prev_vops); + break; + + case GOTO_EXPR: + get_expr_operands (stmt, &GOTO_DESTINATION (stmt), opf_none, &prev_vops); + break; + + case LABEL_EXPR: + get_expr_operands (stmt, &LABEL_EXPR_LABEL (stmt), opf_none, &prev_vops); + break; + + /* These nodes contain no variable references. */ + case BIND_EXPR: + case CASE_LABEL_EXPR: + case TRY_CATCH_EXPR: + case TRY_FINALLY_EXPR: + case EH_FILTER_EXPR: + case CATCH_EXPR: + case RESX_EXPR: + break; + + default: + /* Notice that if get_expr_operands tries to use &STMT as the operand + pointer (which may only happen for USE operands), we will abort in + append_use. This default will handle statements like empty statements, + CALL_EXPRs or VA_ARG_EXPRs that may appear on the RHS of a statement + or as statements themselves. */ + get_expr_operands (stmt, &stmt, opf_none, &prev_vops); + break; + } + + finalize_ssa_stmt_operands (stmt); + + /* Now free the previous virtual ops to memory. */ + free_vdefs (&(prev_vops.vdef_ops), true); + free_vuses (&(prev_vops.vuse_ops), true); + + /* Clear the modified bit for STMT. Subsequent calls to + get_stmt_operands for this statement will do nothing until the + statement is marked modified by a call to modify_stmt(). */ + ann->modified = 0; + + timevar_pop (TV_TREE_OPS); +} + + +/* Recursively scan the expression pointed by EXPR_P in statement STMT. + FLAGS is one of the OPF_* constants modifying how to interpret the + operands found. PREV_VOPS is as in append_vdef and append_vuse. */ + +static void +get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops) +{ + enum tree_code code; + char class; + tree expr = *expr_p; + + if (expr == NULL || expr == error_mark_node) + return; + + code = TREE_CODE (expr); + class = TREE_CODE_CLASS (code); + + /* Expressions that make no memory references. */ + if (class == 'c' + || class == 't' + || class == 'b' + || code == FUNCTION_DECL + || code == EXC_PTR_EXPR + || code == FILTER_EXPR + || code == LABEL_DECL) + return; + + /* We could have the address of a component, array member, etc which + has interesting variable references. */ + if (code == ADDR_EXPR) + { + enum tree_code subcode = TREE_CODE (TREE_OPERAND (expr, 0)); + + /* Taking the address of a variable does not represent a + reference to it, but the fact that STMT takes its address will be + of interest to some passes (e.g. alias resolution). */ + add_stmt_operand (expr_p, stmt, 0, NULL); + + /* If the address is invariant, there may be no interesting variable + references inside. */ + if (is_gimple_min_invariant (expr)) + return; + + /* There should be no VUSEs created, since the referenced objects are + not really accessed. The only operands that we should find here + are ARRAY_REF indices which will always be real operands (GIMPLE + does not allow non-registers as array indices). */ + flags |= opf_no_vops; + + /* Avoid recursion. */ + code = subcode; + class = TREE_CODE_CLASS (code); + expr_p = &TREE_OPERAND (expr, 0); + expr = *expr_p; + } + + /* If we found a variable, add it to DEFS or USES depending on the + operand flags. */ + if (SSA_VAR_P (expr)) + { + add_stmt_operand (expr_p, stmt, flags, prev_vops); + return; + } + + /* Pointer dereferences always represent a use of the base pointer. */ + if (code == INDIRECT_REF) + { + tree *pptr = &TREE_OPERAND (expr, 0); + tree ptr = *pptr; + + if (SSA_VAR_P (ptr)) + { + if (!aliases_computed_p) + { + /* If the pointer does not have a memory tag and aliases have not + been computed yet, mark the statement as having volatile + operands to prevent DOM from entering it in equivalence tables + and DCE from killing it. */ + stmt_ann (stmt)->has_volatile_ops = true; + } + else + { + ssa_name_ann_t ptr_ann = NULL; + + /* If we have computed aliasing already, check if PTR has + flow-sensitive points-to information. */ + if (TREE_CODE (ptr) == SSA_NAME + && (ptr_ann = ssa_name_ann (ptr)) != NULL + && ptr_ann->name_mem_tag) + { + /* PTR has its own memory tag. Use it. */ + add_stmt_operand (&ptr_ann->name_mem_tag, stmt, flags, + prev_vops); + } + else + { + /* If PTR is not an SSA_NAME or it doesn't have a name + tag, use its type memory tag. */ + var_ann_t ann; + + /* If we are emitting debugging dumps, display a warning if + PTR is an SSA_NAME with no flow-sensitive alias + information. That means that we may need to compute + aliasing again. */ + if (dump_file + && TREE_CODE (ptr) == SSA_NAME + && ptr_ann == NULL) + { + fprintf (dump_file, + "NOTE: no flow-sensitive alias info for "); + print_generic_expr (dump_file, ptr, dump_flags); + fprintf (dump_file, " in "); + print_generic_stmt (dump_file, stmt, dump_flags); + } + + if (TREE_CODE (ptr) == SSA_NAME) + ptr = SSA_NAME_VAR (ptr); + ann = var_ann (ptr); + add_stmt_operand (&ann->type_mem_tag, stmt, flags, prev_vops); + } + } + } + + /* If a constant is used as a pointer, we can't generate a real + operand for it but we mark the statement volatile to prevent + optimizations from messing things up. */ + else if (TREE_CODE (ptr) == INTEGER_CST) + { + stmt_ann (stmt)->has_volatile_ops = true; + return; + } + + /* Everything else *should* have been folded elsewhere, but users + are smarter than we in finding ways to write invalid code. We + cannot just abort here. If we were absolutely certain that we + do handle all valid cases, then we could just do nothing here. + That seems optimistic, so attempt to do something logical... */ + else if ((TREE_CODE (ptr) == PLUS_EXPR || TREE_CODE (ptr) == MINUS_EXPR) + && TREE_CODE (TREE_OPERAND (ptr, 0)) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (ptr, 1)) == INTEGER_CST) + { + /* Make sure we know the object is addressable. */ + pptr = &TREE_OPERAND (ptr, 0); + add_stmt_operand (pptr, stmt, 0, NULL); + + /* Mark the object itself with a VUSE. */ + pptr = &TREE_OPERAND (*pptr, 0); + get_expr_operands (stmt, pptr, flags, prev_vops); + return; + } + + /* Ok, this isn't even is_gimple_min_invariant. Something's broke. */ + else + abort (); + + /* Add a USE operand for the base pointer. */ + get_expr_operands (stmt, pptr, opf_none, prev_vops); + return; + } + + /* Treat array references as references to the virtual variable + representing the array. The virtual variable for an ARRAY_REF + is the VAR_DECL for the array. */ + if (code == ARRAY_REF) + { + /* Add the virtual variable for the ARRAY_REF to VDEFS or VUSES + according to the value of IS_DEF. Recurse if the LHS of the + ARRAY_REF node is not a regular variable. */ + if (SSA_VAR_P (TREE_OPERAND (expr, 0))) + add_stmt_operand (expr_p, stmt, flags, prev_vops); + else + get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops); + + get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none, prev_vops); + return; + } + + /* Similarly to arrays, references to compound variables (complex types + and structures/unions) are globbed. + + FIXME: This means that + + a.x = 6; + a.y = 7; + foo (a.x, a.y); + + will not be constant propagated because the two partial + definitions to 'a' will kill each other. Note that SRA may be + able to fix this problem if 'a' can be scalarized. */ + if (code == IMAGPART_EXPR || code == REALPART_EXPR || code == COMPONENT_REF) + { + /* If the LHS of the compound reference is not a regular variable, + recurse to keep looking for more operands in the subexpression. */ + if (SSA_VAR_P (TREE_OPERAND (expr, 0))) + add_stmt_operand (expr_p, stmt, flags, prev_vops); + else + get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops); + + return; + } + + /* Function calls. Add every argument to USES. If the callee is + neither pure nor const, create a VDEF reference for GLOBAL_VAR + (See find_vars_r). */ + if (code == CALL_EXPR) + { + tree op; + int call_flags = call_expr_flags (expr); + + /* Find uses in the called function. */ + get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_none, prev_vops); + + for (op = TREE_OPERAND (expr, 1); op; op = TREE_CHAIN (op)) + get_expr_operands (stmt, &TREE_VALUE (op), opf_none, prev_vops); + + get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none, prev_vops); + + if (bitmap_first_set_bit (call_clobbered_vars) >= 0) + { + if (!(call_flags + & (ECF_PURE + | ECF_CONST + | ECF_NORETURN + | ECF_MALLOC + | ECF_MAY_BE_ALLOCA))) + add_call_clobber_ops (stmt, prev_vops); + else if (!(call_flags & (ECF_CONST | ECF_NORETURN))) + add_call_read_ops (stmt, prev_vops); + } + else if (!aliases_computed_p) + stmt_ann (stmt)->has_volatile_ops = true; + + return; + } + + /* Lists. */ + if (code == TREE_LIST) + { + tree op; + + for (op = expr; op; op = TREE_CHAIN (op)) + get_expr_operands (stmt, &TREE_VALUE (op), flags, prev_vops); + + return; + } + + /* Assignments. */ + if (code == MODIFY_EXPR) + { + get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none, prev_vops); + get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_is_def, prev_vops); + return; + } + + + /* Mark VA_ARG_EXPR nodes as making volatile references. FIXME, + this is needed because we currently do not gimplify VA_ARG_EXPR + properly. */ + if (code == VA_ARG_EXPR) + { + stmt_ann (stmt)->has_volatile_ops = true; + return; + } + + /* Unary expressions. */ + if (class == '1' + || code == TRUTH_NOT_EXPR + || code == BIT_FIELD_REF + || code == CONSTRUCTOR) + { + get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops); + return; + } + + /* Binary expressions. */ + if (class == '2' + || class == '<' + || code == TRUTH_AND_EXPR + || code == TRUTH_OR_EXPR + || code == TRUTH_XOR_EXPR + || code == COMPOUND_EXPR) + { + get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops); + get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags, prev_vops); + return; + } + + /* If we get here, something has gone wrong. */ + fprintf (stderr, "unhandled expression in get_expr_operands():\n"); + debug_tree (expr); + fputs ("\n", stderr); + abort (); +} + + +/* Add *VAR_P to the appropriate operand array of STMT. FLAGS is as in + get_expr_operands. If *VAR_P is a GIMPLE register, it will be added to + the statement's real operands, otherwise it is added to virtual + operands. + + PREV_VOPS is used when adding virtual operands to statements that + already had them (See append_vdef and append_vuse). */ + +static void +add_stmt_operand (tree *var_p, tree stmt, int flags, voperands_t prev_vops) +{ + bool is_real_op; + tree var, sym; + stmt_ann_t s_ann; + var_ann_t v_ann; + + var = *var_p; + STRIP_NOPS (var); + + s_ann = stmt_ann (stmt); + + /* If the operand is an ADDR_EXPR, add its operand to the list of + variables that have had their address taken in this statement. */ + if (TREE_CODE (var) == ADDR_EXPR) + { + note_addressable (TREE_OPERAND (var, 0), s_ann); + return; + } + + /* If the original variable is not a scalar, it will be added to the list + of virtual operands. In that case, use its base symbol as the virtual + variable representing it. */ + is_real_op = is_gimple_reg (var); + if (!is_real_op && !DECL_P (var)) + var = get_virtual_var (var); + + /* If VAR is not a variable that we care to optimize, do nothing. */ + if (var == NULL_TREE || !SSA_VAR_P (var)) + return; + + sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var); + v_ann = var_ann (sym); + + /* FIXME: We currently refuse to optimize variables that have hidden uses + (variables used in VLA declarations, MD builtin calls and variables + from the parent function in nested functions). This is because not + all uses of these variables are exposed in the IL or the statements + that reference them are not in GIMPLE form. If that's the case, mark + the statement as having volatile operands and return. */ + if (v_ann->has_hidden_use) + { + s_ann->has_volatile_ops = true; + return; + } + + /* Don't expose volatile variables to the optimizers. */ + if (TREE_THIS_VOLATILE (sym)) + { + s_ann->has_volatile_ops = true; + return; + } + + if (is_real_op) + { + /* The variable is a GIMPLE register. Add it to real operands. */ + if (flags & opf_is_def) + append_def (var_p, stmt); + else + append_use (var_p, stmt); + } + else + { + varray_type aliases; + + /* The variable is not a GIMPLE register. Add it (or its aliases) to + virtual operands, unless the caller has specifically requested + not to add virtual operands (used when adding operands inside an + ADDR_EXPR expression). */ + if (flags & opf_no_vops) + return; + + aliases = v_ann->may_aliases; + + /* If alias information hasn't been computed yet, then + addressable variables will not be an alias tag nor will they + have aliases. In this case, mark the statement as having + volatile operands. */ + if (!aliases_computed_p && may_be_aliased (var)) + s_ann->has_volatile_ops = true; + + if (aliases == NULL) + { + /* The variable is not aliased or it is an alias tag. */ + if (flags & opf_is_def) + { + append_vdef (var, stmt, prev_vops); + if (v_ann->is_alias_tag) + s_ann->makes_aliased_stores = 1; + } + else + { + append_vuse (var, stmt, prev_vops); + if (v_ann->is_alias_tag) + s_ann->makes_aliased_loads = 1; + } + } + else + { + size_t i; + + /* The variable is aliased. Add its aliases to the virtual + operands. */ + if (VARRAY_ACTIVE_SIZE (aliases) == 0) + abort (); + + if (flags & opf_is_def) + { + /* If the variable is also an alias tag, add a virtual + operand for it, otherwise we will miss representing + references to the members of the variable's alias set. + This fixes the bug in gcc.c-torture/execute/20020503-1.c. */ + if (v_ann->is_alias_tag) + append_vdef (var, stmt, prev_vops); + + for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++) + append_vdef (VARRAY_TREE (aliases, i), stmt, prev_vops); + + s_ann->makes_aliased_stores = 1; + } + else + { + if (v_ann->is_alias_tag) + append_vuse (var, stmt, prev_vops); + + for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++) + append_vuse (VARRAY_TREE (aliases, i), stmt, prev_vops); + + s_ann->makes_aliased_loads = 1; + } + } + } +} + +/* Record that VAR had its address taken in the statement with annotations + S_ANN. */ + +static void +note_addressable (tree var, stmt_ann_t s_ann) +{ + var = get_base_address (var); + if (var && SSA_VAR_P (var)) + { + if (s_ann->addresses_taken == NULL) + s_ann->addresses_taken = BITMAP_GGC_ALLOC (); + bitmap_set_bit (s_ann->addresses_taken, var_ann (var)->uid); + } +} + + +/* Add clobbering definitions for .GLOBAL_VAR or for each of the call + clobbered variables in the function. */ + +static void +add_call_clobber_ops (tree stmt, voperands_t prev_vops) +{ + /* Functions that are not const, pure or never return may clobber + call-clobbered variables. */ + stmt_ann (stmt)->makes_clobbering_call = true; + + /* If we had created .GLOBAL_VAR earlier, use it. Otherwise, add a VDEF + operand for every call clobbered variable. See compute_may_aliases for + the heuristic used to decide whether to create .GLOBAL_VAR or not. */ + if (global_var) + add_stmt_operand (&global_var, stmt, opf_is_def, prev_vops); + else + { + size_t i; + + EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, + { + tree var = referenced_var (i); + + /* If VAR is read-only, don't add a VDEF, just a VUSE operand. */ + if (!TREE_READONLY (var)) + add_stmt_operand (&var, stmt, opf_is_def, prev_vops); + else + add_stmt_operand (&var, stmt, opf_none, prev_vops); + }); + } +} + + +/* Add VUSE operands for .GLOBAL_VAR or all call clobbered variables in the + function. */ + +static void +add_call_read_ops (tree stmt, voperands_t prev_vops) +{ + /* Otherwise, if the function is not pure, it may reference memory. Add + a VUSE for .GLOBAL_VAR if it has been created. Otherwise, add a VUSE + for each call-clobbered variable. See add_referenced_var for the + heuristic used to decide whether to create .GLOBAL_VAR. */ + if (global_var) + add_stmt_operand (&global_var, stmt, opf_none, prev_vops); + else + { + size_t i; + + EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, + { + tree var = referenced_var (i); + add_stmt_operand (&var, stmt, opf_none, prev_vops); + }); + } +} + +#include "gt-tree-ssa-operands.h" diff --git a/gcc/tree-ssa-operands.h b/gcc/tree-ssa-operands.h new file mode 100644 index 00000000000..ceee6d037ab --- /dev/null +++ b/gcc/tree-ssa-operands.h @@ -0,0 +1,97 @@ +/* SSA operand management for trees. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef GCC_TREE_SSA_OPERANDS_H +#define GCC_TREE_SSA_OPERANDS_H + +/* Interface to SSA operands. */ + +typedef struct def_optype_d GTY(()) +{ + unsigned num_defs; + tree * GTY((length("%h.num_defs"), skip(""))) defs[1]; +} def_optype_t; + +typedef def_optype_t *def_optype; + +typedef struct use_optype_d GTY(()) +{ + unsigned num_uses; + tree * GTY((length("%h.num_uses"), skip(""))) uses[1]; +} use_optype_t; + +typedef use_optype_t *use_optype; + +typedef struct vdef_optype_d GTY(()) +{ + unsigned num_vdefs; + tree GTY((length ("%h.num_vdefs * 2"))) vdefs[1]; +} vdef_optype_t; + +typedef vdef_optype_t *vdef_optype; + +typedef struct vuse_optype_d GTY(()) +{ + unsigned num_vuses; + tree GTY((length ("%h.num_vuses"))) vuses[1]; +} vuse_optype_t; + +typedef vuse_optype_t *vuse_optype; + +#define USE_OPS(ANN) get_use_ops (ANN) +#define STMT_USE_OPS(STMT) get_use_ops (stmt_ann (STMT)) +#define NUM_USES(OPS) ((OPS) ? (OPS)->num_uses : 0) +#define USE_OP_PTR(OPS, I) get_use_op_ptr ((OPS), (I)) +#define USE_OP(OPS, I) (*(USE_OP_PTR ((OPS), (I)))) + + +#define DEF_OPS(ANN) get_def_ops (ANN) +#define STMT_DEF_OPS(STMT) get_def_ops (stmt_ann (STMT)) +#define NUM_DEFS(OPS) ((OPS) ? (OPS)->num_defs : 0) +#define DEF_OP_PTR(OPS, I) get_def_op_ptr ((OPS), (I)) +#define DEF_OP(OPS, I) (*(DEF_OP_PTR ((OPS), (I)))) + + +#define VDEF_OPS(ANN) get_vdef_ops (ANN) +#define STMT_VDEF_OPS(STMT) get_vdef_ops (stmt_ann(STMT)) +#define NUM_VDEFS(OPS) ((OPS) ? (OPS)->num_vdefs : 0) +#define VDEF_RESULT_PTR(OPS, I) get_vdef_result_ptr ((OPS), (I)) +#define VDEF_RESULT(OPS, I) (*(VDEF_RESULT_PTR ((OPS), (I)))) +#define VDEF_OP_PTR(OPS, I) get_vdef_op_ptr ((OPS), (I)) +#define VDEF_OP(OPS, I) (*(VDEF_OP_PTR ((OPS), (I)))) + + +#define VUSE_OPS(ANN) get_vuse_ops (ANN) +#define STMT_VUSE_OPS(STMT) get_vuse_ops (stmt_ann(STMT)) +#define NUM_VUSES(OPS) ((OPS) ? (OPS)->num_vuses : 0) +#define VUSE_OP_PTR(OPS, I) get_vuse_op_ptr ((OPS), (I)) +#define VUSE_OP(OPS, I) (*(VUSE_OP_PTR ((OPS), (I)))) + + +extern void init_ssa_operands (void); +extern void fini_ssa_operands (void); +extern void verify_start_operands (tree); +extern void finalize_ssa_stmt_operands (tree); +void add_vuse (tree, tree); +extern void get_stmt_operands (tree); +extern void remove_vuses (tree); +extern void remove_vdefs (tree); + +#endif /* GCC_TREE_SSA_OPERANDS_H */ diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c new file mode 100644 index 00000000000..ea7a94642de --- /dev/null +++ b/gcc/tree-ssa-phiopt.c @@ -0,0 +1,306 @@ +/* Optimization of PHI nodes by converting them into straightline code. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "basic-block.h" +#include "timevar.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "tree-dump.h" +#include "langhooks.h" + +static void tree_ssa_phiopt (void); +static bool conditional_replacement (basic_block bb, tree phi, tree arg0, + tree arg1); + + +/* This pass eliminates PHI nodes which can be trivially implemented as + an assignment from a conditional expression. ie if we have something + like: + + bb0: + if (cond) goto bb2; else goto bb1; + bb1: + bb2: + x = PHI (0 (bb1), 1 (bb0) + + We can rewrite that as: + + bb0: + bb1: + bb2: + x = cond; + + bb1 will become unreachable and bb0 and bb2 will almost always + be merged into a single block. This occurs often due to gimplification + of conditionals. */ + +static void +tree_ssa_phiopt (void) +{ + basic_block bb; + bool removed_phis = false; + + /* Search every basic block for PHI nodes we may be able to optimize. */ + FOR_EACH_BB (bb) + { + tree arg0, arg1, phi; + + + /* We're searching for blocks with one PHI node which has two + arguments. */ + phi = phi_nodes (bb); + if (phi && TREE_CHAIN (phi) == NULL + && PHI_NUM_ARGS (phi) == 2) + { + + arg0 = PHI_ARG_DEF (phi, 0); + arg1 = PHI_ARG_DEF (phi, 1); + + /* Do the replacement of conditional if it can be done. */ + if (conditional_replacement (bb, phi, arg0, arg1)) + { + /* We have done the replacement so we need to rebuild the cfg. */ + removed_phis = true; + continue; + } + } + } + + /* If we removed any PHIs, then we have unreachable blocks and blocks + which need to be merged in the CFG. */ + if (removed_phis) + cleanup_tree_cfg (); +} + +/* The function conditional_replacement does the main work of doing the conditional + replacement. Return true if the replacement is done. Otherwise return false. + bb is the basic block where the replacement is going to be done on. arg0 + is argument 0 from the phi. Likewise for arg1. */ + +static bool +conditional_replacement (basic_block bb, tree phi, tree arg0, tree arg1) +{ + tree result; + basic_block other_block = NULL; + basic_block cond_block = NULL; + tree last0, last1, new, cond; + block_stmt_iterator bsi; + edge true_edge, false_edge; + + /* The PHI arguments have the constants 0 and 1, then convert + it to the conditional. */ + if ((integer_zerop (arg0) && integer_onep (arg1)) + || (integer_zerop (arg1) && integer_onep (arg0))) + ; + else + return false; + + /* One of the alternatives must come from a block ending with + a COND_EXPR. The other block must be entirely empty, except + for labels. */ + last0 = last_stmt (bb->pred->src); + last1 = last_stmt (bb->pred->pred_next->src); + if (last0 && TREE_CODE (last0) == COND_EXPR) + { + cond_block = bb->pred->src; + other_block = bb->pred->pred_next->src; + } + else if (last1 && TREE_CODE (last1) == COND_EXPR) + { + other_block = bb->pred->src; + cond_block = bb->pred->pred_next->src; + } + else + return false; + + /* COND_BLOCK must have precisely two successors. We indirectly + verify that those successors are BB and OTHER_BLOCK. */ + if (!cond_block->succ + || !cond_block->succ->succ_next + || cond_block->succ->succ_next->succ_next + || (cond_block->succ->flags & EDGE_ABNORMAL) != 0 + || (cond_block->succ->succ_next->flags & EDGE_ABNORMAL) != 0) + return false; + + /* OTHER_BLOCK must have a single predecessor which is COND_BLOCK, + OTHER_BLOCK must have a single successor which is BB and + OTHER_BLOCK must have no PHI nodes. */ + if (!other_block->pred + || other_block->pred->src != cond_block + || other_block->pred->pred_next + || !other_block->succ + || other_block->succ->dest != bb + || other_block->succ->succ_next + || phi_nodes (other_block)) + return false; + + /* OTHER_BLOCK must have no executable statements. */ + bsi = bsi_start (other_block); + while (!bsi_end_p (bsi) + && (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR + || IS_EMPTY_STMT (bsi_stmt (bsi)))) + bsi_next (&bsi); + + if (!bsi_end_p (bsi)) + return false; + + /* If the condition is not a naked SSA_NAME and its type does not + match the type of the result, then we can not optimize this case + as it would likely create non-gimple code when the condition + was converted to the result's type. */ + cond = COND_EXPR_COND (last_stmt (cond_block)); + result = PHI_RESULT (phi); + if (TREE_CODE (cond) != SSA_NAME + && !lang_hooks.types_compatible_p (TREE_TYPE (cond), TREE_TYPE (result))) + return false; + + /* If the condition was a naked SSA_NAME and the type is not the + same as the type of the result, then convert the type of the + condition. */ + if (!lang_hooks.types_compatible_p (TREE_TYPE (cond), TREE_TYPE (result))) + cond = fold_convert (TREE_TYPE (result), cond); + + /* We need to know which is the true edge and which is the false + edge so that we know when to invert the condition below. */ + extract_true_false_edges_from_block (cond_block, &true_edge, &false_edge); + + /* At this point we know we have a COND_EXPR with two successors. + One successor is BB, the other successor is an empty block which + falls through into BB. + + There is a single PHI node at the join point (BB) and its arguments + are constants (0, 1). + + So, given the condition COND, and the two PHI arguments, we can + rewrite this PHI into non-branching code: + + dest = (COND) or dest = COND' + + We use the condition as-is if the argument associated with the + true edge has the value one or the argument associated with the + false edge as the value zero. Note that those conditions are not + the same since only one of the outgoing edges from the COND_EXPR + will directly reach BB and thus be associated with an argument. */ + if ((PHI_ARG_EDGE (phi, 0) == true_edge && integer_onep (arg0)) + || (PHI_ARG_EDGE (phi, 0) == false_edge && integer_zerop (arg0)) + || (PHI_ARG_EDGE (phi, 1) == true_edge && integer_onep (arg1)) + || (PHI_ARG_EDGE (phi, 1) == false_edge && integer_zerop (arg1))) + { + new = build (MODIFY_EXPR, TREE_TYPE (PHI_RESULT (phi)), + PHI_RESULT (phi), cond); + } + else + { + cond = invert_truthvalue (cond); + + if (is_gimple_cast (cond) + && !is_gimple_val (TREE_OPERAND (cond, 0))) + return false; + + if (TREE_CODE (cond) == TRUTH_NOT_EXPR + && !is_gimple_val (TREE_OPERAND (cond, 0))) + return false; + + new = build (MODIFY_EXPR, TREE_TYPE (PHI_RESULT (phi)), + PHI_RESULT (phi), cond); + } + + /* Insert our new statement at the head of our block. */ + bsi = bsi_start (bb); + bsi_insert_after (&bsi, new, BSI_SAME_STMT); + + /* Register our new statement as the defining statement for + the result. */ + SSA_NAME_DEF_STMT (PHI_RESULT (phi)) = new; + + /* Remove the now useless PHI node. + + We do not want to use remove_phi_node since that releases the + SSA_NAME as well and the SSA_NAME is still being used. */ + release_phi_node (phi); + bb_ann (bb)->phi_nodes = NULL; + + /* Disconnect the edge leading into the empty block. That will + make the empty block unreachable and it will be removed later. */ + if (cond_block->succ->dest == bb) + { + cond_block->succ->flags |= EDGE_FALLTHRU; + cond_block->succ->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); + ssa_remove_edge (cond_block->succ->succ_next); + } + else + { + cond_block->succ->succ_next->flags |= EDGE_FALLTHRU; + cond_block->succ->succ_next->flags + &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); + ssa_remove_edge (cond_block->succ); + } + + /* Eliminate the COND_EXPR at the end of COND_BLOCK. */ + bsi = bsi_last (cond_block); + bsi_remove (&bsi); + + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + "COND_EXPR in block %d and PHI in block %d converted to straightline code.\n", + cond_block->index, + bb->index); + + /* Note that we optimized this PHI. */ + return true; +} + + +/* Always do these optimizations if we have SSA + trees to work on. */ +static bool +gate_phiopt (void) +{ + return 1; +} + +struct tree_opt_pass pass_phiopt = +{ + "phiopt", /* name */ + gate_phiopt, /* gate */ + tree_ssa_phiopt, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_PHIOPT, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */ + | TODO_verify_ssa +}; + + diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c new file mode 100644 index 00000000000..d3ae62c9e56 --- /dev/null +++ b/gcc/tree-ssa-pre.c @@ -0,0 +1,3388 @@ +/* SSA-PRE for trees. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Daniel Berlin + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" +#include "tree.h" + +/* These RTL headers are needed for basic-block.h. */ +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "diagnostic.h" +#include "tree-inline.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-dump.h" +#include "timevar.h" +#include "fibheap.h" +#include "hashtab.h" +#include "tree-iterator.h" +#include "real.h" +#include "alloc-pool.h" +#include "tree-pass.h" +#include "flags.h" + + +/* + + Some of the algorithms are also based on Open64's SSAPRE implementation. + + Since the papers are a bit dense to read, take a while to grasp, + and have a few bugs, i'll give a quick rundown: + + Normally, in non-SSA form, one performs PRE on expressions using + bit vectors, determining properties for all expressions at once + through bitmap operations and iterative dataflow. + + SSAPRE, like most non-SSA->SSA algorithm conversions, operates one + expression at a time, and doesn't use bitvectors or iterative + dataflow. + + It answers the question "Given a single hypothetical temporary + variable, what expressions could we eliminate. + + To be able to do this, we need an SSA form for expressions. + If you are already confused, you likely think an expression, as + used here, is something like "b_3 = a_2 + 5". It's not. It's "a + + 5". "a_2 + 5" is an *occurrence* of the expression "a + 5". Just + like PRE, it's lexical equivalence that matters. + Compilers generally give you an SSA form for variables, and maybe + arrays (and/or conditionals). But not for expressions. + + GCC doesn't give you one either, so we have to build it. + Thus, the first steps of SSAPRE are to do just these things. + + First we collect lists of occurrences of expressions we are going + to operate on. + Note that: + Unlike the paper, we don't have to ever add newly formed + expressions to the list (for normal SSAPRE, anyway), because we + don't have expressions with more than two operators, and each + operator is either a constant or a variable. Thus, no second + order effects. + + Once we have the lists of occurrences, we process one expression + at a time, doing the following: + 1. Using a slightly modified SSA phi placement algorithm, place + expression PHI's for expressions. + 2. Using a two step optimistic SSA renaming algorithm, version the + nodes and link phi operands to their real occurrences, if they + exist. This creates a factored graph of our expression SSA occurrences. + 3. Using the factored graph, compute downsafe, avail, and later for + EPHIs (which are SSA versions of the same named bitvector PRE + problems) + 4. Using EPHI availability information and versions, compute what + occurrences need to have saves, and what occurrences can be + reloaded from an already saved value. + 5. Insert the saves and reloads, and transform EPHIs into regular + phis of the temporary we use for insertion/saving. + + See http://citeseer.nj.nec.com/chow97new.html, and + http://citeseer.nj.nec.com/kennedy99partial.html for details of the + algorithm. + + kennedy99partial is newer, and is what this implementation is based + on. + + For strength reduction addition, see + http://citeseer.nj.nec.com/kennedy98strength.html. + + There is also a paper on sparse register promotion using PRE that + contains the basic algorithm for load PRE. The exact title/url of + the paper escapes me. + + Lastly, there is a code hoisting extension that open64 performs + (see opt_ehoist.cxx), but we don't. It's not documented in any + papers, but not that difficult to understand of implement. */ + + +/* TODOS: + Do strength reduction on a +-b and -a, not just a * . + */ + +struct expr_info; +static void clear_all_eref_arrays (void); +static inline bool expr_lexically_eq (const tree, const tree); +static void free_expr_info (struct expr_info *); +static bitmap compute_idfs (bitmap *, tree); +static void set_var_phis (struct expr_info *, tree); +static inline bool names_match_p (const tree, const tree); +static bool is_strred_cand (const tree); +static int pre_expression (struct expr_info *, void *, bitmap); +static bool is_injuring_def (struct expr_info *, tree); +static inline bool okay_injuring_def (tree, tree); +static bool expr_phi_insertion (bitmap *, struct expr_info *); +static tree factor_through_injuries (struct expr_info *, tree, tree, bool *); +static inline tree maybe_find_rhs_use_for_var (tree, tree, unsigned int); +static inline tree find_rhs_use_for_var (tree, tree); +static tree create_ephi_node (basic_block, unsigned int); +static inline int opnum_of_phi (tree, int); +static inline int opnum_of_ephi (const tree, const edge); +static tree subst_phis (struct expr_info *, tree, basic_block, basic_block); +static void generate_expr_as_of_bb (tree, basic_block, basic_block); +static void generate_vops_as_of_bb (tree, basic_block, basic_block); +static void rename_1 (struct expr_info *); +static void process_delayed_rename (struct expr_info *, tree, tree); +static void assign_new_class (tree, varray_type *, varray_type *); +static void create_and_insert_occ_in_preorder_dt_order (struct expr_info *); +static void insert_euse_in_preorder_dt_order (struct expr_info *); +static bool ephi_has_unsafe_arg (tree); +static void reset_down_safe (tree, int); +static void compute_down_safety (struct expr_info *); +static void compute_will_be_avail (struct expr_info *); +static void compute_stops (struct expr_info *); +static bool finalize_1 (struct expr_info *); +static void finalize_2 (struct expr_info *); +static tree occ_identical_to (tree); +static void require_phi (struct expr_info *, basic_block); +static bool really_available_def (tree node); + +/* Functions used for an EPHI based depth first search. */ +struct ephi_df_search +{ + /* Return true if the ephi has been seen. */ + bool (*seen) (tree); + /* Mark the ephi as seen. */ + void (*set_seen) (tree); + /* Note that the search reaches from one ephi to it's use. */ + void (*reach_from_to) (tree, int, tree); + /* Return true if we should start a search from this PHI. */ + bool (*start_from) (tree); + /* Return true if we should continue the search to this use. */ + bool (*continue_from_to) (tree, int, tree); +}; +static bool repl_search_seen (tree); +static void repl_search_set_seen (tree); +static void repl_search_reach_from_to (tree, int, tree); +static bool repl_search_start_from (tree); +static bool repl_search_continue_from_to (tree, int, tree); +static bool stops_search_seen (tree); +static void stops_search_set_seen (tree); +static void stops_search_reach_from_to (tree, int, tree); +static bool stops_search_start_from (tree); +static bool stops_search_continue_from_to (tree, int, tree); +static bool cba_search_seen (tree); +static void cba_search_set_seen (tree); +static bool cba_search_start_from (tree); +static bool cba_search_continue_from_to (tree, int, tree); +struct ephi_df_search cant_be_avail_search = { + cba_search_seen, + cba_search_set_seen, + NULL, + cba_search_start_from, + cba_search_continue_from_to +}; + +struct ephi_df_search stops_search = { + stops_search_seen, + stops_search_set_seen, + stops_search_reach_from_to, + stops_search_start_from, + stops_search_continue_from_to +}; + + +/* depth-first replacement search used during temp ESSA minimization. */ +struct ephi_df_search replacing_search = { + repl_search_seen, + repl_search_set_seen, + repl_search_reach_from_to, + repl_search_start_from, + repl_search_continue_from_to +}; + +static void do_ephi_df_search_1 (struct ephi_df_search, tree); +static void do_ephi_df_search (struct expr_info *, struct ephi_df_search); + +static inline bool any_operand_injured (tree); +static void code_motion (struct expr_info *); +static tree pick_ssa_name (tree stmt); +#if 0 +static tree calculate_increment (struct expr_info *, tree); +#endif +static bool can_insert (tree, int); +static void set_save (struct expr_info *, tree); +static tree reaching_def (tree, tree, basic_block, tree); +static tree do_proper_save (tree , tree, int); +static void process_left_occs_and_kills (varray_type, tree); +static tree create_expr_ref (struct expr_info *, tree, enum tree_code, + basic_block, tree); +static inline bool ephi_will_be_avail (tree); +static inline tree ephi_at_block (basic_block); +static tree get_default_def (tree, htab_t); +static inline bool same_e_version_real_occ_real_occ (struct expr_info *, + const tree, + const tree); +static inline bool load_modified_phi_result (basic_block, tree); +static inline bool same_e_version_phi_result (struct expr_info *, + tree, tree, tree); +static inline bool load_modified_real_occ_real_occ (tree, tree); +static inline bool same_e_version_real_occ_phi_opnd (struct expr_info *, + tree, basic_block, + int, tree, bool *); +static inline bool injured_real_occ_real_occ (struct expr_info *, + tree, tree); +static inline bool injured_phi_result_real_occ (struct expr_info *, + tree, tree, basic_block); +static inline bool injured_real_occ_phi_opnd (struct expr_info *, + tree, basic_block, int); +static void compute_du_info (struct expr_info *); +static void add_ephi_use (tree, tree, int); +static void insert_one_operand (struct expr_info *, tree, int, tree, edge, + tree **); +static void collect_expressions (basic_block, varray_type *); +static int build_dfn_array (basic_block, int); +static int eref_compare (const void *, const void *); + + +/* Bitmap of E-PHI predecessor operands have already been created. + We only create one phi-pred per block. */ +static bitmap created_phi_preds; + +/* PRE dominance frontiers. */ +static bitmap *pre_dfs; + +/* Number of redundancy classes. */ +static int class_count = 0; + + +/* Iterated dominance frontiers cache. */ +static bitmap *idfs_cache; + +/* Partial redundancies statistics. */ +static struct pre_stats_d +{ + int reloads; + int saves; + int repairs; + int newphis; + int ephi_allocated; + int ephis_current; + int eref_allocated; + int exprs_generated; +} pre_stats = {0, 0, 0, 0, 0, 0, 0, 0}; + + +/* USE entry in list of uses of ephi's. */ +struct ephi_use_entry +{ + tree phi; + int opnd_indx; +}; + +/* PRE Expression specific info. */ +struct expr_info +{ + /* The actual expression. */ + tree expr; + /* The occurrences. */ + varray_type occurs; + /* The kills. */ + varray_type kills; + /* The left occurrences. */ + varray_type lefts; + /* An array of real occurrences. */ + varray_type reals; + /* True if it's a strength reduction candidate. */ + bool strred_cand; + /* True if it's a load PRE candidate. */ + bool loadpre_cand; + /* The euses/ephis in preorder dt order. */ + varray_type euses_dt_order; + /* The name of the temporary for this expression. */ + tree temp; +}; + + +/* Cache of expressions generated for given phi operand, to avoid + recomputation and wasting memory. */ +static tree *phi_pred_cache; +static int n_phi_preds; + +/* Trying to lookup ephi pred operand indexes takes forever on graphs + that have high connectivity because it's an O(n) linked list + traversal. Thus, we set up a hashtable that tells us the operand + index for a given edge. */ + +typedef struct ephi_pred_index_elt +{ + tree ephi; + edge edge; + int opnd; +} ephi_pindex_t; + +/* Hash an (ephi, edge, opnd) tuple. */ + +static hashval_t +ephi_pindex_hash (const void *p) +{ + const ephi_pindex_t *ep = (const ephi_pindex_t *)p; + return htab_hash_pointer (ep->ephi) + htab_hash_pointer (ep->edge); +} + +/* Determine equality of an (ephi, edge, opnd) tuple. */ + +static int +ephi_pindex_eq (const void *p1, const void *p2) +{ + const ephi_pindex_t *ep1 = (const ephi_pindex_t *)p1; + const ephi_pindex_t *ep2 = (const ephi_pindex_t *)p2; + + return ep1->ephi == ep2->ephi && ep1->edge == ep2->edge; +} + +/* The (ephi, edge) => opnd mapping hashtable. */ +static htab_t ephi_pindex_htab; + +/* Add an ephi predecessor to a PHI. */ + +static int +add_ephi_pred (tree phi, tree def, edge e) +{ + int i = EPHI_NUM_ARGS (phi); + void **slot; + ephi_pindex_t ep, *epp; + + EPHI_ARG_PRED (phi, i) = def; + EPHI_ARG_EDGE (phi, i) = e; + + ep.ephi = phi; + ep.edge = e; + slot = htab_find_slot (ephi_pindex_htab, (void *)&ep, INSERT); + if (*slot == NULL) + { + epp = xmalloc (sizeof (*epp)); + epp->ephi = phi; + epp->edge = e; + epp->opnd = i; + *slot = (void *)epp; + } + else + abort (); + + EPHI_NUM_ARGS (phi)++; + return i; +} + +/* Create a new EPHI node at basic block BB. */ + +static tree +create_ephi_node (basic_block bb, unsigned int add) +{ + tree phi; + int len; + edge e; + size_t size; + bb_ann_t ann; + + for (len = 0, e = bb->pred; e; e = e->pred_next) + len++; + size = (sizeof (struct tree_ephi_node) + + ((len - 1) * sizeof (struct ephi_arg_d))); + + phi = xmalloc (size); + memset (phi, 0, size); + if (add) + { + ann = bb_ann (bb); + if (ann->ephi_nodes == NULL) + ann->ephi_nodes = phi; + else + chainon (ann->ephi_nodes, phi); + } + pre_stats.ephi_allocated += size; + pre_stats.ephis_current += 1; + TREE_SET_CODE (phi, EPHI_NODE); + EPHI_NUM_ARGS (phi) = 0; + EPHI_ARG_CAPACITY (phi) = len; + + /* Associate BB to the PHI node. */ + set_bb_for_stmt (phi, bb); + + return phi; +} + +/* Given DEF (which can be an SSA_NAME or entire statement), and VAR, + find a use of VAR on the RHS of DEF, if one exists. Abort if we + can't find one. */ + +static inline tree +find_rhs_use_for_var (tree def, tree var) +{ + tree ret = maybe_find_rhs_use_for_var (def, var, 0); + if (!ret) + abort (); + return ret; +} + +/* Determine if two trees are referring to the same variable. + Handles SSA_NAME vs non SSA_NAME, etc. Uses operand_equal_p for + non-trivial cases (INDIRECT_REF and friends). */ + +static inline bool +names_match_p (const tree t1, const tree t2) +{ + tree name1, name2; + + if (t1 == t2) + return true; + + if (TREE_CODE (t1) == INDIRECT_REF) + return names_match_p (TREE_OPERAND (t1, 0), t2); + + if (TREE_CODE (t2) == INDIRECT_REF) + return names_match_p (t1, TREE_OPERAND (t2, 0)); + + if (TREE_CODE (t1) == SSA_NAME) + name1 = SSA_NAME_VAR (t1); + else if (DECL_P (t1)) + name1 = t1; + else + name1 = NULL_TREE; + + if (TREE_CODE (t2) == SSA_NAME) + name2 = SSA_NAME_VAR (t2); + else if (DECL_P (t2)) + name2 = t2; + else + name2 = NULL_TREE; + + if (name1 == NULL_TREE && name2 != NULL_TREE) + return false; + if (name2 == NULL_TREE && name1 != NULL_TREE) + return false; + if (name1 == NULL_TREE && name2 == NULL_TREE) + return operand_equal_p (t1, t2, 0); + + return name1 == name2; +} + +/* Given DEF (which can be an SSA_NAME or entire statement), and VAR, + find a use of VAR on the RHS of DEF, if one exists. Return NULL if + we cannot find one. */ + +static inline tree +maybe_find_rhs_use_for_var (tree def, tree var, unsigned int startpos) +{ + use_optype uses; + size_t i; + + if (SSA_VAR_P (def)) + { + if (names_match_p (var, def)) + return def; + return NULL_TREE; + } + get_stmt_operands (def); + uses = STMT_USE_OPS (def); + + for (i = startpos; i < NUM_USES (uses); i++) + { + tree use = USE_OP (uses, i); + if (names_match_p (use, var)) + return use; + } + return NULL_TREE; +} + +/* Determine if an injuring def is one which we can repair, and thus, + ignore for purposes of determining the version of a variable. */ + +static inline bool +okay_injuring_def (tree inj, tree var) +{ + /* Acceptable injuries are those which + 1. aren't empty statements. + 2. aren't phi nodes. + 3. contain a use of VAR on the RHS. */ + if (!inj || IS_EMPTY_STMT (inj) + || TREE_CODE (inj) == PHI_NODE + || !maybe_find_rhs_use_for_var (inj, var, 0)) + return false; + return true; +} + +/* Return true if INJ is an injuring definition */ + +static bool +is_injuring_def (struct expr_info *ei, tree inj) +{ + /* Things that are never injuring definitions. */ + if (!inj || IS_EMPTY_STMT (inj) || TREE_CODE (inj) == PHI_NODE) + return false; + + /* Things we can't handle. */ + if (TREE_CODE (TREE_OPERAND (inj, 1)) != PLUS_EXPR + && TREE_CODE (TREE_OPERAND (inj, 1)) != MINUS_EXPR) + return false; + + /* given inj: a1 = a2 + 5 + expr: a3 * c + we are testing: + if (a1 != a3 + || ! (a2 exists) + || a2 != a3) + return false + + Or, in English, if either the assigned-to variable in + the injury is different from the first variable in the + expression, or the incremented variable is different from the + first variable in the expression, punt. + + This makes sure we have something of the form + + a = a {+,-} {expr} + for an expression like "a * 5". + + This limitation only exists because we don't know how to repair + other forms of increments/decrements. */ + if (!names_match_p (TREE_OPERAND (inj, 0), TREE_OPERAND (ei->expr, 0)) + || !TREE_OPERAND (TREE_OPERAND (inj, 1), 0) + || !names_match_p (TREE_OPERAND (TREE_OPERAND (inj, 1), 0), + TREE_OPERAND (ei->expr, 0))) + return false; + + /* If we are strength reducing a multiply, we have the additional + constraints that + 1. {expr} is 1 + 2. {expr} and the RHS of the expression are constants. */ + if (TREE_CODE (ei->expr) == MULT_EXPR) + { + tree irhs1; + tree irhs2; + tree irhs; + irhs = TREE_OPERAND (inj, 1); + irhs1 = TREE_OPERAND (irhs, 0); + irhs2 = TREE_OPERAND (irhs, 1); + + if (TREE_CODE (irhs2) != INTEGER_CST) + return false; + if (tree_low_cst (irhs2, 0) == 1) + return true; + if (really_constant_p (irhs2) + && really_constant_p (TREE_OPERAND (ei->expr, 1))) + return true; + /* We don't currently support "the injury is inside a loop,expr is + loop-invariant, and b is either loop-invariant or is + another induction variable with respect to the loop." */ + return false; + } + return true; +} + +/* Find the statement defining VAR, ignoring injuries we can repair. + START is the first potential injuring def. */ + +static tree +factor_through_injuries (struct expr_info *ei, tree start, tree var, + bool *injured) +{ + tree end = start; + + while (is_injuring_def (ei, SSA_NAME_DEF_STMT (end))) + { + if (injured) + *injured = true; + end = find_rhs_use_for_var (SSA_NAME_DEF_STMT (end), var); + if (!okay_injuring_def (SSA_NAME_DEF_STMT (end), var)) + break; + if (dump_file) + { + fprintf (dump_file, "Found a real injury:"); + print_generic_stmt (dump_file, SSA_NAME_DEF_STMT (end), dump_flags); + fprintf (dump_file, "\n"); + } + if (injured) + *injured = true; + end = find_rhs_use_for_var (SSA_NAME_DEF_STMT (end), var); + } + return end; +} + +/* Return true if the result of the EPHI, when transformed into a phi, + will be available. */ + +static inline bool +ephi_will_be_avail (tree ephi) +{ + if (!EPHI_CANT_BE_AVAIL (ephi)) + if (EPHI_STOPS (ephi)) + return true; + + return false; +} + +/* EUSE node pool. We allocate EUSE nodes out of this*/ +static alloc_pool euse_node_pool; + +/* EREF node pool. We allocate regular EREF nodes (like EEXIT_NODE) + out of this. */ +static alloc_pool eref_node_pool; + + +/* To order EREF's in a given block, we assign them each an ID based + on when we see them. */ +static int eref_id_counter = 0; + +/* Creation an expression reference of TYPE. */ + +static tree +create_expr_ref (struct expr_info *ei, tree expr, enum tree_code type, + basic_block bb, tree parent) +{ + tree ret; + if (type == EPHI_NODE) + { + int len; + edge e; + + ret = create_ephi_node (bb, 1); + for (len = 0, e = bb->pred; e; e = e->pred_next) + len++; + + EREF_TEMP (ret) = make_phi_node (ei->temp, len); + } + else + { + if (type == EUSE_NODE) + ret = (tree) pool_alloc (euse_node_pool); + else + ret = (tree) pool_alloc (eref_node_pool); + TREE_SET_CODE (ret, type); + memset (ret, 0, tree_size (ret)); + TREE_SET_CODE (ret, type); + pre_stats.eref_allocated += tree_size (ret); + } + + EREF_NAME (ret) = expr; + set_bb_for_stmt (ret, bb); + EREF_STMT (ret) = parent; + EREF_SAVE (ret) = false; + EREF_ID (ret) = eref_id_counter++; + + return ret; +} + + +/* dfphis is a bitmap of where we need to insert ephis due to the + iterated dominance frontier of an expression. */ + +static bitmap dfphis; + +/* varphis is a bitmap of where we need to insert ephis due to the + presence of phis for a variable. */ + +static bitmap varphis; + + +/* Function to recursively figure out where EPHI's need to be placed + because of PHI's. + We always place EPHI's where we place PHI's because they are also + partially anticipated expression points (because some expression + alteration reaches that merge point). + + We do this recursively, because we have to figure out + EPHI's for the variables in the PHI as well. */ + +static void +set_var_phis (struct expr_info *ei, tree phi) +{ + basic_block bb = bb_for_stmt (phi); + /* If we've already got an EPHI set to be placed in PHI's BB, we + don't need to do this again. */ + if (!bitmap_bit_p (varphis, bb->index) + && !bitmap_bit_p (dfphis, bb->index)) + { + tree phi_operand; + int curr_phi_operand; + bitmap_set_bit (varphis, bb->index); + for (curr_phi_operand = 0; + curr_phi_operand < PHI_NUM_ARGS (phi); + curr_phi_operand++) + { + phi_operand = PHI_ARG_DEF (phi, curr_phi_operand); + /* For strength reduction, factor through injuries we can + repair. */ + if (ei->strred_cand && TREE_CODE (phi_operand) != PHI_NODE) + { + phi_operand = factor_through_injuries (ei, phi_operand, + SSA_NAME_VAR (phi_operand), + NULL); + phi_operand = SSA_NAME_DEF_STMT (phi_operand); + if (dump_file) + { + fprintf (dump_file, "After factoring through injuries:"); + print_generic_stmt (dump_file, phi_operand, dump_flags); + fprintf (dump_file, "\n"); + } + } + + /* If our phi operand is defined by a phi, we need to + record where the phi operands alter the expression as + well, and place EPHI's at each point. */ + if (TREE_CODE (phi_operand) == PHI_NODE) + set_var_phis (ei, phi_operand); + } + } +} + + +/* Clear all the expression reference arrays. */ + +static void +clear_all_eref_arrays (void) +{ + basic_block bb; + bb_ann_t ann; + + FOR_ALL_BB (bb) + { + ann = bb_ann (bb); + if (ann->ephi_nodes) + { + free (ann->ephi_nodes); + pre_stats.ephis_current -= 1; + } + ann->ephi_nodes = NULL; + } +} + +/* EPHI insertion algorithm. */ + +static bool +expr_phi_insertion (bitmap *dfs, struct expr_info *ei) +{ + size_t i, j; + vuse_optype vuses; + use_optype uses; + bool retval = true; + + dfphis = BITMAP_XMALLOC (); + bitmap_zero (dfphis); + varphis = BITMAP_XMALLOC (); + bitmap_zero (varphis); + + /* Compute where we need to place EPHIS. There are two types of + places we need EPHI's: Those places we would normally place a + PHI for the occurrence (calculated by determining the IDF+ of + the statement), and those places we need an EPHI due to partial + anticipation. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->occurs); i++) + { + tree occurp = VARRAY_TREE (ei->occurs, i); + tree occur = occurp ? occurp : NULL; + tree killp = VARRAY_TREE (ei->kills, i); + tree kill = killp ? killp : NULL; + tree leftp = VARRAY_TREE (ei->lefts, i); + tree left = leftp ? leftp : NULL; + bitmap temp; + stmt_ann_t ann; + +#ifdef ENABLE_CHECKING + if ((kill && occur) || (left && occur) || (kill && left)) + abort(); +#endif + occurp = occur ? occurp : kill ? killp : leftp; + occur = occur ? occur : kill ? kill : left; + temp = compute_idfs (dfs, occur); + bitmap_a_or_b (dfphis, dfphis, temp); + if (kill != NULL) + continue; + get_stmt_operands (occurp); + ann = stmt_ann (occurp); + uses = USE_OPS (ann); + for (j = 0; j < NUM_USES (uses); j ++) + { + tree use = USE_OP (uses, j); + if (ei->strred_cand) + use = factor_through_injuries (ei, use, SSA_NAME_VAR (use), + NULL); + if (TREE_CODE (SSA_NAME_DEF_STMT (use)) != PHI_NODE) + continue; + set_var_phis (ei, SSA_NAME_DEF_STMT (use)); + } + if (ei->loadpre_cand && TREE_CODE (ei->expr) == INDIRECT_REF) + { + vuses = VUSE_OPS (ann); + for (j = 0; j < NUM_VUSES (vuses); j ++) + { + tree use = VUSE_OP (vuses, j); + if (ei->strred_cand) + use = factor_through_injuries (ei, use, SSA_NAME_VAR (use), + NULL); + if (TREE_CODE (SSA_NAME_DEF_STMT (use)) != PHI_NODE) + continue; + set_var_phis (ei, SSA_NAME_DEF_STMT (use)); + } + } + } + /* Union the results of the dfphis and the varphis to get the + answer to everywhere we need EPHIS. */ + bitmap_a_or_b (dfphis, dfphis, varphis); + + /* Now create the EPHI's in each of these blocks. */ + EXECUTE_IF_SET_IN_BITMAP(dfphis, 0, i, + { + tree ref = create_expr_ref (ei, ei->expr, EPHI_NODE, BASIC_BLOCK (i), + NULL); + EREF_PROCESSED (ref) = false; + EPHI_DOWNSAFE (ref) = true; + EPHI_DEAD (ref) = true; + }); +#if 0 + /* If there are no phis, we don't have anything to optimize, + assuming the dominator optimizer took care of it all. */ + if (bitmap_first_set_bit (dfphis) == -1) + retval = false; +#endif + BITMAP_XFREE (dfphis); + BITMAP_XFREE (varphis); + return retval; + +} + +/* Return the EPHI at block BB, if one exists. */ + +static inline tree +ephi_at_block (basic_block bb) +{ + bb_ann_t ann = bb_ann (bb); + if (ann->ephi_nodes) + return ann->ephi_nodes; + else + return NULL_TREE; +} + +/* Depth first numbering array. */ +static int *dfn; + +/* Build a depth first numbering array to be used in sorting in + dominator order. */ + +static int +build_dfn_array (basic_block bb, int num) +{ + basic_block son; + + if (bb->index >= 0) + dfn[bb->index] = num; + + for (son = first_dom_son (CDI_DOMINATORS, bb); + son; + son = next_dom_son (CDI_DOMINATORS, son)) + num = build_dfn_array (son, ++num); + return num; +} + + +/* Compare two EREF's in terms of dominator preorder. Return -1 if + ELEM1 goes before ELEM2, 1 if ELEM1 goes after ELEM2, and 0 if they + are equal. */ + +static int +eref_compare (const void *elem1, const void *elem2) +{ + tree t1 = *(tree *)elem1; + tree t2 = *(tree *)elem2; + basic_block bb1, bb2; + if (t1 == t2) + return 0; + bb1 = bb_for_stmt (t1); + bb2 = bb_for_stmt (t2); + if (bb1 == bb2) + { + if (TREE_CODE (t1) == EEXIT_NODE) + return 1; + if (TREE_CODE (t2) == EEXIT_NODE) + return -1; + if (TREE_CODE (t1) == EPHI_NODE) + return -1; + if (TREE_CODE (t2) == EPHI_NODE) + return 1; + if ((TREE_CODE (t1) == EUSE_NODE && EUSE_PHIOP (t1)) + && (TREE_CODE (t2) == EUSE_NODE && !EUSE_PHIOP (t2))) + return 1; + if ((TREE_CODE (t1) == EUSE_NODE && !EUSE_PHIOP (t1)) + && (TREE_CODE (t2) == EUSE_NODE && EUSE_PHIOP (t2))) + return -1; + if (TREE_CODE (t1) == EUSE_NODE && TREE_CODE (t2) == EUSE_NODE) + return EREF_ID (t1) - EREF_ID (t2); + if (TREE_CODE (t1) == EPHI_NODE && TREE_CODE (t2) == EPHI_NODE) + abort (); + + } + else + { + if (dfn[bb1->index] == dfn[bb2->index]) + { + if (dominated_by_p (CDI_DOMINATORS, bb1, bb2)) + return 1; + else + return -1; + } + else + return (dfn[bb1->index] < dfn[bb2->index]) ? -1 : 1; + } + + abort (); +} + +/* Create expression references for occurrences, kills, phi operands, + and the like. At the same time, insert the occurrences into the + ei->euses_dt_order array in the proper order. If this function had + any use outside of rename_1, you could split it into two + functions, one creating, one inserting. */ + +static void +create_and_insert_occ_in_preorder_dt_order (struct expr_info *ei) +{ + size_t i; + edge succ; + tree curr_phi_pred = NULL_TREE; + basic_block block; + + /* The ephis references were already created, so just push them into + the euses_dt_order list. */ + FOR_EACH_BB (block) + { + tree ephi = ephi_at_block (block); + /* The ordering for a given BB is EPHI's, real/left/kill + occurrences, phi preds, exit occurrences. */ + if (ephi != NULL_TREE) + VARRAY_PUSH_TREE (ei->euses_dt_order, ephi); + } + + /* The non-ephis have to actually be created, so do that, then push + them into the list. */ + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->occurs); i++) + { + tree newref; + tree current; + current = VARRAY_TREE (ei->occurs, i); + current = current ? current : VARRAY_TREE (ei->kills, i); + current = current ? current : VARRAY_TREE (ei->lefts, i); + block = bb_for_stmt (current); + if (VARRAY_TREE (ei->kills, i) != NULL) + { + tree killexpr = VARRAY_TREE (ei->kills, i); + tree killname = ei->expr; + newref = create_expr_ref (ei, killname, EKILL_NODE, block, killexpr); + VARRAY_PUSH_TREE (ei->euses_dt_order, newref); + } + else if (VARRAY_TREE (ei->lefts, i) != NULL) + { + tree occurexpr = VARRAY_TREE (ei->lefts, i); + tree occurname; + occurname = ei->expr; + newref = create_expr_ref (ei, occurname, EUSE_NODE, block, + occurexpr); + EUSE_DEF (newref) = NULL_TREE; + EUSE_LVAL (newref) = true; + EREF_CLASS (newref) = -1; + EUSE_PHIOP (newref) = false; + EREF_PROCESSED (newref) = false; + VARRAY_PUSH_TREE (ei->euses_dt_order, newref); + } + else + { + tree occurexpr = VARRAY_TREE (ei->occurs, i); + tree occurname; + occurname = ei->expr; + newref = create_expr_ref (ei, occurname, EUSE_NODE, block, + occurexpr); + EUSE_DEF (newref) = NULL_TREE; + EREF_CLASS (newref) = -1; + EUSE_PHIOP (newref) = false; + EREF_PROCESSED (newref) = false; + VARRAY_PUSH_TREE (ei->euses_dt_order, newref); + } + } + + /* Lastly, we need to create and insert the ephi operand occurrences + into the list. */ + FOR_ALL_BB (block) + { + /* Insert the phi operand occurrences into the list at the + successors.*/ + for (succ = block->succ; succ; succ = succ->succ_next) + { + if (succ->dest != EXIT_BLOCK_PTR) + { + tree ephi = ephi_at_block (succ->dest); + if (ephi != NULL + && !bitmap_bit_p (created_phi_preds, block->index)) + { + tree newref = create_expr_ref (ei, 0, EUSE_NODE, block, NULL); + curr_phi_pred = newref; + VARRAY_PUSH_TREE (ei->euses_dt_order, newref); + EUSE_DEF (newref) = NULL_TREE; + EREF_CLASS (newref) = -1; + EUSE_PHIOP (newref) = true; + EREF_SAVE (newref) = false; + EREF_RELOAD (newref) = false; + EUSE_INSERTED (newref) = false; + EREF_PROCESSED (newref) = false; + bitmap_set_bit (created_phi_preds, block->index); + add_ephi_pred (ephi, newref, succ); + } + else if (ephi != NULL) + { +#ifdef ENABLE_CHECKING + if (curr_phi_pred == NULL_TREE) + abort(); +#endif + add_ephi_pred (ephi, curr_phi_pred, succ); + } + } + else if (succ->dest == EXIT_BLOCK_PTR && !(succ->flags & EDGE_FAKE)) + { + /* No point in inserting exit blocks into heap first, since + they'll never be anything on the stack. */ + tree newref; + newref = create_expr_ref (ei, ei->expr, EEXIT_NODE, + block, + NULL); + VARRAY_PUSH_TREE (ei->euses_dt_order, newref); + } + } + } + qsort (ei->euses_dt_order->data.tree, + VARRAY_ACTIVE_SIZE (ei->euses_dt_order), + sizeof (tree), + eref_compare); +} + + +/* Assign a new redundancy class to the occurrence, and push it on the + renaming stack. */ + +static void +assign_new_class (tree occ, varray_type * stack, varray_type * stack2) +{ + /* class(occ) <- count + Push(occ, stack) + count <- count + 1 + */ + EREF_CLASS (occ) = class_count; + VARRAY_PUSH_TREE (*stack, occ); + if (stack2) + VARRAY_PUSH_TREE (*stack2, occ); + class_count++; +} + +/* Determine if two real occurrences have the same ESSA version. + We do this by hashing the expressions and comparing the hash + values. Even if they don't match, we then see if this is a + strength reduction candidate, and if so, if the use is simply + injured. */ + +static inline bool +same_e_version_real_occ_real_occ (struct expr_info *ei, + const tree def, const tree use) +{ + hashval_t expr1val; + hashval_t expr2val; + vuse_optype vuses; + size_t i; + const tree t1 = EREF_STMT (def); + const tree t2 = EREF_STMT (use); + + expr1val = iterative_hash_expr (TREE_OPERAND (t1, 1), 0); + expr2val = iterative_hash_expr (TREE_OPERAND (t2, 1), 0); + + if (expr1val == expr2val) + { + vuses = STMT_VUSE_OPS (t1); + for (i = 0; i < NUM_VUSES (vuses); i++) + expr1val = iterative_hash_expr (VUSE_OP (vuses, i), expr1val); + vuses = STMT_VUSE_OPS (t2); + for (i = 0; i < NUM_VUSES (vuses); i++) + expr2val = iterative_hash_expr (VUSE_OP (vuses, i), expr2val); + if (expr1val != expr2val) + return false; + } + + /* If the def is injured, and the expressions have the same value, + then the use is injured. */ + if (expr1val == expr2val) + { + if (EREF_INJURED (def)) + EREF_INJURED (use) = true; + return true; + } + + /* Even if the expressions don't have the same value, it might be + the case that the use is simply injured, in which case, it's + still okay. */ + if (expr1val != expr2val && ei->strred_cand) + { + if (injured_real_occ_real_occ (ei, def, use)) + { + EREF_INJURED (use) = true; + return true; + } + } + return false; +} + +/* Determine if the use occurrence is injured. + TODO: Finish actually implementing this. */ + +static inline bool +injured_real_occ_real_occ (struct expr_info *ei ATTRIBUTE_UNUSED, + tree def ATTRIBUTE_UNUSED, + tree use ATTRIBUTE_UNUSED) +{ + tree defstmt; + tree defvar; + + defstmt = EREF_STMT (def); + if (TREE_CODE (TREE_OPERAND (defstmt, 0)) != SSA_NAME) + return false; + + defvar = TREE_OPERAND (defstmt, 0); + /* XXX: Implement. */ + return false; + +} + +/* Determine the operand number of edge E in EPHI. */ + +static inline int +opnum_of_ephi (const tree ephi, const edge e) +{ + ephi_pindex_t ep, *epp; + + ep.ephi = ephi; + ep.edge = e; + epp = htab_find (ephi_pindex_htab, &ep); + if (epp == NULL) + abort (); + return epp->opnd; +} + +/* Determine the phi operand index for J in PHI. */ + +static inline int +opnum_of_phi (tree phi, int j) +{ + int i; + /* We can't just count predecessors, since tree-ssa.c generates them + when it sees a phi in the successor during it's traversal. So the + order is dependent on the traversal order. */ + for (i = 0 ; i < PHI_NUM_ARGS (phi); i++) + if (PHI_ARG_EDGE (phi, i)->src->index == j) + return i; + + abort(); +} + +/* Generate EXPR as it would look in basic block PRED (using the phi in + block BB). We do this by replacing the variables with the phi + argument definitions for block J if they are defined by a phi in + block BB. */ + +static void +generate_expr_as_of_bb (tree expr, basic_block pred, basic_block bb) +{ + use_optype uses = STMT_USE_OPS (expr); + bool replaced_constants = false; + size_t k; + + for (k = 0; k < NUM_USES (uses); k++) + { + tree *vp = USE_OP_PTR (uses, k); + tree v = *vp; + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + if (PHI_RESULT (phi) == v) + { + int opnum = opnum_of_phi (phi, pred->index); + tree p = PHI_ARG_DEF (phi, opnum); + replace_exp (vp, p); + if (!phi_ssa_name_p (p)) + replaced_constants = true; + break; + } + } + } + + /* If we've substituted in new constants, we must be sure to + simplify the result lest we crash in get_expr_operands. */ + if (replaced_constants) + fold_stmt (&expr); +} + +/* Generate VUSE ops as they would look in basic block PRED (using the + phi in block BB). Done the same way as we do generation of regular + ops for the bb. */ + +static void +generate_vops_as_of_bb (tree expr, basic_block pred, basic_block bb) +{ + vuse_optype vuses = STMT_VUSE_OPS (expr); + size_t i; + + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree v = VUSE_OP (vuses, i); + tree phi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + if (PHI_RESULT (phi) == v) + { + int opnum = opnum_of_phi (phi, pred->index); + tree p = PHI_ARG_DEF (phi, opnum); + replace_exp (VUSE_OP_PTR (vuses, i), p); + break; + } + } + } +} + +/* Make a copy of Z as it would look in basic block PRED, using the PHIs + in BB. */ + +static tree +subst_phis (struct expr_info *ei, tree Z, basic_block pred, basic_block bb) +{ + tree stmt_copy; + size_t i; + + /* Return the cached version, if we have one. */ + if (pred->index < n_phi_preds + && phi_pred_cache[pred->index] != NULL_TREE) + return phi_pred_cache[pred->index]; + + /* Otherwise, generate a new expression. */ + pre_stats.exprs_generated++; + stmt_copy = unshare_expr (Z); + create_stmt_ann (stmt_copy); + modify_stmt (stmt_copy); + get_stmt_operands (stmt_copy); + generate_expr_as_of_bb (stmt_copy, pred, bb); + set_bb_for_stmt (stmt_copy, bb); + modify_stmt (stmt_copy); + get_stmt_operands (stmt_copy); + + /* If we have vuses on the original statement, and we still have + use_ops on the generated expr, we need to copy the vuses. */ + + if (ei->loadpre_cand + && NUM_VUSES (STMT_VUSE_OPS (Z)) != 0 + && NUM_USES (STMT_USE_OPS (stmt_copy)) != 0) + { + vuse_optype vuses = STMT_VUSE_OPS (Z); + remove_vuses (stmt_copy); + + start_ssa_stmt_operands (stmt_copy); + for (i = 0; i < NUM_VUSES (vuses); i++) + add_vuse (VUSE_OP (vuses, i), stmt_copy); + finalize_ssa_stmt_operands (stmt_copy); + + generate_vops_as_of_bb (stmt_copy, pred, bb); + } + else + { + remove_vuses (stmt_copy); + remove_vdefs (stmt_copy); + } + + if (pred->index < n_phi_preds) + phi_pred_cache[pred->index] = stmt_copy; + return stmt_copy; +} + +/* Determine if def and use_tree should have the same e-version. We do + this by simply determining if something modifies the expression + between DEF and USE_TREE. USE_TREE was generated from the OPND_NUM'th + operand of the EPHI in USE_BB. If it is modified, we determine if + it is simply injured, and thus, okay. */ + +static inline bool +same_e_version_real_occ_phi_opnd (struct expr_info *ei, tree def, + basic_block use_bb, int opnd_num, + tree use_tree, bool *injured) +{ + bool not_mod = true; + *injured = false; + + if (load_modified_real_occ_real_occ (EREF_STMT (def), + use_tree)) + not_mod = false; + + if (not_mod) + return true; + else if (ei->strred_cand) + { + if (injured_real_occ_phi_opnd (ei, def, use_bb, opnd_num)) + return true; + } + return false; +} + +/* Determine whether the OPND_NUM'th operand of USE_BB's EPHI is an + injured version of DEF. */ +static inline bool +injured_real_occ_phi_opnd (struct expr_info *ei ATTRIBUTE_UNUSED, + tree def ATTRIBUTE_UNUSED, + basic_block use_bb ATTRIBUTE_UNUSED, + int opnd_num ATTRIBUTE_UNUSED) +{ + /* XXX: Implement. */ + return false; +} + +/* Determine whether the expression is modified between DEF and USE, + by comparing the hash values of the two expressions. */ +static inline bool +load_modified_real_occ_real_occ (tree def, tree use) +{ + hashval_t expr1val; + hashval_t expr2val; + vuse_optype vuses; + size_t i; + + if (TREE_CODE (def) == VA_ARG_EXPR) + expr1val = iterative_hash_expr (def, 0); + else + expr1val = iterative_hash_expr (TREE_OPERAND (def, 1), 0); + + if (TREE_CODE (use) == VA_ARG_EXPR) + expr2val = iterative_hash_expr (use, 0); + else + expr2val = iterative_hash_expr (TREE_OPERAND (use, 1), 0); + + if (expr1val == expr2val) + { + vuses = STMT_VUSE_OPS (def); + for (i = 0; i < NUM_VUSES (vuses); i++) + expr1val = iterative_hash_expr (VUSE_OP (vuses, i), expr1val); + vuses = STMT_VUSE_OPS (use); + for (i = 0; i < NUM_VUSES (vuses); i++) + expr2val = iterative_hash_expr (VUSE_OP (vuses, i), expr2val); + if (expr1val != expr2val) + return false; + } + return expr1val != expr2val; +} + +/* Determine if the expression is modified between the start of BB, + and the use at USE, ignoring phis. We do this by simple + domination, because of the properties of SSA. */ +static bool +load_modified_phi_result (basic_block bb, tree use) +{ + basic_block defbb = bb_for_stmt (SSA_NAME_DEF_STMT (use)); + if (defbb != bb) + { + /* This guards against moving around undefined variables. + However, PARM_DECL is special because it *IS* live on entry, + so it's not really undefined. */ + if (!defbb && TREE_CODE (SSA_NAME_VAR (use)) != PARM_DECL) + return true; + else if (!defbb && TREE_CODE (SSA_NAME_VAR (use)) == PARM_DECL) + return false; + if (dominated_by_p (CDI_DOMINATORS, bb, defbb)) + return false; + } + else + { + if (TREE_CODE (SSA_NAME_DEF_STMT (use)) == PHI_NODE) + return false; + } + return true; +} + +/* Determine if the variables in EXP are modified between DEF and + USE. If they are, we have to give a new e-version to the result. + For load PRE, we have to check the vuses too. For strength + reduction, we need to check whether the modification is a simple + injury. */ + +static bool +same_e_version_phi_result (struct expr_info *ei, tree def, tree exp, + tree use) +{ + stmt_ann_t ann = stmt_ann (exp); + bool not_mod = true; + size_t i; + use_optype real_expuses = USE_OPS (ann); + vuse_optype expuses; + + + if (NUM_USES (real_expuses) == 0) + return false; + + for (i = 0; i < NUM_USES (real_expuses) && not_mod; i++) + { + tree *use1p = USE_OP_PTR (real_expuses, i); + tree use1; + if (!use1p) + continue; + use1 = *use1p; + if (load_modified_phi_result (bb_for_stmt (def), use1)) + not_mod = false; + } + + if (not_mod && ei->loadpre_cand) + { + expuses = VUSE_OPS (ann); + + for (i = 0; i < NUM_VUSES (expuses) && not_mod; i++) + { + tree use1 = VUSE_OP (expuses, i); + if (load_modified_phi_result (bb_for_stmt (def), use1)) + not_mod = false; + } + } + + if (not_mod) + return true; + else if (ei->strred_cand) + { + if (injured_phi_result_real_occ (ei, def, exp, bb_for_stmt (use))) + { + EREF_INJURED (use) = true; + return true; + } + } + + return false; +} + +/* Determine whether USE_TREE is an injured version of DEF. */ + +static inline bool +injured_phi_result_real_occ (struct expr_info *ei ATTRIBUTE_UNUSED, + tree def ATTRIBUTE_UNUSED, + tree use_tree ATTRIBUTE_UNUSED, + basic_block use_bb ATTRIBUTE_UNUSED) +{ + /* XXX: Implement. */ + return false; +} + +/* Delayed renaming checks to make sure the optimistic assumptions + about ephi operand versions in rename_1 actually turned out to be + true. This requires generating the expressions for each ephi + operand, and comparing them to the versions of the occurrence it is + defined by. + Delayed rename handling is done like open64 does it. Basically, + like the delayed renaming is described in the paper, with + extensions for strength reduction. */ + +static void +process_delayed_rename (struct expr_info *ei, tree use, tree real_occ) +{ + tree exp_phi = use; + int opnd_num = 0; + + /* We only care about operands we actually have DELAYED_RENAME set + on. */ + for (opnd_num = 0; opnd_num < EPHI_NUM_ARGS (exp_phi); opnd_num++) + { + tree opnd = EPHI_ARG_DEF (exp_phi, opnd_num); + if (EPHI_ARG_DELAYED_RENAME (exp_phi, opnd_num)) + { + tree def; + tree newexp; + + /* Mark it as being processed, then generate the ephi + operand expression. */ + EPHI_ARG_DELAYED_RENAME (exp_phi, opnd_num) = false; + def = opnd; + newexp = subst_phis (ei, real_occ, + EPHI_ARG_EDGE (exp_phi, opnd_num)->src, + bb_for_stmt (exp_phi)); + + /* For operands defined by EPHIs, we need to compare the + generated expression and the phi result. + For operands defined by real occurrences, we simply compare + the phi operand and the real occurrence. */ + if (TREE_CODE (def) == EPHI_NODE) + { + tree tmp_use = EPHI_ARG_PRED (exp_phi, opnd_num); + EREF_STMT (tmp_use) = newexp; + if (same_e_version_phi_result (ei, def, newexp, + tmp_use)) + { + + if (EREF_INJURED (tmp_use)) + { + EREF_INJURED (tmp_use) = false; + EPHI_ARG_INJURED (exp_phi, opnd_num) = true; + } + if (EREF_STMT (def) == NULL) + { + /* If it was injured, we need to make up a new + phi result with the actually injured + version. */ + if (EPHI_ARG_INJURED (exp_phi, opnd_num)) + { + /* XXX: Allocate phi result with correct version. */ + + } + EREF_STMT (def) = newexp; + process_delayed_rename (ei, def, newexp); + } + } + /* If it's not the same version, the defining ephi can't + be downsafe, and the operand is not really defined by + anything. */ + else + { + EPHI_DOWNSAFE (def) = false; + EPHI_ARG_DEF (exp_phi, opnd_num) = NULL; + } + } + else if (TREE_CODE (def) == EUSE_NODE && !EUSE_PHIOP (def)) + { + bool injured = false; + if (same_e_version_real_occ_phi_opnd (ei, def, + bb_for_stmt (use), + opnd_num, newexp, &injured)) + { + tree tmp_use = EPHI_ARG_PRED (exp_phi, opnd_num); + EPHI_ARG_HAS_REAL_USE (exp_phi, opnd_num) = true; + /* EREF_STMT (opnd) = EREF_STMT (def); */ + if (injured || EREF_INJURED (def)) + EREF_INJURED (def) = true; + if (injured || EREF_INJURED (def)) + EREF_INJURED (opnd) = true; + else + EREF_STMT (tmp_use) = EREF_STMT (def); + if (EUSE_DEF (def) != NULL) + EPHI_ARG_DEF (exp_phi, opnd_num) = EUSE_DEF (def); + else + EPHI_ARG_DEF (exp_phi, opnd_num) = def; + } + else + { + EPHI_ARG_DEF (exp_phi, opnd_num) = NULL; + } + } + } + } +} + +/* For the uninitiated, the algorithm is a modified SSA renaming + algorithm (working on expressions rather than variables) . We + attempt to determine which expression occurrences have the same + ESSA version (we call it class, for equivalence/redunancy class, + which is what the papers call it. Open64 calls it e-version), and + which occurrences are actually operands for an EPHI (since this has + to be discovered from the program). + + Renaming is done like Open64 does it. Basically as the paper says, + except that we try to use earlier defined occurrences if they are + available in order to keep the number of saves down. */ + +static void +rename_1 (struct expr_info *ei) +{ + tree occur; + basic_block phi_bb; + size_t i; + varray_type stack; + + VARRAY_GENERIC_PTR_NOGC_INIT (stack, 1, "Stack for renaming"); + + /* Start by creating and inserting the occurrences in preorder, + dominator tree into a list. */ + create_and_insert_occ_in_preorder_dt_order (ei); + + /* Walk the occurrences. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + occur = VARRAY_TREE (ei->euses_dt_order, i); + + /* The current occurrence can't have the same version as + something on the top of the stack unless it is in a basic + block dominated by the basic block of the occurrence on the + top of the stack. */ + while (VARRAY_ACTIVE_SIZE (stack) > 0 + && !dominated_by_p (CDI_DOMINATORS, + bb_for_stmt (occur), + bb_for_stmt (VARRAY_TOP_TREE (stack)))) + + VARRAY_POP (stack); + + /* If the stack is empty, we assign a new version since it isn't + dominated by any other version. */ + if (VARRAY_ACTIVE_SIZE (stack) == 0 || VARRAY_TOP_TREE (stack) == NULL) + { + if (TREE_CODE (occur) == EPHI_NODE) + assign_new_class (occur, &stack, NULL); + else if (TREE_CODE (occur) == EUSE_NODE && !EUSE_PHIOP (occur)) + assign_new_class (occur, &stack, NULL); + } + else + { + if (TREE_CODE (occur) == EUSE_NODE && !EUSE_PHIOP (occur)) + { + tree tos = VARRAY_TOP_TREE (stack); + + if (TREE_CODE (tos) == EUSE_NODE && !EUSE_PHIOP (tos)) + { + /* If two real occurrences have the same + e-version/class, then this occurrence can be + defined by the prior occurrence (or whatever + the prior occurrence is defined by, if + anything). + Otherwise, we have to assign a new version. + lvalue occurrences always need a new version, + since they are definitions. */ + if (!EUSE_LVAL (occur) + && same_e_version_real_occ_real_occ (ei, tos, occur)) + { + + + tree newdef; + EREF_CLASS (occur) = EREF_CLASS (tos); + newdef = EUSE_DEF (tos) != NULL ? EUSE_DEF (tos) : tos; + EUSE_DEF (occur) = newdef; + } + else + assign_new_class (occur, &stack, NULL); + } + else if (TREE_CODE (tos) == EPHI_NODE) + { + /* Here we have an ephi occurrence at the top of the + stack, and the current occurrence is a real + occurrence. So determine if the real occurrence + has the same version as the result of the phi. + If so, then this real occurrence is defined by the + EPHI at the top of the stack. + If not, the EPHI isn't downsafe (because something + must change in between the ephi result and the next + occurrence), and we need a new version for the real + occurrence. + lvalues always need a new version. */ + if (!EUSE_LVAL (occur) + && same_e_version_phi_result (ei, tos, EREF_STMT (occur), + occur)) + { + EREF_CLASS (occur) = EREF_CLASS (tos); + EUSE_DEF (occur) = tos; + EREF_STMT (tos) = EREF_STMT (occur); + + VARRAY_PUSH_TREE (stack, occur); + } + else + { + EPHI_DOWNSAFE (tos) = false; + assign_new_class (occur, &stack, NULL); + } + } + } + /* EPHI occurrences always get new versions. */ + else if (TREE_CODE (occur) == EPHI_NODE) + { + assign_new_class (occur, &stack, NULL); + } + /* EPHI operands are optimistcally assumed to be whatever is + at the top of the stack at the time we hit the ephi + operand occurrence. The delayed renaming checks this + optimistic assumption for validity. */ + else if (TREE_CODE (occur) == EUSE_NODE && EUSE_PHIOP (occur)) + { + basic_block pred_bb = bb_for_stmt (occur); + edge e; + tree tos = VARRAY_TOP_TREE (stack); + for (e = pred_bb->succ; e; e = e->succ_next) + { + tree ephi = ephi_at_block (e->dest); + if (ephi != NULL_TREE) + { + int opnum = opnum_of_ephi (ephi, e); + + EPHI_ARG_DELAYED_RENAME (ephi, opnum) = true; + EPHI_ARG_DEF (ephi, opnum) = tos; + } + } + } + /* No EPHI can be downsafe past an exit node. */ + else if (TREE_CODE (occur) == EEXIT_NODE) + { + if (VARRAY_ACTIVE_SIZE (stack) > 0 + && TREE_CODE (VARRAY_TOP_TREE (stack)) == EPHI_NODE) + EPHI_DOWNSAFE (VARRAY_TOP_TREE (stack)) = false; + } + } + } + if (dump_file && (dump_flags & TDF_DETAILS)) + { + size_t i; + fprintf (dump_file, "Occurrences for expression "); + print_generic_expr (dump_file, ei->expr, dump_flags); + fprintf (dump_file, " after Rename 1\n"); + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + print_generic_expr (dump_file, + VARRAY_TREE (ei->euses_dt_order, i), 1); + fprintf (dump_file, "\n"); + } + } + + /* Now process the renames for EPHI's that actually have the result + valid and used. These will be the EPHI's that have the statement + set above. */ + FOR_EACH_BB (phi_bb) + { + tree ephi = ephi_at_block (phi_bb); + if (ephi != NULL && EREF_STMT (ephi) != NULL) + process_delayed_rename (ei, ephi, EREF_STMT (ephi)); + } + + /* If we didn't process the delayed rename for an ephi argument, + but thought we needed to, mark the operand as NULL. Also, if the + operand was defined by an EPHI, we can mark it not downsafe + because there can't have been a real occurrence (or else we would + have processed a rename for it). */ + FOR_EACH_BB (phi_bb) + { + tree ephi = ephi_at_block (phi_bb); + if (ephi != NULL) + { + int j; + for (j = 0; j < EPHI_NUM_ARGS (ephi); j++) + { + if (EPHI_ARG_DELAYED_RENAME (ephi, j)) + { + tree def = EPHI_ARG_DEF (ephi, j); + if (def && TREE_CODE (def) == EPHI_NODE) + EPHI_DOWNSAFE (def) = false; + EPHI_ARG_DEF (ephi, j) = NULL; + } + } + } + } + VARRAY_FREE (stack); +} + +/* Determine if the EPHI has an argument we could never insert + or extend the lifetime of, such as an argument occurring on + an abnormal edge. */ + +static bool +ephi_has_unsafe_arg (tree ephi) +{ + int i; + for (i = 0; i < EPHI_NUM_ARGS (ephi); i++) + if (EPHI_ARG_EDGE (ephi, i)->flags & EDGE_ABNORMAL) + return true; + return false; +} + +/* Reset down safety flags for non-downsafe ephis. Uses depth first + search. */ + +static void +reset_down_safe (tree currphi, int opnum) +{ + tree ephi; + int i; + + if (EPHI_ARG_HAS_REAL_USE (currphi, opnum)) + return; + ephi = EPHI_ARG_DEF (currphi, opnum); + if (!ephi || TREE_CODE (ephi) != EPHI_NODE) + return; + if (!EPHI_DOWNSAFE (ephi)) + return; + EPHI_DOWNSAFE (ephi) = false; + for (i = 0; i < EPHI_NUM_ARGS (ephi); i++) + reset_down_safe (ephi, i); +} + +/* Compute down_safety using a depth first search. + This propagates not fully anticipated phi assignments upwards. */ + +static void +compute_down_safety (struct expr_info *ei) +{ + size_t i; + basic_block bb; + FOR_EACH_BB (bb) + { + tree ephi = ephi_at_block (bb); + if (ephi == NULL_TREE) + continue; + if (ephi_has_unsafe_arg (ephi)) + EPHI_DOWNSAFE (ephi) = false; + } + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + int j; + tree ephi = VARRAY_TREE (ei->euses_dt_order, i); + if (TREE_CODE (ephi) != EPHI_NODE) + continue; + + if (!EPHI_DOWNSAFE (ephi)) + for (j = 0; j < EPHI_NUM_ARGS (ephi); j++) + reset_down_safe (ephi, j); + + } +} + +/* EPHI use node pool. We allocate ephi_use_node's out of this. */ +static alloc_pool ephi_use_pool; + +/* Add a use of DEF to it's use list. The use is at operand OPND_INDX + of USE. */ + +static void +add_ephi_use (tree def, tree use, int opnd_indx) +{ + struct ephi_use_entry *entry; + if (EPHI_USES (def) == NULL) + VARRAY_GENERIC_PTR_INIT (EPHI_USES (def), 1, "EPHI uses"); + entry = (struct ephi_use_entry *) pool_alloc (ephi_use_pool); + entry->phi = use; + entry->opnd_indx = opnd_indx; + VARRAY_PUSH_GENERIC_PTR (EPHI_USES (def), entry); +} + +/* Compute def-uses of ephis. */ + +static void +compute_du_info (struct expr_info *ei) +{ + size_t i; + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + int j; + tree ephi = VARRAY_TREE (ei->euses_dt_order, i); + if (TREE_CODE (ephi) != EPHI_NODE) + continue; + for (j = 0; j < EPHI_NUM_ARGS (ephi); j++) + { + tree def = EPHI_ARG_DEF (ephi, j); + if (def != NULL_TREE) + { + if (TREE_CODE (def) == EPHI_NODE) + add_ephi_use (def, ephi, j); +#ifdef ENABLE_CHECKING + else + if (! (TREE_CODE (def) == EUSE_NODE && !EUSE_PHIOP (def))) + abort(); +#endif + } + } + } +} + +/* STOPS marks what EPHI's/operands stop forward movement. (IE where + we can't insert past). */ + +static void +compute_stops (struct expr_info *ei) +{ + size_t i; + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + tree ephi = VARRAY_TREE (ei->euses_dt_order, i); + int j; + + if (TREE_CODE (ephi) != EPHI_NODE) + continue; + if (EPHI_CANT_BE_AVAIL (ephi)) + EPHI_STOPS (ephi) = true; + for (j = 0; j < EPHI_NUM_ARGS (ephi); j++) + if (EPHI_ARG_HAS_REAL_USE (ephi, j)) + EPHI_ARG_STOPS (ephi, j) = true; + } + do_ephi_df_search (ei, stops_search); +} + +/* Compute will_be_avail property, which consists of cant_be_avail and + stops properties. */ + +static void +compute_will_be_avail (struct expr_info *ei) +{ + do_ephi_df_search (ei, cant_be_avail_search); + compute_stops (ei); +} + +/* Insert the expressions into ei->euses_dt_order in preorder dt order. */ + +static void +insert_euse_in_preorder_dt_order (struct expr_info *ei) +{ + varray_type new_euses_dt_order; + size_t i; + VARRAY_GENERIC_PTR_NOGC_INIT (new_euses_dt_order, 1, "EUSEs"); + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + tree ref = VARRAY_TREE (ei->euses_dt_order, i); + if (TREE_CODE (ref) == EUSE_NODE || TREE_CODE (ref) == EPHI_NODE) + VARRAY_PUSH_TREE (new_euses_dt_order, ref); + } + VARRAY_FREE (ei->euses_dt_order); + ei->euses_dt_order = new_euses_dt_order; + qsort (ei->euses_dt_order->data.tree, + VARRAY_ACTIVE_SIZE (ei->euses_dt_order), + sizeof (tree), + eref_compare); + +} + +/* Determine if we can insert operand OPND_INDX of EPHI. */ + +static bool +can_insert (tree ephi, int opnd_indx) +{ + tree def; + + if (EPHI_ARG_DEF (ephi, opnd_indx) == NULL_TREE) + return true; + def = EPHI_ARG_DEF (ephi, opnd_indx); + if (!EPHI_ARG_HAS_REAL_USE (ephi, opnd_indx)) + if (TREE_CODE (def) == EPHI_NODE && !(ephi_will_be_avail (def))) + return true; + return false; +} + +/* Find the default definition of VAR. + This is incredibly ugly, since we have to walk back through all + the definitions to find the one defined by the empty statement. */ + +static tree +get_default_def (tree var, htab_t seen) +{ + def_optype defs; + size_t i; + tree defstmt = SSA_NAME_DEF_STMT (var); + + if (IS_EMPTY_STMT (defstmt)) + return var; + *(htab_find_slot (seen, var, INSERT)) = var; + if (TREE_CODE (defstmt) == PHI_NODE) + { + int j; + for (j = 0; j < PHI_NUM_ARGS (defstmt); j++) + if (htab_find (seen, PHI_ARG_DEF (defstmt, j)) == NULL) + { + if (TREE_CODE (PHI_ARG_DEF (defstmt, j)) == SSA_NAME) + { + tree temp = get_default_def (PHI_ARG_DEF (defstmt, j), seen); + if (temp != NULL_TREE) + return temp; + } + } + } + + + defs = STMT_DEF_OPS (defstmt); + for (i = 0; i < NUM_DEFS (defs); i++) + { + tree def = DEF_OP (defs, i); + if (SSA_NAME_VAR (def) == SSA_NAME_VAR (var)) + { + if (htab_find (seen, def) != NULL) + return NULL; + return get_default_def (def, seen); + } + } + + /* We should never get here. */ + abort (); +} + +/* Hunt down the right reaching def for VAR, starting with BB. Ignore + defs in statement IGNORE, and stop if we hit CURRSTMT. */ + +static tree +reaching_def (tree var, tree currstmt, basic_block bb, tree ignore) +{ + tree curruse = NULL_TREE; + block_stmt_iterator bsi; + basic_block dom; + tree phi; + + /* Check phis first. */ + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + if (phi == currstmt) + break; + if (phi == ignore) + continue; + if (names_match_p (var, PHI_RESULT (phi))) + curruse = PHI_RESULT (phi); + } + + /* We can't walk BB's backwards right now, so we have to walk *all* + the statements, and choose the last name we find. */ + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + tree *def; + def_optype defs; + size_t i; + + if (stmt == currstmt) + break; + + get_stmt_operands (stmt); + defs = STMT_DEF_OPS (stmt); + for (i = 0; i < NUM_DEFS (defs); i++) + { + def = DEF_OP_PTR (defs, i); + if (def && *def != ignore && names_match_p (var, *def)) + { + curruse = *def; + break; + } + } + } + if (curruse != NULL_TREE) + return curruse; + dom = get_immediate_dominator (CDI_DOMINATORS, bb); + if (bb == ENTRY_BLOCK_PTR) + { + htab_t temp; + temp = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL); + curruse = get_default_def (var, temp); + htab_delete (temp); + } + if (!dom) + return curruse; + return reaching_def (var, currstmt, dom, ignore); +} + +/* Insert one ephi operand that doesn't currently exist as a use. */ + +static void +insert_one_operand (struct expr_info *ei, tree ephi, int opnd_indx, + tree x, edge succ, tree **avdefsp) +{ + /* FIXME. pre_insert_on_edge should probably disappear. */ + extern void pre_insert_on_edge (edge, tree); + tree expr; + tree temp = ei->temp; + tree copy; + tree newtemp; + basic_block bb = bb_for_stmt (x); + + /* Insert definition of expr at end of BB containing x. */ + copy = TREE_OPERAND (EREF_STMT (ephi), 1); + copy = unshare_expr (copy); + expr = build (MODIFY_EXPR, TREE_TYPE (ei->expr), + temp, copy); + expr = subst_phis (ei, expr, bb, bb_for_stmt (ephi)); + newtemp = make_ssa_name (temp, expr); + TREE_OPERAND (expr, 0) = newtemp; + copy = TREE_OPERAND (expr, 1); + if (dump_file) + { + fprintf (dump_file, "In BB %d, insert save of ", bb->index); + print_generic_expr (dump_file, expr, dump_flags); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, newtemp, dump_flags); + fprintf (dump_file, " after "); + print_generic_stmt (dump_file, last_stmt (bb), dump_flags); + fprintf (dump_file, " (on edge), because of EPHI"); + fprintf (dump_file, " in BB %d\n", bb_for_stmt (ephi)->index); + } + + /* Do the insertion. */ + /* ??? Previously we did bizarre searching, presumably to get + around bugs elsewhere in the infrastructure. I'm not sure + if we really should be using pre_insert_on_edge + or just bsi_insert_after at the end of BB. */ + pre_insert_on_edge (succ, expr); + + EPHI_ARG_DEF (ephi, opnd_indx) + = create_expr_ref (ei, ei->expr, EUSE_NODE, bb, 0); + EUSE_DEF (x) = EPHI_ARG_DEF (ephi, opnd_indx); + VARRAY_PUSH_TREE (ei->euses_dt_order, EPHI_ARG_DEF (ephi, opnd_indx)); + qsort (ei->euses_dt_order->data.tree, + VARRAY_ACTIVE_SIZE (ei->euses_dt_order), + sizeof (tree), + eref_compare); + EREF_TEMP (EUSE_DEF (x)) = newtemp; + EREF_RELOAD (EUSE_DEF (x)) = false; + EREF_SAVE (EUSE_DEF (x)) = false; + EUSE_INSERTED (EUSE_DEF (x)) = true; + EUSE_PHIOP (EUSE_DEF (x)) = false; + EREF_SAVE (x) = false; + EREF_RELOAD (x) = false; + EUSE_INSERTED (x) = true; + EREF_CLASS (x) = class_count++; + EREF_CLASS (EUSE_DEF (x)) = class_count++; + *avdefsp = xrealloc (*avdefsp, sizeof (tree) * (class_count + 1)); + (*avdefsp)[class_count - 2] = x; + (*avdefsp)[class_count - 1] = EUSE_DEF (x); + pre_stats.saves++; +} + +/* First step of finalization. Determine which expressions are being + saved and which are being deleted. + This is done as a simple dominator based availabilty calculation, + using the e-versions/redundancy classes. */ + +static bool +finalize_1 (struct expr_info *ei) +{ + tree x; + int nx; + bool made_a_reload = false; + size_t i; + tree *avdefs; + + avdefs = xcalloc (class_count + 1, sizeof (tree)); + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + x = VARRAY_TREE (ei->euses_dt_order, i); + nx = EREF_CLASS (x); + + if (TREE_CODE (x) == EPHI_NODE) + { + if (ephi_will_be_avail (x)) + avdefs[nx] = x; + } + else if (TREE_CODE (x) == EUSE_NODE && EUSE_LVAL (x)) + { + avdefs[nx] = x; + } + else if (TREE_CODE (x) == EUSE_NODE && !EUSE_PHIOP (x)) + { + if (avdefs[nx] == NULL + || !dominated_by_p (CDI_DOMINATORS, bb_for_stmt (x), + bb_for_stmt (avdefs[nx]))) + { + EREF_RELOAD (x) = false; + avdefs[nx] = x; + EUSE_DEF (x) = NULL; + } + else + { + EREF_RELOAD (x) = true; + made_a_reload = true; + EUSE_DEF (x) = avdefs[nx]; +#ifdef ENABLE_CHECKING + if (EREF_CLASS (x) != EREF_CLASS (avdefs[nx])) + abort (); +#endif + } + } + else + { + edge succ; + basic_block bb = bb_for_stmt (x); + /* For each ephi in the successor blocks. */ + for (succ = bb->succ; succ; succ = succ->succ_next) + { + tree ephi = ephi_at_block (succ->dest); + if (ephi == NULL_TREE) + continue; + if (ephi_will_be_avail (ephi)) + { + int opnd_indx = opnum_of_ephi (ephi, succ); +#ifdef ENABLE_CHECKING + if (EPHI_ARG_PRED (ephi, opnd_indx) != x) + abort (); +#endif + if (can_insert (ephi, opnd_indx)) + { + insert_one_operand (ei, ephi, opnd_indx, x, succ, + &avdefs); + } + else + { + nx = EREF_CLASS (EPHI_ARG_DEF (ephi,opnd_indx)); + EPHI_ARG_DEF (ephi, opnd_indx) = avdefs[nx]; + } + } + } + } + } + free (avdefs); + return made_a_reload; +} + +/* Mark the necessary SAVE bits on X. */ + +static void +set_save (struct expr_info *ei, tree X) +{ + if (TREE_CODE (X) == EUSE_NODE && !EUSE_PHIOP (X)) + EREF_SAVE (X) = true; + else if (TREE_CODE (X) == EPHI_NODE) + { + int curr_phiop; + for (curr_phiop = 0; curr_phiop < EPHI_NUM_ARGS (X); curr_phiop++) + { + tree w = EPHI_ARG_DEF (X, curr_phiop); + if (!EPHI_ARG_PROCESSED2 (X, curr_phiop)) + { + EPHI_ARG_PROCESSED2 (X, curr_phiop) = true; + if (w) + set_save (ei, w); + } + } + } +} + +/* DFS Search function: Return true if PHI is can't be available. */ + +static bool +cba_search_seen (tree phi) +{ + return EPHI_CANT_BE_AVAIL (phi); +} + +/* DFS Search function: Mark PHI as can't be available when seen. */ + +static void +cba_search_set_seen (tree phi) +{ + EPHI_CANT_BE_AVAIL (phi) = true; +} + +/* DFS Search function: Return true if PHI should be marked can't be + available due to a NULL operand. */ + +static bool +cba_search_start_from (tree phi) +{ + if (!EPHI_DOWNSAFE (phi)) + { + int i; + for (i = 0; i < EPHI_NUM_ARGS (phi); i++) + if (EPHI_ARG_DEF (phi, i) == NULL_TREE + || EPHI_ARG_EDGE (phi, i)->flags & EDGE_ABNORMAL) + return true; + } + return false; +} + +/* DFS Search function: Return true if the used PHI is not downsafe, + unless we have a real use for the operand. */ + +static bool +cba_search_continue_from_to (tree def_phi ATTRIBUTE_UNUSED, + int opnd_indx, + tree use_phi) +{ + if (EPHI_ARG_HAS_REAL_USE (use_phi, opnd_indx) && + !(EPHI_ARG_EDGE (use_phi, opnd_indx)->flags & EDGE_ABNORMAL)) + return false; + if (!EPHI_DOWNSAFE (use_phi)) + return true; + return false; +} + +/* DFS Search function: Return true if this PHI stops forward + movement. */ + +static bool +stops_search_seen (tree phi) +{ + return EPHI_STOPS (phi); +} + +/* DFS Search function: Mark the PHI as stopping forward movement. */ + +static void +stops_search_set_seen (tree phi) +{ + EPHI_STOPS (phi) = true; +} + +/* DFS Search function: Note that the used phi argument stops forward + movement. */ + +static void +stops_search_reach_from_to (tree def_phi ATTRIBUTE_UNUSED, + int opnd_indx, + tree use_phi) +{ + EPHI_ARG_STOPS (use_phi, opnd_indx) = true; +} + +/* DFS Search function: Return true if the PHI has any arguments + stopping forward movement. */ + +static bool +stops_search_start_from (tree phi) +{ + int i; + for (i = 0; i < EPHI_NUM_ARGS (phi); i++) + if (EPHI_ARG_STOPS (phi, i)) + return true; + return false; +} + +/* DFS Search function: Return true if the PHI has any arguments + stopping forward movement. */ + +static bool +stops_search_continue_from_to (tree def_phi ATTRIBUTE_UNUSED, + int opnd_indx ATTRIBUTE_UNUSED, + tree use_phi) +{ + return stops_search_start_from (use_phi); +} + +/* DFS Search function: Return true if the replacing occurrence is + known. */ + +static bool +repl_search_seen (tree phi) +{ + return EPHI_REP_OCCUR_KNOWN (phi); +} + +/* DFS Search function: Set the identical_to field and note the + replacing occurrence is now known. */ + +static void +repl_search_set_seen (tree phi) +{ + int i; + +#ifdef ENABLE_CHECKING + if (!ephi_will_be_avail (phi)) + abort (); +#endif + + if (EPHI_IDENTICAL_TO (phi) == NULL_TREE) + { + for (i = 0; i < EPHI_NUM_ARGS (phi); i++) + { + tree identical_to = occ_identical_to (EPHI_ARG_DEF (phi, i)); + if (identical_to != NULL_TREE) + { + if (EPHI_IDENTICAL_TO (phi) == NULL) + EPHI_IDENTICAL_TO (phi) = identical_to; + if (EPHI_ARG_INJURED (phi, i)) + EPHI_IDENT_INJURED (phi) = true; + } + } + } + EPHI_REP_OCCUR_KNOWN (phi) = true; +} + +/* Helper function. Return true if any argument in the PHI is + injured. */ + +static inline bool +any_operand_injured (tree ephi) +{ + int i; + for (i = 0; i < EPHI_NUM_ARGS (ephi); i++) + if (EPHI_ARG_INJURED (ephi, i)) + return true; + return false; + +} + +/* DFS Search function: Note the identity of the used phi operand is + the same as it's defining phi operand, if that phi will be + available, and it's known. */ + +static void +repl_search_reach_from_to (tree def_phi, int opnd_indx ATTRIBUTE_UNUSED, + tree use_phi) +{ + if (ephi_will_be_avail (use_phi) + && EPHI_IDENTITY (use_phi) + && EPHI_IDENTICAL_TO (use_phi) == NULL_TREE) + { + EPHI_IDENTICAL_TO (use_phi) = EPHI_IDENTICAL_TO (def_phi); + + if (EPHI_IDENT_INJURED (def_phi) + || any_operand_injured (use_phi)) + EPHI_IDENT_INJURED (use_phi) = true; + } +} + +/* DFS Search function: Return true if the PHI will be available, + it's an identity PHI, and it's arguments are identical to + something. */ + +static bool +repl_search_start_from (tree phi) +{ + if (ephi_will_be_avail (phi) && EPHI_IDENTITY (phi)) + { + int i; + for (i = 0; i < EPHI_NUM_ARGS (phi); i++) + if (occ_identical_to (EPHI_ARG_DEF (phi, i)) != NULL_TREE) + return true; + } + return false; +} + +/* DFS Search function: Return true if the using PHI is will be available, + and identity. */ + +static bool +repl_search_continue_from_to (tree def_phi ATTRIBUTE_UNUSED, + int opnd_indx ATTRIBUTE_UNUSED, + tree use_phi) +{ + return ephi_will_be_avail (use_phi) && EPHI_IDENTITY (use_phi); +} + +/* Mark all will-be-avail ephi's in the dominance frontier of BB as + required. */ + +static void +require_phi (struct expr_info *ei, basic_block bb) +{ + size_t i; + EXECUTE_IF_SET_IN_BITMAP (pre_dfs[bb->index], 0, i, + { + tree ephi; + ephi = ephi_at_block (BASIC_BLOCK (i)); + if (ephi != NULL_TREE + && ephi_will_be_avail (ephi) + && EPHI_IDENTITY (ephi)) + { + EPHI_IDENTITY (ephi) = false; + require_phi (ei, BASIC_BLOCK (i)); + } + }); +} + +/* Return the occurrence this occurrence is identical to, if one exists. */ + +static tree +occ_identical_to (tree t) +{ + if (TREE_CODE (t) == EUSE_NODE && !EUSE_PHIOP (t)) + return t; + else if (TREE_CODE (t) == EUSE_NODE && EUSE_PHIOP (t)) + return t; + else if (TREE_CODE (t) == EPHI_NODE) + { + if (EPHI_IDENTITY (t) && EPHI_REP_OCCUR_KNOWN (t)) + return EPHI_IDENTICAL_TO (t); + else if (!EPHI_IDENTITY (t)) + return t; + } + return NULL_TREE; +} + +/* Return true if NODE was or is going to be saved. */ +static bool +really_available_def (tree node) +{ + if (TREE_CODE (node) == EUSE_NODE + && EUSE_PHIOP (node) + && EUSE_INSERTED (node)) + return true; + if (TREE_CODE (node) == EUSE_NODE + && EUSE_DEF (node) == NULL_TREE) + return true; + return false; +} + + +/* Second part of the finalize step. Performs save bit setting, and + ESSA minimization. */ + +static void +finalize_2 (struct expr_info *ei) +{ + size_t i; + + insert_euse_in_preorder_dt_order (ei); + /* Note which uses need to be saved to a temporary. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + tree ref = VARRAY_TREE (ei->euses_dt_order, i); + if (TREE_CODE (ref) == EUSE_NODE + && !EUSE_PHIOP (ref) + && EREF_RELOAD (ref)) + { + set_save (ei, EUSE_DEF (ref)); + } + } + + /* ESSA Minimization. Determines which phis are identical to other + phis, and not strictly necessary. */ + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + tree ephi = VARRAY_TREE (ei->euses_dt_order, i); + if (TREE_CODE (ephi) != EPHI_NODE) + continue; + EPHI_IDENTITY (ephi) = true; + EPHI_IDENTICAL_TO (ephi) = NULL; + } + + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + tree ephi = VARRAY_TREE (ei->euses_dt_order, i); + if (!ephi || TREE_CODE (ephi) != EPHI_NODE) + continue; + if (ephi_will_be_avail (ephi)) + { + int k; + for (k = 0; k < EPHI_NUM_ARGS (ephi); k++) + { + if (EPHI_ARG_INJURED (ephi, k)) + require_phi (ei, EPHI_ARG_EDGE (ephi, k)->src); + else if (EPHI_ARG_DEF (ephi, k) + && TREE_CODE (EPHI_ARG_DEF (ephi, k)) == EUSE_NODE + && really_available_def (EPHI_ARG_DEF (ephi, k))) + require_phi (ei, bb_for_stmt (EPHI_ARG_DEF (ephi, k))); + } + } + } + do_ephi_df_search (ei, replacing_search); +} + +/* Perform a DFS on EPHI using the functions in SEARCH. */ + +static void +do_ephi_df_search_1 (struct ephi_df_search search, tree ephi) +{ + varray_type uses; + size_t i; + search.set_seen (ephi); + + uses = EPHI_USES (ephi); + if (!uses) + return; + for (i = 0; i < VARRAY_ACTIVE_SIZE (uses); i++) + { + struct ephi_use_entry *use = VARRAY_GENERIC_PTR (uses, i); + if (search.reach_from_to) + search.reach_from_to (ephi, use->opnd_indx, use->phi); + if (!search.seen (use->phi) && + search.continue_from_to (ephi, use->opnd_indx, use->phi)) + { + do_ephi_df_search_1 (search, use->phi); + } + } +} + +/* Perform a DFS on the EPHI's, using the functions in SEARCH. */ + +static void +do_ephi_df_search (struct expr_info *ei, struct ephi_df_search search) +{ + size_t i; + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + tree ephi = VARRAY_TREE (ei->euses_dt_order, i); + if (!ephi || TREE_CODE (ephi) != EPHI_NODE) + continue; + if (!search.seen (ephi) + && search.start_from (ephi)) + do_ephi_df_search_1 (search, ephi); + } +} + +#if 0 +/* Calculate the increment necessary due to EXPR for the temporary. */ +static tree +calculate_increment (struct expr_info *ei, tree expr) +{ + tree incr; + + /*XXX: Currently assume it's like a = a + 5, thus, this will give us the 5. + */ + incr = TREE_OPERAND (TREE_OPERAND (expr, 1), 1); + if (TREE_CODE (incr) != INTEGER_CST) + abort(); + if (TREE_CODE (ei->expr) == MULT_EXPR) + incr = fold (build (MULT_EXPR, TREE_TYPE (ei->expr), + incr, TREE_OPERAND (ei->expr, 1))); +#if DEBUGGING_STRRED + if (dump_file) + { + fprintf (dump_file, "Increment calculated to be: "); + print_generic_expr (dump_file, incr, 0); + fprintf (dump_file, "\n"); + } +#endif + return incr; +} +#endif + + +/* Perform an insertion of EXPR before/after USE, depending on the + value of BEFORE. */ + +static tree +do_proper_save (tree use, tree expr, int before) +{ + basic_block bb = bb_for_stmt (use); + block_stmt_iterator bsi; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + if (bsi_stmt (bsi) == use) + { + if (before) + bsi_insert_before (&bsi, expr, BSI_SAME_STMT); + else + bsi_insert_after (&bsi, expr, BSI_SAME_STMT); + return use; + } + } + abort (); +} + +/* Get the temporary for ESSA node USE. + Takes into account minimized ESSA. */ +static tree +get_temp (tree use) +{ + tree newtemp; + if (TREE_CODE (use) == EPHI_NODE && EPHI_IDENTITY (use)) + { + tree newuse = use; + while (TREE_CODE (newuse) == EPHI_NODE + && EPHI_IDENTITY (newuse)) + { +#ifdef ENABLE_CHECKING + if (!EPHI_IDENTICAL_TO (newuse)) + abort (); +#endif + newuse = EPHI_IDENTICAL_TO (newuse); + if (TREE_CODE (newuse) != EPHI_NODE) + break; + } + if (TREE_CODE (EREF_TEMP (newuse)) == PHI_NODE) + newtemp = PHI_RESULT (EREF_TEMP (newuse)); + else + newtemp = EREF_TEMP (newuse); + } + else + { + if (TREE_CODE (EREF_TEMP (use)) == PHI_NODE) + newtemp = PHI_RESULT (EREF_TEMP (use)); + else + newtemp = EREF_TEMP (use); + } + return newtemp; +} + +/* Return the side of the statement that contains an SSA name. */ + +static tree +pick_ssa_name (tree stmt) +{ + if (TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME) + return TREE_OPERAND (stmt, 0); + else if (TREE_CODE (TREE_OPERAND (stmt, 1)) == SSA_NAME) + return TREE_OPERAND (stmt, 1); + else + abort (); +} + +/* Code motion step of SSAPRE. Take the save bits, and reload bits, + and perform the saves and reloads. Also insert new phis where + necessary. */ + +static void +code_motion (struct expr_info *ei) +{ + tree use; + tree newtemp; + size_t euse_iter; + tree temp = ei->temp; + basic_block bb; + + /* First, add the phi node temporaries so the reaching defs are + always right. */ + for (euse_iter = 0; + euse_iter < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); + euse_iter++) + { + + use = VARRAY_TREE (ei->euses_dt_order, euse_iter); + if (TREE_CODE (use) != EPHI_NODE) + continue; + if (ephi_will_be_avail (use) && !EPHI_IDENTITY (use)) + { + bb = bb_for_stmt (use); + /* Add the new PHI node to the list of PHI nodes for block BB. */ + bb_ann (bb)->phi_nodes = chainon (phi_nodes (bb), EREF_TEMP (use)); + } + else if (EPHI_IDENTITY (use)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Pointless EPHI in block %d\n", + bb_for_stmt (use)->index); + } + } + } + /* Now do the actual saves and reloads, plus repairs. */ + for (euse_iter = 0; + euse_iter < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); + euse_iter++) + { + use = VARRAY_TREE (ei->euses_dt_order, euse_iter); +#ifdef ENABLE_CHECKING + if (TREE_CODE (use) == EUSE_NODE && EUSE_PHIOP (use) + && (EREF_RELOAD (use) || EREF_SAVE (use))) + abort (); +#endif + if (EREF_SAVE (use) && !EUSE_INSERTED (use)) + { + tree newexpr; + tree use_stmt; + tree copy; + basic_block usebb = bb_for_stmt (use); + use_stmt = EREF_STMT (use); + + copy = TREE_OPERAND (use_stmt, 1); + copy = unshare_expr (copy); + newexpr = build (MODIFY_EXPR, TREE_TYPE (temp), temp, copy); + newtemp = make_ssa_name (temp, newexpr); + EREF_TEMP (use) = newtemp; + TREE_OPERAND (newexpr, 0) = newtemp; + TREE_OPERAND (use_stmt, 1) = newtemp; + + if (dump_file) + { + fprintf (dump_file, "In BB %d, insert save of ", + usebb->index); + print_generic_expr (dump_file, copy, dump_flags); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, newtemp, dump_flags); + fprintf (dump_file, " before statement "); + print_generic_expr (dump_file, use_stmt, dump_flags); + fprintf (dump_file, "\n"); + if (EXPR_HAS_LOCATION (use_stmt)) + fprintf (dump_file, " on line %d\n", + EXPR_LINENO (use_stmt)); + } + modify_stmt (newexpr); + modify_stmt (use_stmt); + set_bb_for_stmt (newexpr, usebb); + EREF_STMT (use) = do_proper_save (use_stmt, newexpr, true); + pre_stats.saves++; + } + else if (EREF_RELOAD (use)) + { + tree use_stmt; + tree newtemp; + + use_stmt = EREF_STMT (use); + bb = bb_for_stmt (use_stmt); + + newtemp = get_temp (EUSE_DEF (use)); + if (!newtemp) + abort (); + if (dump_file) + { + fprintf (dump_file, "In BB %d, insert reload of ", + bb->index); + print_generic_expr (dump_file, + TREE_OPERAND (use_stmt, 1), 0); + fprintf (dump_file, " from "); + print_generic_expr (dump_file, newtemp, dump_flags); + fprintf (dump_file, " in statement "); + print_generic_stmt (dump_file, use_stmt, dump_flags); + fprintf (dump_file, "\n"); + if (EXPR_HAS_LOCATION (use_stmt)) + fprintf (dump_file, " on line %d\n", + EXPR_LINENO (use_stmt)); + } + TREE_OPERAND (use_stmt, 1) = newtemp; + EREF_TEMP (use) = newtemp; + modify_stmt (use_stmt); + pre_stats.reloads++; + } + } + + /* Now do the phi nodes. */ + for (euse_iter = 0; + euse_iter < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); + euse_iter++) + { + use = VARRAY_TREE (ei->euses_dt_order, euse_iter); + if (TREE_CODE (use) == EPHI_NODE + && ephi_will_be_avail (use) + && !EPHI_IDENTITY (use)) + { + int i; + tree argdef; + bb = bb_for_stmt (use); + if (dump_file) + { + fprintf (dump_file, + "In BB %d, insert PHI to replace EPHI\n", bb->index); + } + newtemp = EREF_TEMP (use); + for (i = 0; i < EPHI_NUM_ARGS (use); i++) + { + tree rdef; + argdef = EPHI_ARG_DEF (use, i); + if (argdef == use) + rdef = get_temp (use); + else if (EREF_RELOAD (argdef) || EREF_SAVE (argdef)) + rdef = get_temp (argdef); + else if (TREE_CODE (argdef) == EPHI_NODE) + rdef = get_temp (argdef); + else if (argdef + && EPHI_ARG_HAS_REAL_USE (use, i) + && EREF_STMT (argdef) + && !EPHI_ARG_INJURED (use, i)) + rdef = pick_ssa_name (EREF_STMT (argdef)); + else + abort (); + + if (!rdef) + abort(); + add_phi_arg (&newtemp, rdef, EPHI_ARG_EDGE (use, i)); + } + + /* Associate BB to the PHI node. */ + set_bb_for_stmt (EREF_TEMP (use), bb); + pre_stats.newphis++; + + } + } +} + +/* Compute the iterated dominance frontier of a statement. */ + +static bitmap +compute_idfs (bitmap * dfs, tree stmt) +{ + fibheap_t worklist; + sbitmap inworklist, done; + bitmap idf; + size_t i; + basic_block block; + + block = bb_for_stmt (stmt); + if (idfs_cache[block->index] != NULL) + return idfs_cache[block->index]; + + inworklist = sbitmap_alloc (last_basic_block); + done = sbitmap_alloc (last_basic_block); + worklist = fibheap_new (); + sbitmap_zero (inworklist); + sbitmap_zero (done); + + idf = BITMAP_XMALLOC (); + bitmap_zero (idf); + + block = bb_for_stmt (stmt); + fibheap_insert (worklist, block->index, (void *)(size_t)block->index); + SET_BIT (inworklist, block->index); + + while (!fibheap_empty (worklist)) + { + int a = (size_t) fibheap_extract_min (worklist); + if (TEST_BIT (done, a)) + continue; + SET_BIT (done, a); + if (idfs_cache[a]) + { + bitmap_a_or_b (idf, idf, idfs_cache[a]); + EXECUTE_IF_SET_IN_BITMAP (idfs_cache[a], 0, i, + { + SET_BIT (inworklist, i); + SET_BIT (done, i); + }); + } + else + { + bitmap_a_or_b (idf, idf, dfs[a]); + EXECUTE_IF_SET_IN_BITMAP (dfs[a], 0, i, + { + if (!TEST_BIT (inworklist, i)) + { + SET_BIT (inworklist, i); + fibheap_insert (worklist, i, (void *)i); + } + }); + } + + } + fibheap_delete (worklist); + sbitmap_free (inworklist); + sbitmap_free (done); + idfs_cache[block->index] = idf; + return idf; + +} + +/* Return true if EXPR is a strength reduction candidate. */ +static bool +is_strred_cand (const tree expr ATTRIBUTE_UNUSED) +{ +#if 0 + if (TREE_CODE (TREE_OPERAND (expr, 1)) != MULT_EXPR + && TREE_CODE (TREE_OPERAND (expr, 1)) != MINUS_EXPR + && TREE_CODE (TREE_OPERAND (expr, 1)) != NEGATE_EXPR + && TREE_CODE (TREE_OPERAND (expr, 1)) != PLUS_EXPR) + return false; + return true; +#endif + return false; +} + + + +/* Determine if two expressions are lexically equivalent. */ + +static inline bool +expr_lexically_eq (const tree v1, const tree v2) +{ + if (TREE_CODE_CLASS (TREE_CODE (v1)) != TREE_CODE_CLASS (TREE_CODE (v2))) + return false; + if (TREE_CODE (v1) != TREE_CODE (v2)) + return false; + switch (TREE_CODE_CLASS (TREE_CODE (v1))) + { + case 'r': + case '1': + return names_match_p (TREE_OPERAND (v1, 0), TREE_OPERAND (v2, 0)); + case 'x': + case 'd': + return names_match_p (v1, v2); + case '2': + { + bool match; + match = names_match_p (TREE_OPERAND (v1, 0), TREE_OPERAND (v2, 0)); + if (!match) + return false; + match = names_match_p (TREE_OPERAND (v1, 1), TREE_OPERAND (v2, 1)); + if (!match) + return false; + return true; + } + default: + return false; + } + +} + +/* Free an expression info structure. */ + +static void +free_expr_info (struct expr_info *v1) +{ + struct expr_info *e1 = (struct expr_info *)v1; + VARRAY_FREE (e1->occurs); + VARRAY_FREE (e1->kills); + VARRAY_FREE (e1->lefts); + VARRAY_FREE (e1->reals); + VARRAY_FREE (e1->euses_dt_order); +} + +/* Process left occurrences and kills due to EXPR. + A left occurrence occurs wherever a variable in an expression we + are PRE'ing is stored to directly in a def, or indirectly because + of a VDEF of an expression that we VUSE. */ + +static void +process_left_occs_and_kills (varray_type bexprs, tree expr) +{ + size_t i, j, k; + + stmt_ann_t ann = stmt_ann (expr); + vdef_optype vdefs; + vuse_optype vuses; + def_optype defs; + defs = DEF_OPS (ann); + vdefs = VDEF_OPS (ann); + if (NUM_DEFS (defs) == 0 && NUM_VDEFS (vdefs) == 0) + return; + + for (j = 0; j < VARRAY_ACTIVE_SIZE (bexprs); j++) + { + struct expr_info *ei = VARRAY_GENERIC_PTR (bexprs, j); + tree vuse_name; + tree random_occur; + stmt_ann_t ann; + + if (!ei->loadpre_cand) + continue; + + /* If we define the variable itself (IE a in *a, or a in a), + it's a left occurrence. */ + for (i = 0; i < NUM_DEFS (defs); i++) + { + if (names_match_p (DEF_OP (defs, i), ei->expr)) + { + if (TREE_CODE (expr) == ASM_EXPR) + { + ei->loadpre_cand = false; + continue; + } + VARRAY_PUSH_TREE (ei->lefts, expr); + VARRAY_PUSH_TREE (ei->occurs, NULL); + VARRAY_PUSH_TREE (ei->kills, NULL); + } + } + + /* If we VDEF the VUSE of the expression, it's also a left + occurrence. */ + random_occur = VARRAY_TREE (ei->occurs, 0); + ann = stmt_ann (random_occur); + vuses = VUSE_OPS (ann); + if (NUM_VDEFS (vdefs) != 0) + { + for (k = 0; k < NUM_VUSES (vuses); k++) + { + vuse_name = VUSE_OP (vuses, k); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + if (names_match_p (VDEF_OP (vdefs, i), vuse_name)) + { + VARRAY_PUSH_TREE (ei->lefts, expr); + VARRAY_PUSH_TREE (ei->occurs, NULL); + VARRAY_PUSH_TREE (ei->kills, NULL); + } + } + } + } + } +} + +/* Perform SSAPRE on an expression. */ + +static int +pre_expression (struct expr_info *slot, void *data, bitmap vars_to_rename) +{ + struct expr_info *ei = (struct expr_info *) slot; + basic_block bb; + + class_count = 0; + eref_id_counter = 0; + + /* If we don't have two occurrences along any dominated path, and + it's not load PRE, this is a waste of time. */ + + if (VARRAY_ACTIVE_SIZE (ei->reals) < 2) + return 1; + + memset (&pre_stats, 0, sizeof (struct pre_stats_d)); + + ei->temp = create_tmp_var (TREE_TYPE (ei->expr), "pretmp"); + add_referenced_tmp_var (ei->temp); + + bitmap_clear (created_phi_preds); + ephi_pindex_htab = htab_create (500, ephi_pindex_hash, ephi_pindex_eq, free); + phi_pred_cache = xcalloc (last_basic_block, sizeof (tree)); + n_phi_preds = last_basic_block; + + if (!expr_phi_insertion ((bitmap *)data, ei)) + goto cleanup; + rename_1 (ei); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + size_t i; + fprintf (dump_file, "Occurrences for expression "); + print_generic_expr (dump_file, ei->expr, dump_flags); + fprintf (dump_file, " after Rename 2\n"); + for (i = 0; i < VARRAY_ACTIVE_SIZE (ei->euses_dt_order); i++) + { + print_generic_expr (dump_file, + VARRAY_TREE (ei->euses_dt_order, i), 1); + fprintf (dump_file, "\n"); + } + } + compute_down_safety (ei); + compute_du_info (ei); + compute_will_be_avail (ei); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "EPHI's for expression "); + print_generic_expr (dump_file, ei->expr, dump_flags); + fprintf (dump_file, + " after down safety and will_be_avail computation\n"); + FOR_EACH_BB (bb) + { + tree ephi = ephi_at_block (bb); + if (ephi != NULL) + { + print_generic_expr (dump_file, ephi, 1); + fprintf (dump_file, "\n"); + } + } + } + + if (finalize_1 (ei)) + { + finalize_2 (ei); + code_motion (ei); + if (ei->loadpre_cand) + bitmap_set_bit (vars_to_rename, var_ann (ei->temp)->uid); + } + + clear_all_eref_arrays (); + if (dump_file) + if (dump_flags & TDF_STATS) + { + fprintf (dump_file, "PRE stats:\n"); + fprintf (dump_file, "Reloads:%d\n", pre_stats.reloads); + fprintf (dump_file, "Saves:%d\n", pre_stats.saves); + fprintf (dump_file, "Repairs:%d\n", pre_stats.repairs); + fprintf (dump_file, "New phis:%d\n", pre_stats.newphis); + fprintf (dump_file, "EPHI memory allocated:%d\n", + pre_stats.ephi_allocated); + fprintf (dump_file, "EREF memory allocated:%d\n", + pre_stats.eref_allocated); + fprintf (dump_file, "Expressions generated for rename2:%d\n", + pre_stats.exprs_generated); + } + cleanup: + free (phi_pred_cache); + if (ephi_pindex_htab) + { + htab_delete (ephi_pindex_htab); + ephi_pindex_htab = NULL; + } + + + return 0; +} + + +/* Step 1 - Collect the expressions to perform PRE on. */ + +static void +collect_expressions (basic_block block, varray_type *bexprsp) +{ + size_t k; + block_stmt_iterator j; + basic_block son; + + varray_type bexprs = *bexprsp; + + for (j = bsi_start (block); !bsi_end_p (j); bsi_next (&j)) + { + tree stmt = bsi_stmt (j); + tree expr = stmt; + tree orig_expr = expr; + stmt_ann_t ann; + struct expr_info *slot = NULL; + + get_stmt_operands (expr); + ann = stmt_ann (expr); + + if (NUM_USES (USE_OPS (ann)) == 0) + { + process_left_occs_and_kills (bexprs, expr); + continue; + } + + if (TREE_CODE (expr) == MODIFY_EXPR) + expr = TREE_OPERAND (expr, 1); + if ((TREE_CODE_CLASS (TREE_CODE (expr)) == '2' + || TREE_CODE_CLASS (TREE_CODE (expr)) == '<' + /*|| TREE_CODE_CLASS (TREE_CODE (expr)) == '1'*/ + || TREE_CODE (expr) == SSA_NAME + || TREE_CODE (expr) == INDIRECT_REF) + && !ann->makes_aliased_stores + && !ann->has_volatile_ops) + { + bool is_scalar = true; + tree origop0 = TREE_OPERAND (orig_expr, 0); + + if (AGGREGATE_TYPE_P (TREE_TYPE (origop0)) + || TREE_CODE (TREE_TYPE (origop0)) == COMPLEX_TYPE) + is_scalar = false; + + if (is_scalar + && (TREE_CODE (expr) == SSA_NAME + || (TREE_CODE (expr) == INDIRECT_REF + && !DECL_P (TREE_OPERAND (expr, 0))) + ||(!DECL_P (TREE_OPERAND (expr, 0)) + && (!TREE_OPERAND (expr, 1) + || !DECL_P (TREE_OPERAND (expr, 1)))))) + { + for (k = 0; k < VARRAY_ACTIVE_SIZE (bexprs); k++) + { + slot = VARRAY_GENERIC_PTR (bexprs, k); + if (expr_lexically_eq (slot->expr, expr)) + break; + } + if (k >= VARRAY_ACTIVE_SIZE (bexprs)) + slot = NULL; + if (slot) + { + VARRAY_PUSH_TREE (slot->occurs, orig_expr); + VARRAY_PUSH_TREE (slot->kills, NULL); + VARRAY_PUSH_TREE (slot->lefts, NULL); + VARRAY_PUSH_TREE (slot->reals, stmt); + slot->strred_cand &= is_strred_cand (orig_expr); + } + else + { + slot = ggc_alloc (sizeof (struct expr_info)); + slot->expr = expr; + VARRAY_GENERIC_PTR_NOGC_INIT (slot->occurs, 1, "Occurrence"); + VARRAY_GENERIC_PTR_NOGC_INIT (slot->kills, 1, "Kills"); + VARRAY_GENERIC_PTR_NOGC_INIT (slot->lefts, 1, "Left occurrences"); + VARRAY_GENERIC_PTR_NOGC_INIT (slot->reals, 1, "Real occurrences"); + VARRAY_GENERIC_PTR_NOGC_INIT (slot->euses_dt_order, 1, "EUSEs"); + + VARRAY_PUSH_TREE (slot->occurs, orig_expr); + VARRAY_PUSH_TREE (slot->kills, NULL); + VARRAY_PUSH_TREE (slot->lefts, NULL); + VARRAY_PUSH_TREE (slot->reals, stmt); + VARRAY_PUSH_GENERIC_PTR (bexprs, slot); + slot->strred_cand = is_strred_cand (orig_expr); + slot->loadpre_cand = false; + if (TREE_CODE (expr) == SSA_NAME + || TREE_CODE (expr) == INDIRECT_REF) + slot->loadpre_cand = true; + } + } + } + process_left_occs_and_kills (bexprs, orig_expr); + } + *bexprsp = bexprs; + + for (son = first_dom_son (CDI_DOMINATORS, block); + son; + son = next_dom_son (CDI_DOMINATORS, son)) + collect_expressions (son, bexprsp); +} + +/* Main entry point to the SSA-PRE pass. + + PHASE indicates which dump file from the DUMP_FILES array to use when + dumping debugging information. */ + +static void +execute_pre (void) +{ + int currbbs; + varray_type bexprs; + size_t k; + int i; + + if (ENTRY_BLOCK_PTR->succ->dest->pred->pred_next) + if (!(ENTRY_BLOCK_PTR->succ->flags & EDGE_ABNORMAL)) + split_edge (ENTRY_BLOCK_PTR->succ); + + euse_node_pool = create_alloc_pool ("EUSE node pool", + sizeof (struct tree_euse_node), 30); + eref_node_pool = create_alloc_pool ("EREF node pool", + sizeof (struct tree_eref_common), 30); + ephi_use_pool = create_alloc_pool ("EPHI use node pool", + sizeof (struct ephi_use_entry), 30); + VARRAY_GENERIC_PTR_INIT (bexprs, 1, "bexprs"); + /* Compute immediate dominators. */ + calculate_dominance_info (CDI_DOMINATORS); + + /* DCE screws the dom_children up, without bothering to fix it. So fix it. */ + currbbs = n_basic_blocks; + dfn = xcalloc (last_basic_block + 1, sizeof (int)); + build_dfn_array (ENTRY_BLOCK_PTR, 0); + + /* Initialize IDFS cache. */ + idfs_cache = xcalloc (currbbs, sizeof (bitmap)); + + /* Compute dominance frontiers. */ + pre_dfs = (bitmap *) xmalloc (sizeof (bitmap) * currbbs); + for (i = 0; i < currbbs; i++) + pre_dfs[i] = BITMAP_XMALLOC (); + compute_dominance_frontiers (pre_dfs); + + created_phi_preds = BITMAP_XMALLOC (); + + collect_expressions (ENTRY_BLOCK_PTR, &bexprs); + + ggc_push_context (); + + for (k = 0; k < VARRAY_ACTIVE_SIZE (bexprs); k++) + { + pre_expression (VARRAY_GENERIC_PTR (bexprs, k), pre_dfs, vars_to_rename); + free_alloc_pool (euse_node_pool); + free_alloc_pool (eref_node_pool); + free_alloc_pool (ephi_use_pool); + euse_node_pool = create_alloc_pool ("EUSE node pool", + sizeof (struct tree_euse_node), 30); + eref_node_pool = create_alloc_pool ("EREF node pool", + sizeof (struct tree_eref_common), 30); + ephi_use_pool = create_alloc_pool ("EPHI use node pool", + sizeof (struct ephi_use_entry), 30); + free_expr_info (VARRAY_GENERIC_PTR (bexprs, k)); +#ifdef ENABLE_CHECKING + if (pre_stats.ephis_current != 0) + abort (); +#endif + ggc_collect (); + } + + ggc_pop_context (); + + /* Clean up after PRE. */ + memset (&pre_stats, 0, sizeof (struct pre_stats_d)); + free_alloc_pool (euse_node_pool); + free_alloc_pool (eref_node_pool); + VARRAY_CLEAR (bexprs); + for (i = 0; i < currbbs; i++) + BITMAP_XFREE (pre_dfs[i]); + free (pre_dfs); + BITMAP_XFREE (created_phi_preds); + for (i = 0; i < currbbs; i++) + if (idfs_cache[i] != NULL) + BITMAP_XFREE (idfs_cache[i]); + + free (dfn); +} + +static bool +gate_pre (void) +{ + return flag_tree_pre != 0; +} + +struct tree_opt_pass pass_pre = +{ + "pre", /* name */ + gate_pre, /* gate */ + execute_pre, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_TREE_PRE, /* tv_id */ + PROP_no_crit_edges | PROP_cfg | PROP_ssa,/* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_rename_vars + | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ +}; diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c new file mode 100644 index 00000000000..c145708ba1a --- /dev/null +++ b/gcc/tree-ssa.c @@ -0,0 +1,1099 @@ +/* Miscellaneous SSA utility functions. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "rtl.h" +#include "tm_p.h" +#include "ggc.h" +#include "langhooks.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "output.h" +#include "errors.h" +#include "expr.h" +#include "function.h" +#include "diagnostic.h" +#include "bitmap.h" +#include "tree-flow.h" +#include "tree-simple.h" +#include "tree-inline.h" +#include "varray.h" +#include "timevar.h" +#include "tree-alias-common.h" +#include "hashtab.h" +#include "tree-dump.h" +#include "tree-pass.h" + + +/* Remove edge E and remove the corresponding arguments from the PHI nodes + in E's destination block. */ + +void +ssa_remove_edge (edge e) +{ + tree phi, next; + + /* Remove the appropriate PHI arguments in E's destination block. */ + for (phi = phi_nodes (e->dest); phi; phi = next) + { + next = TREE_CHAIN (phi); + remove_phi_arg (phi, e->src); + } + + remove_edge (e); +} + +/* Remove remove the corresponding arguments from the PHI nodes + in E's destination block and redirect it to DEST. Return redirected edge. + The list of removed arguments is stored in PENDING_STMT (e). */ + +edge +ssa_redirect_edge (edge e, basic_block dest) +{ + tree phi, next; + tree list = NULL, *last = &list; + tree src, dst, node; + int i; + + /* Remove the appropriate PHI arguments in E's destination block. */ + for (phi = phi_nodes (e->dest); phi; phi = next) + { + next = TREE_CHAIN (phi); + + i = phi_arg_from_edge (phi, e); + if (i < 0) + continue; + + src = PHI_ARG_DEF (phi, i); + dst = PHI_RESULT (phi); + node = build_tree_list (dst, src); + *last = node; + last = &TREE_CHAIN (node); + + remove_phi_arg_num (phi, i); + } + + e = redirect_edge_succ_nodup (e, dest); + PENDING_STMT (e) = list; + + return e; +} + + +/* Return true if the definition of SSA_NAME at block BB is malformed. + + STMT is the statement where SSA_NAME is created. + + DEFINITION_BLOCK is an array of basic blocks indexed by SSA_NAME version + numbers. If DEFINITION_BLOCK[SSA_NAME_VERSION] is set, it means that the + block in that array slot contains the definition of SSA_NAME. */ + +static bool +verify_def (basic_block bb, basic_block *definition_block, tree ssa_name, + tree stmt) +{ + bool err = false; + + if (TREE_CODE (ssa_name) != SSA_NAME) + { + error ("Expected an SSA_NAME object"); + debug_generic_stmt (ssa_name); + debug_generic_stmt (stmt); + } + + if (definition_block[SSA_NAME_VERSION (ssa_name)]) + { + error ("SSA_NAME created in two different blocks %i and %i", + definition_block[SSA_NAME_VERSION (ssa_name)]->index, bb->index); + fprintf (stderr, "SSA_NAME: "); + debug_generic_stmt (ssa_name); + debug_generic_stmt (stmt); + err = true; + } + + definition_block[SSA_NAME_VERSION (ssa_name)] = bb; + + if (SSA_NAME_DEF_STMT (ssa_name) != stmt) + { + error ("SSA_NAME_DEF_STMT is wrong"); + fprintf (stderr, "SSA_NAME: "); + debug_generic_stmt (ssa_name); + fprintf (stderr, "Expected definition statement:\n"); + debug_generic_stmt (SSA_NAME_DEF_STMT (ssa_name)); + fprintf (stderr, "\nActual definition statement:\n"); + debug_generic_stmt (stmt); + err = true; + } + + return err; +} + + +/* Return true if the use of SSA_NAME at statement STMT in block BB is + malformed. + + DEF_BB is the block where SSA_NAME was found to be created. + + IDOM contains immediate dominator information for the flowgraph. + + CHECK_ABNORMAL is true if the caller wants to check whether this use + is flowing through an abnormal edge (only used when checking PHI + arguments). */ + +static bool +verify_use (basic_block bb, basic_block def_bb, tree ssa_name, + tree stmt, bool check_abnormal) +{ + bool err = false; + + if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (ssa_name))) + ; /* Nothing to do. */ + else if (!def_bb) + { + error ("Missing definition"); + err = true; + } + else if (bb != def_bb + && !dominated_by_p (CDI_DOMINATORS, bb, def_bb)) + { + error ("Definition in block %i does not dominate use in block %i", + def_bb->index, bb->index); + err = true; + } + + if (check_abnormal + && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssa_name)) + { + error ("SSA_NAME_OCCURS_IN_ABNORMAL_PHI should be set"); + err = true; + } + + if (err) + { + fprintf (stderr, "for SSA_NAME: "); + debug_generic_stmt (ssa_name); + fprintf (stderr, "in statement:\n"); + debug_generic_stmt (stmt); + } + + return err; +} + + +/* Return true if any of the arguments for PHI node PHI at block BB is + malformed. + + IDOM contains immediate dominator information for the flowgraph. + + DEFINITION_BLOCK is an array of basic blocks indexed by SSA_NAME version + numbers. If DEFINITION_BLOCK[SSA_NAME_VERSION] is set, it means that the + block in that array slot contains the definition of SSA_NAME. */ + +static bool +verify_phi_args (tree phi, basic_block bb, basic_block *definition_block) +{ + edge e; + bool err = false; + int i, phi_num_args = PHI_NUM_ARGS (phi); + + /* Mark all the incoming edges. */ + for (e = bb->pred; e; e = e->pred_next) + e->aux = (void *) 1; + + for (i = 0; i < phi_num_args; i++) + { + tree op = PHI_ARG_DEF (phi, i); + + e = PHI_ARG_EDGE (phi, i); + + if (TREE_CODE (op) == SSA_NAME) + err |= verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op, + phi, e->flags & EDGE_ABNORMAL); + + if (e->dest != bb) + { + error ("Wrong edge %d->%d for PHI argument\n", + e->src->index, e->dest->index, bb->index); + err = true; + } + + if (e->aux == (void *) 0) + { + error ("PHI argument flowing through dead edge %d->%d\n", + e->src->index, e->dest->index); + err = true; + } + + if (e->aux == (void *) 2) + { + error ("PHI argument duplicated for edge %d->%d\n", e->src->index, + e->dest->index); + err = true; + } + + if (err) + { + fprintf (stderr, "PHI argument\n"); + debug_generic_stmt (op); + } + + e->aux = (void *) 2; + } + + for (e = bb->pred; e; e = e->pred_next) + { + if (e->aux != (void *) 2) + { + error ("No argument flowing through edge %d->%d\n", e->src->index, + e->dest->index); + err = true; + } + e->aux = (void *) 0; + } + + if (err) + { + fprintf (stderr, "for PHI node\n"); + debug_generic_stmt (phi); + } + + + return err; +} + + +/* Verify common invariants in the SSA web. + TODO: verify the variable annotations. */ + +void +verify_ssa (void) +{ + bool err = false; + basic_block bb; + basic_block *definition_block = xcalloc (highest_ssa_version, + sizeof (basic_block)); + + timevar_push (TV_TREE_SSA_VERIFY); + + calculate_dominance_info (CDI_DOMINATORS); + + /* Verify and register all the SSA_NAME definitions found in the + function. */ + FOR_EACH_BB (bb) + { + tree phi; + block_stmt_iterator bsi; + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + err |= verify_def (bb, definition_block, PHI_RESULT (phi), phi); + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt; + stmt_ann_t ann; + unsigned int j; + vdef_optype vdefs; + def_optype defs; + + stmt = bsi_stmt (bsi); + ann = stmt_ann (stmt); + get_stmt_operands (stmt); + + vdefs = VDEF_OPS (ann); + for (j = 0; j < NUM_VDEFS (vdefs); j++) + { + tree op = VDEF_RESULT (vdefs, j); + if (is_gimple_reg (op)) + { + error ("Found a virtual definition for a GIMPLE register"); + debug_generic_stmt (op); + debug_generic_stmt (stmt); + err = true; + } + err |= verify_def (bb, definition_block, op, stmt); + } + + defs = DEF_OPS (ann); + for (j = 0; j < NUM_DEFS (defs); j++) + { + tree op = DEF_OP (defs, j); + if (TREE_CODE (op) == SSA_NAME && !is_gimple_reg (op)) + { + error ("Found a real definition for a non-GIMPLE register"); + debug_generic_stmt (op); + debug_generic_stmt (stmt); + err = true; + } + err |= verify_def (bb, definition_block, op, stmt); + } + } + } + + + /* Now verify all the uses and make sure they agree with the definitions + found in the previous pass. */ + FOR_EACH_BB (bb) + { + edge e; + tree phi; + block_stmt_iterator bsi; + + /* Make sure that all edges have a clear 'aux' field. */ + for (e = bb->pred; e; e = e->pred_next) + { + if (e->aux) + { + error ("AUX pointer initialized for edge %d->%d\n", e->src->index, + e->dest->index); + err = true; + } + } + + /* Verify the arguments for every PHI node in the block. */ + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + err |= verify_phi_args (phi, bb, definition_block); + + /* Now verify all the uses and vuses in every statement of the block. + + Remember, the RHS of a VDEF is a use as well. */ + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + tree stmt = bsi_stmt (bsi); + stmt_ann_t ann = stmt_ann (stmt); + unsigned int j; + vuse_optype vuses; + vdef_optype vdefs; + use_optype uses; + + vuses = VUSE_OPS (ann); + for (j = 0; j < NUM_VUSES (vuses); j++) + { + tree op = VUSE_OP (vuses, j); + + if (is_gimple_reg (op)) + { + error ("Found a virtual use for a GIMPLE register"); + debug_generic_stmt (op); + debug_generic_stmt (stmt); + err = true; + } + err |= verify_use (bb, definition_block[SSA_NAME_VERSION (op)], + op, stmt, false); + } + + vdefs = VDEF_OPS (ann); + for (j = 0; j < NUM_VDEFS (vdefs); j++) + { + tree op = VDEF_OP (vdefs, j); + + if (is_gimple_reg (op)) + { + error ("Found a virtual use for a GIMPLE register"); + debug_generic_stmt (op); + debug_generic_stmt (stmt); + err = true; + } + err |= verify_use (bb, definition_block[SSA_NAME_VERSION (op)], + op, stmt, false); + } + + uses = USE_OPS (ann); + for (j = 0; j < NUM_USES (uses); j++) + { + tree op = USE_OP (uses, j); + + if (TREE_CODE (op) == SSA_NAME && !is_gimple_reg (op)) + { + error ("Found a real use of a non-GIMPLE register"); + debug_generic_stmt (op); + debug_generic_stmt (stmt); + err = true; + } + err |= verify_use (bb, definition_block[SSA_NAME_VERSION (op)], + op, stmt, false); + } + } + } + + free (definition_block); + + timevar_pop (TV_TREE_SSA_VERIFY); + + if (err) + internal_error ("verify_ssa failed."); +} + + +/* Set the USED bit in the annotation for T. */ + +void +set_is_used (tree t) +{ + while (1) + { + if (SSA_VAR_P (t)) + break; + + switch (TREE_CODE (t)) + { + case ARRAY_REF: + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + case BIT_FIELD_REF: + case INDIRECT_REF: + t = TREE_OPERAND (t, 0); + break; + + default: + return; + } + } + + if (TREE_CODE (t) == SSA_NAME) + t = SSA_NAME_VAR (t); + + var_ann (t)->used = 1; +} + + +/* Initialize global DFA and SSA structures. */ + +void +init_tree_ssa (void) +{ + VARRAY_TREE_INIT (referenced_vars, 20, "referenced_vars"); + call_clobbered_vars = BITMAP_XMALLOC (); + init_ssa_operands (); + init_ssanames (); + init_phinodes (); + global_var = NULL_TREE; + aliases_computed_p = false; +} + + +/* Deallocate memory associated with SSA data structures for FNDECL. */ + +void +delete_tree_ssa (void) +{ + size_t i; + basic_block bb; + block_stmt_iterator bsi; + + /* Remove annotations from every tree in the function. */ + FOR_EACH_BB (bb) + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + bsi_stmt (bsi)->common.ann = NULL; + + /* Remove annotations from every referenced variable. */ + if (referenced_vars) + { + for (i = 0; i < num_referenced_vars; i++) + referenced_var (i)->common.ann = NULL; + referenced_vars = NULL; + } + + fini_ssanames (); + fini_phinodes (); + fini_ssa_operands (); + + global_var = NULL_TREE; + BITMAP_FREE (call_clobbered_vars); + call_clobbered_vars = NULL; + aliases_computed_p = false; +} + + +/* Return true if EXPR is a useless type conversion, otherwise return + false. */ + +bool +tree_ssa_useless_type_conversion_1 (tree outer_type, tree inner_type) +{ + /* If the inner and outer types are effectively the same, then + strip the type conversion and enter the equivalence into + the table. */ + if (inner_type == outer_type + || (lang_hooks.types_compatible_p (inner_type, outer_type))) + return true; + + /* If both types are pointers and the outer type is a (void *), then + the conversion is not necessary. The opposite is not true since + that conversion would result in a loss of information if the + equivalence was used. Consider an indirect function call where + we need to know the exact type of the function to correctly + implement the ABI. */ + else if (POINTER_TYPE_P (inner_type) + && POINTER_TYPE_P (outer_type) + && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE) + return true; + + /* Pointers and references are equivalent once we get to GENERIC, + so strip conversions that just switch between them. */ + else if (POINTER_TYPE_P (inner_type) + && POINTER_TYPE_P (outer_type) + && lang_hooks.types_compatible_p (inner_type, outer_type)) + return true; + + /* If both the inner and outer types are integral types, then the + conversion is not necessary if they have the same mode and + signedness and precision. Note that type _Bool can have size of + 4 (only happens on powerpc-darwin right now but can happen on any + target that defines BOOL_TYPE_SIZE to be INT_TYPE_SIZE) and a + precision of 1 while unsigned int is the same expect for a + precision of 4 so testing of precision is necessary. */ + else if (INTEGRAL_TYPE_P (inner_type) + && INTEGRAL_TYPE_P (outer_type) + && TYPE_MODE (inner_type) == TYPE_MODE (outer_type) + && TYPE_UNSIGNED (inner_type) == TYPE_UNSIGNED (outer_type) + && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type)) + return true; + + /* Recurse for complex types. */ + else if (TREE_CODE (inner_type) == COMPLEX_TYPE + && TREE_CODE (outer_type) == COMPLEX_TYPE + && tree_ssa_useless_type_conversion_1 (TREE_TYPE (outer_type), + TREE_TYPE (inner_type))) + return true; + + return false; +} + +/* Return true if EXPR is a useless type conversion, otherwise return + false. */ + +bool +tree_ssa_useless_type_conversion (tree expr) +{ + /* If we have an assignment that merely uses a NOP_EXPR to change + the top of the RHS to the type of the LHS and the type conversion + is "safe", then strip away the type conversion so that we can + enter LHS = RHS into the const_and_copies table. */ + if (TREE_CODE (expr) == NOP_EXPR || TREE_CODE (expr) == CONVERT_EXPR) + return tree_ssa_useless_type_conversion_1 (TREE_TYPE (expr), + TREE_TYPE (TREE_OPERAND (expr, + 0))); + + + return false; +} + + +/* Internal helper for walk_use_def_chains. VAR, FN and DATA are as + described in walk_use_def_chains. VISITED is a bitmap used to mark + visited SSA_NAMEs to avoid infinite loops. */ + +static bool +walk_use_def_chains_1 (tree var, walk_use_def_chains_fn fn, void *data, + bitmap visited) +{ + tree def_stmt; + + if (bitmap_bit_p (visited, SSA_NAME_VERSION (var))) + return false; + + bitmap_set_bit (visited, SSA_NAME_VERSION (var)); + + def_stmt = SSA_NAME_DEF_STMT (var); + + if (TREE_CODE (def_stmt) != PHI_NODE) + { + /* If we reached the end of the use-def chain, call FN. */ + return (*fn) (var, def_stmt, data); + } + else + { + int i; + + /* Otherwise, follow use-def links out of each PHI argument and call + FN after visiting each one. */ + for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++) + { + tree arg = PHI_ARG_DEF (def_stmt, i); + if (TREE_CODE (arg) == SSA_NAME + && walk_use_def_chains_1 (arg, fn, data, visited)) + return true; + + if ((*fn) (arg, def_stmt, data)) + return true; + } + } + return false; +} + + + +/* Walk use-def chains starting at the SSA variable VAR. Call function FN + at each reaching definition found. FN takes three arguments: VAR, its + defining statement (DEF_STMT) and a generic pointer to whatever state + information that FN may want to maintain (DATA). FN is able to stop the + walk by returning true, otherwise in order to continue the walk, FN + should return false. + + Note, that if DEF_STMT is a PHI node, the semantics are slightly + different. For each argument ARG of the PHI node, this function will: + + 1- Walk the use-def chains for ARG. + 2- Call (*FN) (ARG, PHI, DATA). + + Note how the first argument to FN is no longer the original variable + VAR, but the PHI argument currently being examined. If FN wants to get + at VAR, it should call PHI_RESULT (PHI). */ + +void +walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data) +{ + tree def_stmt; + +#if defined ENABLE_CHECKING + if (TREE_CODE (var) != SSA_NAME) + abort (); +#endif + + def_stmt = SSA_NAME_DEF_STMT (var); + + /* We only need to recurse if the reaching definition comes from a PHI + node. */ + if (TREE_CODE (def_stmt) != PHI_NODE) + (*fn) (var, def_stmt, data); + else + { + bitmap visited = BITMAP_XMALLOC (); + walk_use_def_chains_1 (var, fn, data, visited); + BITMAP_XFREE (visited); + } +} + + +/* Replaces immediate uses of VAR by REPL. */ + +static void +replace_immediate_uses (tree var, tree repl) +{ + use_optype uses; + vuse_optype vuses; + vdef_optype vdefs; + int i, j, n; + dataflow_t df; + tree stmt; + stmt_ann_t ann; + + df = get_immediate_uses (SSA_NAME_DEF_STMT (var)); + n = num_immediate_uses (df); + + for (i = 0; i < n; i++) + { + stmt = immediate_use (df, i); + ann = stmt_ann (stmt); + + if (TREE_CODE (stmt) == PHI_NODE) + { + for (j = 0; j < PHI_NUM_ARGS (stmt); j++) + if (PHI_ARG_DEF (stmt, j) == var) + { + PHI_ARG_DEF (stmt, j) = repl; + if (TREE_CODE (repl) == SSA_NAME + && PHI_ARG_EDGE (stmt, j)->flags & EDGE_ABNORMAL) + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (repl) = 1; + } + + continue; + } + + get_stmt_operands (stmt); + if (is_gimple_reg (SSA_NAME_VAR (var))) + { + uses = USE_OPS (ann); + for (j = 0; j < (int) NUM_USES (uses); j++) + if (USE_OP (uses, j) == var) + propagate_value (USE_OP_PTR (uses, j), repl); + } + else + { + vuses = VUSE_OPS (ann); + for (j = 0; j < (int) NUM_VUSES (vuses); j++) + if (VUSE_OP (vuses, j) == var) + propagate_value (VUSE_OP_PTR (vuses, j), repl); + + vdefs = VDEF_OPS (ann); + for (j = 0; j < (int) NUM_VDEFS (vdefs); j++) + if (VDEF_OP (vdefs, j) == var) + propagate_value (VDEF_OP_PTR (vdefs, j), repl); + } + + modify_stmt (stmt); + + /* If REPL is a pointer, it may have different memory tags associated + with it. For instance, VAR may have had a name tag while REPL + only had a type tag. In these cases, the virtual operands (if + any) in the statement will refer to different symbols which need + to be renamed. */ + if (POINTER_TYPE_P (TREE_TYPE (repl))) + mark_new_vars_to_rename (stmt, vars_to_rename); + } +} + +/* Raises value of phi node PHI by joining it with VAL. Processes immediate + uses of PHI recursively. */ + +static void +raise_value (tree phi, tree val, tree *eq_to) +{ + int i, n; + tree var = PHI_RESULT (phi), stmt; + int ver = SSA_NAME_VERSION (var); + dataflow_t df; + + if (eq_to[ver] == var) + return; + + switch (TREE_CODE (val)) + { + case SSA_NAME: + case REAL_CST: + case COMPLEX_CST: + break; + case INTEGER_CST: + if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE) + break; + + default: + /* Do not propagate pointer constants. This might require folding + things like *&foo and rewriting the ssa, which is not worth the + trouble. */ + val = var; + } + + if (eq_to[ver]) + { + if (operand_equal_p (eq_to[ver], val, 0)) + return; + + eq_to[ver] = var; + } + else + eq_to[ver] = val; + + df = get_immediate_uses (SSA_NAME_DEF_STMT (var)); + n = num_immediate_uses (df); + + for (i = 0; i < n; i++) + { + stmt = immediate_use (df, i); + + if (TREE_CODE (stmt) != PHI_NODE) + continue; + + raise_value (stmt, eq_to[ver], eq_to); + } +} + +/* Removes redundant phi nodes. + + A redundant PHI node is a PHI node where all of its PHI arguments + are the same value, excluding any PHI arguments which are the same + as the PHI result. + + A redundant PHI node is effectively a copy, so we forward copy propagate + which removes all uses of the destination of the PHI node then + finally we delete the redundant PHI node. + + Note that if we can not copy propagate the PHI node, then the PHI + will not be removed. Thus we do not have to worry about dependencies + between PHIs and the problems serializing PHIs into copies creates. + + The most important effect of this pass is to remove degenerate PHI + nodes created by removing unreachable code. */ + +static void +kill_redundant_phi_nodes (void) +{ + tree *eq_to, *ssa_names; + unsigned i, ver, aver; + basic_block bb; + tree phi, t, stmt, var; + + /* The EQ_TO array holds the current value of the ssa name in the + lattice: + + top + / | \ + const variables + \ | / + bottom + + Bottom is represented by NULL and top by the variable itself. + + Once the dataflow stabilizes, we know that the phi nodes we need to keep + are exactly those with top as their result. + + The remaining phi nodes have their uses replaced with their value + in the lattice and the phi node itself is removed. */ + eq_to = xcalloc (highest_ssa_version, sizeof (tree)); + + /* The SSA_NAMES array holds each SSA_NAME node we encounter + in a PHI node (indexed by ssa version number). + + One could argue that the SSA_NAME manager ought to provide a + generic interface to get at the SSA_NAME node for a given + ssa version number. */ + ssa_names = xcalloc (highest_ssa_version, sizeof (tree)); + + /* We have had cases where computing immediate uses takes a + significant amount of compile time. If we run into such + problems here, we may want to only compute immediate uses for + a subset of all the SSA_NAMEs instead of computing it for + all of the SSA_NAMEs. */ + compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, NULL); + + FOR_EACH_BB (bb) + { + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + var = PHI_RESULT (phi); + ver = SSA_NAME_VERSION (var); + ssa_names[ver] = var; + + for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++) + { + t = PHI_ARG_DEF (phi, i); + + if (TREE_CODE (t) != SSA_NAME) + { + raise_value (phi, t, eq_to); + continue; + } + + stmt = SSA_NAME_DEF_STMT (t); + aver = SSA_NAME_VERSION (t); + ssa_names[aver] = t; + + /* If the defining statement for this argument is not a + phi node or the argument is associated with an abnormal + edge, then we need to recursively start the forward + dataflow starting with PHI. */ + if (TREE_CODE (stmt) != PHI_NODE + || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (t)) + { + eq_to[aver] = t; + raise_value (phi, t, eq_to); + } + } + } + } + + /* Now propagate the values. */ + for (i = 0; i < highest_ssa_version; i++) + if (eq_to[i] + && eq_to[i] != ssa_names[i]) + replace_immediate_uses (ssa_names[i], eq_to[i]); + + /* And remove the dead phis. */ + for (i = 0; i < highest_ssa_version; i++) + if (eq_to[i] + && eq_to[i] != ssa_names[i]) + { + stmt = SSA_NAME_DEF_STMT (ssa_names[i]); + remove_phi_node (stmt, 0, bb_for_stmt (stmt)); + } + + free_df (); + free (eq_to); + free (ssa_names); +} + +struct tree_opt_pass pass_redundant_phi = +{ + "redphi", /* name */ + NULL, /* gate */ + kill_redundant_phi_nodes, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_rename_vars + | TODO_ggc_collect | TODO_verify_ssa /* todo_flags_finish */ +}; + +/* Emit warnings for uninitialized variables. This is done in two passes. + + The first pass notices real uses of SSA names with default definitions. + Such uses are unconditionally uninitialized, and we can be certain that + such a use is a mistake. This pass is run before most optimizations, + so that we catch as many as we can. + + The second pass follows PHI nodes to find uses that are potentially + uninitialized. In this case we can't necessarily prove that the use + is really uninitialized. This pass is run after most optimizations, + so that we thread as many jumps and possible, and delete as much dead + code as possible, in order to reduce false positives. We also look + again for plain uninitialized variables, since optimization may have + changed conditionally uninitialized to unconditionally uninitialized. */ + +/* Emit a warning for T, an SSA_NAME, being uninitialized. The exact + warning text is in MSGID and LOCUS may contain a location or be null. */ + +static void +warn_uninit (tree t, const char *msgid, location_t *locus) +{ + tree var = SSA_NAME_VAR (t); + tree def = SSA_NAME_DEF_STMT (t); + + /* Default uses (indicated by an empty definition statement), + are uninitialized. */ + if (!IS_EMPTY_STMT (def)) + return; + + /* Except for PARMs of course, which are always initialized. */ + if (TREE_CODE (var) == PARM_DECL) + return; + + /* Hard register variables get their initial value from the ether. */ + if (DECL_HARD_REGISTER (var)) + return; + + /* TREE_NO_WARNING either means we already warned, or the front end + wishes to suppress the warning. */ + if (TREE_NO_WARNING (var)) + return; + + if (!locus) + locus = &DECL_SOURCE_LOCATION (var); + warning (msgid, locus, var); + TREE_NO_WARNING (var) = 1; +} + +/* Called via walk_tree, look for SSA_NAMEs that have empty definitions + and warn about them. */ + +static tree +warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data) +{ + location_t *locus = data; + tree t = *tp; + + /* We only do data flow with SSA_NAMEs, so that's all we can warn about. */ + if (TREE_CODE (t) == SSA_NAME) + { + warn_uninit (t, "%H'%D' is used uninitialized in this function", locus); + *walk_subtrees = 0; + } + else if (DECL_P (t) || TYPE_P (t)) + *walk_subtrees = 0; + + return NULL_TREE; +} + +/* Look for inputs to PHI that are SSA_NAMEs that have empty definitions + and warn about them. */ + +static void +warn_uninitialized_phi (tree phi) +{ + int i, n = PHI_NUM_ARGS (phi); + + /* Don't look at memory tags. */ + if (!is_gimple_reg (PHI_RESULT (phi))) + return; + + for (i = 0; i < n; ++i) + { + tree op = PHI_ARG_DEF (phi, i); + if (TREE_CODE (op) == SSA_NAME) + warn_uninit (op, "%H'%D' may be used uninitialized in this function", + NULL); + } +} + +static void +execute_early_warn_uninitialized (void) +{ + block_stmt_iterator bsi; + basic_block bb; + + FOR_EACH_BB (bb) + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + walk_tree (bsi_stmt_ptr (bsi), warn_uninitialized_var, + EXPR_LOCUS (bsi_stmt (bsi)), NULL); +} + +static void +execute_late_warn_uninitialized (void) +{ + basic_block bb; + tree phi; + + /* Re-do the plain uninitialized variable check, as optimization may have + straightened control flow. Do this first so that we don't accidentally + get a "may be" warning when we'd have seen an "is" warning later. */ + execute_early_warn_uninitialized (); + + FOR_EACH_BB (bb) + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + warn_uninitialized_phi (phi); +} + +static bool +gate_warn_uninitialized (void) +{ + return warn_uninitialized != 0; +} + +struct tree_opt_pass pass_early_warn_uninitialized = +{ + NULL, /* name */ + gate_warn_uninitialized, /* gate */ + execute_early_warn_uninitialized, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + +struct tree_opt_pass pass_late_warn_uninitialized = +{ + NULL, /* name */ + gate_warn_uninitialized, /* gate */ + execute_late_warn_uninitialized, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c new file mode 100644 index 00000000000..1142492430e --- /dev/null +++ b/gcc/tree-ssanames.c @@ -0,0 +1,184 @@ +/* Generic routines for manipulating SSA_NAME expressions + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "varray.h" +#include "ggc.h" + +/* Rewriting a function into SSA form can create a huge number of SSA_NAMEs, + many of which may be thrown away shortly after their creation if jumps + were threaded through PHI nodes. + + While our garbage collection mechanisms will handle this situation, it + is extremely wasteful to create nodes and throw them away, especially + when the nodes can be reused. + + For PR 8361, we can significantly reduce the number of nodes allocated + and thus the total amount of memory allocated by managing SSA_NAMEs a + little. This additionally helps reduce the amount of work done by the + garbage collector. Similar results have been seen on a wider variety + of tests (such as the compiler itself). + + Right now we maintain our free list on a per-function basis. It may + or may not make sense to maintain the free list for the duration of + a compilation unit. + + External code should rely solely upon HIGHEST_SSA_VERSION and the + externally defined functions. External code should not know about + the details of the free list management. + + External code should also not assume the version number on nodes is + monotonically increasing. We reuse the version number when we + reuse an SSA_NAME expression. This helps keep arrays and bitmaps + more compact. + + We could also use a zone allocator for these objects since they have + a very well defined lifetime. If someone wants to experiment with that + this is the place to try it. */ + +/* Next SSA version number to be allocated. */ +unsigned int highest_ssa_version; + +/* Free list of SSA_NAMEs. This list is wiped at the end of each function + after we leave SSA form. */ +static GTY (()) tree free_ssanames; + +/* Version numbers with special meanings. We start allocating new version + numbers after the special ones. */ +#define UNUSED_NAME_VERSION 0 + +#ifdef GATHER_STATISTICS +unsigned int ssa_name_nodes_reused; +unsigned int ssa_name_nodes_created; +#endif + +/* Initialize management of SSA_NAMEs. */ + +void +init_ssanames (void) +{ + highest_ssa_version = UNUSED_NAME_VERSION + 1; + free_ssanames = NULL; +} + +/* Finalize management of SSA_NAMEs. */ + +void +fini_ssanames (void) +{ + free_ssanames = NULL; +} + +/* Dump some simple statistics regarding the re-use of SSA_NAME nodes. */ + +#ifdef GATHER_STATISTICS +void +ssanames_print_statistics (void) +{ + fprintf (stderr, "SSA_NAME nodes allocated: %u\n", ssa_name_nodes_created); + fprintf (stderr, "SSA_NAME nodes reused: %u\n", ssa_name_nodes_reused); +} +#endif + +/* Return an SSA_NAME node for variable VAR defined in statement STMT. + STMT may be an empty statement for artificial references (e.g., default + definitions created when a variable is used without a preceding + definition). */ + +tree +make_ssa_name (tree var, tree stmt) +{ + tree t; + +#if defined ENABLE_CHECKING + if ((!DECL_P (var) + && TREE_CODE (var) != INDIRECT_REF) + || (!IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (stmt))) + && TREE_CODE (stmt) != PHI_NODE)) + abort (); +#endif + + /* If our free list has an element, then use it. Also reuse the + SSA version number of the element on the free list which helps + keep sbitmaps and arrays sized HIGHEST_SSA_VERSION smaller. */ + if (free_ssanames) + { + unsigned int save_version; + + t = free_ssanames; + free_ssanames = TREE_CHAIN (free_ssanames); +#ifdef GATHER_STATISTICS + ssa_name_nodes_reused++; +#endif + + /* Clear the node so that it looks just like one we would have + received from make_node. */ + save_version = SSA_NAME_VERSION (t); + memset (t, 0, tree_size (t)); + TREE_SET_CODE (t, SSA_NAME); + SSA_NAME_VERSION (t) = save_version; + } + else + { + t = make_node (SSA_NAME); + SSA_NAME_VERSION (t) = highest_ssa_version++; +#ifdef GATHER_STATISTICS + ssa_name_nodes_created++; +#endif + } + + TREE_TYPE (t) = TREE_TYPE (var); + SSA_NAME_VAR (t) = var; + SSA_NAME_DEF_STMT (t) = stmt; + + return t; +} + +/* We no longer need the SSA_NAME expression VAR, release it so that + it may be reused. + + Note it is assumed that no calls to make_ssa_name will be made + until all uses of the ssa name are released and that the only + use of the SSA_NAME expression is to check its SSA_NAME_VAR. All + other fields must be assumed clobbered. */ + +void +release_ssa_name (tree var) +{ + /* release_ssa_name can be called multiple times on a single SSA_NAME. + However, it should only end up on our free list one time. We + keep a status bit in the SSA_NAME node itself to indicate it has + been put on the free list. + + Note that once on the freelist you can not reference the SSA_NAME's + defining statement. */ + if (! SSA_NAME_IN_FREE_LIST (var)) + { + SSA_NAME_IN_FREE_LIST (var) = 1; + TREE_CHAIN (var) = free_ssanames; + free_ssanames = var; + } +} + +#include "gt-tree-ssanames.h" diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c new file mode 100644 index 00000000000..65657da250b --- /dev/null +++ b/gcc/tree-tailcall.c @@ -0,0 +1,932 @@ +/* Tail calls optimization on trees. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "tm_p.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "function.h" +#include "tree-flow.h" +#include "tree-dump.h" +#include "diagnostic.h" +#include "except.h" +#include "tree-pass.h" +#include "flags.h" +#include "langhooks.h" + +/* The file implements the tail recursion elimination. It is also used to + analyse the tail calls in general, passing the results to the rtl level + where they are used for sibcall optimization. + + In addition to the standard tail recursion elimination, we handle the most + trivial cases of making the call tail recursive by creating accumulators. + For example the following function + + int sum (int n) + { + if (n > 0) + return n + sum (n - 1); + else + return 0; + } + + is transformed into + + int sum (int n) + { + int acc = 0; + + while (n > 0) + acc += n--; + + return acc; + } + + To do this, we maintain two accumulators (a_acc and m_acc) that indicate + when we reach the return x statement, we should return a_acc + x * m_acc + instead. They are initially initialized to 0 and 1, respectively, + so the semantics of the function is obviously preserved. If we are + guaranteed that the value of the accumulator never change, we + omit the accumulator. + + There are three cases how the function may exit. The first one is + handled in adjust_return_value, the later two in adjust_accumulator_values + (the second case is actually a special case of the third one and we + present it separately just for clarity): + + 1) Just return x, where x is not in any of the remaining special shapes. + We rewrite this to a gimple equivalent of return m_acc * x + a_acc. + + 2) return f (...), where f is the current function, is rewritten in a + clasical tail-recursion elimination way, into assignment of arguments + and jump to the start of the function. Values of the accumulators + are unchanged. + + 3) return a + m * f(...), where a and m do not depend on call to f. + To preserve the semantics described before we want this to be rewritten + in such a way that we finally return + + a_acc + (a + m * f(...)) * m_acc = (a_acc + a * m_acc) + (m * m_acc) * f(...). + + I.e. we increase a_acc by a * m_acc, multiply m_acc by m and + eliminate the tail call to f. Special cases when the value is just + added or just multiplied are obtained by setting a = 0 or m = 1. + + TODO -- it is possible to do similar tricks for other operations. */ + +/* A structure that describes the tailcall. */ + +struct tailcall +{ + /* The block in that the call occur. */ + basic_block call_block; + + /* The iterator pointing to the call statement. */ + block_stmt_iterator call_bsi; + + /* True if it is a call to the current function. */ + bool tail_recursion; + + /* The return value of the caller is mult * f + add, where f is the return + value of the call. */ + tree mult, add; + + /* Next tailcall in the chain. */ + struct tailcall *next; +}; + +/* The variables holding the value of multiplicative and additive + accumulator. */ +static tree m_acc, a_acc; + +static bool suitable_for_tail_opt_p (void); +static bool optimize_tail_call (struct tailcall *, bool); +static void eliminate_tail_call (struct tailcall *); +static void find_tail_calls (basic_block, struct tailcall **); + +/* Returns false when the function is not suitable for tail call optimization + from some reason (e.g. if it takes variable number of arguments). */ + +static bool +suitable_for_tail_opt_p (void) +{ + int i; + + if (current_function_stdarg) + return false; + + /* No local variable should be call-clobbered. We ignore any kind + of memory tag, as these are not real variables. */ + for (i = 0; i < (int) VARRAY_ACTIVE_SIZE (referenced_vars); i++) + { + tree var = VARRAY_TREE (referenced_vars, i); + + if (decl_function_context (var) == current_function_decl + && !TREE_STATIC (var) + && var_ann (var)->mem_tag_kind == NOT_A_TAG + && is_call_clobbered (var)) + return false; + } + + return true; +} +/* Returns false when the function is not suitable for tail call optimization + from some reason (e.g. if it takes variable number of arguments). + This test must pass in addition to suitable_for_tail_opt_p in order to make + tail call discovery happen. */ + +static bool +suitable_for_tail_call_opt_p (void) +{ + /* alloca (until we have stack slot life analysis) inhibits + sibling call optimizations, but not tail recursion. */ + if (current_function_calls_alloca) + return false; + + /* If we are using sjlj exceptions, we may need to add a call to + _Unwind_SjLj_Unregister at exit of the function. Which means + that we cannot do any sibcall transformations. */ + if (USING_SJLJ_EXCEPTIONS && current_function_has_exception_handlers ()) + return false; + + /* Any function that calls setjmp might have longjmp called from + any called function. ??? We really should represent this + properly in the CFG so that this needn't be special cased. */ + if (current_function_calls_setjmp) + return false; + + return true; +} + +/* Checks whether the expression EXPR in stmt AT is independent of the + statement pointed by BSI (in a sense that we already know EXPR's value + at BSI). We use the fact that we are only called from the chain of + basic blocks that have only single successor. Returns the expression + containing the value of EXPR at BSI. */ + +static tree +independent_of_stmt_p (tree expr, tree at, block_stmt_iterator bsi) +{ + basic_block bb, call_bb, at_bb; + edge e; + + if (is_gimple_min_invariant (expr)) + return expr; + + if (TREE_CODE (expr) != SSA_NAME) + return NULL_TREE; + + /* Mark the blocks in the chain leading to the end. */ + at_bb = bb_for_stmt (at); + call_bb = bb_for_stmt (bsi_stmt (bsi)); + for (bb = call_bb; bb != at_bb; bb = bb->succ->dest) + bb->aux = &bb->aux; + bb->aux = &bb->aux; + + while (1) + { + at = SSA_NAME_DEF_STMT (expr); + bb = bb_for_stmt (at); + + /* The default defininition or defined before the chain. */ + if (!bb || !bb->aux) + break; + + if (bb == call_bb) + { + for (; !bsi_end_p (bsi); bsi_next (&bsi)) + if (bsi_stmt (bsi) == at) + break; + + if (!bsi_end_p (bsi)) + expr = NULL_TREE; + break; + } + + if (TREE_CODE (at) != PHI_NODE) + { + expr = NULL_TREE; + break; + } + + for (e = bb->pred; e; e = e->pred_next) + if (e->src->aux) + break; + if (!e) + abort (); + + expr = phi_element_for_edge (at, e)->def; + } + + /* Unmark the blocks. */ + for (bb = call_bb; bb != at_bb; bb = bb->succ->dest) + bb->aux = NULL; + bb->aux = NULL; + + return expr; +} + +/* Simulates the effect of an assignment of ASS in STMT on the return value + of the tail recursive CALL passed in ASS_VAR. M and A are the + multiplicative and the additive factor for the real return value. */ + +static bool +process_assignment (tree ass, tree stmt, block_stmt_iterator call, tree *m, + tree *a, tree *ass_var) +{ + tree op0, op1, non_ass_var; + tree dest = TREE_OPERAND (ass, 0); + tree src = TREE_OPERAND (ass, 1); + enum tree_code code = TREE_CODE (src); + + if (code == SSA_NAME) + { + if (src != *ass_var) + return false; + + *ass_var = dest; + return true; + } + + if (TREE_CODE_CLASS (code) != '2') + return false; + + /* We only handle the code like + + x = call (); + y = m * x; + z = y + a; + return z; + + TODO -- Extend it for cases where the linear transformation of the output + is expressed in a more complicated way. */ + + op0 = TREE_OPERAND (src, 0); + op1 = TREE_OPERAND (src, 1); + + if (op0 == *ass_var + && (non_ass_var = independent_of_stmt_p (op1, stmt, call))) + ; + else if (op1 == *ass_var + && (non_ass_var = independent_of_stmt_p (op0, stmt, call))) + ; + else + return false; + + switch (TREE_CODE (src)) + { + case PLUS_EXPR: + /* There should be no previous addition. TODO -- it should be fairly + straightforward to lift this restriction -- just allow storing + more complicated expressions in *A, and gimplify it in + adjust_accumulator_values. */ + if (*a) + return false; + *a = non_ass_var; + *ass_var = dest; + return true; + + case MULT_EXPR: + /* Similar remark applies here. Handling multiplication after addition + is just slightly more complicated -- we need to multiply both *A and + *M. */ + if (*a || *m) + return false; + *m = non_ass_var; + *ass_var = dest; + return true; + + /* TODO -- Handle other codes (NEGATE_EXPR, MINUS_EXPR). */ + + default: + return false; + } +} + +/* Propagate VAR through phis on edge E. */ + +static tree +propagate_through_phis (tree var, edge e) +{ + basic_block dest = e->dest; + tree phi; + + for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi)) + if (phi_element_for_edge (phi, e)->def == var) + return PHI_RESULT (phi); + + return var; +} + +/* Finds tailcalls falling into basic block BB. The list of found tailcalls is + added to the start of RET. */ + +static void +find_tail_calls (basic_block bb, struct tailcall **ret) +{ + tree ass_var, ret_var, stmt, func, param, args, call = NULL_TREE; + block_stmt_iterator bsi, absi; + bool tail_recursion; + struct tailcall *nw; + edge e; + tree m, a; + basic_block abb; + stmt_ann_t ann; + + if (bb->succ->succ_next) + return; + + for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi)) + { + stmt = bsi_stmt (bsi); + + /* Ignore labels. */ + if (TREE_CODE (stmt) == LABEL_EXPR) + continue; + + get_stmt_operands (stmt); + + /* Check for a call. */ + if (TREE_CODE (stmt) == MODIFY_EXPR) + { + ass_var = TREE_OPERAND (stmt, 0); + call = TREE_OPERAND (stmt, 1); + } + else + { + ass_var = NULL_TREE; + call = stmt; + } + + if (TREE_CODE (call) == CALL_EXPR) + break; + + /* If the statement has virtual operands, fail. */ + ann = stmt_ann (stmt); + if (NUM_VDEFS (VDEF_OPS (ann)) + || NUM_VUSES (VUSE_OPS (ann))) + return; + } + + if (bsi_end_p (bsi)) + { + /* Recurse to the predecessors. */ + for (e = bb->pred; e; e = e->pred_next) + find_tail_calls (e->src, ret); + + return; + } + + /* We found the call, check whether it is suitable. */ + tail_recursion = false; + func = get_callee_fndecl (call); + if (func == current_function_decl) + { + for (param = DECL_ARGUMENTS (func), args = TREE_OPERAND (call, 1); + param && args; + param = TREE_CHAIN (param), args = TREE_CHAIN (args)) + { + tree arg = TREE_VALUE (args); + if (param != arg + /* Make sure there are no problems with copying. Note we must + have a copyable type and the two arguments must have reasonably + equivalent types. The latter requirement could be relaxed if + we emitted a suitable type conversion statement. */ + && (!is_gimple_reg_type (TREE_TYPE (param)) + || !lang_hooks.types_compatible_p (TREE_TYPE (param), + TREE_TYPE (arg)))) + break; + } + if (!args && !param) + tail_recursion = true; + } + + /* Now check the statements after the call. None of them has virtual + operands, so they may only depend on the call through its return + value. The return value should also be dependent on each of them, + since we are running after dce. */ + m = NULL_TREE; + a = NULL_TREE; + + abb = bb; + absi = bsi; + while (1) + { + bsi_next (&absi); + + while (bsi_end_p (absi)) + { + ass_var = propagate_through_phis (ass_var, abb->succ); + abb = abb->succ->dest; + absi = bsi_start (abb); + } + + stmt = bsi_stmt (absi); + + if (TREE_CODE (stmt) == LABEL_EXPR) + continue; + + if (TREE_CODE (stmt) == RETURN_EXPR) + break; + + if (TREE_CODE (stmt) != MODIFY_EXPR) + return; + + /* Unless this is a tail recursive call, we cannot do anything with + the statement anyway. */ + if (!tail_recursion) + return; + + if (!process_assignment (stmt, stmt, bsi, &m, &a, &ass_var)) + return; + } + + ret_var = TREE_OPERAND (stmt, 0); + if (ret_var + && TREE_CODE (ret_var) == MODIFY_EXPR) + { + if (!tail_recursion + && TREE_CODE (TREE_OPERAND (ret_var, 1)) != SSA_NAME) + return; + + if (!process_assignment (ret_var, stmt, bsi, &m, &a, &ass_var)) + return; + ret_var = TREE_OPERAND (ret_var, 0); + } + + /* We may proceed if there either is no return value, or the return value + is identical to the call's return. */ + if (ret_var + && (ret_var != ass_var)) + return; + + nw = xmalloc (sizeof (struct tailcall)); + + nw->call_block = bb; + nw->call_bsi = bsi; + + nw->tail_recursion = tail_recursion; + + nw->mult = m; + nw->add = a; + + nw->next = *ret; + *ret = nw; +} + +/* Adjust the accumulator values according to A and M after BSI, and update + the phi nodes on edge BACK. */ + +static void +adjust_accumulator_values (block_stmt_iterator bsi, tree m, tree a, edge back) +{ + tree stmt, var, phi, tmp; + tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl)); + tree a_acc_arg = a_acc, m_acc_arg = m_acc; + + if (a) + { + if (m_acc) + { + if (integer_onep (a)) + var = m_acc; + else + { + stmt = build (MODIFY_EXPR, ret_type, NULL_TREE, + build (MULT_EXPR, ret_type, m_acc, a)); + + tmp = create_tmp_var (ret_type, "acc_tmp"); + add_referenced_tmp_var (tmp); + + var = make_ssa_name (tmp, stmt); + TREE_OPERAND (stmt, 0) = var; + bsi_insert_after (&bsi, stmt, BSI_NEW_STMT); + } + } + else + var = a; + + stmt = build (MODIFY_EXPR, ret_type, NULL_TREE, + build (PLUS_EXPR, ret_type, a_acc, var)); + var = make_ssa_name (SSA_NAME_VAR (a_acc), stmt); + TREE_OPERAND (stmt, 0) = var; + bsi_insert_after (&bsi, stmt, BSI_NEW_STMT); + a_acc_arg = var; + } + + if (m) + { + stmt = build (MODIFY_EXPR, ret_type, NULL_TREE, + build (MULT_EXPR, ret_type, m_acc, m)); + var = make_ssa_name (SSA_NAME_VAR (m_acc), stmt); + TREE_OPERAND (stmt, 0) = var; + bsi_insert_after (&bsi, stmt, BSI_NEW_STMT); + m_acc_arg = var; + } + + if (a_acc) + { + for (phi = phi_nodes (back->dest); phi; phi = TREE_CHAIN (phi)) + if (PHI_RESULT (phi) == a_acc) + break; + + add_phi_arg (&phi, a_acc_arg, back); + } + + if (m_acc) + { + for (phi = phi_nodes (back->dest); phi; phi = TREE_CHAIN (phi)) + if (PHI_RESULT (phi) == m_acc) + break; + + add_phi_arg (&phi, m_acc_arg, back); + } +} + +/* Adjust value of the return at the end of BB accodring to M and A + accumulators. */ + +static void +adjust_return_value (basic_block bb, tree m, tree a) +{ + tree ret_stmt = last_stmt (bb), ret_var, var, stmt, tmp; + tree ret_type = TREE_TYPE (DECL_RESULT (current_function_decl)); + block_stmt_iterator bsi = bsi_last (bb); + + if (TREE_CODE (ret_stmt) != RETURN_EXPR) + abort (); + + ret_var = TREE_OPERAND (ret_stmt, 0); + if (!ret_var) + return; + + if (TREE_CODE (ret_var) == MODIFY_EXPR) + { + ret_var->common.ann = (tree_ann) stmt_ann (ret_stmt); + bsi_replace (&bsi, ret_var, true); + SSA_NAME_DEF_STMT (TREE_OPERAND (ret_var, 0)) = ret_var; + ret_var = TREE_OPERAND (ret_var, 0); + ret_stmt = build1 (RETURN_EXPR, TREE_TYPE (ret_stmt), ret_var); + bsi_insert_after (&bsi, ret_stmt, BSI_NEW_STMT); + } + + if (m) + { + stmt = build (MODIFY_EXPR, ret_type, NULL_TREE, + build (MULT_EXPR, ret_type, m_acc, ret_var)); + + tmp = create_tmp_var (ret_type, "acc_tmp"); + add_referenced_tmp_var (tmp); + + var = make_ssa_name (tmp, stmt); + TREE_OPERAND (stmt, 0) = var; + bsi_insert_before (&bsi, stmt, BSI_NEW_STMT); + } + else + var = ret_var; + + if (a) + { + stmt = build (MODIFY_EXPR, ret_type, NULL_TREE, + build (PLUS_EXPR, ret_type, a_acc, var)); + + tmp = create_tmp_var (ret_type, "acc_tmp"); + add_referenced_tmp_var (tmp); + + var = make_ssa_name (tmp, stmt); + TREE_OPERAND (stmt, 0) = var; + bsi_insert_before (&bsi, stmt, BSI_NEW_STMT); + } + + TREE_OPERAND (ret_stmt, 0) = var; + modify_stmt (ret_stmt); +} + +/* Eliminates tail call described by T. TMP_VARS is a list of + temporary variables used to copy the function arguments. */ + +static void +eliminate_tail_call (struct tailcall *t) +{ + tree param, stmt, args, rslt, call; + basic_block bb, first; + edge e; + tree phi; + stmt_ann_t ann; + vdef_optype vdefs; + unsigned i; + + stmt = bsi_stmt (t->call_bsi); + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + bb = t->call_block; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Eliminated tail recursion in bb %d : ", + bb->index); + print_generic_stmt (dump_file, stmt, TDF_SLIM); + fprintf (dump_file, "\n"); + } + + if (TREE_CODE (stmt) == MODIFY_EXPR) + stmt = TREE_OPERAND (stmt, 1); + + first = ENTRY_BLOCK_PTR->succ->dest; + + /* Replace the call by a jump to the start of function. */ + e = redirect_edge_and_branch (t->call_block->succ, first); + if (!e) + abort (); + PENDING_STMT (e) = NULL_TREE; + + /* Add phi node entries for arguments. Not every PHI node corresponds to + a function argument (there may be PHI nodes for virtual definitions of the + eliminated calls), so we search for a PHI corresponding to each argument + rather than searching for which argument a PHI node corresponds to. */ + + for (param = DECL_ARGUMENTS (current_function_decl), + args = TREE_OPERAND (stmt, 1); + param; + param = TREE_CHAIN (param), + args = TREE_CHAIN (args)) + { + + for (phi = phi_nodes (first); phi; phi = TREE_CHAIN (phi)) + if (param == SSA_NAME_VAR (PHI_RESULT (phi))) + break; + + /* The phi node indeed does not have to be there, in case the operand is + invariant in the function. */ + if (!phi) + continue; + + add_phi_arg (&phi, TREE_VALUE (args), e); + } + + /* Add phi nodes for the call clobbered variables. */ + vdefs = VDEF_OPS (ann); + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + param = SSA_NAME_VAR (VDEF_RESULT (vdefs, i)); + for (phi = phi_nodes (first); phi; phi = TREE_CHAIN (phi)) + if (param == SSA_NAME_VAR (PHI_RESULT (phi))) + break; + + if (!phi) + { + tree name = var_ann (param)->default_def; + tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name)); + + var_ann (param)->default_def = new_name; + phi = create_phi_node (name, first); + SSA_NAME_DEF_STMT (name) = phi; + add_phi_arg (&phi, new_name, ENTRY_BLOCK_PTR->succ); + + /* For all calls the same set of variables should be clobbered. This + means that there always should be the appropriate phi node except + for the first time we eliminate the call. */ + if (first->pred->pred_next->pred_next) + abort (); + } + + add_phi_arg (&phi, VDEF_OP (vdefs, i), e); + } + + /* Update the values of accumulators. */ + adjust_accumulator_values (t->call_bsi, t->mult, t->add, e); + + call = bsi_stmt (t->call_bsi); + if (TREE_CODE (call) == MODIFY_EXPR) + { + rslt = TREE_OPERAND (call, 0); + + /* Result of the call will no longer be defined. So adjust the + SSA_NAME_DEF_STMT accordingly. */ + SSA_NAME_DEF_STMT (rslt) = build_empty_stmt (); + } + + bsi_remove (&t->call_bsi); +} + +/* Optimizes the tailcall described by T. If OPT_TAILCALLS is true, also + mark the tailcalls for the sibcall optimization. */ + +static bool +optimize_tail_call (struct tailcall *t, bool opt_tailcalls) +{ + if (t->tail_recursion) + { + eliminate_tail_call (t); + return true; + } + + if (opt_tailcalls) + { + tree stmt = bsi_stmt (t->call_bsi); + + if (TREE_CODE (stmt) == MODIFY_EXPR) + stmt = TREE_OPERAND (stmt, 1); + if (TREE_CODE (stmt) != CALL_EXPR) + abort (); + CALL_EXPR_TAILCALL (stmt) = 1; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Found tail call "); + print_generic_expr (dump_file, stmt, dump_flags); + fprintf (dump_file, " in bb %i\n", t->call_block->index); + } + } + + return false; +} + +/* Optimizes tail calls in the function, turning the tail recursion + into iteration. */ + +static void +tree_optimize_tail_calls_1 (bool opt_tailcalls) +{ + edge e; + bool phis_constructed = false; + struct tailcall *tailcalls = NULL, *act, *next; + bool changed = false; + basic_block first = ENTRY_BLOCK_PTR->succ->dest; + tree stmt, param, ret_type, tmp, phi; + + if (!suitable_for_tail_opt_p ()) + return; + if (opt_tailcalls) + opt_tailcalls = suitable_for_tail_call_opt_p (); + + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + { + /* Only traverse the normal exits, i.e. those that end with return + statement. */ + stmt = last_stmt (e->src); + + if (stmt + && TREE_CODE (stmt) == RETURN_EXPR) + find_tail_calls (e->src, &tailcalls); + } + + /* Construct the phi nodes and accumulators if necessary. */ + a_acc = m_acc = NULL_TREE; + for (act = tailcalls; act; act = act->next) + { + if (!act->tail_recursion) + continue; + + if (!phis_constructed) + { + /* Ensure that there is only one predecessor of the block. */ + if (first->pred->pred_next) + first = split_edge (ENTRY_BLOCK_PTR->succ); + + /* Copy the args if needed. */ + for (param = DECL_ARGUMENTS (current_function_decl); + param; + param = TREE_CHAIN (param)) + if (var_ann (param) + /* Also parameters that are only defined but never used need not + be copied. */ + && (var_ann (param)->default_def + && TREE_CODE (var_ann (param)->default_def) == SSA_NAME)) + { + tree name = var_ann (param)->default_def; + tree new_name = make_ssa_name (param, SSA_NAME_DEF_STMT (name)); + tree phi; + + var_ann (param)->default_def = new_name; + phi = create_phi_node (name, first); + SSA_NAME_DEF_STMT (name) = phi; + add_phi_arg (&phi, new_name, first->pred); + } + phis_constructed = true; + } + + if (act->add && !a_acc) + { + ret_type = TREE_TYPE (DECL_RESULT (current_function_decl)); + + tmp = create_tmp_var (ret_type, "add_acc"); + add_referenced_tmp_var (tmp); + + phi = create_phi_node (tmp, first); + add_phi_arg (&phi, convert (ret_type, integer_zero_node), + first->pred); + a_acc = PHI_RESULT (phi); + } + + if (act->mult && !m_acc) + { + ret_type = TREE_TYPE (DECL_RESULT (current_function_decl)); + + tmp = create_tmp_var (ret_type, "mult_acc"); + add_referenced_tmp_var (tmp); + + phi = create_phi_node (tmp, first); + add_phi_arg (&phi, convert (ret_type, integer_one_node), + first->pred); + m_acc = PHI_RESULT (phi); + } + } + + for (; tailcalls; tailcalls = next) + { + next = tailcalls->next; + changed |= optimize_tail_call (tailcalls, opt_tailcalls); + free (tailcalls); + } + + if (a_acc || m_acc) + { + /* Modify the remaining return statements. */ + for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next) + { + stmt = last_stmt (e->src); + + if (stmt + && TREE_CODE (stmt) == RETURN_EXPR) + adjust_return_value (e->src, m_acc, a_acc); + } + } + + if (changed) + { + free_dominance_info (CDI_DOMINATORS); + cleanup_tree_cfg (); + } +} + +static void +execute_tail_recursion (void) +{ + tree_optimize_tail_calls_1 (false); +} + +static bool +gate_tail_calls (void) +{ + return flag_optimize_sibling_calls != 0; +} + +static void +execute_tail_calls (void) +{ + tree_optimize_tail_calls_1 (true); +} + +struct tree_opt_pass pass_tail_recursion = +{ + "tailr", /* name */ + NULL, /* gate */ + execute_tail_recursion, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */ +}; + +struct tree_opt_pass pass_tail_calls = +{ + "tailc", /* name */ + gate_tail_calls, /* gate */ + execute_tail_calls, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + PROP_cfg | PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */ +}; diff --git a/gcc/tree.c b/gcc/tree.c index 0e159c3ca97..33c696ef166 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -45,6 +45,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "output.h" #include "target.h" #include "langhooks.h" +#include "tree-iterator.h" +#include "basic-block.h" +#include "tree-flow.h" /* obstack.[ch] explicitly declined to prototype this. */ extern int _obstack_allocated_p (struct obstack *h, void *obj); @@ -68,6 +71,8 @@ static const char * const tree_node_kind_names[] = { "perm_tree_lists", "temp_tree_lists", "vecs", + "phi_nodes", + "ssa names", "random kinds", "lang_decl kinds", "lang_type kinds" @@ -186,6 +191,22 @@ tree_size (tree node) case ERROR_MARK: case PLACEHOLDER_EXPR: return sizeof (struct tree_common); + case PHI_NODE: return (sizeof (struct tree_phi_node) + + (PHI_ARG_CAPACITY (node) - 1) * + sizeof (struct phi_arg_d)); + + case EPHI_NODE: return (sizeof (struct tree_ephi_node) + + (EPHI_ARG_CAPACITY (node) - 1) * + sizeof (struct ephi_arg_d)); + + case SSA_NAME: return sizeof (struct tree_ssa_name); + case EUSE_NODE: return sizeof (struct tree_euse_node); + + case EKILL_NODE: + case EEXIT_NODE: return sizeof (struct tree_eref_common); + + case STATEMENT_LIST: return sizeof (struct tree_statement_list); + default: return lang_hooks.tree_size (code); } @@ -212,9 +233,9 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) #endif struct tree_common ttmp; - /* We can't allocate a TREE_VEC without knowing how many elements - it will have. */ - if (code == TREE_VEC) + /* We can't allocate a TREE_VEC, PHI_NODE, EPHI_NODE or STRING_CST + without knowing how many elements it will have. */ + if (code == TREE_VEC || code == PHI_NODE || code == EPHI_NODE) abort (); TREE_SET_CODE ((tree)&ttmp, code); @@ -259,6 +280,10 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) kind = id_kind; else if (code == TREE_VEC) kind = vec_kind; + else if (code == PHI_NODE) + kind = phi_kind; + else if (code == SSA_NAME) + kind = ssa_name_kind; else kind = x_kind; break; @@ -311,6 +336,7 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) case 'c': TREE_CONSTANT (t) = 1; + TREE_INVARIANT (t) = 1; break; case 'e': @@ -348,12 +374,19 @@ copy_node_stat (tree node MEM_STAT_DECL) enum tree_code code = TREE_CODE (node); size_t length; +#ifdef ENABLE_CHECKING + if (code == STATEMENT_LIST) + abort (); +#endif + length = tree_size (node); t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT); memcpy (t, node, length); TREE_CHAIN (t) = 0; TREE_ASM_WRITTEN (t) = 0; + TREE_VISITED (t) = 0; + t->common.ann = 0; if (TREE_CODE_CLASS (code) == 'd') DECL_UID (t) = next_decl_uid++; @@ -456,9 +489,8 @@ build_constructor (tree type, tree vals) TREE_SIDE_EFFECTS (c) = TREE_SIDE_EFFECTS (vals); TREE_READONLY (c) = TREE_READONLY (vals); TREE_CONSTANT (c) = TREE_CONSTANT (vals); + TREE_INVARIANT (c) = TREE_INVARIANT (vals); } - else - TREE_CONSTANT (c) = 0; /* safe side */ return c; } @@ -1073,44 +1105,6 @@ tree_cons_stat (tree purpose, tree value, tree chain MEM_STAT_DECL) return node; } -/* Return the first expression in a sequence of COMPOUND_EXPRs. */ - -tree -expr_first (tree expr) -{ - if (expr == NULL_TREE) - return expr; - while (TREE_CODE (expr) == COMPOUND_EXPR) - expr = TREE_OPERAND (expr, 0); - return expr; -} - -/* Return the last expression in a sequence of COMPOUND_EXPRs. */ - -tree -expr_last (tree expr) -{ - if (expr == NULL_TREE) - return expr; - while (TREE_CODE (expr) == COMPOUND_EXPR) - expr = TREE_OPERAND (expr, 1); - return expr; -} - -/* Return the number of subexpressions in a sequence of COMPOUND_EXPRs. */ - -int -expr_length (tree expr) -{ - int len = 0; - - if (expr == NULL_TREE) - return 0; - for (; TREE_CODE (expr) == COMPOUND_EXPR; expr = TREE_OPERAND (expr, 1)) - len += expr_length (TREE_OPERAND (expr, 0)); - ++len; - return len; -} /* Return the size nominally occupied by an object of type TYPE when it resides in memory. The value is measured in units of bytes, @@ -1299,11 +1293,18 @@ staticp (tree arg) case STRING_CST: return 1; + case COMPONENT_REF: + /* If the thing being referenced is not a field, then it is + something language specific. */ + if (TREE_CODE (TREE_OPERAND (arg, 1)) != FIELD_DECL) + return (*lang_hooks.staticp) (arg); + /* If we are referencing a bitfield, we can't evaluate an ADDR_EXPR at compile time and so it isn't a constant. */ - case COMPONENT_REF: - return (! DECL_BIT_FIELD (TREE_OPERAND (arg, 1)) - && staticp (TREE_OPERAND (arg, 0))); + if (DECL_BIT_FIELD (TREE_OPERAND (arg, 1))) + return 0; + + return staticp (TREE_OPERAND (arg, 0)); case BIT_FIELD_REF: return 0; @@ -1321,6 +1322,8 @@ staticp (tree arg) if (TREE_CODE (TYPE_SIZE (TREE_TYPE (arg))) == INTEGER_CST && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST) return staticp (TREE_OPERAND (arg, 0)); + else + return 0; default: if ((unsigned int) TREE_CODE (arg) @@ -1365,7 +1368,8 @@ save_expr (tree expr) Since it is no problem to reevaluate literals, we just return the literal node. */ inner = skip_simple_arithmetic (t); - if (TREE_CONSTANT (inner) + + if (TREE_INVARIANT (inner) || (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner)) || TREE_CODE (inner) == SAVE_EXPR || TREE_CODE (inner) == ERROR_MARK) @@ -1390,6 +1394,7 @@ save_expr (tree expr) eliminated as dead. */ TREE_SIDE_EFFECTS (t) = 1; TREE_READONLY (t) = 1; + TREE_INVARIANT (t) = 1; return t; } @@ -1417,9 +1422,9 @@ skip_simple_arithmetic (tree expr) inner = TREE_OPERAND (inner, 0); else if (TREE_CODE_CLASS (TREE_CODE (inner)) == '2') { - if (TREE_CONSTANT (TREE_OPERAND (inner, 1))) + if (TREE_INVARIANT (TREE_OPERAND (inner, 1))) inner = TREE_OPERAND (inner, 0); - else if (TREE_CONSTANT (TREE_OPERAND (inner, 0))) + else if (TREE_INVARIANT (TREE_OPERAND (inner, 0))) inner = TREE_OPERAND (inner, 1); else break; @@ -1508,7 +1513,14 @@ tree_node_structure (tree t) case IDENTIFIER_NODE: return TS_IDENTIFIER; case TREE_LIST: return TS_LIST; case TREE_VEC: return TS_VEC; + case PHI_NODE: return TS_PHI_NODE; + case EPHI_NODE: return TS_EPHI_NODE; + case EUSE_NODE: return TS_EUSE_NODE; + case EKILL_NODE: return TS_EREF_NODE; + case EEXIT_NODE: return TS_EREF_NODE; + case SSA_NAME: return TS_SSA_NAME; case PLACEHOLDER_EXPR: return TS_COMMON; + case STATEMENT_LIST: return TS_STATEMENT_LIST; default: abort (); @@ -1551,57 +1563,6 @@ unsave_expr_1 (tree expr) } } -/* Default lang hook for "unsave_expr_now". */ - -tree -lhd_unsave_expr_now (tree expr) -{ - enum tree_code code; - - /* There's nothing to do for NULL_TREE. */ - if (expr == 0) - return expr; - - unsave_expr_1 (expr); - - code = TREE_CODE (expr); - switch (TREE_CODE_CLASS (code)) - { - case 'c': /* a constant */ - case 't': /* a type node */ - case 'd': /* A decl node */ - case 'b': /* A block node */ - break; - - case 'x': /* miscellaneous: e.g., identifier, TREE_LIST or ERROR_MARK. */ - if (code == TREE_LIST) - { - lhd_unsave_expr_now (TREE_VALUE (expr)); - lhd_unsave_expr_now (TREE_CHAIN (expr)); - } - break; - - case 'e': /* an expression */ - case 'r': /* a reference */ - case 's': /* an expression with side effects */ - case '<': /* a comparison expression */ - case '2': /* a binary arithmetic expression */ - case '1': /* a unary arithmetic expression */ - { - int i; - - for (i = first_rtl_op (code) - 1; i >= 0; i--) - lhd_unsave_expr_now (TREE_OPERAND (expr, i)); - } - break; - - default: - abort (); - } - - return expr; -} - /* Return 0 if it is safe to evaluate EXPR multiple times, return 1 if it is safe if EXPR is unsaved afterward, or return 2 if it is completely unsafe. @@ -1639,6 +1600,14 @@ unsafe_for_reeval (tree expr) case RTL_EXPR: return 2; + /* A label can only be emitted once. */ + case LABEL_EXPR: + return 1; + + case BIND_EXPR: + unsafeness = 1; + break; + case TREE_LIST: for (exp = expr; exp != 0; exp = TREE_CHAIN (exp)) { @@ -2290,7 +2259,7 @@ stabilize_reference_1 (tree e) ignore things that are actual constant or that already have been handled by this function. */ - if (TREE_CONSTANT (e) || code == SAVE_EXPR) + if (TREE_INVARIANT (e)) return e; switch (TREE_CODE_CLASS (code)) @@ -2343,12 +2312,50 @@ stabilize_reference_1 (tree e) TREE_READONLY (result) = TREE_READONLY (e); TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e); TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e); + TREE_INVARIANT (result) = 1; return result; } /* Low-level constructors for expressions. */ +/* A helper function for build1 and constant folders. + Set TREE_CONSTANT and TREE_INVARIANT for an ADDR_EXPR. */ + +void +recompute_tree_invarant_for_addr_expr (tree t) +{ + tree node = TREE_OPERAND (t, 0); + bool tc = false, ti = false; + + /* Addresses of constants and static variables are constant; + all other decl addresses are invariant. */ + if (staticp (node)) + tc = ti = true; + else + { + /* Step past constant offsets. */ + while (1) + { + if (TREE_CODE (node) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL + && ! DECL_BIT_FIELD (TREE_OPERAND (node, 1))) + ; + else if (TREE_CODE (node) == ARRAY_REF + && TREE_CONSTANT (TREE_OPERAND (node, 1))) + ; + else + break; + node = TREE_OPERAND (node, 0); + } + if (DECL_P (node)) + ti = true; + } + + TREE_CONSTANT (t) = tc; + TREE_INVARIANT (t) = ti; +} + /* Build an expression of code CODE, data type TYPE, and operands as specified. Expressions and reference nodes can be created this way. Constants, decls, types and misc nodes cannot be. @@ -2413,8 +2420,10 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) TREE_SET_CODE (t, code); TREE_TYPE (t) = type; + SET_EXPR_LOCUS (t, NULL); TREE_COMPLEXITY (t) = 0; TREE_OPERAND (t, 0) = node; + TREE_BLOCK (t) = NULL_TREE; if (node && !TYPE_P (node) && first_rtl_op (code) != 0) { TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node); @@ -2448,6 +2457,8 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) case ADDR_EXPR: if (node) { + recompute_tree_invarant_for_addr_expr (t); + /* The address of a volatile decl or reference does not have side-effects. But be careful not to ignore side-effects from other sources deeper in the expression--if node is a _REF and @@ -2472,6 +2483,8 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) if (TREE_CODE_CLASS (code) == '1' && node && !TYPE_P (node) && TREE_CONSTANT (node)) TREE_CONSTANT (t) = 1; + if (TREE_CODE_CLASS (code) == '1' && node && TREE_INVARIANT (node)) + TREE_INVARIANT (t) = 1; break; } @@ -2489,13 +2502,15 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL) read_only = 0; \ if (!TREE_CONSTANT (arg##N)) \ constant = 0; \ + if (!TREE_INVARIANT (arg##N)) \ + invariant = 0; \ } \ } while (0) tree build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL) { - bool constant, read_only, side_effects; + bool constant, read_only, side_effects, invariant; tree t; int fro; @@ -2519,32 +2534,14 @@ build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL) || TREE_CODE_CLASS (code) == '2'); read_only = 1; side_effects = TREE_SIDE_EFFECTS (t); + invariant = constant; PROCESS_ARG(0); PROCESS_ARG(1); - if (code == CALL_EXPR && !side_effects) - { - tree node; - int i; - - /* Calls have side-effects, except those to const or - pure functions. */ - i = call_expr_flags (t); - if (!(i & (ECF_CONST | ECF_PURE))) - side_effects = 1; - - /* And even those have side-effects if their arguments do. */ - else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node)) - if (TREE_SIDE_EFFECTS (TREE_VALUE (node))) - { - side_effects = 1; - break; - } - } - TREE_READONLY (t) = read_only; TREE_CONSTANT (t) = constant; + TREE_INVARIANT (t) = invariant; TREE_SIDE_EFFECTS (t) = side_effects; return t; @@ -2554,20 +2551,10 @@ tree build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1, tree arg2 MEM_STAT_DECL) { - bool constant, read_only, side_effects; + bool constant, read_only, side_effects, invariant; tree t; int fro; - /* ??? Quite a lot of existing code passes one too many arguments to - CALL_EXPR. Not going to fix them, because CALL_EXPR is about to - grow a new argument, so it would just mean changing them back. */ - if (code == CALL_EXPR) - { - if (arg2 != NULL_TREE) - abort (); - return build2 (code, tt, arg0, arg1); - } - #ifdef ENABLE_CHECKING if (TREE_CODE_LENGTH (code) != 3) abort (); @@ -2584,6 +2571,26 @@ build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1, PROCESS_ARG(1); PROCESS_ARG(2); + if (code == CALL_EXPR && !side_effects) + { + tree node; + int i; + + /* Calls have side-effects, except those to const or + pure functions. */ + i = call_expr_flags (t); + if (!(i & (ECF_CONST | ECF_PURE))) + side_effects = 1; + + /* And even those have side-effects if their arguments do. */ + else for (node = arg1; node; node = TREE_CHAIN (node)) + if (TREE_SIDE_EFFECTS (TREE_VALUE (node))) + { + side_effects = 1; + break; + } + } + TREE_SIDE_EFFECTS (t) = side_effects; return t; @@ -2593,7 +2600,7 @@ tree build4_stat (enum tree_code code, tree tt, tree arg0, tree arg1, tree arg2, tree arg3 MEM_STAT_DECL) { - bool constant, read_only, side_effects; + bool constant, read_only, side_effects, invariant; tree t; int fro; @@ -2735,35 +2742,49 @@ build_block (tree vars, tree tags ATTRIBUTE_UNUSED, tree subblocks, return block; } -/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact - location where an expression or an identifier were encountered. It - is necessary for languages where the frontend parser will handle - recursively more than one file (Java is one of them). */ +static GTY(()) tree last_annotated_node; -tree -build_expr_wfl (tree node, const char *file, int line, int col) -{ - static const char *last_file = 0; - static tree last_filenode = NULL_TREE; - tree wfl = make_node (EXPR_WITH_FILE_LOCATION); +/* Record the exact location where an expression or an identifier were + encountered. */ - EXPR_WFL_NODE (wfl) = node; - EXPR_WFL_SET_LINECOL (wfl, line, col); - if (file != last_file) +void +annotate_with_file_line (tree node, const char *file, int line) +{ + /* Roughly one percent of the calls to this function are to annotate + a node with the same information already attached to that node! + Just return instead of wasting memory. */ + if (EXPR_LOCUS (node) + && (EXPR_FILENAME (node) == file + || ! strcmp (EXPR_FILENAME (node), file)) + && EXPR_LINENO (node) == line) { - last_file = file; - last_filenode = file ? get_identifier (file) : NULL_TREE; + last_annotated_node = node; + return; } - EXPR_WFL_FILENAME_NODE (wfl) = last_filenode; - - if (node && !TYPE_P (node)) + /* In heavily macroized code (such as GCC itself) this single + entry cache can reduce the number of allocations by more + than half. */ + if (last_annotated_node + && EXPR_LOCUS (last_annotated_node) + && (EXPR_FILENAME (last_annotated_node) == file + || ! strcmp (EXPR_FILENAME (last_annotated_node), file)) + && EXPR_LINENO (last_annotated_node) == line) { - TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node); - TREE_TYPE (wfl) = TREE_TYPE (node); + SET_EXPR_LOCUS (node, EXPR_LOCUS (last_annotated_node)); + return; } - return wfl; + SET_EXPR_LOCUS (node, ggc_alloc (sizeof (location_t))); + EXPR_LINENO (node) = line; + EXPR_FILENAME (node) = file; + last_annotated_node = node; +} + +void +annotate_with_locus (tree node, location_t locus) +{ + annotate_with_file_line (node, locus.file, locus.line); } /* Return a declaration like DDECL except that its DECL_ATTRIBUTES @@ -3655,10 +3676,8 @@ simple_cst_equal (tree t1, tree t2) TREE_STRING_LENGTH (t1))); case CONSTRUCTOR: - if (CONSTRUCTOR_ELTS (t1) == CONSTRUCTOR_ELTS (t2)) - return 1; - else - abort (); + return simple_cst_list_equal (CONSTRUCTOR_ELTS (t1), + CONSTRUCTOR_ELTS (t2)); case SAVE_EXPR: return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); @@ -3773,10 +3792,7 @@ associative_tree_code (enum tree_code code) case BIT_AND_EXPR: case BIT_XOR_EXPR: case PLUS_EXPR: - case MINUS_EXPR: case MULT_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: case MIN_EXPR: case MAX_EXPR: return true; @@ -3864,9 +3880,17 @@ iterative_hash_expr (tree t, hashval_t val) { val = iterative_hash_object (code, val); - if (code == NOP_EXPR || code == CONVERT_EXPR + /* Don't hash the type, that can lead to having nodes which + compare equal according to operand_equal_p, but which + have different hash codes. */ + if (code == NOP_EXPR + || code == CONVERT_EXPR || code == NON_LVALUE_EXPR) - val = iterative_hash_object (TREE_TYPE (t), val); + { + /* Make sure to include signness in the hash computation. */ + val += TYPE_UNSIGNED (TREE_TYPE (t)); + val = iterative_hash_expr (TREE_OPERAND (t, 0), val); + } if (commutative_tree_code (code)) { @@ -3895,6 +3919,11 @@ iterative_hash_expr (tree t, hashval_t val) for (; t; t = TREE_CHAIN (t)) val = iterative_hash_expr (TREE_VALUE (t), val); } + else if (code == SSA_NAME) + { + val = iterative_hash_object (SSA_NAME_VERSION (t), val); + val = iterative_hash_expr (SSA_NAME_VAR (t), val); + } else abort (); @@ -4855,6 +4884,8 @@ dump_tree_statistics (void) fprintf (stderr, "---------------------------------------\n"); fprintf (stderr, "%-20s %7d %10d\n", "Total", total_nodes, total_bytes); fprintf (stderr, "---------------------------------------\n"); + ssanames_print_statistics (); + phinodes_print_statistics (); #else fprintf (stderr, "(No per-node statistics)\n"); #endif @@ -5155,6 +5186,30 @@ tree_vec_elt_check_failed (int idx, int len, const char *file, int line, idx + 1, len, function, trim_filename (file), line); } +/* Similar to above, except that the check is for the bounds of a EPHI_NODE's + (dynamically sized) vector. */ + +void +ephi_node_elt_check_failed (int idx, int len, const char *file, int line, + const char *function) +{ + internal_error + ("tree check: accessed elt %d of ephi_node with %d elts in %s, at %s:%d", + idx + 1, len, function, trim_filename (file), line); +} + +/* Similar to above, except that the check is for the bounds of a PHI_NODE's + (dynamically sized) vector. */ + +void +phi_node_elt_check_failed (int idx, int len, const char *file, int line, + const char *function) +{ + internal_error + ("tree check: accessed elt %d of phi_node with %d elts in %s, at %s:%d", + idx + 1, len, function, trim_filename (file), line); +} + /* Similar to above, except that the check is for the bounds of the operand vector of an expression node. */ @@ -5447,44 +5502,94 @@ build_vector_type (tree innertype, int nunits) bool initializer_zerop (tree init) { + tree elt; + STRIP_NOPS (init); switch (TREE_CODE (init)) { case INTEGER_CST: return integer_zerop (init); + case REAL_CST: + /* ??? Note that this is not correct for C4X float formats. There, + a bit pattern of all zeros is 1.0; 0.0 is encoded with the most + negative exponent. */ return real_zerop (init) && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init)); + case COMPLEX_CST: return integer_zerop (init) || (real_zerop (init) && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init))) && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init)))); - case CONSTRUCTOR: - { - /* Set is empty if it has no elements. */ - if ((TREE_CODE (TREE_TYPE (init)) == SET_TYPE) - && CONSTRUCTOR_ELTS (init)) + + case VECTOR_CST: + for (elt = TREE_VECTOR_CST_ELTS (init); elt; elt = TREE_CHAIN (elt)) + if (!initializer_zerop (TREE_VALUE (elt))) return false; + return true; - if (AGGREGATE_TYPE_P (TREE_TYPE (init))) - { - tree aggr_init = CONSTRUCTOR_ELTS (init); - - while (aggr_init) - { - if (! initializer_zerop (TREE_VALUE (aggr_init))) - return false; - aggr_init = TREE_CHAIN (aggr_init); - } - return true; - } + case CONSTRUCTOR: + elt = CONSTRUCTOR_ELTS (init); + if (elt == NULL_TREE) + return true; + + /* A set is empty only if it has no elements. */ + if (TREE_CODE (TREE_TYPE (init)) == SET_TYPE) return false; - } + + for (; elt ; elt = TREE_CHAIN (elt)) + if (! initializer_zerop (TREE_VALUE (elt))) + return false; + return true; + default: return false; } } +void +add_var_to_bind_expr (tree bind_expr, tree var) +{ + BIND_EXPR_VARS (bind_expr) + = chainon (BIND_EXPR_VARS (bind_expr), var); + if (BIND_EXPR_BLOCK (bind_expr)) + BLOCK_VARS (BIND_EXPR_BLOCK (bind_expr)) + = BIND_EXPR_VARS (bind_expr); +} + +/* Build an empty statement. */ + +tree +build_empty_stmt (void) +{ + return build1 (NOP_EXPR, void_type_node, size_zero_node); +} + +bool +is_essa_node (tree t) +{ + if (TREE_CODE (t) == EPHI_NODE || TREE_CODE (t) == EUSE_NODE + || TREE_CODE (t) == EEXIT_NODE || TREE_CODE (t) == EKILL_NODE) + return true; + return false; +} + + +/* Return true if T (assumed to be a DECL) must be assigned a memory + location. */ + +bool +needs_to_live_in_memory (tree t) +{ + return (DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (t) + || TREE_STATIC (t) + || DECL_EXTERNAL (t) + || DECL_NONLOCAL (t) + || (TREE_CODE (t) == RESULT_DECL + && aggregate_value_p (t, current_function_decl)) + || decl_function_context (t) != current_function_decl); +} + #include "gt-tree.h" diff --git a/gcc/tree.def b/gcc/tree.def index c8e5398d575..ca9cf9f18b0 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -390,6 +390,12 @@ DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", 'r', 2) Operand 2: index into vtable (must be an integer_cst). */ DEFTREECODE (VTABLE_REF, "vtable_ref", 'r', 3) +/* The exception object from the runtime. */ +DEFTREECODE (EXC_PTR_EXPR, "exc_ptr_expr", 'e', 0) + +/* The filter object from the runtime. */ +DEFTREECODE (FILTER_EXPR, "filter_expr", 'e', 0) + /* Constructor: return an aggregate value made from specified components. In C, this is used only for structure and array initializers. Also used for SET_TYPE in Chill (and potentially Pascal). @@ -447,10 +453,10 @@ DEFTREECODE (TARGET_EXPR, "target_expr", 'e', 4) DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3) /* Declare local variables, including making RTL and allocating space. - Operand 0 is a chain of VAR_DECL nodes for the variables. - Operand 1 is the body, the expression to be computed using + BIND_EXPR_VARS is a chain of VAR_DECL nodes for the variables. + BIND_EXPR_BODY is the body, the expression to be computed using the variables. The value of operand 1 becomes that of the BIND_EXPR. - Operand 2 is the BLOCK that corresponds to these bindings + BIND_EXPR_BLOCK is the BLOCK that corresponds to these bindings for debugging purposes. If this BIND_EXPR is actually expanded, that sets the TREE_USED flag in the BLOCK. @@ -469,10 +475,16 @@ DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3) nodes for the function. */ DEFTREECODE (BIND_EXPR, "bind_expr", 'e', 3) +/* A labeled block. Operand 0 is the label that will be generated to + mark the end of the block. + Operand 1 is the labeled block body. */ +DEFTREECODE (LABELED_BLOCK_EXPR, "labeled_block_expr", 'e', 2) + /* Function call. Operand 0 is the function. Operand 1 is the argument list, a list of expressions - made out of a chain of TREE_LIST nodes. */ -DEFTREECODE (CALL_EXPR, "call_expr", 'e', 2) + made out of a chain of TREE_LIST nodes. + Operand 2 is the static chain argument, or NULL. */ +DEFTREECODE (CALL_EXPR, "call_expr", 'e', 3) /* Specify a value to compute along with its corresponding cleanup. Operand 0 argument is an expression whose value needs a cleanup. @@ -768,21 +780,14 @@ DEFTREECODE (VA_ARG_EXPR, "va_arg_expr", 'e', 1) /* Evaluate operand 1. If and only if an exception is thrown during the evaluation of operand 1, evaluate operand 2. - This differs from WITH_CLEANUP_EXPR, in that operand 2 is never - evaluated unless an exception is throw. */ + This differs from TRY_FINALLY_EXPR in that operand 2 is not evaluated + on a normal or jump exit, only on an exception. */ DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", 'e', 2) /* Evaluate the first operand. The second operand is a cleanup expression which is evaluated on any exit (normal, exception, or jump out) from this expression. */ DEFTREECODE (TRY_FINALLY_EXPR, "try_finally", 'e', 2) - -/* Used internally for cleanups in the implementation of TRY_FINALLY_EXPR. - (Specifically, it is created by expand_expr, not front-ends.) - Operand 0 is the rtx for the start of the subroutine we need to call. - Operand 1 is the rtx for a variable in which to store the address - of where the subroutine should return to. */ -DEFTREECODE (GOTO_SUBROUTINE_EXPR, "goto_subroutine", 'e', 2) /* These types of expressions have no useful value, and always have side effects. */ @@ -796,6 +801,13 @@ DEFTREECODE (LABEL_EXPR, "label_expr", 's', 1) The type should be void and the value should be ignored. */ DEFTREECODE (GOTO_EXPR, "goto_expr", 's', 1) +/* Used internally for cleanups in the implementation of TRY_FINALLY_EXPR. + (Specifically, it is created by expand_expr, not front-ends.) + Operand 0 is the rtx for the start of the subroutine we need to call. + Operand 1 is the rtx for a variable in which to store the address + of where the subroutine should return to. */ +DEFTREECODE (GOTO_SUBROUTINE_EXPR, "goto_subroutine", 's', 2) + /* RETURN. Evaluates operand 0, then returns from the current function. Presumably that operand is an assignment that stores into the RESULT_DECL that hold the value to be returned. @@ -812,33 +824,80 @@ DEFTREECODE (EXIT_EXPR, "exit_expr", 's', 1) The type should be void and the value should be ignored. */ DEFTREECODE (LOOP_EXPR, "loop_expr", 's', 1) -/* A labeled block. Operand 0 is the label that will be generated to - mark the end of the block. - Operand 1 is the labeled block body. */ -DEFTREECODE (LABELED_BLOCK_EXPR, "labeled_block_expr", 'e', 2) - /* Exit a labeled block, possibly returning a value. Operand 0 is a LABELED_BLOCK_EXPR to exit. Operand 1 is the value to return. It may be left null. */ -DEFTREECODE (EXIT_BLOCK_EXPR, "exit_block_expr", 'e', 2) - -/* Annotates a tree node (usually an expression) with source location - information: a file name (EXPR_WFL_FILENAME); a line number - (EXPR_WFL_LINENO); and column number (EXPR_WFL_COLNO). It is - expanded as the contained node (EXPR_WFL_NODE); a line note should - be emitted first if EXPR_WFL_EMIT_LINE_NOTE. - The third operand is only used in the Java front-end, and will - eventually be removed. */ -DEFTREECODE (EXPR_WITH_FILE_LOCATION, "expr_with_file_location", 'e', 3) +DEFTREECODE (EXIT_BLOCK_EXPR, "exit_block_expr", 's', 2) /* Switch expression. - Operand 0 is the expression used to perform the branch, - Operand 1 contains the case values. The way they're organized is - front-end implementation defined. */ -DEFTREECODE (SWITCH_EXPR, "switch_expr", 'e', 2) -/* The exception object from the runtime. */ -DEFTREECODE (EXC_PTR_EXPR, "exc_ptr_expr", 'e', 0) + TREE_TYPE is the original type of the condition, before any + language required type conversions. It may be NULL, in which case + the original type and final types are assumed to be the same. + + Operand 0 is the expression used to perform the branch, + Operand 1 is the body of the switch, which probably contains + CASE_LABEL_EXPRs. It may also be NULL, in which case operand 2 + must not be NULL. + Operand 2 is either NULL_TREE or a TREE_VEC of the CASE_LABEL_EXPRs + of all the cases. */ +DEFTREECODE (SWITCH_EXPR, "switch_expr", 's', 3) + +/* Used to represent a case label. The operands are CASE_LOW and + CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a + 'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case + label. CASE_LABEL is the corresponding LABEL_DECL. */ +DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", 's', 3) + +/* RESX. Resume execution after an exception. Operand 0 is a + number indicating the exception region that is being left. */ +DEFTREECODE (RESX_EXPR, "resx_expr", 's', 1) + +/* Used to represent an inline assembly statement. ASM_STRING returns a + STRING_CST for the instruction (e.g., "mov x, y"). ASM_OUTPUTS, + ASM_INPUTS, and ASM_CLOBBERS represent the outputs, inputs, and clobbers + for the statement. */ +DEFTREECODE (ASM_EXPR, "asm_expr", 's', 4) + +/* Variable references for SSA analysis. New SSA names are created every + time a variable is assigned a new value. The SSA builder uses SSA_NAME + nodes to implement SSA versioning. */ +DEFTREECODE (SSA_NAME, "ssa_name", 'x', 0) + +/* Expression SSA real and phi operand occurrence node. */ +DEFTREECODE (EUSE_NODE, "euse_node", 'x', 0) + +/* Expression SSA kill occurrence node. */ +DEFTREECODE (EKILL_NODE, "ekill_node", 'x', 0) + +/* Expression SSA expression PHI. Like a regular SSA PHI operator, + but for expressions*/ +DEFTREECODE (EPHI_NODE, "ephi_node", 'x', 0) + +/* Expression SSA exit occurrence node. */ +DEFTREECODE (EEXIT_NODE, "eexit_node", 'x', 0) + +/* SSA PHI operator. PHI_RESULT is the new SSA_NAME node created by + the PHI node. PHI_ARG_LENGTH is the number of arguments. + PHI_ARG_ELT returns the Ith tuple from the + argument list. Each tuple contains the incoming reaching + definition (SSA_NAME node) and the edge via which that definition + is coming through. */ +DEFTREECODE (PHI_NODE, "phi_node", 'x', 0) + +/* Used to represent a typed exception handler. CATCH_TYPES is the type (or + list of types) handled, and CATCH_BODY is the code for the handler. */ +DEFTREECODE (CATCH_EXPR, "catch_expr", 's', 2) + +/* Used to represent an exception specification. EH_FILTER_TYPES is a list + of allowed types, and EH_FILTER_FAILURE is an expression to evaluate on + failure. EH_FILTER_MUST_NOT_THROW controls which range type to use when + expanding. */ +DEFTREECODE (EH_FILTER_EXPR, "eh_filter_expr", 's', 2) + +/* Used to chain children of container statements together. + Use the interface in tree-iterator.h to access this node. */ +DEFTREECODE (STATEMENT_LIST, "statement_list", 'x', 0) /* Local variables: diff --git a/gcc/tree.h b/gcc/tree.h index 0f7e7eda5f4..efc8691a0d0 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -148,11 +148,13 @@ extern GTY(()) tree implicit_built_in_decls[(int) END_BUILTINS]; See the accessor macros, defined below, for documentation of the fields. */ +union tree_ann_d; struct tree_common GTY(()) { tree chain; tree type; + union tree_ann_d *ann; ENUM_BITFIELD(tree_code) code : 8; @@ -163,17 +165,16 @@ struct tree_common GTY(()) unsigned readonly_flag : 1; unsigned unsigned_flag : 1; unsigned asm_written_flag: 1; - unsigned used_flag : 1; + unsigned nowarning_flag : 1; + unsigned used_flag : 1; unsigned nothrow_flag : 1; unsigned static_flag : 1; unsigned public_flag : 1; unsigned private_flag : 1; unsigned protected_flag : 1; unsigned deprecated_flag : 1; - - unsigned unused_0 : 1; - unsigned unused_1 : 1; + unsigned invariant_flag : 1; unsigned lang_flag_0 : 1; unsigned lang_flag_1 : 1; @@ -182,7 +183,7 @@ struct tree_common GTY(()) unsigned lang_flag_4 : 1; unsigned lang_flag_5 : 1; unsigned lang_flag_6 : 1; - unsigned unused_2 : 1; + unsigned visited : 1; }; /* The following table lists the uses of each of the above flags and @@ -196,14 +197,12 @@ struct tree_common GTY(()) ..._TYPE, IDENTIFIER_NODE. In a STMT_EXPR, it means we want the result of the enclosed expression. + CALL_EXPR_TAILCALL in CALL_EXPR static_flag: TREE_STATIC in VAR_DECL, FUNCTION_DECL, CONSTRUCTOR, ADDR_EXPR - TREE_NO_UNUSED_WARNING in - CONVERT_EXPR, NOP_EXPR, COMPOUND_EXPR, NON_LVALUE_EXPR - ??? plus other expressions, apparently (e.g. MODIFY_EXPR). TREE_VIA_VIRTUAL in TREE_LIST or TREE_VEC TREE_CONSTANT_OVERFLOW in @@ -213,6 +212,9 @@ struct tree_common GTY(()) CLEANUP_EH_ONLY in TARGET_EXPR, WITH_CLEANUP_EXPR, CLEANUP_STMT, TREE_LIST elements of a block's cleanup list. + ASM_INPUT_P in + ASM_EXPR + EH_FILTER_MUST_NOT_THROW in EH_FILTER_EXPR TYPE_REF_CAN_ALIAS_ALL in POINTER_TYPE, REFERENCE_TYPE @@ -223,8 +225,10 @@ struct tree_common GTY(()) ??? and other expressions? TREE_PUBLIC in VAR_DECL or FUNCTION_DECL or IDENTIFIER_NODE - EXPR_WFL_EMIT_LINE_NOTE in - EXPR_WITH_FILE_LOCATION + TREE_VIA_PUBLIC in + TREE_LIST or TREE_VEC + ASM_VOLATILE_P in + ASM_EXPR private_flag: @@ -248,6 +252,9 @@ struct tree_common GTY(()) all decls all constants + FORCED_LABEL in + LABEL_DECL + volatile_flag: TREE_THIS_VOLATILE in @@ -284,7 +291,7 @@ struct tree_common GTY(()) TREE_ASM_WRITTEN in VAR_DECL, FUNCTION_DECL, RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE - BLOCK + BLOCK, SSA_NAME used_flag: @@ -304,6 +311,19 @@ struct tree_common GTY(()) TREE_DEPRECATED in ..._DECL + visited: + + Used in tree traversals to mark visited nodes. + + invariant_flag: + + TREE_INVARIANT in + all expressions. + + nowarning_flag: + + TREE_NO_WARNING in + ... any expr node */ /* Define accessors for the fields that all tree nodes have @@ -387,6 +407,16 @@ struct tree_common GTY(()) __FUNCTION__); \ __t; }) +#define EREF_NODE_CHECK(t) __extension__ \ +({ const tree __t = t; \ + if (TREE_CODE (__t) != EPHI_NODE \ + && TREE_CODE (__t) != EKILL_NODE \ + && TREE_CODE (__t) != EUSE_NODE \ + && TREE_CODE (__t) != EEXIT_NODE) \ + tree_check_failed (__t, TREE_CODE (t), \ + __FILE__, __LINE__, __FUNCTION__); \ + __t; }) + #define TREE_VEC_ELT_CHECK(T, I) __extension__ \ (*({const tree __t = (T); \ const int __i = (I); \ @@ -398,6 +428,28 @@ struct tree_common GTY(()) __FILE__, __LINE__, __FUNCTION__); \ &__t->vec.a[__i]; })) +#define EPHI_NODE_ELT_CHECK(t, i) __extension__ \ +(*({const tree __t = t; \ + const int __i = (i); \ + if (TREE_CODE (__t) != EPHI_NODE) \ + tree_check_failed (__t, EPHI_NODE, \ + __FILE__, __LINE__, __FUNCTION__); \ + if (__i < 0 || __i >= __t->ephi.capacity) \ + ephi_node_elt_check_failed (__i, __t->ephi.num_args, \ + __FILE__, __LINE__, __FUNCTION__); \ + &__t->ephi.a[__i]; })) + +#define PHI_NODE_ELT_CHECK(t, i) __extension__ \ +(*({const tree __t = t; \ + const int __i = (i); \ + if (TREE_CODE (__t) != PHI_NODE) \ + tree_check_failed (__t, PHI_NODE, \ + __FILE__, __LINE__, __FUNCTION__); \ + if (__i < 0 || __i >= __t->phi.capacity) \ + phi_node_elt_check_failed (__i, __t->phi.num_args, \ + __FILE__, __LINE__, __FUNCTION__); \ + &__t->phi.a[__i]; })) + /* Special checks for TREE_OPERANDs. */ #define TREE_OPERAND_CHECK(T, I) __extension__ \ (*({const tree __t = EXPR_CHECK (T); \ @@ -452,6 +504,12 @@ extern void tree_class_check_failed (const tree, int, extern void tree_vec_elt_check_failed (int, int, const char *, int, const char *) ATTRIBUTE_NORETURN; +extern void phi_node_elt_check_failed (int, int, const char *, + int, const char *) + ATTRIBUTE_NORETURN; +extern void ephi_node_elt_check_failed (int, int, const char *, + int, const char *) + ATTRIBUTE_NORETURN; extern void tree_operand_check_failed (int, enum tree_code, const char *, int, const char *) @@ -471,9 +529,14 @@ extern void tree_operand_check_failed (int, enum tree_code, #define TREE_OPERAND_CHECK(T, I) ((T)->exp.operands[I]) #define TREE_OPERAND_CHECK_CODE(T, CODE, I) ((T)->exp.operands[I]) #define TREE_RTL_OPERAND_CHECK(T, CODE, I) (*(rtx *) &((T)->exp.operands[I])) +#define EREF_NODE_CHECK(T) (T) +#define PHI_NODE_ELT_CHECK(T, i) ((T)->phi.a[i]) +#define EPHI_NODE_ELT_CHECK(T, i) ((T)->ephi.a[i]) #endif +#define TREE_BLOCK(NODE) ((NODE)->exp.block) + #include "tree-check.h" #define TYPE_CHECK(T) TREE_CLASS_CHECK (T, 't') @@ -565,6 +628,13 @@ extern void tree_operand_check_failed (int, enum tree_code, == TREE_TYPE (TREE_OPERAND (EXP, 0)))) \ (EXP) = TREE_OPERAND (EXP, 0) +/* Remove unnecessary type conversions according to + tree_ssa_useless_type_conversion. */ + +#define STRIP_USELESS_TYPE_CONVERSION(EXP) \ + while (tree_ssa_useless_type_conversion (EXP)) \ + EXP = TREE_OPERAND (EXP, 0) + /* Nonzero if TYPE represents an integral type. Note that we do not include COMPLEX types here. */ @@ -638,6 +708,8 @@ extern void tree_operand_check_failed (int, enum tree_code, had its address taken. That matters for inline functions. */ #define TREE_ADDRESSABLE(NODE) ((NODE)->common.addressable_flag) +#define CALL_EXPR_TAILCALL(NODE) (CALL_EXPR_CHECK(NODE)->common.addressable_flag) + /* In a VAR_DECL, nonzero means allocate static storage. In a FUNCTION_DECL, nonzero if function has been defined. In a CONSTRUCTOR, nonzero means allocate static storage. @@ -651,13 +723,9 @@ extern void tree_operand_check_failed (int, enum tree_code, executed if an exception is thrown, not on normal exit of its scope. */ #define CLEANUP_EH_ONLY(NODE) ((NODE)->common.static_flag) -/* In a CONVERT_EXPR, NOP_EXPR, NON_LVALUE_EXPR or COMPOUND_EXPR, this means - the node was made implicitly and should not lead to an "unused value" - warning. - - ??? Apparently this is also used on other expression types (such as - MODIFY_EXPR. This needs to be cleaned up sometime. */ -#define TREE_NO_UNUSED_WARNING(NODE) (EXPR_CHECK (NODE)->common.static_flag) +/* In an expr node (usually a conversion) this means the node was made + implicitly and should not lead to any sort of warning. */ +#define TREE_NO_WARNING(NODE) ((NODE)->common.nowarning_flag) /* Nonzero for a TREE_LIST or TREE_VEC node means that the derivation chain is via a `virtual' declaration. */ @@ -704,6 +772,11 @@ extern void tree_operand_check_failed (int, enum tree_code, #define TREE_SIDE_EFFECTS(NODE) \ (NON_TYPE_CHECK (NODE)->common.side_effects_flag) +/* In a LABEL_DECL, nonzero means this label had its address taken + and therefore can never be deleted and is a jump target for + computed gotos. */ +#define FORCED_LABEL(NODE) ((NODE)->common.side_effects_flag) + /* Nonzero means this expression is volatile in the C sense: its address should be of type `volatile WHATEVER *'. In other words, the declared item is volatile qualified. @@ -746,7 +819,9 @@ extern void tree_operand_check_failed (int, enum tree_code, to be compiled separately. Nonzero in a RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE or ENUMERAL_TYPE if the sdb debugging info for the type has been written. - In a BLOCK node, nonzero if reorder_blocks has already seen this block. */ + In a BLOCK node, nonzero if reorder_blocks has already seen this block. + In an SSA_NAME node, nonzero if the SSA_NAME occurs in an abnormal + PHI node. */ #define TREE_ASM_WRITTEN(NODE) ((NODE)->common.asm_written_flag) /* Nonzero in a _DECL if the name is used in its scope. @@ -772,7 +847,10 @@ extern void tree_operand_check_failed (int, enum tree_code, of this type is aligned at least to the alignment of the type, even if it doesn't appear that it is. We see this, for example, in object-oriented languages where a tag field may show this is an object of a more-aligned - variant of the more generic type. */ + variant of the more generic type. + + In an SSA_NAME node, nonzero if the SSA_NAME node is on the SSA_NAME + freelist. */ #define TYPE_ALIGN_OK(NODE) (TYPE_CHECK (NODE)->common.nothrow_flag) /* Used in classes in C++. */ @@ -785,6 +863,12 @@ extern void tree_operand_check_failed (int, enum tree_code, deprecated feature by __attribute__((deprecated)). */ #define TREE_DEPRECATED(NODE) ((NODE)->common.deprecated_flag) +/* Value of expression is function invariant. A strict subset of + TREE_CONSTANT, such an expression is constant over any one function + invocation, though not across different invocations. May appear in + any expression node. */ +#define TREE_INVARIANT(NODE) ((NODE)->common.invariant_flag) + /* These flags are available for each language front end to use internally. */ #define TREE_LANG_FLAG_0(NODE) ((NODE)->common.lang_flag_0) #define TREE_LANG_FLAG_1(NODE) ((NODE)->common.lang_flag_1) @@ -924,6 +1008,11 @@ struct tree_vec GTY(()) /* Define fields and accessors for some nodes that represent expressions. */ +/* Non-zero if NODE is an emtpy statement (NOP_EXPR <0>). */ +#define IS_EMPTY_STMT(NODE) (TREE_CODE (NODE) == NOP_EXPR \ + && VOID_TYPE_P (TREE_TYPE (NODE)) \ + && integer_zerop (TREE_OPERAND (NODE, 0))) + /* In a SAVE_EXPR node. */ #define SAVE_EXPR_CONTEXT(NODE) TREE_OPERAND_CHECK_CODE (NODE, SAVE_EXPR, 1) #define SAVE_EXPR_RTL(NODE) TREE_RTL_OPERAND_CHECK (NODE, SAVE_EXPR, 2) @@ -967,36 +1056,331 @@ struct tree_vec GTY(()) /* In a LOOP_EXPR node. */ #define LOOP_EXPR_BODY(NODE) TREE_OPERAND_CHECK_CODE (NODE, LOOP_EXPR, 0) -/* In an EXPR_WITH_FILE_LOCATION node. */ -#define EXPR_WFL_EMIT_LINE_NOTE(NODE) \ - (EXPR_WITH_FILE_LOCATION_CHECK (NODE)->common.public_flag) -#define EXPR_WFL_NODE(NODE) \ - TREE_OPERAND_CHECK_CODE (NODE, EXPR_WITH_FILE_LOCATION, 0) -#define EXPR_WFL_FILENAME_NODE(NODE) \ - TREE_OPERAND_CHECK_CODE (NODE, EXPR_WITH_FILE_LOCATION, 1) -#define EXPR_WFL_FILENAME(NODE) \ - IDENTIFIER_POINTER (EXPR_WFL_FILENAME_NODE (NODE)) -/* ??? Java uses this in all expressions. */ -#define EXPR_WFL_LINECOL(NODE) (EXPR_CHECK (NODE)->exp.complexity) -#define EXPR_WFL_LINENO(NODE) (EXPR_WFL_LINECOL (NODE) >> 12) -#define EXPR_WFL_COLNO(NODE) (EXPR_WFL_LINECOL (NODE) & 0xfff) -#define EXPR_WFL_SET_LINECOL(NODE, LINE, COL) \ - (EXPR_WFL_LINECOL(NODE) = ((LINE) << 12) | ((COL) & 0xfff)) +/* The source location of this expression. Non-tree_exp nodes such as + decls and constants can be shared among multiple locations, so + return nothing. */ +#define EXPR_LOCUS(NODE) \ + (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (NODE))) \ + ? (NODE)->exp.locus \ + : (location_t *)NULL) +#define SET_EXPR_LOCUS(NODE, FROM) \ + (EXPR_CHECK (NODE)->exp.locus = (FROM)) +#define EXPR_FILENAME(NODE) \ + (EXPR_CHECK (NODE)->exp.locus->file) +#define EXPR_LINENO(NODE) \ + (EXPR_CHECK (NODE)->exp.locus->line) +#ifdef USE_MAPPED_LOCATION +#define EXPR_LOCATION(NODE) \ + (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (NODE))) \ + ? (NODE)->exp.locus \ + : UNKNOWN_LOCATION) +#define EXPR_HAS_LOCATION(NODE) (EXPR_LOCATION (NODE) != UNKNOWN_LOCATION) +#else +#define EXPR_LOCATION(NODE) (*EXPR_LOCUS (NODE)) +#define EXPR_HAS_LOCATION(NODE) (EXPR_LOCUS (NODE) != NULL) +#endif /* In a TARGET_EXPR node. */ #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0) #define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 1) #define TARGET_EXPR_CLEANUP(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 2) +#define EXIT_EXPR_COND(NODE) TREE_OPERAND (EXIT_EXPR_CHECK (NODE), 0) + +/* SWITCH_EXPR accessors. These give access to the condition, body and + original condition type (before any compiler conversions) + of the switch statement, respectively. */ +#define SWITCH_COND(NODE) TREE_OPERAND ((NODE), 0) +#define SWITCH_BODY(NODE) TREE_OPERAND ((NODE), 1) +#define SWITCH_LABELS(NODE) TREE_OPERAND ((NODE), 2) + +/* CASE_LABEL accessors. These give access to the high and low values + of a case label, respectively. */ +#define CASE_LOW(NODE) TREE_OPERAND ((NODE), 0) +#define CASE_HIGH(NODE) TREE_OPERAND ((NODE), 1) +#define CASE_LABEL(NODE) TREE_OPERAND ((NODE), 2) + +/* The operands of a BIND_EXPR. */ +#define BIND_EXPR_VARS(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 0)) +#define BIND_EXPR_BODY(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 1)) +#define BIND_EXPR_BLOCK(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 2)) + +/* GOTO_EXPR accessor. This gives access to the label associated with + a goto statement. */ +#define GOTO_DESTINATION(NODE) TREE_OPERAND ((NODE), 0) + +/* ASM_STMT accessors. ASM_STRING returns a STRING_CST for the + instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and + ASM_CLOBBERS represent the outputs, inputs, and clobbers for the + statement. */ +#define ASM_STRING(NODE) TREE_OPERAND ((NODE), 0) +#define ASM_OUTPUTS(NODE) TREE_OPERAND ((NODE), 1) +#define ASM_INPUTS(NODE) TREE_OPERAND ((NODE), 2) +#define ASM_CLOBBERS(NODE) TREE_OPERAND ((NODE), 3) +/* Nonzero if we want to create an ASM_INPUT instead of an + ASM_OPERAND with no operands. */ +#define ASM_INPUT_P(NODE) (TREE_STATIC (NODE)) +#define ASM_VOLATILE_P(NODE) (TREE_PUBLIC (NODE)) + +/* COND_EXPR accessors. */ +#define COND_EXPR_COND(NODE) (TREE_OPERAND (COND_EXPR_CHECK (NODE), 0)) +#define COND_EXPR_THEN(NODE) (TREE_OPERAND (COND_EXPR_CHECK (NODE), 1)) +#define COND_EXPR_ELSE(NODE) (TREE_OPERAND (COND_EXPR_CHECK (NODE), 2)) + +/* LABEL_EXPR accessor. This gives access to the label associated with + the given label expression. */ +#define LABEL_EXPR_LABEL(NODE) TREE_OPERAND (LABEL_EXPR_CHECK (NODE), 0) + +/* VDEF_EXPR accessors are specified in tree-flow.h, along with the other + accessors for SSA operands. */ + +/* CATCH_EXPR accessors. */ +#define CATCH_TYPES(NODE) TREE_OPERAND (CATCH_EXPR_CHECK (NODE), 0) +#define CATCH_BODY(NODE) TREE_OPERAND (CATCH_EXPR_CHECK (NODE), 1) + +/* EH_FILTER_EXPR accessors. */ +#define EH_FILTER_TYPES(NODE) TREE_OPERAND (EH_FILTER_EXPR_CHECK (NODE), 0) +#define EH_FILTER_FAILURE(NODE) TREE_OPERAND (EH_FILTER_EXPR_CHECK (NODE), 1) +#define EH_FILTER_MUST_NOT_THROW(NODE) TREE_STATIC (EH_FILTER_EXPR_CHECK (NODE)) + struct tree_exp GTY(()) { struct tree_common common; + location_t *locus; int complexity; + tree block; tree GTY ((special ("tree_exp"), desc ("TREE_CODE ((tree) &%0)"))) operands[1]; }; +/* SSA_NAME accessors. */ + +/* Returns the variable being referenced. Once released, this is the + only field that can be relied upon. */ +#define SSA_NAME_VAR(NODE) SSA_NAME_CHECK (NODE)->ssa_name.var + +/* Returns the statement which defines this reference. Note that + we use the same field when chaining SSA_NAME nodes together on + the SSA_NAME freelist. */ +#define SSA_NAME_DEF_STMT(NODE) SSA_NAME_CHECK (NODE)->common.chain + +/* Returns the SSA version number of this SSA name. Note that in + tree SSA, version numbers are not per variable and may be recycled. */ +#define SSA_NAME_VERSION(NODE) SSA_NAME_CHECK (NODE)->ssa_name.version + +/* Nonzero if this SSA name occurs in an abnormal PHI. SSA_NAMES are + never output, so we can safely use the ASM_WRITTEN_FLAG for this + status bit. */ +#define SSA_NAME_OCCURS_IN_ABNORMAL_PHI(NODE) \ + SSA_NAME_CHECK (NODE)->common.asm_written_flag + +/* Nonzero if this SSA_NAME expression is currently on the freelist of + SSA_NAMES. Using NOTHROW_FLAG seems reasonably safe since throwing + has no meaning for an SSA_NAME. */ +#define SSA_NAME_IN_FREE_LIST(NODE) \ + SSA_NAME_CHECK (NODE)->common.nothrow_flag + +struct tree_ssa_name GTY(()) +{ + struct tree_common common; + + /* _DECL wrapped by this SSA name. */ + tree var; + + /* SSA version number. */ + unsigned int version; +}; + +/* In a PHI_NODE node. */ +#define PHI_RESULT(NODE) PHI_NODE_CHECK (NODE)->phi.result + +/* Nonzero if the PHI node was rewritten by a previous pass through the + SSA renamer. */ +#define PHI_REWRITTEN(NODE) PHI_NODE_CHECK (NODE)->phi.rewritten +#define PHI_NUM_ARGS(NODE) PHI_NODE_CHECK (NODE)->phi.num_args +#define PHI_ARG_CAPACITY(NODE) PHI_NODE_CHECK (NODE)->phi.capacity +#define PHI_ARG_ELT(NODE, I) PHI_NODE_ELT_CHECK (NODE, I) +#define PHI_ARG_EDGE(NODE, I) PHI_NODE_ELT_CHECK (NODE, I).e +#define PHI_ARG_DEF(NODE, I) PHI_NODE_ELT_CHECK (NODE, I).def + +struct edge_def; + +struct phi_arg_d GTY(()) +{ + tree def; + struct edge_def * GTY((skip (""))) e; +}; + +struct tree_phi_node GTY(()) +{ + struct tree_common common; + tree result; + int num_args; + int capacity; + + /* Nonzero if the PHI node was rewritten by a previous pass through the + SSA renamer. */ + int rewritten; + + struct phi_arg_d GTY ((length ("((tree)&%h)->phi.capacity"))) a[1]; +}; + + +struct varray_head_tag; + +struct tree_eref_common GTY(()) +{ + struct tree_common common; + + /* SSAPRE: ID for the EREF. Used only for sorting erefs inside a + block. */ + int id; + + /* SSAPRE: Name for the EREF. Used only for printing.*/ + tree name; + + /* SSAPRE: The statement associated with this expression reference. */ + tree stmt; + + /* SSAPRE: True if expression needs to be saved to a temporary. */ + unsigned int save:1; + + /* SSAPRE: True if expression needs to be reloaded from a temporary. */ + unsigned int reload:1; + + /* SSAPRE: Redundancy class of expression. */ + unsigned int class; + + /* SSAPRE: Processed flag 1. */ + unsigned int processed:1; + + /* SSAPRE: True if expression is injured. */ + unsigned int injured:1; + + /* SSAPRE: Temporary assigned to this reference. */ + tree temp; + +}; + +struct tree_euse_node GTY(()) +{ + struct tree_eref_common common; + + /* SSAPRE: Definition for this use. */ + tree def; + + /* SSAPRE: True if this is an EPHI operand occurrence. */ + unsigned int op_occurrence:1; + + /* SSAPRE: True if expression was inserted as a PHI operand occurrence. */ + unsigned int inserted:1; + + /* SSAPRE: True if expression occurs as a lvalue. */ + unsigned int lval:1; +}; +struct ephi_arg_d GTY(()) +{ + + /* SSAPRE: True if this phi argument is injured. */ + unsigned int injured:1; + + /* SSAPRE: True if there is a real occurrence for this phi argument. */ + unsigned int has_real_use:1; + + /* SSAPRE: True if delayed renaming is required on this phi argument. */ + unsigned int delayed_rename:1; + + /* SSAPRE: Processed 2 flag for this phi argument. */ + unsigned int processed2:1; + + /* SSAPRE: True if this operand stops forward movement. */ + unsigned int stops:1; + + /* SSAPRE: Definition of this phi operand. */ + tree def; + + /* SSAPRE: Phi predecessor for this phi operand. */ + tree pred; + + struct edge_def * GTY((skip (""))) e; +}; +struct tree_ephi_node GTY(()) +{ + struct tree_eref_common common; + + /* SSAPRE: True if PHI is downsafe. */ + unsigned int downsafe:1; + + /* SSAPRE: True if PHI is cant_be_avail. */ + unsigned int cant_be_avail:1; + + /* SSAPRE: True if PHI is dead. */ + unsigned int dead:1; + + /* SSAPRE: True if PHI is pointless or identical to some value. */ + unsigned int identity:1; + + /* SSAPRE: True if replacing occurrence known for ESSA minimization. */ + unsigned int rep_occur_known:1; + + /* SSAPRE: True if PHI is pointless, but is also injured. */ + unsigned int ident_injured:1; + + /* SSAPRE: True if this PHI stops forward movement. */ + unsigned int stops:1; + + /* SSAPRE: If PHI's replacing occurrence is known, this is it. */ + tree identical_to; + + /* SSAPRE: Uses of this ephi. */ + struct varray_head_tag *uses; + + int num_args; + int capacity; + struct ephi_arg_d GTY ((length ("((tree)&%h)->ephi.capacity"))) a[1]; + +}; +/* In both EPHI's and EUSES */ +#define EREF_PROCESSED(NODE) EREF_NODE_CHECK (NODE)->eref.processed +#define EREF_ID(NODE) EREF_NODE_CHECK (NODE)->eref.id +#define EREF_NAME(NODE) EREF_NODE_CHECK (NODE)->eref.name +#define EREF_STMT(NODE) EREF_NODE_CHECK (NODE)->eref.stmt +#define EREF_RELOAD(NODE) EREF_NODE_CHECK (NODE)->eref.reload +#define EREF_SAVE(NODE) EREF_NODE_CHECK (NODE)->eref.save +#define EREF_CLASS(NODE) EREF_NODE_CHECK (NODE)->eref.class +#define EREF_INJURED(NODE) EREF_NODE_CHECK (NODE)->eref.injured +#define EREF_TEMP(NODE) EREF_NODE_CHECK (NODE)->eref.temp + +/* In a EUSE_NODE node. */ +#define EUSE_DEF(NODE) EUSE_NODE_CHECK (NODE)->euse.def +#define EUSE_PHIOP(NODE) EUSE_NODE_CHECK (NODE)->euse.op_occurrence +#define EUSE_INSERTED(NODE) EUSE_NODE_CHECK (NODE)->euse.inserted +#define EUSE_LVAL(NODE) EUSE_NODE_CHECK (NODE)->euse.lval + +/* In a EPHI_NODE node. */ +#define EPHI_NUM_ARGS(NODE) EPHI_NODE_CHECK (NODE)->ephi.num_args +#define EPHI_ARG_CAPACITY(NODE) EPHI_NODE_CHECK (NODE)->ephi.capacity +#define EPHI_ARG_ELT(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I) +#define EPHI_ARG_EDGE(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).e +#define EPHI_ARG_PRED(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).pred +#define EPHI_ARG_DEF(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).def +#define EPHI_ARG_INJURED(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).injured +#define EPHI_ARG_DELAYED_RENAME(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).delayed_rename +#define EPHI_ARG_HAS_REAL_USE(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).has_real_use +#define EPHI_ARG_STOPS(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).stops +#define EPHI_ARG_PROCESSED2(NODE, I) EPHI_NODE_ELT_CHECK (NODE, I).processed2 +#define EPHI_IDENTITY(NODE) EPHI_NODE_CHECK (NODE)->ephi.identity +#define EPHI_IDENT_INJURED(NODE) EPHI_NODE_CHECK (NODE)->ephi.ident_injured + +#define EPHI_REP_OCCUR_KNOWN(NODE) EPHI_NODE_CHECK (NODE)->ephi.rep_occur_known +#define EPHI_IDENTICAL_TO(NODE) EPHI_NODE_CHECK (NODE)->ephi.identical_to +#define EPHI_DOWNSAFE(NODE) EPHI_NODE_CHECK (NODE)->ephi.downsafe +#define EPHI_CANT_BE_AVAIL(NODE) EPHI_NODE_CHECK (NODE)->ephi.cant_be_avail +#define EPHI_DEAD(NODE) EPHI_NODE_CHECK (NODE)->ephi.dead +#define EPHI_USES(NODE) EPHI_NODE_CHECK (NODE)->ephi.uses +#define EPHI_STOPS(NODE) EPHI_NODE_CHECK (NODE)->ephi.stops + /* In a BLOCK node. */ #define BLOCK_VARS(NODE) (BLOCK_CHECK (NODE)->block.vars) #define BLOCK_SUBBLOCKS(NODE) (BLOCK_CHECK (NODE)->block.subblocks) @@ -1198,6 +1582,10 @@ struct tree_block GTY(()) #define TYPE_LANG_FLAG_5(NODE) (TYPE_CHECK (NODE)->type.lang_flag_5) #define TYPE_LANG_FLAG_6(NODE) (TYPE_CHECK (NODE)->type.lang_flag_6) +/* Used to keep track of visited nodes in tree traversals. This is set to + 0 by copy_node and make_node. */ +#define TREE_VISITED(NODE) ((NODE)->common.visited) + /* If set in an ARRAY_TYPE, indicates a string type (for languages that distinguish string from array of char). If set in a SET_TYPE, indicates a bitstring type. */ @@ -1384,6 +1772,16 @@ struct tree_type GTY(()) /* Nonzero if DECL represents a decl. */ #define DECL_P(DECL) (TREE_CODE_CLASS (TREE_CODE (DECL)) == 'd') +/* Nonzero if DECL represents a variable for the SSA passes. */ +#define SSA_VAR_P(DECL) \ + (TREE_CODE (DECL) == VAR_DECL \ + || TREE_CODE (DECL) == PARM_DECL \ + || TREE_CODE (DECL) == RESULT_DECL \ + || (TREE_CODE (DECL) == SSA_NAME \ + && (TREE_CODE (SSA_NAME_VAR (DECL)) == VAR_DECL \ + || TREE_CODE (SSA_NAME_VAR (DECL)) == PARM_DECL \ + || TREE_CODE (SSA_NAME_VAR (DECL)) == RESULT_DECL))) + /* This is the name of the object as written by the user. It is an IDENTIFIER_NODE. */ #define DECL_NAME(NODE) (DECL_CHECK (NODE)->decl.name) @@ -1533,6 +1931,12 @@ struct tree_type GTY(()) this identifies which built-in operation it is. */ #define DECL_FUNCTION_CODE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.u1.f) +/* In a FUNCTION_DECL for which DECL_BUILT_IN does not hold, this is + the approximate number of statements in this function. There is + no need for this number to be exact; it is only used in various + heuristics regarding optimization. */ +#define DECL_NUM_STMTS(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.u1.i) + /* The DECL_VINDEX is used for FUNCTION_DECLS in two different ways. Before the struct containing the FUNCTION_DECL is laid out, DECL_VINDEX may point to a FUNCTION_DECL in a base class which @@ -1647,6 +2051,10 @@ struct tree_type GTY(()) #define DECL_DECLARED_INLINE_P(NODE) \ (FUNCTION_DECL_CHECK (NODE)->decl.declared_inline_flag) +/* In a VAR_DECL, nonzero if the decl is a register variable with + an explicit asm specification. */ +#define DECL_HARD_REGISTER(NODE) (DECL_CHECK (NODE)->decl.inline_flag) + /* Value of the decls's visibility attribute */ #define DECL_VISIBILITY(NODE) (DECL_CHECK (NODE)->decl.visibility) @@ -1774,6 +2182,16 @@ struct tree_type GTY(()) #define DECL_POINTER_ALIAS_SET(NODE) \ (DECL_CHECK (NODE)->decl.pointer_alias_set) +/* Used to store the alias_var for a DECL node. */ +#define DECL_PTA_ALIASVAR(NODE) \ + (DECL_CHECK (NODE)->decl.alias_var) + +/* A numeric unique identifier for a LABEL_DECL. The UID allocation is + dense, unique within any one function, and may be used to index arrays. + If the value is -1, then no UID has been assigned. */ +#define LABEL_DECL_UID(NODE) \ + (LABEL_DECL_CHECK (NODE)->decl.pointer_alias_set) + /* Nonzero if an alias set has been assigned to this declaration. */ #define DECL_POINTER_ALIAS_SET_KNOWN_P(NODE) \ (DECL_POINTER_ALIAS_SET (NODE) != - 1) @@ -1783,6 +2201,15 @@ struct tree_type GTY(()) (! DECL_CONTEXT (EXP) \ || TREE_CODE (DECL_CONTEXT (EXP)) == TRANSLATION_UNIT_DECL) +/* Nonzero for a decl that has been marked as needing a memory slot. + NOTE: Never use this macro directly. It will give you incomplete + information. Most of the time this bit will only be set after alias + analysis in the tree optimizers. It's always better to call + needs_to_live_in_memory instead. To mark memory variables use + mark_call_clobbered. */ +#define DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL(DECL) \ + DECL_CHECK (DECL)->decl.needs_to_live_in_memory + /* Enumerate visibility settings. */ enum symbol_visibility @@ -1794,7 +2221,7 @@ enum symbol_visibility }; struct function; - +union alias_var_def; struct tree_decl GTY(()) { struct tree_common common; @@ -1834,9 +2261,8 @@ struct tree_decl GTY(()) unsigned uninlinable : 1; unsigned thread_local_flag : 1; unsigned declared_inline_flag : 1; + unsigned seen_in_bind_expr : 1; ENUM_BITFIELD(symbol_visibility) visibility : 2; - unsigned unused : 1; - /* one unused bit. */ unsigned lang_flag_0 : 1; unsigned lang_flag_1 : 1; @@ -1847,6 +2273,9 @@ struct tree_decl GTY(()) unsigned lang_flag_6 : 1; unsigned lang_flag_7 : 1; + unsigned needs_to_live_in_memory : 1; + /* 15 unused bits. */ + union tree_decl_u1 { /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is DECL_FUNCTION_CODE. */ @@ -1895,9 +2324,38 @@ struct tree_decl GTY(()) tree vindex; HOST_WIDE_INT pointer_alias_set; + union alias_var_def *GTY ((skip(""))) alias_var; /* Points to a structure whose details depend on the language in use. */ struct lang_decl *lang_specific; }; + + +/* A STATEMENT_LIST chains statements together in GENERIC and GIMPLE. + To reduce overhead, the nodes containing the statements are not trees. + This avoids the overhead of tree_common on all linked list elements. + + Use the interface in tree-iterator.h to access this node. */ + +#define STATEMENT_LIST_HEAD(NODE) \ + (STATEMENT_LIST_CHECK (NODE)->stmt_list.head) +#define STATEMENT_LIST_TAIL(NODE) \ + (STATEMENT_LIST_CHECK (NODE)->stmt_list.tail) + +struct tree_statement_list_node + GTY ((chain_next ("%h.next"), chain_prev ("%h.prev"))) +{ + struct tree_statement_list_node *prev; + struct tree_statement_list_node *next; + tree stmt; +}; + +struct tree_statement_list + GTY(()) +{ + struct tree_common common; + struct tree_statement_list_node *head; + struct tree_statement_list_node *tail; +}; enum tree_node_structure_enum { TS_COMMON, @@ -1912,7 +2370,13 @@ enum tree_node_structure_enum { TS_LIST, TS_VEC, TS_EXP, + TS_SSA_NAME, + TS_PHI_NODE, + TS_EPHI_NODE, + TS_EUSE_NODE, + TS_EREF_NODE, TS_BLOCK, + TS_STATEMENT_LIST, LAST_TS_ENUM }; @@ -1935,8 +2399,14 @@ union tree_node GTY ((ptr_alias (union lang_tree_node), struct tree_list GTY ((tag ("TS_LIST"))) list; struct tree_vec GTY ((tag ("TS_VEC"))) vec; struct tree_exp GTY ((tag ("TS_EXP"))) exp; + struct tree_ssa_name GTY ((tag ("TS_SSA_NAME"))) ssa_name; + struct tree_phi_node GTY ((tag ("TS_PHI_NODE"))) phi; + struct tree_eref_common GTY ((tag ("TS_EREF_NODE"))) eref; + struct tree_ephi_node GTY ((tag ("TS_EPHI_NODE"))) ephi; + struct tree_euse_node GTY ((tag ("TS_EUSE_NODE"))) euse; struct tree_block GTY ((tag ("TS_BLOCK"))) block; - }; + struct tree_statement_list GTY ((tag ("TS_STATEMENT_LIST"))) stmt_list; +}; /* Standard named or nameless data types of the C compiler. */ @@ -2183,6 +2653,24 @@ extern tree copy_list (tree); extern tree make_tree_vec_stat (int MEM_STAT_DECL); #define make_tree_vec(t) make_tree_vec_stat (t MEM_STAT_INFO) +/* Tree nodes for SSA analysis. */ + +extern tree make_phi_node (tree, int); +extern void init_phinodes (void); +extern void fini_phinodes (void); +extern void release_phi_node (tree); +#ifdef GATHER_STATISTICS +extern void phinodes_print_statistics (void); +#endif + +extern void init_ssanames (void); +extern void fini_ssanames (void); +extern tree make_ssa_name (tree, tree); +extern void release_ssa_name (tree); +#ifdef GATHER_STATISTICS +extern void ssanames_print_statistics (void); +#endif + /* Return the (unique) IDENTIFIER_NODE node for a given name. The name is supplied as a char *. */ @@ -2250,7 +2738,9 @@ extern tree build_tree_list_stat (tree, tree MEM_STAT_DECL); extern tree build_decl_stat (enum tree_code, tree, tree MEM_STAT_DECL); #define build_decl(c,t,q) build_decl_stat (c,t,q MEM_STAT_INFO) extern tree build_block (tree, tree, tree, tree, tree); -extern tree build_expr_wfl (tree, const char *, int, int); +extern void annotate_with_file_line (tree, const char *, int); +extern void annotate_with_locus (tree, location_t); +extern tree build_empty_stmt (void); /* Construct various nodes representing data types. */ @@ -2540,7 +3030,7 @@ extern tree convert (tree, tree); extern unsigned int expr_align (tree); extern tree expr_first (tree); extern tree expr_last (tree); -extern int expr_length (tree); +extern tree expr_only (tree); extern tree size_in_bytes (tree); extern HOST_WIDE_INT int_size_in_bytes (tree); extern tree bit_position (tree); @@ -2633,11 +3123,14 @@ extern int fields_length (tree); extern bool initializer_zerop (tree); -/* Given an initializer INIT, return TRUE if INIT is at least 3/4 zeros. - Otherwise return FALSE. */ - +extern void categorize_ctor_elements (tree, HOST_WIDE_INT *, HOST_WIDE_INT *); +extern HOST_WIDE_INT count_type_elements (tree); extern int mostly_zeros_p (tree); +/* add_var_to_bind_expr (bind_expr, var) binds var to bind_expr. */ + +extern void add_var_to_bind_expr (tree, tree); + /* integer_zerop (tree x) is nonzero if X is an integer constant of value 0 */ extern int integer_zerop (tree); @@ -2825,13 +3318,6 @@ extern tree decl_function_context (tree); this _DECL with its context, or zero if none. */ extern tree decl_type_context (tree); -/* Given the FUNCTION_DECL for the current function, - return zero if it is ok for this function to be inline. - Otherwise return a warning message with a single %s - for the function's name. */ - -extern const char *function_cannot_inline_p (tree); - /* Return 1 if EXPR is the real constant zero. */ extern int real_zerop (tree); @@ -2854,6 +3340,11 @@ extern GTY(()) tree current_function_decl; /* Nonzero means a FUNC_BEGIN label was emitted. */ extern GTY(()) tree current_function_func_begin_label; +/* A DECL for the current file-scope context. When using IMA, this heads a + chain of FILE_DECLs; currently only C uses it. */ + +extern GTY(()) tree current_file_decl; + /* Nonzero means all ..._TYPE nodes should be allocated permanently. */ extern int all_types_permanent; @@ -2877,6 +3368,7 @@ extern tree get_callee_fndecl (tree); extern void change_decl_assembler_name (tree, tree); extern int type_num_arguments (tree); extern tree lhd_unsave_expr_now (tree); +extern bool is_essa_node (tree); extern bool associative_tree_code (enum tree_code); extern bool commutative_tree_code (enum tree_code); @@ -2910,6 +3402,9 @@ extern int expand_exit_loop_if_false (struct nesting *,tree); extern int expand_exit_loop_top_cond (struct nesting *, tree); extern int expand_exit_something (void); +extern void expand_stack_alloc (tree, tree); +extern rtx expand_stack_save (void); +extern void expand_stack_restore (tree); extern void expand_return (tree); extern int optimize_tail_recursion (tree, rtx); extern void expand_start_bindings_and_block (int, tree); @@ -2927,7 +3422,7 @@ extern tree last_cleanup_this_contour (void); extern void expand_start_case (int, tree, tree, const char *); extern void expand_end_case_type (tree, tree); #define expand_end_case(cond) expand_end_case_type (cond, NULL) -extern int add_case_node (tree, tree, tree, tree *); +extern int add_case_node (tree, tree, tree, tree *, bool); extern int pushcase (tree, tree (*) (tree, tree), tree, tree *); extern int pushcase_range (tree, tree, tree (*) (tree, tree), tree, tree *); extern void using_eh_for_cleanups (void); @@ -2973,15 +3468,29 @@ extern int div_and_round_double (enum tree_code, int, unsigned HOST_WIDE_INT, HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *); -extern int operand_equal_p (tree, tree, int); +enum operand_equal_flag +{ + OEP_ONLY_CONST = 1, + OEP_PURE_SAME = 2 +}; + +extern int operand_equal_p (tree, tree, unsigned int); + extern tree omit_one_operand (tree, tree, tree); extern tree invert_truthvalue (tree); +extern tree nondestructive_fold_unary_to_constant (enum tree_code, tree, tree); +extern tree nondestructive_fold_binary_to_constant (enum tree_code, tree, tree, tree); +extern tree fold_read_from_constant_string (tree); +extern tree int_const_binop (enum tree_code, tree, tree, int); /* In builtins.c */ extern tree fold_builtin (tree); extern enum built_in_function builtin_mathfn_code (tree); extern tree build_function_call_expr (tree, tree); extern tree mathfn_built_in (tree, enum built_in_function fn); +extern tree strip_float_extensions (tree); +extern tree simplify_builtin (tree, int); +extern tree c_strlen (tree, int); /* In convert.c */ extern tree strip_float_extensions (tree); @@ -3012,6 +3521,9 @@ extern void dump_tree_statistics (void); extern void expand_function_end (void); extern void expand_function_start (tree, int); extern void expand_pending_sizes (tree); +extern void recompute_tree_invarant_for_addr_expr (tree); +extern bool needs_to_live_in_memory (tree); +extern tree make_vector (enum machine_mode, tree, int); extern tree reconstruct_complex_type (tree, tree); extern int real_onep (tree); @@ -3034,7 +3546,7 @@ extern void init_function_start (tree); extern void assign_parms (tree); extern void put_var_into_stack (tree, int); extern void flush_addressof (tree); -extern void uninitialized_vars_warning (tree); +extern void setjmp_vars_warning (tree); extern void setjmp_args_warning (void); extern void mark_all_temps_used (void); extern void init_temp_slots (void); @@ -3123,16 +3635,15 @@ extern bool alloca_call_p (tree); extern tree decl_attributes (tree *, tree, int); /* In integrate.c */ -extern void save_for_inline (tree); extern void set_decl_abstract_flags (tree, int); -extern void output_inline_function (tree); extern void set_decl_origin_self (tree); /* In stor-layout.c */ extern void set_min_and_max_values_for_integral_type (tree, int, bool); extern void fixup_signed_type (tree); extern void internal_reference_types (void); - +extern unsigned int update_alignment_for_field (record_layout_info, tree, + unsigned int); /* varasm.c */ extern void make_decl_rtl (tree, const char *); extern void make_decl_one_only (tree); @@ -3151,6 +3662,8 @@ extern bool parse_output_constraint (const char **, int, int, int, extern bool parse_input_constraint (const char **, int, int, int, int, const char * const *, bool *, bool *); extern void expand_asm_operands (tree, tree, tree, tree, int, location_t); +extern void expand_asm_expr (tree); +extern bool asm_op_is_mem_input (tree, tree); extern tree resolve_asm_operand_names (tree, tree, tree); extern int any_pending_cleanups (void); extern void init_stmt_for_function (void); @@ -3162,9 +3675,13 @@ extern void expand_decl (tree); extern int expand_decl_cleanup (tree, tree); extern int expand_decl_cleanup_eh (tree, tree, int); extern void expand_anon_union_decl (tree, tree, tree); -extern HOST_WIDE_INT all_cases_count (tree, int *); -extern void check_for_full_enumeration_handling (tree); -extern void declare_nonlocal_label (tree); +extern int containing_blocks_have_cleanups_or_stack_level (void); + +/* In gimplify.c. */ +extern tree create_artificial_label (void); +extern void gimplify_function_tree (tree); +extern const char *get_name (tree); +extern tree unshare_expr (tree); /* If KIND=='I', return a suitable global initializer (constructor) name. If KIND=='D', return a suitable global clean-up (destructor) name. */ @@ -3201,22 +3718,30 @@ extern void dwarf2out_return_save (const char *, HOST_WIDE_INT); extern void dwarf2out_return_reg (const char *, unsigned); -/* The type of a function that walks over tree structure. */ +/* The type of a callback function for walking over tree structure. */ typedef tree (*walk_tree_fn) (tree *, int *, void *); +tree walk_tree (tree*, walk_tree_fn, void*, void*); +tree walk_tree_without_duplicates (tree*, walk_tree_fn, void*); /* In tree-dump.c */ /* Different tree dump places. When you add new tree dump places, - extend the DUMP_FILES array in tree-dump.c */ + extend the DUMP_FILES array in tree-dump.c. */ enum tree_dump_index { - TDI_all, /* dump the whole translation unit */ - TDI_class, /* dump class hierarchy */ + TDI_none, /* No dump */ + TDI_tu, /* dump the whole translation unit. */ + TDI_class, /* dump class hierarchy. */ TDI_original, /* dump each function before optimizing it */ - TDI_optimized, /* dump each function after optimizing it */ + TDI_generic, /* dump each function after genericizing it */ + TDI_nested, /* dump each function after unnesting it */ TDI_inlined, /* dump each function after inlining within it. */ + TDI_vcg, /* create a VCG graph file for each + function's flowgraph. */ + TDI_xml, /* dump function call graph. */ + TDI_all, /* enable all the dumps. */ TDI_end }; @@ -3225,6 +3750,16 @@ enum tree_dump_index values, extend the DUMP_OPTIONS array in tree-dump.c */ #define TDF_ADDRESS (1 << 0) /* dump node addresses */ #define TDF_SLIM (1 << 1) /* don't go wild following links */ +#define TDF_RAW (1 << 2) /* don't unparse the function */ +#define TDF_DETAILS (1 << 3) /* show more detailed info about + each pass */ +#define TDF_STATS (1 << 4) /* dump various statistics about + each pass */ +#define TDF_BLOCKS (1 << 5) /* display basic block boundaries */ +#define TDF_VOPS (1 << 6) /* display virtual operands */ +#define TDF_LINENO (1 << 7) /* display statement line numbers */ +#define TDF_UID (1 << 8) /* display decl UIDs */ + typedef struct dump_info *dump_info_p; @@ -3265,6 +3800,8 @@ typedef enum perm_list_kind, temp_list_kind, vec_kind, + phi_kind, + ssa_name_kind, x_kind, lang_decl, lang_type, @@ -3273,5 +3810,10 @@ typedef enum extern int tree_node_counts[]; extern int tree_node_sizes[]; + +/* True if we are in gimple form and the actions of the folders need to + be restricted. False if we are not in gimple form and folding is not + restricted to creating gimple expressions. */ +extern bool in_gimple_form; #endif /* GCC_TREE_H */ diff --git a/gcc/unroll.c b/gcc/unroll.c index 88e442301e6..455d906ffe0 100644 --- a/gcc/unroll.c +++ b/gcc/unroll.c @@ -724,10 +724,6 @@ unroll_loop (struct loop *loop, int insn_count, int strength_reduce_p) map->insn_map = xmalloc (max_insnno * sizeof (rtx)); - /* Set this to zero, to indicate that we are doing loop unrolling, - not function inlining. */ - map->inline_target = 0; - /* The register and constant maps depend on the number of registers present, so the final maps can't be created until after find_splittable_regs is called. However, they are needed for diff --git a/gcc/unwind-sjlj.c b/gcc/unwind-sjlj.c index 505bb86dc5a..08290fc081c 100644 --- a/gcc/unwind-sjlj.c +++ b/gcc/unwind-sjlj.c @@ -270,16 +270,13 @@ uw_init_context (struct _Unwind_Context *context) context->fc = _Unwind_SjLj_GetContext (); } -/* ??? There appear to be bugs in integrate.c wrt __builtin_longjmp and - virtual-stack-vars. An inline version of this segfaults on SPARC. */ -#define uw_install_context(CURRENT, TARGET) \ - do \ - { \ - _Unwind_SjLj_SetContext ((TARGET)->fc); \ - longjmp ((TARGET)->fc->jbuf, 1); \ - } \ - while (0) - +static void __attribute__((noreturn)) +uw_install_context (struct _Unwind_Context *current __attribute__((unused)), + struct _Unwind_Context *target) +{ + _Unwind_SjLj_SetContext (target->fc); + longjmp (target->fc->jbuf, 1); +} static inline _Unwind_Ptr uw_identify_context (struct _Unwind_Context *context) diff --git a/gcc/value-prof.c b/gcc/value-prof.c index 7be8db4f897..66b5c6589bd 100644 --- a/gcc/value-prof.c +++ b/gcc/value-prof.c @@ -34,6 +34,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "optabs.h" #include "regs.h" +static struct value_prof_hooks *value_prof_hooks; + /* In this file value profile based optimizations will be placed (none are here just now, but they are hopefully coming soon). @@ -174,12 +176,14 @@ insn_values_to_profile (rtx insn, } /* Find list of values for that we want to measure histograms. */ -void -find_values_to_profile (unsigned *n_values, struct histogram_value **values) +static void +rtl_find_values_to_profile (unsigned *n_values, struct histogram_value **values) { rtx insn; unsigned i; + life_analysis (get_insns (), NULL, PROP_DEATH_NOTES); + *n_values = 0; *values = NULL; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) @@ -193,7 +197,7 @@ find_values_to_profile (unsigned *n_values, struct histogram_value **values) if (dump_file) fprintf (dump_file, "Interval counter for insn %d, range %d -- %d.\n", - INSN_UID ((*values)[i].insn), + INSN_UID ((rtx)(*values)[i].insn), (*values)[i].hdata.intvl.int_start, ((*values)[i].hdata.intvl.int_start + (*values)[i].hdata.intvl.steps - 1)); @@ -206,16 +210,17 @@ find_values_to_profile (unsigned *n_values, struct histogram_value **values) if (dump_file) fprintf (dump_file, "Pow2 counter for insn %d.\n", - INSN_UID ((*values)[i].insn)); - (*values)[i].n_counters = GET_MODE_BITSIZE ((*values)[i].mode) + - ((*values)[i].hdata.pow2.may_be_other ? 1 : 0); + INSN_UID ((rtx)(*values)[i].insn)); + (*values)[i].n_counters + = GET_MODE_BITSIZE ((*values)[i].mode) + + ((*values)[i].hdata.pow2.may_be_other ? 1 : 0); break; case HIST_TYPE_SINGLE_VALUE: if (dump_file) fprintf (dump_file, "Single value counter for insn %d.\n", - INSN_UID ((*values)[i].insn)); + INSN_UID ((rtx)(*values)[i].insn)); (*values)[i].n_counters = 3; break; @@ -223,7 +228,7 @@ find_values_to_profile (unsigned *n_values, struct histogram_value **values) if (dump_file) fprintf (dump_file, "Constant delta counter for insn %d.\n", - INSN_UID ((*values)[i].insn)); + INSN_UID ((rtx)(*values)[i].insn)); (*values)[i].n_counters = 4; break; @@ -231,6 +236,7 @@ find_values_to_profile (unsigned *n_values, struct histogram_value **values) abort (); } } + allocate_reg_info (max_reg_num (), FALSE, FALSE); } /* Main entry point. Finds REG_VALUE_PROFILE notes from profiler and uses @@ -313,8 +319,8 @@ find_values_to_profile (unsigned *n_values, struct histogram_value **values) making unroller happy. Since this may grow the code significantly, we would have to be very careful here. */ -bool -value_profile_transformations (void) +static bool +rtl_value_profile_transformations (void) { rtx insn, next; int changed = false; @@ -706,3 +712,71 @@ mod_subtract_transform (rtx insn) return true; } + +/* Connection to the outside world. */ +/* Struct for IR-dependent hooks. */ +struct value_prof_hooks { + /* Find list of values for which we want to measure histograms. */ + void (*find_values_to_profile) (unsigned *, struct histogram_value **); + + /* Identify and exploit properties of values that are hard to analyze + statically. See value-prof.c for more detail. */ + bool (*value_profile_transformations) (void); +}; + +/* Hooks for RTL-based versions (the only ones that currently work). */ +static struct value_prof_hooks rtl_value_prof_hooks = +{ + rtl_find_values_to_profile, + rtl_value_profile_transformations +}; + +void +rtl_register_value_prof_hooks (void) +{ + value_prof_hooks = &rtl_value_prof_hooks; + if (ir_type ()) + abort (); +} + +/* Tree-based versions are stubs for now. */ +static void +tree_find_values_to_profile (unsigned *n_values, struct histogram_value **values) +{ + (void)n_values; + (void)values; + abort (); +} + +static bool +tree_value_profile_transformations (void) +{ + abort (); +} + +static struct value_prof_hooks tree_value_prof_hooks = { + tree_find_values_to_profile, + tree_value_profile_transformations +}; + +void +tree_register_value_prof_hooks (void) +{ + value_prof_hooks = &tree_value_prof_hooks; + if (!ir_type ()) + abort (); +} + +/* IR-independent entry points. */ +void +find_values_to_profile (unsigned *n_values, struct histogram_value **values) +{ + (value_prof_hooks->find_values_to_profile) (n_values, values); +} + +bool +value_profile_transformations (void) +{ + return (value_prof_hooks->value_profile_transformations) (); +} + diff --git a/gcc/value-prof.h b/gcc/value-prof.h index afbeb916eb8..16276f2b7de 100644 --- a/gcc/value-prof.h +++ b/gcc/value-prof.h @@ -18,6 +18,9 @@ along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef GCC_VALUE_PROF_H +#define GCC_VALUE_PROF_H + /* Supported histogram types. */ enum hist_type { @@ -35,12 +38,13 @@ enum hist_type ((enum hist_type) ((COUNTER) - GCOV_FIRST_VALUE_COUNTER)) /* The value to measure. */ +/* The void *'s are either rtx or tree, depending on which IR is in use. */ struct histogram_value { - rtx value; /* The value to profile. */ + void * value; /* The value to profile. */ enum machine_mode mode; /* And its mode. */ - rtx seq; /* Insns required to count the profiled value. */ - rtx insn; /* Insn before that to measure. */ + void * seq; /* Insns required to count the profiled value. */ + void * insn; /* Insn before that to measure. */ enum hist_type type; /* Type of information to measure. */ unsigned n_counters; /* Number of required counters. */ union @@ -59,6 +63,48 @@ struct histogram_value } hdata; /* Profiled information specific data. */ }; +/* Hooks registration. */ +extern void rtl_register_value_prof_hooks (void); +extern void tree_register_value_prof_hooks (void); + +/* IR-independent entry points. */ extern void find_values_to_profile (unsigned *, struct histogram_value **); extern void free_profiled_values (unsigned, struct histogram_value *); extern bool value_profile_transformations (void); + +/* External declarations for edge-based profiling. */ +struct profile_hooks { + /* Insert code to increment an edge count. */ + void (*gen_edge_profiler) (int, edge); + + /* Insert code to increment the interval histogram counter. */ + void (*gen_interval_profiler) (struct histogram_value *, unsigned, unsigned); + + /* Insert code to increment the power of two histogram counter. */ + void (*gen_pow2_profiler) (struct histogram_value *, unsigned, unsigned); + + /* Insert code to find the most common value. */ + void (*gen_one_value_profiler) (struct histogram_value *, unsigned, unsigned); + + /* Insert code to find the most common value of a difference between two + evaluations of an expression. */ + void (*gen_const_delta_profiler) (struct histogram_value *, unsigned, + unsigned); + FILE * (*profile_dump_file) (void); +}; + +/* In profile.c. */ +extern void init_branch_prob (void); +extern void branch_prob (void); +extern void end_branch_prob (void); +extern void tree_register_profile_hooks (void); +extern void rtl_register_profile_hooks (void); + +/* In tree-profile.c. */ +extern struct profile_hooks tree_profile_hooks; + +/* In rtl-profile.c. */ +extern struct profile_hooks rtl_profile_hooks; + +#endif /* GCC_VALUE_PROF_H */ + diff --git a/gcc/varasm.c b/gcc/varasm.c index 13f1191a308..4b59129b0f6 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -48,6 +48,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm_p.h" #include "debug.h" #include "target.h" +#include "tree-mudflap.h" #include "cgraph.h" #include "cfglayout.h" @@ -56,10 +57,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA declarations for e.g. AIX 4.x. */ #endif -#ifndef TRAMPOLINE_ALIGNMENT -#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY -#endif - #ifndef ASM_STABS_OP #define ASM_STABS_OP "\t.stabs\t" #endif @@ -782,6 +779,11 @@ make_decl_rtl (tree decl, const char *asmspec) This is necessary, for example, when one machine specific decl attribute overrides another. */ targetm.encode_section_info (decl, DECL_RTL (decl), false); + + /* Make this function static known to the mudflap runtime. */ + if (flag_mudflap && TREE_CODE (decl) == VAR_DECL) + mudflap_enqueue_decl (decl); + return; } @@ -882,6 +884,10 @@ make_decl_rtl (tree decl, const char *asmspec) If the name is changed, the macro ASM_OUTPUT_LABELREF will have to know how to strip this information. */ targetm.encode_section_info (decl, DECL_RTL (decl), true); + + /* Make this function static known to the mudflap runtime. */ + if (flag_mudflap && TREE_CODE (decl) == VAR_DECL) + mudflap_enqueue_decl (decl); } /* Make the rtl for variable VAR be volatile. @@ -1774,6 +1780,8 @@ assemble_static_space (unsigned HOST_WIDE_INT size) This is done at most once per compilation. Returns an RTX for the address of the template. */ +static GTY(()) rtx initial_trampoline; + #ifdef TRAMPOLINE_TEMPLATE rtx assemble_trampoline_template (void) @@ -1783,6 +1791,9 @@ assemble_trampoline_template (void) int align; rtx symbol; + if (initial_trampoline) + return initial_trampoline; + /* By default, put trampoline templates in read-only data section. */ #ifdef TRAMPOLINE_SECTION @@ -1807,7 +1818,10 @@ assemble_trampoline_template (void) symbol = gen_rtx_SYMBOL_REF (Pmode, name); SYMBOL_REF_FLAGS (symbol) = SYMBOL_FLAG_LOCAL; - return symbol; + initial_trampoline = gen_rtx_MEM (BLKmode, symbol); + set_mem_align (initial_trampoline, TRAMPOLINE_ALIGNMENT); + + return initial_trampoline; } #endif @@ -2408,6 +2422,10 @@ build_constant_desc (tree exp) desc = ggc_alloc (sizeof (*desc)); desc->value = copy_constant (exp); + /* Propagate marked-ness to copied constant. */ + if (flag_mudflap && mf_marked_p (exp)) + mf_mark (desc->value); + /* Create a string containing the label name, in LABEL. */ labelno = const_labelno++; ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno); @@ -2553,15 +2571,8 @@ output_constant_def_contents (rtx symbol) /* Output the value of EXP. */ output_constant (exp, size, align); -} - -/* A constant which was deferred in its original location has been - inserted by the RTL inliner into a different function. The - current function's deferred constant count must be incremented. */ -void -notice_rtl_inlining_of_deferred_constant (void) -{ - n_deferred_constants++; + if (flag_mudflap) + mudflap_enqueue_constant (exp); } /* Look up EXP in the table of constant descriptors. Return the rtl @@ -4595,7 +4606,12 @@ categorize_decl_for_section (tree decl, int reloc, int shlib) if (TREE_CODE (decl) == FUNCTION_DECL) return SECCAT_TEXT; else if (TREE_CODE (decl) == STRING_CST) - return SECCAT_RODATA_MERGE_STR; + { + if (flag_mudflap) /* or !flag_merge_constants */ + return SECCAT_RODATA; + else + return SECCAT_RODATA_MERGE_STR; + } else if (TREE_CODE (decl) == VAR_DECL) { if (DECL_INITIAL (decl) == NULL @@ -5020,6 +5036,9 @@ default_file_start (void) which emits a special section directive used to indicate whether or not this object file needs an executable stack. This is primarily a GNU extension to ELF but could be used on other targets. */ + +int trampolines_created; + void file_end_indicate_exec_stack (void) { diff --git a/gcc/varray.c b/gcc/varray.c index 9c70b9f6dad..fc951da56e4 100644 --- a/gcc/varray.c +++ b/gcc/varray.c @@ -99,6 +99,7 @@ static const struct { { sizeof (HOST_WIDE_INT), 1 }, { sizeof (unsigned HOST_WIDE_INT), 1 }, { sizeof (void *), 1 }, + { sizeof (void *), 0 }, { sizeof (char *), 1 }, { sizeof (struct rtx_def *), 1 }, { sizeof (struct rtvec_def *), 1 }, @@ -106,8 +107,10 @@ static const struct { { sizeof (struct bitmap_head_def *), 1 }, { sizeof (struct reg_info_def *), 0 }, { sizeof (struct const_equiv_data), 0 }, - { sizeof (struct basic_block_def *), 0 }, + { sizeof (struct basic_block_def *), 1 }, { sizeof (struct elt_list *), 1 }, + { sizeof (struct edge_def *), 1 }, + { sizeof (tree *), 1 }, }; /* Allocate a virtual array with NUM_ELEMENT elements, each of which is @@ -207,6 +210,26 @@ varray_underflow (varray_type va, const char *file, int line, #endif + +/* Copy varray V2 into varray V1. Both arrays must be the same size + and type. */ + +void +varray_copy (varray_type v1, varray_type v2) +{ + size_t data_size; + + if (v1->type != v2->type) + abort (); + + if (v1->num_elements != v2->num_elements) + abort (); + + data_size = element[v2->type].size * v2->num_elements; + memcpy (v1->data.c, v2->data.c, data_size); + v1->elements_used = v2->elements_used; +} + /* Output per-varray statistics. */ #ifdef GATHER_STATISTICS diff --git a/gcc/varray.h b/gcc/varray.h index 57a3711bb22..371e4e70bcb 100644 --- a/gcc/varray.h +++ b/gcc/varray.h @@ -72,6 +72,7 @@ enum varray_data_enum { VARRAY_DATA_HINT, VARRAY_DATA_UHINT, VARRAY_DATA_GENERIC, + VARRAY_DATA_GENERIC_NOGC, VARRAY_DATA_CPTR, VARRAY_DATA_RTX, VARRAY_DATA_RTVEC, @@ -81,6 +82,8 @@ enum varray_data_enum { VARRAY_DATA_CONST_EQUIV, VARRAY_DATA_BB, VARRAY_DATA_TE, + VARRAY_DATA_EDGE, + VARRAY_DATA_TREE_PTR, NUM_VARRAY_DATA }; @@ -108,6 +111,8 @@ typedef union varray_data_tag GTY (()) { tag ("VARRAY_DATA_UHINT"))) uhint[1]; PTR GTY ((length ("%0.num_elements"), use_param, tag ("VARRAY_DATA_GENERIC"))) generic[1]; + PTR GTY ((length ("%0.num_elements"), skip (""), + tag ("VARRAY_DATA_GENERIC_NOGC"))) generic_nogc[1]; char *GTY ((length ("%0.num_elements"), tag ("VARRAY_DATA_CPTR"))) cptr[1]; rtx GTY ((length ("%0.num_elements"), @@ -126,6 +131,10 @@ typedef union varray_data_tag GTY (()) { tag ("VARRAY_DATA_BB"))) bb[1]; struct elt_list *GTY ((length ("%0.num_elements"), tag ("VARRAY_DATA_TE"))) te[1]; + struct edge_def *GTY ((length ("%0.num_elements"), + tag ("VARRAY_DATA_EDGE"))) e[1]; + tree *GTY ((length ("%0.num_elements"), skip (""), + tag ("VARRAY_DATA_TREE_PTR"))) tp[1]; } varray_data; /* Virtual array of pointers header. */ @@ -177,6 +186,9 @@ extern varray_type varray_init (size_t, enum varray_data_enum, const char *); #define VARRAY_GENERIC_PTR_INIT(va, num, name) \ va = varray_init (num, VARRAY_DATA_GENERIC, name) +#define VARRAY_GENERIC_PTR_NOGC_INIT(va, num, name) \ + va = varray_init (num, VARRAY_DATA_GENERIC_NOGC, name) + #define VARRAY_CHAR_PTR_INIT(va, num, name) \ va = varray_init (num, VARRAY_DATA_CPTR, name) @@ -204,6 +216,12 @@ extern varray_type varray_init (size_t, enum varray_data_enum, const char *); #define VARRAY_ELT_LIST_INIT(va, num, name) \ va = varray_init (num, VARRAY_DATA_TE, name) +#define VARRAY_EDGE_INIT(va, num, name) \ + va = varray_init (num, VARRAY_DATA_EDGE, name) + +#define VARRAY_TREE_PTR_INIT(va, num, name) \ + va = varray_init (num, VARRAY_DATA_TREE_PTR, name) + /* Free up memory allocated by the virtual array, but do not free any of the elements involved. */ #define VARRAY_FREE(vp) \ @@ -222,6 +240,7 @@ extern varray_type varray_grow (varray_type, size_t); #define VARRAY_CLEAR(VA) varray_clear(VA) extern void varray_clear (varray_type); +extern void varray_copy (varray_type v1, varray_type v2); extern void dump_varray_statistics (void); @@ -274,6 +293,7 @@ extern void varray_underflow (varray_type, const char *, int, const char *) #define VARRAY_WIDE_INT(VA, N) VARRAY_CHECK (VA, N, hint) #define VARRAY_UWIDE_INT(VA, N) VARRAY_CHECK (VA, N, uhint) #define VARRAY_GENERIC_PTR(VA,N) VARRAY_CHECK (VA, N, generic) +#define VARRAY_GENERIC_PTR_NOGC(VA,N) VARRAY_CHECK (VA, N, generic_nogc) #define VARRAY_CHAR_PTR(VA,N) VARRAY_CHECK (VA, N, cptr) #define VARRAY_RTX(VA, N) VARRAY_CHECK (VA, N, rtx) #define VARRAY_RTVEC(VA, N) VARRAY_CHECK (VA, N, rtvec) @@ -283,6 +303,8 @@ extern void varray_underflow (varray_type, const char *, int, const char *) #define VARRAY_CONST_EQUIV(VA, N) VARRAY_CHECK (VA, N, const_equiv) #define VARRAY_BB(VA, N) VARRAY_CHECK (VA, N, bb) #define VARRAY_ELT_LIST(VA, N) VARRAY_CHECK (VA, N, te) +#define VARRAY_EDGE(VA, N) VARRAY_CHECK (VA, N, e) +#define VARRAY_TREE_PTR(VA, N) VARRAY_CHECK (VA, N, tp) /* Push a new element on the end of VA, extending it if necessary. */ #define VARRAY_PUSH_CHAR(VA, X) VARRAY_PUSH (VA, c, X) @@ -296,6 +318,7 @@ extern void varray_underflow (varray_type, const char *, int, const char *) #define VARRAY_PUSH_WIDE_INT(VA, X) VARRAY_PUSH (VA, hint, X) #define VARRAY_PUSH_UWIDE_INT(VA, X) VARRAY_PUSH (VA, uhint, X) #define VARRAY_PUSH_GENERIC_PTR(VA, X) VARRAY_PUSH (VA, generic, X) +#define VARRAY_PUSH_GENERIC_PTR_NOGC(VA, X) VARRAY_PUSH (VA, generic_nogc, X) #define VARRAY_PUSH_CHAR_PTR(VA, X) VARRAY_PUSH (VA, cptr, X) #define VARRAY_PUSH_RTX(VA, X) VARRAY_PUSH (VA, rtx, X) #define VARRAY_PUSH_RTVEC(VA, X) VARRAY_PUSH (VA, rtvec, X) @@ -304,6 +327,8 @@ extern void varray_underflow (varray_type, const char *, int, const char *) #define VARRAY_PUSH_REG(VA, X) VARRAY_PUSH (VA, reg, X) #define VARRAY_PUSH_CONST_EQUIV(VA, X) VARRAY_PUSH (VA, const_equiv, X) #define VARRAY_PUSH_BB(VA, X) VARRAY_PUSH (VA, bb, X) +#define VARRAY_PUSH_EDGE(VA, X) VARRAY_PUSH (VA, e, X) +#define VARRAY_PUSH_TREE_PTR(VA, X) VARRAY_PUSH (VA, tp, X) /* Return the last element of VA. */ #define VARRAY_TOP(VA, T) VARRAY_CHECK(VA, (VA)->elements_used - 1, T) @@ -319,6 +344,7 @@ extern void varray_underflow (varray_type, const char *, int, const char *) #define VARRAY_TOP_WIDE_INT(VA) VARRAY_TOP (VA, hint) #define VARRAY_TOP_UWIDE_INT(VA) VARRAY_TOP (VA, uhint) #define VARRAY_TOP_GENERIC_PTR(VA) VARRAY_TOP (VA, generic) +#define VARRAY_TOP_GENERIC_PTR_NOGC(VA) VARRAY_TOP (VA, generic_nogc) #define VARRAY_TOP_CHAR_PTR(VA) VARRAY_TOP (VA, cptr) #define VARRAY_TOP_RTX(VA) VARRAY_TOP (VA, rtx) #define VARRAY_TOP_RTVEC(VA) VARRAY_TOP (VA, rtvec) @@ -327,5 +353,7 @@ extern void varray_underflow (varray_type, const char *, int, const char *) #define VARRAY_TOP_REG(VA) VARRAY_TOP (VA, reg) #define VARRAY_TOP_CONST_EQUIV(VA) VARRAY_TOP (VA, const_equiv) #define VARRAY_TOP_BB(VA) VARRAY_TOP (VA, bb) +#define VARRAY_TOP_EDGE(VA) VARRAY_TOP (VA, e) +#define VARRAY_TOP_TREE_PTR(VA) VARRAY_TOP (VA, tp) #endif /* ! GCC_VARRAY_H */ diff --git a/include/ChangeLog b/include/ChangeLog index 732b81aa2e9..a4df91ab323 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -8,9 +8,9 @@ * hashtab.h (struct htab): Add size_prime_index. 2004-04-13 Jeff Law - - * hashtab.h (htab_remove_elt_with_hash): Prototype new function. - + + * hashtab.h (htab_remove_elt_with_hash): Prototype new function. + 2004-03-30 Zack Weinberg * hashtab.h, splay-tree.h: Use new shorter form of GTY markers. diff --git a/libbanshee/AUTHORS b/libbanshee/AUTHORS new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libbanshee/COPYING b/libbanshee/COPYING new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libbanshee/COPYRIGHT b/libbanshee/COPYRIGHT new file mode 100644 index 00000000000..af706e1ead2 --- /dev/null +++ b/libbanshee/COPYRIGHT @@ -0,0 +1,26 @@ +Copyright (c) 2000-2001 + The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/libbanshee/ChangeLog b/libbanshee/ChangeLog new file mode 100644 index 00000000000..8c0e6be8c3f --- /dev/null +++ b/libbanshee/ChangeLog @@ -0,0 +1,120 @@ +2004-03-26 Andreas Jaeger + + * configure.in: Remove GCC_NO_EXECUTABLES. + * configure: Regenerated. + +2004-03-07 Daniel Berlin + + * engine/Makefile.am (AM_CFLAGS): Add -I$(top_srcddir)/../include, so we + can get ansidecl.h and friends. + * engine/array.c (array_extend): Fix unsigned/signed comparison. + * engine/banshee.h (struct gen_e): Just make void * when empty, instead + of empty struct. + * engine/compiler.h: Don't ever define HAVE_VARIADIC_MACROS, -pedantic + whines about them even when we know we can use them. + * engine/dot.c: constify our char *'s everywhere. + (declare_node): Cast &result to char * before casting to hash_data *. + * engine/dot.h: constify our char *'s everywhere. + * engine/flow-var.c: Ditto. + * engine/flow-var.h: Ditto. + * engine/flowrow-sort.c: Include ansidecl.h. + (get_contour): Mark unused parameter. + (update_upper_bound): Make comment /* instead of //. + (field_eq): Staticify. + * engine/hash.c (string_hash): Staticify. + (string_eq): Ditto. + (entry_cmp): Ditto. + * engine/hash.h: Move comments around. + (hash_table_apply): Add prototype. + * engine/hashset.c (INIT_TABLE_SIZE): Remove extra semicolon. + (EMPTY_KEY): Ditto. + * engine/jcollection.c (jcoll_create_chain): // -> /* comment. + (jcoll_accum): Staticify. + * engine/list.c (sort_linked_list): Staticify. + (compare): Use comparator_fn as last argument, not void *. + * engine/list.h: Declare the functions even for opaque lists. + (list_clear macro): don't return value. + * engine/setif-sort.c: Replaced with new version from banshee cvs. + * engine/setif-var.c: constify our char *'s. + * engine/setif-var.h: Ditto. + * engine/setst-var.c: Ditto. + * engine/setst-var.h: Ditto. + * engine/stamp.c (stamp_string): Use long, not int. + Cast through char *. + * engine/stamp.h (stamp): Long, not int. + * engine/term-sort.c (term_print_stats): Mark argument unused. + include ansidecl.h. + * engine/term-var.c: constify the char *'s. + * engine/term-var.h: Ditto. + * engine/ufind.h (union find update macro): Don't return uf_update's value + (which is void anyway). + * engine/util.c (ptr_hash): Return long, not int. + * engine/util.h (ptr_hash): Ditto. + +2004-02-29 Andreas Jaeger + + * configure.in: Set ac_libbanshee_warn_cflags for GCC. + * configure: Regenerated. + + * libcompat/Makefile.am (AM_CFLAGS): Add + ac_libbanshee_warn_cflags. + * engine/Makefile.am (AM_CFLAGS): Likewise. + * points-to/Makefile.am (AM_CFLAGS): Likewise. + + * libcompat/Makefile.in: Regenerated. + * engine/Makefile.in: Regenerated. + * points-to/Makefile.in: Regenerated. + * Makefile.in: Regenerated. + + * libcompat/radix-tree.c: Include for calloc. + +2004-02-03 Daniel Berlin + + Fix PR other/12220 + * engine/Makefile.am: Remove -fno-strict-aliasing. + * libcompat/Makefile.am: Ditto. + * points-to/Makefile.am: Ditto. + * configure: Regenerated. + * config.h.in: Ditto. + * Makefile.in: Ditto. + * engine/Makefile.am: Ditto. + * libcompat/Makefile.am: Ditto. + * points-to/Makefile.am: Ditto. + +2003-07-01 Daniel Berlin + + * acinclude.m4: New, copy the bool tests from gcc. + + * configure.in: Use the new bool tests. + + * Regenerate configure. + + * engine/bool.h: Rewrite to use the part of gcc's system.h that does + bool type handling. + +2002-12-26 Daniel Berlin + + * Makefile.am: Use the same flag passing hack all other subdirs use. + + * */Makefile.am: Use -fno-strict-aliasing till i get rid of the + type-punning. + + * Regenerate configure and Makefiles. + + * engine/setst-*.c: Remove nested functions. + +2002-11-28 Diego Novillo + + * aclocal.m4: Don't call aclocal and automake with a + version number suffix. + * Makefile.in, config.h.in, configure, + engine/Makefile.in, libcompat/Makefile.in, + points-to/Makefile.in: Regenerate. + +2002-11-24 Daniel Berlin + + * points-to/andersen_terms.c: Fix multi-line string literals + +2002-10-31 Daniel Berlin + + * Autoconf'ed, automak'ed, de-nested functified, etc. diff --git a/libbanshee/INSTALL b/libbanshee/INSTALL new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libbanshee/Makefile.am b/libbanshee/Makefile.am new file mode 100644 index 00000000000..9b9d70b0842 --- /dev/null +++ b/libbanshee/Makefile.am @@ -0,0 +1,41 @@ +SUBDIRS = engine points-to libcompat +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "EXPECT=$(EXPECT)" \ + "RUNTEST=$(RUNTEST)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "prefix=$(prefix)" \ + "tooldir=$(tooldir)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "CC=$(CC)" \ + "CXX=$(CXX)" \ + "LD=$(LD)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "NM=$(NM)" \ + "PICFLAG=$(PICFLAG)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" diff --git a/libbanshee/Makefile.in b/libbanshee/Makefile.in new file mode 100644 index 00000000000..ac898541dcd --- /dev/null +++ b/libbanshee/Makefile.in @@ -0,0 +1,554 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_libbanshee_warn_cflags = @ac_libbanshee_warn_cflags@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +SUBDIRS = engine points-to libcompat +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "EXPECT=$(EXPECT)" \ + "RUNTEST=$(RUNTEST)" \ + "RUNTESTFLAGS=$(RUNTESTFLAGS)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "prefix=$(prefix)" \ + "tooldir=$(tooldir)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "CC=$(CC)" \ + "CXX=$(CXX)" \ + "LD=$(LD)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "NM=$(NM)" \ + "PICFLAG=$(PICFLAG)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" + +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = + +RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ + ps-recursive install-info-recursive uninstall-info-recursive \ + all-recursive install-data-recursive install-exec-recursive \ + installdirs-recursive install-recursive uninstall-recursive \ + check-recursive installcheck-recursive +DIST_COMMON = README ../install-sh ../missing ../mkinstalldirs AUTHORS \ + COPYING ChangeLog INSTALL Makefile.am Makefile.in NEWS \ + acinclude.m4 aclocal.m4 config.h.in configure configure.in +DIST_SUBDIRS = $(SUBDIRS) +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: + +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) + +$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4 + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h + +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOHEADER) + touch $(srcdir)/config.h.in + +distclean-hdr: + -rm -f config.h stamp-h1 +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if (etags --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + else \ + include_option=--include; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = . +distdir = $(PACKAGE)-$(VERSION) + +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } + +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkinstalldirs) $(distdir)/.. + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist dist-all: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + $(am__remove_distdir) + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && $(mkinstalldirs) "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ + && rm -f $(distdir).tar.gz \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @echo "$(distdir).tar.gz is ready for distribution" | \ + sed 'h;s/./=/g;p;x;p;x' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) +distclean-am: clean-am distclean-generic distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ + clean-generic clean-recursive ctags ctags-recursive dist \ + dist-all dist-gzip distcheck distclean distclean-generic \ + distclean-hdr distclean-recursive distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am dvi-recursive info \ + info-am info-recursive install install-am install-data \ + install-data-am install-data-recursive install-exec \ + install-exec-am install-exec-recursive install-info \ + install-info-am install-info-recursive install-man \ + install-recursive install-strip installcheck installcheck-am \ + installdirs installdirs-am installdirs-recursive \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-recursive pdf pdf-am pdf-recursive ps ps-am \ + ps-recursive tags tags-recursive uninstall uninstall-am \ + uninstall-info-am uninstall-info-recursive uninstall-recursive + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libbanshee/NEWS b/libbanshee/NEWS new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libbanshee/README b/libbanshee/README new file mode 100644 index 00000000000..f5e2198957b --- /dev/null +++ b/libbanshee/README @@ -0,0 +1,11 @@ +This is banshee, a toolkit for constructing constraint-based program analyses. +See the user manual in docs/banshee.ps for a complete description of banshee. + +This is a beta release of banshee. Although banshee has been designed to solve +many kinds of constraints, it has only been extensively tested on +Andersen's-style points-to analysis. + +banshee is distributed under the BSD license. See the COPYRIGHT file for more +details. + +Send bug reports to jkodumal@cs.berkeley.edu. \ No newline at end of file diff --git a/libbanshee/acinclude.m4 b/libbanshee/acinclude.m4 new file mode 100644 index 00000000000..8a3afa34ecb --- /dev/null +++ b/libbanshee/acinclude.m4 @@ -0,0 +1,27 @@ +sinclude(../config/accross.m4) + +dnl See if stdbool.h properly defines bool and true/false. +AC_DEFUN(gcc_AC_HEADER_STDBOOL, +[AC_CACHE_CHECK([for working stdbool.h], + ac_cv_header_stdbool_h, +[AC_TRY_COMPILE([#include ], +[bool foo = false;], +ac_cv_header_stdbool_h=yes, ac_cv_header_stdbool_h=no)]) +if test $ac_cv_header_stdbool_h = yes; then + AC_DEFINE(HAVE_STDBOOL_H, 1, + [Define if you have a working header file.]) +fi +]) + +dnl Check whether _Bool is built-in. +AC_DEFUN(gcc_AC_C__BOOL, +[AC_CACHE_CHECK(for built-in _Bool, gcc_cv_c__bool, +[AC_TRY_COMPILE(, +[_Bool foo;], +gcc_cv_c__bool=yes, gcc_cv_c__bool=no) +]) +if test $gcc_cv_c__bool = yes; then + AC_DEFINE(HAVE__BOOL, 1, [Define if the \`_Bool' type is built-in.]) +fi +]) + diff --git a/libbanshee/aclocal.m4 b/libbanshee/aclocal.m4 new file mode 100644 index 00000000000..d548adaaaa3 --- /dev/null +++ b/libbanshee/aclocal.m4 @@ -0,0 +1,928 @@ +# generated automatically by aclocal 1.7.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +sinclude(../config/accross.m4) + +dnl See if stdbool.h properly defines bool and true/false. +AC_DEFUN(gcc_AC_HEADER_STDBOOL, +[AC_CACHE_CHECK([for working stdbool.h], + ac_cv_header_stdbool_h, +[AC_TRY_COMPILE([#include ], +[bool foo = false;], +ac_cv_header_stdbool_h=yes, ac_cv_header_stdbool_h=no)]) +if test $ac_cv_header_stdbool_h = yes; then + AC_DEFINE(HAVE_STDBOOL_H, 1, + [Define if you have a working header file.]) +fi +]) + +dnl Check whether _Bool is built-in. +AC_DEFUN(gcc_AC_C__BOOL, +[AC_CACHE_CHECK(for built-in _Bool, gcc_cv_c__bool, +[AC_TRY_COMPILE(, +[_Bool foo;], +gcc_cv_c__bool=yes, gcc_cv_c__bool=no) +]) +if test $gcc_cv_c__bool = yes; then + AC_DEFINE(HAVE__BOOL, 1, [Define if the \`_Bool' type is built-in.]) +fi +]) + + +# Do all the work for Automake. -*- Autoconf -*- + +# This macro actually does too much some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 10 + +AC_PREREQ([2.54]) + +# Autoconf 2.50 wants to disallow AM_ names. We explicitly allow +# the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl + AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_MISSING_PROG(AMTAR, tar) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl + +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION],[am__api_version="1.7"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.7.6])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright 2001, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# +# Check to make sure that the build environment is sane. +# + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# -*- Autoconf -*- + + +# Copyright 1997, 1999, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# AM_AUX_DIR_EXPAND + +# Copyright 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +# Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50]) + +AC_DEFUN([AM_AUX_DIR_EXPAND], [ +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. + +# Copyright 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# AM_PROG_INSTALL_STRIP + +# Copyright 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# -*- Autoconf -*- +# Copyright (C) 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 1 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# serial 5 -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + : > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # (even with -Werror). So we grep stderr for any message + # that says an option was ignored. + if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +#serial 2 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright 1997, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 5 + +AC_PREREQ(2.52) + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]) +fi])]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- + +# Copyright 1996, 1997, 2000, 2001 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_PREREQ([2.52]) + +# serial 6 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# Copyright 1996, 1998, 2000, 2001, 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +AC_DEFUN([AM_MAINTAINER_MODE], +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + diff --git a/libbanshee/config.h.in b/libbanshee/config.h.in new file mode 100644 index 00000000000..7ef529c3daf --- /dev/null +++ b/libbanshee/config.h.in @@ -0,0 +1,110 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `dup2' function. */ +#undef HAVE_DUP2 + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `floor' function. */ +#undef HAVE_FLOOR + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define if you have a working header file. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define if the \`_Bool' type is built-in. */ +#undef HAVE__BOOL + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ +#undef inline + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned' if does not define. */ +#undef size_t diff --git a/libbanshee/configure b/libbanshee/configure new file mode 100755 index 00000000000..11f4436b348 --- /dev/null +++ b/libbanshee/configure @@ -0,0 +1,5967 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.57 for engine/flowrow-sort.c 0.9. +# +# Report bugs to . +# +# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='engine/flowrow-sort.c' +PACKAGE_TARNAME='engine-flowrow-sort-c' +PACKAGE_VERSION='0.9' +PACKAGE_STRING='engine/flowrow-sort.c 0.9' +PACKAGE_BUGREPORT='dberlin@dberlin.org' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM AWK SET_MAKE am__leading_dot CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE RANLIB ac_ct_RANLIB ac_libbanshee_warn_cflags MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CPP EGREP LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures engine/flowrow-sort.c 0.9 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of engine/flowrow-sort.c 0.9:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking Speeds up one-time builds + --enable-dependency-tracking Do not reject slow dependency extractors + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd $ac_popdir + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +engine/flowrow-sort.c configure 0.9 +generated by GNU Autoconf 2.57 + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 +Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by engine/flowrow-sort.c $as_me 0.9, which was +generated by GNU Autoconf 2.57. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core core.* *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + +am__api_version="1.7" +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + + # test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=libbanshee + VERSION=0.9 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. + + + + ac_config_headers="$ac_config_headers config.h" + + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output" >&5 +echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + ''\ + '#include ' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + : > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # (even with -Werror). So we grep stderr for any message + # that says an option was ignored. + if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +# Checks for libraries. +# FIXME: Replace `main' with a function in `-llambda': +#AC_CHECK_LIB([lambda], [main]) +# FIXME: Replace `main' with a function in `-lm': +#AC_CHECK_LIB([m], [main]) + + +if test x$GCC = xyes; then + ac_libbanshee_warn_cflags='-W -Wall -pedantic -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes' +fi + + +echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi; + echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 +echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6 + + +if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + +# Checks for header files. + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + +for ac_header in fcntl.h limits.h stddef.h stdlib.h string.h sys/param.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + no:yes ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for working stdbool.h" >&5 +echo $ECHO_N "checking for working stdbool.h... $ECHO_C" >&6 +if test "${ac_cv_header_stdbool_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +bool foo = false; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdbool_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdbool_h=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdbool_h" >&5 +echo "${ECHO_T}$ac_cv_header_stdbool_h" >&6 +if test $ac_cv_header_stdbool_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STDBOOL_H 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for built-in _Bool" >&5 +echo $ECHO_N "checking for built-in _Bool... $ECHO_C" >&6 +if test "${gcc_cv_c__bool+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +_Bool foo; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + gcc_cv_c__bool=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +gcc_cv_c__bool=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $gcc_cv_c__bool" >&5 +echo "${ECHO_T}$gcc_cv_c__bool" >&6 +if test $gcc_cv_c__bool = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE__BOOL 1 +_ACEOF + +fi + +# Checks for typedefs, structures, and compiler characteristics. +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for inline" >&5 +echo $ECHO_N "checking for inline... $ECHO_C" >&6 +if test "${ac_cv_c_inline+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_inline=$ac_kw; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +echo "${ECHO_T}$ac_cv_c_inline" >&6 +case $ac_cv_c_inline in + inline | yes) ;; + no) +cat >>confdefs.h <<\_ACEOF +#define inline +_ACEOF + ;; + *) cat >>confdefs.h <<_ACEOF +#define inline $ac_cv_c_inline +_ACEOF + ;; +esac + +echo "$as_me:$LINENO: checking for pid_t" >&5 +echo $ECHO_N "checking for pid_t... $ECHO_C" >&6 +if test "${ac_cv_type_pid_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((pid_t *) 0) + return 0; +if (sizeof (pid_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_pid_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_pid_t=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 +echo "${ECHO_T}$ac_cv_type_pid_t" >&6 +if test $ac_cv_type_pid_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned +_ACEOF + +fi + + +# Checks for library functions. +echo "$as_me:$LINENO: checking for working memcmp" >&5 +echo $ECHO_N "checking for working memcmp... $ECHO_C" >&6 +if test "${ac_cv_func_memcmp_working+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_working=no +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + /* Some versions of memcmp are not 8-bit clean. */ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) + exit (1); + + /* The Next x86 OpenStep bug shows up only when comparing 16 bytes + or more and with at least one buffer not starting on a 4-byte boundary. + William Lewis provided this test program. */ + { + char foo[21]; + char bar[21]; + int i; + for (i = 0; i < 4; i++) + { + char *a = foo + i; + char *b = bar + i; + strcpy (a, "--------01111111"); + strcpy (b, "--------10000000"); + if (memcmp (a, b, 16) >= 0) + exit (1); + } + exit (0); + } + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_memcmp_working=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_memcmp_working=no +fi +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_memcmp_working" >&5 +echo "${ECHO_T}$ac_cv_func_memcmp_working" >&6 +test $ac_cv_func_memcmp_working = no && LIBOBJS="$LIBOBJS memcmp.$ac_objext" + + + +for ac_header in stdlib.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc in + yes:no ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; + no:yes ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_func in getpagesize +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +echo "$as_me:$LINENO: checking for working mmap" >&5 +echo $ECHO_N "checking for working mmap... $ECHO_C" >&6 +if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap_fixed_mapped=no +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +/* malloc might have been renamed as rpl_malloc. */ +#undef malloc + +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the file system buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propagated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ + +#include +#include + +#if !STDC_HEADERS && !HAVE_STDLIB_H +char *malloc (); +#endif + +/* This mess was copied from the GNU getpagesize.h. */ +#if !HAVE_GETPAGESIZE +/* Assume that all systems that can run configure have sys/param.h. */ +# if !HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# if HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +int +main () +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize (); + + /* First, make a file with some known garbage in it. */ + data = (char *) malloc (pagesize); + if (!data) + exit (1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand (); + umask (0); + fd = creat ("conftest.mmap", 0600); + if (fd < 0) + exit (1); + if (write (fd, data, pagesize) != pagesize) + exit (1); + close (fd); + + /* Next, try to mmap the file at a fixed address which already has + something else allocated at it. If we can, also make sure that + we see the same garbage. */ + fd = open ("conftest.mmap", O_RDWR); + if (fd < 0) + exit (1); + data2 = (char *) malloc (2 * pagesize); + if (!data2) + exit (1); + data2 += (pagesize - ((int) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit (1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit (1); + + /* Finally, make sure that changes to the mapped area do not + percolate back to the file as seen by read(). (This is a bug on + some variants of i386 svr4.0.) */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = (char *) malloc (pagesize); + if (!data3) + exit (1); + if (read (fd, data3, pagesize) != pagesize) + exit (1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit (1); + close (fd); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_mmap_fixed_mapped=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_mmap_fixed_mapped=no +fi +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mmap_fixed_mapped" >&5 +echo "${ECHO_T}$ac_cv_func_mmap_fixed_mapped" >&6 +if test $ac_cv_func_mmap_fixed_mapped = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MMAP 1 +_ACEOF + +fi +rm -f conftest.mmap + + +for ac_func in vprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +echo "$as_me:$LINENO: checking for _doprnt" >&5 +echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6 +if test "${ac_cv_func__doprnt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +char (*f) () = _doprnt; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != _doprnt; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func__doprnt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func__doprnt=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 +echo "${ECHO_T}$ac_cv_func__doprnt" >&6 +if test $ac_cv_func__doprnt = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DOPRNT 1 +_ACEOF + +fi + +fi +done + + + + + + + + +for ac_func in atexit dup2 floor getpagesize memset munmap +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ +#ifdef __STDC__ +# include +#else +# include +#endif +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + ac_config_files="$ac_config_files Makefile engine/Makefile libcompat/Makefile points-to/Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi + +# Support unset when possible. +if (FOO=FOO; unset FOO) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by engine/flowrow-sort.c $as_me 0.9, which was +generated by GNU Autoconf 2.57. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +engine/flowrow-sort.c config.status 0.9 +configured by $0, generated by GNU Autoconf 2.57, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "engine/Makefile" ) CONFIG_FILES="$CONFIG_FILES engine/Makefile" ;; + "libcompat/Makefile" ) CONFIG_FILES="$CONFIG_FILES libcompat/Makefile" ;; + "points-to/Makefile" ) CONFIG_FILES="$CONFIG_FILES points-to/Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CYGPATH_W@,$CYGPATH_W,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@AMTAR@,$AMTAR,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t +s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@ac_libbanshee_warn_cflags@,$ac_libbanshee_warn_cflags,;t t +s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t +s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t +s,@MAINT@,$MAINT,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo $f;; + *) # Relative + if test -f "$f"; then + # Build tree + echo $f + elif test -f "$srcdir/$f"; then + # Source tree + echo $srcdir/$f + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null || +$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X$ac_file : 'X\(//\)[^/]' \| \ + X$ac_file : 'X\(//\)$' \| \ + X$ac_file : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X$ac_file | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'`/stamp-h$_am_stamp_count +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac +# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be +# absolute. +ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` +ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` +ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/libbanshee/configure.in b/libbanshee/configure.in new file mode 100644 index 00000000000..a44e7000a0c --- /dev/null +++ b/libbanshee/configure.in @@ -0,0 +1,44 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT(engine/flowrow-sort.c, 0.9, dberlin@dberlin.org) +AM_INIT_AUTOMAKE(libbanshee, 0.9) +AM_CONFIG_HEADER(config.h) + +# Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_RANLIB +# Checks for libraries. +# FIXME: Replace `main' with a function in `-llambda': +#AC_CHECK_LIB([lambda], [main]) +# FIXME: Replace `main' with a function in `-lm': +#AC_CHECK_LIB([m], [main]) + + +if test x$GCC = xyes; then + ac_libbanshee_warn_cflags='-W -Wall -pedantic -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes' +fi +AC_SUBST(ac_libbanshee_warn_cflags) + +AM_MAINTAINER_MODE +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h limits.h stddef.h stdlib.h string.h sys/param.h unistd.h]) + +gcc_AC_HEADER_STDBOOL +gcc_AC_C__BOOL +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_PID_T +AC_TYPE_SIZE_T + +# Checks for library functions. +AC_FUNC_MEMCMP +AC_FUNC_MMAP +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([atexit dup2 floor getpagesize memset munmap]) + +AC_OUTPUT([Makefile + engine/Makefile + libcompat/Makefile + points-to/Makefile]) diff --git a/libbanshee/engine/ChangeLog b/libbanshee/engine/ChangeLog new file mode 100644 index 00000000000..5309328c6fa --- /dev/null +++ b/libbanshee/engine/ChangeLog @@ -0,0 +1,14 @@ +2003-07-01 Daniel Berlin + + * bool.h: Can't include gcc's system.h and bool.h at the same time. + +2003-06-25 Daniel Berlin + + * compiler.h: Fix the grouping of the #if + +2003-02-02 Daniel Berlin + + * compiler.h: Only define HAVE_VARIADIC_MACROS if IN_GCC is not + defined. + * util.h: Add prototypes for min and max. + diff --git a/libbanshee/engine/Makefile.am b/libbanshee/engine/Makefile.am new file mode 100644 index 00000000000..d3a8ba6d805 --- /dev/null +++ b/libbanshee/engine/Makefile.am @@ -0,0 +1,6 @@ +AM_CFLAGS = -I$(srcdir)/../libcompat -I$(top_srcdir)/../include -I$(srcdir)/../include -I. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@ +noinst_LIBRARIES = libbansheeengine.a +libbansheeengine_a_SOURCES = array.c bounds.c hash.c hashset.c list.c stamp.c \ +ufind.c util.c setif-sort.c termhash.c setif-var.c flow-var.c flowrow-sort.c \ +setst-var.c jcollection.c banshee.c buffer.c setst-sort.c term-var.c \ +term-sort.c dot.c diff --git a/libbanshee/engine/Makefile.in b/libbanshee/engine/Makefile.in new file mode 100644 index 00000000000..ddc83d51db3 --- /dev/null +++ b/libbanshee/engine/Makefile.in @@ -0,0 +1,405 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_libbanshee_warn_cflags = @ac_libbanshee_warn_cflags@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CFLAGS = -I$(srcdir)/../libcompat -I$(top_srcdir)/../include -I$(srcdir)/../include -I. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@ +noinst_LIBRARIES = libbansheeengine.a +libbansheeengine_a_SOURCES = array.c bounds.c hash.c hashset.c list.c stamp.c \ +ufind.c util.c setif-sort.c termhash.c setif-var.c flow-var.c flowrow-sort.c \ +setst-var.c jcollection.c banshee.c buffer.c setst-sort.c term-var.c \ +term-sort.c dot.c + +subdir = engine +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libbansheeengine_a_AR = $(AR) cru +libbansheeengine_a_LIBADD = +am_libbansheeengine_a_OBJECTS = array.$(OBJEXT) bounds.$(OBJEXT) \ + hash.$(OBJEXT) hashset.$(OBJEXT) list.$(OBJEXT) stamp.$(OBJEXT) \ + ufind.$(OBJEXT) util.$(OBJEXT) setif-sort.$(OBJEXT) \ + termhash.$(OBJEXT) setif-var.$(OBJEXT) flow-var.$(OBJEXT) \ + flowrow-sort.$(OBJEXT) setst-var.$(OBJEXT) \ + jcollection.$(OBJEXT) banshee.$(OBJEXT) buffer.$(OBJEXT) \ + setst-sort.$(OBJEXT) term-var.$(OBJEXT) term-sort.$(OBJEXT) \ + dot.$(OBJEXT) +libbansheeengine_a_OBJECTS = $(am_libbansheeengine_a_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/array.Po ./$(DEPDIR)/banshee.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/bounds.Po ./$(DEPDIR)/buffer.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/dot.Po ./$(DEPDIR)/flow-var.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/flowrow-sort.Po ./$(DEPDIR)/hash.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/hashset.Po ./$(DEPDIR)/jcollection.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/list.Po ./$(DEPDIR)/setif-sort.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/setif-var.Po ./$(DEPDIR)/setst-sort.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/setst-var.Po ./$(DEPDIR)/stamp.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/term-sort.Po ./$(DEPDIR)/term-var.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/termhash.Po ./$(DEPDIR)/ufind.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/util.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libbansheeengine_a_SOURCES) +DIST_COMMON = ChangeLog Makefile.am Makefile.in +SOURCES = $(libbansheeengine_a_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu engine/Makefile +Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +AR = ar + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbansheeengine.a: $(libbansheeengine_a_OBJECTS) $(libbansheeengine_a_DEPENDENCIES) + -rm -f libbansheeengine.a + $(libbansheeengine_a_AR) libbansheeengine.a $(libbansheeengine_a_OBJECTS) $(libbansheeengine_a_LIBADD) + $(RANLIB) libbansheeengine.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/banshee.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bounds.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow-var.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flowrow-sort.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hashset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcollection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setif-sort.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setif-var.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setst-sort.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setst-var.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stamp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/term-sort.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/term-var.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/termhash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ufind.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) + +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-depend distclean-generic distclean-tags distdir dvi \ + dvi-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libbanshee/engine/array.c b/libbanshee/engine/array.c new file mode 100644 index 00000000000..be297533fa6 --- /dev/null +++ b/libbanshee/engine/array.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "array.h" + +struct array { + region sameregion r; + void *sameregion data; + size_t elemsize; + type_t elemtype; + size_t nelems, nalloc; +}; + +struct array *new_array(region r, size_t initialsize, + size_t typesize, type_t typeinfo) +{ + struct array *a = ralloc(r, struct array); + + a->r = r; + a->data = typed_rarrayalloc(r, initialsize, typesize, typeinfo); + a->elemsize = typesize; + a->elemtype = typeinfo; + a->nelems = 0; + a->nalloc = initialsize; + + return a; +} + +void *array_extend(struct array *a, int by) +{ + size_t oldelems = a->nelems; + + if (by < 0) + assert(((unsigned int)-by) <= a->nelems && by != INT_MIN); + else if (a->nelems + by > a->nalloc) + { + size_t newsize = a->nalloc * 2 + by; + void *newdata = typed_rarrayalloc(a->r, newsize, a->elemsize, a->elemtype); + + /* XXX: could work harder to support really large array sizes + (this code will fail for a->nalloc >= (max(size_t)-by)/2) */ + assert(newsize > a->nalloc); /* die when we get really big */ + typed_rarraycopy(newdata, a->data, a->nelems, a->elemsize, a->elemtype); + a->data = newdata; + a->nalloc = newsize; + } + a->nelems += by; + + return (char *)a->data + a->elemsize * oldelems; +} + +void array_reset(struct array *a) +{ + a->nelems = 0; +} + +size_t array_length(struct array *a) +{ + return a->nelems; +} + +void *array_data(struct array *a) +{ + return a->data; +} + diff --git a/libbanshee/engine/array.h b/libbanshee/engine/array.h new file mode 100644 index 00000000000..6fe3a6cf17d --- /dev/null +++ b/libbanshee/engine/array.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ARRAY_H +#define ARRAY_H + +/* A region-based growable array type */ + +struct array; + +struct array *new_array(region r, size_t initialsize, + size_t typesize, type_t typeinfo); +void *array_extend(struct array *a, int by); +void array_reset(struct array *a); +size_t array_length(struct array *a); +void *array_data(struct array *a); + + +#define DECLARE_ARRAY(name, type) \ +typedef struct name ## _a *name; \ +name new_ ## name(region r, size_t initialsize); \ +type *name ## _extend(name a, int by); \ +void name ## _reset(name a); \ +size_t name ## _length(name a); \ +type *name ## _data(name a); + +#define DEFINE_ARRAY(name, type) \ +name new_ ## name(region r, size_t initialsize) \ +{ \ + return (name)new_array(r, initialsize, sizeof(type), rctypeof(type)); \ +} \ +type *name ## _extend(name a, int by) \ +{ \ + return array_extend((struct array *)a, by); \ +} \ +void name ## _reset(name a) \ +{ \ + return array_reset((struct array *)a); \ +} \ +size_t name ## _length(name a) \ +{ \ + return array_length((struct array *)a); \ +} \ +type *name ## _data(name a) \ +{ \ + return array_data((struct array *)a); \ +} + +#endif diff --git a/libbanshee/engine/banshee.c b/libbanshee/engine/banshee.c new file mode 100644 index 00000000000..54b975afd9c --- /dev/null +++ b/libbanshee/engine/banshee.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include "banshee.h" +#include "setif-sort.h" +#include "setst-sort.h" +#include "flowrow-sort.h" +#include "setif-var.h" + +DEFINE_LIST(gen_e_list,gen_e) + +void engine_init(void) +{ + region_init(); + stamp_init(); +} + +void engine_reset(void) deletes +{ + stamp_reset(); +} + +/* TODO */ +void engine_update(void) +{ +} + +void engine_stats(FILE *f) +{ + setif_print_stats(f); + setst_print_stats(f); + flowrow_print_stats(f); +} + +void print_constraint_graphs(FILE *f) +{ + setif_print_constraint_graph(f); +} diff --git a/libbanshee/engine/banshee.h b/libbanshee/engine/banshee.h new file mode 100644 index 00000000000..f9b647d02a7 --- /dev/null +++ b/libbanshee/engine/banshee.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef BANSHEE_H +#define BANSHEE_H + +#include +#include "linkage.h" +#include "stamp.h" +#include "list.h" +#include "util.h" +#include "dot.h" + +#define ALIAS_TYPE -2 +#define VAR_TYPE -1 +#define ZERO_TYPE 0 +#define ONE_TYPE 1 +#define UNION_TYPE 2 +#define INTER_TYPE 3 +#define CONSTANT_TYPE 4 + +EXTERN_C_BEGIN + + +#ifdef NONSPEC + +typedef enum sort_kind +{ + flowrow_sort, + setif_sort, + setst_sort, + flowterm_sort, + term_sort +} sort_kind; + +typedef struct gen_e +{ + sort_kind sort; +} *gen_e; +#else +typedef void *gen_e; +#endif + +DECLARE_LIST(gen_e_list,gen_e) + + typedef void (*gen_e_pr_fn_ptr) (FILE *, gen_e); + +/* + Function pointers that are common to all sorts +*/ + +/* inclusion */ +typedef void (*incl_fn_ptr) (gen_e, gen_e) deletes; + +/* match constructed terms */ +typedef void (*con_match_fn_ptr) (gen_e, gen_e) deletes; + +/* make fresh variables */ +typedef gen_e (*fresh_fn_ptr) (const char *); +typedef gen_e (*fresh_small_fn_ptr) (const char *); +typedef gen_e (*fresh_large_fn_ptr) (const char *); + +/* get a stamp */ +typedef stamp (*get_stamp_fn_ptr) (gen_e); + +/* extract a term from a proj pat */ +typedef gen_e (*get_proj_fn_ptr) (gen_e_list); + +void engine_init(void); +void engine_reset(void) deletes; +void engine_update(void); +void engine_stats(FILE *f); + +void print_constraint_graphs(FILE *f); + +EXTERN_C_END + +#endif /* BANSHEE_H */ diff --git a/libbanshee/engine/bool.h b/libbanshee/engine/bool.h new file mode 100644 index 00000000000..87638fc2dc6 --- /dev/null +++ b/libbanshee/engine/bool.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef BOOL_H +#define BOOL_H +#ifndef GCC_SYSTEM_H +#include "config.h" +/* 1 if we have _Bool. */ +#ifndef HAVE__BOOL +# define HAVE__BOOL \ + ((GCC_VERSION >= 3000) || (__STDC_VERSION__ >= 199901L)) +#endif +/* Provide some sort of boolean type. We use stdbool.h if it's + available. This must be after all inclusion of system headers, + as some of them will mess us up. */ +#undef bool +#undef true +#undef false +#undef TRUE +#undef FALSE + +#ifdef HAVE_STDBOOL_H +# include +#else +# if !HAVE__BOOL +typedef char _Bool; +# endif +# define bool _Bool +# define true 1 +# define false 0 +#endif + +#define TRUE true +#define FALSE false +#endif +#endif diff --git a/libbanshee/engine/bounds.c b/libbanshee/engine/bounds.c new file mode 100644 index 00000000000..9b14b75b4d9 --- /dev/null +++ b/libbanshee/engine/bounds.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include "bounds.h" + +struct bounds +{ + hash_set set; + gen_e_list elems; +}; + +bounds bounds_create(region r) +{ + bounds result; + + result = ralloc(r, struct bounds); + result->set = hs_create(r); + result->elems = new_gen_e_list(r); + + return result; +} + +gen_e_list bounds_exprs(bounds b) +{ + return b->elems; +} + +bool bounds_add(bounds b, gen_e e, stamp s) +{ + if (hs_member(b->set, s)) + return TRUE; + + else + { + gen_e_list_cons(e,b->elems); + return FALSE; + } +} + +bool bounds_empty(bounds b) +{ + return (gen_e_list_empty(b->elems)); +} + +bool bounds_query(bounds b, stamp x) +{ + return (hs_query(b->set, x)); +} + +void bounds_set(bounds b,gen_e_list l) +{ + b->elems = l; +} + +void bounds_delete(bounds b) +{ + hs_delete(b->set); +} + + diff --git a/libbanshee/engine/bounds.h b/libbanshee/engine/bounds.h new file mode 100644 index 00000000000..8b52247b362 --- /dev/null +++ b/libbanshee/engine/bounds.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef BOUNDS_H +#define BOUNDS_H + +#include "linkage.h" +#include "banshee.h" +#include "stamp.h" +#include "hashset.h" + +EXTERN_C_BEGIN + +typedef struct bounds *bounds; + +bounds bounds_create(region r); + +gen_e_list bounds_exprs(bounds); + +/* returns true if the bound was already present */ +bool bounds_add(bounds,gen_e,stamp); +bool bounds_query(bounds,stamp); +bool bounds_empty(bounds); +void bounds_delete(bounds); +void bounds_set(bounds,gen_e_list); + +EXTERN_C_END + +#endif /* BOUNDS_H */ diff --git a/libbanshee/engine/buffer.c b/libbanshee/engine/buffer.c new file mode 100644 index 00000000000..68f062d365c --- /dev/null +++ b/libbanshee/engine/buffer.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "buffer.h" + +/* Invariant: buffer always null-terminated */ +struct growbuf +{ + region r; + unsigned int maxsize, cursize; + char *buffer; +}; + +/* Make a new buffer with initial size */ +growbuf growbuf_new(region r, int size) +{ + growbuf b = ralloc(r, struct growbuf); + + assert(size > 0); + b->r = r; + b->maxsize = size; /* Force some growth! */ + b->cursize = 1; + b->buffer = rstralloc(r, size); + b->buffer[0] = '\0'; + return b; +} + +/* Empty a buffer */ +void growbuf_reset(growbuf b) +{ + assert(b->maxsize > 0); + b->cursize = 1; + b->buffer[0] = '\0'; +} + +/* Print to a buffer */ +int gprintf(growbuf b, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + return gvprintf(b, fmt, args); +} + +/* Print to a buffer */ +int gvprintf(growbuf b, const char *fmt, va_list args) +{ + int nchars; + + if (!fmt) /* Bug (?)/feature of vnsprintf -- printing \0 returns -1, + goes into infinite loop. */ + return 0; + while (1) + { + char *bufStart; + int sizeLeft; + + bufStart = b->buffer + b->cursize - 1; /* chop trailing \0 */ + sizeLeft = b->maxsize - b->cursize + 1; /* +1 size we're chooping + the trailing \0 */ + assert(*bufStart == '\0'); + nchars = vsnprintf(bufStart, sizeLeft, fmt, args); + if (nchars > -1 && nchars < sizeLeft) + { + b->cursize += nchars; /* nchars doesn't include \0, + but we overwrote our \0 */ + break; + } + else + { + /* How much room do we need? In the new glibc, nchars + tells us how much (not including the trailing null). + So we need the current size, -1 since we'll remove the null, + plus the new size, plus 1 for the new null. */ + int newSize = (nchars > -1) ? b->cursize - 1 + nchars + 1 + : b->maxsize * 2; + char *newBuf; + + /* fprintf(stderr, "Reallocating buffer, newSize=%d\n", newSize); */ + newBuf = rstralloc(b->r, newSize); + memcpy(newBuf, b->buffer, b->cursize); + newBuf[b->cursize-1] = '\0'; /* vsnprintf has printed something! */ + b->buffer = newBuf; + b->maxsize = newSize; + /* b->cursize unchanged */ + } + } + return nchars; +} + +/* Get the contents of a buffer */ +char *growbuf_contents(growbuf b) +{ + return b->buffer; +} + +bool growbuf_empty(growbuf b) +{ + return b->cursize == 1; /* Buffer always null terminated */ +} diff --git a/libbanshee/engine/buffer.h b/libbanshee/engine/buffer.h new file mode 100644 index 00000000000..c270ade32c3 --- /dev/null +++ b/libbanshee/engine/buffer.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef BUFFER_H +#define BUFFER_H + +/* + * Growable buffers + * + * Always null terminated. + */ + +#include +#include "bool.h" +#include "regions.h" +#include "linkage.h" + +EXTERN_C_BEGIN + +typedef struct growbuf *growbuf; + +growbuf growbuf_new(region, int); /* Make a new buffer with initial size */ +void growbuf_reset(growbuf); /* Empty a buffer */ +int gprintf(growbuf, const char *, ...); /* Print to a buffer */ +int gvprintf(growbuf, const char *, va_list); /* Print to a buffer */ +char *growbuf_contents(growbuf); /* Get the contents of a buffer */ +bool growbuf_empty(growbuf); /* Return true iff buffer is empty */ + +EXTERN_C_END + +#endif diff --git a/libbanshee/engine/compiler.h b/libbanshee/engine/compiler.h new file mode 100644 index 00000000000..6c90a63d26c --- /dev/null +++ b/libbanshee/engine/compiler.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef COMPILER_H +#define COMPILER_H + +# if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define HAVE_C99 +# endif + +# if 0 +/*(defined(__GNUC__) || defined(HAVE_C99)) && !defined (IN_GCC) */ +# define HAVE_VARIADIC_MACROS +# endif + + +# if !defined(__GNUC__) && !defined(__attribute__) +# define __attribute__(attributes) +# endif + +#endif /* !COMPILER_H */ diff --git a/libbanshee/engine/dot.c b/libbanshee/engine/dot.c new file mode 100644 index 00000000000..73c772fee53 --- /dev/null +++ b/libbanshee/engine/dot.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include "dot.h" +#include "hash.h" + +static FILE *of; +static hash_table node_hash_table; +static region dot_region; +static int node_count; +static const char *edge_op; + +static void print_n_attrs(node_attr *attrs, int n) +{ + int i; + fputc('[',of); + + for (i = 0; i < n; i++) + { + const char *name; + switch (attrs[i].name) + { + case n_color: + name = "color"; + break; + case n_fontcolor: + name = "fontcolor"; + break; + case n_fontname: + name = "fontname"; + break; + case n_fontsize: + name = "fontsize"; + break; + case n_height: + name = "height"; + break; + case n_width: + name = "width"; + break; + case n_label: + name = "label"; + break; + case n_layer: + name = "layer"; + break; + case n_shape: + name = "shape"; + break; + case n_shapefile: + name = "shapefile"; + break; + case n_style: + name = "style"; + break; + default: + name = ""; + assert(0); + break; + } + if (i > 0) + fputc(',',of); + fprintf(of,"%s = %s",name,attrs[i].value); + } + + fputc(']',of); +} + +static void print_e_attrs(edge_attr *attrs, int n) +{ + int i; + fputc('[',of); + for (i = 0; i < n; i++) + { + const char *name; + switch(attrs[i].name) + { + case e_color: + name = "color"; + break; + case e_decorate: + name = "decorate"; + break; + case e_dir: + name = "dir"; + break; + case e_fontcolor: + name = "fontcolor"; + break; + case e_fontname: + name = "fontname"; + break; + case e_fontsize: + name = "fontsize"; + break; + case e_id: + name = "id"; + break; + case e_label: + name = "label"; + break; + case e_layer: + name = "layer"; + break; + case e_minlen: + name = "minlen"; + break; + case e_style: + name = "style"; + break; + case e_weight: + name = "weight"; + break; + default : + name = ""; + assert(0); + break; + } + if (i > 0) + fputc(',',of); + fprintf(of,"%s = %s",name,attrs[i].value); + } + fputc(']',of); +} + +static void print_g_attrs(graph_attr *attrs, int n) +{ + int i; + fputc('[',of); + + for (i = 0; i < n; i++) + { + const char *name; + switch (attrs[i].name) + { + case g_center: + name = "center"; + break; + case g_clusterrank: + name = "clusterrank"; + break; + case g_color: + name = "color"; + break; + case g_concentrate: + name = "concentrate"; + break; + case g_fontcolor: + name = "fontcolor"; + break; + case g_fontname: + name = "fontname"; + break; + case g_fontsize: + name = "fontsize"; + break; + case g_label: + name = "label"; + break; + case g_layerseq: + name = "layerseq"; + break; + case g_margin: + name = "margin"; + break; + case g_mclimit: + name = "mclimit"; + break; + case g_nodesep: + name = "nodesep"; + break; + case g_nslimit: + name = "nslimit"; + break; + case g_ordering: + name = "ordering"; + break; + case g_orientation: + name = "orientation"; + break; + case g_page: + name = "page"; + break; + case g_rank: + name = "rank"; + break; + case g_rankdir: + name = "rankdir"; + break; + case g_ranksep: + name = "ranksep"; + break; + case g_ratio: + name = "ratio"; + break; + case g_size: + name = "size"; + break; + default : + name = ""; + assert(0); + break; + } + if (i > 0) + fputc(',',of); + fprintf(of,"%s = %s",name,attrs[i].value); + } + fputc(']',of); +} + + +void dot_start(FILE *to,const char *name,bool is_directed,bool is_strict) +{ + const char *graph_type,*strict; + + + node_count = 0; + dot_region = newregion(); + node_hash_table = make_string_hash_table(dot_region,8,TRUE); + of = to; + + if (is_directed) + { + edge_op = "->"; + graph_type = "digraph"; + } + else + { + edge_op = "--"; + graph_type = "graph"; + } + + if (is_strict) + strict = "strict"; + else + strict = ""; + + fprintf(of,"%s %s %s{\n",strict,graph_type,name); + +} + +void dot_global_graph_style(graph_attr *attrs, int n) +{ + fputs("graph ",of); + print_g_attrs(attrs,n); + fputc(';',of); + fputc('\n',of); +} + +void dot_global_edge_style(edge_attr *attrs, int n) +{ + fputs("edge ",of); + print_e_attrs(attrs,n); + fputc(';',of); + fputc('\n',of); +} + +void dot_global_node_style(node_attr *attrs, int n) +{ + fputs("node ",of); + print_n_attrs(attrs,n); + fputc(';',of); + fputc('\n',of); +} + +/* by default, set the node's name to label */ +static void declare_node(dot_node n, char *label) +{ + int i; + char mangled[512]; + + if (label[0] == '\"') + mangled[0] = 's'; + else + mangled[0] = label[0]; + + for (i = 1; label[i] && i < 512 ;i++) + { + if (label[i] == '\"') + mangled[i] = '_'; + else mangled[i] = label[i]; + } + mangled[i] = '\0'; + + fprintf(of,"nd_%d [label=\"%s\"]\n",n,mangled); +} + +dot_node dot_get_node(char *label) deletes +{ + dot_node result; + if (!hash_table_lookup(node_hash_table,(hash_key)label,(hash_data *)(char *)&result)) + { + dot_node newnode = node_count++; + + declare_node(newnode,label); + hash_table_insert(node_hash_table, + (hash_key)rstrdup(dot_region,label), + (hash_data)newnode); + + return newnode; + } + else + return result; + +} + +void dot_node_style(dot_node node,node_attr *attrs, int n) +{ + fprintf(of,"nd_%d ",node); + print_n_attrs(attrs,n); + fputc(';',of); + fputc('\n',of); +} + +void dot_plain_edge(dot_node from, dot_node to) +{ + fprintf(of,"nd_%d %s nd_%d;\n",from,edge_op,to); +} + +void dot_styled_edge(dot_node from, dot_node to, edge_attr *attrs, int n) +{ + fprintf(of,"nd_%d %s nd_%d ",from,edge_op,to); + print_e_attrs(attrs,n); + fputc(';',of); + fputc('\n',of); +} + +void dot_end(void) deletes +{ + fputc('}',of); + hash_table_delete(node_hash_table); + deleteregion_ptr(&dot_region); +} diff --git a/libbanshee/engine/dot.h b/libbanshee/engine/dot.h new file mode 100644 index 00000000000..7e221e68145 --- /dev/null +++ b/libbanshee/engine/dot.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef DOT_H +#define DOT_H + +#include +#include "linkage.h" +#include "bool.h" + +EXTERN_C_BEGIN + +typedef int dot_node; + +typedef struct +{ + enum n_attrs + { + n_color, + n_fontcolor, + n_fontname, + n_fontsize, + n_height, + n_width, + n_label, + n_layer, + n_shape, + n_shapefile, + n_style + } name; + const char *value; +} node_attr; + +typedef struct +{ + enum e_attrs + { + e_color, + e_decorate, + e_dir, + e_fontcolor, + e_fontname, + e_fontsize, + e_id, + e_label, + e_layer, + e_minlen, + e_style, + e_weight + } name; + const char *value; +} edge_attr; + +typedef struct +{ + enum g_attrs + { + g_center, + g_clusterrank, + g_color, + g_concentrate, + g_fontcolor, + g_fontname, + g_fontsize, + g_label, + g_layerseq, + g_margin, + g_mclimit, + g_nodesep, + g_nslimit, + g_ordering, + g_orientation, + g_page, + g_rank, + g_rankdir, + g_ranksep, + g_ratio, + g_size + } name; + const char *value; +} graph_attr; + +void dot_start(FILE *to,const char *name,bool directed,bool strict); + +void dot_global_graph_style(graph_attr *attrs,int n); +void dot_global_edge_style(edge_attr *attrs,int n); +void dot_global_node_style(node_attr *attrs,int n); + +dot_node dot_get_node(char *label) deletes; +void dot_node_style(dot_node node,node_attr *attrs,int n); + +void dot_plain_edge(dot_node from, dot_node to); +void dot_styled_edge(dot_node from, dot_node to, edge_attr *attrs,int n); + +void dot_end(void) deletes; + +EXTERN_C_END + +#endif /* DOT_H */ diff --git a/libbanshee/engine/flow-var.c b/libbanshee/engine/flow-var.c new file mode 100644 index 00000000000..4c60aa4eb47 --- /dev/null +++ b/libbanshee/engine/flow-var.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include "banshee.h" +#include "flow-var.h" +#include "ufind.h" +#include "bounds.h" + +DECLARE_UFIND(contour_elt,contour) + +struct flow_var /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; /* alias or var */ + stamp st; + gen_e alias; + bounds sameregion ubs; + bounds sameregion lbs; + contour_elt elt; + const char *name; +}; + +DEFINE_UFIND(contour_elt,contour) +DEFINE_LIST(flow_var_list, flow_var) + +#define get_contour(x) (contour_elt_get_info((x)->elt)) + +static flow_var make_var(region r, const char *name, stamp st) +{ + flow_var result = ralloc(r,struct flow_var); + + result->type = VAR_TYPE; + result->st = st; + result->alias = NULL; + result->ubs = bounds_create(r); + result->lbs = bounds_create(r); + result->elt = new_contour_elt(r,NULL); + result->name = name; + +#ifdef NONSPEC + result->sort = flow_sort; +#endif + + return result; +} + +flow_var fv_fresh(region r, const char *name) +{ + return make_var(r,name,stamp_fresh()); +} + +flow_var fv_fresh_large(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_large()); +} + +flow_var fv_fresh_small(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_small()); +} + +const char * fv_get_name(flow_var v) +{ + return v->name; +} + +gen_e_list fv_get_lbs(flow_var v) +{ + return bounds_exprs(v->lbs); +} + +gen_e_list fv_get_ubs(flow_var v) +{ + return bounds_exprs(v->ubs); +} + +bool fv_add_ub(flow_var v, gen_e e, stamp st) +{ + return bounds_add(v->ubs,e,st); +} + +bool fv_add_lb(flow_var v, gen_e e, stamp st) +{ + return bounds_add(v->lbs,e,st); +} + +bool fv_is_ub(flow_var v, stamp st) +{ + bool self_edge = v->st == st, + in_bounds = bounds_query(v->ubs,st); + + return (self_edge || in_bounds); +} + +bool fv_is_lb(flow_var v, stamp st) +{ + bool self_edge = v->st == st, + in_bounds = bounds_query(v->lbs,st); + + return (self_edge || in_bounds); +} + +void fv_set_alias(flow_var v, gen_e e) +{ + assert(v->type == VAR_TYPE); + + v->type = ALIAS_TYPE; + v->alias = e; +} + +gen_e fv_get_alias(flow_var v) +{ + return v->alias; +} + +bool fv_has_contour(flow_var v) +{ + return (get_contour(v) != NULL); +} + +void fv_set_contour(flow_var v, contour c) +{ + contour_elt_update(v->elt,c); +} + +static contour combine_contour(contour c1, contour c2) +{ + if (c1 == NULL) + return c2; + else if (c2 == NULL) + return c1; + + else + { + fail("Attempt to unify two distinct contours\n"); + return NULL; + } + +} +void fv_unify_contour(flow_var v1, flow_var v2) +{ + contour_elt_unify(combine_contour,v1->elt,v2->elt); +} + + +gen_e fv_instantiate_contour(flow_var v) deletes +{ + contour c = get_contour(v); + return c->instantiate(c->fresh,c->get_stamp,c->shape); +} diff --git a/libbanshee/engine/flow-var.h b/libbanshee/engine/flow-var.h new file mode 100644 index 00000000000..2d77007824a --- /dev/null +++ b/libbanshee/engine/flow-var.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef FLOW_VAR_H +#define FLOW_VAR_H + +#include "linkage.h" +#include "banshee.h" +#include "jcollection.h" + +EXTERN_C_BEGIN + +typedef struct flow_var *flow_var; + +typedef gen_e (*contour_inst_fn_ptr) (fresh_fn_ptr,get_stamp_fn_ptr,gen_e) deletes; + +struct contour +{ + gen_e shape; + fresh_fn_ptr fresh; + get_stamp_fn_ptr get_stamp; + contour_inst_fn_ptr instantiate; +}; + +typedef struct contour *contour; + +DECLARE_LIST(flow_var_list, flow_var) + +flow_var fv_fresh(region r, const char *name); +flow_var fv_fresh_large(region r, const char *name); +flow_var fv_fresh_small(region r, const char *name); +const char * fv_get_name(flow_var v); +gen_e_list fv_get_lbs(flow_var v); +gen_e_list fv_get_ubs(flow_var v); +bool fv_add_ub(flow_var v, gen_e e, stamp st); +bool fv_add_lb(flow_var v, gen_e e, stamp st); +bool fv_is_ub(flow_var v, stamp st); +bool fv_is_lb(flow_var v, stamp st); + +void fv_set_alias(flow_var v, gen_e e); +gen_e fv_get_alias(flow_var v); +void fv_set_contour(flow_var v, contour c); +bool fv_has_contour(flow_var v); +void fv_unify_contour(flow_var v1, flow_var v2); +gen_e fv_instantiate_contour(flow_var v) deletes; + +EXTERN_C_END + +#endif /* FLOW_VAR_H */ diff --git a/libbanshee/engine/flowrow-sort.c b/libbanshee/engine/flowrow-sort.c new file mode 100644 index 00000000000..baee348ffd3 --- /dev/null +++ b/libbanshee/engine/flowrow-sort.c @@ -0,0 +1,1107 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include "flowrow-sort.h" +#include "termhash.h" + +#include "setif-sort.h" + +#define ABS_TYPE 2 +#define WILD_TYPE 3 +#define ROW_TYPE 4 + +/* generic flow row */ +struct flowrow_gen +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; +#ifdef NONSPEC + sort_kind base_sort; +#endif +}; + +typedef struct flowrow_gen *flowrow_gen; + +struct flowrow +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; +#ifdef NONSPEC + sort_kind base_sort; +#endif + flowrow_map fields; + gen_e rest; +}; + +typedef struct flowrow *flowrow; + +struct field_split +{ + gen_e_list matched1; + gen_e_list matched2; + flowrow_map nomatch1; + flowrow_map nomatch2; +}; + +region flowrow_region; +term_hash flowrow_hash; +struct flowrow_stats flowrow_stats; +static void fields_print(FILE *f,flowrow_map m,field_print_fn_ptr field_print) deletes; + +stamp flowrow_get_stamp(gen_e e) +{ + if ( ((flowrow_gen)e)->type == ALIAS_TYPE) + return ((flowrow_gen)fv_get_alias( (flow_var)e ))->st; + else + return ((flowrow_gen)e)->st; + +} + +static flowrow_map flowrow_get_fields(gen_e e) +{ + assert (flowrow_is_row(e)); + + return ((flowrow)e)->fields; +} + +static gen_e flowrow_get_rest(gen_e e) +{ + assert(flowrow_is_row(e)); + + return ((flowrow)e)->rest; +} + + +static int field_compare(const flowrow_field f1,const flowrow_field f2) + +{ + int compare = strcmp(f1->label,f2->label); + return compare; +} + + +static int field_compare_ne(const flowrow_field f1,const flowrow_field f2) + +{ + int compare = strcmp(f1->label,f2->label); + + if (! compare) /* rows should never have two fields with the same labels */ + { + failure("Multiple fields in this row share the same label\n"); + } + return compare; +} + +static struct field_split split_fields(region r, flowrow_map fields1, + flowrow_map fields2) +{ + struct field_split split; + flowrow_map_scanner scan1, scan2; + flowrow_field field1,field2; + bool consumed1 = TRUE,consumed2 = TRUE, + fields1_remain = TRUE, fields2_remain = TRUE;; + + split.matched1 = new_gen_e_list(r); + split.matched2 = new_gen_e_list(r); + split.nomatch1 = new_flowrow_map(r); + split.nomatch2 = new_flowrow_map(r); + + flowrow_map_scan(fields1,&scan1); + flowrow_map_scan(fields2,&scan2); + + while (TRUE) + { + if (consumed1) + fields1_remain = flowrow_map_next(&scan1,&field1); + if (consumed2) + fields2_remain = flowrow_map_next(&scan2,&field2); + + if (fields1_remain && fields2_remain) + { + int compare_fields = field_compare(field1,field2); + + if (compare_fields < 0) + { + flowrow_map_cons(field1,split.nomatch1); + consumed1 = TRUE; + consumed2 = FALSE; + } + else if (compare_fields > 0) + { + flowrow_map_cons(field2,split.nomatch2); + consumed2 = TRUE; + consumed1 = FALSE; + } + else /* two fields are equal */ + { + gen_e_list_cons(field1->expr,split.matched1); + gen_e_list_cons(field2->expr,split.matched2); + consumed1 = TRUE; + consumed2 = TRUE; + continue; + } + } + else if (fields1_remain) + { + /* flowrow_map_append(split.nomatch1,flowrow_map_copy(r,fields1)); */ + flowrow_map_cons(field1,split.nomatch1); + + while (flowrow_map_next(&scan1,&field1)) + { + flowrow_map_cons(field1,split.nomatch1); + } + + break; + } + else if (fields2_remain) + { + /* flowrow_map_append(split.nomatch2,flowrow_map_copy(r,fields2)); */ + flowrow_map_cons(field2,split.nomatch2); + while (flowrow_map_next(&scan2,&field2)) + { + flowrow_map_cons(field2,split.nomatch2); + } + break; + } + else /* no remaining fields, so */ break; + } + + return split; +} + +static bool flowrow_is_normalized(gen_e r) +{ + if ( flowrow_is_row(r) ) + { + gen_e rest = flowrow_get_rest(r); + + if ( flowrow_is_row(rest) || flowrow_is_alias(rest) ) + return FALSE; + } + else if ( flowrow_is_alias(r) ) + return FALSE; + + return TRUE; +} + +static gen_e normalize(get_stamp_fn_ptr get_stamp, + flowrow_map m,gen_e r) deletes +{ + if (flowrow_is_row(r)) + { + flowrow_map_append(m, + flowrow_map_copy(flowrow_region, + flowrow_get_fields(r))); + return normalize(get_stamp,m,flowrow_get_rest(r)); + } + else if (flowrow_is_alias(r)) + { + assert (! flowrow_is_alias(fv_get_alias((flow_var)r)) ); + return normalize(get_stamp, m,fv_get_alias((flow_var)r)); + } + else + return flowrow_row(get_stamp,m,r); +} + +static gen_e normalize_row(get_stamp_fn_ptr get_stamp, gen_e r) deletes +{ + if (flowrow_is_normalized(r)) + return r; + else /* normalize the row */ + return normalize(get_stamp,new_flowrow_map(flowrow_region),r); +} + +static bool eq(gen_e e1, gen_e e2) +{ + return ( flowrow_get_stamp(e1) == flowrow_get_stamp(e2) ); +} + + +/* + A row constraint row1 <= row2 is l-inductive iff row2 is a var and for all + X = tlv(row1), o(row2) > o(X). + + tlv(row) = {X} if row is a var X, {} otherwise +*/ +static bool l_inductive(gen_e e1, gen_e e2) +{ + if (flowrow_is_var(e2)) + { + if (flowrow_is_var(e1)) + return flowrow_get_stamp(e2) > flowrow_get_stamp(e1); + else return TRUE; + } + return FALSE; +} + +/* + A row constraint row1 <= row2 is r-inductive iff row1 is a var and for all + X = tlv(row2), o(row1) > o(X) +*/ +static bool r_inductive(gen_e e1, gen_e e2) +{ + if (flowrow_is_var(e1)) + { + if (flowrow_is_var(e2)) + return flowrow_get_stamp(e1) > flowrow_get_stamp(e2); + else return TRUE; + } + return FALSE; +} + +static inline bool flowrow_minimal(flowrow r) +{ + return flowrow_is_zero(r->rest); +} + +static inline bool flowrow_maximal(flowrow r) +{ + return flowrow_is_one(r->rest); +} + +static inline bool flowrow_closed(flowrow r) +{ + return flowrow_is_abs(r->rest); +} + +static inline bool flowrow_wildcard(flowrow r) +{ + return flowrow_is_wild(r->rest); +} + +static inline bool flowrow_var(flowrow r) +{ + return flowrow_is_var(r->rest); +} + +static gen_e contour_instantiate(fresh_fn_ptr fresh, + get_stamp_fn_ptr get_stamp, + gen_e e) deletes +{ + if (flowrow_is_row(e)) + { + gen_e result; + flowrow_map_scanner scan; + flowrow_field f; + gen_e row = normalize_row(get_stamp,e); + + region scratch_rgn = newregion(); + + flowrow_map new_fields = new_flowrow_map(scratch_rgn); + + flowrow_map_scan(flowrow_get_fields(row),&scan); + + while (flowrow_map_next(&scan,&f)) + { + flowrow_field new_field = + ralloc(flowrow_region,struct flowrow_field); + new_field->label = f->label; + new_field->expr = fresh(NULL); + + flowrow_map_cons(new_field,new_fields); + } + + result = flowrow_row(get_stamp,new_fields,flowrow_fresh(NULL)); + + deleteregion(scratch_rgn); + + assert( flowrow_is_row(result) ); + + return result; + } + + else /* TODO */ + { + failure("Unmatched contour\n"); + return NULL; + } +} + +static contour get_contour(fresh_fn_ptr fresh,get_stamp_fn_ptr get_stamp, + gen_e zero_elem ATTRIBUTE_UNUSED,gen_e e) +{ + if (flowrow_is_row(e)) + { + contour result; + + result = ralloc(flowrow_region,struct contour); + result->shape = e; + result->fresh = fresh; + result->get_stamp = get_stamp; + result->instantiate = contour_instantiate; + + return result; + } + else /* TODO */ + { + failure("Unmatched contour\n"); + return NULL; + } +} + + +static void trans_lbs(fresh_fn_ptr fresh,get_stamp_fn_ptr get_stamp, + incl_fn_ptr field_incl, gen_e zero_elem, + flow_var v, gen_e e) deletes +{ + gen_e temp; + gen_e_list_scanner scan; + + gen_e_list_scan(fv_get_lbs(v),&scan); + while (gen_e_list_next(&scan,&temp)) + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,temp,e); + +} + +static void trans_ubs(fresh_fn_ptr fresh,get_stamp_fn_ptr get_stamp, + incl_fn_ptr field_incl, gen_e zero_elem, + flow_var v, gen_e e) deletes +{ + gen_e temp; + gen_e_list_scanner scan; + + gen_e_list_scan(fv_get_ubs(v),&scan); + while (gen_e_list_next(&scan,&temp)) + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e,temp); +} + +static void update_lower_bound(fresh_fn_ptr fresh,get_stamp_fn_ptr get_stamp, + incl_fn_ptr field_incl, gen_e zero_elem, + flow_var v,gen_e e) deletes +{ + if (fv_has_contour(v)) /* _ <= v, and v has a contour */ + { + gen_e shape = fv_instantiate_contour(v); + + fv_set_alias(v,shape); + trans_ubs(fresh,get_stamp,field_incl,zero_elem,v,shape); + trans_lbs(fresh,get_stamp,field_incl,zero_elem,v,shape); + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e,shape); + + } + + else if (flowrow_is_var(e)) + { + flow_var v_lb = (flow_var)e; + + if (fv_has_contour(v_lb)) /* v1 <= v2, v1 has a contour */ + { + gen_e shape = fv_instantiate_contour(v_lb); + + fv_set_alias(v_lb,shape); + trans_ubs(fresh,get_stamp,field_incl,zero_elem,v_lb,shape); + trans_lbs(fresh,get_stamp,field_incl,zero_elem,v_lb,shape); + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem, + shape,(gen_e)v); + + } + + else /* we have v1 <= v2, no contours */ + { + bool redundant; + + fv_unify_contour(v,(flow_var)e); + redundant = fv_add_lb(v,e,flowrow_get_stamp(e)); + + if (! redundant) + trans_ubs(fresh,get_stamp,field_incl,zero_elem,v,e); + + } + } + else /* we have c(...) <= v, and v has no contour */ + { + gen_e shape = NULL; + fv_set_contour(v,get_contour(fresh,get_stamp,zero_elem,e)); + + shape = fv_instantiate_contour(v); + fv_set_alias(v,shape); + trans_ubs(fresh,get_stamp,field_incl,zero_elem,v,shape); + trans_lbs(fresh,get_stamp,field_incl,zero_elem,v,shape); + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e,shape); + + } +} + +static void update_upper_bound(fresh_fn_ptr fresh,get_stamp_fn_ptr get_stamp, + incl_fn_ptr field_incl, gen_e zero_elem, + flow_var v,gen_e e) deletes +{ + if (fv_has_contour(v)) /* v isn't aliased, and we discovered a contour*/ + { + gen_e shape = fv_instantiate_contour(v); + + fv_set_alias(v,shape); + trans_ubs(fresh,get_stamp,field_incl,zero_elem,v,shape); + trans_lbs(fresh,get_stamp,field_incl,zero_elem,v,shape); + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,shape,e); + + } + + else if (flowrow_is_var(e)) + { + flow_var v2 = (flow_var)e; + + if (fv_has_contour(v2)) // v2 isn't aliased, and we discovered a contour + { + gen_e shape = fv_instantiate_contour(v2); + + fv_set_alias(v2,shape); + trans_ubs(fresh,get_stamp,field_incl,zero_elem,v2,shape); + trans_lbs(fresh,get_stamp,field_incl,zero_elem,v2,shape); + + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem, + (gen_e)v,shape); + + } + + else /* we have v1 <= v2, no contours */ + { + bool redundant; + + fv_unify_contour(v,(flow_var)e); + redundant = fv_add_ub(v,e,flowrow_get_stamp(e)); + + if (! redundant) + trans_lbs(fresh,get_stamp,field_incl,zero_elem,v,e); + + } + } + else /* we have v <= c(...), and v has no contour */ + { + gen_e shape = NULL; + fv_set_contour(v,get_contour(fresh,get_stamp,zero_elem,e)); + + shape = fv_instantiate_contour(v); + + if (! flowrow_is_row(shape) ) + { + assert(0); + } + + fv_set_alias(v,shape); + trans_ubs(fresh,get_stamp,field_incl,zero_elem,v,shape); + trans_lbs(fresh,get_stamp,field_incl,zero_elem,v,shape); + + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,shape,e); + + } + +} + +// END + + +void flowrow_inclusion(fresh_fn_ptr fresh,get_stamp_fn_ptr get_stamp, + incl_fn_ptr field_incl, gen_e zero_elem, gen_e a, + gen_e b) deletes +{ + gen_e e1 = normalize_row(get_stamp, a), + e2 = normalize_row(get_stamp, b); + + if (eq(e1,e2)) + return; + else if (flowrow_is_zero(e1) || flowrow_is_wild(e1)) + return; + else if (flowrow_is_one(e2) || flowrow_is_wild(e2)) + return; + + else if ( l_inductive(e1,e2) ) + { + flow_var v2 = (flow_var)e2; + + flowrow_stats.rows_l_inductive++; + + update_lower_bound(fresh,get_stamp,field_incl,zero_elem,v2,e1); + return; + } + + else if ( r_inductive(e1,e2) ) + { + flow_var v1 = (flow_var)e1; + + flowrow_stats.rows_r_inductive++; + + update_upper_bound(fresh,get_stamp,field_incl,zero_elem,v1,e2); + return; + } + + else if ( flowrow_is_row(e1) && flowrow_is_row(e2)) + { + region scratch_rgn = newregion(); + + flowrow r1 = (flowrow)e1, + r2 = (flowrow)e2; + + struct field_split split = + split_fields(scratch_rgn,r1->fields,r2->fields); + + if ( gen_e_list_empty(split.matched1) ) + { + assert ( gen_e_list_empty(split.matched2) ); + + if (flowrow_wildcard(r1) || flowrow_minimal(r1)) + { + gen_e newrow = + flowrow_row(get_stamp,split.nomatch1,flowrow_get_rest(e1)); + + flowrow_inclusion(fresh,get_stamp,field_incl, zero_elem,newrow, + flowrow_get_rest(e2)); + } + else if (flowrow_maximal(r2) || flowrow_closed(r2)) + { + gen_e newrow = + flowrow_row(get_stamp,split.nomatch2,flowrow_get_rest(e2)); + + flowrow_inclusion(fresh, get_stamp,field_incl,zero_elem, + flowrow_get_rest(e1),newrow); + } + else + { + gen_e rest1 = flowrow_get_rest(e1), + rest2 = flowrow_get_rest(e2); + + //assert( flowrow_is_var(rest1) && flowrow_is_var(rest2)); + + if ( eq(rest1,rest2)) + failure("Recursive row resolution\n"); + else + { + gen_e fv = flowrow_fresh(NULL); + gen_e newrow1 = flowrow_row(get_stamp,split.nomatch1,fv); + gen_e newrow2 = flowrow_row(get_stamp,split.nomatch2,fv); + + flowrow_inclusion(fresh,get_stamp,field_incl, + zero_elem,rest1,newrow2); + flowrow_inclusion(fresh,get_stamp,field_incl, + zero_elem,newrow1,rest2); + } + + } + } + + else /* some fields matched */ + { + gen_e_list_scanner scan1, scan2; + gen_e f1,f2; + + assert( gen_e_list_length(split.matched1) + == gen_e_list_length(split.matched2) ); + + gen_e_list_scan(split.matched1,&scan1); + gen_e_list_scan(split.matched2,&scan2); + + while (gen_e_list_next(&scan1,&f1) && + gen_e_list_next(&scan2,&f2) ) + { + field_incl(f1,f2); + } + + if ( flowrow_wildcard(r1) && flowrow_wildcard(r2) ) + { + goto END; + } + else + { + flowrow_map fields1 = split.nomatch1; + flowrow_map fields2 = split.nomatch2; + + gen_e newrow1 = flowrow_row(get_stamp,fields1,r1->rest); + gen_e newrow2 = flowrow_row(get_stamp,fields2,r2->rest); + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem, + newrow1, newrow2); + } + } + END: + deleteregion(scratch_rgn); + } + + else /* potentially a problem normalizing a row? */ + { + failure("Unmatched case in row inclusion\n"); + return; + } +} + +gen_e flowrow_row(get_stamp_fn_ptr get_stamp,flowrow_map f, gen_e rest) deletes +{ + flowrow_map fields = flowrow_map_copy(flowrow_region,f); + + if (flowrow_map_empty(fields)) + { + return rest; + } + else + { + flowrow_map_scanner scan; + flowrow_field temp; + gen_e result; + int i = 2, + length = flowrow_map_length(fields); + stamp st[2+2*length]; + + st[0] = ROW_TYPE; + if (rest) + st[1] = flowrow_get_stamp(rest); + else + assert(0); + + flowrow_map_sort(fields,field_compare_ne); + + flowrow_map_scan(fields,&scan); + while(flowrow_map_next(&scan,&temp)) + { + st[i++] = stamp_string(temp->label); + if (temp->expr) + st[i++] = get_stamp(temp->expr); + else + assert(0); + } + + if ( (result = term_hash_find(flowrow_hash,st,2 + 2*length)) == NULL) + { + flowrow r = ralloc(flowrow_region, struct flowrow); + r->type = ROW_TYPE; + r->st = stamp_fresh(); + r->fields = fields; + r->rest = rest; + +#ifdef NONSPEC + r->base_sort = row_map_head(fields)->expr->sort; + r->sort = flowrow_sort; +#endif + result = (gen_e) r; + term_hash_insert(flowrow_hash,result,st,2+2*length); + } + /* assert(flowrow_is_normalized(result)); */ + return result; + + } +} + +#ifndef NONSPEC +static struct flowrow_gen zero_row = {ZERO_TYPE,ZERO_TYPE}; +static struct flowrow_gen one_row = {ONE_TYPE,ONE_TYPE}; +static struct flowrow_gen abs_row = {ABS_TYPE, ABS_TYPE}; +static struct flowrow_gen wild_row = {WILD_TYPE, WILD_TYPE}; + +gen_e flowrow_zero(void) +{ + return (gen_e)&zero_row; +} + +gen_e flowrow_one(void) +{ + return (gen_e)&one_row; +} + +gen_e flowrow_abs(void) +{ + return (gen_e)&abs_row; +} + +gen_e flowrow_wild(void) +{ + return (gen_e)&wild_row; +} + +gen_e flowrow_fresh(const char *name) +{ + flowrow_stats.fresh++; + return (gen_e)fv_fresh(flowrow_region,name); +} + +gen_e flowrow_fresh_small(const char *name) +{ + flowrow_stats.fresh_small++; + return (gen_e)fv_fresh_small(flowrow_region,name); +} + +gen_e flowrow_fresh_large(const char *name) +{ + flowrow_stats.fresh_large++; + return (gen_e)fv_fresh_large(flowrow_region,name); +} + +#else +static struct flowrow_gen term_zero_row = {flowrow_sort,ZERO_TYPE,ZERO_TYPE,term_sort}; +static struct flowrow_gen term_one_row = {flowrow_sort,ONE_TYPE,ONE_TYPE,term_sort}; +static struct flowrow_gen term_abs_row = {flowrow_sort,ABS_TYPE, ABS_TYPE,term_sort}; +static struct flowrow_gen term_wild_row = {flowrow_sort,WILD_TYPE, WILD_TYPE,term_sort}; + + +static struct flowrow_gen setif_zero_row = {flowrow_sort,ZERO_TYPE,ZERO_TYPE,setif_sort}; +static struct flowrow_gen setif_one_row = {flowrow_sort,ONE_TYPE,ONE_TYPE,setif_sort}; +static struct flowrow_gen setif_abs_row = {flowrow_sort,ABS_TYPE, ABS_TYPE,setif_sort}; +static struct flowrow_gen setif_wild_row = {flowrow_sort,WILD_TYPE, WILD_TYPE,setif_sort}; + +static struct flowrow_gen setst_zero_row = {flowrow_sort,ZERO_TYPE,ZERO_TYPE,setst_sort}; +static struct flowrow_gen setst_one_row = {flowrow_sort,ONE_TYPE,ONE_TYPE,setst_sort}; +static struct flowrow_gen setst_abs_row = {flowrow_sort,ABS_TYPE, ABS_TYPE,setst_sort}; +static struct flowrow_gen setst_wild_row = {flowrow_sort,WILD_TYPE, WILD_TYPE,setst_sort}; + + +gen_e flowrow_zero(sort_kind base_sort) +{ + switch (base_sort) + { + case setif_sort: + return (gen_e)&setif_zero_row; + case setst_sort: + return (gen_e)&setst_zero_row; + case term_sort: + return (gen_e)&term_zero_row; + default: + { + failure("No matching base sort: flowrow_zero\n"); + return NULL; + } + } + + return NULL; +} + +gen_e flowrow_one(sort_kind base_sort) +{ + switch (base_sort) + { + case setif_sort: + return (gen_e)&setif_one_row; + case setst_sort: + return (gen_e)&setst_one_row; + case term_sort: + return (gen_e)&term_one_row; + default: + { + failure("No matching base sort: flowrow_one\n"); + return NULL; + } + } + + return NULL; +} + +gen_e flowrow_abs(sort_kind base_sort) +{ + switch (base_sort) + { + case setif_sort: + return (gen_e)&setif_abs_row; + case setst_sort: + return (gen_e)&setst_abs_row; + case term_sort: + return (gen_e)&term_abs_row; + default: + { + failure("No matching base sort: flowrow_abs\n"); + return NULL; + } + } + + return NULL; +} + +gen_e flowrow_wild(sort_kind base_sort) +{ + + switch (base_sort) + { + case setif_sort: + return (gen_e)&setif_wild_row; + case setst_sort: + return (gen_e)&setst_wild_row; + case term_sort: + return (gen_e)&term_wild_row; + default: + { + failure("No matching base sort: flowrow_wild\n"); + return NULL; + } + } + + return NULL; +} + +gen_e flowrow_fresh(const char *name,sort_kind base_sort) +{ + + switch (base_sort) + { + case setif_sort: + return + case setst_sort: + return (gen_e)&setst_one_row; + case term_sort: + return (gen_e)&term_one_row; + default: + { + failure("No matching base sort: flowrow_one\n"); + return NULL; + } + } + + return NULL; +} + +gen_e flowrow_fresh_small(sort_kind base_sort) +{ + + switch (base_sort) + { + case setif_sort: + return (gen_e)&setif_one_row; + case setst_sort: + return (gen_e)&setst_one_row; + case term_sort: + return (gen_e)&term_one_row; + default: + { + failure("No matching base sort: flowrow_one\n"); + return NULL; + } + } + + return NULL; +} + +gen_e flowrow_fresh_large(sort_kind base_sort) +{ + +} + +sort_kind flowrow_base_sort(gen_e e) +{ + +} +#endif /* NONSPEC */ + + +gen_e flowrow_extract_field(const char *name, gen_e e) +{ + + static bool field_eq(const flowrow_field f) + { + return (! strcmp(f->label,name)); + } + + if (flowrow_is_row(e)) + { + flowrow_map fields = flowrow_get_fields(e); + flowrow_field f = flowrow_map_find(fields,field_eq); + + if (f) + return f->expr; + } + return NULL; +} + +gen_e flowrow_extract_rest(gen_e e) +{ + if (flowrow_is_row(e)) + return flowrow_get_rest(e); + else + return NULL; +} + +flowrow_map flowrow_extract_fields(gen_e e) +{ + if (flowrow_is_row(e)) + return flowrow_map_copy(flowrow_region,flowrow_get_fields(e)); + else + return NULL; +} + + +bool flowrow_is_alias(gen_e e) +{ + return ((flowrow_gen)e)->type == ALIAS_TYPE; +} + +bool flowrow_is_zero(gen_e e) +{ + return ((flowrow_gen)e)->type == ZERO_TYPE; +} + +bool flowrow_is_one(gen_e e) +{ + return ((flowrow_gen)e)->type == ONE_TYPE; +} + +bool flowrow_is_abs(gen_e e) +{ + return ((flowrow_gen)e)->type == ABS_TYPE; +} + +bool flowrow_is_wild(gen_e e) +{ + return ((flowrow_gen)e)->type == WILD_TYPE; +} + +bool flowrow_is_var(gen_e e) +{ + return ((flowrow_gen)e)->type == VAR_TYPE; +} + +bool flowrow_is_row(gen_e e) +{ + return ((flowrow_gen)e)->type == ROW_TYPE; +} + +void flowrow_init(void) +{ + flowrow_region = newregion(); + flowrow_hash = make_term_hash(flowrow_region); +} + +static void flowrow_reset_stats(void) +{ + flowrow_stats.fresh = 0; + flowrow_stats.fresh_small = 0; + flowrow_stats.fresh_large = 0; + + flowrow_stats.rows_disjoint_wild = 0; + flowrow_stats.rows_equal = 0; + flowrow_stats.rows_zero_one_wild = 0; + flowrow_stats.rows_l_inductive = 0; + flowrow_stats.rows_r_inductive = 0; + flowrow_stats.rows_disjoint_r1_minimal = 0; + flowrow_stats.rows_disjoint_r1_var_r2_minimal = 0; + flowrow_stats.rows_disjoint_r1_var_r2_maximal = 0; + flowrow_stats.rows_disjoint_r1_var_r2_closed = 0; + flowrow_stats.rows_disjoint_r1_var_r2_var_lt = 0; + flowrow_stats.rows_disjoint_r1_var_r2_var_gt = 0; + flowrow_stats.rows_equal_domains = 0; + flowrow_stats.rows_nonempty_intersection = 0; + flowrow_stats.rows_fresh = 0; + flowrow_stats.rows_fresh_large = 0; +} + +void flowrow_reset(void) deletes +{ + term_hash_delete(flowrow_hash); + deleteregion_ptr(&flowrow_region); + + flowrow_reset_stats(); + + flowrow_region = newregion(); + flowrow_hash = make_term_hash(flowrow_region); + +} + +static void fields_print(FILE *f,flowrow_map m,field_print_fn_ptr field_print) deletes +{ + flowrow_map_scanner scan; + flowrow_field temp; + + flowrow_map_scan(m,&scan); + + if (flowrow_map_next(&scan,&temp)) + { + fprintf(f,"%s : ",temp->label); + + if (field_print) + field_print(f,temp->expr); + else + fprintf(f,"?"); + } + + while (flowrow_map_next(&scan,&temp)) + { + fprintf(f,",%s : ",temp->label); + + if (field_print) + field_print(f,temp->expr); + else + fprintf(f,"?"); + } +} + +void flowrow_print(FILE *f,get_stamp_fn_ptr get_stamp, + field_print_fn_ptr field_print,gen_e row) deletes +{ + gen_e e = normalize_row(get_stamp,row); + + switch ( ((flowrow_gen)e)->type) + { + case ZERO_TYPE: + fprintf(f, "0"); + break; + case ONE_TYPE: + fprintf(f, "1"); + break; + case ABS_TYPE: + fprintf(f, "abs"); + break; + case WILD_TYPE: + fprintf(f, "wild"); + break; + case VAR_TYPE: + fprintf(f, fv_get_name((flow_var)e)); + break; + case ROW_TYPE: + fprintf(f, "<"); + fields_print(f, flowrow_get_fields(e), field_print); + fprintf(f, "|"); + flowrow_print(f, get_stamp, field_print, flowrow_get_rest(e)); + fprintf(f, ">"); + break; + default: + assert(0); + break; + } +} + +void flowrow_print_stats(FILE *f) +{ + fprintf(f,"\n========== Flow Var Stats ==========\n"); + fprintf(f,"Fresh : %d\n",flowrow_stats.fresh); + fprintf(f,"Fresh Small : %d\n",flowrow_stats.fresh_small); + fprintf(f,"Fresh Large : %d\n",flowrow_stats.fresh_large); + fprintf(f,"=====================================\n"); +} + +DEFINE_LIST(flowrow_map,flowrow_field) diff --git a/libbanshee/engine/flowrow-sort.h b/libbanshee/engine/flowrow-sort.h new file mode 100644 index 00000000000..8d79b42c29d --- /dev/null +++ b/libbanshee/engine/flowrow-sort.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef FLOWROW_SORT_H +#define FLOWROW_SORT_H + + +#include "stdio.h" +#include "banshee.h" +#include "termhash.h" +#include "flow-var.h" + +struct flowrow_field +{ + char *label; + gen_e expr; +}; + +typedef struct flowrow_field *flowrow_field; + +DECLARE_LIST(flowrow_map,flowrow_field) + +extern region flowrow_region; + +void flowrow_inclusion(fresh_fn_ptr fresh, get_stamp_fn_ptr get_stamp, + incl_fn_ptr field_incl,gen_e zero_elem, gen_e e1, + gen_e e2) deletes; + +gen_e flowrow_row(get_stamp_fn_ptr get_stamp,flowrow_map fields, gen_e rest) deletes; + +gen_e flowrow_extract_field(const char *name, gen_e e); +gen_e flowrow_extract_rest(gen_e e); +flowrow_map flowrow_extract_fields(gen_e e); + +stamp flowrow_get_stamp(gen_e e); + +#ifndef NONSPEC +gen_e flowrow_zero(void); +gen_e flowrow_one(void); +gen_e flowrow_abs(void); +gen_e flowrow_wild(void); +gen_e flowrow_fresh(const char *name); +gen_e flowrow_fresh_small(const char *name); +gen_e flowrow_fresh_large(const char *name); +#else +sort_kind flowrow_base_sort(gen_e e); +gen_e flowrow_zero(sort_kind base_sort); +gen_e flowrow_one(sort_kind base_sort); +gen_e flowrow_abs(sort_kind base_sort); +gen_e flowrow_wild(sort_kind base_sort); +gen_e flowrow_fresh(sort_kind base_sort); +gen_e flowrow_fresh_small(sort_kind base_sort); +gen_e flowrow_fresh_large(sort_kind base_sort); +#endif + +bool flowrow_is_zero(gen_e e); +bool flowrow_is_one(gen_e e); +bool flowrow_is_abs(gen_e e); +bool flowrow_is_wild(gen_e e); +bool flowrow_is_var(gen_e e); +bool flowrow_is_row(gen_e e); +bool flowrow_is_alias(gen_e e); + + +void flowrow_init(void); +void flowrow_reset(void) deletes; + +typedef void (* field_print_fn_ptr) (FILE *f,gen_e e) deletes; + +void flowrow_print(FILE *f,get_stamp_fn_ptr get_stamp, + field_print_fn_ptr field_print,gen_e e) deletes; +void flowrow_print_stats(FILE *f); + +extern struct flowrow_stats flowrow_stats; + +struct flowrow_stats +{ + int fresh; + int fresh_small; + int fresh_large; + + int rows_disjoint_wild; + int rows_equal; + int rows_zero_one_wild; + int rows_l_inductive; + int rows_r_inductive; + int rows_disjoint_r1_minimal; + int rows_disjoint_r1_var_r2_minimal; + int rows_disjoint_r1_var_r2_maximal; + int rows_disjoint_r1_var_r2_closed; + int rows_disjoint_r1_var_r2_var_lt; + int rows_disjoint_r1_var_r2_var_gt; + int rows_equal_domains; + int rows_nonempty_intersection; + int rows_fresh; + int rows_fresh_large; +}; + +#endif /* FLOWROW_H */ + + + + + + + diff --git a/libbanshee/engine/hash.c b/libbanshee/engine/hash.c new file mode 100644 index 00000000000..bf315cee4a5 --- /dev/null +++ b/libbanshee/engine/hash.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "hash.h" +#include "util.h" + +struct bucket +{ + hash_key key; + hash_data data; + struct bucket *next; +}; + +#define scan_bucket(b, var) for (var = b; var; var = var->next) + +struct Hash_table +{ + region r; /* Region for this table */ + hash_fn hash; /* Function for hashing keys */ + keyeq_fn cmp; /* Function for comparing keys */ + + int size; /* Number of buckets */ + int elts; /* Number of elements */ + bool internal_rgn; /* TRUE if the ht uses an internal region */ + bucket *table; /* Array of (size) buckets */ +}; + +static void rehash(hash_table ht) deletes; + +/* Make a new hash table, with size buckets initially. The actual + table is allocated in a local region, which is discarded on rehashing. */ +hash_table make_hash_table(region r, int size, hash_fn hash, + keyeq_fn cmp, bool internal_rgn) +{ + hash_table result; + + assert(size > 0); + result = ralloc(r, struct Hash_table); + + if (internal_rgn) + result->r = newregion(); + else + result->r = r; + + result->internal_rgn = internal_rgn; + result->hash = hash; + result->cmp = cmp; + result->size = size; + result->elts = 0; + result->table = rarrayalloc(result->r, size, bucket); + + return result; +} + +/* Hash a string */ +static int string_hash(char *str) +{ + char *c; + int h; + + c = str; + h = 0; + if (!c) + return 0; + while (*c) + h = 33*h + 720 + *c++; /* SML/NJ's string hash function */ + return h; +} + +/* Return TRUE iff s1 == s2 */ +static bool string_eq(char *s1, char *s2) +{ + return !strcmp(s1, s2); +} + +/* Make a hash table for strings. */ +hash_table make_string_hash_table(region rhash, int size, bool internal_rgn) +{ + return make_hash_table(rhash, size, (hash_fn) string_hash, + (keyeq_fn) string_eq,internal_rgn); +} + +/* Zero out ht. Doesn't reclaim bucket space. */ +void hash_table_reset(hash_table ht) deletes +{ + int i; + + if (ht->internal_rgn) + { + deleteregion(ht->r); + ht->r = newregion(); + } + + ht->elts = 0; + for (i = 0; i < ht->size; i++) + ht->table[i] = NULL; +} + +void hash_table_delete(hash_table ht) deletes +{ + if (ht->internal_rgn) + deleteregion(ht->r); +} + + +/* Return the number of entries in ht */ +int hash_table_size(hash_table ht) +{ + return ht->elts; +} + +/* Return the bucket corresponding to k in ht */ +static inline bucket *find_bucket(hash_table ht, hash_key k) +{ + int hash; + + hash = ht->hash(k); + if (hash < 0) + hash = -1*hash; + return &ht->table[hash % ht->size]; +} + +/* Lookup k in ht. Returns corresponding data in *d, and function + result is TRUE if the k was in ht, false otherwise. */ +bool hash_table_lookup(hash_table ht, hash_key k, hash_data *d) +{ + bucket cur; + + cur = *find_bucket(ht, k); + while (cur) + { + if (ht->cmp(k, cur->key)) + { + if (d) + *d = cur->data; + return TRUE; + } + cur = cur->next; + } + return FALSE; +} + + +/* Add k:d to ht. If k was already in ht, replace old entry by k:d. + Rehash if necessary. Returns TRUE if k was not already in ht. */ +bool hash_table_insert(hash_table ht, hash_key k, hash_data d) deletes +{ + bucket *cur; + + if (ht->elts > ht->size*15) + rehash(ht); + cur = find_bucket(ht, k); + while (*cur) + { + if (ht->cmp(k, (*cur)->key)) + { + (*cur)->data = d; + return FALSE; /* Replace */ + } + cur = &(*cur)->next; + } + *cur = ralloc(ht->r, struct bucket); + (*cur)->key = k; + (*cur)->data = d; + (*cur)->next = NULL; + ht->elts++; + return TRUE; /* New key */ +} + +/* Remove mapping for k in ht. Returns TRUE if k was in ht. */ +bool hash_table_remove(hash_table ht, hash_key k) +{ + bucket *cur; + bucket *prev = NULL; + + cur = find_bucket(ht, k); + while (*cur) + { + if (ht->cmp(k, (*cur)->key)) + { + if (!*prev) + (*prev)->next = (*cur)->next; + else + *cur = NULL; + ht->elts--; + return TRUE; + } + prev = cur; + cur = &(*cur)->next; + } + return FALSE; +} + +/* Return a copy of ht */ +hash_table hash_table_copy(region r, hash_table ht) +{ + int i; + hash_table result; + bucket cur, newbucket, *prev; + + result = make_hash_table(r, ht->size, ht->hash, ht->cmp,ht->internal_rgn); + result->elts = ht->elts; + + for (i = 0; i < ht->size; i++) + { + prev = &result->table[i]; + scan_bucket(ht->table[i], cur) + { + newbucket = ralloc(result->r, struct bucket); + newbucket->key = cur->key; + newbucket->data = cur->data; + newbucket->next = NULL; + assert(!*prev); + *prev = newbucket; + prev = &newbucket->next; + } + } + return result; + /* + hash_table result; + hash_table_scanner hts; + hash_key k; + hash_data d; + + result = make_hash_table(r, ht->size, ht->hash, ht->cmp); + hash_table_scan(ht, &hts); + while (hash_table_next(&hts, &k, &d)) + insist(hash_table_insert(result, k, d)); + + return result; + */ +} + +/* Increase size of ht (double it) and reinsert all the elements */ +static void rehash(hash_table ht) deletes +{ + int old_table_size, i; + bucket *old_table, cur; + region old_region; + +#ifdef DEBUG + printf("Rehash table size=%d, elts=%d\n", ht->size, ht->elts); +#endif + + old_table_size = ht->size; + old_table = ht->table; + old_region = ht->r; + + if (ht->internal_rgn) + ht->r = newregion(); + + ht->size = ht->size*2; + ht->elts = 0; + ht->table = rarrayalloc(ht->r, ht->size, bucket); + + for (i = 0; i < old_table_size; i++) + scan_bucket(old_table[i], cur) + insist(hash_table_insert(ht, cur->key, cur->data)); + + if (ht->internal_rgn) + deleteregion(old_region); +} + +/* Begin scanning ht */ +void hash_table_scan(hash_table ht, hash_table_scanner *hts) +{ + hts->ht = ht; + hts->i = 0; + hts->cur = hts->ht->table[0]; +} + +/* Get next elt in table, storing the elt in *k and *d if k and d are + non-NULL, respectively. Returns TRUE if there is a next elt, FALSE + otherwise. */ +bool hash_table_next(hash_table_scanner *hts, hash_key *k, hash_data *d) +{ + while (hts->cur == NULL) + { + hts->i++; + if (hts->i < hts->ht->size) + hts->cur = hts->ht->table[hts->i]; + else + break; + } + + if (hts->i == hts->ht->size) + { + return FALSE; + } + else + { + if (k) + *k = hts->cur->key; + if (d) + *d = hts->cur->data; + hts->cur = hts->cur->next; + } + return TRUE; +} + +/* Apply f to all elements of ht, in some arbitrary order */ +void hash_table_apply(hash_table ht, hash_apply_fn f, void *arg) +{ + int i; + bucket cur; + + for (i = 0; i < ht->size; i++) + scan_bucket(ht->table[i], cur) + f(cur->key, cur->data, arg); +} + +/* Map f to all elements on ht, creating a new hash table */ +hash_table hash_table_map(hash_table ht, hash_map_fn f, void *arg) +{ + int i; + hash_table result; + bucket cur, newbucket, *prev; + + result = make_hash_table(ht->r, ht->size, ht->hash, ht->cmp,ht->internal_rgn); + result->elts = ht->elts; + + for (i = 0; i < ht->size; i++) + { + prev = &result->table[i]; + scan_bucket(ht->table[i], cur) + { + newbucket = ralloc(ht->r, struct bucket); + newbucket->key = cur->key; + newbucket->data = f(cur->key, cur->data, arg); + newbucket->next = NULL; + assert(!*prev); + *prev = newbucket; + prev = &newbucket->next; + } + } + return result; + /* + hash_table result; + int i; + bucket cur; + + result = make_hash_table(ht->r, ht->size, ht->hash, ht->cmp); + for (i = 0; i < ht->size; i++) + scan_bucket(ht->table[i], cur) + insist(hash_table_insert(result, cur->key, f(cur->key, cur->data, arg))); + return result; + */ +} + +static keycmp_fn cur_cmp = NULL; + +static int entry_cmp(const void *a, const void *b) +{ + struct sorted_entry *ae = (struct sorted_entry *) a; + struct sorted_entry *be = (struct sorted_entry *) b; + return cur_cmp(ae->k, be->k); +} + +/* Begin scanning ht in sorted order according to f */ +void hash_table_scan_sorted(hash_table ht, keycmp_fn f, + hash_table_scanner_sorted *htss) +{ + hash_table_scanner hts; + int i; + + htss->r = newregion(); + htss->size = hash_table_size(ht); + htss->entries = rarrayalloc(htss->r, htss->size, struct sorted_entry); + htss->i = 0; + + hash_table_scan(ht, &hts); + i = 0; + while (hash_table_next(&hts, &htss->entries[i].k, + &htss->entries[i].d)) + i++; + assert(i == htss->size); + cur_cmp = f; + qsort(htss->entries, htss->size, sizeof(struct sorted_entry), entry_cmp); + cur_cmp = NULL; +} + +/* Just like hash_table_next, but scans in sorted order */ +bool hash_table_next_sorted(hash_table_scanner_sorted *htss, hash_key *k, + hash_data *d) deletes +{ + if (htss->i < htss->size) + { + *k = htss->entries[htss->i].k; + *d = htss->entries[htss->i].d; + htss->i++; + return TRUE; + } + else + { + deleteregion(htss->r); + htss->r = NULL; + return FALSE; + } +} diff --git a/libbanshee/engine/hash.h b/libbanshee/engine/hash.h new file mode 100644 index 00000000000..eb93ac88b31 --- /dev/null +++ b/libbanshee/engine/hash.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef HASH_H +#define HASH_H + +#include +#include "bool.h" +/*#include "hash_info.h"*/ /* Includes hash_key, hash_data typedef */ +#include "linkage.h" + +EXTERN_C_BEGIN + +typedef void *hash_key; +typedef void *hash_data; + +/* Function to hash a key */ +typedef int (*hash_fn)(hash_key k); + +/* Function returning true iff k1 and k2 are equal */ +typedef bool (*keyeq_fn)(hash_key k1, hash_key k2); + +/* Function applied to elts in the hash table */ +typedef void (*hash_apply_fn)(hash_key k, hash_data d, void *arg); + +/* Function mapped to elts in the hash table */ +typedef hash_data (*hash_map_fn)(hash_key k, hash_data d, void *arg); + +typedef struct Hash_table *hash_table; + +/* Make a new hash table, with size buckets initially. */ +hash_table make_hash_table(region rhash, int size, hash_fn hash, + keyeq_fn cmp, bool internal_rgn); + +/* Make a hash table for strings. */ +hash_table make_string_hash_table(region rhash, int size, bool internal_rgn); + +/* Zero out ht. Doesn't reclaim bucket space. */ +void hash_table_reset(hash_table ht) deletes; + +/* Delete ht and internal memory associated with it. The top level pointer + must still be deleted. */ +void hash_table_delete(hash_table ht) deletes; + +/* Return the number of entries in ht */ +int hash_table_size(hash_table ht); + + +/* Lookup k in ht. If d is not NULL, returns corresponding data in *d. + Function result is TRUE if the k was in ht, false otherwise. */ +bool hash_table_lookup(hash_table ht, hash_key k, hash_data *d); + +/* Add k:d to ht. If k was already in ht, replace old entry by k:d. + Rehash if necessary. Returns TRUE if k was not already in ht. */ +bool hash_table_insert(hash_table ht, hash_key k, hash_data d) deletes; + +/* Remove mapping for k in ht. Returns TRUE if k was in ht. */ +bool hash_table_remove(hash_table ht, hash_key k); + +/* Return a copy of ht, allocated in rhash */ +hash_table hash_table_copy(region rhash, hash_table ht); + +/* Apply f to all elements of ht, in some arbitrary order */ +void hash_table_apply(hash_table ht, hash_apply_fn f, void *arg); + +/* Map f to all elements on ht, creating a new hash table */ +hash_table hash_table_map(hash_table ht, hash_map_fn f, void *arg); + +typedef struct bucket *bucket; +typedef struct +{ + hash_table ht; + int i; + bucket cur; +} hash_table_scanner; /* Opaque type! Do not modify fields. */ + +/* Begin scanning ht */ +void hash_table_scan(hash_table ht, hash_table_scanner *); + +/* Get next elt in table, storing the elt in *k and *d if k and d are + non-NULL, respectively. Returns TRUE if there is a next elt, FALSE + otherwise. */ +bool hash_table_next(hash_table_scanner *, hash_key *k, hash_data *d); + +/* Total order on hash table keys, only uesd for hash_table_scan_sorted */ +typedef int (*keycmp_fn)(hash_key k1, hash_key k2); + +struct sorted_entry +{ + hash_key k; + hash_data d; +}; + +typedef struct +{ + region r; + int i; + int size; + struct sorted_entry *entries; +} hash_table_scanner_sorted; + +/* Begin scanning ht in sorted order according to f */ +void hash_table_scan_sorted(hash_table ht, keycmp_fn f, + hash_table_scanner_sorted *htss); + +/* Just like hash_table_next, but scans in sorted order */ +bool hash_table_next_sorted(hash_table_scanner_sorted *htss, hash_key *k, + hash_data *d) deletes; + + +EXTERN_C_END + +#endif diff --git a/libbanshee/engine/hashset.c b/libbanshee/engine/hashset.c new file mode 100644 index 00000000000..27195e767bd --- /dev/null +++ b/libbanshee/engine/hashset.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include "hashset.h" +#include "util.h" +#define INIT_TABLE_SIZE 2 +#define EMPTY_KEY 0 +#define UB(n) ((1<ub = UB(init_table_size); + hs->size = init_table_size; + hs->capacity = CAP(init_table_size); + hs->table = (int *)calloc(hs->capacity, sizeof(int)); + hs->inserts = 0; + return hs; +} + +int hs_num_items(hash_set hs) +{ + return hs->inserts; +} + +int *hs_list_items(hash_set hs) +{ + return hs->table; +} + +static bool member(int *table, int ub, int i, int value) +{ + while (table[i] != empty_key) + { + if (table[i] == value) + return TRUE; + + else + i = ub & (i + prime_2); + } + return FALSE; +} + +static inline void reinsert(int *table, int ub, int value) +{ + int i; + + i = ub & (prime_1 * value); + + while (table[i] != empty_key) + { + /* possibly the value is already present */ + if (table[i] == value) + return; + + else + i = ub & (i + prime_2); + } + + table[i] = value; +} + +static bool member_or_insert(int *table, int ub, int i, int value) +{ + while (table[i] != empty_key) + { + if (table[i] == value) + return TRUE; + + else + i = ub & (i + prime_2); + } + table[i] = value; + return FALSE; +} + +static void rehash(hash_set hs) +{ + int *old_table; + int old_capacity, i; + + old_table = hs->table; + old_capacity = hs->capacity; + hs->capacity *= 2; + hs->ub = UB(++hs->size); + hs->table = (int *)calloc(hs->capacity, sizeof(int)); + assert(hs->table); + + + for (i = 0; i < old_capacity; i++) + { + reinsert(hs->table, hs->ub, old_table[i]); + } + + free(old_table); +} +/* +static void post_insert(hash_set hs) +{ + float percent_full; + + int capacity = hs->capacity; + int inserts = ++hs->inserts; + + printf("%d,%d->%f\n",inserts,capacity,percent_full); + assert(capacity); + percent_full = (float) inserts / capacity; + + + if (percent_full != percent_full) + { + assert (0); + } + + if (percent_full >= .85) + rehash(hs); +} +*/ + +static void post_insert(hash_set hs) +{ + int capacity = hs->capacity; + int inserts = ++hs->inserts; + + float percent_capacity = capacity * .85; + + /* + printf("%d,%d->%f\n",inserts,capacity,percent_capacity); + */ + + if ( (float) inserts >= percent_capacity) + { + rehash(hs); + } + +} + + +bool hs_query(hash_set hs, int entry) +{ + int hash; + int ub = hs->ub; + + hash = ub & (prime_1 * abs(entry)); + return member(hs->table, ub, hash, entry); +} + +bool hs_member(hash_set hs, int entry) +{ + int hash; + int ub = hs->ub; + + hash = ub & (prime_1 * abs(entry)); + if (member_or_insert(hs->table, ub, hash, entry)) + return TRUE; + + else + { + post_insert(hs); + return FALSE; + } +} + +void hs_delete(hash_set hs) +{ + free(hs->table); +} + + diff --git a/libbanshee/engine/hashset.h b/libbanshee/engine/hashset.h new file mode 100644 index 00000000000..0b06cd0a657 --- /dev/null +++ b/libbanshee/engine/hashset.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef HASHSET_H +#define HASHSET_H + +#include "linkage.h" +#include "banshee.h" + +EXTERN_C_BEGIN + +typedef struct hash_set *hash_set; + +hash_set hs_create(region r); +void hs_delete(hash_set); +bool hs_member(hash_set,int); /* adds the entry if not present */ +bool hs_query(hash_set,int); /* query only */ +int *hs_list_items(hash_set); +int hs_num_items(hash_set); + +EXTERN_C_END + +#endif /* HASHSET_H */ diff --git a/libbanshee/engine/jcollection.c b/libbanshee/engine/jcollection.c new file mode 100644 index 00000000000..8df072c8c8d --- /dev/null +++ b/libbanshee/engine/jcollection.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "jcollection.h" +#include "hashset.h" +#include "termhash.h" + + +/* + static term_hash jcoll_hash; + */ + +struct jcoll_dict +{ + region r; + term_hash hash; + get_stamp_fn_ptr get_stamp; +}; + +enum jcoll_type +{ + j_single, + j_chain, + j_join +}; + +/* generic jcoll type */ +struct jcoll +{ + enum jcoll_type type; + stamp st; +}; + +struct jcoll_single +{ + enum jcoll_type type; + stamp st; + gen_e entry; +}; + +struct jcoll_chain +{ + enum jcoll_type type; + stamp st; + gen_e_list sameregion entries; +}; + +struct jcoll_join +{ + enum jcoll_type type; + stamp st; + jcoll_list sameregion joins; + gen_e_list sameregion cache; +}; + +typedef struct jcoll_single *jcoll_single; +typedef struct jcoll_chain *jcoll_chain; +typedef struct jcoll_join *jcoll_join; + +DEFINE_LIST(jcoll_list,jcoll) + + + +jcoll jcoll_new(jcoll_dict d, gen_e e) +{ + jcoll_single result = ralloc(d->r, struct jcoll_single); + result->type = j_single; + result->st = stamp_fresh(); + result->entry = e; + return (jcoll)result; +} + +jcoll jcoll_jjoin(jcoll_dict d,jcoll_list list) +{ + + if (jcoll_list_empty(list)) + return NULL; + else if (jcoll_list_length(list) == 1) + return jcoll_list_head(list); + + else + { + int i = 0, + length = jcoll_list_length(list) + 1; + stamp sts[length]; + jcoll_join result; + + jcoll_list_scanner scan; + jcoll temp; + + sts[i++] = j_join; + + jcoll_list_scan(list,&scan); + while (jcoll_list_next(&scan,&temp)) + { + stamp st = temp ? temp->st : 0; + sts[i++] = st; + } + qsort(&sts[1],length-1,sizeof(int),ptr_cmp); + + if ( NULL == (result = (jcoll_join)term_hash_find(d->hash,sts,length)) ) + { + result = ralloc(d->r,struct jcoll_join); + + result->type = j_join; + result->st = stamp_fresh(); + result->joins = list; + result->cache = new_gen_e_list(d->r); + term_hash_insert(d->hash,(gen_e)result,sts,length); + } + return (jcoll)result; + } + +} + +/* + Hash chains + */ +jcoll jcoll_create_chain(jcoll_dict d, gen_e_list elems) +{ + int i = 0, + length = gen_e_list_length(elems) + 1; + stamp sts[length]; + gen_e_list_scanner scan; + gen_e temp; + jcoll_chain result; + + sts[i++] = j_chain; + + gen_e_list_scan(elems,&scan); + while (gen_e_list_next(&scan,&temp)) + { + sts[i++] = d->get_stamp(temp); + } + qsort(&sts[1],length-1,sizeof(int),ptr_cmp); /* FIX, first pos should always be chain */ + + if ( NULL == (result = (jcoll_chain)term_hash_find(d->hash,sts,length)) ) + { + result = ralloc(d->r,struct jcoll_chain); + result->type = j_chain; + result->st = stamp_fresh(); + result->entries = elems; + term_hash_insert(d->hash,(gen_e)result,sts, + length); + } + return (jcoll)result; +} + +typedef void (*japp_fn_ptr) (void *, void *); + +static void app_aux(hash_set h, get_stamp_fn_ptr get_stamp, japp_fn_ptr app, + jcoll j, void *data) +{ + if (! j) + return; + + switch(j->type) + { + case j_single: + { + jcoll_single single = (jcoll_single) j; + + if (! hs_member(h,get_stamp(single->entry)) ) + app(single->entry, data); + } + break; + case j_chain: + { + jcoll_chain chain = (jcoll_chain) j; + + if (! hs_member(h,chain->st) ) + { + gen_e_list_scanner scan; + gen_e entry; + + gen_e_list_scan(chain->entries, &scan); + while (gen_e_list_next(&scan, &entry)) + { + if (! hs_member(h, get_stamp(entry)) ) + app(entry, data); + } + + } + + } + break; + case j_join: + { + jcoll_join join = (jcoll_join) j; + + if (! hs_member(h, join->st)) + { + if (! gen_e_list_empty(join->cache)) + { + gen_e_list_scanner scan; + gen_e entry; + + gen_e_list_scan(join->cache, &scan); + while (gen_e_list_next(&scan, &entry)) + { + if (! hs_member(h, get_stamp(entry)) ) + app(entry, data); + } + } + else + { + jcoll_list_scanner scan; + jcoll temp; + + jcoll_list_scan(join->joins, &scan); + while (jcoll_list_next(&scan,&temp)) + { + app_aux(h,get_stamp,app,temp, data); + } + + } + } + + } + break; + } + +} + +static void jcoll_app(jcoll_dict d, japp_fn_ptr app, jcoll j, void *data) deletes +{ + region scratch_rgn = newregion(); + hash_set hash = hs_create(scratch_rgn); + app_aux(hash,d->get_stamp, app, j, data); + hs_delete(hash); + deleteregion(scratch_rgn); +} + static void jcoll_accum(void *e, void *accum) + { + gen_e_list_cons((gen_e) e, (gen_e_list) accum); + } + +gen_e_list jcoll_flatten(jcoll_dict d, jcoll j) deletes +{ + + gen_e_list accum = NULL; + + + if (j == NULL) + return new_gen_e_list(d->r); + + switch (j->type) + { + case j_single: + { + jcoll_single single = (jcoll_single)j; + + accum = new_gen_e_list(d->r); + gen_e_list_cons(single->entry,accum); + } + break; + case j_chain: + { + jcoll_chain chain = (jcoll_chain)j; + /* accum = gen_e_list_copy(r,chain->entries); */ + accum = chain->entries; + } + break; + case j_join: + { + jcoll_join join = (jcoll_join)j; + + if (! gen_e_list_empty(join->cache)) + return join->cache; + else + { + accum = new_gen_e_list(d->r); + jcoll_app(d, jcoll_accum,j, accum); + + gen_e_list_append(join->cache,accum /* gen_e_list_copy(r,accum)*/); + } + } + break; + } + + return accum; +} + +jcoll_dict jcoll_create_dict(region r,get_stamp_fn_ptr get_stamp) +{ + jcoll_dict result = ralloc(r,struct jcoll_dict); + + result->r = r; + result->hash = make_term_hash(r); + result->get_stamp = get_stamp; + return result; +} + + +void jcoll_delete_dict(jcoll_dict d) +{ + term_hash_delete(d->hash); +} diff --git a/libbanshee/engine/jcollection.h b/libbanshee/engine/jcollection.h new file mode 100644 index 00000000000..b1f0e717d4e --- /dev/null +++ b/libbanshee/engine/jcollection.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef JCOLLECTION_H +#define JCOLLECTION_H + +#include "linkage.h" +#include "banshee.h" + +EXTERN_C_BEGIN + +typedef struct jcoll *jcoll; + +typedef struct jcoll_dict *jcoll_dict; + +DECLARE_LIST(jcoll_list,jcoll) + +jcoll jcoll_new(jcoll_dict d, gen_e e); +jcoll jcoll_jjoin(jcoll_dict d, jcoll_list list); +gen_e_list jcoll_flatten(jcoll_dict d, jcoll j) deletes; +jcoll jcoll_create_chain(jcoll_dict d, gen_e_list elems); + +jcoll_dict jcoll_create_dict(region r,get_stamp_fn_ptr get_stamp); +void jcoll_delete_dict(jcoll_dict d); + +EXTERN_C_END + +#endif /* JCOLLECTION_H */ + + + + + + + + diff --git a/libbanshee/engine/linkage.h b/libbanshee/engine/linkage.h new file mode 100644 index 00000000000..ef70bbe2468 --- /dev/null +++ b/libbanshee/engine/linkage.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef LINKAGE_H +#define LINKAGE_H + +#ifdef __cplusplus +# define EXTERN_C extern "C" +# define EXTERN_C_BEGIN extern "C" { +# define EXTERN_C_END } +#else +# define EXTERN_C +# define EXTERN_C_BEGIN +# define EXTERN_C_END +#endif + +#endif diff --git a/libbanshee/engine/list.c b/libbanshee/engine/list.c new file mode 100644 index 00000000000..3972e2dd904 --- /dev/null +++ b/libbanshee/engine/list.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "list.h" +#include "util.h" + +struct list_node +{ + void *data; + struct list_node *sameregion next; +}; + +#define scan_node(b,var) for (var = b; var; var = var->next) + +struct list +{ + region sameregion r; + int length; + list_node sameregion head; +}; + +struct list *new_list(region r) +{ + struct list *result; + + assert(r); + + result = ralloc(r,struct list); + result->r = r; + result->length = 0; + result->head = NULL; + + return result; +} + +int list_size(struct list *l) +{ + return l->length; +} + +struct list *list_cons(void *data, struct list *l) +{ + list_node newnode = ralloc(l->r, struct list_node); + newnode->next = l->head; + newnode->data = data; + + l->head = newnode; + l->length++; + + return l; +} + +struct list *list_reverse(struct list *l) +{ + + if (list_empty(l)) + return l; + + else + { + list_node temp,reversed = NULL; + + while (l->head) + { + temp = l->head->next; + + l->head->next = reversed; + + reversed = l->head; + + l->head = temp; + } + + l->head = reversed; + return l; + } + +} + +bool list_empty(struct list *l) +{ + return (l->head == NULL); +} + +static inline list_node tail(list_node n) +{ + if (n == NULL) + return NULL; + else + { + list_node temp = NULL, + tail = NULL; + + scan_node(n,temp) + tail = temp; + + assert(tail && tail->next == NULL); + + return tail; + } +} + +struct list *list_append(struct list *a, struct list *b) +{ + list_node tl; + + assert( a && b ); + assert( a != b); + assert( ptr_eq(a->r,b->r) ); + + tl = tail(a->head); + + + if (! tl) + { + a->head = b->head; + a->length = b->length; + } + + else + { + tl->next = b->head; + a->length += b->length; + } + return a; +} + +struct list *list_app(struct list *l,app_fn app) +{ + list_node n = NULL; + + + assert(l); + + scan_node(l->head,n) + { + app(n->data); + } + return l; +} + +void *list_find(struct list *l,eq_fn eq) +{ + list_node n = NULL; + assert(l); + + scan_node(l->head,n) + { + if (eq(n->data)) + return n; + } + + return NULL; +} + +struct list *list_tail(struct list *l) +{ + l->length--; + l->head = l->head->next; + return l; +} + +void *list_head(struct list *l) +{ + return l->head->data; +} + +struct list *list_filter(region r,struct list *l,eq_fn eq) +{ + struct list *result; + list_node n = NULL; + assert(l); + + result = new_list(r); + + scan_node(l->head,n) + { + if (eq(n->data)) + list_cons(n->data,result); + } + + return result; +} + +struct list *list_keep(struct list *l, eq_fn eq) +{ + list_node prev, n; + assert(l); + + while (l->head && !eq(l->head->data)) + { + l->head = l->head->next; + } + + prev = l->head; + scan_node(l->head->next,n) + { + if (!eq(n->data)) + prev->next = n->next; + else prev = n; + } + return l; +} + +struct list *list_filter2(struct list *l,eq_fn eq) +{ + return list_filter(l->r,l,eq); +} + +struct list *list_copy(region r, struct list *l) +{ + + struct list *result; + list_node n = NULL; +#ifndef NDEBUG + int count = 0; +#endif + assert(l); + + result = new_list(r); + + scan_node(l->head,n) + { + list_cons(n->data,result); + assert(++count <= l->length); + } + + return list_reverse(result); +} +/* A Linked-List Memory Sort + by Philip J. Erdelsky + pje@acm.org + http://www.alumni.caltech.edu/~pje/ +*/ + +#include + +static void *sort_linked_list(void *p, unsigned index, + int (*compare)(const void *,const void *, comparator_fn), long *pcount, comparator_fn data) +{ + unsigned base; + unsigned long block_size; + + struct record + { + struct record *next[1]; + /* other members not directly accessed by this function */ + }; + + struct tape + { + struct record *first, *last; + unsigned long count; + } tape[4]; + + /* Distribute the records alternately to tape[0] and tape[1]. */ + + tape[0].count = tape[1].count = 0L; + tape[0].first = NULL; + base = 0; + while (p != NULL) + { + struct record *next = ((struct record *)p)->next[index]; + ((struct record *)p)->next[index] = tape[base].first; + tape[base].first = ((struct record *)p); + tape[base].count++; + p = next; + base ^= 1; + } + + /* If the list is empty or contains only a single record, then */ + /* tape[1].count == 0L and this part is vacuous. */ + + for (base = 0, block_size = 1L; tape[base+1].count != 0L; + base ^= 2, block_size <<= 1) + { + int dest; + struct tape *tape0, *tape1; + tape0 = tape + base; + tape1 = tape + base + 1; + dest = base ^ 2; + tape[dest].count = tape[dest+1].count = 0; + for (; tape0->count != 0; dest ^= 1) + { + unsigned long n0, n1; + struct tape *output_tape = tape + dest; + n0 = n1 = block_size; + while (1) + { + struct record *chosen_record; + struct tape *chosen_tape; + if (n0 == 0 || tape0->count == 0) + { + if (n1 == 0 || tape1->count == 0) + break; + chosen_tape = tape1; + n1--; + } + else if (n1 == 0 || tape1->count == 0) + { + chosen_tape = tape0; + n0--; + } + else if ((*compare)(tape0->first, tape1->first, data) > 0) + { + chosen_tape = tape1; + n1--; + } + else + { + chosen_tape = tape0; + n0--; + } + chosen_tape->count--; + chosen_record = chosen_tape->first; + chosen_tape->first = chosen_record->next[index]; + if (output_tape->count == 0) + output_tape->first = chosen_record; + else + output_tape->last->next[index] = chosen_record; + output_tape->last = chosen_record; + output_tape->count++; + } + } + } + + if (tape[base].count > 1L) + tape[base].last->next[index] = NULL; + if (pcount != NULL) + *pcount = tape[base].count; + return tape[base].first; +} + + + +static int compare(const void *node1, const void *node2, comparator_fn data) +{ + comparator_fn cmp = (comparator_fn) data; + return cmp(((struct list_node *)node1)->data, + ((struct list_node *)node2)->data); +} + +struct list *list_sort(struct list *l, comparator_fn cmp) +{ + long pcount; + l->head = sort_linked_list(l->head,1,compare,&pcount, cmp); + assert(pcount == l->length); + return l; +} + +struct list *list_merge(struct list *a,struct list *b, comparator_fn cmp) +{ + return list_sort( list_append(a,b),cmp); +} + +void list_scan(struct list *a,struct list_scanner *scan) +{ + scan->l = a; + scan->cur = a->head; +} + +bool list_next(struct list_scanner *scan, void **data) +{ + if (!scan->cur) + return FALSE; + else + { + if (data) + *data = scan->cur->data; + scan->cur = scan->cur->next; + return TRUE; + } +} + +void list_clear(struct list *l) +{ + l->head = NULL; + l->length = 0; +} + +bool list_member(struct list *l,void *data) +{ + list_node n = NULL; + scan_node(l->head,n) + { + if (n->data == data) + return TRUE; + } + return FALSE; +} + + +struct list *list_from_array(region r,void **data, int length) +{ + struct list *result = new_list(r); + int i; + + for (i = length -1; i >= 0; i--) + { + list_cons(data[i],result); + } + return result; +} + + + + + + + diff --git a/libbanshee/engine/list.h b/libbanshee/engine/list.h new file mode 100644 index 00000000000..1dfae50c0f1 --- /dev/null +++ b/libbanshee/engine/list.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef LIST_H +#define LIST_H + +#include +#include "bool.h" + +typedef void *list_data; +typedef void (*app_fn) (void *); +typedef bool (*eq_fn)(const void *); +typedef int (*comparator_fn)(const void *,const void *); + +struct list; + +typedef struct list_node *list_node; + +struct list_scanner +{ + struct list *l; + list_node cur; +}; /* Opaque type. Do not modify fields */ + + +struct list *new_list(region r); +int list_size(struct list *a); +struct list *list_cons(void *data, struct list *a); +struct list *list_append(struct list *a, struct list *b); +struct list *list_app(struct list *a,app_fn app); +void *list_find(struct list *a,eq_fn eq); +void *list_head(struct list *a); +struct list *list_tail(struct list *a); +struct list *list_filter(region r,struct list *a,eq_fn eq); +struct list *list_filter2(struct list *a,eq_fn eq); +struct list *list_keep(struct list *a,eq_fn eq); +struct list *list_copy(region r, struct list *a); +struct list *list_sort(struct list *a, comparator_fn cmp); +struct list *list_merge(struct list *a,struct list *b, comparator_fn cmp); +void list_scan(struct list *a,struct list_scanner *scan); +bool list_next(struct list_scanner *scan, void **data); +bool list_empty(struct list *a); +bool list_member(struct list *a, void *data); +void list_clear(struct list *a); +struct list *list_reverse(struct list *a); +struct list *list_from_array(region r,void **data, int length); + +#define DECLARE_OPAQUE_LIST(name,type) \ +typedef struct list_scanner name ## _scanner; \ +typedef void (* name ## _app_fn) (type); \ +typedef bool (* name ## _eq_fn) (const type); \ +typedef int (* name ## _comparator_fn)(const type,const type); \ +name new_ ## name(region r); \ +int name ## _length(name a); \ +name name ## _cons(type data, name a); \ +name name ## _append(name a, name b); \ +name name ## _app(name a, name ## _app_fn app); \ +type name ## _find(name a, name ## _eq_fn eq); \ +type name ## _head(name a); \ +name name ## _tail(name a); \ +name name ## _filter(region r,name a, name ## _eq_fn eq); \ +name name ## _filter2(name a, name ## _eq_fn eq); \ +name name ## _keep(name a, name ## _eq_fn eq); \ +name name ## _copy(region r, name a); \ +name name ## _sort(name a, name ## _comparator_fn cmp); \ +name name ## _merge(name a,name b, name ## _comparator_fn cmp); \ +void name ## _scan(name a, name ##_scanner *scan); \ +bool name ## _next(name ##_scanner *scan, type *data); \ +bool name ## _empty(name a); \ +void name ## _clear(name a); \ +bool name ## _member(name a, type data); \ +name name ## _reverse(name a); \ +name name ## _from_array(region r,type data[], int length); + +#define DECLARE_LIST(name,type) \ +typedef struct name ## _a *name; \ +typedef struct list_scanner name ## _scanner; \ +typedef void (* name ## _app_fn) (type); \ +typedef bool (* name ## _eq_fn) (const type); \ +typedef int (* name ## _comparator_fn)(const type,const type); \ +name new_ ## name(region r); \ +int name ## _length(name a); \ +name name ## _cons(type data, name a); \ +name name ## _append(name a, name b); \ +name name ## _app(name a, name ## _app_fn app); \ +type name ## _find(name a, name ## _eq_fn eq); \ +type name ## _head(name a); \ +name name ## _tail(name a); \ +name name ## _filter(region r,name a, name ## _eq_fn eq); \ +name name ## _filter2(name a, name ## _eq_fn eq); \ +name name ## _keep(name a, name ## _eq_fn eq); \ +name name ## _copy(region r, name a); \ +name name ## _sort(name a, name ## _comparator_fn cmp); \ +name name ## _merge(name a,name b, name ## _comparator_fn cmp); \ +void name ## _scan(name a, name ##_scanner *scan); \ +bool name ## _next(name ##_scanner *scan, type *data); \ +bool name ## _empty(name a); \ +void name ## _clear(name a); \ +bool name ## _member(name a, type data); \ +name name ## _reverse(name a); \ +name name ## _from_array(region r,type data[], int length); + +#define DEFINE_LIST(name,type) \ +name new_ ## name(region r) \ +{ \ + return (name)new_list(r); \ +} \ +int name ## _length(name a) \ +{ \ + return list_size((struct list *)a); \ +} \ +name name ## _cons(type data, name a) \ +{ \ + return (name)list_cons((void *)data,(struct list *) a ); \ +}\ +name name ## _append(name a, name b) \ +{ \ + return (name)list_append((struct list *)a,(struct list *)b); \ +} \ +name name ## _app(name a, name ## _app_fn app) \ +{ \ + return (name)list_app((struct list *) a, (app_fn) app); \ +} \ +type name ## _find(name a, name ## _eq_fn eq) \ +{ \ + return (type)list_find((struct list *)a, (eq_fn) eq); \ +} \ +name name ## _tail(name a) \ +{\ + return (name)list_tail((struct list *)a);\ +}\ +type name ## _head(name a) \ +{ \ + return (type)list_head((struct list *)a); \ +} \ +name name ## _filter(region r,name a, name ## _eq_fn eq) \ +{ \ + return (name)list_filter(r,(struct list *)a, (eq_fn) eq); \ +} \ +name name ## _keep(name a, name ## _eq_fn eq) \ +{ \ + return (name)list_keep((struct list *)a, (eq_fn) eq); \ +} \ +name name ## _filter2(name a, name ## _eq_fn eq) \ +{ \ + return (name)list_filter2((struct list *)a, (eq_fn) eq); \ +} \ +name name ## _copy(region r, name a) \ +{ \ + return (name)list_copy(r,(struct list *) a); \ +} \ +name name ## _sort(name a, name ## _comparator_fn cmp) \ +{ \ + return (name)list_sort((struct list *)a,(comparator_fn) cmp); \ +} \ +name name ## _merge(name a,name b, name ## _comparator_fn cmp) \ +{ \ + return (name)list_merge((struct list *)a,(struct list *)b,(comparator_fn)cmp); \ +} \ +void name ## _scan(name a, name ##_scanner *scan) \ +{ \ + list_scan((struct list *)a,(struct list_scanner *)scan);\ +}\ +bool name ## _next(name ##_scanner *scan, type *data) \ +{ \ + return list_next((struct list_scanner *)scan, (void **)data); \ +} \ +bool name ## _empty(name a) \ +{ \ + return list_empty((struct list *)a); \ +} \ +void name ## _clear(name a) \ +{ \ + list_clear((struct list *)a); \ +} \ +bool name ## _member(name a, type data) \ +{ \ + return list_member((struct list *)a,(void *)data); \ +} \ +name name ## _reverse(name a) \ +{\ + return (name)list_reverse((struct list *)a);\ +}\ +name name ## _from_array(region r,type data[], int length) \ +{\ + return (name)list_from_array(r,(void **)data,length); \ +}\ + +#endif /* LIST_H */ diff --git a/libbanshee/engine/malloc.c b/libbanshee/engine/malloc.c new file mode 100644 index 00000000000..84facdb0160 --- /dev/null +++ b/libbanshee/engine/malloc.c @@ -0,0 +1,5400 @@ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain. Use, modify, and + redistribute this code without permission or acknowledgement in any + way you wish. Send questions, comments, complaints, performance + data, etc to dl@cs.oswego.edu + +* VERSION 2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O), and link it into another program. All + of the compile-time options default to reasonable values for use on + most unix platforms. Compile -DWIN32 for reasonable defaults on windows. + You might later want to step through various compile-time and dynamic + tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.7.0.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. + +* Why use this malloc? + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and tunable. + Consistent balance across these factors results in a good general-purpose + allocator for malloc-intensive programs. + + The main properties of the algorithms are: + * For large (>= 512 bytes) requests, it is a pure best-fit allocator, + with ties normally decided via FIFO (i.e. least recently used). + * For small (<= 64 bytes by default) requests, it is a caching + allocator, that maintains pools of quickly recycled chunks. + * In between, and for combinations of large and small requests, it does + the best it can trying to meet both goals at once. + * For very large requests (>= 128KB by default), it relies on system + memory mapping facilities, if supported. + + For a longer but slightly out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + + You may already by default be using a C library containing a malloc + that is based on some version of this malloc (for example in + linux). You might still want to use the one in this file in order to + customize settings or to avoid overheads associated with library + versions. + +* Contents, described in more detail in "description of public routines" below. + + Standard (ANSI/SVID/...) functions: + malloc(size_t n); + calloc(size_t n_elements, size_t element_size); + free(Void_t* p); + realloc(Void_t* p, size_t n); + memalign(size_t alignment, size_t n); + valloc(size_t n); + mallinfo() + mallopt(int parameter_number, int parameter_value) + + Additional functions: + independent_calloc(size_t n_elements, size_t size, Void_t* chunks[]); + independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]); + pvalloc(size_t n); + cfree(Void_t* p); + malloc_trim(size_t pad); + malloc_usable_size(Void_t* p); + malloc_stats(); + +* Vital statistics: + + Supported pointer representation: 4 or 8 bytes + Supported size_t representation: 4 or 8 bytes + Note that size_t is allowed to be 4 bytes even if pointers are 8. + You can adjust this by defining INTERNAL_SIZE_T + + Alignment: 2 * sizeof(size_t) (default) + (i.e., 8 byte alignment with 4byte size_t). This suffices for + nearly all current machines and C compilers. However, you can + define MALLOC_ALIGNMENT to be wider than this if necessary. + + Minimum overhead per allocated chunk: 4 or 8 bytes + Each malloced chunk has a hidden word of overhead holding size + and status information. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) + 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) + + When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte + ptrs but 4 byte size) or 24 (for 8/8) additional bytes are + needed; 4 (8) for a trailing size field and 8 (16) bytes for + free list pointers. Thus, the minimum allocatable size is + 16/24/32 bytes. + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is 2 * + sizeof(size_t) bytes plus the remainder from a system page (the + minimal mmap unit); typically 4096 or 8192 bytes. + + Maximum allocated size: 4-byte size_t: 2^32 minus about two pages + 8-byte size_t: 2^64 minus about two pages + + It is assumed that (possibly signed) size_t values suffice to + represent chunk sizes. `Possibly signed' is due to the fact + that `size_t' may be defined on a system as either a signed or + an unsigned type. The ISO C standard says that it must be + unsigned, but a few systems are known not to adhere to this. + Additionally, even when size_t is unsigned, sbrk (which is by + default used to obtain memory from system) accepts signed + arguments, and may not be able to handle size_t-wide arguments + with negative sign bit. Generally, values that would + appear as negative after accounting for overhead and alignment + are supported only via mmap(), which does not have this + limitation. + + Requests for sizes outside the allowed range will perform an optional + failure action and then return null. (Requests may also + also fail because a system is out of memory.) + + Thread-safety: NOT thread-safe unless USE_MALLOC_LOCK defined + + When USE_MALLOC_LOCK is defined, wrappers are created to + surround every public call with either a pthread mutex or + a win32 spinlock (depending on WIN32). This is not + especially fast, and can be a major bottleneck. + It is designed only to provide minimal protection + in concurrent environments, and to provide a basis for + extensions. If you are using malloc in a concurrent program, + you would be far better off obtaining ptmalloc, which is + derived from a version of this malloc, and is well-tuned for + concurrent programs. (See http://www.malloc.de) + + Compliance: I believe it is compliant with the 1997 Single Unix Specification + (See http://www.opennc.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Synopsis of compile-time options: + + People have reported using previous versions of this malloc on all + versions of Unix, sometimes by tweaking some of the defines + below. It has been tested most extensively on Solaris and + Linux. It is also reported to work on WIN32 platforms. + People also report using it in stand-alone embedded systems. + + The implementation is in straight, hand-tuned ANSI C. It is not + at all modular. (Sorry!) It uses a lot of macros. To be at all + usable, this code should be compiled using an optimizing compiler + (for example gcc -O3) that can simplify expressions and control + paths. (FAQ: some macros import variables as arguments rather than + declare locals because people reported that some debuggers + otherwise get confused.) + + OPTION DEFAULT VALUE + + Compilation Environment options: + + __STD_C derived from C compiler defines + WIN32 NOT defined + HAVE_MEMCPY defined + USE_MEMCPY 1 if HAVE_MEMCPY is defined + HAVE_MMAP defined as 1 + MMAP_CLEARS 1 + HAVE_MREMAP 0 unless linux defined + malloc_getpagesize derived from system #includes, or 4096 if not + HAVE_USR_INCLUDE_MALLOC_H NOT defined + LACKS_UNISTD_H NOT defined unless WIN32 + LACKS_SYS_PARAM_H NOT defined unless WIN32 + LACKS_SYS_MMAN_H NOT defined unless WIN32 + + Changing default word sizes: + + INTERNAL_SIZE_T size_t + MALLOC_ALIGNMENT 2 * sizeof(INTERNAL_SIZE_T) + + Configuration and functionality options: + + USE_DL_PREFIX NOT defined + USE_PUBLIC_MALLOC_WRAPPERS NOT defined + USE_MALLOC_LOCK NOT defined + DEBUG NOT defined + REALLOC_ZERO_BYTES_FREES NOT defined + MALLOC_FAILURE_ACTION errno = ENOMEM, if __STD_C defined, else no-op + TRIM_FASTBINS 0 + + Options for customizing MORECORE: + + MORECORE sbrk + MORECORE_CONTIGUOUS 1 + MORECORE_CANNOT_TRIM NOT defined + MMAP_AS_MORECORE_SIZE (1024 * 1024) + + Tuning options that are also dynamically changeable via mallopt: + + DEFAULT_MXFAST 64 + DEFAULT_TRIM_THRESHOLD 128 * 1024 + DEFAULT_TOP_PAD 0 + DEFAULT_MMAP_THRESHOLD 128 * 1024 + DEFAULT_MMAP_MAX 65536 + + There are several other #defined constants and macros that you + probably don't want to touch unless you are extending or adapting malloc. +*/ + +/* + WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. +*/ + +/* #define WIN32 */ + +#ifdef WIN32 + +#define WIN32_LEAN_AND_MEAN +#include + +/* Win32 doesn't supply or need the following headers */ +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H + +/* Use the supplied emulation of sbrk */ +#define MORECORE sbrk +#define MORECORE_CONTIGUOUS 1 +#define MORECORE_FAILURE ((void*)(-1)) + +/* Use the supplied emulation of mmap and munmap */ +#define HAVE_MMAP 1 +#define MUNMAP_FAILURE (-1) +#define MMAP_CLEARS 1 + +/* These values don't really matter in windows mmap emulation */ +#define MAP_PRIVATE 1 +#define MAP_ANONYMOUS 2 +#define PROT_READ 1 +#define PROT_WRITE 2 + +/* Emulation functions defined at the end of this file */ + +/* If USE_MALLOC_LOCK, use supplied critical-section-based lock functions */ +#ifdef USE_MALLOC_LOCK +static int slwait(int *sl); +static int slrelease(int *sl); +#endif + +static long getpagesize(void); +static long getregionsize(void); +static void *sbrk(long size); +static void *mmap(void *ptr, long size, long prot, long type, long handle, long arg); +static long munmap(void *ptr, long size); + +static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed); +static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user); + +#endif + +/* + __STD_C should be nonzero if using ANSI-standard C compiler, a C++ + compiler, or a C compiler sufficiently close to ANSI to get away + with it. +*/ + +#ifndef __STD_C +#if defined(__STDC__) || defined(_cplusplus) +#define __STD_C 1 +#else +#define __STD_C 0 +#endif +#endif /*__STD_C*/ + + +/* + Void_t* is the pointer type that malloc should say it returns +*/ + +#ifndef Void_t +#if (__STD_C || defined(WIN32)) +#define Void_t void +#else +#define Void_t char +#endif +#endif /*Void_t*/ + +#if __STD_C +#include /* for size_t */ +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* define LACKS_UNISTD_H if your system does not have a . */ + +/* #define LACKS_UNISTD_H */ + +#ifndef LACKS_UNISTD_H +#include +#endif + +/* define LACKS_SYS_PARAM_H if your system does not have a . */ + +/* #define LACKS_SYS_PARAM_H */ + + +#include /* needed for malloc_stats */ +#include /* needed for optional MALLOC_FAILURE_ACTION */ + + +/* + Debugging: + + Because freed chunks may be overwritten with bookkeeping fields, this + malloc will often die when freed memory is overwritten by user + programs. This can be very effective (albeit in an annoying way) + in helping track down dangling pointers. + + If you compile with -DDEBUG, a number of assertion checks are + enabled that will catch more memory errors. You probably won't be + able to make much sense of the actual assertion errors, but they + should help you locate incorrectly overwritten memory. The + checking is fairly extensive, and will slow down execution + noticeably. Calling malloc_stats or mallinfo with DEBUG set will + attempt to check every non-mmapped allocated and free chunk in the + course of computing the summmaries. (By nature, mmapped regions + cannot be checked very much automatically.) + + Setting DEBUG may also be helpful if you are trying to modify + this code. The assertions in the check routines spell out in more + detail the assumptions and invariants underlying the algorithms. + + Setting DEBUG does NOT provide an automated mechanism for checking + that all accesses to malloced memory stay within their + bounds. However, there are several add-ons and adaptations of this + or other mallocs available that do this. +*/ + +#if DEBUG +#include +#else +#define assert(x) ((void)0) +#endif + + +/* + INTERNAL_SIZE_T is the word-size used for internal bookkeeping + of chunk sizes. + + The default version is the same as size_t. + + While not strictly necessary, it is best to define this as an + unsigned type, even if size_t is a signed type. This may avoid some + artificial size limitations on some systems. + + On a 64-bit machine, you may be able to reduce malloc overhead by + defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the + expense of not being able to handle more than 2^32 of malloced + space. If this limitation is acceptable, you are encouraged to set + this unless you are on a platform requiring 16byte alignments. In + this case the alignment requirements turn out to negate any + potential advantages of decreasing size_t word size. + + Implementors: Beware of the possible combinations of: + - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits, + and might be the same width as int or as long + - size_t might have different width and signedness as INTERNAL_SIZE_T + - int and long might be 32 or 64 bits, and might be the same width + To deal with this, most comparisons and difference computations + among INTERNAL_SIZE_Ts should cast them to unsigned long, being + aware of the fact that casting an unsigned int to a wider long does + not sign-extend. (This also makes checking for negative numbers + awkward.) Some of these casts result in harmless compiler warnings + on some systems. +*/ + +#ifndef INTERNAL_SIZE_T +#define INTERNAL_SIZE_T size_t +#endif + +/* The corresponding word size */ +#define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) + + +/* + MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks. + It must be a power of two at least 2 * SIZE_SZ, even on machines + for which smaller alignments would suffice. It may be defined as + larger than this though. Note however that code and data structures + are optimized for the case of 8-byte alignment. +*/ + + +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT (2 * SIZE_SZ) +#endif + +/* The corresponding bit mask value */ +#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) + + + +/* + REALLOC_ZERO_BYTES_FREES should be set if a call to + realloc with zero bytes should be the same as a call to free. + Some people think it should. Otherwise, since this malloc + returns a unique pointer for malloc(0), so does realloc(p, 0). +*/ + +/* #define REALLOC_ZERO_BYTES_FREES */ + +/* + TRIM_FASTBINS controls whether free() of a very small chunk can + immediately lead to trimming. Setting to true (1) can reduce memory + footprint, but will almost always slow down programs that use a lot + of small chunks. + + Define this only if you are willing to give up some speed to more + aggressively reduce system-level memory footprint when releasing + memory in programs that use many small chunks. You can get + essentially the same effect by setting MXFAST to 0, but this can + lead to even greater slowdowns in programs using many small chunks. + TRIM_FASTBINS is an in-between compile-time option, that disables + only those chunks bordering topmost memory from being placed in + fastbins. +*/ + +#ifndef TRIM_FASTBINS +#define TRIM_FASTBINS 0 +#endif + + +/* + USE_DL_PREFIX will prefix all public routines with the string 'dl'. + This is necessary when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. +*/ + +/* #define USE_DL_PREFIX */ + + +/* + USE_MALLOC_LOCK causes wrapper functions to surround each + callable routine with pthread mutex lock/unlock. + + USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined +*/ + + +/* #define USE_MALLOC_LOCK */ + + +/* + If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is + actually a wrapper function that first calls MALLOC_PREACTION, then + calls the internal routine, and follows it with + MALLOC_POSTACTION. This is needed for locking, but you can also use + this, without USE_MALLOC_LOCK, for purposes of interception, + instrumentation, etc. It is a sad fact that using wrappers often + noticeably degrades performance of malloc-intensive programs. +*/ + +#ifdef USE_MALLOC_LOCK +#define USE_PUBLIC_MALLOC_WRAPPERS +#else +/* #define USE_PUBLIC_MALLOC_WRAPPERS */ +#endif + + +/* + Two-phase name translation. + All of the actual routines are given mangled names. + When wrappers are used, they become the public callable versions. + When DL_PREFIX is used, the callable names are prefixed. +*/ + +#ifndef USE_PUBLIC_MALLOC_WRAPPERS +#define cALLOc public_cALLOc +#define fREe public_fREe +#define cFREe public_cFREe +#define mALLOc public_mALLOc +#define mEMALIGn public_mEMALIGn +#define rEALLOc public_rEALLOc +#define vALLOc public_vALLOc +#define pVALLOc public_pVALLOc +#define mALLINFo public_mALLINFo +#define mALLOPt public_mALLOPt +#define mTRIm public_mTRIm +#define mSTATs public_mSTATs +#define mUSABLe public_mUSABLe +#define iCALLOc public_iCALLOc +#define iCOMALLOc public_iCOMALLOc +#endif + +#ifdef USE_DL_PREFIX +#define public_cALLOc dlcalloc +#define public_fREe dlfree +#define public_cFREe dlcfree +#define public_mALLOc dlmalloc +#define public_mEMALIGn dlmemalign +#define public_rEALLOc dlrealloc +#define public_vALLOc dlvalloc +#define public_pVALLOc dlpvalloc +#define public_mALLINFo dlmallinfo +#define public_mALLOPt dlmallopt +#define public_mTRIm dlmalloc_trim +#define public_mSTATs dlmalloc_stats +#define public_mUSABLe dlmalloc_usable_size +#define public_iCALLOc dlindependent_calloc +#define public_iCOMALLOc dlindependent_comalloc +#else /* USE_DL_PREFIX */ +#define public_cALLOc calloc +#define public_fREe free +#define public_cFREe cfree +#define public_mALLOc malloc +#define public_mEMALIGn memalign +#define public_rEALLOc realloc +#define public_vALLOc valloc +#define public_pVALLOc pvalloc +#define public_mALLINFo mallinfo +#define public_mALLOPt mallopt +#define public_mTRIm malloc_trim +#define public_mSTATs malloc_stats +#define public_mUSABLe malloc_usable_size +#define public_iCALLOc independent_calloc +#define public_iCOMALLOc independent_comalloc +#endif /* USE_DL_PREFIX */ + + +/* + HAVE_MEMCPY should be defined if you are not otherwise using + ANSI STD C, but still have memcpy and memset in your C library + and want to use them in calloc and realloc. Otherwise simple + macro versions are defined below. + + USE_MEMCPY should be defined as 1 if you actually want to + have memset and memcpy called. People report that the macro + versions are faster than libc versions on some systems. + + Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks + (of <= 36 bytes) are manually unrolled in realloc and calloc. +*/ + +#define HAVE_MEMCPY + +#ifndef USE_MEMCPY +#ifdef HAVE_MEMCPY +#define USE_MEMCPY 1 +#else +#define USE_MEMCPY 0 +#endif +#endif + + +#if (__STD_C || defined(HAVE_MEMCPY)) + +#ifdef WIN32 +/* On Win32 memset and memcpy are already declared in windows.h */ +#else +#if __STD_C +void* memset(void*, int, size_t); +void* memcpy(void*, const void*, size_t); +#else +Void_t* memset(); +Void_t* memcpy(); +#endif +#endif +#endif + +/* + MALLOC_FAILURE_ACTION is the action to take before "return 0" when + malloc fails to be able to return memory, either because memory is + exhausted or because of illegal arguments. + + By default, sets errno if running on STD_C platform, else does nothing. +*/ + +#ifndef MALLOC_FAILURE_ACTION +#if __STD_C +#define MALLOC_FAILURE_ACTION \ + errno = ENOMEM; + +#else +#define MALLOC_FAILURE_ACTION +#endif +#endif + +/* + MORECORE-related declarations. By default, rely on sbrk +*/ + + +#ifdef LACKS_UNISTD_H +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#if __STD_C +extern Void_t* sbrk(ptrdiff_t); +#else +extern Void_t* sbrk(); +#endif +#endif +#endif + +/* + MORECORE is the name of the routine to call to obtain more memory + from the system. See below for general guidance on writing + alternative MORECORE functions, as well as a version for WIN32 and a + sample version for pre-OSX macos. +*/ + +#ifndef MORECORE +#define MORECORE sbrk +#endif + +/* + MORECORE_FAILURE is the value returned upon failure of MORECORE + as well as mmap. Since it cannot be an otherwise valid memory address, + and must reflect values of standard sys calls, you probably ought not + try to redefine it. +*/ + +#ifndef MORECORE_FAILURE +#define MORECORE_FAILURE (-1) +#endif + +/* + If MORECORE_CONTIGUOUS is true, take advantage of fact that + consecutive calls to MORECORE with positive arguments always return + contiguous increasing addresses. This is true of unix sbrk. Even + if not defined, when regions happen to be contiguous, malloc will + permit allocations spanning regions obtained from different + calls. But defining this when applicable enables some stronger + consistency checks and space efficiencies. +*/ + +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif + +/* + Define MORECORE_CANNOT_TRIM if your version of MORECORE + cannot release space back to the system when given negative + arguments. This is generally necessary only if you are using + a hand-crafted MORECORE function that cannot handle negative arguments. +*/ + +/* #define MORECORE_CANNOT_TRIM */ + + +/* + Define HAVE_MMAP as true to optionally make malloc() use mmap() to + allocate very large blocks. These will be returned to the + operating system immediately after a free(). Also, if mmap + is available, it is used as a backup strategy in cases where + MORECORE fails to provide space from system. + + This malloc is best tuned to work with mmap for large requests. + If you do not have mmap, operations involving very large chunks (1MB + or so) may be slower than you'd like. +*/ + +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 + +/* + Standard unix mmap using /dev/zero clears memory so calloc doesn't + need to. +*/ + +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif + +#else /* no mmap */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 0 +#endif +#endif + + +/* + MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if + sbrk fails, and mmap is used as a backup (which is done only if + HAVE_MMAP). The value must be a multiple of page size. This + backup strategy generally applies only when systems have "holes" in + address space, so sbrk cannot perform contiguous expansion, but + there is still space available on system. On systems for which + this is known to be useful (i.e. most linux kernels), this occurs + only when programs allocate huge amounts of memory. Between this, + and the fact that mmap regions tend to be limited, the size should + be large, to avoid too many mmap calls and thus avoid running out + of kernel resources. +*/ + +#ifndef MMAP_AS_MORECORE_SIZE +#define MMAP_AS_MORECORE_SIZE (1024 * 1024) +#endif + +/* + Define HAVE_MREMAP to make realloc() use mremap() to re-allocate + large blocks. This is currently only possible on Linux with + kernel versions newer than 1.3.77. +*/ + +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else +#define HAVE_MREMAP 0 +#endif + +#endif /* HAVE_MMAP */ + + +/* + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. Note that this value is + cached during initialization into a field of malloc_state. So even + if malloc_getpagesize is a function, it is only called once. + + The following mechanics for getpagesize were adapted from bsd/gnu + getpagesize.h. If none of the system-probes here apply, a value of + 4096 is used, which should be OK: If they don't apply, then using + the actual value probably doesn't impact performance. +*/ + + +#ifndef malloc_getpagesize + +#ifndef LACKS_UNISTD_H +# include +#endif + +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif + +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 /* use supplied emulation of getpagesize */ +# define malloc_getpagesize getpagesize() +# else +# ifndef LACKS_SYS_PARAM_H +# include +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else /* just guess */ +# define malloc_getpagesize (4096) +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif + +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any SVID/XPG compliant system that has + a /usr/include/malloc.h defining struct mallinfo. (If you'd like to + install such a thing yourself, cut out the preliminary declarations + as described above and below and save them in a malloc.h file. But + there's no compelling reason to bother to do this.) + + The main declaration needed is the mallinfo struct that is returned + (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a + bunch of field that are not even meaningful in this version of + malloc. These fields are are instead filled by mallinfo() with + other numbers that might be of interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else an SVID2/XPG2 compliant + version is declared below. These must be precisely the same for + mallinfo() to work. The original SVID version of this struct, + defined on most systems with mallinfo, declares all fields as + ints. But some others define as unsigned long. If your system + defines the fields using a type of different width than listed here, + you must #include your system version and #define + HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else + +/* SVID2/XPG mallinfo structure */ + +struct mallinfo { + int arena; /* non-mmapped space allocated from system */ + int ordblks; /* number of free chunks */ + int smblks; /* number of fastbin blocks */ + int hblks; /* number of mmapped regions */ + int hblkhd; /* space in mmapped regions */ + int usmblks; /* maximum total allocated space */ + int fsmblks; /* space available in freed fastbin blocks */ + int uordblks; /* total allocated space */ + int fordblks; /* total free space */ + int keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +/* + SVID/XPG defines four standard parameter numbers for mallopt, + normally defined in malloc.h. Only one of these (M_MXFAST) is used + in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply, + so setting them has no effect. But this malloc also supports other + options in mallopt described below. +*/ +#endif + + +/* ---------- description of public routines ------------ */ + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or null + if no space is available. Additionally, on failure, errno is + set to ENOMEM on ANSI C systems. + + If n is zero, malloc returns a minumum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit + systems.) On most systems, size_t is an unsigned type, so calls + with negative arguments are interpreted as requests for huge amounts + of space, which will often fail. The maximum supported value of n + differs across systems, but is in all cases less than the maximum + representable value of a size_t. +*/ +#if __STD_C +Void_t* public_mALLOc(size_t); +#else +Void_t* public_mALLOc(); +#endif + +/* + free(Void_t* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. It can have arbitrary (i.e., bad!) + effects if p has already been freed. + + Unless disabled (using mallopt), freeing very large spaces will + when possible, automatically trigger operations that give + back unused memory to the system, thus reducing program footprint. +*/ +#if __STD_C +void public_fREe(Void_t*); +#else +void public_fREe(); +#endif + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +#if __STD_C +Void_t* public_cALLOc(size_t, size_t); +#else +Void_t* public_cALLOc(); +#endif + +/* + realloc(Void_t* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p when possible, otherwise it employs the + equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. Unless the #define + REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of + zero (re)allocates a minimum-sized chunk. + + Large chunks that were internally obtained via mmap will always + be reallocated using malloc-copy-free sequences unless + the system supports MREMAP (currently only linux). + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ +#if __STD_C +Void_t* public_rEALLOc(Void_t*, size_t); +#else +Void_t* public_rEALLOc(); +#endif + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +#if __STD_C +Void_t* public_mEMALIGn(size_t, size_t); +#else +Void_t* public_mEMALIGn(); +#endif + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +#if __STD_C +Void_t* public_vALLOc(size_t); +#else +Void_t* public_vALLOc(); +#endif + + + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. Only one of these (M_MXFAST) is used + in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply, + so setting them has no effect. But this malloc also supports four + other options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_MXFAST 1 64 0-80 (0 disables fastbins) + M_TRIM_THRESHOLD -1 128*1024 any (-1U disables trimming) + M_TOP_PAD -2 0 any + M_MMAP_THRESHOLD -3 128*1024 any (or 0 if no MMAP support) + M_MMAP_MAX -4 65536 any (0 disables use of mmap) +*/ +#if __STD_C +int public_mALLOPt(int, int); +#else +int public_mALLOPt(); +#endif + + +/* + mallinfo() + Returns (by copy) a struct containing various summary statistics: + + arena: current total non-mmapped bytes allocated from system + ordblks: the number of free chunks + smblks: the number of fastbin blocks (i.e., small chunks that + have been freed but not use resused or consolidated) + hblks: current number of mmapped regions + hblkhd: total bytes held in mmapped regions + usmblks: the maximum total allocated space. This will be greater + than current total if trimming has occurred. + fsmblks: total bytes held in fastbin blocks + uordblks: current total allocated space (normal or mmapped) + fordblks: total free space + keepcost: the maximum number of bytes that could ideally be released + back to system via malloc_trim. ("ideally" means that + it ignores page restrictions etc.) + + Because these fields are ints, but internal bookkeeping may + be kept as longs, the reported values may wrap around zero and + thus be inaccurate. +*/ +#if __STD_C +struct mallinfo public_mALLINFo(void); +#else +struct mallinfo public_mALLINFo(); +#endif + +/* + independent_calloc(size_t n_elements, size_t element_size, Void_t* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use regular calloc and assign pointers into this + space to represent elements. (In this case though, you cannot + independently free elements.) + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +#if __STD_C +Void_t** public_iCALLOc(size_t, size_t, Void_t**); +#else +Void_t** public_iCALLOc(); +#endif + +/* + independent_comalloc(size_t n_elements, size_t sizes[], Void_t* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use a single regular malloc, and assign pointers at + particular offsets in the aggregate space. (In this case though, you + cannot independently free elements.) + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +#if __STD_C +Void_t** public_iCOMALLOc(size_t, size_t*, Void_t**); +#else +Void_t** public_iCOMALLOc(); +#endif + + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +#if __STD_C +Void_t* public_pVALLOc(size_t); +#else +Void_t* public_pVALLOc(); +#endif + +/* + cfree(Void_t* p); + Equivalent to free(p). + + cfree is needed/defined on some systems that pair it with calloc, + for odd historical reasons (such as: cfree is used in example + code in the first edition of K&R). +*/ +#if __STD_C +void public_cFREe(Void_t*); +#else +void public_cFREe(); +#endif + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative + arguments to sbrk) if there is unused memory at the `high' end of + the malloc pool. You can call this after freeing large blocks of + memory to potentially reduce the system-level memory requirements + of a program. However, it cannot guarantee to reduce memory. Under + some allocation patterns, some large free blocks of memory will be + locked between two used chunks, so they cannot be given back to + the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, + only the minimum amount of memory to maintain internal data + structures will be left (one page or less). Non-zero arguments + can be supplied to maintain enough trailing space to service + future expected allocations without having to re-obtain memory + from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. + On systems that do not support "negative sbrks", it will always + rreturn 0. +*/ +#if __STD_C +int public_mTRIm(size_t); +#else +int public_mTRIm(); +#endif + +/* + malloc_usable_size(Void_t* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); + +*/ +#if __STD_C +size_t public_mUSABLe(Void_t*); +#else +size_t public_mUSABLe(); +#endif + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. + +*/ +#if __STD_C +void public_mSTATs(); +#else +void public_mSTATs(); +#endif + +/* mallopt tuning options */ + +/* + M_MXFAST is the maximum request size used for "fastbins", special bins + that hold returned chunks without consolidating their spaces. This + enables future requests for chunks of the same size to be handled + very quickly, but can increase fragmentation, and thus increase the + overall memory footprint of a program. + + This malloc manages fastbins very conservatively yet still + efficiently, so fragmentation is rarely a problem for values less + than or equal to the default. The maximum supported value of MXFAST + is 80. You wouldn't want it any higher than this anyway. Fastbins + are designed especially for use with many small structs, objects or + strings -- the default handles structs/objects/arrays with sizes up + to 8 4byte fields, or small strings representing words, tokens, + etc. Using fastbins for larger objects normally worsens + fragmentation without improving speed. + + M_MXFAST is set in REQUEST size units. It is internally used in + chunksize units, which adds padding and alignment. You can reduce + M_MXFAST to 0 to disable all use of fastbins. This causes the malloc + algorithm to be a closer approximation of fifo-best-fit in all cases, + not just for larger requests, but will generally cause it to be + slower. +*/ + + +/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */ +#ifndef M_MXFAST +#define M_MXFAST 1 +#endif + +#ifndef DEFAULT_MXFAST +#define DEFAULT_MXFAST 64 +#endif + + +/* + M_TRIM_THRESHOLD is the maximum amount of unused top-most memory + to keep before releasing via malloc_trim in free(). + + Automatic trimming is mainly useful in long-lived programs. + Because trimming via sbrk can be slow on some systems, and can + sometimes be wasteful (in cases where programs immediately + afterward allocate more large chunks) the value should be high + enough so that your overall system performance would improve by + releasing this much memory. + + The trim threshold and the mmap control parameters (see below) + can be traded off with one another. Trimming and mmapping are + two different ways of releasing unused memory back to the + system. Between these two, it is often possible to keep + system-level demands of a long-lived program down to a bare + minimum. For example, in one test suite of sessions measuring + the XF86 X server on Linux, using a trim threshold of 128K and a + mmap threshold of 192K led to near-minimal long term resource + consumption. + + If you are using this malloc in a long-lived program, it should + pay to experiment with these values. As a rough guide, you + might set to a value close to the average size of a process + (program) running on your system. Releasing this much memory + would allow such a process to run in memory. Generally, it's + worth it to tune for trimming rather tham memory mapping when a + program undergoes phases where several large chunks are + allocated and released in ways that can reuse each other's + storage, perhaps mixed with phases where there are no such + chunks at all. And in well-behaved long-lived programs, + controlling release of large blocks via trimming versus mapping + is usually faster. + + However, in most programs, these parameters serve mainly as + protection against the system-level effects of carrying around + massive amounts of unneeded memory. Since frequent calls to + sbrk, mmap, and munmap otherwise degrade performance, the default + parameters are set to relatively high values that serve only as + safeguards. + + The trim value It must be greater than page size to have any useful + effect. To disable trimming completely, you can set to + (unsigned long)(-1) + + Trim settings interact with fastbin (MXFAST) settings: Unless + TRIM_FASTBINS is defined, automatic trimming never takes place upon + freeing a chunk with size less than or equal to MXFAST. Trimming is + instead delayed until subsequent freeing of larger chunks. However, + you can still force an attempted trim by calling malloc_trim. + + Also, trimming is not generally possible in cases where + the main arena is obtained via mmap. + + Note that the trick some people use of mallocing a huge space and + then freeing it at program startup, in an attempt to reserve system + memory, doesn't have the intended effect under automatic trimming, + since that memory will immediately be returned to the system. +*/ + +#define M_TRIM_THRESHOLD -1 + +#ifndef DEFAULT_TRIM_THRESHOLD +#define DEFAULT_TRIM_THRESHOLD (128 * 1024) +#endif + +/* + M_TOP_PAD is the amount of extra `padding' space to allocate or + retain whenever sbrk is called. It is used in two ways internally: + + * When sbrk is called to extend the top of the arena to satisfy + a new malloc request, this much padding is added to the sbrk + request. + + * When malloc_trim is called automatically from free(), + it is used as the `pad' argument. + + In both cases, the actual amount of padding is rounded + so that the end of the arena is always a system page boundary. + + The main reason for using padding is to avoid calling sbrk so + often. Having even a small pad greatly reduces the likelihood + that nearly every malloc request during program start-up (or + after trimming) will invoke sbrk, which needlessly wastes + time. + + Automatic rounding-up to page-size units is normally sufficient + to avoid measurable overhead, so the default is 0. However, in + systems where sbrk is relatively slow, it can pay to increase + this value, at the expense of carrying around more memory than + the program needs. +*/ + +#define M_TOP_PAD -2 + +#ifndef DEFAULT_TOP_PAD +#define DEFAULT_TOP_PAD (0) +#endif + +/* + M_MMAP_THRESHOLD is the request size threshold for using mmap() + to service a request. Requests of at least this size that cannot + be allocated using already-existing space will be serviced via mmap. + (If enough normal freed space already exists it is used instead.) + + Using mmap segregates relatively large chunks of memory so that + they can be individually obtained and released from the host + system. A request serviced through mmap is never reused by any + other request (at least not directly; the system may just so + happen to remap successive requests to the same locations). + + Segregating space in this way has the benefits that: + + 1. Mmapped space can ALWAYS be individually released back + to the system, which helps keep the system level memory + demands of a long-lived program low. + 2. Mapped memory can never become `locked' between + other chunks, as can happen with normally allocated chunks, which + means that even trimming via malloc_trim would not release them. + 3. On some systems with "holes" in address spaces, mmap can obtain + memory that sbrk cannot. + + However, it has the disadvantages that: + + 1. The space cannot be reclaimed, consolidated, and then + used to service later requests, as happens with normal chunks. + 2. It can lead to more wastage because of mmap page alignment + requirements + 3. It causes malloc performance to be more dependent on host + system memory management support routines which may vary in + implementation quality and may impose arbitrary + limitations. Generally, servicing a request via normal + malloc steps is faster than going through a system's mmap. + + The advantages of mmap nearly always outweigh disadvantages for + "large" chunks, but the value of "large" varies across systems. The + default is an empirically derived value that works well in most + systems. +*/ + +#define M_MMAP_THRESHOLD -3 + +#ifndef DEFAULT_MMAP_THRESHOLD +#define DEFAULT_MMAP_THRESHOLD (128 * 1024) +#endif + +/* + M_MMAP_MAX is the maximum number of requests to simultaneously + service using mmap. This parameter exists because +. Some systems have a limited number of internal tables for + use by mmap, and using more than a few of them may degrade + performance. + + The default is set to a value that serves only as a safeguard. + Setting to 0 disables use of mmap for servicing large requests. If + HAVE_MMAP is not set, the default value is 0, and attempts to set it + to non-zero values in mallopt will fail. +*/ + +#define M_MMAP_MAX -4 + +#ifndef DEFAULT_MMAP_MAX +#if HAVE_MMAP +#define DEFAULT_MMAP_MAX (65536) +#else +#define DEFAULT_MMAP_MAX (0) +#endif +#endif + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/* --------------------- public wrappers ---------------------- */ + +#ifdef USE_PUBLIC_MALLOC_WRAPPERS + +/* Declare all routines as internal */ +#if __STD_C +static Void_t* mALLOc(size_t); +static void fREe(Void_t*); +static Void_t* rEALLOc(Void_t*, size_t); +static Void_t* mEMALIGn(size_t, size_t); +static Void_t* vALLOc(size_t); +static Void_t* pVALLOc(size_t); +static Void_t* cALLOc(size_t, size_t); +static Void_t** iCALLOc(size_t, size_t, Void_t**); +static Void_t** iCOMALLOc(size_t, size_t*, Void_t**); +static void cFREe(Void_t*); +static int mTRIm(size_t); +static size_t mUSABLe(Void_t*); +static void mSTATs(); +static int mALLOPt(int, int); +static struct mallinfo mALLINFo(void); +#else +static Void_t* mALLOc(); +static void fREe(); +static Void_t* rEALLOc(); +static Void_t* mEMALIGn(); +static Void_t* vALLOc(); +static Void_t* pVALLOc(); +static Void_t* cALLOc(); +static Void_t** iCALLOc(); +static Void_t** iCOMALLOc(); +static void cFREe(); +static int mTRIm(); +static size_t mUSABLe(); +static void mSTATs(); +static int mALLOPt(); +static struct mallinfo mALLINFo(); +#endif + +/* + MALLOC_PREACTION and MALLOC_POSTACTION should be + defined to return 0 on success, and nonzero on failure. + The return value of MALLOC_POSTACTION is currently ignored + in wrapper functions since there is no reasonable default + action to take on failure. +*/ + + +#ifdef USE_MALLOC_LOCK + +#ifdef WIN32 + +static int mALLOC_MUTEx; +#define MALLOC_PREACTION slwait(&mALLOC_MUTEx) +#define MALLOC_POSTACTION slrelease(&mALLOC_MUTEx) + +#else + +#include + +static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER; + +#define MALLOC_PREACTION pthread_mutex_lock(&mALLOC_MUTEx) +#define MALLOC_POSTACTION pthread_mutex_unlock(&mALLOC_MUTEx) + +#endif /* USE_MALLOC_LOCK */ + +#else + +/* Substitute anything you like for these */ + +#define MALLOC_PREACTION (0) +#define MALLOC_POSTACTION (0) + +#endif + +Void_t* public_mALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = mALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +void public_fREe(Void_t* m) { + if (MALLOC_PREACTION != 0) { + return; + } + fREe(m); + if (MALLOC_POSTACTION != 0) { + } +} + +Void_t* public_rEALLOc(Void_t* m, size_t bytes) { + if (MALLOC_PREACTION != 0) { + return 0; + } + m = rEALLOc(m, bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_mEMALIGn(size_t alignment, size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = mEMALIGn(alignment, bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_vALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = vALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_pVALLOc(size_t bytes) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = pVALLOc(bytes); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t* public_cALLOc(size_t n, size_t elem_size) { + Void_t* m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = cALLOc(n, elem_size); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + + +Void_t** public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks) { + Void_t** m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = iCALLOc(n, elem_size, chunks); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +Void_t** public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks) { + Void_t** m; + if (MALLOC_PREACTION != 0) { + return 0; + } + m = iCOMALLOc(n, sizes, chunks); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +void public_cFREe(Void_t* m) { + if (MALLOC_PREACTION != 0) { + return; + } + cFREe(m); + if (MALLOC_POSTACTION != 0) { + } +} + +int public_mTRIm(size_t s) { + int result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mTRIm(s); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + +size_t public_mUSABLe(Void_t* m) { + size_t result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mUSABLe(m); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + +void public_mSTATs() { + if (MALLOC_PREACTION != 0) { + return; + } + mSTATs(); + if (MALLOC_POSTACTION != 0) { + } +} + +struct mallinfo public_mALLINFo() { + struct mallinfo m; + if (MALLOC_PREACTION != 0) { + struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + return nm; + } + m = mALLINFo(); + if (MALLOC_POSTACTION != 0) { + } + return m; +} + +int public_mALLOPt(int p, int v) { + int result; + if (MALLOC_PREACTION != 0) { + return 0; + } + result = mALLOPt(p, v); + if (MALLOC_POSTACTION != 0) { + } + return result; +} + +#endif + + + +/* ------------- Optional versions of memcopy ---------------- */ + + +#if USE_MEMCPY + +/* + Note: memcpy is ONLY invoked with non-overlapping regions, + so the (usually slower) memmove is not needed. +*/ + +#define MALLOC_COPY(dest, src, nbytes) memcpy(dest, src, nbytes) +#define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes) + +#else /* !USE_MEMCPY */ + +/* Use Duff's device for good zeroing/copying performance. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ + unsigned long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \ + long mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mzp++ = 0; \ + case 7: *mzp++ = 0; \ + case 6: *mzp++ = 0; \ + case 5: *mzp++ = 0; \ + case 4: *mzp++ = 0; \ + case 3: *mzp++ = 0; \ + case 2: *mzp++ = 0; \ + case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +define MALLOC_COPY(dest,src,nbytes) \ +do { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ + unsigned long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \ + long mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mcdst++ = *mcsrc++; \ + case 7: *mcdst++ = *mcsrc++; \ + case 6: *mcdst++ = *mcsrc++; \ + case 5: *mcdst++ = *mcsrc++; \ + case 4: *mcdst++ = *mcsrc++; \ + case 3: *mcdst++ = *mcsrc++; \ + case 2: *mcdst++ = *mcsrc++; \ + case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#endif + +/* ------------------ MMAP support ------------------ */ + + +#if HAVE_MMAP + +#include +#ifndef LACKS_SYS_MMAN_H +#include +#endif + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + +/* + Nearly all versions of mmap support MAP_ANONYMOUS, + so the following is unlikely to be needed, but is + supplied just in case. +*/ + +#ifndef MAP_ANONYMOUS + +static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ + +#define MMAP(addr, size, prot, flags) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) : \ + mmap((addr), (size), (prot), (flags), dev_zero_fd, 0)) + +#else + +#define MMAP(addr, size, prot, flags) \ + (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0)) + +#endif + + +#endif /* HAVE_MMAP */ + + +/* + ----------------------- Chunk representations ----------------------- +*/ + + +/* + This struct declaration is misleading (but accurate and necessary). + It declares a "view" into memory allowing access to necessary + fields at known offsets from a given base. See explanation below. +*/ + +struct malloc_chunk { + + INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ + INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ + + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + + +typedef struct malloc_chunk* mchunkptr; + +/* + malloc_chunk details: + + (The following includes lightly edited explanations by Colin Plumb.) + + Chunks of memory are maintained using a `boundary tag' method as + described in e.g., Knuth or Standish. (See the paper by Paul + Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a + survey of such techniques.) Sizes of free chunks are stored both + in the front of each chunk and at the end. This makes + consolidating fragmented chunks into bigger chunks very fast. The + size fields also hold bits representing whether chunks are free or + in use. + + An allocated chunk looks like this: + + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk, if allocated | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | User data starts here... . + . . + . (malloc_usable_space() bytes) . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Where "chunk" is the front of the chunk for the purpose of most of + the malloc code, but "mem" is the pointer that is returned to the + user. "Nextchunk" is the beginning of the next contiguous chunk. + + Chunks always begin on even word boundries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + Free chunks are stored in circular doubly-linked lists, and look like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The P (PREV_INUSE) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, + preventing access to non-existent (or non-owned) memory. If + prev_inuse is set for any given chunk, then you CANNOT determine + the size of the previous chunk, and might even get a memory + addressing fault when trying to do so. + + Note that the `foot' of the current chunk is actually represented + as the prev_size of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The two exceptions to all this are + + 1. The special chunk `top' doesn't bother using the + trailing size field since there is no next contiguous chunk + that would have to index off it. After initialization, `top' + is forced to always exist. If it would become less than + MINSIZE bytes long, it is replenished. + + 2. Chunks allocated via mmap, which have the second-lowest-order + bit (IS_MMAPPED) set in their size fields. Because they are + allocated one-by-one, each must contain its own trailing size field. + +*/ + +/* + ---------- Size and alignment checks and conversions ---------- +*/ + +/* conversion from malloc headers to user pointers, and back */ + +#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) + +/* The smallest possible chunk */ +#define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk)) + +/* The smallest size we can malloc is an aligned minimal chunk */ + +#define MINSIZE \ + (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)) + +/* Check if m has acceptable alignment */ + +#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) + + +/* + Check if a request is so large that it would wrap around zero when + padded and aligned. To simplify some other code, the bound is made + low enough so that adding MINSIZE will also not wrap around sero. +*/ + +#define REQUEST_OUT_OF_RANGE(req) \ + ((unsigned long)(req) >= \ + (unsigned long)(INTERNAL_SIZE_T)(-2 * MINSIZE)) + +/* pad request bytes into a usable size -- internal version */ + +#define request2size(req) \ + (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ + MINSIZE : \ + ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) + +/* Same, except also perform argument check */ + +#define checked_request2size(req, sz) \ + if (REQUEST_OUT_OF_RANGE(req)) { \ + MALLOC_FAILURE_ACTION; \ + return 0; \ + } \ + (sz) = request2size(req); + +/* + --------------- Physical chunk operations --------------- +*/ + + +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ +#define PREV_INUSE 0x1 + +/* extract inuse bit of previous chunk */ +#define prev_inuse(p) ((p)->size & PREV_INUSE) + + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ +#define IS_MMAPPED 0x2 + +/* check for mmap()'ed chunk */ +#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) + +/* + Bits to mask off when extracting size + + Note: IS_MMAPPED is intentionally not masked off from size field in + macros for which mmapped chunks should never be seen. This should + cause helpful core dumps to occur if it is tried by accident by + people extending or adapting this malloc. +*/ +#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) + +/* Get size, ignoring use bits */ +#define chunksize(p) ((p)->size & ~(SIZE_BITS)) + + +/* Ptr to next physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) + +/* Ptr to previous physical malloc_chunk */ +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) + +/* Treat space at ptr + offset as a chunk */ +#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) + +/* extract p's inuse bit */ +#define inuse(p)\ +((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) + +/* set/clear chunk as being inuse without otherwise disturbing */ +#define set_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE + +#define clear_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) + + +/* check/set/clear inuse bits in known places */ +#define inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) + +#define set_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) + +#define clear_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) + + +/* Set size at head, without disturbing its use bit */ +#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) + +/* Set size/use field */ +#define set_head(p, s) ((p)->size = (s)) + +/* Set size at footer (only when chunk is not in use) */ +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) + + +/* + -------------------- Internal data structures -------------------- + + All internal state is held in an instance of malloc_state defined + below. There are no other static variables, except in two optional + cases: + * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared above. + * If HAVE_MMAP is true, but mmap doesn't support + MAP_ANONYMOUS, a dummy file descriptor for mmap. + + Beware of lots of tricks that minimize the total bookkeeping space + requirements. The result is a little over 1K bytes (for 4byte + pointers and size_t.) +*/ + +/* + Bins + + An array of bin headers for free chunks. Each bin is doubly + linked. The bins are approximately proportionally (log) spaced. + There are a lot of these bins (128). This may look excessive, but + works very well in practice. Most bins hold sizes that are + unusual as malloc request sizes, but are more usual for fragments + and consolidated sets of chunks, which is what these bins hold, so + they can be found quickly. All procedures maintain the invariant + that no consolidated chunk physically borders another one, so each + chunk in a list is known to be preceeded and followed by either + inuse chunks or the ends of memory. + + Chunks in bins are kept in size order, with ties going to the + approximately least recently used chunk. Ordering isn't needed + for the small bins, which all contain the same-sized chunks, but + facilitates best-fit allocation for larger chunks. These lists + are just sequential. Keeping them in order almost never requires + enough traversal to warrant using fancier ordered data + structures. + + Chunks of the same size are linked with the most + recently freed at the front, and allocations are taken from the + back. This results in LRU (FIFO) allocation order, which tends + to give each chunk an equal opportunity to be consolidated with + adjacent freed chunks, resulting in larger free chunks and less + fragmentation. + + To simplify use in double-linked lists, each bin header acts + as a malloc_chunk. This avoids special-casing for headers. + But to conserve space and improve locality, we allocate + only the fd/bk pointers of bins, and then use repositioning tricks + to treat these as the fields of a malloc_chunk*. +*/ + +typedef struct malloc_chunk* mbinptr; + +/* addressing -- note that bin_at(0) does not exist */ +#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - (SIZE_SZ<<1))) + +/* analog of ++bin */ +#define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1))) + +/* Reminders about list directionality within bins */ +#define first(b) ((b)->fd) +#define last(b) ((b)->bk) + +/* Take a chunk off a bin list */ +#define unlink(P, BK, FD) { \ + FD = P->fd; \ + BK = P->bk; \ + FD->bk = BK; \ + BK->fd = FD; \ +} + +/* + Indexing + + Bins for sizes < 512 bytes contain chunks of all the same size, spaced + 8 bytes apart. Larger bins are approximately logarithmically spaced: + + 64 bins of size 8 + 32 bins of size 64 + 16 bins of size 512 + 8 bins of size 4096 + 4 bins of size 32768 + 2 bins of size 262144 + 1 bin of size what's left + + There is actually a little bit of slop in the numbers in bin_index + for the sake of speed. This makes no difference elsewhere. + + The bins top out around 1MB because we expect to service large + requests via mmap. +*/ + +#define NBINS 128 +#define NSMALLBINS 64 +#define SMALLBIN_WIDTH 8 +#define MIN_LARGE_SIZE 512 + +#define in_smallbin_range(sz) \ + ((unsigned long)(sz) < (unsigned long)MIN_LARGE_SIZE) + +#define smallbin_index(sz) (((unsigned)(sz)) >> 3) + +#define largebin_index(sz) \ +(((((unsigned long)(sz)) >> 6) <= 32)? 56 + (((unsigned long)(sz)) >> 6): \ + ((((unsigned long)(sz)) >> 9) <= 20)? 91 + (((unsigned long)(sz)) >> 9): \ + ((((unsigned long)(sz)) >> 12) <= 10)? 110 + (((unsigned long)(sz)) >> 12): \ + ((((unsigned long)(sz)) >> 15) <= 4)? 119 + (((unsigned long)(sz)) >> 15): \ + ((((unsigned long)(sz)) >> 18) <= 2)? 124 + (((unsigned long)(sz)) >> 18): \ + 126) + +#define bin_index(sz) \ + ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz)) + + +/* + Unsorted chunks + + All remainders from chunk splits, as well as all returned chunks, + are first placed in the "unsorted" bin. They are then placed + in regular bins after malloc gives them ONE chance to be used before + binning. So, basically, the unsorted_chunks list acts as a queue, + with chunks being placed on it in free (and malloc_consolidate), + and taken off (to be either used or placed in bins) in malloc. +*/ + +/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */ +#define unsorted_chunks(M) (bin_at(M, 1)) + +/* + Top + + The top-most available chunk (i.e., the one bordering the end of + available memory) is treated specially. It is never included in + any bin, is used only if no other chunk is available, and is + released back to the system if it is very large (see + M_TRIM_THRESHOLD). Because top initially + points to its own bin with initial zero size, thus forcing + extension on the first malloc request, we avoid having any special + code in malloc to check whether it even exists yet. But we still + need to do so when getting memory from system, so we make + initial_top treat the bin as a legal but unusable chunk during the + interval between initialization and the first call to + sYSMALLOc. (This is somewhat delicate, since it relies on + the 2 preceding words to be zero during this interval as well.) +*/ + +/* Conveniently, the unsorted bin can be used as dummy top on first call */ +#define initial_top(M) (unsorted_chunks(M)) + +/* + Binmap + + To help compensate for the large number of bins, a one-level index + structure is used for bin-by-bin searching. `binmap' is a + bitvector recording whether bins are definitely empty so they can + be skipped over during during traversals. The bits are NOT always + cleared as soon as bins are empty, but instead only + when they are noticed to be empty during traversal in malloc. +*/ + +/* Conservatively use 32 bits per map word, even if on 64bit system */ +#define BINMAPSHIFT 5 +#define BITSPERMAP (1U << BINMAPSHIFT) +#define BINMAPSIZE (NBINS / BITSPERMAP) + +#define idx2block(i) ((i) >> BINMAPSHIFT) +#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT)-1)))) + +#define mark_bin(m,i) ((m)->binmap[idx2block(i)] |= idx2bit(i)) +#define unmark_bin(m,i) ((m)->binmap[idx2block(i)] &= ~(idx2bit(i))) +#define get_binmap(m,i) ((m)->binmap[idx2block(i)] & idx2bit(i)) + +/* + Fastbins + + An array of lists holding recently freed small chunks. Fastbins + are not doubly linked. It is faster to single-link them, and + since chunks are never removed from the middles of these lists, + double linking is not necessary. Also, unlike regular bins, they + are not even processed in FIFO order (they use faster LIFO) since + ordering doesn't much matter in the transient contexts in which + fastbins are normally used. + + Chunks in fastbins keep their inuse bit set, so they cannot + be consolidated with other free chunks. malloc_consolidate + releases all chunks in fastbins and consolidates them with + other free chunks. +*/ + +typedef struct malloc_chunk* mfastbinptr; + +/* offset 2 to use otherwise unindexable first 2 bins */ +#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2) + +/* The maximum fastbin request size we support */ +#define MAX_FAST_SIZE 80 + +#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE))+1) + +/* + FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free() + that triggers automatic consolidation of possibly-surrounding + fastbin chunks. This is a heuristic, so the exact value should not + matter too much. It is defined at half the default trim threshold as a + compromise heuristic to only attempt consolidation if it is likely + to lead to trimming. However, it is not dynamically tunable, since + consolidation reduces fragmentation surrounding loarge chunks even + if trimming is not used. +*/ + +#define FASTBIN_CONSOLIDATION_THRESHOLD (65536UL) + +/* + Since the lowest 2 bits in max_fast don't matter in size comparisons, + they are used as flags. +*/ + +/* + FASTCHUNKS_BIT held in max_fast indicates that there are probably + some fastbin chunks. It is set true on entering a chunk into any + fastbin, and cleared only in malloc_consolidate. + + The truth value is inverted so that have_fastchunks will be true + upon startup (since statics are zero-filled), simplifying + initialization checks. +*/ + +#define FASTCHUNKS_BIT (1U) + +#define have_fastchunks(M) (((M)->max_fast & FASTCHUNKS_BIT) == 0) +#define clear_fastchunks(M) ((M)->max_fast |= FASTCHUNKS_BIT) +#define set_fastchunks(M) ((M)->max_fast &= ~FASTCHUNKS_BIT) + +/* + NONCONTIGUOUS_BIT indicates that MORECORE does not return contiguous + regions. Otherwise, contiguity is exploited in merging together, + when possible, results from consecutive MORECORE calls. + + The initial value comes from MORECORE_CONTIGUOUS, but is + changed dynamically if mmap is ever used as an sbrk substitute. +*/ + +#define NONCONTIGUOUS_BIT (2U) + +#define contiguous(M) (((M)->max_fast & NONCONTIGUOUS_BIT) == 0) +#define noncontiguous(M) (((M)->max_fast & NONCONTIGUOUS_BIT) != 0) +#define set_noncontiguous(M) ((M)->max_fast |= NONCONTIGUOUS_BIT) +#define set_contiguous(M) ((M)->max_fast &= ~NONCONTIGUOUS_BIT) + +/* + Set value of max_fast. + Use impossibly small value if 0. + Precondition: there are no existing fastbin chunks. + Setting the value clears fastchunk bit but preserves noncontiguous bit. +*/ + +#define set_max_fast(M, s) \ + (M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \ + FASTCHUNKS_BIT | \ + ((M)->max_fast & NONCONTIGUOUS_BIT) + + +/* + ----------- Internal state representation and initialization ----------- +*/ + +struct malloc_state { + + /* The maximum chunk size to be eligible for fastbin */ + INTERNAL_SIZE_T max_fast; /* low 2 bits used as flags */ + + /* Fastbins */ + mfastbinptr fastbins[NFASTBINS]; + + /* Base of the topmost chunk -- not otherwise kept in a bin */ + mchunkptr top; + + /* The remainder from the most recent split of a small request */ + mchunkptr last_remainder; + + /* Normal bins packed as described above */ + mchunkptr bins[NBINS * 2]; + + /* Bitmap of bins */ + unsigned int binmap[BINMAPSIZE]; + + /* Tunable parameters */ + unsigned long trim_threshold; + INTERNAL_SIZE_T top_pad; + INTERNAL_SIZE_T mmap_threshold; + + /* Memory map support */ + int n_mmaps; + int n_mmaps_max; + int max_n_mmaps; + + /* Cache malloc_getpagesize */ + unsigned int pagesize; + + /* Statistics */ + INTERNAL_SIZE_T mmapped_mem; + INTERNAL_SIZE_T sbrked_mem; + INTERNAL_SIZE_T max_sbrked_mem; + INTERNAL_SIZE_T max_mmapped_mem; + INTERNAL_SIZE_T max_total_mem; +}; + +typedef struct malloc_state *mstate; + +/* + There is exactly one instance of this struct in this malloc. + If you are adapting this malloc in a way that does NOT use a static + malloc_state, you MUST explicitly zero-fill it before using. This + malloc relies on the property that malloc_state is initialized to + all zeroes (as is true of C statics). +*/ + +static struct malloc_state av_; /* never directly referenced */ + +/* + All uses of av_ are via get_malloc_state(). + At most one "call" to get_malloc_state is made per invocation of + the public versions of malloc and free, but other routines + that in turn invoke malloc and/or free may call more then once. + Also, it is called in check* routines if DEBUG is set. +*/ + +#define get_malloc_state() (&(av_)) + +/* + Initialize a malloc_state struct. + + This is called only from within malloc_consolidate, which needs + be called in the same contexts anyway. It is never called directly + outside of malloc_consolidate because some optimizing compilers try + to inline it at all call points, which turns out not to be an + optimization at all. (Inlining it in malloc_consolidate is fine though.) +*/ + +#if __STD_C +static void malloc_init_state(mstate av) +#else +static void malloc_init_state(av) mstate av; +#endif +{ + int i; + mbinptr bin; + + /* Establish circular links for normal bins */ + for (i = 1; i < NBINS; ++i) { + bin = bin_at(av,i); + bin->fd = bin->bk = bin; + } + + av->top_pad = DEFAULT_TOP_PAD; + av->n_mmaps_max = DEFAULT_MMAP_MAX; + av->mmap_threshold = DEFAULT_MMAP_THRESHOLD; + av->trim_threshold = DEFAULT_TRIM_THRESHOLD; + +#if !MORECORE_CONTIGUOUS + set_noncontiguous(av); +#endif + + set_max_fast(av, DEFAULT_MXFAST); + + av->top = initial_top(av); + av->pagesize = malloc_getpagesize; +} + +/* + Other internal utilities operating on mstates +*/ + +#if __STD_C +static Void_t* sYSMALLOc(INTERNAL_SIZE_T, mstate); +static int sYSTRIm(size_t, mstate); +static void malloc_consolidate(mstate); +static Void_t** iALLOc(size_t, size_t*, int, Void_t**); +#else +static Void_t* sYSMALLOc(); +static int sYSTRIm(); +static void malloc_consolidate(); +static Void_t** iALLOc(); +#endif + +/* + Debugging support + + These routines make a number of assertions about the states + of data structures that should be true at all times. If any + are not true, it's very likely that a user program has somehow + trashed memory. (It's also possible that there is a coding error + in malloc. In which case, please report it!) +*/ + +#if ! DEBUG + +#define check_chunk(P) +#define check_free_chunk(P) +#define check_inuse_chunk(P) +#define check_remalloced_chunk(P,N) +#define check_malloced_chunk(P,N) +#define check_malloc_state() + +#else +#define check_chunk(P) do_check_chunk(P) +#define check_free_chunk(P) do_check_free_chunk(P) +#define check_inuse_chunk(P) do_check_inuse_chunk(P) +#define check_remalloced_chunk(P,N) do_check_remalloced_chunk(P,N) +#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) +#define check_malloc_state() do_check_malloc_state() + +/* + Properties of all chunks +*/ + +#if __STD_C +static void do_check_chunk(mchunkptr p) +#else +static void do_check_chunk(p) mchunkptr p; +#endif +{ + mstate av = get_malloc_state(); + unsigned long sz = chunksize(p); + /* min and max possible addresses assuming contiguous allocation */ + char* max_address = (char*)(av->top) + chunksize(av->top); + char* min_address = max_address - av->sbrked_mem; + + if (!chunk_is_mmapped(p)) { + + /* Has legal address ... */ + if (p != av->top) { + if (contiguous(av)) { + assert(((char*)p) >= min_address); + assert(((char*)p + sz) <= ((char*)(av->top))); + } + } + else { + /* top size is always at least MINSIZE */ + assert((unsigned long)(sz) >= MINSIZE); + /* top predecessor always marked inuse */ + assert(prev_inuse(p)); + } + + } + else { +#if HAVE_MMAP + /* address is outside main heap */ + if (contiguous(av) && av->top != initial_top(av)) { + assert(((char*)p) < min_address || ((char*)p) > max_address); + } + /* chunk is page-aligned */ + assert(((p->prev_size + sz) & (av->pagesize-1)) == 0); + /* mem is aligned */ + assert(aligned_OK(chunk2mem(p))); +#else + /* force an appropriate assert violation if debug set */ + assert(!chunk_is_mmapped(p)); +#endif + } +} + +/* + Properties of free chunks +*/ + +#if __STD_C +static void do_check_free_chunk(mchunkptr p) +#else +static void do_check_free_chunk(p) mchunkptr p; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + mchunkptr next = chunk_at_offset(p, sz); + + do_check_chunk(p); + + /* Chunk must claim to be free ... */ + assert(!inuse(p)); + assert (!chunk_is_mmapped(p)); + + /* Unless a special marker, must have OK fields */ + if ((unsigned long)(sz) >= MINSIZE) + { + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert(aligned_OK(chunk2mem(p))); + /* ... matching footer field */ + assert(next->prev_size == sz); + /* ... and is fully consolidated */ + assert(prev_inuse(p)); + assert (next == av->top || inuse(next)); + + /* ... and has minimally sane links */ + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_SZ */ + assert(sz == SIZE_SZ); +} + +/* + Properties of inuse chunks +*/ + +#if __STD_C +static void do_check_inuse_chunk(mchunkptr p) +#else +static void do_check_inuse_chunk(p) mchunkptr p; +#endif +{ + mstate av = get_malloc_state(); + mchunkptr next; + do_check_chunk(p); + + if (chunk_is_mmapped(p)) + return; /* mmapped chunks have no next/prev */ + + /* Check whether it claims to be in use ... */ + assert(inuse(p)); + + next = next_chunk(p); + + /* ... and is surrounded by OK chunks. + Since more things can be checked with free chunks than inuse ones, + if an inuse chunk borders them and debug is on, it's worth doing them. + */ + if (!prev_inuse(p)) { + /* Note that we cannot even look at prev unless it is not inuse */ + mchunkptr prv = prev_chunk(p); + assert(next_chunk(prv) == p); + do_check_free_chunk(prv); + } + + if (next == av->top) { + assert(prev_inuse(next)); + assert(chunksize(next) >= MINSIZE); + } + else if (!inuse(next)) + do_check_free_chunk(next); +} + +/* + Properties of chunks recycled from fastbins +*/ + +#if __STD_C +static void do_check_remalloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_remalloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + + do_check_inuse_chunk(p); + + /* Legal size ... */ + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert((unsigned long)(sz) >= MINSIZE); + /* ... and alignment */ + assert(aligned_OK(chunk2mem(p))); + /* chunk is less than MINSIZE more than request */ + assert((long)(sz) - (long)(s) >= 0); + assert((long)(sz) - (long)(s + MINSIZE) < 0); +} + +/* + Properties of nonrecycled chunks at the point they are malloced +*/ + +#if __STD_C +static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + /* same as recycled case ... */ + do_check_remalloced_chunk(p, s); + + /* + ... plus, must obey implementation invariant that prev_inuse is + always true of any allocated chunk; i.e., that each allocated + chunk borders either a previously allocated and still in-use + chunk, or the base of its memory arena. This is ensured + by making all allocations from the the `lowest' part of any found + chunk. This does not necessarily hold however for chunks + recycled via fastbins. + */ + + assert(prev_inuse(p)); +} + + +/* + Properties of malloc_state. + + This may be useful for debugging malloc, as well as detecting user + programmer errors that somehow write into malloc_state. + + If you are extending or experimenting with this malloc, you can + probably figure out how to hack this routine to print out or + display chunk addresses, sizes, bins, and other instrumentation. +*/ + +static void do_check_malloc_state() +{ + mstate av = get_malloc_state(); + int i; + mchunkptr p; + mchunkptr q; + mbinptr b; + unsigned int binbit; + int empty; + unsigned int idx; + INTERNAL_SIZE_T size; + unsigned long total = 0; + int max_fast_bin; + + /* internal size_t must be no wider than pointer type */ + assert(sizeof(INTERNAL_SIZE_T) <= sizeof(char*)); + + /* alignment is a power of 2 */ + assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0); + + /* cannot run remaining checks until fully initialized */ + if (av->top == 0 || av->top == initial_top(av)) + return; + + /* pagesize is a power of 2 */ + assert((av->pagesize & (av->pagesize-1)) == 0); + + /* properties of fastbins */ + + /* max_fast is in allowed range */ + assert((av->max_fast & ~1) <= request2size(MAX_FAST_SIZE)); + + max_fast_bin = fastbin_index(av->max_fast); + + for (i = 0; i < NFASTBINS; ++i) { + p = av->fastbins[i]; + + /* all bins past max_fast are empty */ + if (i > max_fast_bin) + assert(p == 0); + + while (p != 0) { + /* each chunk claims to be inuse */ + do_check_inuse_chunk(p); + total += chunksize(p); + /* chunk belongs in this bin */ + assert(fastbin_index(chunksize(p)) == i); + p = p->fd; + } + } + + if (total != 0) + assert(have_fastchunks(av)); + else if (!have_fastchunks(av)) + assert(total == 0); + + /* check normal bins */ + for (i = 1; i < NBINS; ++i) { + b = bin_at(av,i); + + /* binmap is accurate (except for bin 1 == unsorted_chunks) */ + if (i >= 2) { + binbit = get_binmap(av,i); + empty = last(b) == b; + if (!binbit) + assert(empty); + else if (!empty) + assert(binbit); + } + + for (p = last(b); p != b; p = p->bk) { + /* each chunk claims to be free */ + do_check_free_chunk(p); + size = chunksize(p); + total += size; + if (i >= 2) { + /* chunk belongs in bin */ + idx = bin_index(size); + assert(idx == i); + /* lists are sorted */ + assert(p->bk == b || + (unsigned long)chunksize(p->bk) >= (unsigned long)chunksize(p)); + } + /* chunk is followed by a legal chain of inuse chunks */ + for (q = next_chunk(p); + (q != av->top && inuse(q) && + (unsigned long)(chunksize(q)) >= MINSIZE); + q = next_chunk(q)) + do_check_inuse_chunk(q); + } + } + + /* top chunk is OK */ + check_chunk(av->top); + + /* sanity checks for statistics */ + + assert(total <= (unsigned long)(av->max_total_mem)); + assert(av->n_mmaps >= 0); + assert(av->n_mmaps <= av->n_mmaps_max); + assert(av->n_mmaps <= av->max_n_mmaps); + + assert((unsigned long)(av->sbrked_mem) <= + (unsigned long)(av->max_sbrked_mem)); + + assert((unsigned long)(av->mmapped_mem) <= + (unsigned long)(av->max_mmapped_mem)); + + assert((unsigned long)(av->max_total_mem) >= + (unsigned long)(av->mmapped_mem) + (unsigned long)(av->sbrked_mem)); +} +#endif + + +/* ----------- Routines dealing with system allocation -------------- */ + +/* + sysmalloc handles malloc cases requiring more memory from the system. + On entry, it is assumed that av->top does not have enough + space to service request for nb bytes, thus requiring that av->top + be extended or replaced. +*/ + +#if __STD_C +static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av) +#else +static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av; +#endif +{ + mchunkptr old_top; /* incoming value of av->top */ + INTERNAL_SIZE_T old_size; /* its size */ + char* old_end; /* its end address */ + + long size; /* arg to first MORECORE or mmap call */ + char* brk; /* return value from MORECORE */ + + long correction; /* arg to 2nd MORECORE call */ + char* snd_brk; /* 2nd return val */ + + INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ + INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */ + char* aligned_brk; /* aligned offset into brk */ + + mchunkptr p; /* the allocated/returned chunk */ + mchunkptr remainder; /* remainder from allocation */ + unsigned long remainder_size; /* its size */ + + unsigned long sum; /* for updating stats */ + + size_t pagemask = av->pagesize - 1; + + +#if HAVE_MMAP + + /* + If have mmap, and the request size meets the mmap threshold, and + the system supports mmap, and there are few enough currently + allocated mmapped regions, try to directly map this request + rather than expanding top. + */ + + if ((unsigned long)(nb) >= (unsigned long)(av->mmap_threshold) && + (av->n_mmaps < av->n_mmaps_max)) { + + char* mm; /* return value from mmap call*/ + + /* + Round up size to nearest page. For mmapped chunks, the overhead + is one SIZE_SZ unit larger than for normal chunks, because there + is no following chunk whose prev_size field could be used. + */ + size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask; + + /* Don't try if size wraps around 0 */ + if ((unsigned long)(size) > (unsigned long)(nb)) { + + mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); + + if (mm != (char*)(MORECORE_FAILURE)) { + + /* + The offset to the start of the mmapped region is stored + in the prev_size field of the chunk. This allows us to adjust + returned start address to meet alignment requirements here + and in memalign(), and still be able to compute proper + address argument for later munmap in free() and realloc(). + */ + + front_misalign = (INTERNAL_SIZE_T)chunk2mem(mm) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) { + correction = MALLOC_ALIGNMENT - front_misalign; + p = (mchunkptr)(mm + correction); + p->prev_size = correction; + set_head(p, (size - correction) |IS_MMAPPED); + } + else { + p = (mchunkptr)mm; + set_head(p, size|IS_MMAPPED); + } + + /* update statistics */ + + if (++av->n_mmaps > av->max_n_mmaps) + av->max_n_mmaps = av->n_mmaps; + + sum = av->mmapped_mem += size; + if (sum > (unsigned long)(av->max_mmapped_mem)) + av->max_mmapped_mem = sum; + sum += av->sbrked_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + check_chunk(p); + + return chunk2mem(p); + } + } + } +#endif + + /* Record incoming configuration of top */ + + old_top = av->top; + old_size = chunksize(old_top); + old_end = (char*)(chunk_at_offset(old_top, old_size)); + + brk = snd_brk = (char*)(MORECORE_FAILURE); + + /* + If not the first time through, we require old_size to be + at least MINSIZE and to have prev_inuse set. + */ + + assert((old_top == initial_top(av) && old_size == 0) || + ((unsigned long) (old_size) >= MINSIZE && + prev_inuse(old_top))); + + /* Precondition: not enough current space to satisfy nb request */ + assert((unsigned long)(old_size) < (unsigned long)(nb + MINSIZE)); + + /* Precondition: all fastbins are consolidated */ + assert(!have_fastchunks(av)); + + + /* Request enough space for nb + pad + overhead */ + + size = nb + av->top_pad + MINSIZE; + + /* + If contiguous, we can subtract out existing space that we hope to + combine with new space. We add it back later only if + we don't actually get contiguous space. + */ + + if (contiguous(av)) + size -= old_size; + + /* + Round to a multiple of page size. + If MORECORE is not contiguous, this ensures that we only call it + with whole-page arguments. And if MORECORE is contiguous and + this is not first time through, this preserves page-alignment of + previous calls. Otherwise, we correct to page-align below. + */ + + size = (size + pagemask) & ~pagemask; + + /* + Don't try to call MORECORE if argument is so big as to appear + negative. Note that since mmap takes size_t arg, it may succeed + below even if we cannot call MORECORE. + */ + + if (size > 0) + brk = (char*)(MORECORE(size)); + + /* + If have mmap, try using it as a backup when MORECORE fails or + cannot be used. This is worth doing on systems that have "holes" in + address space, so sbrk cannot extend to give contiguous space, but + space is available elsewhere. Note that we ignore mmap max count + and threshold limits, since the space will not be used as a + segregated mmap region. + */ + +#if HAVE_MMAP + if (brk == (char*)(MORECORE_FAILURE)) { + + /* Cannot merge with old top, so add its size back in */ + if (contiguous(av)) + size = (size + old_size + pagemask) & ~pagemask; + + /* If we are relying on mmap as backup, then use larger units */ + if ((unsigned long)(size) < (unsigned long)(MMAP_AS_MORECORE_SIZE)) + size = MMAP_AS_MORECORE_SIZE; + + /* Don't try if size wraps around 0 */ + if ((unsigned long)(size) > (unsigned long)(nb)) { + + brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); + + if (brk != (char*)(MORECORE_FAILURE)) { + + /* We do not need, and cannot use, another sbrk call to find end */ + snd_brk = brk + size; + + /* + Record that we no longer have a contiguous sbrk region. + After the first time mmap is used as backup, we do not + ever rely on contiguous space since this could incorrectly + bridge regions. + */ + set_noncontiguous(av); + } + } + } +#endif + + if (brk != (char*)(MORECORE_FAILURE)) { + av->sbrked_mem += size; + + /* + If MORECORE extends previous space, we can likewise extend top size. + */ + + if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) { + set_head(old_top, (size + old_size) | PREV_INUSE); + } + + /* + Otherwise, make adjustments: + + * If the first time through or noncontiguous, we need to call sbrk + just to find out where the end of memory lies. + + * We need to ensure that all returned chunks from malloc will meet + MALLOC_ALIGNMENT + + * If there was an intervening foreign sbrk, we need to adjust sbrk + request size to account for fact that we will not be able to + combine new space with existing space in old_top. + + * Almost all systems internally allocate whole pages at a time, in + which case we might as well use the whole last page of request. + So we allocate enough more memory to hit a page boundary now, + which in turn causes future contiguous calls to page-align. + */ + + else { + front_misalign = 0; + end_misalign = 0; + correction = 0; + aligned_brk = brk; + + /* handle contiguous cases */ + if (contiguous(av)) { + + /* Guarantee alignment of first new chunk made from this space */ + + front_misalign = (INTERNAL_SIZE_T)chunk2mem(brk) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) { + + /* + Skip over some bytes to arrive at an aligned position. + We don't need to specially mark these wasted front bytes. + They will never be accessed anyway because + prev_inuse of av->top (and any chunk created from its start) + is always true after initialization. + */ + + correction = MALLOC_ALIGNMENT - front_misalign; + aligned_brk += correction; + } + + /* + If this isn't adjacent to existing space, then we will not + be able to merge with old_top space, so must add to 2nd request. + */ + + correction += old_size; + + /* Extend the end address to hit a page boundary */ + end_misalign = (INTERNAL_SIZE_T)(brk + size + correction); + correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign; + + assert(correction >= 0); + snd_brk = (char*)(MORECORE(correction)); + + /* + If can't allocate correction, try to at least find out current + brk. It might be enough to proceed without failing. + + Note that if second sbrk did NOT fail, we assume that space + is contiguous with first sbrk. This is a safe assumption unless + program is multithreaded but doesn't use locks and a foreign sbrk + occurred between our first and second calls. + */ + + if (snd_brk == (char*)(MORECORE_FAILURE)) { + correction = 0; + snd_brk = (char*)(MORECORE(0)); + } + } + + /* handle non-contiguous cases */ + else { + /* MORECORE/mmap must correctly align */ + assert(((unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK) == 0); + + /* Find out current end of memory */ + if (snd_brk == (char*)(MORECORE_FAILURE)) { + snd_brk = (char*)(MORECORE(0)); + } + } + + /* Adjust top based on results of second sbrk */ + if (snd_brk != (char*)(MORECORE_FAILURE)) { + av->top = (mchunkptr)aligned_brk; + set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); + av->sbrked_mem += correction; + + /* + If not the first time through, we either have a + gap due to foreign sbrk or a non-contiguous region. Insert a + double fencepost at old_top to prevent consolidation with space + we don't own. These fenceposts are artificial chunks that are + marked as inuse and are in any case too small to use. We need + two to make sizes and alignments work out. + */ + + if (old_size != 0) { + /* + Shrink old_top to insert fenceposts, keeping size a + multiple of MALLOC_ALIGNMENT. We know there is at least + enough space in old_top to do this. + */ + old_size = (old_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; + set_head(old_top, old_size | PREV_INUSE); + + /* + Note that the following assignments completely overwrite + old_top when old_size was previously MINSIZE. This is + intentional. We need the fencepost, even if old_top otherwise gets + lost. + */ + chunk_at_offset(old_top, old_size )->size = + SIZE_SZ|PREV_INUSE; + + chunk_at_offset(old_top, old_size + SIZE_SZ)->size = + SIZE_SZ|PREV_INUSE; + + /* If possible, release the rest. */ + if (old_size >= MINSIZE) { + fREe(chunk2mem(old_top)); + } + + } + } + } + + /* Update statistics */ + sum = av->sbrked_mem; + if (sum > (unsigned long)(av->max_sbrked_mem)) + av->max_sbrked_mem = sum; + + sum += av->mmapped_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + check_malloc_state(); + + /* finally, do the allocation */ + p = av->top; + size = chunksize(p); + + /* check that one of the above allocation paths succeeded */ + if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) { + remainder_size = size - nb; + remainder = chunk_at_offset(p, nb); + av->top = remainder; + set_head(p, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + check_malloced_chunk(p, nb); + return chunk2mem(p); + } + } + + /* catch all failure paths */ + MALLOC_FAILURE_ACTION; + return 0; +} + + +/* + sYSTRIm is an inverse of sorts to sYSMALLOc. It gives memory back + to the system (via negative arguments to sbrk) if there is unused + memory at the `high' end of the malloc pool. It is called + automatically by free() when top space exceeds the trim + threshold. It is also called by the public malloc_trim routine. It + returns 1 if it actually released any memory, else 0. +*/ + +#if __STD_C +static int sYSTRIm(size_t pad, mstate av) +#else +static int sYSTRIm(pad, av) size_t pad; mstate av; +#endif +{ + long top_size; /* Amount of top-most memory */ + long extra; /* Amount to release */ + long released; /* Amount actually released */ + char* current_brk; /* address returned by pre-check sbrk call */ + char* new_brk; /* address returned by post-check sbrk call */ + size_t pagesz; + + pagesz = av->pagesize; + top_size = chunksize(av->top); + + /* Release in pagesize units, keeping at least one page */ + extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; + + if (extra > 0) { + + /* + Only proceed if end of memory is where we last set it. + This avoids problems if there were foreign sbrk calls. + */ + current_brk = (char*)(MORECORE(0)); + if (current_brk == (char*)(av->top) + top_size) { + + /* + Attempt to release memory. We ignore MORECORE return value, + and instead call again to find out where new end of memory is. + This avoids problems if first call releases less than we asked, + of if failure somehow altered brk value. (We could still + encounter problems if it altered brk in some very bad way, + but the only thing we can do is adjust anyway, which will cause + some downstream failure.) + */ + + MORECORE(-extra); + new_brk = (char*)(MORECORE(0)); + + if (new_brk != (char*)MORECORE_FAILURE) { + released = (long)(current_brk - new_brk); + + if (released != 0) { + /* Success. Adjust top. */ + av->sbrked_mem -= released; + set_head(av->top, (top_size - released) | PREV_INUSE); + check_malloc_state(); + return 1; + } + } + } + } + return 0; +} + +/* + ------------------------------ malloc ------------------------------ +*/ + +#if __STD_C +Void_t* mALLOc(size_t bytes) +#else + Void_t* mALLOc(bytes) size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T nb; /* normalized request size */ + unsigned int idx; /* associated bin index */ + mbinptr bin; /* associated bin */ + mfastbinptr* fb; /* associated fastbin */ + + mchunkptr victim; /* inspected/selected chunk */ + INTERNAL_SIZE_T size; /* its size */ + int victim_index; /* its bin index */ + + mchunkptr remainder; /* remainder from a split */ + unsigned long remainder_size; /* its size */ + + unsigned int block; /* bit map traverser */ + unsigned int bit; /* bit map traverser */ + unsigned int map; /* current word of binmap */ + + mchunkptr fwd; /* misc temp for linking */ + mchunkptr bck; /* misc temp for linking */ + + /* + Convert request size to internal form by adding SIZE_SZ bytes + overhead plus possibly more to obtain necessary alignment and/or + to obtain a size of at least MINSIZE, the smallest allocatable + size. Also, checked_request2size traps (returning 0) request sizes + that are so large that they wrap around zero when padded and + aligned. + */ + + checked_request2size(bytes, nb); + + /* + If the size qualifies as a fastbin, first check corresponding bin. + This code is safe to execute even if av is not yet initialized, so we + can try it without checking, which saves some time on this fast path. + */ + + if ((unsigned long)(nb) <= (unsigned long)(av->max_fast)) { + fb = &(av->fastbins[(fastbin_index(nb))]); + if ( (victim = *fb) != 0) { + *fb = victim->fd; + check_remalloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + + /* + If a small request, check regular bin. Since these "smallbins" + hold one size each, no searching within bins is necessary. + (For a large request, we need to wait until unsorted chunks are + processed to find best fit. But for small ones, fits are exact + anyway, so we can check now, which is faster.) + */ + + if (in_smallbin_range(nb)) { + idx = smallbin_index(nb); + bin = bin_at(av,idx); + + if ( (victim = last(bin)) != bin) { + if (victim == 0) /* initialization check */ + malloc_consolidate(av); + else { + bck = victim->bk; + set_inuse_bit_at_offset(victim, nb); + bin->bk = bck; + bck->fd = bin; + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } + + /* + If this is a large request, consolidate fastbins before continuing. + While it might look excessive to kill all fastbins before + even seeing if there is space available, this avoids + fragmentation problems normally associated with fastbins. + Also, in practice, programs tend to have runs of either small or + large requests, but less often mixtures, so consolidation is not + invoked all that often in most programs. And the programs that + it is called frequently in otherwise tend to fragment. + */ + + else { + idx = largebin_index(nb); + if (have_fastchunks(av)) + malloc_consolidate(av); + } + + /* + Process recently freed or remaindered chunks, taking one only if + it is exact fit, or, if this a small request, the chunk is remainder from + the most recent non-exact fit. Place other traversed chunks in + bins. Note that this step is the only place in any routine where + chunks are placed in bins. + + The outer loop here is needed because we might not realize until + near the end of malloc that we should have consolidated, so must + do so and retry. This happens at most once, and only when we would + otherwise need to expand memory to service a "small" request. + */ + + for(;;) { + + while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) { + bck = victim->bk; + size = chunksize(victim); + + /* + If a small request, try to use last remainder if it is the + only chunk in unsorted bin. This helps promote locality for + runs of consecutive small requests. This is the only + exception to best-fit, and applies only when there is + no exact fit for a small chunk. + */ + + if (in_smallbin_range(nb) && + bck == unsorted_chunks(av) && + victim == av->last_remainder && + (unsigned long)(size) > (unsigned long)(nb + MINSIZE)) { + + /* split and reattach remainder */ + remainder_size = size - nb; + remainder = chunk_at_offset(victim, nb); + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + av->last_remainder = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* remove from unsorted list */ + unsorted_chunks(av)->bk = bck; + bck->fd = unsorted_chunks(av); + + /* Take now instead of binning if exact fit */ + + if (size == nb) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* place chunk in bin */ + + if (in_smallbin_range(size)) { + victim_index = smallbin_index(size); + bck = bin_at(av, victim_index); + fwd = bck->fd; + } + else { + victim_index = largebin_index(size); + bck = bin_at(av, victim_index); + fwd = bck->fd; + + /* maintain large bins in sorted order */ + if (fwd != bck) { + size |= PREV_INUSE; /* Or with inuse bit to speed comparisons */ + /* if smaller than smallest, bypass loop below */ + if ((unsigned long)(size) <= (unsigned long)(bck->bk->size)) { + fwd = bck; + bck = bck->bk; + } + else { + while ((unsigned long)(size) < (unsigned long)(fwd->size)) + fwd = fwd->fd; + bck = fwd->bk; + } + } + } + + mark_bin(av, victim_index); + victim->bk = bck; + victim->fd = fwd; + fwd->bk = victim; + bck->fd = victim; + } + + /* + If a large request, scan through the chunks of current bin in + sorted order to find smallest that fits. This is the only step + where an unbounded number of chunks might be scanned without doing + anything useful with them. However the lists tend to be short. + */ + + if (!in_smallbin_range(nb)) { + bin = bin_at(av, idx); + + /* skip scan if empty or largest chunk is too small */ + if ((victim = last(bin)) != bin && + (unsigned long)(first(bin)->size) >= (unsigned long)(nb)) { + + while (((unsigned long)(size = chunksize(victim)) < + (unsigned long)(nb))) + victim = victim->bk; + + remainder_size = size - nb; + unlink(victim, bck, fwd); + + /* Exhaust */ + if (remainder_size < MINSIZE) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + /* Split */ + else { + remainder = chunk_at_offset(victim, nb); + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } + + /* + Search for a chunk by scanning bins, starting with next largest + bin. This search is strictly by best-fit; i.e., the smallest + (with ties going to approximately the least recently used) chunk + that fits is selected. + + The bitmap avoids needing to check that most blocks are nonempty. + The particular case of skipping all bins during warm-up phases + when no chunks have been returned yet is faster than it might look. + */ + + ++idx; + bin = bin_at(av,idx); + block = idx2block(idx); + map = av->binmap[block]; + bit = idx2bit(idx); + + for (;;) { + + /* Skip rest of block if there are no more set bits in this block. */ + if (bit > map || bit == 0) { + do { + if (++block >= BINMAPSIZE) /* out of bins */ + goto use_top; + } while ( (map = av->binmap[block]) == 0); + + bin = bin_at(av, (block << BINMAPSHIFT)); + bit = 1; + } + + /* Advance to bin with set bit. There must be one. */ + while ((bit & map) == 0) { + bin = next_bin(bin); + bit <<= 1; + assert(bit != 0); + } + + /* Inspect the bin. It is likely to be non-empty */ + victim = last(bin); + + /* If a false alarm (empty bin), clear the bit. */ + if (victim == bin) { + av->binmap[block] = map &= ~bit; /* Write through */ + bin = next_bin(bin); + bit <<= 1; + } + + else { + size = chunksize(victim); + + /* We know the first chunk in this bin is big enough to use. */ + assert((unsigned long)(size) >= (unsigned long)(nb)); + + remainder_size = size - nb; + + /* unlink */ + bck = victim->bk; + bin->bk = bck; + bck->fd = bin; + + /* Exhaust */ + if (remainder_size < MINSIZE) { + set_inuse_bit_at_offset(victim, size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* Split */ + else { + remainder = chunk_at_offset(victim, nb); + + unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; + remainder->bk = remainder->fd = unsorted_chunks(av); + /* advertise as last remainder */ + if (in_smallbin_range(nb)) + av->last_remainder = remainder; + + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + } + + use_top: + /* + If large enough, split off the chunk bordering the end of memory + (held in av->top). Note that this is in accord with the best-fit + search rule. In effect, av->top is treated as larger (and thus + less well fitting) than any other available chunk since it can + be extended to be as large as necessary (up to system + limitations). + + We require that av->top always exists (i.e., has size >= + MINSIZE) after initialization, so if it would otherwise be + exhuasted by current request, it is replenished. (The main + reason for ensuring it exists is that we may need MINSIZE space + to put in fenceposts in sysmalloc.) + */ + + victim = av->top; + size = chunksize(victim); + + if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) { + remainder_size = size - nb; + remainder = chunk_at_offset(victim, nb); + av->top = remainder; + set_head(victim, nb | PREV_INUSE); + set_head(remainder, remainder_size | PREV_INUSE); + + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* + If there is space available in fastbins, consolidate and retry, + to possibly avoid expanding memory. This can occur only if nb is + in smallbin range so we didn't consolidate upon entry. + */ + + else if (have_fastchunks(av)) { + assert(in_smallbin_range(nb)); + malloc_consolidate(av); + idx = smallbin_index(nb); /* restore original bin index */ + } + + /* + Otherwise, relay to handle system-dependent cases + */ + else + return sYSMALLOc(nb, av); + } +} + +/* + ------------------------------ free ------------------------------ +*/ + +#if __STD_C +void fREe(Void_t* mem) +#else +void fREe(mem) Void_t* mem; +#endif +{ + mstate av = get_malloc_state(); + + mchunkptr p; /* chunk corresponding to mem */ + INTERNAL_SIZE_T size; /* its size */ + mfastbinptr* fb; /* associated fastbin */ + mchunkptr nextchunk; /* next contiguous chunk */ + INTERNAL_SIZE_T nextsize; /* its size */ + int nextinuse; /* true if nextchunk is used */ + INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */ + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + + + /* free(0) has no effect */ + if (mem != 0) { + p = mem2chunk(mem); + size = chunksize(p); + + check_inuse_chunk(p); + + /* + If eligible, place chunk on a fastbin so it can be found + and used quickly in malloc. + */ + + if ((unsigned long)(size) <= (unsigned long)(av->max_fast) + +#if TRIM_FASTBINS + /* + If TRIM_FASTBINS set, don't place chunks + bordering top into fastbins + */ + && (chunk_at_offset(p, size) != av->top) +#endif + ) { + + set_fastchunks(av); + fb = &(av->fastbins[fastbin_index(size)]); + p->fd = *fb; + *fb = p; + } + + /* + Consolidate other non-mmapped chunks as they arrive. + */ + + else if (!chunk_is_mmapped(p)) { + nextchunk = chunk_at_offset(p, size); + nextsize = chunksize(nextchunk); + + /* consolidate backward */ + if (!prev_inuse(p)) { + prevsize = p->prev_size; + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + unlink(p, bck, fwd); + } + + if (nextchunk != av->top) { + /* get and clear inuse bit */ + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + set_head(nextchunk, nextsize); + + /* consolidate forward */ + if (!nextinuse) { + unlink(nextchunk, bck, fwd); + size += nextsize; + } + + /* + Place the chunk in unsorted chunk list. Chunks are + not placed into regular bins until after they have + been given one chance to be used in malloc. + */ + + bck = unsorted_chunks(av); + fwd = bck->fd; + p->bk = bck; + p->fd = fwd; + bck->fd = p; + fwd->bk = p; + + set_head(p, size | PREV_INUSE); + set_foot(p, size); + + check_free_chunk(p); + } + + /* + If the chunk borders the current high end of memory, + consolidate into top + */ + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + check_chunk(p); + } + + /* + If freeing a large space, consolidate possibly-surrounding + chunks. Then, if the total unused topmost memory exceeds trim + threshold, ask malloc_trim to reduce top. + + Unless max_fast is 0, we don't know if there are fastbins + bordering top, so we cannot tell for sure whether threshold + has been reached unless fastbins are consolidated. But we + don't want to consolidate on each free. As a compromise, + consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD + is reached. + */ + + if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) { + if (have_fastchunks(av)) + malloc_consolidate(av); + +#ifndef MORECORE_CANNOT_TRIM + if ((unsigned long)(chunksize(av->top)) >= + (unsigned long)(av->trim_threshold)) + sYSTRIm(av->top_pad, av); +#endif + } + + } + /* + If the chunk was allocated via mmap, release via munmap() + Note that if HAVE_MMAP is false but chunk_is_mmapped is + true, then user must have overwritten memory. There's nothing + we can do to catch this error unless DEBUG is set, in which case + check_inuse_chunk (above) will have triggered error. + */ + + else { +#if HAVE_MMAP + int ret; + INTERNAL_SIZE_T offset = p->prev_size; + av->n_mmaps--; + av->mmapped_mem -= (size + offset); + ret = munmap((char*)p - offset, size + offset); + /* munmap returns non-zero on failure */ + assert(ret == 0); +#endif + } + } +} + +/* + ------------------------- malloc_consolidate ------------------------- + + malloc_consolidate is a specialized version of free() that tears + down chunks held in fastbins. Free itself cannot be used for this + purpose since, among other things, it might place chunks back onto + fastbins. So, instead, we need to use a minor variant of the same + code. + + Also, because this routine needs to be called the first time through + malloc anyway, it turns out to be the perfect place to trigger + initialization code. +*/ + +#if __STD_C +static void malloc_consolidate(mstate av) +#else +static void malloc_consolidate(av) mstate av; +#endif +{ + mfastbinptr* fb; /* current fastbin being consolidated */ + mfastbinptr* maxfb; /* last fastbin (for loop control) */ + mchunkptr p; /* current chunk being consolidated */ + mchunkptr nextp; /* next chunk to consolidate */ + mchunkptr unsorted_bin; /* bin header */ + mchunkptr first_unsorted; /* chunk to link to */ + + /* These have same use as in free() */ + mchunkptr nextchunk; + INTERNAL_SIZE_T size; + INTERNAL_SIZE_T nextsize; + INTERNAL_SIZE_T prevsize; + int nextinuse; + mchunkptr bck; + mchunkptr fwd; + + /* + If max_fast is 0, we know that av hasn't + yet been initialized, in which case do so below + */ + + if (av->max_fast != 0) { + clear_fastchunks(av); + + unsorted_bin = unsorted_chunks(av); + + /* + Remove each chunk from fast bin and consolidate it, placing it + then in unsorted bin. Among other reasons for doing this, + placing in unsorted bin avoids needing to calculate actual bins + until malloc is sure that chunks aren't immediately going to be + reused anyway. + */ + + maxfb = &(av->fastbins[fastbin_index(av->max_fast)]); + fb = &(av->fastbins[0]); + do { + if ( (p = *fb) != 0) { + *fb = 0; + + do { + check_inuse_chunk(p); + nextp = p->fd; + + /* Slightly streamlined version of consolidation code in free() */ + size = p->size & ~PREV_INUSE; + nextchunk = chunk_at_offset(p, size); + nextsize = chunksize(nextchunk); + + if (!prev_inuse(p)) { + prevsize = p->prev_size; + size += prevsize; + p = chunk_at_offset(p, -((long) prevsize)); + unlink(p, bck, fwd); + } + + if (nextchunk != av->top) { + nextinuse = inuse_bit_at_offset(nextchunk, nextsize); + set_head(nextchunk, nextsize); + + if (!nextinuse) { + size += nextsize; + unlink(nextchunk, bck, fwd); + } + + first_unsorted = unsorted_bin->fd; + unsorted_bin->fd = p; + first_unsorted->bk = p; + + set_head(p, size | PREV_INUSE); + p->bk = unsorted_bin; + p->fd = first_unsorted; + set_foot(p, size); + } + + else { + size += nextsize; + set_head(p, size | PREV_INUSE); + av->top = p; + } + + } while ( (p = nextp) != 0); + + } + } while (fb++ != maxfb); + } + else { + malloc_init_state(av); + check_malloc_state(); + } +} + +/* + ------------------------------ realloc ------------------------------ +*/ + + +#if __STD_C +Void_t* rEALLOc(Void_t* oldmem, size_t bytes) +#else +Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + + INTERNAL_SIZE_T nb; /* padded request size */ + + mchunkptr oldp; /* chunk corresponding to oldmem */ + INTERNAL_SIZE_T oldsize; /* its size */ + + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + Void_t* newmem; /* corresponding user mem */ + + mchunkptr next; /* next contiguous chunk after oldp */ + + mchunkptr remainder; /* extra space at end of newp */ + unsigned long remainder_size; /* its size */ + + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + + unsigned long copysize; /* bytes to copy */ + unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */ + INTERNAL_SIZE_T* s; /* copy source */ + INTERNAL_SIZE_T* d; /* copy destination */ + + +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + fREe(oldmem); + return 0; + } +#endif + + /* realloc of null is supposed to be same as malloc */ + if (oldmem == 0) return mALLOc(bytes); + + checked_request2size(bytes, nb); + + oldp = mem2chunk(oldmem); + oldsize = chunksize(oldp); + + check_inuse_chunk(oldp); + + if (!chunk_is_mmapped(oldp)) { + + if ((unsigned long)(oldsize) >= (unsigned long)(nb)) { + /* already big enough; split below */ + newp = oldp; + newsize = oldsize; + } + + else { + next = chunk_at_offset(oldp, oldsize); + + /* Try to expand forward into top */ + if (next == av->top && + (unsigned long)(newsize = oldsize + chunksize(next)) >= + (unsigned long)(nb + MINSIZE)) { + set_head_size(oldp, nb); + av->top = chunk_at_offset(oldp, nb); + set_head(av->top, (newsize - nb) | PREV_INUSE); + return chunk2mem(oldp); + } + + /* Try to expand forward into next chunk; split off remainder below */ + else if (next != av->top && + !inuse(next) && + (unsigned long)(newsize = oldsize + chunksize(next)) >= + (unsigned long)(nb)) { + newp = oldp; + unlink(next, bck, fwd); + } + + /* allocate, copy, free */ + else { + newmem = mALLOc(nb - MALLOC_ALIGN_MASK); + if (newmem == 0) + return 0; /* propagate failure */ + + newp = mem2chunk(newmem); + newsize = chunksize(newp); + + /* + Avoid copy if newp is next chunk after oldp. + */ + if (newp == next) { + newsize += oldsize; + newp = oldp; + } + else { + /* + Unroll copy of <= 36 bytes (72 if 8byte sizes) + We know that contents have an odd number of + INTERNAL_SIZE_T-sized words; minimally 3. + */ + + copysize = oldsize - SIZE_SZ; + s = (INTERNAL_SIZE_T*)(oldmem); + d = (INTERNAL_SIZE_T*)(newmem); + ncopies = copysize / sizeof(INTERNAL_SIZE_T); + assert(ncopies >= 3); + + if (ncopies > 9) + MALLOC_COPY(d, s, copysize); + + else { + *(d+0) = *(s+0); + *(d+1) = *(s+1); + *(d+2) = *(s+2); + if (ncopies > 4) { + *(d+3) = *(s+3); + *(d+4) = *(s+4); + if (ncopies > 6) { + *(d+5) = *(s+5); + *(d+6) = *(s+6); + if (ncopies > 8) { + *(d+7) = *(s+7); + *(d+8) = *(s+8); + } + } + } + } + + fREe(oldmem); + check_inuse_chunk(newp); + return chunk2mem(newp); + } + } + } + + /* If possible, free extra space in old or extended chunk */ + + assert((unsigned long)(newsize) >= (unsigned long)(nb)); + + remainder_size = newsize - nb; + + if (remainder_size < MINSIZE) { /* not enough extra to split off */ + set_head_size(newp, newsize); + set_inuse_bit_at_offset(newp, newsize); + } + else { /* split remainder */ + remainder = chunk_at_offset(newp, nb); + set_head_size(newp, nb); + set_head(remainder, remainder_size | PREV_INUSE); + /* Mark remainder as inuse so free() won't complain */ + set_inuse_bit_at_offset(remainder, remainder_size); + fREe(chunk2mem(remainder)); + } + + check_inuse_chunk(newp); + return chunk2mem(newp); + } + + /* + Handle mmap cases + */ + + else { +#if HAVE_MMAP + +#if HAVE_MREMAP + INTERNAL_SIZE_T offset = oldp->prev_size; + size_t pagemask = av->pagesize - 1; + char *cp; + unsigned long sum; + + /* Note the extra SIZE_SZ overhead */ + newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask; + + /* don't need to remap if still within same page */ + if (oldsize == newsize - offset) + return oldmem; + + cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1); + + if (cp != (char*)MORECORE_FAILURE) { + + newp = (mchunkptr)(cp + offset); + set_head(newp, (newsize - offset)|IS_MMAPPED); + + assert(aligned_OK(chunk2mem(newp))); + assert((newp->prev_size == offset)); + + /* update statistics */ + sum = av->mmapped_mem += newsize - oldsize; + if (sum > (unsigned long)(av->max_mmapped_mem)) + av->max_mmapped_mem = sum; + sum += av->sbrked_mem; + if (sum > (unsigned long)(av->max_total_mem)) + av->max_total_mem = sum; + + return chunk2mem(newp); + } +#endif + + /* Note the extra SIZE_SZ overhead. */ + if ((unsigned long)(oldsize) >= (unsigned long)(nb + SIZE_SZ)) + newmem = oldmem; /* do nothing */ + else { + /* Must alloc, copy, free. */ + newmem = mALLOc(nb - MALLOC_ALIGN_MASK); + if (newmem != 0) { + MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); + fREe(oldmem); + } + } + return newmem; + +#else + /* If !HAVE_MMAP, but chunk_is_mmapped, user must have overwritten mem */ + check_malloc_state(); + MALLOC_FAILURE_ACTION; + return 0; +#endif + } +} + +/* + ------------------------------ memalign ------------------------------ +*/ + +#if __STD_C +Void_t* mEMALIGn(size_t alignment, size_t bytes) +#else +Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; +#endif +{ + INTERNAL_SIZE_T nb; /* padded request size */ + char* m; /* memory returned by malloc call */ + mchunkptr p; /* corresponding chunk */ + char* brk; /* alignment point within p */ + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + INTERNAL_SIZE_T leadsize; /* leading space before alignment point */ + mchunkptr remainder; /* spare room at end to split off */ + unsigned long remainder_size; /* its size */ + INTERNAL_SIZE_T size; + + /* If need less alignment than we give anyway, just relay to malloc */ + + if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); + + /* Otherwise, ensure that it is at least a minimum chunk size */ + + if (alignment < MINSIZE) alignment = MINSIZE; + + /* Make sure alignment is power of 2 (in case MINSIZE is not). */ + if ((alignment & (alignment - 1)) != 0) { + size_t a = MALLOC_ALIGNMENT * 2; + while ((unsigned long)a < (unsigned long)alignment) a <<= 1; + alignment = a; + } + + checked_request2size(bytes, nb); + + /* + Strategy: find a spot within that chunk that meets the alignment + request, and then possibly free the leading and trailing space. + */ + + + /* Call malloc with worst case padding to hit alignment. */ + + m = (char*)(mALLOc(nb + alignment + MINSIZE)); + + if (m == 0) return 0; /* propagate failure */ + + p = mem2chunk(m); + + if ((((unsigned long)(m)) % alignment) != 0) { /* misaligned */ + + /* + Find an aligned spot inside chunk. Since we need to give back + leading space in a chunk of at least MINSIZE, if the first + calculation places us at a spot with less than MINSIZE leader, + we can move to the next aligned spot -- we've allocated enough + total room so that this is always possible. + */ + + brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & + -((signed long) alignment)); + if ((unsigned long)(brk - (char*)(p)) < MINSIZE) + brk += alignment; + + newp = (mchunkptr)brk; + leadsize = brk - (char*)(p); + newsize = chunksize(p) - leadsize; + + /* For mmapped chunks, just adjust offset */ + if (chunk_is_mmapped(p)) { + newp->prev_size = p->prev_size + leadsize; + set_head(newp, newsize|IS_MMAPPED); + return chunk2mem(newp); + } + + /* Otherwise, give back leader, use the rest */ + set_head(newp, newsize | PREV_INUSE); + set_inuse_bit_at_offset(newp, newsize); + set_head_size(p, leadsize); + fREe(chunk2mem(p)); + p = newp; + + assert (newsize >= nb && + (((unsigned long)(chunk2mem(p))) % alignment) == 0); + } + + /* Also give back spare room at the end */ + if (!chunk_is_mmapped(p)) { + size = chunksize(p); + if ((unsigned long)(size) > (unsigned long)(nb + MINSIZE)) { + remainder_size = size - nb; + remainder = chunk_at_offset(p, nb); + set_head(remainder, remainder_size | PREV_INUSE); + set_head_size(p, nb); + fREe(chunk2mem(remainder)); + } + } + + check_inuse_chunk(p); + return chunk2mem(p); +} + +/* + ------------------------------ calloc ------------------------------ +*/ + +#if __STD_C +Void_t* cALLOc(size_t n_elements, size_t elem_size) +#else +Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size; +#endif +{ + mchunkptr p; + unsigned long clearsize; + unsigned long nclears; + INTERNAL_SIZE_T* d; + + Void_t* mem = mALLOc(n_elements * elem_size); + + if (mem != 0) { + p = mem2chunk(mem); + +#if MMAP_CLEARS + if (!chunk_is_mmapped(p)) /* don't need to clear mmapped space */ +#endif + { + /* + Unroll clear of <= 36 bytes (72 if 8byte sizes) + We know that contents have an odd number of + INTERNAL_SIZE_T-sized words; minimally 3. + */ + + d = (INTERNAL_SIZE_T*)mem; + clearsize = chunksize(p) - SIZE_SZ; + nclears = clearsize / sizeof(INTERNAL_SIZE_T); + assert(nclears >= 3); + + if (nclears > 9) + MALLOC_ZERO(d, clearsize); + + else { + *(d+0) = 0; + *(d+1) = 0; + *(d+2) = 0; + if (nclears > 4) { + *(d+3) = 0; + *(d+4) = 0; + if (nclears > 6) { + *(d+5) = 0; + *(d+6) = 0; + if (nclears > 8) { + *(d+7) = 0; + *(d+8) = 0; + } + } + } + } + } + } + return mem; +} + +/* + ------------------------------ cfree ------------------------------ +*/ + +#if __STD_C +void cFREe(Void_t *mem) +#else +void cFREe(mem) Void_t *mem; +#endif +{ + fREe(mem); +} + +/* + ------------------------- independent_calloc ------------------------- +*/ + +#if __STD_C +Void_t** iCALLOc(size_t n_elements, size_t elem_size, Void_t* chunks[]) +#else +Void_t** iCALLOc(n_elements, elem_size, chunks) size_t n_elements; size_t elem_size; Void_t* chunks[]; +#endif +{ + size_t sz = elem_size; /* serves as 1-element array */ + /* opts arg of 3 means all elements are same size, and should be cleared */ + return iALLOc(n_elements, &sz, 3, chunks); +} + +/* + ------------------------- independent_comalloc ------------------------- +*/ + +#if __STD_C +Void_t** iCOMALLOc(size_t n_elements, size_t sizes[], Void_t* chunks[]) +#else +Void_t** iCOMALLOc(n_elements, sizes, chunks) size_t n_elements; size_t sizes[]; Void_t* chunks[]; +#endif +{ + return iALLOc(n_elements, sizes, 0, chunks); +} + + +/* + ------------------------------ ialloc ------------------------------ + ialloc provides common support for independent_X routines, handling all of + the combinations that can result. + + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed +*/ + + +#if __STD_C +static Void_t** iALLOc(size_t n_elements, + size_t* sizes, + int opts, + Void_t* chunks[]) +#else +static Void_t** iALLOc(n_elements, sizes, opts, chunks) size_t n_elements; size_t* sizes; int opts; Void_t* chunks[]; +#endif +{ + mstate av = get_malloc_state(); + INTERNAL_SIZE_T element_size; /* chunksize of each element, if all same */ + INTERNAL_SIZE_T contents_size; /* total size of elements */ + INTERNAL_SIZE_T array_size; /* request size of pointer array */ + Void_t* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + INTERNAL_SIZE_T remainder_size; /* remaining bytes while splitting */ + Void_t** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + int mmx; /* to disable mmap */ + INTERNAL_SIZE_T size; + size_t i; + + /* Ensure initialization/consolidation */ + if (have_fastchunks(av)) malloc_consolidate(av); + + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (Void_t**) mALLOc(0); + marray = 0; + array_size = request2size(n_elements * (sizeof(Void_t*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + /* subtract out alignment bytes from total to minimize overallocation */ + size = contents_size + array_size - MALLOC_ALIGN_MASK; + + /* + Allocate the aggregate chunk. + But first disable mmap so malloc won't use it, since + we would not be able to later free/realloc space internal + to a segregated mmap region. + */ + mmx = av->n_mmaps_max; /* disable mmap */ + av->n_mmaps_max = 0; + mem = mALLOc(size); + av->n_mmaps_max = mmx; /* reset mmap */ + if (mem == 0) + return 0; + + p = mem2chunk(mem); + assert(!chunk_is_mmapped(p)); + remainder_size = chunksize(p); + + if (opts & 0x2) { /* optionally clear the elements */ + MALLOC_ZERO(mem, remainder_size - SIZE_SZ - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + array_chunk = chunk_at_offset(p, contents_size); + marray = (Void_t**) (chunk2mem(array_chunk)); + set_head(array_chunk, (remainder_size - contents_size) | PREV_INUSE); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_head(p, size | PREV_INUSE); + p = chunk_at_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_head(p, remainder_size | PREV_INUSE); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) + assert(remainder_size == element_size); + else + assert(remainder_size == request2size(sizes[i])); + check_inuse_chunk(mem2chunk(marray)); + } + + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(mem2chunk(marray[i])); +#endif + + return marray; +} + + +/* + ------------------------------ valloc ------------------------------ +*/ + +#if __STD_C +Void_t* vALLOc(size_t bytes) +#else +Void_t* vALLOc(bytes) size_t bytes; +#endif +{ + /* Ensure initialization/consolidation */ + mstate av = get_malloc_state(); + if (have_fastchunks(av)) malloc_consolidate(av); + return mEMALIGn(av->pagesize, bytes); +} + +/* + ------------------------------ pvalloc ------------------------------ +*/ + + +#if __STD_C +Void_t* pVALLOc(size_t bytes) +#else +Void_t* pVALLOc(bytes) size_t bytes; +#endif +{ + mstate av = get_malloc_state(); + size_t pagesz; + + /* Ensure initialization/consolidation */ + if (have_fastchunks(av)) malloc_consolidate(av); + pagesz = av->pagesize; + return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1)); +} + + +/* + ------------------------------ malloc_trim ------------------------------ +*/ + +#if __STD_C +int mTRIm(size_t pad) +#else +int mTRIm(pad) size_t pad; +#endif +{ + mstate av = get_malloc_state(); + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + +#ifndef MORECORE_CANNOT_TRIM + return sYSTRIm(pad, av); +#else + return 0; +#endif +} + + +/* + ------------------------- malloc_usable_size ------------------------- +*/ + +#if __STD_C +size_t mUSABLe(Void_t* mem) +#else +size_t mUSABLe(mem) Void_t* mem; +#endif +{ + mchunkptr p; + if (mem != 0) { + p = mem2chunk(mem); + if (chunk_is_mmapped(p)) + return chunksize(p) - 2*SIZE_SZ; + else if (inuse(p)) + return chunksize(p) - SIZE_SZ; + } + return 0; +} + +/* + ------------------------------ mallinfo ------------------------------ +*/ + +struct mallinfo mALLINFo() +{ + mstate av = get_malloc_state(); + struct mallinfo mi; + int i; + mbinptr b; + mchunkptr p; + INTERNAL_SIZE_T avail; + INTERNAL_SIZE_T fastavail; + int nblocks; + int nfastblocks; + + /* Ensure initialization */ + if (av->top == 0) malloc_consolidate(av); + + check_malloc_state(); + + /* Account for top */ + avail = chunksize(av->top); + nblocks = 1; /* top always exists */ + + /* traverse fastbins */ + nfastblocks = 0; + fastavail = 0; + + for (i = 0; i < NFASTBINS; ++i) { + for (p = av->fastbins[i]; p != 0; p = p->fd) { + ++nfastblocks; + fastavail += chunksize(p); + } + } + + avail += fastavail; + + /* traverse regular bins */ + for (i = 1; i < NBINS; ++i) { + b = bin_at(av, i); + for (p = last(b); p != b; p = p->bk) { + ++nblocks; + avail += chunksize(p); + } + } + + mi.smblks = nfastblocks; + mi.ordblks = nblocks; + mi.fordblks = avail; + mi.uordblks = av->sbrked_mem - avail; + mi.arena = av->sbrked_mem; + mi.hblks = av->n_mmaps; + mi.hblkhd = av->mmapped_mem; + mi.fsmblks = fastavail; + mi.keepcost = chunksize(av->top); + mi.usmblks = av->max_total_mem; + return mi; +} + +/* + ------------------------------ malloc_stats ------------------------------ +*/ + +void mSTATs() +{ + struct mallinfo mi = mALLINFo(); + +#ifdef WIN32 + { + unsigned long free, reserved, committed; + vminfo (&free, &reserved, &committed); + fprintf(stderr, "free bytes = %10lu\n", + free); + fprintf(stderr, "reserved bytes = %10lu\n", + reserved); + fprintf(stderr, "committed bytes = %10lu\n", + committed); + } +#endif + + + fprintf(stderr, "max system bytes = %10lu\n", + (unsigned long)(mi.usmblks)); + fprintf(stderr, "system bytes = %10lu\n", + (unsigned long)(mi.arena + mi.hblkhd)); + fprintf(stderr, "in use bytes = %10lu\n", + (unsigned long)(mi.uordblks + mi.hblkhd)); + + +#ifdef WIN32 + { + unsigned long kernel, user; + if (cpuinfo (TRUE, &kernel, &user)) { + fprintf(stderr, "kernel ms = %10lu\n", + kernel); + fprintf(stderr, "user ms = %10lu\n", + user); + } + } +#endif +} + + +/* + ------------------------------ mallopt ------------------------------ +*/ + +#if __STD_C +int mALLOPt(int param_number, int value) +#else +int mALLOPt(param_number, value) int param_number; int value; +#endif +{ + mstate av = get_malloc_state(); + /* Ensure initialization/consolidation */ + malloc_consolidate(av); + + switch(param_number) { + case M_MXFAST: + if (value >= 0 && value <= MAX_FAST_SIZE) { + set_max_fast(av, value); + return 1; + } + else + return 0; + + case M_TRIM_THRESHOLD: + av->trim_threshold = value; + return 1; + + case M_TOP_PAD: + av->top_pad = value; + return 1; + + case M_MMAP_THRESHOLD: + av->mmap_threshold = value; + return 1; + + case M_MMAP_MAX: +#if !HAVE_MMAP + if (value != 0) + return 0; +#endif + av->n_mmaps_max = value; + return 1; + + default: + return 0; + } +} + + +/* + -------------------- Alternative MORECORE functions -------------------- +*/ + + +/* + General Requirements for MORECORE. + + The MORECORE function must have the following properties: + + If MORECORE_CONTIGUOUS is false: + + * MORECORE must allocate in multiples of pagesize. It will + only be called with arguments that are multiples of pagesize. + + * MORECORE(0) must return an address that is at least + MALLOC_ALIGNMENT aligned. (Page-aligning always suffices.) + + else (i.e. If MORECORE_CONTIGUOUS is true): + + * Consecutive calls to MORECORE with positive arguments + return increasing addresses, indicating that space has been + contiguously extended. + + * MORECORE need not allocate in multiples of pagesize. + Calls to MORECORE need not have args of multiples of pagesize. + + * MORECORE need not page-align. + + In either case: + + * MORECORE may allocate more memory than requested. (Or even less, + but this will generally result in a malloc failure.) + + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. This malloc does NOT call MORECORE(0) + until at least one call with positive arguments is made, so + the initial value returned is not important. + + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + + * MORECORE need not handle negative arguments -- it may instead + just return MORECORE_FAILURE when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + There is some variation across systems about the type of the + argument to sbrk/MORECORE. If size_t is unsigned, then it cannot + actually be size_t, because sbrk supports negative args, so it is + normally the signed type of the same width as size_t (sometimes + declared as "intptr_t", and sometimes "ptrdiff_t"). It doesn't much + matter though. Internally, we use "long" as arguments, which should + work across all reasonable possibilities. + + Additionally, if MORECORE ever returns failure for a positive + request, and HAVE_MMAP is true, then mmap is used as a noncontiguous + system allocator. This is a useful backup strategy for systems with + holes in address spaces -- in this case sbrk cannot contiguously + expand the heap, but mmap may be able to map noncontiguous space. + + If you'd like mmap to ALWAYS be used, you can define MORECORE to be + a function that always returns MORECORE_FAILURE. + + If you are using this malloc with something other than sbrk (or its + emulation) to supply memory regions, you probably want to set + MORECORE_CONTIGUOUS as false. As an example, here is a custom + allocator kindly contributed for pre-OSX macOS. It uses virtually + but not necessarily physically contiguous non-paged memory (locked + in, present and won't get swapped out). You can use it by + uncommenting this section, adding some #includes, and setting up the + appropriate defines above: + + #define MORECORE osMoreCore + #define MORECORE_CONTIGUOUS 0 + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MORECORE_FAILURE; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((unsigned long) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MORECORE_FAILURE; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* + -------------------------------------------------------------- + + Emulation of sbrk for win32. + Donated by J. Walter . + For additional information about this code, and malloc on Win32, see + http://www.genesys-e.de/jwalter/ +*/ + + +#ifdef WIN32 + +#ifdef _DEBUG +/* #define TRACE */ +#endif + +/* Support for USE_MALLOC_LOCK */ +#ifdef USE_MALLOC_LOCK + +/* Wait for spin lock */ +static int slwait (int *sl) { + while (InterlockedCompareExchange ((void **) sl, (void *) 1, (void *) 0) != 0) + Sleep (0); + return 0; +} + +/* Release spin lock */ +static int slrelease (int *sl) { + InterlockedExchange (sl, 0); + return 0; +} + +#ifdef NEEDED +/* Spin lock for emulation code */ +static int g_sl; +#endif + +#endif /* USE_MALLOC_LOCK */ + +/* getpagesize for windows */ +static long getpagesize (void) { + static long g_pagesize = 0; + if (! g_pagesize) { + SYSTEM_INFO system_info; + GetSystemInfo (&system_info); + g_pagesize = system_info.dwPageSize; + } + return g_pagesize; +} +static long getregionsize (void) { + static long g_regionsize = 0; + if (! g_regionsize) { + SYSTEM_INFO system_info; + GetSystemInfo (&system_info); + g_regionsize = system_info.dwAllocationGranularity; + } + return g_regionsize; +} + +/* A region list entry */ +typedef struct _region_list_entry { + void *top_allocated; + void *top_committed; + void *top_reserved; + long reserve_size; + struct _region_list_entry *previous; +} region_list_entry; + +/* Allocate and link a region entry in the region list */ +static int region_list_append (region_list_entry **last, void *base_reserved, long reserve_size) { + region_list_entry *next = HeapAlloc (GetProcessHeap (), 0, sizeof (region_list_entry)); + if (! next) + return FALSE; + next->top_allocated = (char *) base_reserved; + next->top_committed = (char *) base_reserved; + next->top_reserved = (char *) base_reserved + reserve_size; + next->reserve_size = reserve_size; + next->previous = *last; + *last = next; + return TRUE; +} +/* Free and unlink the last region entry from the region list */ +static int region_list_remove (region_list_entry **last) { + region_list_entry *previous = (*last)->previous; + if (! HeapFree (GetProcessHeap (), sizeof (region_list_entry), *last)) + return FALSE; + *last = previous; + return TRUE; +} + +#define CEIL(size,to) (((size)+(to)-1)&~((to)-1)) +#define FLOOR(size,to) ((size)&~((to)-1)) + +#define SBRK_SCALE 0 +/* #define SBRK_SCALE 1 */ +/* #define SBRK_SCALE 2 */ +/* #define SBRK_SCALE 4 */ + +/* sbrk for windows */ +static void *sbrk (long size) { + static long g_pagesize, g_my_pagesize; + static long g_regionsize, g_my_regionsize; + static region_list_entry *g_last; + void *result = (void *) MORECORE_FAILURE; +#ifdef TRACE + printf ("sbrk %d\n", size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) { + g_pagesize = getpagesize (); + g_my_pagesize = g_pagesize << SBRK_SCALE; + } + if (! g_regionsize) { + g_regionsize = getregionsize (); + g_my_regionsize = g_regionsize << SBRK_SCALE; + } + if (! g_last) { + if (! region_list_append (&g_last, 0, 0)) + goto sbrk_exit; + } + /* Assert invariants */ + assert (g_last); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && + g_last->top_allocated <= g_last->top_committed); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && + g_last->top_committed <= g_last->top_reserved && + (unsigned) g_last->top_committed % g_pagesize == 0); + assert ((unsigned) g_last->top_reserved % g_regionsize == 0); + assert ((unsigned) g_last->reserve_size % g_regionsize == 0); + /* Allocation requested? */ + if (size >= 0) { + /* Allocation size is the requested size */ + long allocate_size = size; + /* Compute the size to commit */ + long to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Do we reach the commit limit? */ + if (to_commit > 0) { + /* Round size to commit */ + long commit_size = CEIL (to_commit, g_my_pagesize); + /* Compute the size to reserve */ + long to_reserve = (char *) g_last->top_committed + commit_size - (char *) g_last->top_reserved; + /* Do we reach the reserve limit? */ + if (to_reserve > 0) { + /* Compute the remaining size to commit in the current region */ + long remaining_commit_size = (char *) g_last->top_reserved - (char *) g_last->top_committed; + if (remaining_commit_size > 0) { + /* Assert preconditions */ + assert ((unsigned) g_last->top_committed % g_pagesize == 0); + assert (0 < remaining_commit_size && remaining_commit_size % g_pagesize == 0); { + /* Commit this */ + void *base_committed = VirtualAlloc (g_last->top_committed, remaining_commit_size, + MEM_COMMIT, PAGE_READWRITE); + /* Check returned pointer for consistency */ + if (base_committed != g_last->top_committed) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", base_committed, remaining_commit_size); +#endif + /* Adjust the regions commit top */ + g_last->top_committed = (char *) base_committed + remaining_commit_size; + } + } { + /* Now we are going to search and reserve. */ + int contiguous = -1; + int found = FALSE; + MEMORY_BASIC_INFORMATION memory_info; + void *base_reserved; + long reserve_size; + do { + /* Assume contiguous memory */ + contiguous = TRUE; + /* Round size to reserve */ + reserve_size = CEIL (to_reserve, g_my_regionsize); + /* Start with the current region's top */ + memory_info.BaseAddress = g_last->top_reserved; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { + /* Assert postconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); +#ifdef TRACE + printf ("Query %p %d %s\n", memory_info.BaseAddress, memory_info.RegionSize, + memory_info.State == MEM_FREE ? "FREE": + (memory_info.State == MEM_RESERVE ? "RESERVED": + (memory_info.State == MEM_COMMIT ? "COMMITTED": "?"))); +#endif + /* Region is free, well aligned and big enough: we are done */ + if (memory_info.State == MEM_FREE && + (unsigned) memory_info.BaseAddress % g_regionsize == 0 && + memory_info.RegionSize >= (unsigned) reserve_size) { + found = TRUE; + break; + } + /* From now on we can't get contiguous memory! */ + contiguous = FALSE; + /* Recompute size to reserve */ + reserve_size = CEIL (allocate_size, g_my_regionsize); + memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_pagesize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + } + /* Search failed? */ + if (! found) + goto sbrk_exit; + /* Assert preconditions */ + assert ((unsigned) memory_info.BaseAddress % g_regionsize == 0); + assert (0 < reserve_size && reserve_size % g_regionsize == 0); + /* Try to reserve this */ + base_reserved = VirtualAlloc (memory_info.BaseAddress, reserve_size, + MEM_RESERVE, PAGE_NOACCESS); + if (! base_reserved) { + int rc = GetLastError (); + if (rc != ERROR_INVALID_ADDRESS) + goto sbrk_exit; + } + /* A null pointer signals (hopefully) a race condition with another thread. */ + /* In this case, we try again. */ + } while (! base_reserved); + /* Check returned pointer for consistency */ + if (memory_info.BaseAddress && base_reserved != memory_info.BaseAddress) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_reserved % g_regionsize == 0); +#ifdef TRACE + printf ("Reserve %p %d\n", base_reserved, reserve_size); +#endif + /* Did we get contiguous memory? */ + if (contiguous) { + long start_size = (char *) g_last->top_committed - (char *) g_last->top_allocated; + /* Adjust allocation size */ + allocate_size -= start_size; + /* Adjust the regions allocation top */ + g_last->top_allocated = g_last->top_committed; + /* Recompute the size to commit */ + to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Round size to commit */ + commit_size = CEIL (to_commit, g_my_pagesize); + } + /* Append the new region to the list */ + if (! region_list_append (&g_last, base_reserved, reserve_size)) + goto sbrk_exit; + /* Didn't we get contiguous memory? */ + if (! contiguous) { + /* Recompute the size to commit */ + to_commit = (char *) g_last->top_allocated + allocate_size - (char *) g_last->top_committed; + /* Round size to commit */ + commit_size = CEIL (to_commit, g_my_pagesize); + } + } + } + /* Assert preconditions */ + assert ((unsigned) g_last->top_committed % g_pagesize == 0); + assert (0 < commit_size && commit_size % g_pagesize == 0); { + /* Commit this */ + void *base_committed = VirtualAlloc (g_last->top_committed, commit_size, + MEM_COMMIT, PAGE_READWRITE); + /* Check returned pointer for consistency */ + if (base_committed != g_last->top_committed) + goto sbrk_exit; + /* Assert postconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", base_committed, commit_size); +#endif + /* Adjust the regions commit top */ + g_last->top_committed = (char *) base_committed + commit_size; + } + } + /* Adjust the regions allocation top */ + g_last->top_allocated = (char *) g_last->top_allocated + allocate_size; + result = (char *) g_last->top_allocated - size; + /* Deallocation requested? */ + } else if (size < 0) { + long deallocate_size = - size; + /* As long as we have a region to release */ + while ((char *) g_last->top_allocated - deallocate_size < (char *) g_last->top_reserved - g_last->reserve_size) { + /* Get the size to release */ + long release_size = g_last->reserve_size; + /* Get the base address */ + void *base_reserved = (char *) g_last->top_reserved - release_size; + /* Assert preconditions */ + assert ((unsigned) base_reserved % g_regionsize == 0); + assert (0 < release_size && release_size % g_regionsize == 0); { + /* Release this */ + int rc = VirtualFree (base_reserved, 0, + MEM_RELEASE); + /* Check returned code for consistency */ + if (! rc) + goto sbrk_exit; +#ifdef TRACE + printf ("Release %p %d\n", base_reserved, release_size); +#endif + } + /* Adjust deallocation size */ + deallocate_size -= (char *) g_last->top_allocated - (char *) base_reserved; + /* Remove the old region from the list */ + if (! region_list_remove (&g_last)) + goto sbrk_exit; + } { + /* Compute the size to decommit */ + long to_decommit = (char *) g_last->top_committed - ((char *) g_last->top_allocated - deallocate_size); + if (to_decommit >= g_my_pagesize) { + /* Compute the size to decommit */ + long decommit_size = FLOOR (to_decommit, g_my_pagesize); + /* Compute the base address */ + void *base_committed = (char *) g_last->top_committed - decommit_size; + /* Assert preconditions */ + assert ((unsigned) base_committed % g_pagesize == 0); + assert (0 < decommit_size && decommit_size % g_pagesize == 0); { + /* Decommit this */ + int rc = VirtualFree ((char *) base_committed, decommit_size, + MEM_DECOMMIT); + /* Check returned code for consistency */ + if (! rc) + goto sbrk_exit; +#ifdef TRACE + printf ("Decommit %p %d\n", base_committed, decommit_size); +#endif + } + /* Adjust deallocation size and regions commit and allocate top */ + deallocate_size -= (char *) g_last->top_allocated - (char *) base_committed; + g_last->top_committed = base_committed; + g_last->top_allocated = base_committed; + } + } + /* Adjust regions allocate top */ + g_last->top_allocated = (char *) g_last->top_allocated - deallocate_size; + /* Check for underflow */ + if ((char *) g_last->top_reserved - g_last->reserve_size > (char *) g_last->top_allocated || + g_last->top_allocated > g_last->top_committed) { + /* Adjust regions allocate top */ + g_last->top_allocated = (char *) g_last->top_reserved - g_last->reserve_size; + goto sbrk_exit; + } + result = g_last->top_allocated; + } + /* Assert invariants */ + assert (g_last); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_allocated && + g_last->top_allocated <= g_last->top_committed); + assert ((char *) g_last->top_reserved - g_last->reserve_size <= (char *) g_last->top_committed && + g_last->top_committed <= g_last->top_reserved && + (unsigned) g_last->top_committed % g_pagesize == 0); + assert ((unsigned) g_last->top_reserved % g_regionsize == 0); + assert ((unsigned) g_last->reserve_size % g_regionsize == 0); + +sbrk_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return result; +} + +/* mmap for windows */ +static void *mmap (void *ptr, long size, long prot, long type, long handle, long arg) { + static long g_pagesize; + static long g_regionsize; +#ifdef TRACE + printf ("mmap %d\n", size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) + g_pagesize = getpagesize (); + if (! g_regionsize) + g_regionsize = getregionsize (); + /* Assert preconditions */ + assert ((unsigned) ptr % g_regionsize == 0); + assert (size % g_pagesize == 0); + /* Allocate this */ + ptr = VirtualAlloc (ptr, size, + MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE); + if (! ptr) { + ptr = (void *) MORECORE_FAILURE; + goto mmap_exit; + } + /* Assert postconditions */ + assert ((unsigned) ptr % g_regionsize == 0); +#ifdef TRACE + printf ("Commit %p %d\n", ptr, size); +#endif +mmap_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return ptr; +} + +/* munmap for windows */ +static long munmap (void *ptr, long size) { + static long g_pagesize; + static long g_regionsize; + int rc = MUNMAP_FAILURE; +#ifdef TRACE + printf ("munmap %p %d\n", ptr, size); +#endif +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Wait for spin lock */ + slwait (&g_sl); +#endif + /* First time initialization */ + if (! g_pagesize) + g_pagesize = getpagesize (); + if (! g_regionsize) + g_regionsize = getregionsize (); + /* Assert preconditions */ + assert ((unsigned) ptr % g_regionsize == 0); + assert (size % g_pagesize == 0); + /* Free this */ + if (! VirtualFree (ptr, 0, + MEM_RELEASE)) + goto munmap_exit; + rc = 0; +#ifdef TRACE + printf ("Release %p %d\n", ptr, size); +#endif +munmap_exit: +#if defined (USE_MALLOC_LOCK) && defined (NEEDED) + /* Release spin lock */ + slrelease (&g_sl); +#endif + return rc; +} + +static void vminfo (unsigned long *free, unsigned long *reserved, unsigned long *committed) { + MEMORY_BASIC_INFORMATION memory_info; + memory_info.BaseAddress = 0; + *free = *reserved = *committed = 0; + while (VirtualQuery (memory_info.BaseAddress, &memory_info, sizeof (memory_info))) { + switch (memory_info.State) { + case MEM_FREE: + *free += memory_info.RegionSize; + break; + case MEM_RESERVE: + *reserved += memory_info.RegionSize; + break; + case MEM_COMMIT: + *committed += memory_info.RegionSize; + break; + } + memory_info.BaseAddress = (char *) memory_info.BaseAddress + memory_info.RegionSize; + } +} + +static int cpuinfo (int whole, unsigned long *kernel, unsigned long *user) { + if (whole) { + __int64 creation64, exit64, kernel64, user64; + int rc = GetProcessTimes (GetCurrentProcess (), + (FILETIME *) &creation64, + (FILETIME *) &exit64, + (FILETIME *) &kernel64, + (FILETIME *) &user64); + if (! rc) { + *kernel = 0; + *user = 0; + return FALSE; + } + *kernel = (unsigned long) (kernel64 / 10000); + *user = (unsigned long) (user64 / 10000); + return TRUE; + } else { + __int64 creation64, exit64, kernel64, user64; + int rc = GetThreadTimes (GetCurrentThread (), + (FILETIME *) &creation64, + (FILETIME *) &exit64, + (FILETIME *) &kernel64, + (FILETIME *) &user64); + if (! rc) { + *kernel = 0; + *user = 0; + return FALSE; + } + *kernel = (unsigned long) (kernel64 / 10000); + *user = (unsigned long) (user64 / 10000); + return TRUE; + } +} + +#endif /* WIN32 */ + +/* ------------------------------------------------------------ +History: + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sYSMALLOc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ diff --git a/libbanshee/engine/nonspec.c b/libbanshee/engine/nonspec.c new file mode 100644 index 00000000000..96e0652d2cb --- /dev/null +++ b/libbanshee/engine/nonspec.c @@ -0,0 +1,852 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "banshee.h" +#include "flowrow-sort.h" +#include "flowrow-var.h" +#include "setif-sort.h" +#include "setif-var.h" +#include "setst-sort.h" +#include "setst-var.h" +#include "term-sort.h" +#include "term-var.h" + +struct constructor +{ + sort_kind sort; + int type; + int arity; + char *name; + sig_elt *sig; +}; + +typedef struct constructor *constructor; + +typedef enum +{ + vnc_pos, + vnc_neg, + vnc_non +} vnc_kind; + +struct sig_elt +{ + vnc_kind variance; + sort_kind sort; +}; + +typedef struct sig_elt sig_elt; + +typedef struct proj_pat +{ + sort_kind sort; + int type; + stamp st; + int i; + gen_e exp; + vnc_kind variance; + constructor c; +} *proj_pat; + + +typedef struct cons_expr +{ + sort_kind sort; + int type; + stamp st; + int arity; + char *name; + sig_elt *sig; + gen_e *exps; +} * cons_expr; + + +static int new_type() +{ + static int type = 10; + int ret = type; + if (type > 2000) + { + fprintf(stderr, "Exceeded maximum number of constructors\n"); + assert(0); + } + type += 2; + return ret; +} + +static bool fixed_sort(sort_kind s) +{ + return !(s == sort_term || s == sort_set); +} + +/* + Convention : constructor types are even, pats are odd. + The smallest specialized type is 10. +*/ +static bool setif_is_pat(gen_e e) +{ + int type = ((setif_term)e)->type; + return ( (type & 1) && (type > 10) ); +} + +static bool setst_is_pat(gen_e e) +{ + int type = ((setst_term)e)->type; + return ( (type & 1) && (type > 10) ); +} + +static gen_e get_proj_var(sort_kind s, bool large) +{ + switch (s) + { + case setif_sort: + { + if (large) + return (gen_e)sv_fresh_large(get_sort_region(setif_sort),NULL); + else return (gen_e)sv_fresh(get_sort_region(setif_sort),NULL); + } + break; + case setst_sort: + { + if (large) + return (gen_e)st_fresh_large(get_sort_region(setst_sort),NULL); + else return (gen_e)st_fresh(get_sort_region(setst_sort),NULL); + } + break; + case flowrow_sort: + { + if (large) + return (gen_e)fv_fresh_large(get_sort_region(flowrow_sort),NULL); + else return (gen_e)fv_fresh(get_sort_region(flowrow_sort),NULL); + } + break; + case term_sort: + { + if (large) + return (gen_e)tv_fresh_large(get_sort_region(term_sort),NULL); + else return (gen_e)tv_fresh(get_sort_region(term_sort),NULL) + } + break; + default: + { + fail("Unmatched sort in get_proj_var\n"); + return NULL; + } + break; + } + + return NULL; +} + +static gen_e get_sort_zero(sort_kind s) +{ +switch (s) + { + case setif_sort: + return setif_zero(); + case setst_sort: + return setst_zero(); + case flowrow_sort: + return flowrow_zero(); + case term_sort: + return term_zero(); + default: + fail("Unmatched sort in get_sort_zero\n"); + return NULL; + } + return NULL; +} + +static gen_e get_sort_one(sort_kind s) +{ +switch (s) + { + case setif_sort: + return setif_one(); + case setst_sort: + return setst_one(); + case flowrow_sort: + return flowrow_one(); + case term_sort: + return term_one(); + default: + fail("Unmatched sort in get_sort_zero\n"); + return NULL; + } + return NULL; +} + +static region get_sort_region(sort s) +{ + switch (s) + { + case setif_sort: + return setif_region; + case setst_sort: + return setst_region; + case flowrow_sort: + return flowrow_region; + case term_sort: + return term_region: + default: + fail("Unmatched sort in get_sort_region\n"); + return NULL; + } + return NULL; +} + +static term_hash get_sort_hash(sort s) +{ + switch (s) + { + case setif_sort: + return setif_hash; + case setst_sort: + return setst_hash; + case flowrow_sort: + return flowrow_hash; + case term_sort: + return term_hash: + default: + fail("Unmatched sort in get_sort_hash\n"); + return NULL; + } + return NULL; +} + +constructor make_constructor(const char *name,sort_kind sort, sig_elt s[], + int arity) +{ + constructor c = ralloc(expr_region,struct constructor); + sig_elt *sig = rarrayalloc(expr_region,arity,sig_elt); + + c->type = new_type(); + + if (arity) + { + memcpy(sig,s,sizeof(sig_elt)*arity); + } + + if ( fixed_sort(sort) ) + failure("Specified sort does not allow constructor types\n"); + + c->sort = sort; + c->arity = arity; + c->name = rstrdup(expr_region,name); + c->sig = sig; + + return c; +} + +gen_e constructor_expr(constructor c, gen_e exps[], int arity) +{ + cons_expr result; + int i; + region sort_region = get_sort_region(c->sort); + term_hash sort_hash = get_sort_hash(c->sort); + + stamp *st = rarrayalloc(sort_region,arity + 1,stamp); + st[0] = c->type; + + // Dynamic arity check + if(arity != c->arity) + failure("Signature mismatch\n"); + + // Dynamic sort checks + for (i = 0; i < arity; i++) + { + if ( c->sig[i].sort != exps[i]->sort) + failure(stderr,"Signature mismatch\n"); + st[i+1] = exps[i]->st; + } + + // Hash-consing of terms + if (!(result = term_hash_find(sort_hash,st,arity+1)) || arity == 0 ) + { + gen_e *e = rarrayalloc(sort_region,arity,gen_e); + + if (arity) + memcpy(e,exps,sizeof(gen_e)*arity); + else + e = NULL; + + result = ralloc(sort_region,struct cons_expr); + result->type = st[0]; + result->st = stamp_fresh(); + result->sort = c->sort; + result->arity = c->arity; + result->name = c->name; + result->sig = c->sig; + result->exps = e; + + term_hash_insert(expr_hash,result,st,arity+1); + } + + return (gen_e)result; +} + +static gen_e proj_pat(constructor c, int i, gen_e e) +{ + proj_pat pat; + region sort_region = get_sort_region(e->sort); + term_hash sort_hash = get_sort_hash(e->sort); + + stamp s[3]; + s[0] = c->type + 1; + s[1] = e->st; + s[2] = i; + + if (! (pat = term_hash_find(sort_hash,s,3)) ) + { + pat = ralloc(sort_region,struct proj_pat); + pat->type = s[0]; + pat->st = stamp_fresh(); + pat->sort = c->sort; + pat->exp = e; + pat->variance = c->sig[i].variance; + pat->c = c; + pat->i = i; + term_hash_insert(sort_hash,pat,s,3); + } + + return (gen_e)pat; +} + +gen_e setif_proj_pat(constructor c,int i,gen_e e) +{ + return proj_pat(c,i,e); +} + +gen_e setst_proj_pat(constructor c, int i, gen_e e) +{ + return proj_pat(c,i,e); +} + +gen_e setif_proj(constructor c, int i, gen_e e) +{ + setif_var v; + gen_e proj_var, proj; + + gen_e nonspec_get_proj(gen_e_list arg1) + { + proj_pat pat; + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list_scan(arg1,&scan); + while (gen_e_list_next(&scan,&temp)) + { + pat = (proj_pat)temp; + if ( pat_match(pat->type,c->type) && i == pat->i ) + return pat->exp; + } + return NULL; + } + + if (e->sort != setif_sort) + { + failure("Sort check : setif_proj\n"); + } + + else if (i < 0 || i > c->arity) + { + failure("Signature mismatch\n"); + } + + else if (setif_is_zero(e)) + return get_sort_zero(c->sig[i].sort); + + else if ( ((setif_term)e)->type == c->type ) + { + cons_expr constructed = (cons_expr)e; + return constructed->exps[i]; + } + + else if (setif_is_var(e)) + { + v = (setif_var)e; + if ( (proj = sv_get_ub_proj(v,nonspec_get_proj)) ) + { + return proj; + } + else + { + gen_e pat; + gen_e_list_scanner scan; + gen_e lb; + proj_var = get_proj_var(c->sig[i].sort,FALSE); + pat = setif_proj_pat(c,i,proj_var); + sv_add_ub_proj(sort_region,v,pat); + + gen_e_list_scan(sv_get_lbs(v),&scan); + while (gen_e_list_next(&scan,&lb)) + { + setif_inclusion(lb,pat); + } + return proj_var; + } + } + + else if (setif_is_union(e)) + { + if( (proj = nonspec_get_proj(setif_get_proj_cache(e))) ) + return proj; + else + { + gen_e pat; + proj_var = get_proj_var(c->sig[i].sort,FALSE); + pat = setif_proj_pat(c,i,proj_var); + + setif_set_proj_cache(e,pat); + + setif_inclusion(e,pat); + return proj_var; + } + } + else + { + gen_e pat; + proj_var = get_proj_var(c->sig[i].sort,FALSE); + pat = setif_proj_pat(c,i,proj_var); + setif_inclusion(e,pat); + return proj_var; + } +} + +gen_e setst_proj(constructor c, int i, gen_e e) +{ + setst_var v; + gen_e proj_var, proj; + + gen_e nonspec_get_proj(gen_e_list arg1) + { + proj_pat pat; + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list_scan(arg1,&scan); + while (gen_e_list_next(&scan,&temp)) + { + pat = (proj_pat)temp; + if ( pat_match(pat->type,c->type) && i == pat->i ) + return pat->exp; + } + return NULL; + } + + if (e->sort != setst_sort) + { + failure("Sort check : setst_proj\n"); + } + + else if (i < 0 || i > c->arity) + { + failure("Signature mismatch\n"); + } + + else if (setst_is_zero(e)) + return get_sort_zero(c->sig[i].sort); + + else if ( ((setst_term)e)->type == c->type ) + { + cons_expr constructed = (cons_expr)e; + return constructed->exps[i]; + } + + else if (setst_is_var(e)) + { + v = (setst_var)e; + if ( (proj = sv_get_ub_proj(v,nonspec_get_proj)) ) + { + return proj; + } + else + { + gen_e pat; + gen_e_list_scanner scan; + gen_e lb; + proj_var = get_proj_var(c->sig[i].sort,FALSE); + pat = setst_proj_pat(c,i,proj_var); + sv_add_ub_proj(sort_region,v,pat); + + gen_e_list_scan(sv_get_lbs(v),&scan); + while (gen_e_list_next(&scan,&lb)) + { + setst_inclusion(lb,pat); + } + return proj_var; + } + } + + else if (setst_is_union(e)) + { + if( (proj = nonspec_get_proj(setst_get_proj_cache(e))) ) + return proj; + else + { + gen_e pat; + proj_var = get_proj_var(c->sig[i].sort,FALSE); + pat = setst_proj_pat(c,i,proj_var); + + setst_set_proj_cache(e,pat); + + setst_inclusion(e,pat); + return proj_var; + } + } + else + { + gen_e pat; + proj_var = get_proj_var(c->sig[i].sort,FALSE); + pat = setst_proj_pat(c,i,proj_var); + setst_inclusion(e,pat); + return proj_var; + } +} + +static void setif_con_match(gen_e e1, gen_e e2) +{ + // Case where e1 is a constructor expression and e2 is a proj_pat + if (pat_match(((setif_term)e2)->type,((setif_term)e1)->type)) + { + cons_expr c = (cons_expr)e1; + proj_pat p = (proj_pat)e2; + int i = p->i; + + if (c->sig[i].variance == vnc_pos) + call_inclusion_fn(c->exps[i],p->exp); + else if (c->sig[i].variance == vnc_neg) + call_inclusion_fn(p->exp,c->exps[i]); + else + call_unify_fn(c->exps[i],p->exp); + } + else if (setif_is_pat(e2)) + { + return; + } + + // Case where e1 and e2 are constructor expressions + else + { + cons_expr c1 = (cons_expr)e1, + c2 = (cons_expr)e2; + + if (c1->type != c2->type) + failure("Constructor mismatch\n"); + else + { + int i; + for (i = 0; i < c1->arity; i++) + { + if (c1->sig[i].variance == vnc_pos) + call_inclusion_fn(e1,e2); + else if (c1->sig[i].variance == vnc_neg) + call_inclusion_fn(e2,e1); + else + call_unify_fn(e1,e2); + } + + } + } +} + +static void setst_con_match(gen_e e1, gen_e e2) +{ + // Case where e1 is a constructor expression and e2 is a proj_pat + if (pat_match(((setst_term)e2)->type,((setst_term)e1)->type)) + { + cons_expr c = (cons_expr)e1; + proj_pat p = (proj_pat)e2; + int i = p->i; + + if (c->sig[i].variance == vnc_pos) + call_inclusion_fn(c->exps[i],p->exp); + else if (c->sig[i].variance == vnc_neg) + call_inclusion_fn(p->exp,c->exps[i]); + else + call_unify_fn(c->exps[i],p->exp); + } + else if (setst_is_pat(e2)) + { + return; + } + + // Case where e1 and e2 are constructor expressions + else + { + cons_expr c1 = (cons_expr)e1, + c2 = (cons_expr)e2; + + if (c1->type != c2->type) + failure("Constructor mismatch\n"); + else + { + int i; + for (i = 0; i < c1->arity; i++) + { + if (c1->sig[i].variance == vnc_pos) + call_inclusion_fn(e1,e2); + else if (c1->sig[i].variance == vnc_neg) + call_inclusion_fn(e2,e1); + else + call_unify_fn(e1,e2); + } + + } + } +} + +// given x <= proj(c,i,e) +// proj_merge(region,e,get_proj_i_arg,fresh_large_fn_ptr, +// sort_inclusion_fn_ptr,set_inclusion) +static bool nonspec_res_proj(set_var v1,gen_e e2) +{ + proj_pat projection_pat = (proj_pat)e2; + + gen_e setif_get_proj(gen_e_list arg1) + { + gen_e_list_scanner scan; + gen_e temp; + proj_pat pat; + + gen_e_list_scan(arg1,&scan); + while(gen_e_list_next(&scan,&temp)) + { + pat = (proj_pat)temp; + if ( pat->type == ((setif_term)e2)->type && + pat->i == ((proj_pat)e2)->i) + return pat->exp; + } + return NULL; + } + + gen_e fresh_large(void) + { + return get_proj_var( ((proj_pat)e2)->exp->sort,TRUE); + } + + bool sort_inclusion(gen_e e1, gen_e e2) + { + if ( projection_pat->variance == vnc_pos ) + return call_inclusion_fn(e1,e2); + else if ( projection_pat->variance == vnc_neg) + return call_inclusion_fn(e2,e1); + else + return call_unify_fn(e1,e2); + } + + gen_e proj_con(gen_e e) + { + return make_proj_pat( ((proj_pat)e2)->c, ((proj_pat)e2)->i,e); + } + + return setif_proj_merge(setif_region,v1,((proj_pat)e2)->exp, + setif_get_proj,proj_con, + fresh_large,sort_inclusion, + call_setif_inclusion); + +} + + +void call_setif_inclusion(gen_e e1,gen_e e2) +{ + setif_inclusion(setif_con_match,setif_res_proj,e1,e2); +} + +void call_setif_unify(gen_e e1, gen_e e2) +{ + setif_inclusion(setif_con_match,setif_res_proj,e1,e2); + setif_inclusion(setif_con_match,setif_res_proj,e2,e1); +} + +void call_setst_inclusion(gen_e e1, gen_e e2) +{ + setst_inclusion(setst_con_match,e1,e2); +} + +void call_setst_unify(gen_e e1, gen_e e2) +{ + setst_inclusion(setst_con_match,e1,e2); + setst_inclusion(setst_con_match,e2,e1); +} + +void call_flowrow_inclusion(gen_e e1,gen_e e2) +{ + + if ( (e1->sort != flowrow_sort) || (e2->sort != flowrow_sort) ) + failure("Constraint system is not well-sorted\n"); + + if ( flowrow_base_sort(e1) != flowrow_base_sert(e2)) + failure("Constraint system is not well-sorted\n"); + + + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e1,e2); +} + +void call_flowrow_unify(gen_e e1, gen_e e2) +{ + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e1,e2); + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e2,e1); +} + +static void term_con_match(gen_e e1, gen_e e2) +{ + cons_expr c1 = (cons_expr)e1, + c2 = (cons_expr)e2; + + if (c1->type != c2->type) + failure("Constructor mismatch\n"); + else + { + int i; + for (i = 0; i < c1->arity; i++) + { + call_unify_fn(e1,e2); + } + + } +} + +static void term_occurs(term_var v, gen_e e) +{ + gen_e ecr = term_get_ecr(e); + + if (((gen_term)ecr)->type == VAR_TYPE) + return ( term_get_stamp((gen_e)v) == term_get_stamp(e) ); + + else if (((gen_term)ecr)->type >= 10) + { + cons_expr c_e = (cons_expr) e; + int i; + for (int i = 0; i < arity; i++) + { + if (term_occurs(v,c->exps[i])) + return TRUE; + } + } + + return FALSE; +} + +void call_term_unify(gen_e e1, gen_e e2) +{ + term_unify(term_con_match,term_occurs,e1,e2); +} + +void call_term_cunify(gen_e e1, gen_e e2) +{ + term_cunify(term_con_match,term_occurs,e1,e2); +} + + +static void call_inclusion_fn(gen_e e1, gen_e e2) +{ + switch (e1->sort) + { + case sort_setif: + { + setif_inclusion(setif_con_match,setif_res_proj,e1,e2); + } + break; + case sort_setst: + { + setst_inclusion(setst_con_match,e1,e2); + } + break; + case sort_term: + { + term_unify(term_con_match,term_occurs,e1,e2); + } + break; + case sort_row: + { + /* TODO */ + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e1,e2); + } + break; + default : + fail("Unmatched sort in call inclusion\n"); + } +} + +static bool call_unify_fn(gen_e e1, gen_e e2) +{ + + switch (e1->sort) + { + case sort_setif: + { + setif_inclusion(setif_con_match,setif_res_proj,e1,e2); + setif_inclusion(setif_con_match,setif_res_proj,e2,e1); + } + break; + case sort_setst: + { + setst_inclusion(setst_con_match,e1,e2); + setst_inclusion(setst_con_match,e2,e1); + } + break; + case sort_term: + { + term_unify(term_con_match,term_occurs,e1,e2); + } + break; + case sort_row: + { + /* TODO */ + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e1,e2); + flowrow_inclusion(fresh,get_stamp,field_incl,zero_elem,e2,e1); + } + break; + default : + fail("Unmatched sort in call inclusion\n"); + } +} + +void nonspec_init(void) +{ + banshee_init(); + setif_init(); + setst_init(); + flowrow_init(); +} + +void nonspec_reset(void) +{ + flowrow_reset(); + setst_reset(); + setif_reset(); + banshee_reset(); +} + +void expr_print(FILE *f,gen_e e) +{ + +} diff --git a/libbanshee/engine/nonspec.h b/libbanshee/engine/nonspec.h new file mode 100644 index 00000000000..bfa3b9d8b90 --- /dev/null +++ b/libbanshee/engine/nonspec.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef NONSPEC_H +#define NONSPEC_H + +#include + +EXTERN_C_BEGIN + +typedef enum +{ + vnc_pos, + vnc_neg, + vnc_non +} vnc_kind; + +struct sig_elt +{ + vnc_kind variance; + sort_kind sort; +}; + +typedef struct sig_elt sig_elt; +typedef struct constructor *constructor; + +struct flowrow_field +{ + char *label; + gen_e expr; +}; + +DECLARE_LIST(flowrow_map,flowrow_field) + +/* + Flags +*/ +extern bool flag_merge_projections; +extern bool flag_eliminate_cycles; +extern bool flag_occurs_check; + +/* + Operations for building terms +*/ + +/* Defines a new constructor for sort s with the given signature */ +constructor make_constructor(const char *name,sort_kind sort, sig_elt[], + int arity); + +/* Build the term c(exps[0]....exps[n]) */ +gen_e constructor_expr(constructor c, gen_e exps[], int arity); + +/* make a constant of sort s */ +gen_e setif_constant(const char *name); + +gen_e setst_constant(const char *name); + +gen_e term_constant(const char *name); + +/* Creates a projection pattern projpat(c,i,e) */ +gen_e setif_proj_pat(constructor c,int i,gen_e e); + +gen_e setst_proj_pat(constructor c, int i, gen_e e); + +/* Adds a constraint e <= projpat(c,i,fv) where fv is a fresh variable */ +gen_e setif_proj(constructor c, int i, gen_e e); + +gen_e setst_proj(constructor c, int i, gen_e e); + +/* Make a new variable of sort s */ +gen_e setif_fresh(const char *name); + +gen_e term_fresh(const char *name); + +gen_e flowrow_fresh(const char *name); + +gen_e setst_fresh(const char *name); + +/* Operations for unions */ + +gen_e setif_union(gen_e exps[]); + +gen_e setif_inter(gen_e exps[]); + +gen_e setst_union(gen_e exps[]); + +gen_e setst_inter(gen_e exps[]); + +/* Empty set of sort s */ +gen_e setif_zero(void); + +gen_e setst_zero(void); + +gen_e flowrow_zero(sort_kind base_sort); + +gen_e term_zero(void); + +/* Universal set of sort s */ +gen_e setif_one(void); + +gen_e setst_one(void); + +gen_e flowrow_one(sort_kind base_sort); + +gen_e term_one(void); + +/* + Operations for building flowrows +*/ + +/* Closed flowrow of base sort s */ +gen_e flowrow_abs(sort_kind base_sort); + +/* Wild flowrow of base sort s */ +gen_e flowrow_wild(sort_kind base_sort); + +/* Build a flowrow of _fields o */ +gen_e flowrow_row(flowrow_map fields, gen_e rest); + +/* + Inclusion functions +*/ +void call_setif_inclusion(gen_e e1,gen_e e2); +void call_setif_unify(gen_e e1, gen_e e2); + +void call_setst_inclusion(gen_e e1, gen_e e2); +void call_setst_unify(gen_e e1, gen_e e2); + +void call_flowrow_inclusion(gen_e e1,gen_e e2); +void call_flowrow_unify(gen_e e1, gen_e e2); + +void call_term_unify(gen_e e1, gen_e e2); +void call_term_cunify(gen_e e1, gen_e e2); + +/* + Extracting solutions + */ +struct decon +{ + int arity; + gen_e[1]; +}; +struct decon deconstruct_expr(constructor c,gen_e e); + +gen_e_list setif_tlb(gen_e e); + +gen_e_list setst_tlb(gen_e e); + +gen_e term_get_ecr(gen_e e); + +gen_e flowrow_extract_field(const char *label,gen_e row); +flowrow_map flowrow_extract_fields(gen_e row); +gen_e flowrow_extract_rest(gen_e row); + +void nonspec_init(void); +void nonspec_reset(void); + +void expr_print(FILE *f,gen_e e); + +EXTERN_C_END + +#endif /* NONSPEC_H */ diff --git a/libbanshee/engine/setif-sort.c b/libbanshee/engine/setif-sort.c new file mode 100644 index 00000000000..0350018dfcd --- /dev/null +++ b/libbanshee/engine/setif-sort.c @@ -0,0 +1,1141 @@ +/* + * Copyright (c) 2000-2004 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include "regions.h" +#include "bounds.h" +#include "jcollection.h" +#include "setif-sort.h" +#include "util.h" + +bool flag_eliminate_cycles = TRUE; +bool flag_merge_projections = TRUE; + +struct setif_union_ /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + gen_e_list exprs; + gen_e_list proj_cache; +}; + +struct setif_inter_ /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + gen_e_list exprs; +}; + +struct setif_constant_ /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + char *name; +}; + +typedef struct setif_inter_ *setif_inter_; +typedef struct setif_union_ *setif_union_; +typedef struct setif_constant_ *setif_constant_; + +static setif_var_list setif_vars; +static region tlb_cache_region; +static setif_var_list tlb_var_cache; +static jcoll_dict tlb_dict; + + +region setif_region; +term_hash setif_hash; +struct setif_stats setif_stats; + +stamp setif_get_stamp(gen_e e) +{ +#ifdef NONSPEC + assert(e->sort == setif_sort); +#endif + + if ( ((setif_term)e)->type == VAR_TYPE) + return sv_get_stamp( (setif_var)e ); + + else + return ((setif_term)e)->st; +} + +static void tlv_lower_aux(jmp_buf buf,stamp st, gen_e e) +{ + if ( setif_is_var(e) && (setif_get_stamp(e) > st) ) + longjmp(buf,1); + + else if (setif_is_union(e)) + { + gen_e temp; + gen_e_list exprs = ((setif_union_)e)->exprs; + gen_e_list_scanner scan; + + gen_e_list_scan(exprs,&scan); + while (gen_e_list_next(&scan,&temp)) + tlv_lower_aux(buf,st,temp); + } +} + +static bool tlv_lower(stamp st, gen_e e) +{ + jmp_buf buf; + int higher; + + higher = setjmp(buf); + if (higher) + return FALSE; + + tlv_lower_aux(buf,st,e); + + return TRUE; +} + +static void invalidate_tlb_cache(void) deletes +{ + assert(tlb_cache_region); + + setif_var_list_app(tlb_var_cache,sv_clear_tlb_cache); + jcoll_delete_dict(tlb_dict); + deleteregion_ptr(&tlb_cache_region); + + tlb_cache_region = newregion(); + tlb_dict = jcoll_create_dict(tlb_cache_region,setif_get_stamp); + tlb_var_cache = new_setif_var_list(tlb_cache_region); +} + +static void set_tlb_cache(setif_var v, jcoll j) +{ + setif_var_list_cons(v,tlb_var_cache); + sv_set_tlb_cache(v,j); +} + +/* + A constraint e1 <= e2 is l-inductive iff e2 is a variable x and + for each y in tlv(e1), stamp(y) < stamp(x) +*/ +static bool l_inductive(gen_e e1, gen_e e2) +{ + if (setif_is_var(e2) && tlv_lower(setif_get_stamp(e2), e1)) + return TRUE; + + else return FALSE; +} + +/* + A constraint e1 <= e2 is r-inductive iff e1 is a variable x and + for each y in tlv(e2), stamp(y) < stamp(x) +*/ +static bool r_inductive(gen_e e1, gen_e e2) +{ + if (setif_is_var(e1) && tlv_lower(setif_get_stamp(e1), e2)) + return TRUE; + + else return FALSE; +} + +static bool eq(gen_e e1, gen_e e2) +{ + return ( setif_get_stamp(e1) == setif_get_stamp(e2) ); +} + +gen_e_list setif_get_union(gen_e e) +{ + assert ( ((setif_term)e)->type == UNION_TYPE); + + return ( (setif_union_) e)->exprs; +} + +gen_e_list setif_get_inter(gen_e e) +{ + assert ( ((setif_term)e)->type == INTER_TYPE); + + return ( (setif_inter_) e)->exprs; +} + +static setif_var_list search_ubs(region r, setif_var v1, setif_var goal) +{ + bool found = FALSE; + setif_var_list cycle; + + static void search_ubs_aux(setif_var v) + { + assert(! found); + + if (sv_eq (v, goal)) + { + found = TRUE; + return; + } + else if (sv_lt(v,goal)) + { + return; + } + else + { + gen_e_list_scanner scan; + gen_e ub; + gen_e_list ubs = sv_get_ubs(v); + + gen_e_list_scan(ubs,&scan); + while (gen_e_list_next(&scan,&ub)) + { + if (setif_is_var(ub)) + { + search_ubs_aux((setif_var)ub); + if (found) + { + setif_var_list_cons(v,cycle); + return; + } + } + } + } + } + + found = FALSE; + cycle = new_setif_var_list(r); + search_ubs_aux(v1); + + return cycle; +} + +static setif_var_list search_lbs(region r, setif_var v1, setif_var goal) +{ + bool found; + setif_var_list cycle; + + static void search_lbs_aux(setif_var v) + { + assert (! found); + if (sv_eq(v,goal)) + { + found = TRUE; + return; + } + else if (sv_lt(v,goal)) + { + return; + } + else + { + gen_e_list_scanner scan; + gen_e lb; + gen_e_list lbs = sv_get_lbs(v); + + gen_e_list_scan(lbs,&scan); + while (gen_e_list_next(&scan,&lb)) + { + if (setif_is_var(lb)) + { + search_lbs_aux((setif_var)lb); + if (found) + { + setif_var_list_cons(v,cycle); + return; + } + } + } + } + + } + + found = FALSE; + cycle = new_setif_var_list(r); + search_lbs_aux(v1); + + return cycle; +} + +static setif_var_list cycle_detect(region r,setif_var v1,setif_var v2) +{ + if (sv_union_component(v1,v2)) + return new_setif_var_list(r); + + else + { + setif_stats.cycles_searched_forward++; + return search_ubs(r, v2, v1); + } +} + + +static setif_var_list cycle_detect_rev(region r, setif_var v1, setif_var v2) +{ + if (sv_union_component(v1,v2)) + return new_setif_var_list(r); + + else + { + setif_stats.cycles_searched_backward++; + return search_lbs(r, v1, v2); + } +} + +void setif_inclusion(con_match_fn_ptr con_match, res_proj_fn_ptr res_proj, + gen_e e1, gen_e e2) deletes +{ + + static void collapse_cycle_lower(region r, setif_var witness, + setif_var_list cycle) deletes + { + gen_e lb; + gen_e_list_scanner scan_bounds; + setif_var_list_scanner scan_cycle; + setif_var var; + +#ifndef NDEBUG + stamp lowest = sv_get_stamp(witness); +#endif + bounds b = bounds_create(r); + + /* Collect all lower bounds in the cycle, and add transitive edges */ + setif_var_list_scan(cycle,&scan_cycle); + while(setif_var_list_next(&scan_cycle,&var)) + { + assert( sv_get_stamp(var) > lowest); + gen_e_list_scan(sv_get_lbs(var),&scan_bounds); + while(gen_e_list_next(&scan_bounds,&lb)) + bounds_add(b,lb,setif_get_stamp(lb)); + } + + sv_unify(witness,cycle); + assert(sv_get_stamp(witness) == lowest); + + gen_e_list_scan(bounds_exprs(b),&scan_bounds); + while (gen_e_list_next(&scan_bounds,&lb)) + setif_inclusion(con_match,res_proj,lb, (gen_e) witness); + + bounds_delete(b); + invalidate_tlb_cache(); + + setif_stats.cycles_collapsed_backward++; + setif_stats.cycles_length_backward += setif_var_list_length(cycle); + } + + static void collapse_cycle_upper(region r, setif_var witness, + setif_var_list cycle) deletes + { + gen_e ub; + gen_e_list_scanner scan_bounds; + setif_var_list_scanner scan_cycle; + setif_var var; + +#ifndef NDEBUG + stamp lowest = sv_get_stamp(witness); +#endif + bounds b = bounds_create(r); + + /* Collect all upper bounds in the cycle, and add transitive edges */ + setif_var_list_scan(cycle,&scan_cycle); + while(setif_var_list_next(&scan_cycle,&var)) + { + assert( sv_get_stamp(var) > lowest); + + gen_e_list_scan(sv_get_ubs(var),&scan_bounds); + while(gen_e_list_next(&scan_bounds,&ub)) + bounds_add(b,ub,setif_get_stamp(ub)); + + gen_e_list_scan(sv_get_ub_projs(var),&scan_bounds); + while(gen_e_list_next(&scan_bounds,&ub)) + bounds_add(b,ub,setif_get_stamp(ub)); + } + + sv_unify(witness,cycle); + assert(sv_get_stamp(witness) == lowest); + + gen_e_list_scan(bounds_exprs(b),&scan_bounds); + while (gen_e_list_next(&scan_bounds,&ub)) + setif_inclusion(con_match,res_proj,(gen_e) witness, ub); + + bounds_delete(b); + invalidate_tlb_cache(); + + setif_stats.cycles_collapsed_forward++; + setif_stats.cycles_length_backward += setif_var_list_length(cycle); + } + + static void update_lower_bound(setif_var v, gen_e e) deletes + { + if (sv_add_lb(v,e,setif_get_stamp(e))) + { + if (setif_is_var(e)) + setif_stats.redundant_succ++; + + else + setif_stats.redundant_source++; + } + + else + { + gen_e_list_scanner scan; + gen_e ub; + + if (setif_is_var(e)) + setif_stats.added_succ++; + else + setif_stats.added_source++; + + invalidate_tlb_cache(); + + gen_e_list_scan(sv_get_ubs(v),&scan); + while(gen_e_list_next(&scan,&ub)) + setif_inclusion(con_match,res_proj,e,ub); + + gen_e_list_scan(sv_get_ub_projs(v),&scan); + while (gen_e_list_next(&scan,&ub)) + setif_inclusion(con_match,res_proj,e,ub); + + } + + } + + static void update_upper_bound(setif_var v, gen_e e) deletes + { + if (sv_add_ub(v,e,setif_get_stamp(e))) + { + if (setif_is_var(e)) + setif_stats.redundant_pred++; + + else + setif_stats.redundant_sink++; + } + + else + { + gen_e_list_scanner scan; + gen_e lb; + + if (setif_is_var(e)) + setif_stats.added_pred++; + else + setif_stats.added_sink++; + + invalidate_tlb_cache(); + + gen_e_list_scan(sv_get_lbs(v),&scan); + while (gen_e_list_next(&scan,&lb)) + setif_inclusion(con_match,res_proj,lb,e); + + } + + } + + + if (eq(e1,e2)) + return; + + else if ( setif_is_zero(e1) || setif_is_one(e2) ) + return; + + /* c <= d */ + else if ( setif_is_constant(e1) && setif_is_constant(e2) ) + { + + failure("Inconsistent system of constraints\n"); + return; + } + + else if ( setif_is_union(e1) ) + { + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list exprs = setif_get_union(e1); + + gen_e_list_scan(exprs,&scan); + while (gen_e_list_next(&scan,&temp)) + { + setif_inclusion(con_match,res_proj,temp,e2); + } + + return; + } + + else if ( setif_is_inter(e2) ) + { + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list exprs = setif_get_inter(e2); + + gen_e_list_scan(exprs,&scan); + while (gen_e_list_next(&scan,&temp)) + { + setif_inclusion(con_match,res_proj,e1,temp); + } + + return; + } + + else if ( l_inductive(e1,e2) ) /* _ <= 'x */ + { + setif_var v2 = ((setif_var)e2); + + if (setif_is_var(e1)) + { + setif_var v1 = ((setif_var)e1); + + if (flag_eliminate_cycles) + { + region scratch = newregion(); + setif_var_list cycle = cycle_detect(scratch,v1,v2); + + if (! setif_var_list_empty(cycle)) + collapse_cycle_upper(scratch,v1,cycle); + else + update_lower_bound(v2,e1); + + deleteregion(scratch); + } + + else + update_lower_bound(v2,e1); + } + else /* e1 is a source */ + update_lower_bound(v2,e1); + } + + else if ( r_inductive(e1,e2) ) /* 'x <= _ */ + { + setif_var v1 = ((setif_var)e1); + + if (setif_is_var(e2)) + { + setif_var v2 = ((setif_var)e2); + + if (flag_eliminate_cycles) + { + region scratch = newregion(); + setif_var_list cycle = cycle_detect_rev(scratch,v1,v2); + + if (! setif_var_list_empty(cycle)) + collapse_cycle_lower(scratch,v2,cycle); + else + update_upper_bound(v1,e2); + + deleteregion(scratch); + } + + else + update_upper_bound(v1,e2); + } + else /* e2 is a sink */ + { + if (flag_merge_projections && res_proj(v1,e2)) + return; + else + update_upper_bound(v1,e2); + } + } + + else /* c(...) <= c(...) or c(...) <= projpat(c,i,e) */ + { + con_match(e1,e2); + return; + } + +} + +#ifdef NONSPEC +static struct setif_term zero = {setif_sort,ZERO_TYPE,ZERO_TYPE}; +static struct setif_term one = {setif_sort,ONE_TYPE,ONE_TYPE}; +#else +static struct setif_term zero = {ZERO_TYPE,ZERO_TYPE}; +static struct setif_term one = {ONE_TYPE,ONE_TYPE}; +#endif /* NONSPEC */ + +gen_e setif_zero(void) +{ + return (gen_e)&zero; +} + +gen_e setif_one(void) +{ + return (gen_e)&one; +} + +gen_e setif_fresh(const char *name) +{ + setif_var result = sv_fresh(setif_region,name); + setif_var_list_cons(result,setif_vars); + + setif_stats.fresh++; + return (gen_e)result; +} + +gen_e setif_fresh_large(const char *name) +{ + setif_var result = sv_fresh_large(setif_region,name); + setif_var_list_cons(result,setif_vars); + + setif_stats.fresh_large++; + return (gen_e)result; +} + +gen_e setif_fresh_small(const char *name) +{ + setif_var result = sv_fresh_small(setif_region,name); + setif_var_list_cons(result,setif_vars); + + setif_stats.fresh_small++; + return (gen_e)result; +} + +gen_e setif_constant(const char *str) deletes +{ + stamp st[2]; + gen_e result; + char *name = rstrdup(setif_region,str); + + assert (str != NULL); + + st[0] = CONSTANT_TYPE; + st[1] = stamp_string(name); + + if ( (result = term_hash_find(setif_hash,st,2)) == NULL) + { + setif_constant_ c = ralloc(setif_region, struct setif_constant_); +#ifdef NONSPEC + c->sort = setif_sort; +#endif + c->type = CONSTANT_TYPE; + c->st = stamp_fresh(); + c->name = name; + + result = (gen_e) c; + term_hash_insert(setif_hash,result,st,2); + + setif_stats.distinct_constants++; + + return result; + } + + else + { + setif_stats.hashed_constants++; + return result; + } +} + +static bool filter_zero(const gen_e e) +{ + return (!setif_is_zero(e)); +} + + +static bool filter_one(const gen_e e) +{ + return (!setif_is_one(e)); +} + +gen_e setif_union(gen_e_list exprs) deletes +{ + gen_e_list filtered = gen_e_list_filter(setif_region,exprs,filter_zero); + + if ( gen_e_list_empty(filtered) ) + { + setif_stats.filtered_unions++; + return setif_zero(); + } + else if (gen_e_list_length(filtered) == 1) + { + setif_stats.filtered_unions++; + return gen_e_list_head(filtered); + } + + else + { + int i = 0; + gen_e temp,result; + gen_e_list_scanner scan; + stamp st[ gen_e_list_length(filtered) + 1 ]; + + st[0] = UNION_TYPE; + + gen_e_list_scan(filtered,&scan); + while (gen_e_list_next(&scan,&temp)) + { + st[++i] = setif_get_stamp(temp); + } + + if ( (result = + term_hash_find(setif_hash,st,gen_e_list_length(filtered)+1)) + == NULL ) + { + struct setif_union_ *u = ralloc(setif_region,struct setif_union_); + + u->type = UNION_TYPE; + u->st = stamp_fresh(); + u->proj_cache = new_gen_e_list(setif_region); + u->exprs = filtered; + + result = (gen_e)u; + term_hash_insert(setif_hash,result,st,gen_e_list_length(filtered)+1); + + setif_stats.distinct_unions++; + return result; + } + else + { + setif_stats.hashed_unions++; + return result; + } + } +} + +gen_e setif_inter(gen_e_list exprs) deletes +{ + gen_e_list filtered = gen_e_list_filter(setif_region,exprs,filter_one); + + if ( gen_e_list_empty(filtered) ) + { + setif_stats.filtered_intersections++; + return setif_one(); + } + else if (gen_e_list_length(filtered) == 1) + { + setif_stats.filtered_intersections++; + return gen_e_list_head(filtered); + } + + else + { + int i = 0; + gen_e temp,result; + gen_e_list_scanner scan; + stamp st[ gen_e_list_length(filtered) + 1 ]; + + st[0] = INTER_TYPE; + + gen_e_list_scan(filtered,&scan); + while (gen_e_list_next(&scan,&temp)) + { + st[++i] = setif_get_stamp(temp); + } + + if ( (result = + term_hash_find(setif_hash,st,gen_e_list_length(filtered)+1)) + == NULL ) + { + struct setif_inter_ *u = ralloc(setif_region,struct setif_inter_); + + u->type = UNION_TYPE; + u->st = stamp_fresh(); + u->exprs = filtered; + + result = (gen_e)u; + term_hash_insert(setif_hash,result,st,gen_e_list_length(filtered)+1); + + setif_stats.distinct_intersections++; + + return result; + } + else + { + setif_stats.hashed_intersections++; + return result; + } + } +} + +bool setif_is_zero(gen_e e) +{ + return ((setif_term)e)->type == ZERO_TYPE; +} + +bool setif_is_one(gen_e e) +{ + return ((setif_term)e)->type == ONE_TYPE; +} + +bool setif_is_var(gen_e e) +{ + return ((setif_term)e)->type == VAR_TYPE; +} + +bool setif_is_union(gen_e e) +{ + return ((setif_term)e)->type == UNION_TYPE; +} + +bool setif_is_inter(gen_e e) +{ + return ((setif_term)e)->type == INTER_TYPE; +} + +bool setif_is_constant(gen_e e) +{ + return ((setif_term)e)->type == CONSTANT_TYPE; +} + +char *setif_get_constant_name(gen_e e) +{ + assert( ((setif_term)e)->type == CONSTANT_TYPE ); + + return ((setif_constant_)e)->name; +} + +void setif_init(void) +{ + setif_region = newregion(); + tlb_cache_region = newregion(); + setif_vars = new_setif_var_list(setif_region); + tlb_var_cache = new_setif_var_list(tlb_cache_region); + setif_hash = make_term_hash(setif_region); + tlb_dict = jcoll_create_dict(tlb_cache_region,setif_get_stamp); +} + + + +static void setif_reset_stats(void) +{ + setif_stats.fresh = 0; + setif_stats.fresh_small = 0; + setif_stats.fresh_large = 0; + + setif_stats.distinct_constructors = 0; + setif_stats.hashed_constructors = 0; + setif_stats.distinct_constants = 0; + setif_stats.hashed_constants = 0; + setif_stats.distinct_unions = 0; + setif_stats.filtered_unions = 0; + setif_stats.hashed_unions = 0; + setif_stats.distinct_intersections = 0; + setif_stats.filtered_intersections = 0; + setif_stats.hashed_intersections = 0; + + setif_stats.redundant_pred = 0; + setif_stats.redundant_succ = 0; + setif_stats.redundant_source = 0; + setif_stats.redundant_sink = 0; + + setif_stats.added_pred = 0; + setif_stats.added_succ = 0; + setif_stats.added_source = 0; + setif_stats.added_sink = 0; + + setif_stats.cycles_searched_forward = 0; + setif_stats.cycles_searched_backward = 0; + + setif_stats.cycles_collapsed_forward = 0; + setif_stats.cycles_collapsed_backward = 0; + + setif_stats.cycles_length_forward = 0; + setif_stats.cycles_length_backward = 0; +} + +void setif_reset(void) deletes +{ + term_hash_delete(setif_hash); + invalidate_tlb_cache(); + deleteregion_ptr(&setif_region); + deleteregion_ptr(&tlb_cache_region); + + setif_reset_stats(); + + setif_region = newregion(); + tlb_cache_region = newregion(); + setif_vars = new_setif_var_list(setif_region); + tlb_var_cache = new_setif_var_list(tlb_cache_region); + setif_hash = make_term_hash(setif_region); +} + +static jcoll tlb_aux(gen_e e) +{ + if (setif_is_var(e)) + { + setif_var v = (setif_var)e; + + if ( sv_get_tlb_cache(v) != NULL) + return sv_get_tlb_cache(v); + + else + { + jcoll result; + gen_e_list sources = new_gen_e_list(tlb_cache_region); + jcoll_list jvars = new_jcoll_list(tlb_cache_region); + gen_e_list_scanner scan; + gen_e lb; + + gen_e_list_scan(sv_get_lbs(v),&scan); + while (gen_e_list_next(&scan,&lb)) + { + if (setif_is_var(lb)) + jcoll_list_cons(tlb_aux(lb),jvars); + else + gen_e_list_cons(lb,sources); + /* jsources = jcoll_jcons(tlb_cache_region,lb,jsources); */ + } + + if (! gen_e_list_empty(sources)) + jcoll_list_cons(jcoll_create_chain(tlb_dict,sources),jvars); + + result = + jcoll_jjoin(tlb_dict,jvars); + + set_tlb_cache(v,result); + return result; + } + } + else if (setif_is_union(e)) + { + gen_e_list_scanner scan; + gen_e temp; + jcoll_list jexprs = new_jcoll_list(tlb_cache_region); + + gen_e_list_scan(setif_get_union(e),&scan); + while (gen_e_list_next(&scan,&temp)) + { + jcoll_list_cons(tlb_aux(temp),jexprs); + } + + return jcoll_jjoin(tlb_dict,jexprs); + + } + else + { + failure("Unmatched case in setif tlb computation\n"); + return NULL; + } +} + +gen_e_list setif_tlb(gen_e e) deletes +{ + return jcoll_flatten(tlb_dict,tlb_aux(e)); +} + +void setif_set_proj_cache(gen_e e,gen_e elem) +{ + if (setif_is_union(e)) + { + setif_union_ u = (setif_union_)e; + gen_e_list_cons(elem,u->proj_cache); + } +} + +gen_e_list setif_get_proj_cache(gen_e e) +{ + if (setif_is_union(e)) + { + setif_union_ u = (setif_union_)e; + return u->proj_cache; + } + else + { + failure("Term does not cache projections\n"); + return NULL; + } +} + + +bool setif_proj_merge(setif_var v, gen_e se, get_proj_fn_ptr get_proj, + proj_con_fn_ptr proj_con,fresh_large_fn_ptr fresh_large, + incl_fn_ptr sort_incl, incl_fn_ptr set_incl) deletes +{ + gen_e proj; + + if ((proj = sv_get_ub_proj(v,get_proj)) != NULL) + { + sort_incl(proj, se); + return TRUE; + } + + else + { + gen_e_list_scanner scan; + gen_e lb; + + gen_e proj_var; + gen_e proj_cons; + + /* create a projection variable for this projection */ + proj_var = fresh_large(NULL); + + assert(setif_is_var(proj_var)); + + proj_cons = proj_con(proj_var); + + sv_add_ub_proj(v, proj_cons); + + /* apply the transitive rule to each of v's lower bounds */ + gen_e_list_scan(sv_get_lbs(v),&scan); + while (gen_e_list_next(&scan,&lb)) + { + set_incl(lb,proj_cons); + } + + sort_incl(proj_var, se); + return TRUE; + } + +} + + +void setif_print_stats(FILE *f) +{ + fprintf(f,"\n========== SetIF Var Stats ==========\n"); + fprintf(f,"Fresh : %d\n",setif_stats.fresh); + fprintf(f,"Fresh Small : %d\n",setif_stats.fresh_small); + fprintf(f,"Fresh Large : %d\n",setif_stats.fresh_large); + fprintf(f,"Total : %d\n",setif_stats.fresh + setif_stats.fresh_small + + setif_stats.fresh_large); + fprintf(f,"\n========== SetIF Sort Stats ==========\n"); + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Additions"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Pred: %d\n",setif_stats.added_pred); + fprintf(f,"Succ: %d\n",setif_stats.added_succ); + fprintf(f,"Source: %d\n",setif_stats.added_source); + fprintf(f,"Sink: %d",setif_stats.added_sink); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Total: %d",setif_stats.added_pred + setif_stats.added_succ + + setif_stats.added_source + setif_stats.added_sink); + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Redundant"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Pred: %d\n",setif_stats.redundant_pred); + fprintf(f,"Succ: %d\n",setif_stats.redundant_succ); + fprintf(f,"Source: %d\n",setif_stats.redundant_source); + fprintf(f,"Sink: %d",setif_stats.redundant_sink); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Total: %d\n", + setif_stats.redundant_pred+setif_stats.redundant_succ+setif_stats.redundant_source+setif_stats.redundant_sink); + + fprintf(f,"\n"); + + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Forward Cycles"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Collapsed: %d\n",setif_stats.cycles_collapsed_forward); + fprintf(f,"Searched: %d\n",setif_stats.cycles_searched_forward); + fprintf(f,"Hit rate: %f\n", + ((float)setif_stats.cycles_collapsed_forward)/((float)setif_stats.cycles_searched_forward)); + fprintf(f,"Average Length: %f\n", + 1+((float)setif_stats.cycles_length_forward) / ((float)setif_stats.cycles_collapsed_forward)); + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Reverse Cycles"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Collapsed: %d\n",setif_stats.cycles_collapsed_backward); + fprintf(f,"Searched: %d\n",setif_stats.cycles_searched_backward); + fprintf(f,"Hit rate: %f\n", + ((float)setif_stats.cycles_collapsed_backward)/((float)setif_stats.cycles_searched_backward)); + fprintf(f,"Average Length: %f\n", + 1+((float)setif_stats.cycles_length_backward) / ((float)setif_stats.cycles_collapsed_backward)); + fprintf(f,"=====================================\n"); +} + +/* + for now, print stamps and types for sources and sinks. + must eventually rely on specialized code +*/ +void setif_print_constraint_graph(FILE *f) +{ + setif_var_list_scanner scan; + gen_e_list_scanner scan_edges; + gen_e edge; + setif_var v; + dot_node n1,n2; + char temp_str[512]; + + graph_attr graph_style[3] = {{g_size,"\"8.5,11\""}, + {g_center,"true"}, + {g_orientation,"portrait"}}; + edge_attr succ_edge[1] = {{e_style,"solid"}}; + edge_attr pred_edge[1] = {{e_style,"dotted"}}; + + dot_start(f,"setif",TRUE,TRUE); + dot_global_graph_style(graph_style,3); + + setif_var_list_scan(setif_vars,&scan); + while(setif_var_list_next(&scan,&v)) + { + snprintf(temp_str,512,"%s:%ld",sv_get_name(v),sv_get_stamp(v)); + n1 = dot_get_node(temp_str); + gen_e_list_scan(sv_get_lbs(v),&scan_edges); + while(gen_e_list_next(&scan_edges,&edge)) + { + if (setif_is_var(edge)) + { + snprintf(temp_str,512,"%s:%ld",sv_get_name((setif_var)edge), + setif_get_stamp(edge)); + n2 = dot_get_node(temp_str); + } + else + { + snprintf(temp_str,512,"source:%ld",setif_get_stamp(edge)); + n2 = dot_get_node(temp_str); + } + dot_styled_edge(n2,n1,pred_edge,1); + } + + gen_e_list_scan(sv_get_ubs(v),&scan_edges); + while(gen_e_list_next(&scan_edges,&edge)) + { + if (setif_is_var(edge)) + { + snprintf(temp_str,512,"%s:%ld",sv_get_name((setif_var)edge), + setif_get_stamp(edge)); + n2 = dot_get_node(temp_str); + } + else + { + snprintf(temp_str,512,"sink:%ld",setif_get_stamp(edge)); + n2 = dot_get_node(temp_str); + } + dot_styled_edge(n1,n2,succ_edge,1); + } + + gen_e_list_scan(sv_get_ub_projs(v),&scan_edges); + while(gen_e_list_next(&scan_edges,&edge)) + { + snprintf(temp_str,512,"projpat:%ld",setif_get_stamp(edge)); + n2 = dot_get_node(temp_str); + dot_styled_edge(n1,n2,succ_edge,1); + } + + } + + dot_end(); +} + diff --git a/libbanshee/engine/setif-sort.h b/libbanshee/engine/setif-sort.h new file mode 100644 index 00000000000..7cfabc81752 --- /dev/null +++ b/libbanshee/engine/setif-sort.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef SETIF_SORT_H +#define SETIF_SORT_H + +#include +#include "banshee.h" +#include "termhash.h" +#include "setif-var.h" + + +struct setif_term /* extends gen_e */ +{ +#ifdef NONSPEC + const sort_kind sort; +#endif + const int type; + const stamp st; +}; + +typedef struct setif_term *setif_term; + +extern bool flag_merge_projections; +extern bool flag_eliminate_cycles; + +extern region setif_region; +extern term_hash setif_hash; + +typedef bool (*res_proj_fn_ptr) (setif_var v,gen_e proj) deletes; +typedef gen_e (*proj_con_fn_ptr) (gen_e) deletes; + +stamp setif_get_stamp(gen_e e); +void setif_inclusion(con_match_fn_ptr,res_proj_fn_ptr, gen_e, gen_e) deletes; + +bool setif_proj_merge(setif_var v, gen_e se, get_proj_fn_ptr get_proj, + proj_con_fn_ptr make_proj,fresh_large_fn_ptr fresh_var, + incl_fn_ptr sort_incl, incl_fn_ptr set_incl) deletes; + +gen_e setif_zero(void); +gen_e setif_one(void); +gen_e setif_fresh(const char *name); +gen_e setif_fresh_large(const char *name); +gen_e setif_fresh_small(const char *name); +gen_e setif_constant(const char *name) deletes; +gen_e setif_union(gen_e_list exprs) deletes; +gen_e setif_inter(gen_e_list exprs) deletes; +bool setif_is_zero(gen_e e); +bool setif_is_one(gen_e e); +bool setif_is_var(gen_e e); +bool setif_is_union(gen_e e); +bool setif_is_inter(gen_e e); +bool setif_is_constant(gen_e e); +char *setif_get_constant_name(gen_e e); + +gen_e_list setif_get_union(gen_e e); +gen_e_list setif_get_inter(gen_e e); + +gen_e_list setif_tlb(gen_e e) deletes; + +void setif_set_proj_cache(gen_e e, gen_e elem); +gen_e_list setif_get_proj_cache(gen_e e); + +void setif_init(void); +void setif_reset(void) deletes; +void setif_print_stats(FILE *f); +void setif_print_constraint_graph(FILE *f); + +extern struct setif_stats setif_stats; +struct setif_stats +{ + int fresh; + int fresh_small; + int fresh_large; + + int distinct_constructors; + int hashed_constructors; + int distinct_constants; + int hashed_constants; + int distinct_unions; + int filtered_unions; + int hashed_unions; + int distinct_intersections; + int filtered_intersections; + int hashed_intersections; + + int redundant_pred; + int redundant_succ; + int redundant_source; + int redundant_sink; + + int added_pred; + int added_succ; + int added_source; + int added_sink; + + int cycles_searched_forward; + int cycles_searched_backward; + + int cycles_collapsed_forward; + int cycles_collapsed_backward; + + int cycles_length_forward; + int cycles_length_backward; +}; + +#endif /* SETIF_SORT_H */ diff --git a/libbanshee/engine/setif-var.c b/libbanshee/engine/setif-var.c new file mode 100644 index 00000000000..21941021284 --- /dev/null +++ b/libbanshee/engine/setif-var.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "setif-var.h" +#include "ufind.h" +#include "bounds.h" + +struct sv_info +{ + stamp st; + bounds sameregion lbs; + bounds sameregion ubs; + jcoll tlb_cache; + gen_e_list ub_projs; + const char *name; + uf_element component; +}; + +typedef struct sv_info *sv_info; + +DECLARE_UFIND(sv_elt,sv_info) + +DEFINE_UFIND(sv_elt,sv_info) + +DEFINE_LIST(setif_var_list,setif_var) + +#define get_info(v) (sv_elt_get_info((v)->elt)) + +struct setif_var /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + sv_elt elt; +}; + +bool sv_lt(setif_var v1, setif_var v2) +{ + return ( sv_get_stamp(v1) < sv_get_stamp(v2) ); +} + +bool sv_eq(setif_var v1, setif_var v2) +{ + return ( sv_get_stamp(v1) == sv_get_stamp(v2) ); +} + +static setif_var make_var(region r, const char *name, stamp st) +{ + setif_var result = ralloc(r, struct setif_var); + sv_info info = ralloc(r, struct sv_info); + + info->st = st; + info->lbs = bounds_create(r); + info->ubs = bounds_create(r); + info->tlb_cache = NULL; + info->ub_projs = new_gen_e_list(r); + info->name = name ? rstrdup(r,name) : "fv"; + info->component = new_uf_element(r, NULL); + + result->type = VAR_TYPE; + result->elt = new_sv_elt(r,info); + +#ifdef NONSPEC + result->sort = setif_sort; +#endif + + return result; +} + +setif_var sv_fresh(region r, const char *name) +{ + return make_var(r,name,stamp_fresh()); +} + +setif_var sv_fresh_large(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_large()); +} + +setif_var sv_fresh_small(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_small()); +} + +stamp sv_get_stamp(setif_var v) +{ + return get_info(v)->st; +} + +const char *sv_get_name(setif_var v) +{ + return get_info(v)->name; +} + + +static sv_info combine(sv_info i1, sv_info i2) +{ + if (i1->st < i2->st) + return i1; + else return i2; +} + +void sv_unify(setif_var v,setif_var_list vars) +{ + setif_var temp; + setif_var_list_scanner scan; + + setif_var_list_scan(vars,&scan); + + while (setif_var_list_next(&scan,&temp)) + { + sv_elt_unify(combine,v->elt,temp->elt); + } +} + +gen_e_list sv_get_lbs(setif_var v) +{ + return bounds_exprs(get_info(v)->lbs); +} + +gen_e_list sv_get_ubs(setif_var v) +{ + return bounds_exprs(get_info(v)->ubs); +} + +bool sv_add_ub(setif_var v, gen_e e, stamp s) +{ + return bounds_add(get_info(v)->ubs,e,s); +} + +bool sv_add_lb(setif_var v, gen_e e, stamp s) +{ + return bounds_add(get_info(v)->lbs,e,s); +} + +bool sv_is_ub(setif_var v, stamp s) +{ + bool self_edge = sv_get_stamp(v) == s, + in_bounds = bounds_query(get_info(v)->ubs,s); + + return (self_edge || in_bounds); +} + +bool sv_is_lb(setif_var v, stamp s) +{ + + bool self_edge = sv_get_stamp(v) == s, + in_bounds = bounds_query(get_info(v)->lbs,s); + + return (self_edge || in_bounds); + +} + +void sv_add_ub_proj(setif_var v, gen_e e) +{ + gen_e_list_cons(e,get_info(v)->ub_projs); +} + +gen_e sv_get_ub_proj(setif_var v, get_proj_fn_ptr get_proj) +{ + return get_proj(get_info(v)->ub_projs); +} + +gen_e_list sv_get_ub_projs(setif_var v) +{ + return get_info(v)->ub_projs; +} + + +bool sv_union_component(setif_var v1, setif_var v2) +{ + if (uf_eq(get_info(v1)->component,get_info(v2)->component)) + return FALSE; + + else + { + uf_union(get_info(v1)->component,get_info(v2)->component); + return TRUE; + } +} + +void sv_set_tlb_cache(setif_var v, jcoll j) +{ + get_info(v)->tlb_cache = j; +} + +jcoll sv_get_tlb_cache(setif_var v) +{ + return get_info(v)->tlb_cache; +} + +void sv_clear_tlb_cache(setif_var v) +{ + get_info(v)->tlb_cache = NULL; +} diff --git a/libbanshee/engine/setif-var.h b/libbanshee/engine/setif-var.h new file mode 100644 index 00000000000..6ded7363ae2 --- /dev/null +++ b/libbanshee/engine/setif-var.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef SETIF_VAR_H +#define SETIF_VAR_H + +#include "linkage.h" +#include "banshee.h" +#include "jcollection.h" + +EXTERN_C_BEGIN + +typedef struct setif_var *setif_var; + +DECLARE_LIST(setif_var_list,setif_var) + +bool sv_lt(setif_var v1, setif_var v2); +bool sv_eq(setif_var v1, setif_var v2); +setif_var sv_fresh(region r, const char *name); +setif_var sv_fresh_large(region r, const char *name); +setif_var sv_fresh_small(region r, const char *name); +stamp sv_get_stamp(setif_var v); +const char *sv_get_name(setif_var v); +void sv_unify(setif_var v,setif_var_list vars); +gen_e_list sv_get_lbs(setif_var v); +gen_e_list sv_get_ubs(setif_var v); +bool sv_add_ub(setif_var v, gen_e e, stamp st); +bool sv_add_lb(setif_var v, gen_e e, stamp st); +bool sv_is_ub(setif_var v, stamp st); +bool sv_is_lb(setif_var v, stamp st); +void sv_set_tlb_cache(setif_var v, jcoll j); +jcoll sv_get_tlb_cache(setif_var v); +void sv_clear_tlb_cache(setif_var v); +void sv_add_ub_proj(setif_var v, gen_e e); + +gen_e sv_get_ub_proj(setif_var v, get_proj_fn_ptr get_proj); +gen_e_list sv_get_ub_projs(setif_var v); + +bool sv_union_component(setif_var v1, setif_var v2); + +EXTERN_C_END + + +#endif /* SETIF_VAR_H */ + diff --git a/libbanshee/engine/setst-sort.c b/libbanshee/engine/setst-sort.c new file mode 100644 index 00000000000..5d89817ed00 --- /dev/null +++ b/libbanshee/engine/setst-sort.c @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "bounds.h" +#include "setst-sort.h" + + +struct setst_union_ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + gen_e_list exprs; + gen_e_list proj_cache; +}; + +struct setst_inter_ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + gen_e_list exprs; +}; + +struct setst_constant_ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + char *name; +}; + +typedef struct setst_inter_ *setst_inter_; +typedef struct setst_union_ *setst_union_; +typedef struct setst_constant_ *setst_constant_; + +static region tlb_cache_region; +static jcoll_dict tlb_dict; +static setst_var_list setst_vars; +static bool setst_changed = FALSE; + +region setst_region; +term_hash setst_hash; +struct setst_stats setst_stats; + +stamp setst_get_stamp(gen_e e) +{ +#ifdef NONSPEC + assert(e->sort == setst_sort); +#endif + + if ( ((setst_term)e)->type == VAR_TYPE) + return st_get_stamp( (setst_var)e ); + + else + return ((setst_term)e)->st; +} + +static bool eq(gen_e e1, gen_e e2) +{ + return ( setst_get_stamp(e1) == setst_get_stamp(e2) ); +} + +static gen_e_list get_union(gen_e e) +{ + assert ( ((setst_term)e)->type == UNION_TYPE); + + return ( (setst_union_) e)->exprs; +} + +static gen_e_list get_inter(gen_e e) +{ + assert ( ((setst_term)e)->type == INTER_TYPE); + + return ( (setst_inter_) e)->exprs; +} + +static void update_lower_bound(setst_var v, gen_e e) +{ + if (setst_is_var(e)) + { + if (st_add_lb(v,(setst_var)e)) + { + setst_stats.redundant_var++; + } + else + { + setst_stats.added_var++; + setst_changed = TRUE; + } + } + else + { + if (st_add_source(v, e,setst_get_stamp(e))) + { + setst_stats.redundant_source++; + } + else + { + setst_stats.added_source++; + setst_changed = TRUE; + } + } + +} + +static void update_upper_bound(setst_var v, gen_e e) +{ + assert(! setst_is_var(e)); + + if (st_add_sink(v,e,setst_get_stamp(e))) + { + setst_stats.redundant_sink++; + } + else + { + setst_stats.added_sink++; + setst_changed = TRUE; + } +} + + +void setst_inclusion(con_match_fn_ptr con_match,gen_e e1, gen_e e2) +{ + if (eq(e1,e2)) + return; + + else if ( setst_is_zero(e1) || setst_is_one(e2) ) + return; + + else if (setst_is_union(e1)) + { + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list exprs = get_union(e1); + + gen_e_list_scan(exprs,&scan); + while (gen_e_list_next(&scan,&temp)) + { + setst_inclusion(con_match,temp,e2); + } + + return; + } + + else if (setst_is_inter(e2)) + { + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list exprs = get_inter(e2); + + gen_e_list_scan(exprs,&scan); + while (gen_e_list_next(&scan,&temp)) + { + setst_inclusion(con_match,e1,temp); + } + + return; + } + + else if (setst_is_var(e2)) + { + setst_var v = (setst_var)e2; + + update_lower_bound(v,e1); + } + + else if (setst_is_var(e1)) + { + setst_var v = (setst_var)e1; + + update_upper_bound(v,e2); + } + + else con_match(e1,e2); +} + +#ifdef NONSPEC +static struct setst_term zero = {ZERO_TYPE,setst_sort,ZERO_TYPE}; +static struct setst_term one = {ONE_TYPE,setst_sort,ONE_TYPE}; +#else +static struct setst_term zero = {ZERO_TYPE,ZERO_TYPE}; +static struct setst_term one = {ONE_TYPE,ONE_TYPE}; +#endif /* NONSPEC */ + +gen_e setst_zero(void) +{ + return (gen_e)&zero; +} + +gen_e setst_one(void) +{ + return (gen_e)&one; +} + +gen_e setst_fresh(const char *name) +{ + setst_var v = st_fresh(setst_region,name); + setst_var_list_cons(v,setst_vars); + return (gen_e)v; +} + +gen_e setst_fresh_large(const char *name) +{ + setst_var v = st_fresh_large(setst_region,name); + setst_var_list_cons(v,setst_vars); + return (gen_e)v; +} + +gen_e setst_fresh_small(const char *name) +{ + setst_var v = st_fresh_small(setst_region,name); + setst_var_list_cons(v,setst_vars); + return (gen_e)v; +} + +gen_e setst_constant(const char *str) deletes +{ + stamp st[2]; + gen_e result; + char *name = rstrdup(setst_region,str); + + assert (str != NULL); + + st[0] = CONSTANT_TYPE; + st[1] = stamp_string(name); + + if ( (result = term_hash_find(setst_hash,st,2)) == NULL) + { + setst_constant_ c = ralloc(setst_region, struct setst_constant_); + c->type = CONSTANT_TYPE; + c->st = stamp_fresh(); + c->name = name; + + result = (gen_e) c; + term_hash_insert(setst_hash,result,st,2); + + setst_stats.distinct_constants++; + + return result; + } + + else + { + setst_stats.hashed_constants++; + return result; + } +} + +static bool filter_zero(const gen_e e) +{ + return (!setst_is_zero(e)); +} + + +static bool filter_one(const gen_e e) +{ + return (!setst_is_one(e)); +} + +gen_e setst_union(gen_e_list exprs) deletes +{ + gen_e_list filtered = gen_e_list_filter(setst_region,exprs,filter_zero); + + if ( gen_e_list_empty(filtered) ) + { + setst_stats.filtered_unions++; + return setst_zero(); + } + else if (gen_e_list_length(filtered) == 1) + { + setst_stats.filtered_unions++; + return gen_e_list_head(filtered); + } + + else + { + int i = 0; + gen_e temp,result; + gen_e_list_scanner scan; + stamp st[ gen_e_list_length(filtered) + 1 ]; + + st[0] = UNION_TYPE; + + gen_e_list_scan(filtered,&scan); + while (gen_e_list_next(&scan,&temp)) + { + st[++i] = setst_get_stamp(temp); + } + + if ( (result = + term_hash_find(setst_hash,st,gen_e_list_length(filtered)+1)) + == NULL ) + { + struct setst_union_ *u = ralloc(setst_region,struct setst_union_); + + u->type = UNION_TYPE; + u->st = stamp_fresh(); + u->proj_cache = new_gen_e_list(setst_region); + u->exprs = filtered; + + result = (gen_e)u; + term_hash_insert(setst_hash,result,st,gen_e_list_length(filtered)+1); + + setst_stats.distinct_unions++; + return result; + } + else + { + setst_stats.hashed_unions++; + return result; + } + } +} + +gen_e setst_inter(gen_e_list exprs) deletes +{ + gen_e_list filtered = gen_e_list_filter(setst_region,exprs,filter_one); + + if ( gen_e_list_empty(filtered) ) + { + setst_stats.filtered_intersections++; + return setst_one(); + } + else if (gen_e_list_length(filtered) == 1) + { + setst_stats.filtered_intersections++; + return gen_e_list_head(filtered); + } + + else + { + int i = 0; + gen_e temp,result; + gen_e_list_scanner scan; + stamp st[ gen_e_list_length(filtered) + 1 ]; + + st[0] = INTER_TYPE; + + gen_e_list_scan(filtered,&scan); + while (gen_e_list_next(&scan,&temp)) + { + st[++i] = setst_get_stamp(temp); + } + + if ( (result = + term_hash_find(setst_hash,st,gen_e_list_length(filtered)+1)) + == NULL ) + { + struct setst_inter_ *u = ralloc(setst_region,struct setst_inter_); + + u->type = UNION_TYPE; + u->st = stamp_fresh(); + u->exprs = filtered; + + result = (gen_e)u; + term_hash_insert(setst_hash,result,st,gen_e_list_length(filtered)+1); + + setst_stats.distinct_intersections++; + + return result; + } + else + { + setst_stats.hashed_intersections++; + return result; + } + } +} + + +gen_e_list setst_get_union(gen_e e) +{ + assert (((setst_term)e)->type == UNION_TYPE); + + return ((setst_union_)e)->exprs; +} + + +gen_e_list setst_get_inter(gen_e e) +{ + assert (((setst_term)e)->type == INTER_TYPE); + + return ((setst_inter_)e)->exprs; +} + +static void invalidate_tlb_cache(void) +{ + assert(tlb_cache_region); + + jcoll_delete_dict(tlb_dict); + setst_var_list_app(setst_vars,st_clear_tlb_cache); + deleteregion_ptr(&tlb_cache_region); + + tlb_cache_region = newregion(); + tlb_dict = jcoll_create_dict(tlb_cache_region,setst_get_stamp); +} + +static void set_tlb_cache(setst_var v,jcoll j) +{ + st_set_tlb_cache(v,j); +} + +static void collect_sinks(bounds b,setst_var v) +{ + gen_e sink; + gen_e_list_scanner scan; + + gen_e_list_scan(st_get_sinks(v),&scan); + + while (gen_e_list_next(&scan,&sink)) + { + bounds_add(b,sink,setst_get_stamp(sink)); + } +} + +static void collect_sources(bounds b, setst_var v) +{ + gen_e source; + gen_e_list_scanner scan; + + gen_e_list_scan(st_get_sources(v),&scan); + + while (gen_e_list_next(&scan,&source)) + { + bounds_add(b,source,setst_get_stamp(source)); + } +} + +static void collect_lower_bounds(bounds b, setst_var v) +{ + setst_var lb; + setst_var_list_scanner scan; + + setst_var_list_scan(st_get_lbs(v),&scan); + + while (setst_var_list_next(&scan,&lb)) + { + bounds_add(b,(gen_e)lb,st_get_stamp(lb)); + } +} + +static void apply_sources(setst_var witness, bounds sources) +{ + gen_e source; + gen_e_list_scanner scan; + + gen_e_list_scan(bounds_exprs(sources),&scan); + + while (gen_e_list_next(&scan,&source)) + { + if ( st_add_source(witness,source,setst_get_stamp(source))) + setst_stats.redundant_source++; + + else + setst_stats.added_source++; + } +} + +static void apply_sinks(setst_var witness, bounds sinks) +{ + gen_e sink; + gen_e_list_scanner scan; + + gen_e_list_scan(bounds_exprs(sinks),&scan); + + while (gen_e_list_next(&scan,&sink)) + { + if (st_add_sink(witness,sink,setst_get_stamp(sink))) + setst_stats.redundant_sink++; + + else + setst_stats.added_sink++; + } +} + +static void apply_lower_bounds(setst_var witness,bounds lower) +{ + gen_e lb; + gen_e_list_scanner scan; + + gen_e_list_scan(bounds_exprs(lower),&scan); + + while (gen_e_list_next(&scan,&lb)) + { + if (st_add_lb(witness,(setst_var)lb)) + setst_stats.redundant_var++; + else + setst_stats.added_var++; + } +} + +static void collapse_cycle(setst_var witness, setst_var_list cycle) deletes +{ + setst_var_list_scanner var_scan; + setst_var temp; + region scratch_rgn = newregion(); + + bounds sources = bounds_create(scratch_rgn); + bounds sinks = bounds_create(scratch_rgn); + bounds lower = bounds_create(scratch_rgn); + + + setst_stats.cycles_collapsed++; + + /* force at least another iteration */ + setst_changed = TRUE; + + /* collect all bounds */ + setst_var_list_scan(cycle,&var_scan); + while (setst_var_list_next(&var_scan,&temp)) + { + collect_sources(sources,temp); + collect_sinks(sinks,temp); + collect_lower_bounds(lower,temp); + } + + /* unify all vars */ + st_unify(witness,cycle); + + /* add all bounds back */ + apply_sources(witness,sources); + apply_sinks(witness,sinks); + apply_lower_bounds(witness,lower); + + /* cleanup */ + bounds_delete(sources); + bounds_delete(sinks); + bounds_delete(lower); + deleteregion(scratch_rgn); + + /* remove self edges */ + st_repair_bounds(witness); +} +/* +static bool cycle_detect(setst_var goal, setst_var_list path, + setst_var_list *result) +{ + int pos = st_get_path_pos(goal); + setst_stats.cycles_searched++; + + if (pos) + { + setst_var_list_scanner scan; + setst_var temp; + setst_var_list cycle = new_setst_var_list(tlb_cache_region); + + setst_var_list_scan(path,&scan); + while(setst_var_list_next(&scan,&temp)) + { + if (st_get_path_pos(temp) >= pos) + setst_var_list_cons(temp,cycle); + } + + *result = cycle; + return TRUE; + } + + else + return FALSE; +} + +*/ +static bool cycle_detect(setst_var goal, setst_var_list path, + setst_var_list *result) +{ + setst_var_list cycle = + setst_var_list_reverse(setst_var_list_copy(tlb_cache_region,path)); + + setst_stats.cycles_searched++; + + while (!setst_var_list_empty(cycle) && + !eq((gen_e)setst_var_list_head(cycle),(gen_e)goal)) + { + setst_var_list_tail(cycle); + } + + if (setst_var_list_empty(cycle)) + { + return FALSE; + } + else + { + *result = cycle; + return TRUE; + } +} + +static jcoll tlb_aux(gen_e e,int path_len,setst_var_list path) deletes +{ + if (setst_is_var(e)) + { + setst_var_list cycle; + setst_var v = (setst_var)e; + if ( cycle_detect(v,path,&cycle) ) + { + setst_stats.cycles_length += setst_var_list_length(cycle); + collapse_cycle(v,cycle); + return NULL; + } + else + { + if (st_get_tlb_cache(v) != NULL) + return st_get_tlb_cache(v); + else + { + jcoll result; + setst_var_list_scanner scan; + setst_var lb; + jcoll_list jvars = new_jcoll_list(tlb_cache_region); + + gen_e_list sources = gen_e_list_copy(tlb_cache_region, + st_get_sources(v)); + + st_set_path_pos(v,path_len); + setst_var_list_scan(st_get_lbs(v),&scan); + while (setst_var_list_next(&scan,&lb)) + { + setst_var_list_cons(v,path); + jcoll_list_cons(tlb_aux((gen_e)lb,++path_len,path), + jvars); + setst_var_list_tail(path); + } + + if (! gen_e_list_empty(sources)) + jcoll_list_cons(jcoll_create_chain(tlb_dict,sources), + jvars); + result = jcoll_jjoin(tlb_dict,jvars); + set_tlb_cache(v,result); + st_set_path_pos(v,0); + return result; + } + + } + } + else if (setst_is_union(e)) + { + gen_e_list_scanner scan; + gen_e temp; + jcoll_list jexprs = new_jcoll_list(tlb_cache_region); + + gen_e_list_scan(setst_get_union(e),&scan); + while (gen_e_list_next(&scan,&temp)) + { + jcoll_list_cons(tlb_aux(temp,++path_len,path),jexprs); + } + + return jcoll_jjoin(tlb_dict,jexprs); + } + else + { + fail("Unmatched case in setst tlb computation\n"); + return NULL; + } +} +static gen_e_list tlb(gen_e e) +{ + return jcoll_flatten(tlb_dict, + tlb_aux(e,1,new_setst_var_list(tlb_cache_region)) ); +} +static void match_sinks(incl_fn_ptr setst_incl) +{ + gen_e_list_scanner tlb_scanner, sink_scanner; + setst_var_list_scanner var_scanner; + setst_var v; + gen_e lb, sink; + + setst_var_list_scan(setst_vars,&var_scanner); + + while (setst_var_list_next(&var_scanner,&v)) + { + gen_e_list tlbs = tlb((gen_e)v); + gen_e_list snks = st_get_sinks(v); + + + if(gen_e_list_empty(st_get_sinks(v))) + { + setst_stats.no_sinks++; + continue; + } + else if(st_get_seen(v)) + { + setst_stats.incycle_vars++; + continue; + } + else if (gen_e_list_length(tlbs) == st_get_src_sz(v) + && gen_e_list_length(snks) == st_get_snk_sz(v) ) + { + setst_stats.unchanged_vars++; + continue; + } + st_set_seen(v,TRUE); + + st_set_src_sz(v,gen_e_list_length(tlbs)); + st_set_snk_sz(v,gen_e_list_length(snks)); + + gen_e_list_scan(tlbs,&tlb_scanner); + + while (gen_e_list_next(&tlb_scanner,&lb)) + { + gen_e_list_scan(snks,&sink_scanner); + + while (gen_e_list_next(&sink_scanner,&sink)) + setst_incl(lb,sink); + } + } +} +static void iterate(incl_fn_ptr setst_incl) +{ + setst_var_list_scanner var_scanner; + setst_var v; + /* static int iterations = 0; */ + setst_changed = FALSE; + + setst_var_list_scan(setst_vars,&var_scanner); + while (setst_var_list_next(&var_scanner,&v)) + { + st_set_seen(v,FALSE); + } + + invalidate_tlb_cache(); + match_sinks(setst_incl); + + /* fprintf(stderr,"Iterations : %d\n",++iterations); */ + + if (setst_changed) + iterate(setst_incl); +} +gen_e_list setst_tlb(gen_e e,incl_fn_ptr setst_incl) deletes +{ + if (! setst_changed) + { + return tlb(e); + } + else + { + iterate(setst_incl); + return tlb(e); + } + +} + +void setst_set_proj_cache(gen_e e, gen_e elem) +{ + if (setst_is_union(e)) + { + setst_union_ u = (setst_union_)e; + gen_e_list_cons(elem,u->proj_cache); + } +} + +gen_e_list setst_get_proj_cache(gen_e e) +{ + + if (setst_is_union(e)) + { + setst_union_ u = (setst_union_)e; + return u->proj_cache; + } + else + { + fail("Term does not cache projections\n"); + return NULL; + } +} + +void setst_init(void) +{ + setst_region = newregion(); + tlb_cache_region = newregion(); + setst_hash = make_term_hash(setst_region); + setst_vars = new_setst_var_list(setst_region); + tlb_dict = jcoll_create_dict(tlb_cache_region,setst_get_stamp); +} + +void setst_reset(void) deletes +{ + term_hash_delete(setst_hash); + deleteregion_ptr(&setst_region); + + setst_region = newregion(); + setst_hash = make_term_hash(setst_region); + setst_vars = new_setst_var_list(setst_region); + invalidate_tlb_cache(); + setst_changed = FALSE; +} + +bool setst_is_zero(gen_e e) +{ + return ((setst_term)e)->type == ZERO_TYPE; +} + +bool setst_is_one(gen_e e) +{ + return ((setst_term)e)->type == ONE_TYPE; +} + +bool setst_is_var(gen_e e) +{ + return ((setst_term)e)->type == VAR_TYPE; +} + +bool setst_is_union(gen_e e) +{ + return ((setst_term)e)->type == UNION_TYPE; +} + +bool setst_is_inter(gen_e e) +{ + return ((setst_term)e)->type == INTER_TYPE; +} + +char *setst_get_constant_name(gen_e e) +{ + assert( ((setst_term)e)->type == CONSTANT_TYPE ); + + return ((setst_constant_)e)->name; +} + +void setst_print_stats(FILE *f) +{ + fprintf(f,"\n========== SetST Var Stats ==========\n"); + fprintf(f,"Fresh : %d\n",setst_stats.fresh); + fprintf(f,"Fresh Small : %d\n",setst_stats.fresh_small); + fprintf(f,"Fresh Large : %d\n",setst_stats.fresh_large); + fprintf(f,"Total : %d\n",setst_stats.fresh + setst_stats.fresh_small + + setst_stats.fresh_large); + fprintf(f,"\n========== SetST Sort Stats ==========\n"); + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Additions"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Var: %d\n",setst_stats.added_var); + fprintf(f,"Source: %d\n",setst_stats.added_source); + fprintf(f,"Sink: %d",setst_stats.added_sink); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Total: %d",setst_stats.added_var + setst_stats.added_source + + setst_stats.added_sink); + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Redundant"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Var: %d\n",setst_stats.redundant_var); + fprintf(f,"Source: %d\n",setst_stats.redundant_source); + fprintf(f,"Sink: %d",setst_stats.redundant_sink); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Total: %d\n", + setst_stats.redundant_var + setst_stats.redundant_source + + setst_stats.redundant_sink); + + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Iteration Optimizations"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Skipped vars: %d\n",setst_stats.incycle_vars); + fprintf(f,"Unchanged vars: %d\n",setst_stats.unchanged_vars); + fprintf(f,"Vars w/o sinks: %d\n",setst_stats.no_sinks); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Cycles"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Collapsed: %d\n",setst_stats.cycles_collapsed); + fprintf(f,"Searched: %d\n",setst_stats.cycles_searched); + fprintf(f,"Hit rate: %f\n", + ((float)setst_stats.cycles_collapsed)/((float)setst_stats.cycles_searched)); + fprintf(f,"Average Length: %f\n", + ((float)setst_stats.cycles_length) / ((float)setst_stats.cycles_collapsed)); + fprintf(f,"=====================================\n"); +} + diff --git a/libbanshee/engine/setst-sort.h b/libbanshee/engine/setst-sort.h new file mode 100644 index 00000000000..5aafde398cf --- /dev/null +++ b/libbanshee/engine/setst-sort.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef SETST_SORT_H +#define SETST_SORT_H + +#include "banshee.h" +#include "termhash.h" +#include "setst-var.h" + +extern region setst_region; +extern term_hash setst_hash; + +struct setst_term /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; +}; + +typedef struct setst_term *setst_term; + +stamp setst_get_stamp(gen_e e); +void setst_inclusion(con_match_fn_ptr,gen_e, gen_e); + +gen_e setst_zero(void); +gen_e setst_one(void); +gen_e setst_fresh(const char *name); +gen_e setst_fresh_large(const char *name); +gen_e setst_fresh_small(const char *name); +gen_e setst_constant(const char *name) deletes; +gen_e setst_union(gen_e_list exprs) deletes; +gen_e setst_inter(gen_e_list exprs) deletes; +bool setst_is_zero(gen_e e); +bool setst_is_one(gen_e e); +bool setst_is_var(gen_e e); +bool setst_is_union(gen_e e); +bool setst_is_inter(gen_e e); +bool setst_is_constant(gen_e e); + +char *setst_get_constant_name(gen_e e); +gen_e_list setst_get_union(gen_e e); +gen_e_list setst_get_inter(gen_e e); + +gen_e_list setst_tlb(gen_e e,incl_fn_ptr setst_incl) deletes; +void setst_set_proj_cache(gen_e e, gen_e elem); +gen_e_list setst_get_proj_cache(gen_e e); + + +void setst_init(void); +void setst_reset(void) deletes; +void setst_print_stats(FILE *f); + +extern struct setst_stats setst_stats; + +struct setst_stats +{ + int fresh; + int fresh_large; + int fresh_small; + + int distinct_constructors; + int hashed_constructors; + int distinct_constants; + int hashed_constants; + int distinct_unions; + int filtered_unions; + int hashed_unions; + int distinct_intersections; + int filtered_intersections; + int hashed_intersections; + + int redundant_var; + int redundant_source; + int redundant_sink; + + int added_var; + int added_source; + int added_sink; + + int incycle_vars; + int unchanged_vars; + int no_sinks; + + int cycles_searched; + int cycles_collapsed; + int cycles_length; +}; + + +#endif /* SETST_SORT_H */ + diff --git a/libbanshee/engine/setst-var.c b/libbanshee/engine/setst-var.c new file mode 100644 index 00000000000..ba4c59eb5de --- /dev/null +++ b/libbanshee/engine/setst-var.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "setst-var.h" +#include "jcollection.h" +#include "ufind.h" +#include "bounds.h" + +struct st_info +{ + stamp st; + bounds lbs; + bounds sources; + bounds sinks; + jcoll tlb_cache; + const char *name; + bool seen; + int path_pos; + int src_sz; + int snk_sz; +}; + +typedef struct st_info *st_info; + +DECLARE_UFIND(st_elt,st_info) + +DEFINE_UFIND(st_elt,st_info) + +DEFINE_LIST(setst_var_list,setst_var) + +#define get_info(v) (st_elt_get_info((v)->elt)) + +struct setst_var /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + st_elt elt; +}; + +bool st_eq(setst_var v1, setst_var v2) +{ + return (st_get_stamp(v1) == st_get_stamp(v2)); +} + +static setst_var make_var(region r, const char *name, stamp st) +{ + setst_var result = ralloc(r,struct setst_var); + st_info info = ralloc(r, struct st_info); + + info->st = st; + info->lbs = bounds_create(r); + info->sources = bounds_create(r); + info->sinks = bounds_create(r); + info->tlb_cache = NULL; + info->name = name ? rstrdup(r,name) : "fv"; + info->seen = FALSE; + info->path_pos = 0; + info->src_sz = 0; + info->snk_sz = 0; + + result->type = VAR_TYPE; + result->elt = new_st_elt(r,info); + + +#ifdef NONSPEC + result->sort = setst_sort; +#endif + + return result; +} + +setst_var st_fresh(region r, const char *name) +{ + return make_var(r,name,stamp_fresh()); +} + +setst_var st_fresh_large(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_large()); +} + +setst_var st_fresh_small(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_small()); +} + +stamp st_get_stamp(setst_var v) +{ + return get_info(v)->st; +} + +const char *st_get_name(setst_var v) +{ + return get_info(v)->name; +} + +void st_unify(setst_var v,setst_var_list vars) +{ + setst_var temp; + setst_var_list_scanner scan; + + setst_var_list_scan(vars,&scan); + + while (setst_var_list_next(&scan,&temp)) + { + st_elt_union(v->elt,temp->elt); + } +} + +setst_var_list st_get_lbs(setst_var v) +{ + return (setst_var_list)bounds_exprs(get_info(v)->lbs); +} + +gen_e_list st_get_sources(setst_var v) +{ + return bounds_exprs(get_info(v)->sources); +} + +gen_e_list st_get_sinks(setst_var v) +{ + return bounds_exprs(get_info(v)->sinks); +} + +bool st_add_lb(setst_var v, setst_var lb) +{ + return bounds_add(get_info(v)->lbs,(gen_e)lb,st_get_stamp(lb)); +} + +bool st_add_source(setst_var v, gen_e source, stamp s) +{ + return bounds_add(get_info(v)->sources,source,s); +} + +bool st_add_sink(setst_var v, gen_e sink, stamp s) +{ + return bounds_add(get_info(v)->sinks,sink,s); +} + +jcoll st_get_tlb_cache(setst_var v) +{ + return get_info(v)->tlb_cache; +} + +void st_set_tlb_cache(setst_var v, jcoll j) +{ + get_info(v)->tlb_cache = j; +} + +void st_clear_tlb_cache(setst_var v) +{ + get_info(v)->tlb_cache = NULL; +} + +gen_e st_get_ub_proj(setst_var v, get_proj_fn_ptr get_proj) +{ + return get_proj(st_get_sinks(v)); +} +static setst_var neq_temp; +static bool neq (const setst_var v2) +{ + return (!(st_get_stamp (neq_temp) == st_get_stamp (v2))); +} +void st_repair_bounds(setst_var v1) +{ + setst_var_list lbs; + neq_temp = v1; + lbs = setst_var_list_filter2(st_get_lbs(v1),neq); + + bounds_set(get_info(v1)->lbs,(gen_e_list)lbs); +} + +void st_set_path_pos(setst_var v, int pos) +{ + get_info(v)->path_pos = pos; +} + +int st_get_path_pos(setst_var v) +{ + return get_info(v)->path_pos; +} + +void st_set_seen(setst_var v, bool b) +{ + get_info(v)->seen = b; +} + +bool st_get_seen(setst_var v) +{ + return get_info(v)->seen; +} + +void st_set_src_sz(setst_var v, int size) +{ + get_info(v)->src_sz = size; +} + +int st_get_src_sz(setst_var v) +{ + return get_info(v)->src_sz; +} + +void st_set_snk_sz(setst_var v, int size) +{ + get_info(v)->snk_sz = size; +} + +int st_get_snk_sz(setst_var v) +{ + return get_info(v)->snk_sz; +} + + + + + + diff --git a/libbanshee/engine/setst-var.h b/libbanshee/engine/setst-var.h new file mode 100644 index 00000000000..6ef2f84a005 --- /dev/null +++ b/libbanshee/engine/setst-var.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef SETST_VAR_H +#define SETST_VAR_H + +#include "linkage.h" +#include "banshee.h" +#include "jcollection.h" + +EXTERN_C_BEGIN + +typedef struct setst_var *setst_var; + +DECLARE_LIST(setst_var_list,setst_var) + +bool st_eq(setst_var v1, setst_var v2); +setst_var st_fresh(region r, const char *name); +setst_var st_fresh_large(region r, const char *name); +setst_var st_fresh_small(region r, const char *name); +stamp st_get_stamp(setst_var v); +const char *st_get_name(setst_var v); +void st_unify(setst_var v,setst_var_list vars); +setst_var_list st_get_lbs(setst_var v); +gen_e_list st_get_sources(setst_var v); +gen_e_list st_get_sinks(setst_var v); +gen_e st_get_ub_proj(setst_var v, get_proj_fn_ptr get_proj); +bool st_add_lb(setst_var v, setst_var lb); +bool st_add_source(setst_var v, gen_e source, stamp s); +bool st_add_sink(setst_var v, gen_e sink, stamp s); + +void st_set_path_pos(setst_var v, int pos); +int st_get_path_pos(setst_var v); +void st_set_seen(setst_var v, bool b); +bool st_get_seen(setst_var v); +void st_set_src_sz(setst_var v, int size); +int st_get_src_sz(setst_var v); +void st_set_snk_sz(setst_var v, int size); +int st_get_snk_sz(setst_var v); + +jcoll st_get_tlb_cache(setst_var v); +void st_set_tlb_cache(setst_var v, jcoll j); +void st_clear_tlb_cache(setst_var v); + +void st_repair_bounds(setst_var v); + +EXTERN_C_END + +#endif /* SETST_VAR_H */ + diff --git a/libbanshee/engine/stamp.c b/libbanshee/engine/stamp.c new file mode 100644 index 00000000000..8a1f5a95faf --- /dev/null +++ b/libbanshee/engine/stamp.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "stamp.h" +#include "util.h" +#include "hash.h" +#include "list.h" +#define INITIAL_SIZE 32 +#define INITIAL1 0 +#define INITIAL2 2000 +#define INITIAL3 536870911 +#define MIN -1073741824 /* -2^30 */ +#define MAX 1073741824 /* 2^30 */ + +static hash_table str_hash; +static region str_hash_rgn; + +static int count1 = INITIAL1, count2 = INITIAL2, count3 = INITIAL3; +static int bounds1 = MIN, bounds2 = 536870911, bounds3 = MAX; + +static inline stamp check1(int i) +{ + if (i <= bounds1) + fail ("Unable to create stamp with small index\n"); + return i; +} + +static inline stamp check2(int i) +{ + if (i > bounds2) + fail ("Unable to create a stamp with regular index\n"); + return i; +} + +static inline stamp check3(int i) +{ + if (i >= bounds3) + fail ("Unable to create a stamp with large index\n"); + return i; +} + +stamp stamp_fresh(void) +{ + return (check2(++count2)); +} + +stamp stamp_fresh_small(void) +{ + return (check1(--count1)); +} + +stamp stamp_fresh_large(void) +{ + return (check3(++count3)); +} + +stamp stamp_string(const char *str) deletes +{ + long st; + assert(str_hash != NULL); + + if (! hash_table_lookup(str_hash,(hash_key)str, (void *)(char *) &st)) + { + st = stamp_fresh(); + (void)hash_table_insert(str_hash,(hash_key)str,(hash_data) st); + } + return st; +} + +void stamp_reset(void) deletes +{ + count1 = INITIAL1; + count2 = INITIAL2; + count3 = INITIAL3; + hash_table_reset(str_hash); + deleteregion_ptr(&str_hash_rgn); +} + + + +void stamp_init(void) +{ + str_hash_rgn = newregion(); + str_hash = make_string_hash_table(str_hash_rgn,INITIAL_SIZE,FALSE); + +} +#if 0 +const char *stamp_to_str(region r,stamp st) +{ + return inttostr(r,st); +} +#endif diff --git a/libbanshee/engine/stamp.h b/libbanshee/engine/stamp.h new file mode 100644 index 00000000000..52c55598327 --- /dev/null +++ b/libbanshee/engine/stamp.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef STAMP_H +#define STAMP_H + +#include +#include "linkage.h" + +EXTERN_C_BEGIN + +typedef long stamp; + +stamp stamp_fresh(void); +stamp stamp_fresh_small(void); +stamp stamp_fresh_large(void); + +stamp stamp_string(const char *) deletes; + +const char *stamp_to_str(region r,stamp st); + +void stamp_reset(void) deletes; +void stamp_init(void); + +EXTERN_C_END + +#endif /* STAMP_H */ + + + diff --git a/libbanshee/engine/term-sort.c b/libbanshee/engine/term-sort.c new file mode 100644 index 00000000000..7503f296338 --- /dev/null +++ b/libbanshee/engine/term-sort.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "term-sort.h" + +struct term_constant_ /* extends gen_e */ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + char *name; +}; + +typedef struct term_constant_ *term_constant_; + +region term_sort_region; +term_hash term_sort_hash; +bool flag_occurs_check = FALSE; + +struct term_stats term_stats; + +stamp term_get_stamp(gen_e e) +{ + if ( ((gen_term)e)->type == VAR_TYPE ) + return ((gen_term)term_get_ecr(e))->st; + else + return ((gen_term)e)->st; +} + +gen_e term_fresh(const char *name) +{ + term_stats.fresh++; + return (gen_e)tv_fresh(term_sort_region,name); +} + +gen_e term_fresh_large(const char *name) +{ + term_stats.fresh_large++; + return (gen_e)tv_fresh_large(term_sort_region,name); +} + +gen_e term_fresh_small(const char *name) +{ + term_stats.fresh_small++; + return (gen_e)tv_fresh_small(term_sort_region,name); +} + + +#ifdef NONSPEC +static struct gen_term zero = {ZERO_TYPE,term_sort,ZERO_TYPE}; +static struct gen_term one = {ONE_TYPE,term_sort,ONE_TYPE}; +#else +static struct gen_term zero = {ZERO_TYPE,ZERO_TYPE}; +static struct gen_term one = {ONE_TYPE,ONE_TYPE}; +#endif /* NONSPEC */ + +gen_e term_zero(void) +{ + return (gen_e)&zero; +} + +gen_e term_one(void) +{ + return (gen_e)&one; +} + + +gen_e term_constant(const char *str) +{ + stamp st[2]; + gen_e result; + char *name = rstrdup(term_sort_region,str); + + assert (str != NULL); + + st[0] = CONSTANT_TYPE; + st[1] = stamp_string(name); + + if ( (result = term_hash_find(term_sort_hash,st,2)) == NULL) + { + term_constant_ c = ralloc(term_sort_region, struct term_constant_); + c->type = CONSTANT_TYPE; + c->st = stamp_fresh(); + c->name = name; + + result = (gen_e) c; + term_hash_insert(term_sort_hash,result,st,2); + + return result; + } + + else + { + return result; + } + +} + +static bool term_is_bottom(gen_e e) +{ + return (term_is_zero(e) || term_is_var(e)); +} + +bool term_is_zero(gen_e e) +{ + return ( ((gen_term)term_get_ecr(e))->type == ZERO_TYPE); +} + +bool term_is_one(gen_e e) +{ + return ( ((gen_term)term_get_ecr(e))->type == ONE_TYPE); +} + +bool term_is_var(gen_e e) +{ + return ( ((gen_term)term_get_ecr(e))->type == VAR_TYPE); +} + +bool term_is_constant(gen_e e) +{ + return ( ((gen_term)term_get_ecr(e))->type == CONSTANT_TYPE); +} + +char *term_get_constant_name(gen_e e) +{ + gen_e ecr = term_get_ecr(e); + if(! term_is_constant(ecr)) + return NULL; + else + return ((term_constant_)ecr)->name; +} + +gen_e term_get_ecr(gen_e e) +{ + if (((gen_term)e)->type == VAR_TYPE) + return tv_get_ecr((term_var)e); + else return e; +} + +static void fire_pending(term_var v, gen_e e, + con_match_fn_ptr con_match, + occurs_check_fn_ptr occurs) +{ + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list_scan(tv_get_pending(v),&scan); + while (gen_e_list_next(&scan,&temp)) + { + term_unify(con_match,occurs,temp,e); + } +} + +static bool eq(gen_e e1, gen_e e2) +{ + return term_get_ecr(e1) == term_get_ecr(e2); +} + +void term_unify(con_match_fn_ptr con_match, occurs_check_fn_ptr occurs, + gen_e a, gen_e b) +{ + gen_e e1 = term_get_ecr(a), + e2 = term_get_ecr(b); + + if ( eq(e1,e2) ) + { + return; + } + if (term_is_constant(e1) && term_is_constant(e2)) + { + failure("Inconsistent system of constraints\n"); + } + else if (term_is_var(e1)) + { + term_var v = (term_var)e1; + + + if (! term_is_bottom(e2)) + fire_pending(v,e2,con_match,occurs); + + if (term_is_var(e2)) + tv_unify_vars(v,(term_var)e2); + else /* v = e2, e2 is not a var */ + { + if (occurs(v,e2)) + failure("Unify terms: occurs check failed\n"); + tv_unify(v,e2); + } + } + else if (term_is_var(e2)) + { + term_var v = (term_var)e2; + + if (! term_is_bottom(e2)) + fire_pending(v,e1,con_match,occurs); + + /* v = e1, e1 is not a var */ + if (occurs(v,e1)) + failure("Unify terms: occurs check failed\n"); + tv_unify(v,e1); + + } + else con_match(e1,e2); +} + +void term_cunify(con_match_fn_ptr con_match, occurs_check_fn_ptr occurs, + gen_e e1, gen_e e2) +{ + if (term_is_bottom(e1) && term_is_var(e1)) + { + term_var v1 = (term_var)e1; + tv_add_pending(v1,e2); + } + else + { + term_unify(con_match,occurs,e1,e2); + } +} + +static void term_reset_stats(void) +{ + term_stats.fresh = 0; + term_stats.fresh_small = 0; + term_stats.fresh_large = 0; +} + +void term_print_stats(FILE *f) +{ + fprintf(f,"\n========== Term Var Stats ==========\n"); + fprintf(f,"Fresh : %d\n",term_stats.fresh); + fprintf(f,"Fresh Small : %d\n",term_stats.fresh_small); + fprintf(f,"Fresh Large : %d\n",term_stats.fresh_large); + fprintf(f,"=====================================\n"); +} + +/* TODO */ +void term_print_constraint_graph(FILE *f ATTRIBUTE_UNUSED) +{ +} + +void term_init(void) +{ + term_sort_region = newregion(); + term_sort_hash = make_term_hash(term_sort_region); +} + +void term_reset(void) +{ + term_hash_delete(term_sort_hash); + deleteregion_ptr(&term_sort_region); + + term_reset_stats(); + + term_sort_region = newregion(); + term_sort_hash = make_term_hash(term_sort_region); +} + + + diff --git a/libbanshee/engine/term-sort.h b/libbanshee/engine/term-sort.h new file mode 100644 index 00000000000..21a5dc5cff1 --- /dev/null +++ b/libbanshee/engine/term-sort.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef TERM_SORT_H +#define TERM_SORT_H + +#include +#include "banshee.h" +#include "termhash.h" +#include "term-var.h" + +EXTERN_C_BEGIN + +extern bool flag_occurs_check; +extern region term_sort_region; +extern term_hash term_sort_hash; + +struct gen_term /* extends gen_e */ +{ +#ifdef NONSPEC + const sort_kind sort; +#endif + const int type; + const stamp st; +}; + +typedef struct gen_term *gen_term; + +/* return TRUE if v occurs in e, fals otherwise */ +typedef bool (* occurs_check_fn_ptr) (term_var v, gen_e e); + +stamp term_get_stamp(gen_e e); + +gen_e term_fresh(const char *name); +gen_e term_fresh_large(const char *name); +gen_e term_fresh_small(const char *name); +gen_e term_zero(void); +gen_e term_one(void); +gen_e term_constant(const char *name); + +bool term_is_zero(gen_e e); +bool term_is_one(gen_e e); +bool term_is_var(gen_e e); +bool term_is_constant(gen_e e); + +char *term_get_constant_name(gen_e e); +gen_e term_get_ecr(gen_e e); + +void term_unify(con_match_fn_ptr con_match, occurs_check_fn_ptr occurs, + gen_e e1, gen_e e2); +void term_cunify(con_match_fn_ptr con_match, occurs_check_fn_ptr occurs, + gen_e e1, gen_e e2); + +void term_print_stats(FILE *f); +void term_print_constraint_graph(FILE *f); + +void term_init(void); +void term_reset(void); + +extern struct term_stats term_stats; + +struct term_stats +{ + int fresh; + int fresh_small; + int fresh_large; +}; + +EXTERN_C_END + +#endif /* TERM_SORT_H */ + + + diff --git a/libbanshee/engine/term-var.c b/libbanshee/engine/term-var.c new file mode 100644 index 00000000000..9b8e2059871 --- /dev/null +++ b/libbanshee/engine/term-var.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include "ufind.h" +#include "term-var.h" + +DECLARE_UFIND(tv_elt,gen_e) + +DEFINE_UFIND(tv_elt,gen_e) + +DEFINE_LIST(term_var_list,term_var) + +struct term_var +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + gen_e_list pending; + const char *name; + tv_elt elt; +}; + +static term_var make_var(region r, const char *name, stamp st) +{ + term_var result = ralloc(r, struct term_var); + gen_e info = (gen_e) result; + + result->type = VAR_TYPE; + result->st = st; + result->pending = new_gen_e_list(r); + result->name = name ? rstrdup(r,name) : "fv"; + result->elt = new_tv_elt(r,info); + + return result; +} + +term_var tv_fresh(region r, const char *name) +{ + return make_var(r,name,stamp_fresh()); +} + +term_var tv_fresh_small(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_small()); +} + +term_var tv_fresh_large(region r, const char *name) +{ + return make_var(r,name,stamp_fresh_large()); +} + +static term_var tv_get_v_ecr(term_var v) +{ + term_var ecr = (term_var)tv_get_ecr(v); + assert (ecr->type == VAR_TYPE); /* this is a hack, but should be ok */ + + return ecr; +} + +const char *tv_get_name(term_var v) +{ + return tv_get_v_ecr(v)->name; +} + +gen_e_list tv_get_pending(term_var v) +{ + return tv_get_v_ecr(v)->pending; +} + +void tv_add_pending(term_var v,gen_e e) +{ + gen_e_list_cons(e,tv_get_v_ecr(v)->pending); +} + +void tv_unify(term_var v, gen_e e) +{ + tv_elt_update(v->elt,e); + + assert(tv_get_ecr(v) == e); +} + +static gen_e tv_combine(gen_e e1, gen_e e2) +{ + term_var v1 = (term_var)e1, + v2 = (term_var)e2; + + if (! (v1 == v2) ) + gen_e_list_append(tv_get_pending(v1), tv_get_pending(v2)); + + return e1; +} + +void tv_unify_vars(term_var v1, term_var v2) +{ + tv_elt_unify(tv_combine,v1->elt, v2->elt); +} + +gen_e tv_get_ecr(term_var v) +{ + return tv_elt_get_info(v->elt); +} diff --git a/libbanshee/engine/term-var.h b/libbanshee/engine/term-var.h new file mode 100644 index 00000000000..1ca035ff8c6 --- /dev/null +++ b/libbanshee/engine/term-var.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef TERM_VAR_H +#define TERM_VAR_H + +#include "linkage.h" +#include "banshee.h" + +EXTERN_C_BEGIN + +typedef struct term_var *term_var; + +DECLARE_LIST(term_var_list,term_var) + +term_var tv_fresh(region r, const char *name); +term_var tv_fresh_small(region r, const char *name); +term_var tv_fresh_large(region r, const char *name); + +const char *tv_get_name(term_var v); + +gen_e_list tv_get_pending(term_var v); +void tv_add_pending(term_var v,gen_e e); + +void tv_unify(term_var v, gen_e e); +void tv_unify_vars(term_var v1, term_var v2); + +gen_e tv_get_ecr(term_var v); + + +EXTERN_C_END + +#endif /* TERM_VAR_H */ diff --git a/libbanshee/engine/termhash.c b/libbanshee/engine/termhash.c new file mode 100644 index 00000000000..b42f9ba7304 --- /dev/null +++ b/libbanshee/engine/termhash.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "termhash.h" +#include "hash.h" +#include "termhash.h" +#include "util.h" + +#define UB(n) ((1<next) + +/* size: initial_table_size + number of rehashes */ +/* capacity: 2^size (for array size) */ +/* ub: 2^size-1 (for array indexing) */ +/* inserts: num of elements inserted into the array */ +struct term_hash +{ + term_bucket * term_buckets; + region rgn; + int ub; + int size; + int capacity; + int inserts; +}; + +static int hash(int ub, stamp stamps[], int len); +static void post_insert(term_hash tab) deletes; +static void rehash(term_hash tab) deletes; +static void reinsert(term_hash tab, term_bucket b); +static void insert(term_hash tab, gen_e e, stamp * stamps, int len); +static void insert_entry(term_hash tab, struct hash_entry *entry); +static gen_e walk(term_bucket b, stamp * stamps, int len); + +static const int primes[] = + { 83, 1789, 5189, 5449, 5659, 6703, 7517, 7699, 8287, 8807, 9067, 9587, + 10627, 10939, 11239}; +/* +static const int prime_1 = 83; +static const int prime_2 = 1789; +*/ +static const int initial_table_size = INITIAL_TABLE_SIZE; + +term_hash make_term_hash(region rgn) +{ + int ub, n; + int i; + + region r; + + term_hash tab = ralloc(rgn, struct term_hash); + + r = newregion(); + ub = UB(initial_table_size); + n = CAP(initial_table_size); + + + tab->term_buckets = rarrayalloc(r, n, term_bucket); + + for (i = 0; i < n; i++) + { + tab->term_buckets[i] = NULL; + } + + tab->rgn = r; + tab->ub = ub; + tab->size = initial_table_size; + tab->capacity = n; + tab->inserts = 0; + return tab; +} + +void term_hash_delete(term_hash tab) deletes +{ + deleteregion(tab->rgn); +} + +gen_e term_hash_find(term_hash tab, stamp stamps[], int len) +{ + int hash_val; + + term_bucket b; + hash_val = hash(tab->ub, stamps, len); + b = tab->term_buckets[hash_val]; + return walk(b, stamps, len); +} + +static gen_e walk(term_bucket b, stamp stamps[], int len) +{ + term_bucket cur; + scan_term_bucket(b,cur) + { + if (len == cur->entry->length + && (memcmp(stamps, cur->entry->stamps, sizeof(int)*len) == 0) ) + return cur->entry->e; + } + return NULL; +} + +/* Should call t_hash_find to see if a gen_e with the given stamp */ +/* signature is already in the table. If so, insert should return */ +/* true and do nothing. */ +bool term_hash_insert(term_hash tab, gen_e e, stamp * stamps, int len) deletes +{ + if (term_hash_find(tab, stamps, len) != NULL) + { + return TRUE; + } + insert(tab, e, stamps, len); + post_insert(tab); + return FALSE; +} + + +/* Insert an expression e represented by the given stamp array into */ +/* the hash table. */ +static void insert(term_hash tab, gen_e e, stamp stamps[], int len) +{ + hash_entry entry; + stamp * stamp_cpy; + int i; + + + entry = ralloc(tab->rgn, struct hash_entry); + + stamp_cpy = rarrayalloc(tab->rgn, len, stamp); + for (i = 0; i < len; i++) + { + stamp_cpy[i] = stamps[i]; + } + + entry->length = len; + entry->stamps = stamp_cpy; + entry->e = e; + insert_entry(tab, entry); +} + +static void insert_entry(term_hash tab, hash_entry entry) +{ + int hash_val; + + term_bucket b, new_term_bucket; + hash_val = hash(tab->ub, entry->stamps, entry->length); + b = tab->term_buckets[hash_val]; + new_term_bucket = ralloc(tab->rgn, struct term_bucket); + + new_term_bucket->entry = entry; + new_term_bucket->next = b; + tab->term_buckets[hash_val] = new_term_bucket; +} + +static void post_insert(term_hash tab) deletes +{ + if (tab->capacity == ++tab->inserts) + { + rehash(tab); + } +} + +/* Double the size of the hash table and reinsert all of the elements. */ +static void rehash(term_hash tab) deletes +{ + region old_rgn; + term_bucket * old_term_buckets; + int i; + int old_table_size = tab->capacity; + + old_term_buckets = tab->term_buckets; + tab->capacity *= 2; + tab->ub = UB(++tab->size); + old_rgn = tab->rgn; + tab->rgn = newregion(); + + + tab->term_buckets = rarrayalloc(tab->rgn, tab->capacity, term_bucket); + for (i = 0; i < old_table_size; i++) + { + if (old_term_buckets[i] != NULL && old_term_buckets[i]->entry != NULL) + reinsert(tab, old_term_buckets[i]); + } + + deleteregion(old_rgn); + + +} + +static void reinsert(term_hash tab, term_bucket b) +{ + term_bucket cur; + scan_term_bucket(b,cur) + insert(tab, cur->entry->e, cur->entry->stamps, cur->entry->length); +} + +static int hash(int ub, stamp stamps[], int len) +{ + int i, n; + + n = 0; + for (i = 0; i < len; i++) + { + n = (n + (primes[i % 15] * abs(stamps[i]))) & ub; + } + return n; +} + + + + + + diff --git a/libbanshee/engine/termhash.h b/libbanshee/engine/termhash.h new file mode 100644 index 00000000000..777adc3fd16 --- /dev/null +++ b/libbanshee/engine/termhash.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef TERMHASH_H +#define TERMHASH_H + +#include "banshee.h" +#include "stamp.h" +#include "bool.h" + +typedef struct term_hash *term_hash; + +term_hash make_term_hash(region r); + +gen_e term_hash_find(term_hash h, stamp *st,int length); + +bool term_hash_insert(term_hash h, gen_e e, stamp *st, int length) deletes; + +void term_hash_delete(term_hash h) deletes; + +#endif /* TERMHASH_H */ diff --git a/libbanshee/engine/ufind.c b/libbanshee/engine/ufind.c new file mode 100644 index 00000000000..545171812bb --- /dev/null +++ b/libbanshee/engine/ufind.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include "ufind.h" +#include "assert.h" + + +enum uf_type {uf_ecr,uf_link}; +typedef enum uf_type uf_type; + +struct uf_element +{ + uf_type type; + int rank; + void *info; + struct uf_element *link; +}; + +struct uf_element *new_uf_element(region r, void *info) +{ + struct uf_element *result; + + result = ralloc(r, struct uf_element); + + result->type = uf_ecr; + result->rank = 0; + result->info = info; + result->link = NULL; + + return result; +} + +static struct uf_element *find(struct uf_element *e) +{ + + if (e->type == uf_ecr) + return e; + + else if (e->link->type == uf_link) + { + struct uf_element *temp = e->link; + + e->link = e->link->link; + + return find(temp); + } + + else + return e->link; +} + +bool uf_union(struct uf_element *a, struct uf_element *b) +{ + struct uf_element *e1 = find(a); + struct uf_element *e2 = find(b); + + if ( e1 == e2 ) + return FALSE; + + else if (e1->rank < e2->rank) + { + e1->type = uf_link; + e1->link = e2; + + return TRUE; + } + + else if (e1->rank > e2->rank) + { + e2->type = uf_link; + e2->link = e1; + + return TRUE; + } + + else + { + e2->rank++; + + e1->type = uf_link; + e1->link = e2; + + return TRUE; + } + +} + +bool uf_unify(combine_fn_ptr combine, + struct uf_element *a, struct uf_element *b) +{ + struct uf_element *e1 = find(a); + struct uf_element *e2 = find(b); + + if ( e1 == e2 ) + return FALSE; + + else if (e1->rank < e2->rank) + { + e2->info = combine(e2->info,e1->info); + e1->type = uf_link; + e1->link = e2; + + return TRUE; + } + + else if (e1->rank > e2->rank) + { + e1->info = combine(e1->info,e2->info); + e2->type = uf_link; + e2->link = e1; + + return TRUE; + } + + else + { + e2->info = combine(e2->info, e1->info); + + e2->rank++; + e1->type = uf_link; + e1->link = e2; + + return TRUE; + } +} + + + +void *uf_get_info(struct uf_element *e) +{ + return find(e)->info; +} + + +bool uf_eq(struct uf_element *e1,struct uf_element *e2) +{ + return (find(e1) == find(e2)); +} + +void uf_update(struct uf_element *e,uf_info i) +{ + find(e)->info = i; +} + + + + + + diff --git a/libbanshee/engine/ufind.h b/libbanshee/engine/ufind.h new file mode 100644 index 00000000000..5068530114e --- /dev/null +++ b/libbanshee/engine/ufind.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef UFIND_H +#define UFIND_H + +#include +#include "linkage.h" +#include "bool.h" + +EXTERN_C_BEGIN + +struct uf_element; + +typedef struct uf_element *uf_element; +typedef void *uf_info; + +typedef uf_info (*combine_fn_ptr)(uf_info,uf_info); + +struct uf_element *new_uf_element(region r,uf_info i); +uf_info uf_get_info(struct uf_element *); +bool uf_unify(combine_fn_ptr,struct uf_element *,struct uf_element *); +bool uf_union(struct uf_element *,struct uf_element *); +bool uf_eq(struct uf_element *,struct uf_element *); +void uf_update(struct uf_element *,uf_info i); + +#define DECLARE_UFIND(name,type) \ +typedef struct name *name; \ +typedef type (* name ## _combine_fn_ptr)(type info1,type info2); \ +name new_ ## name(region r, type info); \ +type name ## _get_info(name); \ +bool name ## _unify(name ## _combine_fn_ptr,name e1, name e2); \ +bool name ## _union(name e1, name e2); \ +bool name ## _eq(name e1, name e2); \ +void name ## _update(name e1, type info); + +#define DEFINE_UFIND(name,type) \ +name new_ ## name(region r, type info) \ +{ \ + return (name)new_uf_element(r,info);\ +}\ +type name ## _get_info(name elem) \ +{ \ + return (type)uf_get_info((struct uf_element *)elem);\ +} \ +bool name ## _unify(name ## _combine_fn_ptr cmb,name e1, name e2) \ +{ \ + return uf_unify((combine_fn_ptr)cmb,(struct uf_element *)e1,(struct uf_element *)e2); \ +} \ +bool name ## _union(name e1, name e2) \ +{ \ + return uf_union((struct uf_element *)e1,(struct uf_element *)e2); \ +}\ +bool name ## _eq(name e1, name e2) \ +{ \ + return uf_eq((struct uf_element *)e1,(struct uf_element *)e2); \ +} \ +void name ##_update(name e1, type info) \ +{ \ + uf_update((struct uf_element *)e1,(uf_info)info); \ +} \ + +EXTERN_C_END + +#endif /* UFIND_H */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libbanshee/engine/util.c b/libbanshee/engine/util.c new file mode 100644 index 00000000000..8989956b70a --- /dev/null +++ b/libbanshee/engine/util.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "buffer.h" +#include "util.h" + +/* Panic with a message */ +static void vfail(const char *fmt, va_list args) __attribute__((__noreturn__)); + +static void vfail(const char *fmt, va_list args) +{ + vfprintf(stderr, fmt, args); + fflush(stdin); + fflush(stderr); + fflush(stdout); + sync(); + fsync(STDIN_FILENO); + fsync(STDERR_FILENO); + fsync(STDOUT_FILENO); + abort(); + while (1); /* Work around stupid gcc-2.96-85 bug */ +} + +/* Panic with a nice message */ +void __fail(const char *file, unsigned int line, + const char *func __attribute__((unused)), + const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "\n%s:%u ", file, line); + vfail(fmt, args); +} + +#ifndef HAVE_VARIADIC_MACROS +/* Panic with a not-quite-as-nice message */ +void fail(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfail(fmt, args); +} +#endif + +void failure(const char *message) +{ + fprintf(stderr,message); + exit(1); +} + +/* Concatenate 2 strings, allocating space in r for the result */ +char *rstrcat(region r, const char *s1, const char *s2) +{ + char *result = rarrayalloc(r, strlen(s1)+strlen(s2)+1, char); + result[0] = '\0'; + strcat(result, s1); + strcat(result, s2); + return result; +} + +/* Concatenate n strings, allocating space in r for the result. The + last argument should be a null pointer. */ +char *rstrscat(region r, ...) +{ + char *result; + int len = 0; + const char *s; + va_list args; + + va_start(args, r); + while ((s = va_arg(args, const char *))) + len += strlen(s); + result = rarrayalloc(r, len+1, char); + result[0] = '\0'; + + va_start(args, r); + while ((s = va_arg(args, const char *))) + strcat(result, s); + + return result; +} +#if 0 +/* Convert an integer to a string, storing the result in r */ +const char *inttostr(region r, int i) +{ + char *result; + int width; + + if (i == 0) + width = 1; + else + width = (int) (floor(log10(abs((double) i))) + 1); + if (i<0) width++; + + printf("i=%d, width=%d\n", i, width); + assert(width >0); + + result = rarrayalloc(r, width + 1, char); + if (snprintf(result, width + 1, "%d", i) == -1) { + printf("i=%d, width=%d\n", i, width); + fail ("inttostr width wrong\n"); + } + return result; +} +#endif + +/* sprintf a string, allocating space in r for the result */ +char *rsprintf(region r, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + return rvsprintf(r, fmt, args); +} + +char *rvsprintf(region r, const char *fmt, va_list args) +{ + growbuf buf = growbuf_new(r, 100); + gvprintf(buf, fmt, args); + return growbuf_contents(buf); +} + +/* Space for the ASCII representation of a pointer -- 2 hex chars per + byte, plus 3 chars for 0x prefix and trailing \0 */ +#define PTR_ASCII_SIZE ((int) (3 + sizeof(void *)*2)) + +/* Convert a pointer to an ascii string with leading 0x. Re-uses + internal buffer. */ +char *ptr_to_ascii(void *ptr) { + static char addr[PTR_ASCII_SIZE]; + int nchars; + + nchars = snprintf(addr, PTR_ASCII_SIZE, "%p", ptr); + if (nchars == -1 || nchars >= PTR_ASCII_SIZE) + fail("Unable to convert ptr to ascii (need %d bytes, have %d)\n", + nchars, PTR_ASCII_SIZE); + return addr; +} + +/* Convert a pointer to an integer */ +long ptr_hash(void *ptr) +{ + return (long) ptr; +} + +/* Return TRUE iff ptr1 == ptr2 */ +bool ptr_eq(void *ptr1, void *ptr2) +{ + return ptr1 == ptr2; +} + +/* Return TRUE iff s1 == s2 */ +bool str_eq(const char *s1, const char *s2) +{ + return (strcmp(s1, s2) == 0); +} + +/* A total ordering on pointers. Returns 0 if ptr1 = ptr2, a value <0 + if ptr1 < ptr2, or a value >0 if ptr1 > ptr2. */ +int ptr_cmp(const void *ptr1, const void *ptr2) +{ + return (char *) ptr1 - (char *) ptr2; +} + +int min(int a, int b) { if (a < b) return a; else return b; } +int max(int a, int b) { if (a < b) return b; else return a; } +/* int abs(int a) { if (a < 0) return -a; else return a; } */ diff --git a/libbanshee/engine/util.h b/libbanshee/engine/util.h new file mode 100644 index 00000000000..1d13147da08 --- /dev/null +++ b/libbanshee/engine/util.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include +#include +#include "compiler.h" +#include "linkage.h" +#include "bool.h" + + +EXTERN_C_BEGIN + +#ifdef HAVE_VARIADIC_MACROS +#define fail(args...) __fail(__FILE__, __LINE__, __FUNCTION__, args) +#else +void fail(const char *fmt, ...); +#endif + +void __fail(const char *file, unsigned int line, + const char *func, const char *fmt, ...) __attribute__ ((__noreturn__)); + + +/* insist(action) is like assert(action), but action may have + side-effects */ +#ifdef NDEBUG +# define insist(action) (action) +#else +# define insist assert +#endif + +#ifdef NDEBUG +# define insistnot(action) (action) +#else +# define insistnot(action) assert(!(action)) +#endif + +void failure(const char *message); + +/* Concatenate 2 strings, allocating space in r for the result */ +char *rstrcat(region, const char *, const char *); + +/* Concatenate n strings, allocating space in r for the result. The + last argument should be a null pointer. */ +char *rstrscat(region, ...); + +/* Convert an integer to a string, storing the result in r */ +const char *inttostr(region r, int); + +/* sprintf a string, allocating space in r for the result */ +char *rsprintf(region r, const char *fmt, ...); +char *rvsprintf(region r, const char *fmt, va_list args); + +/* Convert a pointer to an ascii string with leading 0x. Re-uses + internal buffer. */ +char *ptr_to_ascii(void *ptr); + +/* Convert a pointer to an integer */ +long ptr_hash(void *ptr); + +/* Return TRUE iff ptr1 == ptr2 */ +bool ptr_eq(void *ptr1, void *ptr2); + +/* Return TRUE iff s1 == s2 */ +bool str_eq(const char *s1, const char *s2); + +/* A total ordering on pointers. Returns 0 if ptr1 = ptr2, a value <0 + if ptr1 < ptr2, or a value >0 if ptr1 > ptr2. */ +int ptr_cmp(const void *ptr1, const void *ptr2); + +extern inline int min(int, int); +extern inline int max(int, int); +extern inline int min(int a, int b) { if (a < b) return a; else return b; } +extern inline int max(int a, int b) { if (a < b) return b; else return a; } +EXTERN_C_END + +#endif diff --git a/libbanshee/libcompat/Makefile.am b/libbanshee/libcompat/Makefile.am new file mode 100644 index 00000000000..dae6ac0052f --- /dev/null +++ b/libbanshee/libcompat/Makefile.am @@ -0,0 +1,4 @@ +AM_CFLAGS = -I$(srcdir)/../engine -I$(srcdir)/../include -I. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@ +noinst_LIBRARIES = libbansheecompat.a +libbansheecompat_a_SOURCES = regions.c radix-tree.c + diff --git a/libbanshee/libcompat/Makefile.in b/libbanshee/libcompat/Makefile.in new file mode 100644 index 00000000000..48e4249ee3d --- /dev/null +++ b/libbanshee/libcompat/Makefile.in @@ -0,0 +1,365 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_libbanshee_warn_cflags = @ac_libbanshee_warn_cflags@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CFLAGS = -I$(srcdir)/../engine -I$(srcdir)/../include -I. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@ +noinst_LIBRARIES = libbansheecompat.a +libbansheecompat_a_SOURCES = regions.c radix-tree.c +subdir = libcompat +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libbansheecompat_a_AR = $(AR) cru +libbansheecompat_a_LIBADD = +am_libbansheecompat_a_OBJECTS = regions.$(OBJEXT) radix-tree.$(OBJEXT) +libbansheecompat_a_OBJECTS = $(am_libbansheecompat_a_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/radix-tree.Po ./$(DEPDIR)/regions.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libbansheecompat_a_SOURCES) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(libbansheecompat_a_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu libcompat/Makefile +Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +AR = ar + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libbansheecompat.a: $(libbansheecompat_a_OBJECTS) $(libbansheecompat_a_DEPENDENCIES) + -rm -f libbansheecompat.a + $(libbansheecompat_a_AR) libbansheecompat.a $(libbansheecompat_a_OBJECTS) $(libbansheecompat_a_LIBADD) + $(RANLIB) libbansheecompat.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radix-tree.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regions.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) + +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-depend distclean-generic distclean-tags distdir dvi \ + dvi-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libbanshee/libcompat/alloc.c b/libbanshee/libcompat/alloc.c new file mode 100644 index 00000000000..7f2cfd369b2 --- /dev/null +++ b/libbanshee/libcompat/alloc.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1999-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* TBD: recover unusued portions of pages for use as individual pages */ + +#include +#include "regions.h" + +static void alloc_block(region r, struct allocator *a, struct ablock *blk, + void **p1, int s1, int a1, void **p2, int s2, int a2, + size_t blksize, int needsclear) +{ + struct page *newp; + char *mem1, *mem2; + + mem1 = PALIGN(blk->allocfrom, a1); + mem2 = PALIGN(mem1 + s1, a2); + + /* Can't use last byte of page (pointers to the byte after an object are + valid) */ + if (mem2 + s2 >= blk->base + blksize) + { + if (blksize == RPAGESIZE) + { + newp = alloc_single_page(a->pages); + a->pages = newp; + blk->allocfrom = (char *)newp + offsetof(struct page, previous); + set_region(newp, 1, r); + } + else + { + newp = alloc_pages(blksize >> RPAGELOG, a->bigpages); + a->bigpages = newp; + blk->allocfrom = (char *)newp + offsetof(struct page, previous); + set_region(newp, blksize >> RPAGELOG, r); + } + blk->base = (char *)newp; + + if (needsclear) + preclear(blk->allocfrom, blksize - (blk->allocfrom - (char *)newp)); + mem1 = PALIGN(blk->allocfrom, a1); + mem2 = PALIGN(mem1 + s1, a2); + } + + ASSERT_INUSE(blk->base, r); + blk->allocfrom = mem2 + s2; + + *p1 = mem1; + *p2 = mem2; +} + +void qalloc(region r, struct allocator *a, void **p1, int s1, int a1, + void **p2, int s2, int a2, int needsclear) +{ + struct page *p; + char *mem; + int npages; + int n = ALIGN(s1, a2) + s2; /* Yes, this is correct (see alloc_block) */ + + if (n <= RPAGESIZE / K) + { + alloc_block(r, a, &a->page, p1, s1, a1, p2, s2, a2, RPAGESIZE, + needsclear); + return; + } + if (n <= RPAGESIZE) + { + alloc_block(r, a, &a->superpage, p1, s1, a1, p2, s2, a2, + K * RPAGESIZE, needsclear); + return; + } + if (n <= RPAGESIZE * K) + { + alloc_block(r, a, &a->hyperpage, p1, s1, a1, p2, s2, a2, + K * K * RPAGESIZE, needsclear); + return; + } + + npages = (n + ALIGN(offsetof(struct page, previous), a1) + RPAGESIZE - 1) + >> RPAGELOG; + p = alloc_pages(npages, a->bigpages); + a->bigpages = p; + set_region(p, npages, r); + + mem = (char *)p + offsetof(struct page, previous); + *p1 = PALIGN(mem, a1); + *p2 = PALIGN((char *) *p1 + s1, a2); + if (needsclear) + preclear(*p2, s2); +} + +void free_all_pages(region r, struct allocator *a) +/* Assumes freepages_lock held */ +{ + struct page *p, *next; + + for (p = a->pages; p; p = next) + { + next = p->next; + free_single_page(r, p); + } + for (p = a->bigpages; p; p = next) + { + next = p->next; + free_pages(r, p); + } +} diff --git a/libbanshee/libcompat/pages.c b/libbanshee/libcompat/pages.c new file mode 100644 index 00000000000..9e85e9baef0 --- /dev/null +++ b/libbanshee/libcompat/pages.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 1999-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include + +typedef __rcintptr pageid; + +#if 0 +#define FREEPAGE ((region)-1) /* Id of a free page */ +#else +#define FREEPAGE (&zeroregion) +#endif +#ifdef NMEMDEBUG +#define ASSERT_FREE(p) +#define ASSERT_INUSE(p, r) +#else +#define ASSERT_FREE(p) assert(regionof(p) == FREEPAGE) +#ifdef DUPLICATES +#define ASSERT_INUSE(p, r) assert(regionof(p) == r->base) +#else +#define ASSERT_INUSE(p, r) assert(regionof(p) == r) +#endif +#endif + +/* Page allocator for region-based memory management */ +/* TBD: special free list for size == K ?? */ + +#define PAGECOUNTBITS (CHAR_BIT * sizeof(pageid) - 1) + +struct page +{ + /* Next page in region or in free list */ + struct page *next; + + /* Doubly linked list of pages sorted by address */ + struct page *next_address, *prev_address; + + /* number of pages in this allocation unit. Negative for free pages. */ + pageid pagecount : PAGECOUNTBITS; + + unsigned int free : 1; + + /* Only in free pages not in the single_pages list */ + struct page *previous; +}; + +/* The pages are kept in a single list sorted by address via the + next_address and prev_address fields. The first page's prev_address and + the last page's next_address fields points to pages_byaddress. + page_byaddress.next_address is the first page + page_byaddress.prev_address is the last page + + This list is used for coalescing operations. +*/ +static struct page pages_byaddress; + +struct page *alloc_single_page(struct page *next); +void free_single_page(region r, struct page *p); + +struct page *alloc_pages(int n, struct page *next); +void free_pages(region r, struct page *p); + + +/* a list of free individual pages */ +struct page *single_pages; + +/* free pages (not including those in single_pages) */ +struct page *unused_pages; + +static void init_pages(void) +{ + pages_byaddress.next_address = &pages_byaddress; + pages_byaddress.prev_address = &pages_byaddress; +} + +static void insertbefore_address(struct page *p, struct page *before) +{ + p->prev_address = before->prev_address; + p->next_address = before; + before->prev_address = p; + p->prev_address->next_address = p; +} + +static void unlink_address(struct page *p) +{ + p->prev_address->next_address = p->next_address; + p->next_address->prev_address = p->prev_address; +} + +static void addbyaddress(struct page *p) +{ + struct page *address_scan; + + /* Warning: this is slow. Calls to it should not be frequent (once app + reaches a steady state of memory usage). */ + + for (address_scan = pages_byaddress.next_address; ; + address_scan = address_scan->next_address) + if (p < address_scan || address_scan == &pages_byaddress) + { + insertbefore_address(p, address_scan); + return; + } +} + +/* Doubly linked page list management */ +void addfront(struct page **list, struct page *p) +/* Effects: Adds p to the front of doubly-linked list list */ +{ + p->previous = NULL; + p->next = *list; + if (*list) (*list)->previous = p; + *list = p; +} + +void unlink_page(struct page **list, struct page *p) +/* Effects: Remove p from its doubly linked list */ +{ + if (p->previous) + p->previous->next = p->next; + else + *list = p->next; + if (p->next) + p->next->previous = p->previous; +} + +void *region_get_mem(size_t s) +{ + void *mem = malloc(s + RPAGESIZE - 1); + + return (void *)ALIGN((__rcintptr)mem, RPAGESIZE); +} + +/* Page to region map management */ +/* ----------------------------- */ + +RADIX_TREE(__rcregionmap); + +static void set_page_region(pageid pagenb, region r) +{ + radix_tree_delete (&__rcregionmap, pagenb); + radix_tree_insert (&__rcregionmap, pagenb, r); +} + +#define page_region(pagenb) (radix_tree_lookup (&__rcregionmap, (pagenb))) + +void set_region(struct page *p, int npages, region r) +{ + pageid pnb = PAGENB(p); + + while (npages-- > 0) + set_page_region(pnb++, r); +} + +/* Mark the memory range from 'from' (inclusive) to 'to' (exclusive) + as belonging to region with id 'rid' */ +void set_region_range(void *from, void *to, region r) +{ + pageid first = PAGENB(from), last = PAGENB((pageid)to - 1); + + while (first <= last) + set_page_region(first++, r); +} + +/* Multi-page allocation management */ +/* -------------------------------- */ + +struct page *alloc_new(int n, struct page *next) +/* Assumes freepages_lock held */ +{ + struct page *newp = region_get_mem(n << RPAGELOG); + + if (!newp) + { + if (nomem_h) + nomem_h(); + abort(); + } + assert(!((long)newp & (RPAGESIZE - 1))); + + newp->next = next; + newp->pagecount = n; + newp->free = 0; + addbyaddress(newp); +#ifndef NMEMDEBUG + { + pageid i, pnb = PAGENB(newp); + + for (i = pnb; i < pnb + n; i++) + set_page_region(i, FREEPAGE); + } +#endif + + return newp; +} + +struct page *alloc_split(struct page *split, int n, struct page *next) +/* Assumes freepages_lock held */ +{ +#ifndef NMEMDEBUG + /* These pages had better be free */ + pageid i, pnb = PAGENB(split); + + assert(split->pagecount >= n); + for (i = pnb; i < pnb + split->pagecount; i++) + assert(page_region(i) == FREEPAGE); +#endif + if (split->pagecount > n) + { + struct page *splitoff; + + /* Keep first part of block */ + split->pagecount -= n; + /* Return latter part of block */ + splitoff = split; + split = (struct page *)((char *)split + (split->pagecount << RPAGELOG)); + + /* Update the by adress list */ + insertbefore_address(split, splitoff->next_address); + } + else + { + /* remove split from list */ + unlink_page(&unused_pages, split); + } + split->next = next; + split->pagecount = n; + split->free = 0; + + return split; +} + +struct page *alloc_pages(int n, struct page *next) +{ + struct page *best; + int bestn; + struct page *scan; + + assert(n >= K); + + scan = unused_pages; + /* Find first fit */ + for (;;) + { + if (!scan) + return alloc_new(n, next); + + if (scan->pagecount >= n) break; + scan = scan->next; + } + + /* Now find best fit */ + best = scan; + bestn = scan->pagecount; + for (;;) + { + scan = scan->next; + if (!scan) + return alloc_split(best, n, next); + + if (scan->pagecount >=n && scan->pagecount < bestn) + { + best = scan; + bestn = scan->pagecount; + } + } +} + +static void coalesce(struct page *p) +{ + struct page *prev = p->prev_address, *next; + + p->free = 1; + + /* Coalesce with predecessor ? */ + if (prev->free && (char *)prev + (prev->pagecount << RPAGELOG) == (char *)p) + { + prev->pagecount += p->pagecount; + unlink_address(p); + p = prev; + } + else /* No, add to free pages list */ + addfront(&unused_pages, p); + + next = p->next_address; + /* Coalesce with successor ? */ + if (next->free && (char *)p + (p->pagecount << RPAGELOG) == (char *)next) + { + unlink_page(&unused_pages, next); + p->pagecount += next->pagecount; + unlink_address(next); + } +} + +void free_pages(region r, struct page *p) +/* Assumes freepages_lock held */ +{ +#ifndef NMEMDEBUG + pageid i, pnb = PAGENB(p); + + for (i = pnb; i < pnb + p->pagecount; i++) + { + assert(page_region(i) == r); + set_page_region(i, FREEPAGE); + } +#endif + + coalesce(p); +} + + +/* Single page management */ +/* ---------------------- */ + +static int single_page_count; + +static void add_single_pages(struct page *base) +/* Effects: Adds pages at base to the single_pages list */ +{ + pageid n = base->pagecount; + struct page *prev = base->prev_address, *basenext = base->next_address, + *next; + + single_page_count += n; + + for (;;) + { + ASSERT_FREE(base); + base->free = 0; /* Not free so that coalesce won't steal these back */ + base->prev_address = prev; + prev = base; + base->next = single_pages; + single_pages = base; + if (--n == 0) + break; + next = (struct page *)((char *)base + RPAGESIZE); + base->next_address = next; + base = next; + } + base->next_address = basenext; + basenext->prev_address = base; +} + +void scavenge_single_pages(int n) +{ + /* Add n pages to the single_pages list */ + struct page *scan, *best; + __rcintptr bestn; + + /* Take any group in unused_pages that is <= n or < K. + Remember smallest entry > n too. This is sortof equivalent to + a best fit where we allow partial allocations to make up a whole */ + best = NULL; + bestn = (__rcintptr)1 << (sizeof(__rcintptr) * CHAR_BIT - 2); + scan = unused_pages; + while (scan) + { + /* The pages < K can't be used for anything but single pages so we + might as well grab them even if they are a little too big */ + if (scan->pagecount <= n || scan->pagecount < K) + { + struct page *adding = scan; + + scan = scan->next; + n -= adding->pagecount; + unlink_page(&unused_pages, adding); + add_single_pages(adding); + if (n <= 0) return; + } + else + { + if (scan->pagecount < bestn) + { + bestn = scan->pagecount; + best = scan; + } + scan = scan->next; + } + } + /* Still not enough. Split the best block if there is one, allocate + new pages otherwise */ + if (!best) + add_single_pages(alloc_new(n, NULL)); + else if (best->pagecount - n < K) + { + unlink_page(&unused_pages, best); + add_single_pages(best); + } + else + add_single_pages(alloc_split(best, n, NULL)); +} + +struct page *alloc_single_page(struct page *next) +{ + struct page *p; + + if (!single_pages) + { + scavenge_single_pages(PAGE_GROUP_SIZE); + } + ASSERT_FREE(single_pages); + p = single_pages; + single_pages = p->next; + p->next = next; + + single_page_count--; + + return p; +} + +void free_single_page(region r, struct page *p) +/* Assumes freepages_lock held */ +{ +#ifndef NMEMDEBUG + ASSERT_INUSE(p, r); + set_page_region(PAGENB(p), FREEPAGE); +#endif + + /* Once free list is big enough just coalesce the pages. + The actual threshold to use might merit further study (something + adaptive ? e.g., proportional to allocated single pages) */ + if (single_page_count > PAGE_GROUP_SIZE * 2) + { + p->pagecount = 1; + coalesce(p); + } + else + { + p->next = single_pages; + single_pages = p; + single_page_count++; + } +} diff --git a/libbanshee/libcompat/profile.c b/libbanshee/libcompat/profile.c new file mode 100644 index 00000000000..0a30a55e41e --- /dev/null +++ b/libbanshee/libcompat/profile.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 1999-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#undef REGION_PROFILE +#include "regions.h" +#include "profile.h" + +typedef struct Alloc_info +{ + struct Alloc_info *next; + char *file; + int line; + unsigned long size; + unsigned long calls; +} *ainfo; + +static ainfo ainfos = NULL; +static region profile_region = NULL; + +/* perror(s) then exit */ +void pfail(const char *s) +{ + perror(s); + exit(EXIT_FAILURE); +} + +/************************************************************************** + * * + * Log information about an allocation -- generic * + * * + **************************************************************************/ + +static int registered_exit = 0; + +static ainfo find_ainfo(char *file, int line) +{ + ainfo ai; + + for (ai = ainfos; ai; ai = ai->next) + if (line == ai->line && !strcmp(file, ai->file)) + return ai; + + if (!registered_exit) + { + if (atexit(profile)) + fprintf(stderr, "Registration of profile at exit failed\n"); + registered_exit = 1; + } + + if (!profile_region) + profile_region = newregion(); + ai = ralloc(profile_region, struct Alloc_info); + ai->file = file; + ai->line = line; + ai->size = 0; + ai->calls = 0; + ai->next = ainfos; + ainfos = ai; + return ai; +} + +/************************************************************************** + * * + * Log information about an allocation -- GCC * + * * + * WARNING: This code uses __builtin_return_address, a non-portable * + * feature of gcc, to trace the call chain back. You'll also get ugly * + * output unless the addr2line (in GNU binutils) is installed. * + * * + * ANOTHER WARNING: The depths hard-coded in find_cinfo are only correct * + * if find_cinfo is inlined. Ack! * + * * + **************************************************************************/ + +#define REGION_PROFILE_DEPTH 2 +#undef TRACE_STACK +#if defined(__GNUC__) && defined(__OPTIMIZE__) && REGION_PROFILE_DEPTH > 1 +#define TRACE_STACK +#endif + +#ifdef TRACE_STACK + +#if REGION_PROFILE_DEPTH > 6 +#error "REGION_PROFILE_DEPTH must be less than 6. See find_cinfo()." +#endif + +typedef struct Call_info +{ + struct Call_info *next; + void **stack; /* Array holding the call chain */ + unsigned long size; + unsigned long calls; +} *cinfo; + +static cinfo cinfos = NULL; + +/* Find the current call chain and return a pointer to our status for + it, or allocate a new entry if there is none. */ +static cinfo find_cinfo(void) +{ + void *calls[REGION_PROFILE_DEPTH]; + int i; + cinfo ci; + + /* Compute the call chain. This is an awful hack. */ + i = 0; + if (i < REGION_PROFILE_DEPTH) + calls[i++] = __builtin_return_address(1); + if (i < REGION_PROFILE_DEPTH) + calls[i++] = __builtin_return_address(2); + if (i < REGION_PROFILE_DEPTH) + calls[i++] = __builtin_return_address(3); + if (i < REGION_PROFILE_DEPTH) + calls[i++] = __builtin_return_address(4); + if (i < REGION_PROFILE_DEPTH) + calls[i++] = __builtin_return_address(5); + if (i < REGION_PROFILE_DEPTH) + calls[i++] = __builtin_return_address(6); + /* Add more if you want a higher call-depth (why would you?) */ + + /* Find it */ + for (ci = cinfos; ci; ci = ci->next) + if (!memcmp(calls, ci->stack, REGION_PROFILE_DEPTH*sizeof(void *))) + return ci; + + if (!profile_region) + profile_region = newregion(); + ci = ralloc(profile_region, struct Call_info); + ci->stack = rarrayalloc(profile_region, REGION_PROFILE_DEPTH, void *); + memcpy(ci->stack, calls, REGION_PROFILE_DEPTH*sizeof(void *)); + ci->size = 0; + ci->calls = 0; + ci->next = cinfos; + cinfos = ci; + return ci; + +} +#endif + +static void add_alloc(char *file, int line, int size) +{ + ainfo ai = find_ainfo(file, line); + ai->calls++; + ai->size += size; +#ifdef TRACE_STACK + { + cinfo ci; + + ci = find_cinfo(); + ci->calls++; + ci->size += size; + } +#endif +} + +/************************************************************************** + * * + * Intercept and log calls to region library * + * * + **************************************************************************/ + +void *profile_typed_ralloc(region r, size_t size, type_t type, char *file, + int line) +{ + add_alloc(file, line, size); + return typed_ralloc(r, size, type); +} + +void *profile_typed_rarrayalloc(region r, size_t n, size_t size, type_t type, + char *file, int line) +{ + add_alloc(file, line, n*size); + return typed_rarrayalloc(r, n, size, type); +} + +void *profile_typed_rarrayextend(region r, void *old, size_t n, size_t size, + type_t type, char *file, int line) +{ + add_alloc(file, line, n*size); /* XXX: Fix */ + return typed_rarrayextend(r, old, n, size, type); +} + +char *profile_rstralloc(region r, size_t size, char *file, int line) +{ + add_alloc(file, line, size); + return rstralloc(r, size); +} + +char *profile_rstralloc0(region r, size_t size, char *file, int line) +{ + add_alloc(file, line, size); + return rstralloc0(r, size); +} + +char *profile_rstrdup(region r, const char *s, char *file, int line) +{ + add_alloc(file, line, strlen(s)); + return rstrdup(r, s); +} + +char *profile_rstrextend(region r, const char *old, size_t newsize, + char *file, int line) +{ + add_alloc(file, line, newsize); /* XXX: Fix */ + return rstrextend(r, old, newsize); +} + +char *profile_rstrextend0(region r, const char *old, size_t newsize, + char *file, int line) +{ + add_alloc(file, line, newsize); /* XXX: Fix */ + return rstrextend0(r, old, newsize); +} + +/************************************************************************** + * * + * Display results -- generic * + * * + **************************************************************************/ + +static FILE *out = NULL; + +/* Generic list -- used for generic sorting. Note that next field is + at the top. */ +typedef struct List +{ + struct List *next; +} *list; + +/* Sort a list. cmp should sort in reverse order. */ +static list sort_list(list l, int (*cmp)(const void *, const void *)) +{ + list cur, result; + list *sorted; + int i, length; + region temp_region; + + /* Compute length of list */ + for (cur = l, length = 0; cur; cur = cur->next, length++); + + temp_region = newregion(); + sorted = rarrayalloc(temp_region, length, list *); + for (cur = l, i = 0; cur; cur = cur->next) + sorted[i++] = cur; + qsort(sorted, length, sizeof(list *), cmp); + + result = NULL; + for (i = 0; i < length; i++) + { + cur = result; + result = sorted[i]; + result->next = cur; + } + deleteregion(temp_region); + return result; +} + + +typedef struct File_info +{ + struct File_info *next; + char *file; + unsigned long size; + unsigned long calls; + unsigned long sites; +} *finfo; + +static finfo finfos = NULL; + +static int finfo_cmp(const void *a, const void *b) +{ + finfo *afi = (finfo *) a; + finfo *bfi = (finfo *) b; + return (*afi)->size - (*bfi)->size; /* Reverse order */ +} + +static void print_finfos(void) +{ + finfo fi; + unsigned long size, sites, calls; + + finfos = (finfo) sort_list((list) finfos, finfo_cmp); + size = sites = calls = 0; + fprintf(out, " Bytes | Sites | Calls | File\n"); + fprintf(out, " ------------+-------+----------+---------------------\n"); + for (fi = finfos; fi; fi = fi->next) + { + size += fi->size; + sites += fi->sites; + calls += fi->calls; + fprintf(out, " %12lu | %5lu | %8lu | %s\n", + fi->size, fi->sites, fi->calls, fi->file); + } + fprintf(out, " ------------+-------+----------+---------------------\n"); + fprintf(out, " %12lu | %5lu | %8lu | Total\n", + size, sites, calls); + +} + +static int ainfo_cmp(const void *a, const void *b) +{ + ainfo *afi = (ainfo *) a; + ainfo *bfi = (ainfo *) b; + return (*afi)->size - (*bfi)->size; /* Reverse order */ +} + +static void print_ainfos(void) +{ + ainfo ai; + + unsigned long size, calls; + + ainfos = (ainfo) sort_list((list) ainfos, ainfo_cmp); + size = calls = 0; + fprintf(out, " Bytes | Calls | Site\n"); + fprintf(out, " ------------+----------+---------------------\n"); + for (ai = ainfos; ai; ai = ai->next) + { + size += ai->size; + calls += ai->calls; + fprintf(out, " %12lu | %8lu | %s:%d\n", + ai->size, ai->calls, ai->file, ai->line); + } + fprintf(out, " ------------+----------+---------------------\n"); + fprintf(out, " %12lu | %8lu | Total\n", + size, calls); +} + +static finfo find_finfo(char *file) +{ + finfo fi; + + for (fi = finfos; fi; fi = fi->next) + if (!strcmp(file, fi->file)) + return fi; + + fi = ralloc(profile_region, struct File_info); + fi->file = file; + fi->size = 0; + fi->calls = 0; + fi->sites = 0; + fi->next = finfos; + finfos = fi; + return fi; +} + +static void gather_finfo(void) +{ + ainfo ai; + + for (ai = ainfos; ai; ai = ai->next) + { + finfo fi = find_finfo(ai->file); + fi->size += ai->size; + fi->calls += ai->calls; + fi->sites++; + } +} + +/************************************************************************** + * * + * Display results -- GCC * + * * + **************************************************************************/ + +#ifdef TRACE_STACK + +pid_t child_pid = 0; +int child_in[2], child_out[2]; /* pipes to child process */ + +static void start_prettiness(void) +{ + if (pipe(child_in) || pipe(child_out)) + pfail("Unable to open pipe to child process"); + if (!(child_pid = fork())) + { + /* Child process */ + pid_t parent_pid; + char filename[64]; + + if (dup2(child_in[0], STDIN_FILENO) == -1) + pfail("Unable to open pipe from parent"); + close(child_in[0]); + close(child_in[1]); + if (dup2(child_out[1], STDOUT_FILENO) == -1) + pfail("Unable to open pipe to parent"); + close(child_out[0]); + close(child_out[1]); + + parent_pid = getppid(); + snprintf(filename, 64, "/proc/%d/exe", parent_pid); + filename[63] = '\0'; + execlp("addr2line", "addr2line", "-s", "-e", filename, 0); + fprintf(stderr, "Unable to fork addr2line\n"); + exit(EXIT_FAILURE); + } + else + { + close(child_in[0]); + close(child_out[1]); + } +} + +/* Turn p into a file:line string */ +static char *prettify(void *p) +{ +#define BUFSIZE 1024 + static char buf[BUFSIZE]; + int size; + + /*printf("To child: %p\n", p);*/ + size = snprintf(buf, BUFSIZE, "%p\n", p); + write(child_in[1], buf, size); + size = read(child_out[0], buf, BUFSIZE - 1); + if (!size) + pfail("Unable to read from child process"); + buf[size-1] = '\0'; /* Kill \n */ + /*printf("Read: [%s]\n", buf);*/ + return buf; +} + +static void end_prettiness(void) +{ + if (child_pid) + kill(child_pid, SIGHUP); +} + +static int cinfo_cmp(const void *a, const void *b) +{ + cinfo *aci = (cinfo *) a; + cinfo *bci = (cinfo *) b; + return (*aci)->size - (*bci)->size; /* Reverse order */ +} + +/* Print the call chain information out to a file. */ +static void print_cinfos(void) +{ + cinfo ci; + unsigned long size, calls; + int i; + + cinfos = (cinfo) sort_list((list) cinfos, cinfo_cmp); + size = calls = 0; + start_prettiness(); + fprintf(out, " Bytes | Calls | Call Stack\n"); + fprintf(out, " ------------+----------+---------------------\n"); + for (ci = cinfos; ci; ci = ci->next) + { + size += ci->size; + calls += ci->calls; + fprintf(out, " %12lu | %8lu | ", ci->size, ci->calls); + for (i = 0; i < REGION_PROFILE_DEPTH; i++) + fprintf(out, "%s ", prettify(ci->stack[i])); + fprintf(out, "\n"); + } + fprintf(out, " ------------+----------+---------------------\n"); + fprintf(out, " %12lu | %8lu | Total\n", + size, calls); + end_prettiness(); +} +#endif + + +void profile(void) +{ + if (profile_region == NULL) + return; + + gather_finfo(); + + if (!(out = fopen("profile.out", "w"))) + pfail("Unable to open profile.out"); + + fprintf(out, "---------------------------\n"); + fprintf(out, "Region Library Memory Usage\n"); + fprintf(out, "---------------------------\n\n"); + + print_finfos(); + fprintf(out, "\n"); + print_ainfos(); +#ifdef TRACE_STACK + fprintf(out, "\n"); + print_cinfos(); +#endif + + fclose(out); +} diff --git a/libbanshee/libcompat/profile.h b/libbanshee/libcompat/profile.h new file mode 100644 index 00000000000..b07034e2191 --- /dev/null +++ b/libbanshee/libcompat/profile.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1999-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef PROFILE_H +#define PROFILE_H + +/* Should only be included in regions.h and profile.c */ + +void *profile_typed_ralloc(region r, size_t size, type_t type, char *file, int line); +void *profile_typed_rarrayalloc(region r, size_t n, size_t size, type_t type, char *file, int line); +void *profile_typed_rarrayextend(region r, void *old, size_t n, size_t size, type_t type, char *file, int line); +char *profile_rstralloc(region r, size_t size, char *file, int line); +char *profile_rstralloc0(region r, size_t size, char *file, int line); +char *profile_rstrdup(region r, const char *s, char *file, int line); +char *profile_rstrextend(region r, const char *old, size_t newsize, char *file, int line); +char *profile_rstrextend0(region r, const char *old, size_t newsize, char *file, int line); + +#ifdef REGION_PROFILE +#define typed_ralloc(r, size, type) profile_typed_ralloc(r, size, type, __FILE__, __LINE__) +#define typed_rarrayalloc(r, n, size, type) profile_typed_rarrayalloc(r, n, size, type, __FILE__, __LINE__) +#define typed_rarrayextend(r, old, n, size, type) profile_typed_rarrayextend(r, old, n, size, type, __FILE__, __LINE__) + +#define rstralloc(r, size) profile_rstralloc(r, size, __FILE__, __LINE__) +#define rstralloc0(r, size) profile_rstralloc0(r, size, __FILE__, __LINE__) +#define rstrdup(r, s) profile_rstrdup(r, s, __FILE__, __LINE__) + +#define rstrextend(r, old, newsize) profile_rstrextend(r, old, newsize, __FILE__, __LINE__) +#define rstrextend0(r, old, newsize) profile_rstrextend0(r, old, newsize, __FILE__, __LINE__) +#endif + +void profile(void); + +#endif diff --git a/libbanshee/libcompat/radix-tree.c b/libbanshee/libcompat/radix-tree.c new file mode 100644 index 00000000000..18f8929ad2d --- /dev/null +++ b/libbanshee/libcompat/radix-tree.c @@ -0,0 +1,364 @@ +/* + * Modified to work in GCC in 2003 by Daniel Berlin + * Copyright (C) 2001 Momchil Velikov + * Portions Copyright (C) 2001 Christoph Hellwig + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include "radix-tree.h" +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) +/* + * Radix tree node definition. + */ +#define RADIX_TREE_MAP_SHIFT 6 +#define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) +#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) + +struct radix_tree_node { + unsigned int count; + void *slots[RADIX_TREE_MAP_SIZE]; +}; + +struct radix_tree_path { + struct radix_tree_node *node, **slot; +}; + +#define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) +#define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2) + +static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH]; + + +/* + * This assumes that the caller has performed appropriate preallocation, and + * that the caller has pinned this thread of control to the current CPU. + */ +static struct radix_tree_node * +radix_tree_node_alloc(struct radix_tree_root *root) +{ + struct radix_tree_node *ret; + + ret = (struct radix_tree_node *) + calloc (1, sizeof (struct radix_tree_node)); + if (!ret) + abort (); + return ret; +} + +static inline void +radix_tree_node_free(struct radix_tree_node *node) +{ + free (node); +} + + +/* + * Return the maximum key which can be store into a + * radix tree with height HEIGHT. + */ +static inline unsigned long radix_tree_maxindex(unsigned int height) +{ + return height_to_maxindex[height]; +} + +/* + * Extend a radix tree so it can store key @index. + */ +static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) +{ + struct radix_tree_node *node; + unsigned int height; + + /* Figure out what the height should be. */ + height = root->height + 1; + while (index > radix_tree_maxindex(height)) + height++; + + if (root->rnode) { + do { + if (!(node = radix_tree_node_alloc(root))) + return -ENOMEM; + + /* Increase the height. */ + node->slots[0] = root->rnode; + node->count = 1; + root->rnode = node; + root->height++; + } while (height > root->height); + } else + root->height = height; + + return 0; +} + +/** + * radix_tree_insert - insert into a radix tree + * @root: radix tree root + * @index: index key + * @item: item to insert + * + * Insert an item into the radix tree at position @index. + */ +int radix_tree_insert(struct radix_tree_root *root, unsigned long index, + void *item) +{ + struct radix_tree_node *node = NULL, *tmp, **slot; + unsigned int height, shift; + int error; + + /* Make sure the tree is high enough. */ + if (index > radix_tree_maxindex(root->height)) { + error = radix_tree_extend(root, index); + if (error) + return error; + } + + slot = &root->rnode; + height = root->height; + shift = (height-1) * RADIX_TREE_MAP_SHIFT; + + while (height > 0) { + if (*slot == NULL) { + /* Have to add a child node. */ + if (!(tmp = radix_tree_node_alloc(root))) + return -ENOMEM; + *slot = tmp; + if (node) + node->count++; + } + + /* Go a level down. */ + node = *slot; + slot = (struct radix_tree_node **) + (node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK)); + shift -= RADIX_TREE_MAP_SHIFT; + height--; + } + + if (*slot != NULL) + return -EEXIST; + if (node) + node->count++; + + *slot = item; + return 0; +} + +/** + * radix_tree_lookup - perform lookup operation on a radix tree + * @root: radix tree root + * @index: index key + * + * Lookup them item at the position @index in the radix tree @root. + */ +void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) +{ + unsigned int height, shift; + struct radix_tree_node **slot; + + height = root->height; + if (index > radix_tree_maxindex(height)) + return NULL; + + shift = (height-1) * RADIX_TREE_MAP_SHIFT; + slot = &root->rnode; + + while (height > 0) { + if (*slot == NULL) + return NULL; + + slot = (struct radix_tree_node **) + ((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK)); + shift -= RADIX_TREE_MAP_SHIFT; + height--; + } + + return (void *) *slot; +} + +static /* inline */ unsigned int +__lookup(struct radix_tree_root *root, void **results, unsigned long index, + unsigned int max_items, unsigned long *next_index) +{ + unsigned int nr_found = 0; + unsigned int shift; + unsigned int height = root->height; + struct radix_tree_node *slot; + + shift = (height-1) * RADIX_TREE_MAP_SHIFT; + slot = root->rnode; + + while (height > 0) { + unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; + + for ( ; i < RADIX_TREE_MAP_SIZE; i++) { + if (slot->slots[i] != NULL) + break; + index &= ~((1 << shift) - 1); + index += 1 << shift; + if (index == 0) + goto out; /* 32-bit wraparound */ + } + if (i == RADIX_TREE_MAP_SIZE) + goto out; + height--; + if (height == 0) { /* Bottom level: grab some items */ + unsigned long j = index & RADIX_TREE_MAP_MASK; + + for ( ; j < RADIX_TREE_MAP_SIZE; j++) { + index++; + if (slot->slots[j]) { + results[nr_found++] = slot->slots[j]; + if (nr_found == max_items) + goto out; + } + } + } + shift -= RADIX_TREE_MAP_SHIFT; + slot = slot->slots[i]; + } + out: + *next_index = index; + return nr_found; +} + +/** + * radix_tree_gang_lookup - perform multiple lookup on a radix tree + * @root: radix tree root + * @results: where the results of the lookup are placed + * @first_index: start the lookup from this key + * @max_items: place up to this many items at *results + * + * Performs an index-ascending scan of the tree for present items. Places + * them at *@results and returns the number of items which were placed at + * *@results. + * + * The implementation is naive. + */ +unsigned int +radix_tree_gang_lookup(struct radix_tree_root *root, void **results, + unsigned long first_index, unsigned int max_items) +{ + const unsigned long max_index = radix_tree_maxindex(root->height); + unsigned long cur_index = first_index; + unsigned int ret = 0; + + if (root->rnode == NULL) + goto out; + if (max_index == 0) { /* Bah. Special case */ + if (first_index == 0) { + if (max_items > 0) { + *results = root->rnode; + ret = 1; + } + } + goto out; + } + while (ret < max_items) { + unsigned int nr_found; + unsigned long next_index; /* Index of next search */ + + if (cur_index > max_index) + break; + nr_found = __lookup(root, results + ret, cur_index, + max_items - ret, &next_index); + ret += nr_found; + if (next_index == 0) + break; + cur_index = next_index; + } + out: + return ret; +} + +/** + * radix_tree_delete - delete an item from a radix tree + * @root: radix tree root + * @index: index key + * + * Remove the item at @index from the radix tree rooted at @root. + * + * Returns the address of the deleted item, or NULL if it was not present. + */ +void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) +{ + struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; + unsigned int height, shift; + void *ret = NULL; + + height = root->height; + if (index > radix_tree_maxindex(height)) + goto out; + + shift = (height-1) * RADIX_TREE_MAP_SHIFT; + pathp->node = NULL; + pathp->slot = &root->rnode; + + while (height > 0) { + if (*pathp->slot == NULL) + goto out; + + pathp[1].node = *pathp[0].slot; + pathp[1].slot = (struct radix_tree_node **) + (pathp[1].node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK)); + pathp++; + shift -= RADIX_TREE_MAP_SHIFT; + height--; + } + + ret = *pathp[0].slot; + if (ret == NULL) + goto out; + + *pathp[0].slot = NULL; + while (pathp[0].node && --pathp[0].node->count == 0) { + pathp--; + *pathp[0].slot = NULL; + radix_tree_node_free(pathp[1].node); + } + + if (root->rnode == NULL) + root->height = 0; /* Empty tree, we can reset the height */ + out: + return ret; +} + + +static unsigned long __maxindex(unsigned int height) +{ + unsigned int tmp = height * RADIX_TREE_MAP_SHIFT; + unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1; + + if (tmp >= RADIX_TREE_INDEX_BITS) + index = ~0UL; + return index; +} + +static void radix_tree_init_maxindex(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) + height_to_maxindex[i] = __maxindex(i); +} + +void radix_tree_init(void) +{ + radix_tree_init_maxindex(); +} diff --git a/libbanshee/libcompat/radix-tree.h b/libbanshee/libcompat/radix-tree.h new file mode 100644 index 00000000000..a6b6dc185a3 --- /dev/null +++ b/libbanshee/libcompat/radix-tree.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2001 Momchil Velikov + * Portions Copyright (C) 2001 Christoph Hellwig + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _LINUX_RADIX_TREE_H +#define _LINUX_RADIX_TREE_H + + +struct radix_tree_node; + +struct radix_tree_root { + unsigned int height; + struct radix_tree_node *rnode; +}; + +#define RADIX_TREE_INIT() {0, NULL} + +#define RADIX_TREE(name) \ + struct radix_tree_root name = RADIX_TREE_INIT() + +#define INIT_RADIX_TREE(root) \ +do { \ + (root)->height = 0; \ + (root)->rnode = NULL; \ +} while (0) + +extern int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); +extern void *radix_tree_lookup(struct radix_tree_root *, unsigned long); +extern void *radix_tree_delete(struct radix_tree_root *, unsigned long); +extern unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, + void **results, + unsigned long first_index, + unsigned int max_items); +extern void radix_tree_init(void); + + +#endif /* _LINUX_RADIX_TREE_H */ diff --git a/libbanshee/libcompat/regions.c b/libbanshee/libcompat/regions.c new file mode 100644 index 00000000000..6426fd68d1e --- /dev/null +++ b/libbanshee/libcompat/regions.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 1999-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* Idea: clear on page alloc rather than individual alloc + Turns out not so good (on lcc at least, seems a wash on mudlle): + logically should be bad for small regions (less than a few pages) +*/ +#undef PRECLEAR +#undef REGION_PROFILE +#include "regions.h" +#include +#include +#include +#include "radix-tree.h" +#define RPAGESIZE (1 << RPAGELOG) +#define PAGE_GROUP_SIZE 32 +#define K 4 +#define MAXPAGE (1 << (32 - RPAGELOG)) + +#define PAGENB(x) ((__rcintptr)(x) >> RPAGELOG) + +#define ALIGN(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) +#define PALIGN(x, n) ((void *)ALIGN((__rcintptr)(x), n)) +#ifdef __GNUC__ +#define RALIGNMENT __alignof(double) +#define PTRALIGNMENT __alignof(void *) +#define ALIGNMENT_LONG __alignof(unsigned long) +#else +#define RALIGNMENT 8 +#define PTRALIGNMENT 4 +#define ALIGNMENT_LONG 4 +#endif + +typedef unsigned long __rcintptr; + +struct ablock { + char *base, *allocfrom; +}; + +struct allocator { + struct ablock page; + struct ablock superpage; + struct ablock hyperpage; + struct page *pages; + struct page *bigpages; +}; + +struct Region { + struct allocator normal; + struct Region *parent, *sibling, *children; +}; + +nomem_handler nomem_h; + +/* dummy region for NULL and malloc memory */ +struct Region zeroregion; + +static void clear(void *start, __rcintptr size) +{ + long *clear, *clearend; + + clear = (long *)start; + clearend = (long *)((char *)start + size); + do *clear++ = 0; + while (clear < clearend) ; +} + +#ifdef PRECLEAR +#define preclear clear +#define postclear(s, e) +#else +#define preclear(s, e) +#define postclear clear +#endif + +#include "pages.c" +#include "alloc.c" + +static void nochildren(region r) +{ + if (r->children) + abort(); +} + +static void unlink_region(region r) +{ + region *scan; + + scan = &r->parent->children; + while (*scan != r) + scan = &(*scan)->sibling; + *scan = (*scan)->sibling; +} + +static void link_region(region r, region parent) +{ + r->sibling = parent->children; + r->parent = parent; + parent->children = r; +} + +static int rstart; + +void initregion(region r) +{ + char *first = + (char *)r - rstart - offsetof(struct page, previous); + + /* Start using page with region header as a pointer-containing page */ + r->normal.page.base = first; + r->normal.page.allocfrom = (char *)(r + 1); + + /* Guarantee failure for all other blocks */ + r->normal.superpage.allocfrom = (char *)(K * RPAGESIZE + 1); + r->normal.hyperpage.allocfrom = (char *)(K * K * RPAGESIZE + 1); + + /* Remember that r owns this page. */ + r->normal.pages = (struct page *)first; + set_region(r->normal.pages, 1, r); +} + +region newregion(void) +{ + return newsubregion(&zeroregion); +} + +region newsubregion(region parent) +{ + char *first; + region r; + + first = (char *)alloc_single_page(NULL); + preclear(first + offsetof(struct page, pagecount), RPAGESIZE - offsetof(struct page, pagecount)); + + /* stagger regions across cache lines a bit */ + rstart += 64; + if (rstart > RPAGESIZE / K) rstart = 0; + r = (region)(first + rstart + offsetof(struct page, previous)); + postclear(r, sizeof *r); + initregion(r); + + link_region(r, parent); + + return r; +} + +void *typed_ralloc(region r, size_t size, type_t t) +{ + return rstralloc0(r, size); +} + +void *typed_rarrayextend(region r, void *old, size_t n, size_t size, type_t t) +{ + return rstrextend0(r, old, n * size); +} + +void *typed_rarrayalloc(region r, size_t n, size_t size, type_t t) +{ + return typed_ralloc(r, n * size, t); +} + +char *rstralloc(region r, size_t size) +{ + void *mem, *dummy; + + qalloc(r, &r->normal, &dummy, 0, 1, &mem, size, RALIGNMENT, 0); + + return mem; +} + +char *rstralloc0(region r, size_t size) +{ + char *mem; + + mem = rstralloc(r, size); + clear(mem, size); + + return mem; +} + +char *rstrdup(region r, const char *s) +{ + char *news = rstralloc(r, strlen(s) + 1); + + strcpy(news, s); + + return news; +} + +static char *internal_rstrextend(region r, const char *old, size_t newsize, + int needsclear) +{ + /* For now we don't attempt to extend the old storage area */ + void *newmem, *hdr; + unsigned long *oldhdr, oldsize; + + qalloc(r, &r->normal, &hdr, sizeof(unsigned long), ALIGNMENT_LONG, + &newmem, newsize, RALIGNMENT, 0); + + /* If we don't do this we can't find the header: */ + hdr = (char *)newmem - sizeof(unsigned long); + + *(unsigned long *)hdr = newsize; + + if (old) + { + oldhdr = (unsigned long *)(old - ALIGNMENT_LONG); + oldsize = *oldhdr; + + if (oldsize > newsize) + oldsize = newsize; + else if (needsclear) + clear((char *) newmem + oldsize, newsize - oldsize); + memcpy(newmem, old, oldsize); + } + else if (needsclear) + clear(newmem, newsize); + + return newmem; +} + +char *rstrextend(region r, const char *old, size_t newsize) +{ + return internal_rstrextend(r, old, newsize, 0); +} + +char *rstrextend0(region r, const char *old, size_t newsize) +{ + return internal_rstrextend(r, old, newsize, 1); +} + +void typed_rarraycopy(void *to, void *from, size_t n, size_t size, type_t type) +{ + memcpy(to, from, n * size); +} + +static void delregion(region r) +{ + nochildren(r); + free_all_pages(r, &r->normal); +} + +void deleteregion(region r) +{ + unlink_region(r); + delregion(r); +} + +void deleteregion_ptr(region *r) +{ + region tmp = *r; + + *r = NULL; + deleteregion(tmp); +} + +void deleteregion_array(int n, region *regions) +{ + int i; + + for (i = 0; i < n; i++) + unlink_region(regions[i]); + + for (i = 0; i < n; i++) + { + delregion(regions[i]); + regions[i] = NULL; + } +} + +region regionof(void *ptr) +{ + return radix_tree_lookup (&__rcregionmap, (unsigned long)ptr >> RPAGELOG); +} + +void region_init(void) +{ + static int initialized = 0; + radix_tree_init (); + if ( initialized ) + return; + else + { + rstart = -64; /* Save 64 bytes of memory! (sometimes ;-)) */ + init_pages(); + } + + initialized = 1; +} + +nomem_handler set_nomem_handler(nomem_handler newhandler) +{ + nomem_handler oldh = nomem_h; + + nomem_h = newhandler; + + return oldh; +} + +/* +int region_main(int argc, char **argv, char **envp); + +int main(int argc, char **argv, char **envp) +{ + region_init(); + return region_main(argc, argv, envp); +} +*/ + + +/* Debugging support */ + +static FILE *out; + +static void printref(void *x) +{ +/* if (x >= (void *)__rcregionmap && x < (void *)&__rcregionmap[MAXPAGE]) + return; +*/ +#ifdef RCPAIRS + if (x >= (void *)__rcregions && x < (void *)&__rcregions[MAXREGIONS]) + return; + +#endif + + fprintf(out, "info symbol 0x%p\n", x); +} + +void findrefs(region r, void *from, void *to) +{ + char *f; + + if (!out) + out = fopen("/dev/tty", "w"); + + for (f = PALIGN(from, PTRALIGNMENT); f < (char *)to; f += PTRALIGNMENT) + if (regionof(*(void **)f) == r) + printref(f); + + fflush(out); +} + +#ifdef sparc +extern void _DYNAMIC, _end; + +void findgrefs(region r) +{ + findrefs(r, &_DYNAMIC, &_end); +} +#endif + +void findrrefs(region r, region from) +{ + struct page *p; + + for (p = from->normal.pages; p; p = p->next) + findrefs(r, (char *)&p->previous, (char *)p + RPAGESIZE); + + for (p = r->normal.bigpages; p; p = p->next) + findrefs(r, (char *)&p->previous, (char *)p + p->pagecount * RPAGESIZE); +} diff --git a/libbanshee/libcompat/regions.h b/libbanshee/libcompat/regions.h new file mode 100644 index 00000000000..9f0231ddd82 --- /dev/null +++ b/libbanshee/libcompat/regions.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1999-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef REGIONS_H +#define REGIONS_H + +#define RPAGELOG 13 + +typedef struct Region *region; + +#include + +void region_init(void); /* You MUST call this function before using any + part of this library */ + +region newregion(void); +region newsubregion(region parent); + +typedef int type_t; +#define rctypeof(type) 0 + +/* Low-level alloc with dynamic type info */ +void *typed_ralloc(region r, size_t size, type_t type); +void *typed_rarrayalloc(region r, size_t n, size_t size, type_t type); +void *typed_rarrayextend(region r, void *old, size_t n, size_t size, type_t type); +void typed_rarraycopy(void *to, void *from, size_t n, size_t size, type_t type); + +#define ralloc(r, type) typed_ralloc((r), sizeof(type), rctypeof(type)) +#define rarrayalloc(r, n, type) typed_rarrayalloc((r), (n), sizeof(type), rctypeof(type)) +#define rarrayextend(r, old, n, type) typed_rarrayextend((r), (old), (n), sizeof(type), rctypeof(type)) +#define rarraycopy(to, from, n, type) typed_rarraycopy((to), (from), (n), sizeof(type), rctypeof(type)) + +char *rstralloc(region r, size_t size); +char *rstralloc0(region r, size_t size); +char *rstrdup(region r, const char *s); + +/* rstrextend is used to extend an old string. The string MUST have been + initially allocated by a call to rstrextend with old == NULL (you cannot + initially allocate the string with rstralloc) */ +char *rstrextend(region r, const char *old, size_t newsize); +char *rstrextend0(region r, const char *old, size_t newsize); + +void deleteregion(region r); +void deleteregion_ptr(region *r); +void deleteregion_array(int n, region *regions); +region regionof(void *ptr); + +typedef void (*nomem_handler)(void); +nomem_handler set_nomem_handler(nomem_handler newhandler); + +/* Debugging support */ +void findrefs(region r, void *from, void *to); +void findgrefs(region r); +void findrrefs(region r, region from); + +#ifdef REGION_PROFILE +#include "profile.h" +#endif + +#endif diff --git a/libbanshee/points-to/Makefile.am b/libbanshee/points-to/Makefile.am new file mode 100644 index 00000000000..7f6e8c6cafc --- /dev/null +++ b/libbanshee/points-to/Makefile.am @@ -0,0 +1,4 @@ +AM_CFLAGS = -I$(top_srcdir)/../include -I$(srcdir)/../libcompat -I$(srcdir)/../include -I$(srcdir)/.. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@ +noinst_LIBRARIES = libandersen.a +libandersen_a_SOURCES = andersen_terms.c + diff --git a/libbanshee/points-to/Makefile.in b/libbanshee/points-to/Makefile.in new file mode 100644 index 00000000000..c18b844ee96 --- /dev/null +++ b/libbanshee/points-to/Makefile.in @@ -0,0 +1,364 @@ +# Makefile.in generated by automake 1.7.6 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_libbanshee_warn_cflags = @ac_libbanshee_warn_cflags@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CFLAGS = -I$(top_srcdir)/../include -I$(srcdir)/../libcompat -I$(srcdir)/../include -I$(srcdir)/.. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@ +noinst_LIBRARIES = libandersen.a +libandersen_a_SOURCES = andersen_terms.c +subdir = points-to +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + +libandersen_a_AR = $(AR) cru +libandersen_a_LIBADD = +am_libandersen_a_OBJECTS = andersen_terms.$(OBJEXT) +libandersen_a_OBJECTS = $(am_libandersen_a_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/andersen_terms.Po +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libandersen_a_SOURCES) +DIST_COMMON = Makefile.am Makefile.in +SOURCES = $(libandersen_a_SOURCES) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu points-to/Makefile +Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +AR = ar + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libandersen.a: $(libandersen_a_OBJECTS) $(libandersen_a_DEPENDENCIES) + -rm -f libandersen.a + $(libandersen_a_AR) libandersen.a $(libandersen_a_OBJECTS) $(libandersen_a_LIBADD) + $(RANLIB) libandersen.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/andersen_terms.Po@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) + +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-depend distclean-generic distclean-tags distdir dvi \ + dvi-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libbanshee/points-to/andersen_terms.c b/libbanshee/points-to/andersen_terms.c new file mode 100644 index 00000000000..9268a516ee8 --- /dev/null +++ b/libbanshee/points-to/andersen_terms.c @@ -0,0 +1,1363 @@ +/* + +DO NOT edit this file + +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REF_ 11 +#define REFPROJ0_ 12 +#define REFPROJ1_ 13 +#define REFPROJ2_ 14 +#define LAM_ 15 +#define LAMPROJ0_ 16 +#define LAMPROJ1_ 17 +#define LAMPROJ2_ 18 + +typedef gen_e label_term; +typedef gen_e_list label_term_list; + +typedef struct flowrow_field *argterm_field; +typedef flowrow_map argterm_map; +typedef gen_e argterm; + +typedef gen_e aterm; +typedef gen_e_list aterm_list; + + +stamp label_term_get_stamp(gen_e arg1); +bool label_term_is_var(gen_e arg1); +DECLARE_OPAQUE_LIST(label_term_list,gen_e) +label_term label_term_zero(void); +label_term label_term_one(void); +label_term label_term_fresh(const char *name); +label_term label_term_union(label_term_list exprs) deletes; +label_term label_term_inter(label_term_list exprs) deletes; +label_term label_term_constant(const char *name) deletes; +bool label_term_is_constant(label_term e,const char *name); +label_term_list label_term_tlb(label_term e) deletes; +void label_term_inclusion(label_term e1,label_term e2) deletes; +void label_term_unify(label_term e1,label_term e2) deletes; + +void label_term_print(FILE* arg1,label_term arg2) deletes; +static bool label_term_res_proj(setif_var arg1,gen_e arg2) deletes; +static void label_term_con_match(gen_e arg1,gen_e arg2) deletes; +stamp argterm_get_stamp(gen_e arg1); +bool argterm_is_var(gen_e arg1); +DECLARE_OPAQUE_LIST(argterm_map,flowrow_field) +void argterm_print(FILE *f,argterm row) deletes; +stamp aterm_get_stamp(gen_e arg1); +bool aterm_is_var(gen_e arg1); +DECLARE_OPAQUE_LIST(aterm_list,gen_e) +aterm aterm_zero(void); +aterm aterm_one(void); +aterm aterm_fresh(const char *name); +aterm aterm_union(aterm_list exprs) deletes; +aterm aterm_inter(aterm_list exprs) deletes; +aterm aterm_constant(const char *name) deletes; +bool aterm_is_constant(aterm e,const char *name); +aterm_list aterm_tlb(aterm e) deletes; +void aterm_inclusion(aterm e1,aterm e2) deletes; +void aterm_unify(aterm e1,aterm e2) deletes; + +aterm ref(label_term arg1,aterm arg2,aterm arg3) deletes; +struct ref_decon ref_decon(aterm arg1); +struct ref_ +{ +int type; +stamp st; +label_term f0; +aterm f1; +aterm f2; +}; +struct ref_decon +{ +label_term f0; +aterm f1; +aterm f2; +}; +struct refProj0_ +{ +int type; +stamp st; +label_term f0; +}; +static gen_e ref_pat0_con(gen_e arg1) deletes; +aterm ref_pat0(label_term arg1) deletes; +struct refProj1_ +{ +int type; +stamp st; +aterm f0; +}; +static gen_e ref_pat1_con(gen_e arg1) deletes; +aterm ref_pat1(aterm arg1) deletes; +struct refProj2_ +{ +int type; +stamp st; +aterm f0; +}; +static gen_e ref_pat2_con(gen_e arg1) deletes; +aterm ref_pat2(aterm arg1) deletes; +aterm lam(label_term arg1,argterm arg2,aterm arg3) deletes; +struct lam_decon lam_decon(aterm arg1); +struct lam_ +{ +int type; +stamp st; +label_term f0; +argterm f1; +aterm f2; +}; +struct lam_decon +{ +label_term f0; +argterm f1; +aterm f2; +}; +struct lamProj0_ +{ +int type; +stamp st; +label_term f0; +}; +static gen_e lam_pat0_con(gen_e arg1) deletes; +aterm lam_pat0(label_term arg1) deletes; +struct lamProj1_ +{ +int type; +stamp st; +argterm f0; +}; +static gen_e lam_pat1_con(gen_e arg1) deletes; +aterm lam_pat1(argterm arg1) deletes; +struct lamProj2_ +{ +int type; +stamp st; +aterm f0; +}; +static gen_e lam_pat2_con(gen_e arg1) deletes; +aterm lam_pat2(aterm arg1) deletes; +void aterm_print(FILE* arg1,aterm arg2) deletes; +static bool aterm_res_proj(setif_var arg1,gen_e arg2) deletes; +static void aterm_con_match(gen_e arg1,gen_e arg2) deletes; + +stamp label_term_get_stamp(gen_e arg1) +{ +return setif_get_stamp((gen_e)arg1); +} + +bool label_term_is_var(gen_e arg1) +{ +return setif_is_var((gen_e)arg1); +} + +DEFINE_LIST(label_term_list,gen_e) +label_term label_term_zero(void) +{ + return setif_zero(); +} + +label_term label_term_one(void) +{ + return setif_one(); +} + +label_term label_term_fresh(const char *name) +{ + return setif_fresh(name); +} + +static label_term label_term_fresh_small(const char *name) +{ + return setif_fresh_small(name); +} + +static label_term label_term_fresh_large(const char *name) +{ + return setif_fresh_large(name); +} + +label_term label_term_union(label_term_list exprs) deletes +{ + return setif_union(exprs); +} + +label_term label_term_inter(label_term_list exprs) deletes +{ + return setif_inter(exprs); +} + +label_term label_term_constant(const char *name) deletes +{ + return setif_constant(name); +} + +bool label_term_is_constant(label_term e, const char *name) +{ + if (setif_is_constant(e)) +return (! strcmp(name,setif_get_constant_name(e))); +else return FALSE; +} + +label_term_list label_term_tlb(label_term e) deletes +{ + return setif_tlb(e); +} + +void label_term_inclusion(label_term e1, label_term e2) deletes +{ + setif_inclusion(label_term_con_match,label_term_res_proj,e1,e2); +} + +static void label_term_inclusion_contra(label_term e1, label_term e2) deletes +{ + setif_inclusion(label_term_con_match,label_term_res_proj,e2,e1); +} + +void label_term_unify(label_term e1, label_term e2) deletes +{ + setif_inclusion(label_term_con_match,label_term_res_proj,e1,e2); +setif_inclusion(label_term_con_match,label_term_res_proj,e2,e1); +} + +void label_term_print(FILE* arg1,label_term arg2) deletes +{ +switch(((setif_term)arg2)->type) +{ +case VAR_TYPE: +fprintf(arg1,"%s",sv_get_name((setif_var)arg2)); +break; +case ZERO_TYPE: +fprintf(arg1,"0"); +break; +case ONE_TYPE: +fprintf(arg1,"1"); +break; +case CONSTANT_TYPE: +fprintf(arg1,setif_get_constant_name(arg2)); +break; +case UNION_TYPE: +{ +gen_e_list list = setif_get_union(arg2); +gen_e_list_scanner scan; +gen_e temp; +gen_e_list_scan(list,&scan); +if (gen_e_list_next(&scan,&temp)) +label_term_print(arg1,temp); +while (gen_e_list_next(&scan,&temp)) +{ +fprintf(arg1," || "); +label_term_print(arg1,temp); +} + +} +break; +case INTER_TYPE: +{ +gen_e_list list = setif_get_inter(arg2); +gen_e_list_scanner scan; +gen_e temp; +gen_e_list_scan(list,&scan); +if (gen_e_list_next(&scan,&temp)) +label_term_print(arg1,temp); +while (gen_e_list_next(&scan,&temp)) +{ +fprintf(arg1," && "); +label_term_print(arg1,temp); +} + +} +break; + +default: +return ; +} + +} + +static bool label_term_res_proj(setif_var arg1,gen_e arg2) deletes +{ +switch(((setif_term)arg2)->type) +{ + +default: +return FALSE; +} + +return FALSE; +} + +static void label_term_con_match(gen_e arg1,gen_e arg2) deletes +{ +switch(((setif_term)arg1)->type) +{ + +default: +failure("Inconsistent system of constraints\n"); +} + +return; +} + +stamp argterm_get_stamp(gen_e arg1) +{ +return flowrow_get_stamp((gen_e)arg1); +} + +bool argterm_is_var(gen_e arg1) +{ +return flowrow_is_var((gen_e)arg1); +} + +DEFINE_LIST(argterm_map,flowrow_field) +argterm_field argterm_make_field(const char *label, aterm expr) +{ + flowrow_field result = ralloc(flowrow_region, struct flowrow_field); +result->label = rstrdup(flowrow_region,label); +result->expr = (gen_e) expr; +return result; +} + +argterm argterm_zero(void) +{ + return flowrow_zero(); +} + +argterm argterm_one(void) +{ + return flowrow_one(); +} + +argterm argterm_abs(void) +{ +return flowrow_abs(); +} + +argterm argterm_wild(void) +{ +return flowrow_wild(); +} + +argterm argterm_fresh(const char *name) +{ +return flowrow_fresh(name); +} + +static argterm argterm_fresh_small(const char *name) +{ +return flowrow_fresh_small(name); +} + +static argterm argterm_fresh_large(const char *name) +{ +return flowrow_fresh_large(name); +} + +argterm argterm_row(argterm_map fields,argterm rest) deletes +{ +return flowrow_row(aterm_get_stamp,fields,rest); +} + +aterm argterm_extract_field(const char *field_name, argterm row) +{ +return flowrow_extract_field(field_name,row); +} + +argterm argterm_extract_rest(argterm row) +{ +return flowrow_extract_rest(row); +} + +argterm_map argterm_extract_fields(argterm row) +{ +return flowrow_extract_fields(row); +} + +void argterm_inclusion(argterm row1, argterm row2) deletes +{ +flowrow_inclusion(aterm_fresh,aterm_get_stamp,aterm_inclusion,aterm_zero(), row1,row2); +} + +static void argterm_inclusion_contra(argterm row1, argterm row2) deletes +{ +flowrow_inclusion(aterm_fresh,aterm_get_stamp,aterm_inclusion,aterm_zero(), row2,row1); +} + +void argterm_unify(argterm row1, argterm row2) deletes +{ +argterm_inclusion(row1,row2); +argterm_inclusion(row2,row1); +} + +void argterm_print(FILE *f,argterm row) deletes +{ +flowrow_print(f,aterm_get_stamp,aterm_print,row); +} + +stamp aterm_get_stamp(gen_e arg1) +{ +return setif_get_stamp((gen_e)arg1); +} + +bool aterm_is_var(gen_e arg1) +{ +return setif_is_var((gen_e)arg1); +} + +DEFINE_LIST(aterm_list,gen_e) +aterm aterm_zero(void) +{ + return setif_zero(); +} + +aterm aterm_one(void) +{ + return setif_one(); +} + +aterm aterm_fresh(const char *name) +{ + return setif_fresh(name); +} + +static aterm aterm_fresh_small(const char *name) +{ + return setif_fresh_small(name); +} + +static aterm aterm_fresh_large(const char *name) +{ + return setif_fresh_large(name); +} + +aterm aterm_union(aterm_list exprs) deletes +{ + return setif_union(exprs); +} + +aterm aterm_inter(aterm_list exprs) deletes +{ + return setif_inter(exprs); +} + +aterm aterm_constant(const char *name) deletes +{ + return setif_constant(name); +} + +bool aterm_is_constant(aterm e, const char *name) +{ + if (setif_is_constant(e)) +return (! strcmp(name,setif_get_constant_name(e))); +else return FALSE; +} + +aterm_list aterm_tlb(aterm e) deletes +{ + return setif_tlb(e); +} + +void aterm_inclusion(aterm e1, aterm e2) deletes +{ + setif_inclusion(aterm_con_match,aterm_res_proj,e1,e2); +} + +static void aterm_inclusion_contra(aterm e1, aterm e2) deletes +{ + setif_inclusion(aterm_con_match,aterm_res_proj,e2,e1); +} + +void aterm_unify(aterm e1, aterm e2) deletes +{ + setif_inclusion(aterm_con_match,aterm_res_proj,e1,e2); +setif_inclusion(aterm_con_match,aterm_res_proj,e2,e1); +} + +bool aterm_is_ref(aterm e) +{ + return ((setif_term)e)->type == 11; +} + +aterm ref(label_term arg1,aterm arg2,aterm arg3) deletes +{ +struct ref_ *ret; +stamp s[4]; +s[0] = REF_; +s[1] = label_term_get_stamp((gen_e)arg1); +s[2] = aterm_get_stamp((gen_e)arg2); +s[3] = aterm_get_stamp((gen_e)arg3); +if ((ret = (struct ref_ *)term_hash_find(setif_hash,s,4)) == NULL) +{ +ret = ralloc(setif_region,struct ref_); +ret->type = s[0]; +ret->st = stamp_fresh(); +ret->f0 = arg1; +ret->f1 = arg2; +ret->f2 = arg3; +term_hash_insert(setif_hash,(gen_e)ret,s,4); +} +return (aterm)ret; +} + +struct ref_decon ref_decon(aterm arg1) +{ +if (((setif_term)arg1)->type == REF_) +{ +struct ref_* c = (struct ref_ *)arg1; +return (struct ref_decon){c->f0,c->f1,c->f2}; + +} +else +return (struct ref_decon){NULL,NULL,NULL}; +} + +static gen_e get_ref_proj0_arg(gen_e_list arg1) +{ +gen_e temp; +gen_e_list_scanner scan; +gen_e_list_scan(arg1,&scan); +while (gen_e_list_next(&scan,&temp)) +{ +if (((setif_term)temp)->type == REFPROJ0_) +return (gen_e)((struct refProj0_ * ) temp)->f0; +} +return NULL; +} + +label_term ref_proj0(aterm arg1) deletes + { +label_term c; +if (setif_is_var(arg1)) +{ +setif_var v = (setif_var)arg1; +c = (label_term)sv_get_ub_proj(v,get_ref_proj0_arg); +if (c != NULL) +return c; +else +{ +aterm e; +gen_e lb; +gen_e_list_scanner scan; +c = label_term_fresh(NULL); +e = ref_pat0(c); +sv_add_ub_proj(v,e); +gen_e_list_scan(sv_get_lbs(v),&scan); +while (gen_e_list_next(&scan,&lb)) +{ +setif_inclusion(aterm_con_match,aterm_res_proj,lb,e); +} +return c; +} +} +else if ( ((setif_term)arg1)->type == REF_) +return ((struct ref_ * )arg1)->f0; +else if ( setif_is_zero(arg1)) +return label_term_zero(); +else if ( setif_is_union(arg1)) +{ +c = get_ref_proj0_arg(setif_get_proj_cache(arg1)); +if (c != NULL) +return c; +else +{ +aterm e; +c = label_term_fresh(NULL); +e = ref_pat0(c); +setif_set_proj_cache(arg1,e); +aterm_inclusion(arg1,e); +return c; +} +} +else +{ +aterm e; +c = label_term_fresh(NULL); +e = ref_pat0(c); +aterm_inclusion(arg1,e); +return c; +} +} + +static gen_e ref_pat0_con(gen_e arg1) deletes +{ +return (gen_e)ref_pat0((label_term)arg1); +} + +aterm ref_pat0(label_term arg1) deletes +{ +struct refProj0_* ret; +stamp s[2]; +s[0] = REFPROJ0_; +s[1] = label_term_get_stamp((gen_e)arg1); +if ((ret = (struct refProj0_ *)term_hash_find(setif_hash,s,2)) == NULL) +{ +ret = ralloc(setif_region,struct refProj0_); +ret->type = REFPROJ0_; +ret->st = stamp_fresh(); +ret->f0 = arg1; +term_hash_insert(setif_hash,(gen_e)ret,s,2); +} +return (aterm)ret; +} + +static gen_e get_ref_proj1_arg(gen_e_list arg1) +{ +gen_e temp; +gen_e_list_scanner scan; +gen_e_list_scan(arg1,&scan); +while (gen_e_list_next(&scan,&temp)) +{ +if (((setif_term)temp)->type == REFPROJ1_) +return (gen_e)((struct refProj1_ * ) temp)->f0; +} +return NULL; +} + +aterm ref_proj1(aterm arg1) deletes + { +aterm c; +if (setif_is_var(arg1)) +{ +setif_var v = (setif_var)arg1; +c = (aterm)sv_get_ub_proj(v,get_ref_proj1_arg); +if (c != NULL) +return c; +else +{ +aterm e; +gen_e lb; +gen_e_list_scanner scan; +c = aterm_fresh(NULL); +e = ref_pat1(c); +sv_add_ub_proj(v,e); +gen_e_list_scan(sv_get_lbs(v),&scan); +while (gen_e_list_next(&scan,&lb)) +{ +setif_inclusion(aterm_con_match,aterm_res_proj,lb,e); +} +return c; +} +} +else if ( ((setif_term)arg1)->type == REF_) +return ((struct ref_ * )arg1)->f1; +else if ( setif_is_zero(arg1)) +return aterm_zero(); +else if ( setif_is_union(arg1)) +{ +c = get_ref_proj1_arg(setif_get_proj_cache(arg1)); +if (c != NULL) +return c; +else +{ +aterm e; +c = aterm_fresh(NULL); +e = ref_pat1(c); +setif_set_proj_cache(arg1,e); +aterm_inclusion(arg1,e); +return c; +} +} +else +{ +aterm e; +c = aterm_fresh(NULL); +e = ref_pat1(c); +aterm_inclusion(arg1,e); +return c; +} +} + +static gen_e ref_pat1_con(gen_e arg1) deletes +{ +return (gen_e)ref_pat1((aterm)arg1); +} + +aterm ref_pat1(aterm arg1) deletes +{ +struct refProj1_* ret; +stamp s[2]; +s[0] = REFPROJ1_; +s[1] = aterm_get_stamp((gen_e)arg1); +if ((ret = (struct refProj1_ *)term_hash_find(setif_hash,s,2)) == NULL) +{ +ret = ralloc(setif_region,struct refProj1_); +ret->type = REFPROJ1_; +ret->st = stamp_fresh(); +ret->f0 = arg1; +term_hash_insert(setif_hash,(gen_e)ret,s,2); +} +return (aterm)ret; +} + +static gen_e get_ref_proj2_arg(gen_e_list arg1) +{ +gen_e temp; +gen_e_list_scanner scan; +gen_e_list_scan(arg1,&scan); +while (gen_e_list_next(&scan,&temp)) +{ +if (((setif_term)temp)->type == REFPROJ2_) +return (gen_e)((struct refProj2_ * ) temp)->f0; +} +return NULL; +} + +aterm ref_proj2(aterm arg1) deletes + { +aterm c; +if (setif_is_var(arg1)) +{ +setif_var v = (setif_var)arg1; +c = (aterm)sv_get_ub_proj(v,get_ref_proj2_arg); +if (c != NULL) +return c; +else +{ +aterm e; +gen_e lb; +gen_e_list_scanner scan; +c = aterm_fresh(NULL); +e = ref_pat2(c); +sv_add_ub_proj(v,e); +gen_e_list_scan(sv_get_lbs(v),&scan); +while (gen_e_list_next(&scan,&lb)) +{ +setif_inclusion(aterm_con_match,aterm_res_proj,lb,e); +} +return c; +} +} +else if ( ((setif_term)arg1)->type == REF_) +return ((struct ref_ * )arg1)->f2; +else if ( setif_is_zero(arg1)) +return aterm_zero(); +else if ( setif_is_union(arg1)) +{ +c = get_ref_proj2_arg(setif_get_proj_cache(arg1)); +if (c != NULL) +return c; +else +{ +aterm e; +c = aterm_fresh(NULL); +e = ref_pat2(c); +setif_set_proj_cache(arg1,e); +aterm_inclusion(arg1,e); +return c; +} +} +else +{ +aterm e; +c = aterm_fresh(NULL); +e = ref_pat2(c); +aterm_inclusion(arg1,e); +return c; +} +} + +static gen_e ref_pat2_con(gen_e arg1) deletes +{ +return (gen_e)ref_pat2((aterm)arg1); +} + +aterm ref_pat2(aterm arg1) deletes +{ +struct refProj2_* ret; +stamp s[2]; +s[0] = REFPROJ2_; +s[1] = aterm_get_stamp((gen_e)arg1); +if ((ret = (struct refProj2_ *)term_hash_find(setif_hash,s,2)) == NULL) +{ +ret = ralloc(setif_region,struct refProj2_); +ret->type = REFPROJ2_; +ret->st = stamp_fresh(); +ret->f0 = arg1; +term_hash_insert(setif_hash,(gen_e)ret,s,2); +} +return (aterm)ret; +} + +bool aterm_is_lam(aterm e) +{ + return ((setif_term)e)->type == 15; +} + +aterm lam(label_term arg1,argterm arg2,aterm arg3) deletes +{ +struct lam_ *ret; +stamp s[4]; +s[0] = LAM_; +s[1] = label_term_get_stamp((gen_e)arg1); +s[2] = argterm_get_stamp((gen_e)arg2); +s[3] = aterm_get_stamp((gen_e)arg3); +if ((ret = (struct lam_ *)term_hash_find(setif_hash,s,4)) == NULL) +{ +ret = ralloc(setif_region,struct lam_); +ret->type = s[0]; +ret->st = stamp_fresh(); +ret->f0 = arg1; +ret->f1 = arg2; +ret->f2 = arg3; +term_hash_insert(setif_hash,(gen_e)ret,s,4); +} +return (aterm)ret; +} + +struct lam_decon lam_decon(aterm arg1) +{ +if (((setif_term)arg1)->type == LAM_) +{ +struct lam_* c = (struct lam_ *)arg1; +return (struct lam_decon){c->f0,c->f1,c->f2}; + +} +else +return (struct lam_decon){NULL,NULL,NULL}; +} + +static gen_e get_lam_proj0_arg(gen_e_list arg1) +{ +gen_e temp; +gen_e_list_scanner scan; +gen_e_list_scan(arg1,&scan); +while (gen_e_list_next(&scan,&temp)) +{ +if (((setif_term)temp)->type == LAMPROJ0_) +return (gen_e)((struct lamProj0_ * ) temp)->f0; +} +return NULL; +} + +label_term lam_proj0(aterm arg1) deletes + { +label_term c; +if (setif_is_var(arg1)) +{ +setif_var v = (setif_var)arg1; +c = (label_term)sv_get_ub_proj(v,get_lam_proj0_arg); +if (c != NULL) +return c; +else +{ +aterm e; +gen_e lb; +gen_e_list_scanner scan; +c = label_term_fresh(NULL); +e = lam_pat0(c); +sv_add_ub_proj(v,e); +gen_e_list_scan(sv_get_lbs(v),&scan); +while (gen_e_list_next(&scan,&lb)) +{ +setif_inclusion(aterm_con_match,aterm_res_proj,lb,e); +} +return c; +} +} +else if ( ((setif_term)arg1)->type == LAM_) +return ((struct lam_ * )arg1)->f0; +else if ( setif_is_zero(arg1)) +return label_term_zero(); +else if ( setif_is_union(arg1)) +{ +c = get_lam_proj0_arg(setif_get_proj_cache(arg1)); +if (c != NULL) +return c; +else +{ +aterm e; +c = label_term_fresh(NULL); +e = lam_pat0(c); +setif_set_proj_cache(arg1,e); +aterm_inclusion(arg1,e); +return c; +} +} +else +{ +aterm e; +c = label_term_fresh(NULL); +e = lam_pat0(c); +aterm_inclusion(arg1,e); +return c; +} +} + +static gen_e lam_pat0_con(gen_e arg1) deletes +{ +return (gen_e)lam_pat0((label_term)arg1); +} + +aterm lam_pat0(label_term arg1) deletes +{ +struct lamProj0_* ret; +stamp s[2]; +s[0] = LAMPROJ0_; +s[1] = label_term_get_stamp((gen_e)arg1); +if ((ret = (struct lamProj0_ *)term_hash_find(setif_hash,s,2)) == NULL) +{ +ret = ralloc(setif_region,struct lamProj0_); +ret->type = LAMPROJ0_; +ret->st = stamp_fresh(); +ret->f0 = arg1; +term_hash_insert(setif_hash,(gen_e)ret,s,2); +} +return (aterm)ret; +} + +static gen_e get_lam_proj1_arg(gen_e_list arg1) +{ +gen_e temp; +gen_e_list_scanner scan; +gen_e_list_scan(arg1,&scan); +while (gen_e_list_next(&scan,&temp)) +{ +if (((setif_term)temp)->type == LAMPROJ1_) +return (gen_e)((struct lamProj1_ * ) temp)->f0; +} +return NULL; +} + +argterm lam_proj1(aterm arg1) deletes + { +argterm c; +if (setif_is_var(arg1)) +{ +setif_var v = (setif_var)arg1; +c = (argterm)sv_get_ub_proj(v,get_lam_proj1_arg); +if (c != NULL) +return c; +else +{ +aterm e; +gen_e lb; +gen_e_list_scanner scan; +c = argterm_fresh(NULL); +e = lam_pat1(c); +sv_add_ub_proj(v,e); +gen_e_list_scan(sv_get_lbs(v),&scan); +while (gen_e_list_next(&scan,&lb)) +{ +setif_inclusion(aterm_con_match,aterm_res_proj,lb,e); +} +return c; +} +} +else if ( ((setif_term)arg1)->type == LAM_) +return ((struct lam_ * )arg1)->f1; +else if ( setif_is_zero(arg1)) +return argterm_zero(); +else if ( setif_is_union(arg1)) +{ +c = get_lam_proj1_arg(setif_get_proj_cache(arg1)); +if (c != NULL) +return c; +else +{ +aterm e; +c = argterm_fresh(NULL); +e = lam_pat1(c); +setif_set_proj_cache(arg1,e); +aterm_inclusion(arg1,e); +return c; +} +} +else +{ +aterm e; +c = argterm_fresh(NULL); +e = lam_pat1(c); +aterm_inclusion(arg1,e); +return c; +} +} + +static gen_e lam_pat1_con(gen_e arg1) deletes +{ +return (gen_e)lam_pat1((argterm)arg1); +} + +aterm lam_pat1(argterm arg1) deletes +{ +struct lamProj1_* ret; +stamp s[2]; +s[0] = LAMPROJ1_; +s[1] = argterm_get_stamp((gen_e)arg1); +if ((ret = (struct lamProj1_ *)term_hash_find(setif_hash,s,2)) == NULL) +{ +ret = ralloc(setif_region,struct lamProj1_); +ret->type = LAMPROJ1_; +ret->st = stamp_fresh(); +ret->f0 = arg1; +term_hash_insert(setif_hash,(gen_e)ret,s,2); +} +return (aterm)ret; +} + +static gen_e get_lam_proj2_arg(gen_e_list arg1) +{ +gen_e temp; +gen_e_list_scanner scan; +gen_e_list_scan(arg1,&scan); +while (gen_e_list_next(&scan,&temp)) +{ +if (((setif_term)temp)->type == LAMPROJ2_) +return (gen_e)((struct lamProj2_ * ) temp)->f0; +} +return NULL; +} + +aterm lam_proj2(aterm arg1) deletes + { +aterm c; +if (setif_is_var(arg1)) +{ +setif_var v = (setif_var)arg1; +c = (aterm)sv_get_ub_proj(v,get_lam_proj2_arg); +if (c != NULL) +return c; +else +{ +aterm e; +gen_e lb; +gen_e_list_scanner scan; +c = aterm_fresh(NULL); +e = lam_pat2(c); +sv_add_ub_proj(v,e); +gen_e_list_scan(sv_get_lbs(v),&scan); +while (gen_e_list_next(&scan,&lb)) +{ +setif_inclusion(aterm_con_match,aterm_res_proj,lb,e); +} +return c; +} +} +else if ( ((setif_term)arg1)->type == LAM_) +return ((struct lam_ * )arg1)->f2; +else if ( setif_is_zero(arg1)) +return aterm_zero(); +else if ( setif_is_union(arg1)) +{ +c = get_lam_proj2_arg(setif_get_proj_cache(arg1)); +if (c != NULL) +return c; +else +{ +aterm e; +c = aterm_fresh(NULL); +e = lam_pat2(c); +setif_set_proj_cache(arg1,e); +aterm_inclusion(arg1,e); +return c; +} +} +else +{ +aterm e; +c = aterm_fresh(NULL); +e = lam_pat2(c); +aterm_inclusion(arg1,e); +return c; +} +} + +static gen_e lam_pat2_con(gen_e arg1) deletes +{ +return (gen_e)lam_pat2((aterm)arg1); +} + +aterm lam_pat2(aterm arg1) deletes +{ +struct lamProj2_* ret; +stamp s[2]; +s[0] = LAMPROJ2_; +s[1] = aterm_get_stamp((gen_e)arg1); +if ((ret = (struct lamProj2_ *)term_hash_find(setif_hash,s,2)) == NULL) +{ +ret = ralloc(setif_region,struct lamProj2_); +ret->type = LAMPROJ2_; +ret->st = stamp_fresh(); +ret->f0 = arg1; +term_hash_insert(setif_hash,(gen_e)ret,s,2); +} +return (aterm)ret; +} + +void aterm_print(FILE* arg1,aterm arg2) deletes +{ +switch(((setif_term)arg2)->type) +{ +case VAR_TYPE: +fprintf(arg1,"%s",sv_get_name((setif_var)arg2)); +break; +case ZERO_TYPE: +fprintf(arg1,"0"); +break; +case ONE_TYPE: +fprintf(arg1,"1"); +break; +case CONSTANT_TYPE: +fprintf(arg1,setif_get_constant_name(arg2)); +break; +case UNION_TYPE: +{ +gen_e_list list = setif_get_union(arg2); +gen_e_list_scanner scan; +gen_e temp; +gen_e_list_scan(list,&scan); +if (gen_e_list_next(&scan,&temp)) +aterm_print(arg1,temp); +while (gen_e_list_next(&scan,&temp)) +{ +fprintf(arg1," || "); +aterm_print(arg1,temp); +} + +} +break; +case INTER_TYPE: +{ +gen_e_list list = setif_get_inter(arg2); +gen_e_list_scanner scan; +gen_e temp; +gen_e_list_scan(list,&scan); +if (gen_e_list_next(&scan,&temp)) +aterm_print(arg1,temp); +while (gen_e_list_next(&scan,&temp)) +{ +fprintf(arg1," && "); +aterm_print(arg1,temp); +} + +} +break; +case REF_: +{ +fprintf(arg1,"ref("); +label_term_print(arg1,((struct ref_ *)arg2)->f0); +fprintf(arg1,","); +aterm_print(arg1,((struct ref_ *)arg2)->f1); +fprintf(arg1,","); +aterm_print(arg1,((struct ref_ *)arg2)->f2); +fprintf(arg1,")"); + +} +break; +case LAM_: +{ +fprintf(arg1,"lam("); +label_term_print(arg1,((struct lam_ *)arg2)->f0); +fprintf(arg1,","); +argterm_print(arg1,((struct lam_ *)arg2)->f1); +fprintf(arg1,","); +aterm_print(arg1,((struct lam_ *)arg2)->f2); +fprintf(arg1,")"); + +} +break; +case REFPROJ0_: +{ +fprintf(arg1,"Proj[ref,0,"); +label_term_print(arg1,((struct refProj0_ *)arg2)->f0); +fprintf(arg1,"]"); + +} +break; +case REFPROJ1_: +{ +fprintf(arg1,"Proj[ref,1,"); +aterm_print(arg1,((struct refProj1_ *)arg2)->f0); +fprintf(arg1,"]"); + +} +break; +case REFPROJ2_: +{ +fprintf(arg1,"Proj[ref,2,"); +aterm_print(arg1,((struct refProj2_ *)arg2)->f0); +fprintf(arg1,"]"); + +} +break; +case LAMPROJ0_: +{ +fprintf(arg1,"Proj[lam,0,"); +label_term_print(arg1,((struct lamProj0_ *)arg2)->f0); +fprintf(arg1,"]"); + +} +break; +case LAMPROJ1_: +{ +fprintf(arg1,"Proj[lam,1,"); +argterm_print(arg1,((struct lamProj1_ *)arg2)->f0); +fprintf(arg1,"]"); + +} +break; +case LAMPROJ2_: +{ +fprintf(arg1,"Proj[lam,2,"); +aterm_print(arg1,((struct lamProj2_ *)arg2)->f0); +fprintf(arg1,"]"); + +} +break; + +default: +return ; +} + +} + +static bool aterm_res_proj(setif_var arg1,gen_e arg2) deletes +{ +switch(((setif_term)arg2)->type) +{ +case REFPROJ0_: +return setif_proj_merge(arg1,(gen_e)((struct refProj0_ *)arg2)->f0,get_ref_proj0_arg,ref_pat0_con,(fresh_large_fn_ptr)label_term_fresh_large,(incl_fn_ptr)label_term_inclusion,aterm_inclusion); +break; +case REFPROJ1_: +return setif_proj_merge(arg1,(gen_e)((struct refProj1_ *)arg2)->f0,get_ref_proj1_arg,ref_pat1_con,(fresh_large_fn_ptr)aterm_fresh_large,(incl_fn_ptr)aterm_inclusion_contra,aterm_inclusion); +break; +case REFPROJ2_: +return setif_proj_merge(arg1,(gen_e)((struct refProj2_ *)arg2)->f0,get_ref_proj2_arg,ref_pat2_con,(fresh_large_fn_ptr)aterm_fresh_large,(incl_fn_ptr)aterm_inclusion,aterm_inclusion); +break; +case LAMPROJ0_: +return setif_proj_merge(arg1,(gen_e)((struct lamProj0_ *)arg2)->f0,get_lam_proj0_arg,lam_pat0_con,(fresh_large_fn_ptr)label_term_fresh_large,(incl_fn_ptr)label_term_inclusion,aterm_inclusion); +break; +case LAMPROJ1_: +return setif_proj_merge(arg1,(gen_e)((struct lamProj1_ *)arg2)->f0,get_lam_proj1_arg,lam_pat1_con,(fresh_large_fn_ptr)argterm_fresh_large,(incl_fn_ptr)argterm_inclusion_contra,aterm_inclusion); +break; +case LAMPROJ2_: +return setif_proj_merge(arg1,(gen_e)((struct lamProj2_ *)arg2)->f0,get_lam_proj2_arg,lam_pat2_con,(fresh_large_fn_ptr)aterm_fresh_large,(incl_fn_ptr)aterm_inclusion,aterm_inclusion); +break; + +default: +return FALSE; +} + +return FALSE; +} + +static void aterm_con_match(gen_e arg1,gen_e arg2) deletes +{ +switch(((setif_term)arg1)->type) +{ +case REF_: +switch(((setif_term)arg2)->type) +{ +case REF_: +{ +label_term_inclusion(((struct ref_ *)arg1)->f0,((struct ref_ *)arg2)->f0); +aterm_inclusion_contra(((struct ref_ *)arg1)->f1,((struct ref_ *)arg2)->f1); +aterm_inclusion(((struct ref_ *)arg1)->f2,((struct ref_ *)arg2)->f2); + +} +break; +case REFPROJ0_: +label_term_inclusion(((struct ref_ *)arg1)->f0,((struct refProj0_ *)arg2)->f0); +break; +case REFPROJ1_: +aterm_inclusion_contra(((struct ref_ *)arg1)->f1,((struct refProj1_ *)arg2)->f0); +break; +case REFPROJ2_: +aterm_inclusion(((struct ref_ *)arg1)->f2,((struct refProj2_ *)arg2)->f0); +break; +case LAMPROJ0_: +return ; +break; +case LAMPROJ1_: +return ; +break; +case LAMPROJ2_: +return ; +break; + +default: +failure("Inconsistent system of constraints\n"); +} + +break; +case LAM_: +switch(((setif_term)arg2)->type) +{ +case LAM_: +{ +label_term_inclusion(((struct lam_ *)arg1)->f0,((struct lam_ *)arg2)->f0); +argterm_inclusion_contra(((struct lam_ *)arg1)->f1,((struct lam_ *)arg2)->f1); +aterm_inclusion(((struct lam_ *)arg1)->f2,((struct lam_ *)arg2)->f2); + +} +break; +case LAMPROJ0_: +label_term_inclusion(((struct lam_ *)arg1)->f0,((struct lamProj0_ *)arg2)->f0); +break; +case LAMPROJ1_: +argterm_inclusion_contra(((struct lam_ *)arg1)->f1,((struct lamProj1_ *)arg2)->f0); +break; +case LAMPROJ2_: +aterm_inclusion(((struct lam_ *)arg1)->f2,((struct lamProj2_ *)arg2)->f0); +break; +case REFPROJ0_: +return ; +break; +case REFPROJ1_: +return ; +break; +case REFPROJ2_: +return ; +break; + +default: +failure("Inconsistent system of constraints\n"); +} + +break; + +default: +failure("Inconsistent system of constraints\n"); +} + +return; +} + +void andersen_terms_init(void) +{ +engine_init(); +setif_init(); +setif_init(); +flowrow_init(); +} + +void andersen_terms_reset(void) deletes +{ +setif_reset(); +setif_reset(); +flowrow_reset(); +engine_reset(); +} + +void andersen_terms_stats(FILE * arg1) +{ +engine_stats(arg1); +} + +void andersen_terms_print_graph(FILE * arg1) +{ +print_constraint_graphs(arg1); +} + diff --git a/libbanshee/points-to/andersen_terms.h b/libbanshee/points-to/andersen_terms.h new file mode 100644 index 00000000000..b893c573496 --- /dev/null +++ b/libbanshee/points-to/andersen_terms.h @@ -0,0 +1,100 @@ +/* + +DO NOT edit this file + +*/ +#ifndef ANDERSEN_TERMS_H +#define ANDERSEN_TERMS_H +#include +#include +#include + + +typedef struct label_term_* label_term; +typedef struct argterm_* argterm; +typedef struct argterm_field_* argterm_field; +typedef struct aterm_* aterm; + +extern bool flag_merge_projections; +extern bool flag_eliminate_cycles; +DECLARE_LIST(label_term_list,label_term) +label_term label_term_zero(void); +label_term label_term_one(void); +label_term label_term_fresh(const char *name); +label_term label_term_union(label_term_list exprs) ; +label_term label_term_inter(label_term_list exprs) ; +label_term label_term_constant(const char *name) ; +bool label_term_is_constant(label_term e,const char *name); +void label_term_inclusion(label_term e1,label_term e2) ; +void label_term_unify(label_term e1,label_term e2) ; +label_term_list label_term_tlb(label_term e) ; + +void label_term_print(FILE* arg1,label_term arg2) ; +DECLARE_LIST(argterm_map,argterm_field) +argterm_field argterm_make_field(const char *label,aterm expr); +argterm argterm_zero(void); +argterm argterm_one(void); +argterm argterm_abs(void); +argterm argterm_wild(void); +argterm argterm_fresh(const char *name); +argterm argterm_row(argterm_map fields,argterm rest) ; +aterm argterm_extract_field(const char *field_name,argterm row); +argterm argterm_extract_rest(argterm row); +argterm_map argterm_extract_fields(argterm row); +void argterm_inclusion(argterm row1,argterm row2) ; +void argterm_unify(argterm row1,argterm row2) ; +void argterm_print(FILE *f,argterm row) ; + +DECLARE_LIST(aterm_list,aterm) +aterm aterm_zero(void); +aterm aterm_one(void); +aterm aterm_fresh(const char *name); +aterm aterm_union(aterm_list exprs) ; +aterm aterm_inter(aterm_list exprs) ; +aterm aterm_constant(const char *name) ; +bool aterm_is_constant(aterm e,const char *name); +void aterm_inclusion(aterm e1,aterm e2) ; +void aterm_unify(aterm e1,aterm e2) ; +aterm_list aterm_tlb(aterm e) ; + +bool aterm_is_ref(aterm e); +aterm ref(label_term arg1,aterm arg2,aterm arg3) ; +struct ref_decon ref_decon(aterm arg1); +struct ref_decon +{ +label_term f0; +aterm f1; +aterm f2; +}; +label_term ref_proj0(aterm arg1) ; +aterm ref_pat0(label_term arg1) ; +aterm ref_proj1(aterm arg1) ; +aterm ref_pat1(aterm arg1) ; +aterm ref_proj2(aterm arg1) ; +aterm ref_pat2(aterm arg1) ; +bool aterm_is_lam(aterm e); +aterm lam(label_term arg1,argterm arg2,aterm arg3) ; +struct lam_decon lam_decon(aterm arg1); +struct lam_decon +{ +label_term f0; +argterm f1; +aterm f2; +}; +label_term lam_proj0(aterm arg1) ; +aterm lam_pat0(label_term arg1) ; +argterm lam_proj1(aterm arg1) ; +aterm lam_pat1(argterm arg1) ; +aterm lam_proj2(aterm arg1) ; +aterm lam_pat2(aterm arg1) ; +void aterm_print(FILE* arg1,aterm arg2) ; +/* + +Init/reset engine, print constraint graphs + +*/ +void andersen_terms_init(void); +void andersen_terms_reset(void) ; +void andersen_terms_stats(FILE * arg1); +void andersen_terms_print_graph(FILE * arg1); +#endif diff --git a/libbanshee/points-to/andersen_terms.spec b/libbanshee/points-to/andersen_terms.spec new file mode 100644 index 00000000000..244f643f908 --- /dev/null +++ b/libbanshee/points-to/andersen_terms.spec @@ -0,0 +1,34 @@ +% Copyright (c) 2000-2001 +% The Regents of the University of California. All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions +% are met: +% 1. Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% 2. Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% 3. Neither the name of the University nor the names of its contributors +% may be used to endorse or promote products derived from this software +% without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +% ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +% FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +% OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +% SUCH DAMAGE. + +specification andersen_terms : ANDERSEN_TERMS = + spec + data label_term : set + data aterm : set = ref of +label_term * -aterm * +aterm + | lam of +label_term * -argterm * +aterm + and argterm : row(aterm) + end diff --git a/libbanshee/points-to/andersen_terms_st.spec b/libbanshee/points-to/andersen_terms_st.spec new file mode 100644 index 00000000000..0984e001e5b --- /dev/null +++ b/libbanshee/points-to/andersen_terms_st.spec @@ -0,0 +1,34 @@ +% Copyright (c) 2000-2001 +% The Regents of the University of California. All rights reserved. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions +% are met: +% 1. Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% 2. Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% 3. Neither the name of the University nor the names of its contributors +% may be used to endorse or promote products derived from this software +% without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +% ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +% FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +% OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +% SUCH DAMAGE. + +specification andersen_terms : ANDERSEN_TERMS = + spec + data label_term : setST + data aterm : setST = ref of +label_term * -aterm * +aterm + | lam of +label_term * -argterm * +aterm + and argterm : row(aterm) + end diff --git a/libbanshee/stamp-h.in b/libbanshee/stamp-h.in new file mode 100644 index 00000000000..9788f70238c --- /dev/null +++ b/libbanshee/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/libgfortran/AUTHORS b/libgfortran/AUTHORS new file mode 100644 index 00000000000..4926bede9c8 --- /dev/null +++ b/libgfortran/AUTHORS @@ -0,0 +1,2 @@ +Paul Brook +Jeremy Sanders diff --git a/libgfortran/COPYING b/libgfortran/COPYING new file mode 100644 index 00000000000..15a6fe93154 --- /dev/null +++ b/libgfortran/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + 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. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog new file mode 100644 index 00000000000..1f4dd23e1d3 --- /dev/null +++ b/libgfortran/ChangeLog @@ -0,0 +1,753 @@ +2004-05-06 Rainer Orth + Steven Bosscher + + PR libfortran/15234 + * libgfortran.h: Include if available. + +2004-05-03 Rainer Orth + + * io/unix.c (MAP_FAILED): Define if missing. + (mmap_alloc): Cast MAP_FAILED to char *. + (mmap_open): Likewise. + +2004-04-26 Bud Davis + + * generated/_abs_i8.f90: New file. + * generated/_abs_c4.f90: New file. + * generated/_abs_c8.f90: New file. + * Makefile.am: Add them. + * Makefile.in: Regenerate. +` +2004-04-26 Bud Davis + + PR fortran/14056 + * generated/_abs_i4.f90: New file. + * Makefile.am: Add it. + * Makefile.in: Regenerate. + +2004-04-25 Bud Davis + + PR fortran/14942 + * io/list_read.c(list_formatted_read): finish consuming the + spaces and seperators at eoln to get ready for next item. + +2004-04-23 Bud Davis + + PR fortran/15113 + * io/read.c(read_a): Handle field width > destination and no field width. + +2004-04-22 Bud Davis + + PR fortran/14906 + * io/format.c (format_item): gracefully handle a ')' + when it is the first character encountered in the string. + +2004-04-11 Bud Davis + + PR fortran/14904 + * io/transfer.c (next_record): Update last_record when + more than one record is written to a direct access file + with one write statement. + +2004-04-11 Bud Davis + + PR fortran/14901 + * io/transfer.c (next_record_w) : No '\n' if internal. + * io/unix.c (empty_internal_buffer) : Init to spaces, not '\n'. + +2004-04-11 Bud Davis + + * io.h (ioparm): Interface from FE is 32 bit, irregardless of offset_t. + Will need to change this later to support direct access files > 2gb. + +2004-04-03 Bud Davis + + PR gfortran/14762 + * io/transfer.c (next_record_r) : Skip to next record. + +2004-04-03 Bud Davis + + PR gfortran/14836 + * io/transfer.c (next_record): Update last_record for DIRECT + +2004-04-03 Bud Davis + + PR gfortran/14837 + * io/unix.c (find_file0): Use fd field of struct + +2004-04-03 Bud Davis + + PR 14831 + * io/inquire.c (inquire_via_unit): Changed return string for + BLANK=NULL. Use correct variable for ACTION. + +2004-04-01 Bud Davis + + PR 14746 + * io/read.c (read_f): Allow a decimal without a leading digit. + * io/write.c (output_float): remove a leading '0' to keep from + overflowing the field (F edit descriptor). + +2004-04-01 Bud Davis + + PR gfortran/14565 + * io/open.c (new_unit), + * io/io.h : new_unit is now visible + * io/transfer.c (data_transfer_init): open unit if no OPEN statement. + * io/transfer.c (data_transfer_init): remove compile warnings. + * io/rewind.c (st_rewind): ftruncate if writing. + +2004-03-24 Bud Davis + + * write.c (write_l): Use extract_int for 'L' edit descriptor. + +2004-03-24 Bud Davis + + PR 13919 + * io/io.h (global_t): + * io/list_read.c (next_char,list_formatted_read,ist_formatted_read): + Move eof_jmp to a global structure. + * io/transfer.c(finalize_transfer) : Set up eof_jump for callers. + +2004-03-24 Bud Davis + + * m4/cexp.m4 (csqrt): Actually use the passed value. + * generated/exp_c?.c: Regenerate. + +2004-03-24 Bud Davis + + PR 12921 + * io.h, transfer.c, open.c : recl_in changed from ptr to variable. + * open.c (new_unit): Moved test for positioned direct access error. + (init_units): Corrected calculation of max records. + +2004-02-06 Feng Wang + + * Makefile.am: Add m4/dotprodc.m4. And fix spelling. + * Makefile.in: Regenerate. + * m4/dotprodc.m4: New file. Implement complex dot_product. + * m4/dotprod.m4: Delete the complex implementation. + * generated/dotprod_*: Update. + +2004-02-07 Bud Davis + + * transfer.c (write_constant_string): Do not delete H's in hollerith + formats. + +2004-01-05 Andrew Pinski + + * configure.in: Check for csin in -lmx also. + * configure: Regenerate. + +2004-01-01 Paul Brook + + * io/list_read.c (find_nml_node): Make static. + (match_namelist_name): Ditto. + * io/read.c (convert_precision_real): Make static, fix spelling. + * io/transfer.c (extract_real): Remove unused prototype. + (st_set_nml_var): Make static. + * io/write.c (extract_real): Make static. + +2003-12-12 Huang Chun + + * intrinsics/string_intrinsics.c (string_index): Fix logics thinko. + +2003-12-05 Melvin Hadasht + + * io/transfer.c (data_transfer_init): Give a runtime error for list + formatted reads and writes from/to files opened for unformatted IO. + +2003-11-30 Paul Brook + + * runtime/memory.c (push_context): Remove. + (pop_context): Remove. + * libgfortran.h: Remove prototypes. + +2003-11-27 Paul Brook + + * runtime/memory.c (deallocate): Nullify pointer after freeing. + +2003-11-27 Paul Brook + + * intrinsics/string_intrinsics.c: Use new memory allocation interface. + * libgfortran.h: Ditto. + * m4/in_pack.m4: Ditto. + * runtime/in_pack_generic.c: Ditto. + * runtime/memory.c: Ditto. + +2003-11-26 Richard Henderson + + * m4/exponent.m4, m4/fraction.m4: New. + * m4/nearest.m4, m4/set_exponent.m4: New. + * generated/*: Update. + * Makefile.am: Add them. + (AM_CFLAGS): New. Use -std=gnu99. + * Makefile.in: Regenerate. + +2003-11-08 Paul Brook + + PR fortran/12704 + * m4/maxloc0.m4: Use default value of 1. Handle zero sized arrays. + * m4/maxloc1.m4: Ditto. + * m4/minloc0.m4: Ditto. + * m4/minloc1.m4: Ditto. + * m4/ifunction.m4: Set return value for zero sized arrays. + * m4/iforeach.m4: Ditto. + * m4/all.m4, m4/any.m4, m4/count.m4, m4/maxloc1.m4, m4/minloc1.m4, + m4/mxaval.m4, m4/minval.m4, m4/product.m4, m4/sum.m4: Ditto. + * generated/*: Update. + +2003-10-30 Toon Moene + + PR fortran/12702 + * io/list_read.c (eat_spaces): Treat tab as space. + +2003-10-30 Lars Segerlund + + * intrinsics/random.c: Add reference to paper containing algorithm. + (random_seed): Extra error checking and proper handling of arrays. + (arandom_r4, arandom_r8): Implement. + +2003-10-29 Toon Moene + + PR fortran/12703 + * runtime/memory.c (allocate_size): Allow allocation + of zero-sized objects. + +2003-10-29 Toon Moene + + PR fortran/12701 + * open.c (new_unit): Open without a file name opens + a file with name fort.. + +2003-10-12 Feng Wang + + * intrinsics/cshift0.c: New file. + * m4/cshift1.m4: New file + * generated/cshift*.c: New files. + * Makefile.am: Add them. + * Makefile.in: Regenerate. + +2003-10-12 XiaoQiang Zhang + + * io/list_read.c (read_character): Remove unwanted call to free_saved. + +2003-10-11 Huang Chun + + * intrinsics/string_intrinsics.c (string_trim): New function. + (string_repeat): New function. + +2003-10-11 Paul Brook + + * intrinsics/dprod_r8.f90: New file. + * Makefile.am (gfor_specific_src): Add it. + (gfor_built_specific_src): Rename from gfor_build_specific_c. + Add new intrinsics. + (gfor_specific2_src): Rename from gfor_built_specific2_c. + Add new intrinsics. + * Makefile.in: Regenerate. + * generated/_aint_*.f90: New files. + * generated/_anint*.f90: New files. + * generated/_atan2*.f90: New files. + * generated/_mod*.f90: New files. + +2003-09-20 Kejia Zhao + + * intrinsics/selected_kind.f90: New file. + * Makefile.am: Add it. + * Makefile.in: regenerate. + +2003-09-19 Lars Segerlund + Paul Brook + + * intrinsics/random.c: New file. + * Makefile.am (gfor_hemper_src): Add it. + (gfor_specific_c): Fix typo. + +2003-09-19 Paul Brook + + * All: rename g95->gfc. + +2003-09-18 XiaoQiang Zhang + + * io/write.c (output_float): Fix bug of FMT_E, Add comments. + +2003-09-09 XiaoQiang Zhang + + * io/write.c (write_float): Dectection of positive infinite number, + Not a Number(NaN) and negative infinite number. + (ioutput_float): Bug fix for FMT_E and FMT_D processing to + output a very_very small number ( < 0.1e-100 ). + +2003-09-07 XiaoQiang Zhang + + * libgfortran.h (xtoa, itoa): Parameter modified. + * io/io.h (namelist_info): Declaration to support namelist I/O + (st_parameter): Add namelist related component + (ionml, empty_internal_buffer, st_set_nml_var_int, + st_set_nml_var_float, st_set_nml_var_char, st_set_nml_var_complex, + st_set_nml_var_log): Declaration + (set_integer, set_integer): Parameter changed + * io/format.c (free_nodes): Fix annoying bug of lefting "deallocated" + fnodes + (parse_format_list): Fix bug about FMT_SLASH + * io/list_read.c (push_char): Totally clear old saved_string, zeroize + newly allocated saved_string + (next_char): Add detection of End_Of_Line support + (convert_integer): Now can process 64 bits interger + (read_real): Bug fixed + (init_at_eol, find_nml_node, match_namelist_name): Add new functions + (match_namelist_name): New implemention + * io/lock.c (ionml): New global variable + (library_end): Free memory in ionml + * io/open.c (st_open): Variable initializtion + * io/read.c (max_value): 64 bits interger support + (convert_precsion_real): New procedure to replace "strtod" with more + features + (read_f, read_radix): Input bug fix + * io/transfer.c: (sf_seen_eor): New static variable + (read_sf): Zeroize base buffer; fix bugs: single read statement can + not get input in mutli line when read from stdin + (formatted_transfer): Fix bug of FMT_O, FMT_B, FMT_Z for INTEGER type + request + (data_transfer_init): Clear internal buffer for Internel File I/O. + Internal File now worked. Detect some error condition for namelist. + Some minor bug fix + (next_record_w): Internal file and Namelist I/O support. + (st_set_nml_var, st_set_nml_var_float, st_set_nml_var_char, + st_set_nml_var_complex, st_set_nml_var_log): Implemention. + * io/unit.c (implicit_unit): Deletion + (get_unit): Now cannot open a unit implicitly. + * io/unix.c (mmap_alloc): Fix fatal error in calculating the length of + mapped buffer. + (mem_alloc_r_at): Internal file I/O support added + (empty_internal_buffer): New function + * io/write.c (extract_int): Support 64 bits interger processing + (output_float): Varibale initialization + (write_float): Infinite real number detection. + (write_int): 64 bits integer I/O support + (write_decimal): New function to output decimal number + (otoa, btoa): Better implemention and 64 bits interger support + (namelist_write): New function + * runtime/error.c (itoa, xtoa): Better implemention and 64 bits + interger support + +2003-08-15 Arnaud Desitter + + * libgfortran.h (os_error, runtime_error,internal_error, sys_exit, + get_mem ): Add attribute. + * intrinsics/spread_generic.c (__spread): Fix spelling. + * io/inquire.c (inquire_via_filename): Add const. + * io/io.h (sys_exit): Add attribute. + * io/io.h (move_pos_offset): Add move_pos_offset. + * io/io.h (compare_file_filename, inquire_sequential, inquire_direct, + inquire_formatted, inquire_unformatted, inquire_read, inquire_write, + inquire_readwrite, convert_real, write_a, write_b, write_d, write_e, + write_en, write_es, write_f, write_i, write_l, write_o, write_x, + write_z): Add const. + * io/read.c (convert_real): Add const. + * io/transfer.c (type_name): Add const. + * io/unix.c (unpack_filename, compare_file_filename,inquire_sequential, + inquire_direct, inquire_formatted, inquire_unformatted, inquire_access, + inquire_read, inquire_write, inquire_readwrite): Add const. + * io/write.c (output_float): Remove unused variable. + * io/write.c (write_a, extract_int, extract_real, output_float, + write_float, write_int, write_i, write_b, write_o, write_z, write_d, + write_e, write_f, write_en, write_es, write_logical, write_integer, + write_character, write_real, write_complex): Add const. + * runtime/error.c (rtoa): Remove unused variable. + * runtime/select.c (select_string): Add const. + * runtime/stop.c (stop_string): Add const. + +2003-08-10 Paul Brook + + * Makefile.am (gfor_helper_src): Add intrinsics/abort.c. + (FFLAGS): Add -fno-underscoring. + * Makefile.in: Regenerate. + * intrinsics/abort.c: New file. + +2003-08-10 Erik Schnetter + + * fmain.c (main): Do not call init and cleanup; call set_args instead. + * libgfortran.h (init, cleanup): Remove declarations. + (set_args): Add declaration. + * runtime/main.c (init, cleanup): Make them static, and give them + the constructor and destructor attributes. + (set_args): New function. + +2003-08-10 Paul Brook + + * intrinsics/strinf_intrinsics.c (compare_string): Return value based + on which string is longest. + +2003-08-10 Paul Brook + + * Makefile.am (EXTRA_DIST): Remove old files. + * Makefile.in: Regenerate. + +2003-07-26 Paul Brook + + Rename library to libgfortran. + * libgfortran.h: Change prefix to _libgfortran_. + +2003-07-24 Paul Brook + + * configure.in: Don't pull in system libtool. Use toplevel + auxiliary files. + +2003-07-22 Paul Brook + + Regenerate all configury files. + +2003-07-09 Chun Huang + + * intrinsics/string_intrinsic.c (string_scan): New function. + (string_verify): New function. + +2003-06-25 Paul Brook + + * io/unix.c (mem_alloc_r_at, mem_alloc_w_at): Advance logical_offset. + (mem_seek): Don't bother setting physical_offset. + +2003-06-20 Paul Brook + + * libgfor.h (stop_numeric): Declare. + * runtime/pause.c: New file. + * Makefile.am: Add it. + +2003-06-08 Paul Brook + + * m4/cexp.m4 (cabs): Use correct typed version. + (csqrt): New function. + +2003-06-07 Canqun Yang + + Spotted by Benjamin and Tobias: + * io/list_read.c: Add Separator '\t'. + (parse_real, read_real): Accept real values starting with an optional + sign follows a decimal point. + +2003-06-06 Steven Bosscher + + * Makefile.am: Don't put cmath objects in subdir. + * configure.in: Rename MATHOBJ to MATH_OBJ. + +2003-06-02 Kejia Zhao + + * intrinsics/associated.c: New file. + * Makefile.am: Add it. Regenerate Makefile.in. + * libgfor.h: Define g95_array_void, G95_DESCRIPTOR_DATA, and + G95_DESCRIPTOR_DTYPE. + +2003-06-01 Canqun Yang + + * io/write.c (calcuate_exp): Rewrite it to avoid overflow. + (calculate_G_format): Rewrite it to eliminate an infinte loop and set + the scale_factor to 0 for F editing. + +2003-05-11 Tobias Schlüter + + * libgfor.h: Only include stdint.h if it exists. + +2003-05-07 Paul Brook + + * libgfor.h: Use stdint.h types. + * intrinsics/ishift.c: Ditto. + * runtime/memory.c (malloc_t): Reorder fields for better alignment. + +2003-05-05 Steven Bosscher + + * libgfor.h (offsetof): Define if nobody else does. + * runtime/memory.c (HEADER_SIZE): Use it. + +2003-05-01 Tobias Schlüter + + * configure.in: Require autoconf 2.54. + +2003-04-28 Tobias Schlüter + Paul Brook + + * intrinsics/reshape_generic.c: Copy the whole element, not just the + first byte. + * m4/transpose.m4: New file. + * Makefile.am: Add them. + Regenerate generated files. + +2003-04-18 Steven Bosscher + + * io/format.c (parse_format_list): Allow 'X' without integer + prefix. This is an extension. Interpretation is '1X'. + +2003-04-18 Tobias Schlüter + + * io/format.c (parse_format_list): Allow '0P'. + +2003-04-18 Steven Bosscher + + * Makefile.in: Re-regenerate for automake 1.7.3. + +2003-04-18 Canqun Yang + + Port implementation for CHARACTER SELECT from Andy's tree. + * runtime/select.c: New file + * Makefile.am: Add it. + * Makefile.in: Regenerate. + +2003-04-17 Xiaoqiang Zhang + + * io/transfer.c (formatted_transfer): Modified + * io/unix.c (move_pos_offset): New Function. + * io/format.c (parse_format_list): Modified. + +2003-04-15 Xiaoqiang Zhang + + * io/write.c (write_float,write_real): New implemention of + FMT_G and default float editing. + (calculate_exp,calculate_G_format,output_float): New Function. + (write_float,write_real,write_logical): Modified + * libgfor.h (default_rtoa): Remove Declaration. + * runtime/error.c (default_rtoa): Remove Function. + +2003-04-15 Steven Bosscher + + Spotted by Yang: + * io/write.c (extract_real): Add missing break statement. + +2003-04-13 Steven Bosscher + + * cpu_time.c: Make sure we have a definition of HZ. Don't + rely on CLOCKS_PER_SEC, it is always 1000000, on any system. + +2003-04-13 Steven Bosscher + Paul Brook + + * configure.in: Check for process time headers and GETTIMEOFDAY. + * makefile.am: Add intrinsics/cpu_time.c. + * acinclude.m4: New file. + * intrinsics/cpu_time.c: New file. + * m4/dotprodl.m4: Fix typo. + Regenerate generated files. + +2003-04-11 Xiaoqiang Zhang + + * io/write.c (extract_real): Ouput floating point value. + (write_float): New Function. + (write_e, write_f, write_en, write_es): Modified + * io/transfer.c (formatted_transfer): Modified. + * libgfor.h (default_rtoa): Declaration. + (rtoa): Declaration. + * runtime/error.c (default_rtoa): New Function. + (rtoa): New Function. + +2003-04-05 Paul Brook + + * intrinsics/spread_generic.c: New file. + * Makefile.am: Add it. Regenerate Makefile.in. + +2003-03-29 Paul Brook + + * intrinsics/pack_generic.c: New file. + * intrinsics/unpack_generic.c: New file. + * Makefile.am: Add them. Regenerate Makefile.in. + +2003-03-25 Paul Brook + + * intrinsics/eoshift0.c: New file. + * intrinsics/eoshift2.c: New file. + * m4/eoshift1.m4: New file. + * m4/eoshift3.m4: New file. + * Makefile.am: Add them. + * in_unpack_generic.c: Initialize src. + Regenerate generated files. + +2003-03-14 Paul Brook + + * m4/shape.m4: Work properly with array temporaries. + * m4/in_pack.m4: Skip redundant checks for array temporaries. + * runtime/in_pack_generic.c: Ditto. + +2003-03-12 Paul Brook + + * m4/shape.m4: Work properly with noncontiguous arrays. + +2003-03-08 Paul Brook + + * m4/in_pack.m4: Correctly handle zero sized and assumed size arrays. + * runtime/in_pack_generic.c: Ditto. + +2003-02-08 Paul Brook + + * intrinsics/reshape_generic.c: Use runtime_error to report errors. + * io/close.c (st_close): Return void. + * io/open.c (st_open): Return void. + * libgfor.h (g95_array_char): Declare. + (internal_malloc_size): Ditto. + (internal_pack*, internal_unpack*): Ditto. + * m4/in_pack.m4: Allocate storage if neccessary. Fix logic for packed + arrays. + * m4/in_unpack.m4: Include file fixes. + * m4/reshape.m4: Increment the correct source pointer. + * Makefile.am (maxloc): Fix typo. + * runtime/in_pack_generic.c: Call optimized functions. Allocate + storage if neccessary. Fix logic for packed arrays. + * runtime/in_unpack_generic.c: Call optimized functions. + * runtime/main.c: Use runtime_error to report errors. + * memory.c (internal_malloc_size): Make non-static. + +2003-02-02 Arnaud Desitter + + * reshape_packed.c, lock.c: Add #include . + * libgfor.h, format.c, inquire.c, io.h, transfer.c, unix.c, + environ.c, error.c, memory.c, string.c: Add const. + * error.c (show_locus): Add void. + +2003-02-21 Paul Brook + + * m4/in_pack.m4: Avoid returning const * parameter. + * Makefile.am: Only regenerate files in maintainer mode. + +2003-02-20 Paul Brook + + Add array repacking support functions. + * m4/in_pack.m4, m4/in_unpack.m4: New files. + * runtime/in_pack_generic.c, runtime/in_unpack_generic.c: New files. + * Makefile.am: Build them. Regenerate configury files. + * generated/: New directory for generated files (need to move + everything else there). + +2003-02-07 Tobias Schlueter + + * m4/cexp.m4: Fix typo. + +2003-01-26 Paul Brook + + * intrinsics/: Add missing generated files. + +2003-01-26 Paul Brook + + * Makefile.am: Put -I before the filename. + +2003-01-24 Paul Brook + + * configure.in: Add AM_MAINTAINER_MODE. + +2003-01-23 Paul Brook + + * configure.in, Makefile.am: Modify to work with unmodified autoconf + and auotmake. + Also regenerate other configury files. + +2003-01-21 Paul Brook + + * io/read.c: Don't use stdint.h, it doesn't exist on cygwin. + +2003-01-20 Steven Bosscher + + * io/read.c (read_f): Don't use alloca, but safe get_mem instead. + Don't include "alloca.h". + +2003-01-20 Steven Bosscher + + * intrinsics/string.c: Rename to intrinsics/string_intrinsics.c. + * Makefile.am: Adjust file name. + * Makefile.in: Regenerate. + * gfortypes.h: Kill, include everything in... + * libgfor.h: ...here. Include config.h + * fmain.c, intrinsics/ishftc.c, intrinsic/reshape_generic.c, + intrinsics/reshape_i4.c, intrinsics/reshape_i8.c, + intrinsics/reshape_packed.c, intrinsics/size.c, + m4/reshape.m4, runtime/main.c, runtime/memory.c: Use macro + for prefix for all functions instead of hardcoded. + +2003-01-19 Steven Bosscher + + * io/lock.c (library_end): Propagate library return + code. + +2003-01-19 Steven Bosscher + + Port fixes from Andy's tree: + * io/read.c (read_decimal): Reverse sense of overflow + comparison during integer reads. + * io/format.c (revert): Fix comment. + (next_format): Fix format revision. + * io/unix.c: Fix and simplify mmap version of stream + functions. + +2003-01-11 Paul Brook + + * configure, Makefile.in: Regenerate. + +2003-01-11 Paul Brook + + * runtime/stop.c: Rewrite. + +2003-01-08 Paul Brook + + * configure, Makefile.in: Regenerate. + +2003-01-05 Paul Brook + + * (*.m4) Move to m4/. + * intrinsics/string.c (_gfor_string_index): New Function. + +2002-12-29 Paul Brook + + * intrinsics/reshape.*: New files. + * gcc_config.patch: Update to new GCC configure system. + +2002-10-10 Paul Brook + + * intrinsics/size.c: New file. + * intrinsics/shape.m4: New file. + * Makefile.am: Add above files. + +2002-10-02 Paul Brook + + * fmain.c (main): Move here. + * libgfor.c: From here. + * libgfor.h (gfor_init, gfor_runtime_cleanup): Declare. + * Makefile.am: Build libgforbegin. + * gcc_config.patch: Remove stray -march=athlon. + * dotprodl.m4: Fix use of L8_TO_L4 macro. + * ifunction.m4: Move variable declarations to allow compilation with + gcc < 3.0 + * specific.m4, specific4.m4: Fix typo typecode->type_code. + * README: Document use of patch -p1. + +2002-09-12 Paul Brook + + * math/*: Add complex math library functions. + * intrinsics/specific(2).m4: Generate Specific intrinsic functions. + * Makefile.am: Add details for above. + * configure.in: Use AC_PROG_F95. Test for the presence of csin. + +2002-09-09 Paul Brook + + * libgfor.c (determine_endianness): Use an array rather than a struct. + * intrinsics/dotprod*, matmul*: Implement DOT_PRODUCT and MATMUL. + +2002-09-09 Steven Bosscher + + * libgfor.c: Add fatal signal handler. + Romove superfluous abort() calls. + +2002-09-07 Paul Brook + + * Makefile.am, intrinsics: Major rewrite. + +2002-09-02 Paul Brook + + * Makefile.am: Added -I$(srcdir) to m4 rule. + +2002-08-30 Paul Brook + + * io/*: Integrated libgforio. + * Makefile.am, configure.in: Make compatable with GCC. Build code for + intrinsics in the intrisics directory. + * intrinsics/intrinsics.m4: Move here. Strip directories from the + filename. Add 'and' and 'all' intrinsics. + +2002-08-17 Paul Brook + + * ALL: First release as more than just a single file diff --git a/libgfortran/INSTALL b/libgfortran/INSTALL new file mode 100644 index 00000000000..33391e47413 --- /dev/null +++ b/libgfortran/INSTALL @@ -0,0 +1 @@ +This should be installed as part of GCC. If not, you're on your own. diff --git a/libgfortran/Makefile.am b/libgfortran/Makefile.am new file mode 100644 index 00000000000..5213ca9883c --- /dev/null +++ b/libgfortran/Makefile.am @@ -0,0 +1,464 @@ +## Process this file with automake to produce Makefile.in + +## We like to use C99 routines when available. This makes sure that +## __STDC_VERSION__ is set such that libc includes make them available. +AM_CFLAGS = -std=gnu99 + +lib_LTLIBRARIES = libgfortran.la libgfortranbegin.la + +## This should really go in the compiler lib dir, not the system lib dir. +libgfortranbegin_la_SOURCES = fmain.c +libgfortranbegin_la_LDFLAGS = -static + +INCLUDES = -I$(srcdir)/io + +libgfortranincludedir = $(includedir)/gforio + +gfor_io_src= \ +io/backspace.c \ +io/close.c \ +io/endfile.c \ +io/format.c \ +io/inquire.c \ +io/list_read.c \ +io/lock.c \ +io/open.c \ +io/read.c \ +io/rewind.c \ +io/transfer.c \ +io/unit.c \ +io/unix.c \ +io/write.c + +gfor_io_headers= \ +io/io.h + +gfor_helper_src= \ +intrinsics/associated.c \ +intrinsics/abort.c \ +intrinsics/cpu_time.c \ +intrinsics/cshift0.c \ +intrinsics/eoshift0.c \ +intrinsics/eoshift2.c \ +intrinsics/ishftc.c \ +intrinsics/pack_generic.c \ +intrinsics/size.c \ +intrinsics/spread_generic.c \ +intrinsics/string_intrinsics.c \ +intrinsics/random.c \ +intrinsics/reshape_generic.c \ +intrinsics/reshape_packed.c \ +intrinsics/selected_kind.f90 \ +intrinsics/transpose_generic.c \ +intrinsics/unpack_generic.c \ +runtime/in_pack_generic.c \ +runtime/in_unpack_generic.c + +gfor_src= \ +runtime/environ.c \ +runtime/error.c \ +runtime/main.c \ +runtime/memory.c \ +runtime/pause.c \ +runtime/stop.c \ +runtime/string.c \ +runtime/select.c \ +gfortypes.h \ +libgfortran.h + +i_all_c= \ +generated/all_l4.c \ +generated/all_l8.c + +i_any_c= \ +generated/any_l4.c \ +generated/any_l8.c + +i_count_c= \ +generated/count_4_l4.c \ +generated/count_8_l4.c \ +generated/count_4_l8.c \ +generated/count_8_l8.c + +i_maxloc0_c= \ +generated/maxloc0_4_i4.c \ +generated/maxloc0_8_i4.c \ +generated/maxloc0_4_i8.c \ +generated/maxloc0_8_i8.c \ +generated/maxloc0_4_r4.c \ +generated/maxloc0_8_r4.c \ +generated/maxloc0_4_r8.c \ +generated/maxloc0_8_r8.c + +i_maxloc1_c= \ +generated/maxloc1_4_i4.c \ +generated/maxloc1_8_i4.c \ +generated/maxloc1_4_i8.c \ +generated/maxloc1_8_i8.c \ +generated/maxloc1_4_r4.c \ +generated/maxloc1_8_r4.c \ +generated/maxloc1_4_r8.c \ +generated/maxloc1_8_r8.c + +i_maxval_c= \ +generated/maxval_i4.c \ +generated/maxval_i8.c \ +generated/maxval_r4.c \ +generated/maxval_r8.c + +i_minloc0_c= \ +generated/minloc0_4_i4.c \ +generated/minloc0_8_i4.c \ +generated/minloc0_4_i8.c \ +generated/minloc0_8_i8.c \ +generated/minloc0_4_r4.c \ +generated/minloc0_8_r4.c \ +generated/minloc0_4_r8.c \ +generated/minloc0_8_r8.c + +i_minloc1_c= \ +generated/minloc1_4_i4.c \ +generated/minloc1_8_i4.c \ +generated/minloc1_4_i8.c \ +generated/minloc1_8_i8.c \ +generated/minloc1_4_r4.c \ +generated/minloc1_8_r4.c \ +generated/minloc1_4_r8.c \ +generated/minloc1_8_r8.c + +i_minval_c= \ +generated/minval_i4.c \ +generated/minval_i8.c \ +generated/minval_r4.c \ +generated/minval_r8.c + +i_sum_c= \ +generated/sum_i4.c \ +generated/sum_i8.c \ +generated/sum_r4.c \ +generated/sum_r8.c \ +generated/sum_c4.c \ +generated/sum_c8.c + +i_product_c= \ +generated/product_i4.c \ +generated/product_i8.c \ +generated/product_r4.c \ +generated/product_r8.c \ +generated/product_c4.c \ +generated/product_c8.c + +i_dotprod_c= \ +generated/dotprod_i4.c \ +generated/dotprod_i8.c \ +generated/dotprod_r4.c \ +generated/dotprod_r8.c + +i_dotprodl_c= \ +generated/dotprod_l4.c \ +generated/dotprod_l8.c + +i_dotprodc_c= \ +generated/dotprod_c4.c \ +generated/dotprod_c8.c + +i_matmul_c= \ +generated/matmul_i4.c \ +generated/matmul_i8.c \ +generated/matmul_r4.c \ +generated/matmul_r8.c \ +generated/matmul_c4.c \ +generated/matmul_c8.c + +i_matmull_c= \ +generated/matmul_l4.c \ +generated/matmul_l8.c + +i_transpose_c= \ +generated/transpose_i4.c \ +generated/transpose_i8.c + +i_shape_c= \ +generated/shape_i4.c \ +generated/shape_i8.c + +i_reshape_c= \ +generated/reshape_i4.c \ +generated/reshape_i8.c + +i_eoshift1_c= \ +generated/eoshift1_4.c \ +generated/eoshift1_8.c + +i_eoshift3_c= \ +generated/eoshift3_4.c \ +generated/eoshift3_8.c + +i_cshift1_c= \ +generated/cshift1_4.c \ +generated/cshift1_8.c + +in_pack_c = \ +generated/in_pack_i4.c \ +generated/in_pack_i8.c + +in_unpack_c = \ +generated/in_unpack_i4.c \ +generated/in_unpack_i8.c + +i_exponent_c = \ +generated/exponent_r4.c \ +generated/exponent_r8.c + +i_fraction_c = \ +generated/fraction_r4.c \ +generated/fraction_r8.c + +i_nearest_c = \ +generated/nearest_r4.c \ +generated/nearest_r8.c + +i_set_exponent_c = \ +generated/set_exponent_r4.c \ +generated/set_exponent_r8.c + +m4_files= m4/iparm.m4 m4/ifunction.m4 m4/iforeach.m4 m4/types.m4 m4/all.m4 \ + m4/any.m4 m4/count.m4 m4/maxloc0.m4 m4/maxloc1.m4 m4/maxval.m4 \ + m4/minloc0.m4 m4/minloc1.m4 m4/minval.m4 m4/product.m4 m4/sum.m4 \ + m4/dotprod.m4 m4/dotprodl.m4 m4/dotprodc.m4 m4/matmul.m4 m4/matmull.m4 \ + m4/ctrig.m4 m4/cexp.m4 m4/chyp.m4 m4/mtype.m4 \ + m4/specific.m4 m4/specific2.m4 m4/head.m4 m4/shape.m4 m4/reshape.m4 \ + m4/transpose.m4 m4/eoshift1.m4 m4/eoshift3.m4 m4/exponent.m4 \ + m4/fraction.m4 m4/nearest.m4 m4/set_exponent.m4 + +gfor_built_src= $(i_all_c) $(i_any_c) $(i_count_c) $(i_maxloc0_c) \ + $(i_maxloc1_c) $(i_maxval_c) $(i_minloc0_c) $(i_minloc1_c) $(i_minval_c) \ + $(i_product_c) $(i_sum_c) $(i_dotprod_c) $(i_dotprodl_c) $(i_dotprodc_c) \ + $(i_matmul_c) $(i_matmull_c) $(i_transpose_c) $(i_shape_c) $(i_eoshift1_c) \ + $(i_eoshift3_c) $(i_cshift1_c) $(i_reshape_c) $(in_pack_c) $(in_unpack_c) \ + $(i_exponent_c) $(i_fraction_c) $(i_nearest_c) $(i_set_exponent_c) + +# We only use these if libm doesn't contain complex math functions. + +gfor_math_trig_c= \ +generated/trig_c4.c \ +generated/trig_c8.c +gfor_math_exp_c= \ +generated/exp_c4.c \ +generated/exp_c8.c +gfor_math_hyp_c= \ +generated/hyp_c4.c \ +generated/hyp_c8.c + +gfor_math_trig_obj= \ +trig_c4.lo \ +trig_c8.lo +gfor_math_exp_obj= \ +exp_c4.lo \ +exp_c8.lo +gfor_math_hyp_obj= \ +hyp_c4.lo \ +hyp_c8.lo + +# Machine generated specifics +gfor_built_specific_src= \ +generated/_abs_c4.f90 \ +generated/_abs_c8.f90 \ +generated/_abs_i4.f90 \ +generated/_abs_i8.f90 \ +generated/_abs_r4.f90 \ +generated/_abs_r8.f90 \ +generated/_exp_r4.f90 \ +generated/_exp_r8.f90 \ +generated/_exp_c4.f90 \ +generated/_exp_c8.f90 \ +generated/_log_r4.f90 \ +generated/_log_r8.f90 \ +generated/_log_c4.f90 \ +generated/_log_c8.f90 \ +generated/_log10_r4.f90 \ +generated/_log10_r8.f90 \ +generated/_sqrt_r4.f90 \ +generated/_sqrt_r8.f90 \ +generated/_sqrt_c4.f90 \ +generated/_sqrt_c8.f90 \ +generated/_asin_r4.f90 \ +generated/_asin_r8.f90 \ +generated/_acos_r4.f90 \ +generated/_acos_r8.f90 \ +generated/_atan_r4.f90 \ +generated/_atan_r8.f90 \ +generated/_sin_r4.f90 \ +generated/_sin_r8.f90 \ +generated/_sin_c4.f90 \ +generated/_sin_c8.f90 \ +generated/_cos_r4.f90 \ +generated/_cos_r8.f90 \ +generated/_cos_c4.f90 \ +generated/_cos_c8.f90 \ +generated/_tan_r4.f90 \ +generated/_tan_r8.f90 \ +generated/_sinh_r4.f90 \ +generated/_sinh_r8.f90 \ +generated/_cosh_r4.f90 \ +generated/_cosh_r8.f90 \ +generated/_tanh_r4.f90 \ +generated/_tanh_r8.f90 \ +generated/_conjg_c4.f90 \ +generated/_conjg_c8.f90 \ +generated/_aint_r4.f90 \ +generated/_aint_r8.f90 \ +generated/_anint_r4.f90 \ +generated/_anint_r8.f90 + +gfor_built_specific2_src= \ +generated/_sign_i4.f90 \ +generated/_sign_i8.f90 \ +generated/_sign_r4.f90 \ +generated/_sign_r8.f90 \ +generated/_dim_i4.f90 \ +generated/_dim_i8.f90 \ +generated/_dim_r4.f90 \ +generated/_dim_r8.f90 \ +generated/_atan2_r4.f90 \ +generated/_atan2_r8.f90 \ +generated/_mod_i4.f90 \ +generated/_mod_i8.f90 \ +generated/_mod_r4.f90 \ +generated/_mod_r8.f90 +#specific intrinsics requiring manal code +#gfor_specific_c= \ +intrinsics/_aimag.c \ +intrinsics/_cabs.c \ +foo + +gfor_specific_src= \ +$(gfor_built_specific_src) \ +$(gfor_built_specific2_src) \ +intrinsics/dprod_r8.f90 + +gfor_cmath_src= $(gfor_math_trig_c) $(gfor_math_exp_c) $(gfor_math_hyp_c) +gfor_cmath_obj= $(gfor_math_trig_obj) $(gfor_math_exp_obj) \ + $(gfor_math_hyp_obj) + +BUILT_SOURCES=$(gfor_built_src) $(gfor_cmath_src) $(gfor_built_specific_src) \ + $(gfor_built_specific2_src) +libgfortran_la_SOURCES = $(gfor_src) $(gfor_built_src) $(gfor_io_src) \ + $(gfor_helper_src) $(gfor_io_headers) $(gfor_specific_src) + +EXTRA_libgfortran_la_SOURCES = $(gfor_cmath_src) + +libgfortran_la_LIBADD = @MATH_OBJ@ +libgfortran_la_DEPENDENCIES = @MATH_OBJ@ + +I_M4_DEPS=m4/iparm.m4 m4/types.m4 +I_M4_DEPS0=$(I_M4_DEPS) m4/iforeach.m4 +I_M4_DEPS1=$(I_M4_DEPS) m4/ifunction.m4 + +## A 'normal' build shouldn't need to regenerate these +## so we only include them in maintainer mode + +if MAINTAINER_MODE +$(i_all_c): m4/all.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 all.m4 > $@ + +$(i_any_c): m4/any.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 any.m4> $@ + +$(i_count_c): m4/count.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 count.m4> $@ + +$(i_maxloc0_c): m4/maxloc0.m4 $(I_M4_DEPS0) + m4 -Dfile=$@ -I$(srcdir)/m4 maxloc0.m4 > $@ + +$(i_maxloc1_c): m4/maxloc1.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 maxloc1.m4 > $@ + +$(i_maxval_c): m4/maxval.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 maxval.m4 > $@ + +$(i_minloc0_c): m4/minloc0.m4 $(I_M4_DEPS0) + m4 -Dfile=$@ -I$(srcdir)/m4 minloc0.m4 > $@ + +$(i_minloc1_c): m4/minloc1.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 minloc1.m4 > $@ + +$(i_minval_c): m4/minval.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 minval.m4 > $@ + +$(i_product_c): m4/product.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 product.m4 > $@ + +$(i_sum_c): m4/sum.m4 $(I_M4_DEPS1) + m4 -Dfile=$@ -I$(srcdir)/m4 sum.m4 > $@ + +$(i_dotprod_c): m4/dotprod.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 dotprod.m4 > $@ + +$(i_dotprodl_c): m4/dotprodl.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 dotprodl.m4 > $@ + +$(i_dotprodc_c): m4/dotprodc.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 dotprodc.m4 > $@ + +$(i_matmul_c): m4/matmul.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 matmul.m4 > $@ + +$(i_matmull_c): m4/matmull.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 matmull.m4 > $@ + +$(i_transpose_c): m4/transpose.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 transpose.m4 > $@ + +$(i_shape_c): m4/shape.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 shape.m4 > $@ + +$(i_reshape_c): m4/reshape.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 reshape.m4 > $@ + +$(i_eoshift1_c): m4/eoshift1.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 eoshift1.m4 > $@ + +$(i_eoshift3_c): m4/eoshift3.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 eoshift3.m4 > $@ + +$(i_cshift1_c): m4/cshift1.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 cshift1.m4 > $@ + +$(in_pack_c): m4/in_pack.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 in_pack.m4 > $@ + +$(in_unpack_c): m4/in_unpack.m4 $(I_M4_DEPS) + m4 -Dfile=$@ -I$(srcdir)/m4 in_unpack.m4 > $@ + +$(i_exponent_c): m4/exponent.m4 m4/mtype.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 exponent.m4 > $@ + +$(i_fraction_c): m4/fraction.m4 m4/mtype.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 fraction.m4 > $@ + +$(i_nearest_c): m4/nearest.m4 m4/mtype.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 nearest.m4 > $@ + +$(i_set_exponent_c): m4/set_exponent.m4 m4/mtype.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 set_exponent.m4 > $@ + +$(gfor_math_trig_c): m4/ctrig.m4 m4/mtype.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 ctrig.m4 > $@ + +$(gfor_math_exp_c): m4/cexp.m4 m4/mtype.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 cexp.m4 > $@ + +$(gfor_math_hyp_c): m4/chyp.m4 m4/mtype.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 chyp.m4 > $@ + +$(gfor_built_specific_src): m4/specific.m4 m4/head.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 specific.m4 > $@ + +$(gfor_built_specific2_src): m4/specific2.m4 m4/head.m4 + m4 -Dfile=$@ -I$(srcdir)/m4 specific2.m4 > $@ +## end of maintainer mode only rules +endif + +EXTRA_DIST = $(m4_files) + diff --git a/libgfortran/Makefile.in b/libgfortran/Makefile.in new file mode 100644 index 00000000000..9803454c4d8 --- /dev/null +++ b/libgfortran/Makefile.in @@ -0,0 +1,5479 @@ +# Makefile.in generated by automake 1.8.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libgfortran_la_SOURCES) $(EXTRA_libgfortran_la_SOURCES) $(libgfortranbegin_la_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_triplet = @host@ +DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \ + $(srcdir)/../config.sub $(srcdir)/../depcomp \ + $(srcdir)/../install-sh $(srcdir)/../ltmain.sh \ + $(srcdir)/../missing $(srcdir)/../mkinstalldirs \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in $(top_srcdir)/configure AUTHORS COPYING \ + ChangeLog INSTALL NEWS +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +am__installdirs = $(DESTDIR)$(libdir) +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +am__objects_1 = environ.lo error.lo main.lo memory.lo pause.lo stop.lo \ + string.lo select.lo +am__objects_2 = all_l4.lo all_l8.lo +am__objects_3 = any_l4.lo any_l8.lo +am__objects_4 = count_4_l4.lo count_8_l4.lo count_4_l8.lo \ + count_8_l8.lo +am__objects_5 = maxloc0_4_i4.lo maxloc0_8_i4.lo maxloc0_4_i8.lo \ + maxloc0_8_i8.lo maxloc0_4_r4.lo maxloc0_8_r4.lo \ + maxloc0_4_r8.lo maxloc0_8_r8.lo +am__objects_6 = maxloc1_4_i4.lo maxloc1_8_i4.lo maxloc1_4_i8.lo \ + maxloc1_8_i8.lo maxloc1_4_r4.lo maxloc1_8_r4.lo \ + maxloc1_4_r8.lo maxloc1_8_r8.lo +am__objects_7 = maxval_i4.lo maxval_i8.lo maxval_r4.lo maxval_r8.lo +am__objects_8 = minloc0_4_i4.lo minloc0_8_i4.lo minloc0_4_i8.lo \ + minloc0_8_i8.lo minloc0_4_r4.lo minloc0_8_r4.lo \ + minloc0_4_r8.lo minloc0_8_r8.lo +am__objects_9 = minloc1_4_i4.lo minloc1_8_i4.lo minloc1_4_i8.lo \ + minloc1_8_i8.lo minloc1_4_r4.lo minloc1_8_r4.lo \ + minloc1_4_r8.lo minloc1_8_r8.lo +am__objects_10 = minval_i4.lo minval_i8.lo minval_r4.lo minval_r8.lo +am__objects_11 = product_i4.lo product_i8.lo product_r4.lo \ + product_r8.lo product_c4.lo product_c8.lo +am__objects_12 = sum_i4.lo sum_i8.lo sum_r4.lo sum_r8.lo sum_c4.lo \ + sum_c8.lo +am__objects_13 = dotprod_i4.lo dotprod_i8.lo dotprod_r4.lo \ + dotprod_r8.lo +am__objects_14 = dotprod_l4.lo dotprod_l8.lo +am__objects_15 = dotprod_c4.lo dotprod_c8.lo +am__objects_16 = matmul_i4.lo matmul_i8.lo matmul_r4.lo matmul_r8.lo \ + matmul_c4.lo matmul_c8.lo +am__objects_17 = matmul_l4.lo matmul_l8.lo +am__objects_18 = transpose_i4.lo transpose_i8.lo +am__objects_19 = shape_i4.lo shape_i8.lo +am__objects_20 = eoshift1_4.lo eoshift1_8.lo +am__objects_21 = eoshift3_4.lo eoshift3_8.lo +am__objects_22 = cshift1_4.lo cshift1_8.lo +am__objects_23 = reshape_i4.lo reshape_i8.lo +am__objects_24 = in_pack_i4.lo in_pack_i8.lo +am__objects_25 = in_unpack_i4.lo in_unpack_i8.lo +am__objects_26 = exponent_r4.lo exponent_r8.lo +am__objects_27 = fraction_r4.lo fraction_r8.lo +am__objects_28 = nearest_r4.lo nearest_r8.lo +am__objects_29 = set_exponent_r4.lo set_exponent_r8.lo +am__objects_30 = $(am__objects_2) $(am__objects_3) $(am__objects_4) \ + $(am__objects_5) $(am__objects_6) $(am__objects_7) \ + $(am__objects_8) $(am__objects_9) $(am__objects_10) \ + $(am__objects_11) $(am__objects_12) $(am__objects_13) \ + $(am__objects_14) $(am__objects_15) $(am__objects_16) \ + $(am__objects_17) $(am__objects_18) $(am__objects_19) \ + $(am__objects_20) $(am__objects_21) $(am__objects_22) \ + $(am__objects_23) $(am__objects_24) $(am__objects_25) \ + $(am__objects_26) $(am__objects_27) $(am__objects_28) \ + $(am__objects_29) +am__objects_31 = backspace.lo close.lo endfile.lo format.lo inquire.lo \ + list_read.lo lock.lo open.lo read.lo rewind.lo transfer.lo \ + unit.lo unix.lo write.lo +am__objects_32 = associated.lo abort.lo cpu_time.lo cshift0.lo \ + eoshift0.lo eoshift2.lo ishftc.lo pack_generic.lo size.lo \ + spread_generic.lo string_intrinsics.lo random.lo \ + reshape_generic.lo reshape_packed.lo selected_kind.lo \ + transpose_generic.lo unpack_generic.lo in_pack_generic.lo \ + in_unpack_generic.lo +am__objects_33 = +am__objects_34 = _abs_c4.lo _abs_c8.lo _abs_i4.lo _abs_i8.lo \ + _abs_r4.lo _abs_r8.lo _exp_r4.lo _exp_r8.lo _exp_c4.lo \ + _exp_c8.lo _log_r4.lo _log_r8.lo _log_c4.lo _log_c8.lo \ + _log10_r4.lo _log10_r8.lo _sqrt_r4.lo _sqrt_r8.lo _sqrt_c4.lo \ + _sqrt_c8.lo _asin_r4.lo _asin_r8.lo _acos_r4.lo _acos_r8.lo \ + _atan_r4.lo _atan_r8.lo _sin_r4.lo _sin_r8.lo _sin_c4.lo \ + _sin_c8.lo _cos_r4.lo _cos_r8.lo _cos_c4.lo _cos_c8.lo \ + _tan_r4.lo _tan_r8.lo _sinh_r4.lo _sinh_r8.lo _cosh_r4.lo \ + _cosh_r8.lo _tanh_r4.lo _tanh_r8.lo _conjg_c4.lo _conjg_c8.lo \ + _aint_r4.lo _aint_r8.lo _anint_r4.lo _anint_r8.lo +am__objects_35 = _sign_i4.lo _sign_i8.lo _sign_r4.lo _sign_r8.lo \ + _dim_i4.lo _dim_i8.lo _dim_r4.lo _dim_r8.lo _atan2_r4.lo \ + _atan2_r8.lo _mod_i4.lo _mod_i8.lo _mod_r4.lo _mod_r8.lo +am__objects_36 = $(am__objects_34) $(am__objects_35) dprod_r8.lo +am_libgfortran_la_OBJECTS = $(am__objects_1) $(am__objects_30) \ + $(am__objects_31) $(am__objects_32) $(am__objects_33) \ + $(am__objects_36) +libgfortran_la_OBJECTS = $(am_libgfortran_la_OBJECTS) +libgfortranbegin_la_LIBADD = +am_libgfortranbegin_la_OBJECTS = fmain.lo +libgfortranbegin_la_OBJECTS = $(am_libgfortranbegin_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I. +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/abort.Plo ./$(DEPDIR)/all_l4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/all_l8.Plo ./$(DEPDIR)/any_l4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/any_l8.Plo ./$(DEPDIR)/associated.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/backspace.Plo ./$(DEPDIR)/close.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/count_4_l4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/count_4_l8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/count_8_l4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/count_8_l8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/cpu_time.Plo ./$(DEPDIR)/cshift0.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/cshift1_4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/cshift1_8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_c4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_c8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_l4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_l8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/dotprod_r8.Plo ./$(DEPDIR)/endfile.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/environ.Plo ./$(DEPDIR)/eoshift0.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/eoshift1_4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/eoshift1_8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/eoshift2.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/eoshift3_4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/eoshift3_8.Plo ./$(DEPDIR)/error.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exp_c4.Plo ./$(DEPDIR)/exp_c8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exponent_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/exponent_r8.Plo ./$(DEPDIR)/fmain.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/format.Plo ./$(DEPDIR)/fraction_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/fraction_r8.Plo ./$(DEPDIR)/hyp_c4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/hyp_c8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/in_pack_generic.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/in_pack_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/in_pack_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/in_unpack_generic.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/in_unpack_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/in_unpack_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/inquire.Plo ./$(DEPDIR)/ishftc.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/list_read.Plo ./$(DEPDIR)/lock.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/main.Plo ./$(DEPDIR)/matmul_c4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matmul_c8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matmul_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matmul_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matmul_l4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matmul_l8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matmul_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matmul_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_4_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_4_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_4_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_4_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_8_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_8_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_8_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc0_8_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_4_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_4_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_4_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_4_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_8_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_8_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_8_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxloc1_8_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxval_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxval_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxval_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/maxval_r8.Plo ./$(DEPDIR)/memory.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_4_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_4_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_4_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_4_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_8_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_8_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_8_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc0_8_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_4_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_4_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_4_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_4_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_8_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_8_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_8_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minloc1_8_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minval_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minval_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minval_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/minval_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/nearest_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/nearest_r8.Plo ./$(DEPDIR)/open.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/pack_generic.Plo ./$(DEPDIR)/pause.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/product_c4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/product_c8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/product_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/product_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/product_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/product_r8.Plo ./$(DEPDIR)/random.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/read.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/reshape_generic.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/reshape_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/reshape_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/reshape_packed.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/rewind.Plo ./$(DEPDIR)/select.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/set_exponent_r4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/set_exponent_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/shape_i4.Plo ./$(DEPDIR)/shape_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/size.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/spread_generic.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/stop.Plo ./$(DEPDIR)/string.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/string_intrinsics.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/sum_c4.Plo ./$(DEPDIR)/sum_c8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/sum_i4.Plo ./$(DEPDIR)/sum_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/sum_r4.Plo ./$(DEPDIR)/sum_r8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/transfer.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/transpose_generic.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/transpose_i4.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/transpose_i8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/trig_c4.Plo ./$(DEPDIR)/trig_c8.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/unit.Plo ./$(DEPDIR)/unix.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/unpack_generic.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/write.Plo +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +F77COMPILE = $(F77) $(AM_FFLAGS) $(FFLAGS) +LTF77COMPILE = $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) +F77LD = $(F77) +F77LINK = $(LIBTOOL) --mode=link $(F77LD) $(AM_FFLAGS) $(FFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libgfortran_la_SOURCES) $(EXTRA_libgfortran_la_SOURCES) \ + $(libgfortranbegin_la_SOURCES) +DIST_SOURCES = $(libgfortran_la_SOURCES) \ + $(EXTRA_libgfortran_la_SOURCES) $(libgfortranbegin_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ +MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ +MAKEINFO = @MAKEINFO@ +MATH_OBJ = @MATH_OBJ@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +enable_shared = @enable_shared@ +enable_static = @enable_static@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +AM_CFLAGS = -std=gnu99 +lib_LTLIBRARIES = libgfortran.la libgfortranbegin.la +libgfortranbegin_la_SOURCES = fmain.c +libgfortranbegin_la_LDFLAGS = -static +INCLUDES = -I$(srcdir)/io +libgfortranincludedir = $(includedir)/gforio +gfor_io_src = \ +io/backspace.c \ +io/close.c \ +io/endfile.c \ +io/format.c \ +io/inquire.c \ +io/list_read.c \ +io/lock.c \ +io/open.c \ +io/read.c \ +io/rewind.c \ +io/transfer.c \ +io/unit.c \ +io/unix.c \ +io/write.c + +gfor_io_headers = \ +io/io.h + +gfor_helper_src = \ +intrinsics/associated.c \ +intrinsics/abort.c \ +intrinsics/cpu_time.c \ +intrinsics/cshift0.c \ +intrinsics/eoshift0.c \ +intrinsics/eoshift2.c \ +intrinsics/ishftc.c \ +intrinsics/pack_generic.c \ +intrinsics/size.c \ +intrinsics/spread_generic.c \ +intrinsics/string_intrinsics.c \ +intrinsics/random.c \ +intrinsics/reshape_generic.c \ +intrinsics/reshape_packed.c \ +intrinsics/selected_kind.f90 \ +intrinsics/transpose_generic.c \ +intrinsics/unpack_generic.c \ +runtime/in_pack_generic.c \ +runtime/in_unpack_generic.c + +gfor_src = \ +runtime/environ.c \ +runtime/error.c \ +runtime/main.c \ +runtime/memory.c \ +runtime/pause.c \ +runtime/stop.c \ +runtime/string.c \ +runtime/select.c \ +gfortypes.h \ +libgfortran.h + +i_all_c = \ +generated/all_l4.c \ +generated/all_l8.c + +i_any_c = \ +generated/any_l4.c \ +generated/any_l8.c + +i_count_c = \ +generated/count_4_l4.c \ +generated/count_8_l4.c \ +generated/count_4_l8.c \ +generated/count_8_l8.c + +i_maxloc0_c = \ +generated/maxloc0_4_i4.c \ +generated/maxloc0_8_i4.c \ +generated/maxloc0_4_i8.c \ +generated/maxloc0_8_i8.c \ +generated/maxloc0_4_r4.c \ +generated/maxloc0_8_r4.c \ +generated/maxloc0_4_r8.c \ +generated/maxloc0_8_r8.c + +i_maxloc1_c = \ +generated/maxloc1_4_i4.c \ +generated/maxloc1_8_i4.c \ +generated/maxloc1_4_i8.c \ +generated/maxloc1_8_i8.c \ +generated/maxloc1_4_r4.c \ +generated/maxloc1_8_r4.c \ +generated/maxloc1_4_r8.c \ +generated/maxloc1_8_r8.c + +i_maxval_c = \ +generated/maxval_i4.c \ +generated/maxval_i8.c \ +generated/maxval_r4.c \ +generated/maxval_r8.c + +i_minloc0_c = \ +generated/minloc0_4_i4.c \ +generated/minloc0_8_i4.c \ +generated/minloc0_4_i8.c \ +generated/minloc0_8_i8.c \ +generated/minloc0_4_r4.c \ +generated/minloc0_8_r4.c \ +generated/minloc0_4_r8.c \ +generated/minloc0_8_r8.c + +i_minloc1_c = \ +generated/minloc1_4_i4.c \ +generated/minloc1_8_i4.c \ +generated/minloc1_4_i8.c \ +generated/minloc1_8_i8.c \ +generated/minloc1_4_r4.c \ +generated/minloc1_8_r4.c \ +generated/minloc1_4_r8.c \ +generated/minloc1_8_r8.c + +i_minval_c = \ +generated/minval_i4.c \ +generated/minval_i8.c \ +generated/minval_r4.c \ +generated/minval_r8.c + +i_sum_c = \ +generated/sum_i4.c \ +generated/sum_i8.c \ +generated/sum_r4.c \ +generated/sum_r8.c \ +generated/sum_c4.c \ +generated/sum_c8.c + +i_product_c = \ +generated/product_i4.c \ +generated/product_i8.c \ +generated/product_r4.c \ +generated/product_r8.c \ +generated/product_c4.c \ +generated/product_c8.c + +i_dotprod_c = \ +generated/dotprod_i4.c \ +generated/dotprod_i8.c \ +generated/dotprod_r4.c \ +generated/dotprod_r8.c + +i_dotprodl_c = \ +generated/dotprod_l4.c \ +generated/dotprod_l8.c + +i_dotprodc_c = \ +generated/dotprod_c4.c \ +generated/dotprod_c8.c + +i_matmul_c = \ +generated/matmul_i4.c \ +generated/matmul_i8.c \ +generated/matmul_r4.c \ +generated/matmul_r8.c \ +generated/matmul_c4.c \ +generated/matmul_c8.c + +i_matmull_c = \ +generated/matmul_l4.c \ +generated/matmul_l8.c + +i_transpose_c = \ +generated/transpose_i4.c \ +generated/transpose_i8.c + +i_shape_c = \ +generated/shape_i4.c \ +generated/shape_i8.c + +i_reshape_c = \ +generated/reshape_i4.c \ +generated/reshape_i8.c + +i_eoshift1_c = \ +generated/eoshift1_4.c \ +generated/eoshift1_8.c + +i_eoshift3_c = \ +generated/eoshift3_4.c \ +generated/eoshift3_8.c + +i_cshift1_c = \ +generated/cshift1_4.c \ +generated/cshift1_8.c + +in_pack_c = \ +generated/in_pack_i4.c \ +generated/in_pack_i8.c + +in_unpack_c = \ +generated/in_unpack_i4.c \ +generated/in_unpack_i8.c + +i_exponent_c = \ +generated/exponent_r4.c \ +generated/exponent_r8.c + +i_fraction_c = \ +generated/fraction_r4.c \ +generated/fraction_r8.c + +i_nearest_c = \ +generated/nearest_r4.c \ +generated/nearest_r8.c + +i_set_exponent_c = \ +generated/set_exponent_r4.c \ +generated/set_exponent_r8.c + +m4_files = m4/iparm.m4 m4/ifunction.m4 m4/iforeach.m4 m4/types.m4 m4/all.m4 \ + m4/any.m4 m4/count.m4 m4/maxloc0.m4 m4/maxloc1.m4 m4/maxval.m4 \ + m4/minloc0.m4 m4/minloc1.m4 m4/minval.m4 m4/product.m4 m4/sum.m4 \ + m4/dotprod.m4 m4/dotprodl.m4 m4/dotprodc.m4 m4/matmul.m4 m4/matmull.m4 \ + m4/ctrig.m4 m4/cexp.m4 m4/chyp.m4 m4/mtype.m4 \ + m4/specific.m4 m4/specific2.m4 m4/head.m4 m4/shape.m4 m4/reshape.m4 \ + m4/transpose.m4 m4/eoshift1.m4 m4/eoshift3.m4 m4/exponent.m4 \ + m4/fraction.m4 m4/nearest.m4 m4/set_exponent.m4 + +gfor_built_src = $(i_all_c) $(i_any_c) $(i_count_c) $(i_maxloc0_c) \ + $(i_maxloc1_c) $(i_maxval_c) $(i_minloc0_c) $(i_minloc1_c) $(i_minval_c) \ + $(i_product_c) $(i_sum_c) $(i_dotprod_c) $(i_dotprodl_c) $(i_dotprodc_c) \ + $(i_matmul_c) $(i_matmull_c) $(i_transpose_c) $(i_shape_c) $(i_eoshift1_c) \ + $(i_eoshift3_c) $(i_cshift1_c) $(i_reshape_c) $(in_pack_c) $(in_unpack_c) \ + $(i_exponent_c) $(i_fraction_c) $(i_nearest_c) $(i_set_exponent_c) + + +# We only use these if libm doesn't contain complex math functions. +gfor_math_trig_c = \ +generated/trig_c4.c \ +generated/trig_c8.c + +gfor_math_exp_c = \ +generated/exp_c4.c \ +generated/exp_c8.c + +gfor_math_hyp_c = \ +generated/hyp_c4.c \ +generated/hyp_c8.c + +gfor_math_trig_obj = \ +trig_c4.lo \ +trig_c8.lo + +gfor_math_exp_obj = \ +exp_c4.lo \ +exp_c8.lo + +gfor_math_hyp_obj = \ +hyp_c4.lo \ +hyp_c8.lo + + +# Machine generated specifics +gfor_built_specific_src = \ +generated/_abs_c4.f90 \ +generated/_abs_c8.f90 \ +generated/_abs_i4.f90 \ +generated/_abs_i8.f90 \ +generated/_abs_r4.f90 \ +generated/_abs_r8.f90 \ +generated/_exp_r4.f90 \ +generated/_exp_r8.f90 \ +generated/_exp_c4.f90 \ +generated/_exp_c8.f90 \ +generated/_log_r4.f90 \ +generated/_log_r8.f90 \ +generated/_log_c4.f90 \ +generated/_log_c8.f90 \ +generated/_log10_r4.f90 \ +generated/_log10_r8.f90 \ +generated/_sqrt_r4.f90 \ +generated/_sqrt_r8.f90 \ +generated/_sqrt_c4.f90 \ +generated/_sqrt_c8.f90 \ +generated/_asin_r4.f90 \ +generated/_asin_r8.f90 \ +generated/_acos_r4.f90 \ +generated/_acos_r8.f90 \ +generated/_atan_r4.f90 \ +generated/_atan_r8.f90 \ +generated/_sin_r4.f90 \ +generated/_sin_r8.f90 \ +generated/_sin_c4.f90 \ +generated/_sin_c8.f90 \ +generated/_cos_r4.f90 \ +generated/_cos_r8.f90 \ +generated/_cos_c4.f90 \ +generated/_cos_c8.f90 \ +generated/_tan_r4.f90 \ +generated/_tan_r8.f90 \ +generated/_sinh_r4.f90 \ +generated/_sinh_r8.f90 \ +generated/_cosh_r4.f90 \ +generated/_cosh_r8.f90 \ +generated/_tanh_r4.f90 \ +generated/_tanh_r8.f90 \ +generated/_conjg_c4.f90 \ +generated/_conjg_c8.f90 \ +generated/_aint_r4.f90 \ +generated/_aint_r8.f90 \ +generated/_anint_r4.f90 \ +generated/_anint_r8.f90 + +gfor_built_specific2_src = \ +generated/_sign_i4.f90 \ +generated/_sign_i8.f90 \ +generated/_sign_r4.f90 \ +generated/_sign_r8.f90 \ +generated/_dim_i4.f90 \ +generated/_dim_i8.f90 \ +generated/_dim_r4.f90 \ +generated/_dim_r8.f90 \ +generated/_atan2_r4.f90 \ +generated/_atan2_r8.f90 \ +generated/_mod_i4.f90 \ +generated/_mod_i8.f90 \ +generated/_mod_r4.f90 \ +generated/_mod_r8.f90 + +#specific intrinsics requiring manal code +#gfor_specific_c= \ +#intrinsics/_aimag.c \ +#intrinsics/_cabs.c \ +#foo +gfor_specific_src = \ +$(gfor_built_specific_src) \ +$(gfor_built_specific2_src) \ +intrinsics/dprod_r8.f90 + +gfor_cmath_src = $(gfor_math_trig_c) $(gfor_math_exp_c) $(gfor_math_hyp_c) +gfor_cmath_obj = $(gfor_math_trig_obj) $(gfor_math_exp_obj) \ + $(gfor_math_hyp_obj) + +BUILT_SOURCES = $(gfor_built_src) $(gfor_cmath_src) $(gfor_built_specific_src) \ + $(gfor_built_specific2_src) + +libgfortran_la_SOURCES = $(gfor_src) $(gfor_built_src) $(gfor_io_src) \ + $(gfor_helper_src) $(gfor_io_headers) $(gfor_specific_src) + +EXTRA_libgfortran_la_SOURCES = $(gfor_cmath_src) +libgfortran_la_LIBADD = @MATH_OBJ@ +libgfortran_la_DEPENDENCIES = @MATH_OBJ@ +I_M4_DEPS = m4/iparm.m4 m4/types.m4 +I_M4_DEPS0 = $(I_M4_DEPS) m4/iforeach.m4 +I_M4_DEPS1 = $(I_M4_DEPS) m4/ifunction.m4 +EXTRA_DIST = $(m4_files) +all: $(BUILT_SOURCES) config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .f90 .lo .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkdir_p) $(DESTDIR)$(libdir) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgfortran.la: $(libgfortran_la_OBJECTS) $(libgfortran_la_DEPENDENCIES) + $(F77LINK) -rpath $(libdir) $(libgfortran_la_LDFLAGS) $(libgfortran_la_OBJECTS) $(libgfortran_la_LIBADD) $(LIBS) +libgfortranbegin.la: $(libgfortranbegin_la_OBJECTS) $(libgfortranbegin_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libgfortranbegin_la_LDFLAGS) $(libgfortranbegin_la_OBJECTS) $(libgfortranbegin_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/abort.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/all_l4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/all_l8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/any_l4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/any_l8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/associated.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backspace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/close.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/count_4_l4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/count_4_l8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/count_8_l4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/count_8_l8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpu_time.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cshift0.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cshift1_4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cshift1_8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_c4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_c8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_l4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_l8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dotprod_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/endfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/environ.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eoshift0.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eoshift1_4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eoshift1_8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eoshift2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eoshift3_4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eoshift3_8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exp_c4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exp_c8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exponent_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exponent_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmain.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fraction_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fraction_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hyp_c4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hyp_c8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/in_pack_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/in_pack_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/in_pack_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/in_unpack_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/in_unpack_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/in_unpack_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inquire.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ishftc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_read.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_c4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_c8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_l4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_l8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matmul_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_4_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_4_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_4_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_4_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_8_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_8_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_8_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc0_8_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_4_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_4_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_4_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_4_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_8_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_8_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_8_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxloc1_8_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxval_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxval_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxval_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxval_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_4_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_4_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_4_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_4_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_8_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_8_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_8_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc0_8_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_4_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_4_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_4_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_4_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_8_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_8_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_8_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minloc1_8_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minval_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minval_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minval_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minval_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nearest_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nearest_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/open.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pack_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pause.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/product_c4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/product_c8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/product_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/product_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/product_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/product_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reshape_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reshape_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reshape_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reshape_packed.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rewind.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/select.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_exponent_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_exponent_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shape_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shape_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/size.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spread_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stop.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string_intrinsics.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sum_c4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sum_c8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sum_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sum_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sum_r4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sum_r8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transfer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transpose_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transpose_i4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transpose_i8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trig_c4.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trig_c8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unpack_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +environ.o: runtime/environ.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT environ.o -MD -MP -MF "$(DEPDIR)/environ.Tpo" -c -o environ.o `test -f 'runtime/environ.c' || echo '$(srcdir)/'`runtime/environ.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/environ.Tpo" "$(DEPDIR)/environ.Po"; else rm -f "$(DEPDIR)/environ.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/environ.c' object='environ.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/environ.Po' tmpdepfile='$(DEPDIR)/environ.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o environ.o `test -f 'runtime/environ.c' || echo '$(srcdir)/'`runtime/environ.c + +environ.obj: runtime/environ.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT environ.obj -MD -MP -MF "$(DEPDIR)/environ.Tpo" -c -o environ.obj `if test -f 'runtime/environ.c'; then $(CYGPATH_W) 'runtime/environ.c'; else $(CYGPATH_W) '$(srcdir)/runtime/environ.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/environ.Tpo" "$(DEPDIR)/environ.Po"; else rm -f "$(DEPDIR)/environ.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/environ.c' object='environ.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/environ.Po' tmpdepfile='$(DEPDIR)/environ.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o environ.obj `if test -f 'runtime/environ.c'; then $(CYGPATH_W) 'runtime/environ.c'; else $(CYGPATH_W) '$(srcdir)/runtime/environ.c'; fi` + +environ.lo: runtime/environ.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT environ.lo -MD -MP -MF "$(DEPDIR)/environ.Tpo" -c -o environ.lo `test -f 'runtime/environ.c' || echo '$(srcdir)/'`runtime/environ.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/environ.Tpo" "$(DEPDIR)/environ.Plo"; else rm -f "$(DEPDIR)/environ.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/environ.c' object='environ.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/environ.Plo' tmpdepfile='$(DEPDIR)/environ.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o environ.lo `test -f 'runtime/environ.c' || echo '$(srcdir)/'`runtime/environ.c + +error.o: runtime/error.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT error.o -MD -MP -MF "$(DEPDIR)/error.Tpo" -c -o error.o `test -f 'runtime/error.c' || echo '$(srcdir)/'`runtime/error.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/error.Tpo" "$(DEPDIR)/error.Po"; else rm -f "$(DEPDIR)/error.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/error.c' object='error.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/error.Po' tmpdepfile='$(DEPDIR)/error.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o error.o `test -f 'runtime/error.c' || echo '$(srcdir)/'`runtime/error.c + +error.obj: runtime/error.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT error.obj -MD -MP -MF "$(DEPDIR)/error.Tpo" -c -o error.obj `if test -f 'runtime/error.c'; then $(CYGPATH_W) 'runtime/error.c'; else $(CYGPATH_W) '$(srcdir)/runtime/error.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/error.Tpo" "$(DEPDIR)/error.Po"; else rm -f "$(DEPDIR)/error.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/error.c' object='error.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/error.Po' tmpdepfile='$(DEPDIR)/error.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o error.obj `if test -f 'runtime/error.c'; then $(CYGPATH_W) 'runtime/error.c'; else $(CYGPATH_W) '$(srcdir)/runtime/error.c'; fi` + +error.lo: runtime/error.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT error.lo -MD -MP -MF "$(DEPDIR)/error.Tpo" -c -o error.lo `test -f 'runtime/error.c' || echo '$(srcdir)/'`runtime/error.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/error.Tpo" "$(DEPDIR)/error.Plo"; else rm -f "$(DEPDIR)/error.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/error.c' object='error.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/error.Plo' tmpdepfile='$(DEPDIR)/error.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o error.lo `test -f 'runtime/error.c' || echo '$(srcdir)/'`runtime/error.c + +main.o: runtime/main.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main.o -MD -MP -MF "$(DEPDIR)/main.Tpo" -c -o main.o `test -f 'runtime/main.c' || echo '$(srcdir)/'`runtime/main.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/main.Tpo" "$(DEPDIR)/main.Po"; else rm -f "$(DEPDIR)/main.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/main.c' object='main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/main.Po' tmpdepfile='$(DEPDIR)/main.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main.o `test -f 'runtime/main.c' || echo '$(srcdir)/'`runtime/main.c + +main.obj: runtime/main.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main.obj -MD -MP -MF "$(DEPDIR)/main.Tpo" -c -o main.obj `if test -f 'runtime/main.c'; then $(CYGPATH_W) 'runtime/main.c'; else $(CYGPATH_W) '$(srcdir)/runtime/main.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/main.Tpo" "$(DEPDIR)/main.Po"; else rm -f "$(DEPDIR)/main.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/main.c' object='main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/main.Po' tmpdepfile='$(DEPDIR)/main.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main.obj `if test -f 'runtime/main.c'; then $(CYGPATH_W) 'runtime/main.c'; else $(CYGPATH_W) '$(srcdir)/runtime/main.c'; fi` + +main.lo: runtime/main.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main.lo -MD -MP -MF "$(DEPDIR)/main.Tpo" -c -o main.lo `test -f 'runtime/main.c' || echo '$(srcdir)/'`runtime/main.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/main.Tpo" "$(DEPDIR)/main.Plo"; else rm -f "$(DEPDIR)/main.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/main.c' object='main.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/main.Plo' tmpdepfile='$(DEPDIR)/main.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main.lo `test -f 'runtime/main.c' || echo '$(srcdir)/'`runtime/main.c + +memory.o: runtime/memory.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT memory.o -MD -MP -MF "$(DEPDIR)/memory.Tpo" -c -o memory.o `test -f 'runtime/memory.c' || echo '$(srcdir)/'`runtime/memory.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/memory.Tpo" "$(DEPDIR)/memory.Po"; else rm -f "$(DEPDIR)/memory.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/memory.c' object='memory.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/memory.Po' tmpdepfile='$(DEPDIR)/memory.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o memory.o `test -f 'runtime/memory.c' || echo '$(srcdir)/'`runtime/memory.c + +memory.obj: runtime/memory.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT memory.obj -MD -MP -MF "$(DEPDIR)/memory.Tpo" -c -o memory.obj `if test -f 'runtime/memory.c'; then $(CYGPATH_W) 'runtime/memory.c'; else $(CYGPATH_W) '$(srcdir)/runtime/memory.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/memory.Tpo" "$(DEPDIR)/memory.Po"; else rm -f "$(DEPDIR)/memory.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/memory.c' object='memory.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/memory.Po' tmpdepfile='$(DEPDIR)/memory.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o memory.obj `if test -f 'runtime/memory.c'; then $(CYGPATH_W) 'runtime/memory.c'; else $(CYGPATH_W) '$(srcdir)/runtime/memory.c'; fi` + +memory.lo: runtime/memory.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT memory.lo -MD -MP -MF "$(DEPDIR)/memory.Tpo" -c -o memory.lo `test -f 'runtime/memory.c' || echo '$(srcdir)/'`runtime/memory.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/memory.Tpo" "$(DEPDIR)/memory.Plo"; else rm -f "$(DEPDIR)/memory.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/memory.c' object='memory.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/memory.Plo' tmpdepfile='$(DEPDIR)/memory.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o memory.lo `test -f 'runtime/memory.c' || echo '$(srcdir)/'`runtime/memory.c + +pause.o: runtime/pause.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pause.o -MD -MP -MF "$(DEPDIR)/pause.Tpo" -c -o pause.o `test -f 'runtime/pause.c' || echo '$(srcdir)/'`runtime/pause.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/pause.Tpo" "$(DEPDIR)/pause.Po"; else rm -f "$(DEPDIR)/pause.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/pause.c' object='pause.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/pause.Po' tmpdepfile='$(DEPDIR)/pause.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pause.o `test -f 'runtime/pause.c' || echo '$(srcdir)/'`runtime/pause.c + +pause.obj: runtime/pause.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pause.obj -MD -MP -MF "$(DEPDIR)/pause.Tpo" -c -o pause.obj `if test -f 'runtime/pause.c'; then $(CYGPATH_W) 'runtime/pause.c'; else $(CYGPATH_W) '$(srcdir)/runtime/pause.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/pause.Tpo" "$(DEPDIR)/pause.Po"; else rm -f "$(DEPDIR)/pause.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/pause.c' object='pause.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/pause.Po' tmpdepfile='$(DEPDIR)/pause.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pause.obj `if test -f 'runtime/pause.c'; then $(CYGPATH_W) 'runtime/pause.c'; else $(CYGPATH_W) '$(srcdir)/runtime/pause.c'; fi` + +pause.lo: runtime/pause.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pause.lo -MD -MP -MF "$(DEPDIR)/pause.Tpo" -c -o pause.lo `test -f 'runtime/pause.c' || echo '$(srcdir)/'`runtime/pause.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/pause.Tpo" "$(DEPDIR)/pause.Plo"; else rm -f "$(DEPDIR)/pause.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/pause.c' object='pause.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/pause.Plo' tmpdepfile='$(DEPDIR)/pause.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pause.lo `test -f 'runtime/pause.c' || echo '$(srcdir)/'`runtime/pause.c + +stop.o: runtime/stop.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stop.o -MD -MP -MF "$(DEPDIR)/stop.Tpo" -c -o stop.o `test -f 'runtime/stop.c' || echo '$(srcdir)/'`runtime/stop.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/stop.Tpo" "$(DEPDIR)/stop.Po"; else rm -f "$(DEPDIR)/stop.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/stop.c' object='stop.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/stop.Po' tmpdepfile='$(DEPDIR)/stop.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stop.o `test -f 'runtime/stop.c' || echo '$(srcdir)/'`runtime/stop.c + +stop.obj: runtime/stop.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stop.obj -MD -MP -MF "$(DEPDIR)/stop.Tpo" -c -o stop.obj `if test -f 'runtime/stop.c'; then $(CYGPATH_W) 'runtime/stop.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stop.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/stop.Tpo" "$(DEPDIR)/stop.Po"; else rm -f "$(DEPDIR)/stop.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/stop.c' object='stop.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/stop.Po' tmpdepfile='$(DEPDIR)/stop.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stop.obj `if test -f 'runtime/stop.c'; then $(CYGPATH_W) 'runtime/stop.c'; else $(CYGPATH_W) '$(srcdir)/runtime/stop.c'; fi` + +stop.lo: runtime/stop.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT stop.lo -MD -MP -MF "$(DEPDIR)/stop.Tpo" -c -o stop.lo `test -f 'runtime/stop.c' || echo '$(srcdir)/'`runtime/stop.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/stop.Tpo" "$(DEPDIR)/stop.Plo"; else rm -f "$(DEPDIR)/stop.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/stop.c' object='stop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/stop.Plo' tmpdepfile='$(DEPDIR)/stop.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stop.lo `test -f 'runtime/stop.c' || echo '$(srcdir)/'`runtime/stop.c + +string.o: runtime/string.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT string.o -MD -MP -MF "$(DEPDIR)/string.Tpo" -c -o string.o `test -f 'runtime/string.c' || echo '$(srcdir)/'`runtime/string.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/string.Tpo" "$(DEPDIR)/string.Po"; else rm -f "$(DEPDIR)/string.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/string.c' object='string.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/string.Po' tmpdepfile='$(DEPDIR)/string.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o string.o `test -f 'runtime/string.c' || echo '$(srcdir)/'`runtime/string.c + +string.obj: runtime/string.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT string.obj -MD -MP -MF "$(DEPDIR)/string.Tpo" -c -o string.obj `if test -f 'runtime/string.c'; then $(CYGPATH_W) 'runtime/string.c'; else $(CYGPATH_W) '$(srcdir)/runtime/string.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/string.Tpo" "$(DEPDIR)/string.Po"; else rm -f "$(DEPDIR)/string.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/string.c' object='string.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/string.Po' tmpdepfile='$(DEPDIR)/string.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o string.obj `if test -f 'runtime/string.c'; then $(CYGPATH_W) 'runtime/string.c'; else $(CYGPATH_W) '$(srcdir)/runtime/string.c'; fi` + +string.lo: runtime/string.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT string.lo -MD -MP -MF "$(DEPDIR)/string.Tpo" -c -o string.lo `test -f 'runtime/string.c' || echo '$(srcdir)/'`runtime/string.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/string.Tpo" "$(DEPDIR)/string.Plo"; else rm -f "$(DEPDIR)/string.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/string.c' object='string.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/string.Plo' tmpdepfile='$(DEPDIR)/string.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o string.lo `test -f 'runtime/string.c' || echo '$(srcdir)/'`runtime/string.c + +select.o: runtime/select.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT select.o -MD -MP -MF "$(DEPDIR)/select.Tpo" -c -o select.o `test -f 'runtime/select.c' || echo '$(srcdir)/'`runtime/select.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/select.Tpo" "$(DEPDIR)/select.Po"; else rm -f "$(DEPDIR)/select.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/select.c' object='select.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/select.Po' tmpdepfile='$(DEPDIR)/select.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o select.o `test -f 'runtime/select.c' || echo '$(srcdir)/'`runtime/select.c + +select.obj: runtime/select.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT select.obj -MD -MP -MF "$(DEPDIR)/select.Tpo" -c -o select.obj `if test -f 'runtime/select.c'; then $(CYGPATH_W) 'runtime/select.c'; else $(CYGPATH_W) '$(srcdir)/runtime/select.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/select.Tpo" "$(DEPDIR)/select.Po"; else rm -f "$(DEPDIR)/select.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/select.c' object='select.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/select.Po' tmpdepfile='$(DEPDIR)/select.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o select.obj `if test -f 'runtime/select.c'; then $(CYGPATH_W) 'runtime/select.c'; else $(CYGPATH_W) '$(srcdir)/runtime/select.c'; fi` + +select.lo: runtime/select.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT select.lo -MD -MP -MF "$(DEPDIR)/select.Tpo" -c -o select.lo `test -f 'runtime/select.c' || echo '$(srcdir)/'`runtime/select.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/select.Tpo" "$(DEPDIR)/select.Plo"; else rm -f "$(DEPDIR)/select.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/select.c' object='select.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/select.Plo' tmpdepfile='$(DEPDIR)/select.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o select.lo `test -f 'runtime/select.c' || echo '$(srcdir)/'`runtime/select.c + +all_l4.o: generated/all_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT all_l4.o -MD -MP -MF "$(DEPDIR)/all_l4.Tpo" -c -o all_l4.o `test -f 'generated/all_l4.c' || echo '$(srcdir)/'`generated/all_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/all_l4.Tpo" "$(DEPDIR)/all_l4.Po"; else rm -f "$(DEPDIR)/all_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/all_l4.c' object='all_l4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/all_l4.Po' tmpdepfile='$(DEPDIR)/all_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o all_l4.o `test -f 'generated/all_l4.c' || echo '$(srcdir)/'`generated/all_l4.c + +all_l4.obj: generated/all_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT all_l4.obj -MD -MP -MF "$(DEPDIR)/all_l4.Tpo" -c -o all_l4.obj `if test -f 'generated/all_l4.c'; then $(CYGPATH_W) 'generated/all_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/all_l4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/all_l4.Tpo" "$(DEPDIR)/all_l4.Po"; else rm -f "$(DEPDIR)/all_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/all_l4.c' object='all_l4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/all_l4.Po' tmpdepfile='$(DEPDIR)/all_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o all_l4.obj `if test -f 'generated/all_l4.c'; then $(CYGPATH_W) 'generated/all_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/all_l4.c'; fi` + +all_l4.lo: generated/all_l4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT all_l4.lo -MD -MP -MF "$(DEPDIR)/all_l4.Tpo" -c -o all_l4.lo `test -f 'generated/all_l4.c' || echo '$(srcdir)/'`generated/all_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/all_l4.Tpo" "$(DEPDIR)/all_l4.Plo"; else rm -f "$(DEPDIR)/all_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/all_l4.c' object='all_l4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/all_l4.Plo' tmpdepfile='$(DEPDIR)/all_l4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o all_l4.lo `test -f 'generated/all_l4.c' || echo '$(srcdir)/'`generated/all_l4.c + +all_l8.o: generated/all_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT all_l8.o -MD -MP -MF "$(DEPDIR)/all_l8.Tpo" -c -o all_l8.o `test -f 'generated/all_l8.c' || echo '$(srcdir)/'`generated/all_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/all_l8.Tpo" "$(DEPDIR)/all_l8.Po"; else rm -f "$(DEPDIR)/all_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/all_l8.c' object='all_l8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/all_l8.Po' tmpdepfile='$(DEPDIR)/all_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o all_l8.o `test -f 'generated/all_l8.c' || echo '$(srcdir)/'`generated/all_l8.c + +all_l8.obj: generated/all_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT all_l8.obj -MD -MP -MF "$(DEPDIR)/all_l8.Tpo" -c -o all_l8.obj `if test -f 'generated/all_l8.c'; then $(CYGPATH_W) 'generated/all_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/all_l8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/all_l8.Tpo" "$(DEPDIR)/all_l8.Po"; else rm -f "$(DEPDIR)/all_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/all_l8.c' object='all_l8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/all_l8.Po' tmpdepfile='$(DEPDIR)/all_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o all_l8.obj `if test -f 'generated/all_l8.c'; then $(CYGPATH_W) 'generated/all_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/all_l8.c'; fi` + +all_l8.lo: generated/all_l8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT all_l8.lo -MD -MP -MF "$(DEPDIR)/all_l8.Tpo" -c -o all_l8.lo `test -f 'generated/all_l8.c' || echo '$(srcdir)/'`generated/all_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/all_l8.Tpo" "$(DEPDIR)/all_l8.Plo"; else rm -f "$(DEPDIR)/all_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/all_l8.c' object='all_l8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/all_l8.Plo' tmpdepfile='$(DEPDIR)/all_l8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o all_l8.lo `test -f 'generated/all_l8.c' || echo '$(srcdir)/'`generated/all_l8.c + +any_l4.o: generated/any_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT any_l4.o -MD -MP -MF "$(DEPDIR)/any_l4.Tpo" -c -o any_l4.o `test -f 'generated/any_l4.c' || echo '$(srcdir)/'`generated/any_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/any_l4.Tpo" "$(DEPDIR)/any_l4.Po"; else rm -f "$(DEPDIR)/any_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/any_l4.c' object='any_l4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/any_l4.Po' tmpdepfile='$(DEPDIR)/any_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o any_l4.o `test -f 'generated/any_l4.c' || echo '$(srcdir)/'`generated/any_l4.c + +any_l4.obj: generated/any_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT any_l4.obj -MD -MP -MF "$(DEPDIR)/any_l4.Tpo" -c -o any_l4.obj `if test -f 'generated/any_l4.c'; then $(CYGPATH_W) 'generated/any_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/any_l4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/any_l4.Tpo" "$(DEPDIR)/any_l4.Po"; else rm -f "$(DEPDIR)/any_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/any_l4.c' object='any_l4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/any_l4.Po' tmpdepfile='$(DEPDIR)/any_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o any_l4.obj `if test -f 'generated/any_l4.c'; then $(CYGPATH_W) 'generated/any_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/any_l4.c'; fi` + +any_l4.lo: generated/any_l4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT any_l4.lo -MD -MP -MF "$(DEPDIR)/any_l4.Tpo" -c -o any_l4.lo `test -f 'generated/any_l4.c' || echo '$(srcdir)/'`generated/any_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/any_l4.Tpo" "$(DEPDIR)/any_l4.Plo"; else rm -f "$(DEPDIR)/any_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/any_l4.c' object='any_l4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/any_l4.Plo' tmpdepfile='$(DEPDIR)/any_l4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o any_l4.lo `test -f 'generated/any_l4.c' || echo '$(srcdir)/'`generated/any_l4.c + +any_l8.o: generated/any_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT any_l8.o -MD -MP -MF "$(DEPDIR)/any_l8.Tpo" -c -o any_l8.o `test -f 'generated/any_l8.c' || echo '$(srcdir)/'`generated/any_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/any_l8.Tpo" "$(DEPDIR)/any_l8.Po"; else rm -f "$(DEPDIR)/any_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/any_l8.c' object='any_l8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/any_l8.Po' tmpdepfile='$(DEPDIR)/any_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o any_l8.o `test -f 'generated/any_l8.c' || echo '$(srcdir)/'`generated/any_l8.c + +any_l8.obj: generated/any_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT any_l8.obj -MD -MP -MF "$(DEPDIR)/any_l8.Tpo" -c -o any_l8.obj `if test -f 'generated/any_l8.c'; then $(CYGPATH_W) 'generated/any_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/any_l8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/any_l8.Tpo" "$(DEPDIR)/any_l8.Po"; else rm -f "$(DEPDIR)/any_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/any_l8.c' object='any_l8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/any_l8.Po' tmpdepfile='$(DEPDIR)/any_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o any_l8.obj `if test -f 'generated/any_l8.c'; then $(CYGPATH_W) 'generated/any_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/any_l8.c'; fi` + +any_l8.lo: generated/any_l8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT any_l8.lo -MD -MP -MF "$(DEPDIR)/any_l8.Tpo" -c -o any_l8.lo `test -f 'generated/any_l8.c' || echo '$(srcdir)/'`generated/any_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/any_l8.Tpo" "$(DEPDIR)/any_l8.Plo"; else rm -f "$(DEPDIR)/any_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/any_l8.c' object='any_l8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/any_l8.Plo' tmpdepfile='$(DEPDIR)/any_l8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o any_l8.lo `test -f 'generated/any_l8.c' || echo '$(srcdir)/'`generated/any_l8.c + +count_4_l4.o: generated/count_4_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_4_l4.o -MD -MP -MF "$(DEPDIR)/count_4_l4.Tpo" -c -o count_4_l4.o `test -f 'generated/count_4_l4.c' || echo '$(srcdir)/'`generated/count_4_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_4_l4.Tpo" "$(DEPDIR)/count_4_l4.Po"; else rm -f "$(DEPDIR)/count_4_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_4_l4.c' object='count_4_l4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_4_l4.Po' tmpdepfile='$(DEPDIR)/count_4_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_4_l4.o `test -f 'generated/count_4_l4.c' || echo '$(srcdir)/'`generated/count_4_l4.c + +count_4_l4.obj: generated/count_4_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_4_l4.obj -MD -MP -MF "$(DEPDIR)/count_4_l4.Tpo" -c -o count_4_l4.obj `if test -f 'generated/count_4_l4.c'; then $(CYGPATH_W) 'generated/count_4_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_4_l4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_4_l4.Tpo" "$(DEPDIR)/count_4_l4.Po"; else rm -f "$(DEPDIR)/count_4_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_4_l4.c' object='count_4_l4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_4_l4.Po' tmpdepfile='$(DEPDIR)/count_4_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_4_l4.obj `if test -f 'generated/count_4_l4.c'; then $(CYGPATH_W) 'generated/count_4_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_4_l4.c'; fi` + +count_4_l4.lo: generated/count_4_l4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_4_l4.lo -MD -MP -MF "$(DEPDIR)/count_4_l4.Tpo" -c -o count_4_l4.lo `test -f 'generated/count_4_l4.c' || echo '$(srcdir)/'`generated/count_4_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_4_l4.Tpo" "$(DEPDIR)/count_4_l4.Plo"; else rm -f "$(DEPDIR)/count_4_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_4_l4.c' object='count_4_l4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_4_l4.Plo' tmpdepfile='$(DEPDIR)/count_4_l4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_4_l4.lo `test -f 'generated/count_4_l4.c' || echo '$(srcdir)/'`generated/count_4_l4.c + +count_8_l4.o: generated/count_8_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_8_l4.o -MD -MP -MF "$(DEPDIR)/count_8_l4.Tpo" -c -o count_8_l4.o `test -f 'generated/count_8_l4.c' || echo '$(srcdir)/'`generated/count_8_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_8_l4.Tpo" "$(DEPDIR)/count_8_l4.Po"; else rm -f "$(DEPDIR)/count_8_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_8_l4.c' object='count_8_l4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_8_l4.Po' tmpdepfile='$(DEPDIR)/count_8_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_8_l4.o `test -f 'generated/count_8_l4.c' || echo '$(srcdir)/'`generated/count_8_l4.c + +count_8_l4.obj: generated/count_8_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_8_l4.obj -MD -MP -MF "$(DEPDIR)/count_8_l4.Tpo" -c -o count_8_l4.obj `if test -f 'generated/count_8_l4.c'; then $(CYGPATH_W) 'generated/count_8_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_8_l4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_8_l4.Tpo" "$(DEPDIR)/count_8_l4.Po"; else rm -f "$(DEPDIR)/count_8_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_8_l4.c' object='count_8_l4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_8_l4.Po' tmpdepfile='$(DEPDIR)/count_8_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_8_l4.obj `if test -f 'generated/count_8_l4.c'; then $(CYGPATH_W) 'generated/count_8_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_8_l4.c'; fi` + +count_8_l4.lo: generated/count_8_l4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_8_l4.lo -MD -MP -MF "$(DEPDIR)/count_8_l4.Tpo" -c -o count_8_l4.lo `test -f 'generated/count_8_l4.c' || echo '$(srcdir)/'`generated/count_8_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_8_l4.Tpo" "$(DEPDIR)/count_8_l4.Plo"; else rm -f "$(DEPDIR)/count_8_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_8_l4.c' object='count_8_l4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_8_l4.Plo' tmpdepfile='$(DEPDIR)/count_8_l4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_8_l4.lo `test -f 'generated/count_8_l4.c' || echo '$(srcdir)/'`generated/count_8_l4.c + +count_4_l8.o: generated/count_4_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_4_l8.o -MD -MP -MF "$(DEPDIR)/count_4_l8.Tpo" -c -o count_4_l8.o `test -f 'generated/count_4_l8.c' || echo '$(srcdir)/'`generated/count_4_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_4_l8.Tpo" "$(DEPDIR)/count_4_l8.Po"; else rm -f "$(DEPDIR)/count_4_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_4_l8.c' object='count_4_l8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_4_l8.Po' tmpdepfile='$(DEPDIR)/count_4_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_4_l8.o `test -f 'generated/count_4_l8.c' || echo '$(srcdir)/'`generated/count_4_l8.c + +count_4_l8.obj: generated/count_4_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_4_l8.obj -MD -MP -MF "$(DEPDIR)/count_4_l8.Tpo" -c -o count_4_l8.obj `if test -f 'generated/count_4_l8.c'; then $(CYGPATH_W) 'generated/count_4_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_4_l8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_4_l8.Tpo" "$(DEPDIR)/count_4_l8.Po"; else rm -f "$(DEPDIR)/count_4_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_4_l8.c' object='count_4_l8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_4_l8.Po' tmpdepfile='$(DEPDIR)/count_4_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_4_l8.obj `if test -f 'generated/count_4_l8.c'; then $(CYGPATH_W) 'generated/count_4_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_4_l8.c'; fi` + +count_4_l8.lo: generated/count_4_l8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_4_l8.lo -MD -MP -MF "$(DEPDIR)/count_4_l8.Tpo" -c -o count_4_l8.lo `test -f 'generated/count_4_l8.c' || echo '$(srcdir)/'`generated/count_4_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_4_l8.Tpo" "$(DEPDIR)/count_4_l8.Plo"; else rm -f "$(DEPDIR)/count_4_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_4_l8.c' object='count_4_l8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_4_l8.Plo' tmpdepfile='$(DEPDIR)/count_4_l8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_4_l8.lo `test -f 'generated/count_4_l8.c' || echo '$(srcdir)/'`generated/count_4_l8.c + +count_8_l8.o: generated/count_8_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_8_l8.o -MD -MP -MF "$(DEPDIR)/count_8_l8.Tpo" -c -o count_8_l8.o `test -f 'generated/count_8_l8.c' || echo '$(srcdir)/'`generated/count_8_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_8_l8.Tpo" "$(DEPDIR)/count_8_l8.Po"; else rm -f "$(DEPDIR)/count_8_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_8_l8.c' object='count_8_l8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_8_l8.Po' tmpdepfile='$(DEPDIR)/count_8_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_8_l8.o `test -f 'generated/count_8_l8.c' || echo '$(srcdir)/'`generated/count_8_l8.c + +count_8_l8.obj: generated/count_8_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_8_l8.obj -MD -MP -MF "$(DEPDIR)/count_8_l8.Tpo" -c -o count_8_l8.obj `if test -f 'generated/count_8_l8.c'; then $(CYGPATH_W) 'generated/count_8_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_8_l8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_8_l8.Tpo" "$(DEPDIR)/count_8_l8.Po"; else rm -f "$(DEPDIR)/count_8_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_8_l8.c' object='count_8_l8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_8_l8.Po' tmpdepfile='$(DEPDIR)/count_8_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_8_l8.obj `if test -f 'generated/count_8_l8.c'; then $(CYGPATH_W) 'generated/count_8_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/count_8_l8.c'; fi` + +count_8_l8.lo: generated/count_8_l8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT count_8_l8.lo -MD -MP -MF "$(DEPDIR)/count_8_l8.Tpo" -c -o count_8_l8.lo `test -f 'generated/count_8_l8.c' || echo '$(srcdir)/'`generated/count_8_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/count_8_l8.Tpo" "$(DEPDIR)/count_8_l8.Plo"; else rm -f "$(DEPDIR)/count_8_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/count_8_l8.c' object='count_8_l8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/count_8_l8.Plo' tmpdepfile='$(DEPDIR)/count_8_l8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o count_8_l8.lo `test -f 'generated/count_8_l8.c' || echo '$(srcdir)/'`generated/count_8_l8.c + +maxloc0_4_i4.o: generated/maxloc0_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_i4.o -MD -MP -MF "$(DEPDIR)/maxloc0_4_i4.Tpo" -c -o maxloc0_4_i4.o `test -f 'generated/maxloc0_4_i4.c' || echo '$(srcdir)/'`generated/maxloc0_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_i4.Tpo" "$(DEPDIR)/maxloc0_4_i4.Po"; else rm -f "$(DEPDIR)/maxloc0_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_i4.c' object='maxloc0_4_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_i4.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_i4.o `test -f 'generated/maxloc0_4_i4.c' || echo '$(srcdir)/'`generated/maxloc0_4_i4.c + +maxloc0_4_i4.obj: generated/maxloc0_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_i4.obj -MD -MP -MF "$(DEPDIR)/maxloc0_4_i4.Tpo" -c -o maxloc0_4_i4.obj `if test -f 'generated/maxloc0_4_i4.c'; then $(CYGPATH_W) 'generated/maxloc0_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_i4.Tpo" "$(DEPDIR)/maxloc0_4_i4.Po"; else rm -f "$(DEPDIR)/maxloc0_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_i4.c' object='maxloc0_4_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_i4.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_i4.obj `if test -f 'generated/maxloc0_4_i4.c'; then $(CYGPATH_W) 'generated/maxloc0_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_i4.c'; fi` + +maxloc0_4_i4.lo: generated/maxloc0_4_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_i4.lo -MD -MP -MF "$(DEPDIR)/maxloc0_4_i4.Tpo" -c -o maxloc0_4_i4.lo `test -f 'generated/maxloc0_4_i4.c' || echo '$(srcdir)/'`generated/maxloc0_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_i4.Tpo" "$(DEPDIR)/maxloc0_4_i4.Plo"; else rm -f "$(DEPDIR)/maxloc0_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_i4.c' object='maxloc0_4_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_i4.Plo' tmpdepfile='$(DEPDIR)/maxloc0_4_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_i4.lo `test -f 'generated/maxloc0_4_i4.c' || echo '$(srcdir)/'`generated/maxloc0_4_i4.c + +maxloc0_8_i4.o: generated/maxloc0_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_i4.o -MD -MP -MF "$(DEPDIR)/maxloc0_8_i4.Tpo" -c -o maxloc0_8_i4.o `test -f 'generated/maxloc0_8_i4.c' || echo '$(srcdir)/'`generated/maxloc0_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_i4.Tpo" "$(DEPDIR)/maxloc0_8_i4.Po"; else rm -f "$(DEPDIR)/maxloc0_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_i4.c' object='maxloc0_8_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_i4.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_i4.o `test -f 'generated/maxloc0_8_i4.c' || echo '$(srcdir)/'`generated/maxloc0_8_i4.c + +maxloc0_8_i4.obj: generated/maxloc0_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_i4.obj -MD -MP -MF "$(DEPDIR)/maxloc0_8_i4.Tpo" -c -o maxloc0_8_i4.obj `if test -f 'generated/maxloc0_8_i4.c'; then $(CYGPATH_W) 'generated/maxloc0_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_i4.Tpo" "$(DEPDIR)/maxloc0_8_i4.Po"; else rm -f "$(DEPDIR)/maxloc0_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_i4.c' object='maxloc0_8_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_i4.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_i4.obj `if test -f 'generated/maxloc0_8_i4.c'; then $(CYGPATH_W) 'generated/maxloc0_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_i4.c'; fi` + +maxloc0_8_i4.lo: generated/maxloc0_8_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_i4.lo -MD -MP -MF "$(DEPDIR)/maxloc0_8_i4.Tpo" -c -o maxloc0_8_i4.lo `test -f 'generated/maxloc0_8_i4.c' || echo '$(srcdir)/'`generated/maxloc0_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_i4.Tpo" "$(DEPDIR)/maxloc0_8_i4.Plo"; else rm -f "$(DEPDIR)/maxloc0_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_i4.c' object='maxloc0_8_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_i4.Plo' tmpdepfile='$(DEPDIR)/maxloc0_8_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_i4.lo `test -f 'generated/maxloc0_8_i4.c' || echo '$(srcdir)/'`generated/maxloc0_8_i4.c + +maxloc0_4_i8.o: generated/maxloc0_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_i8.o -MD -MP -MF "$(DEPDIR)/maxloc0_4_i8.Tpo" -c -o maxloc0_4_i8.o `test -f 'generated/maxloc0_4_i8.c' || echo '$(srcdir)/'`generated/maxloc0_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_i8.Tpo" "$(DEPDIR)/maxloc0_4_i8.Po"; else rm -f "$(DEPDIR)/maxloc0_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_i8.c' object='maxloc0_4_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_i8.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_i8.o `test -f 'generated/maxloc0_4_i8.c' || echo '$(srcdir)/'`generated/maxloc0_4_i8.c + +maxloc0_4_i8.obj: generated/maxloc0_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_i8.obj -MD -MP -MF "$(DEPDIR)/maxloc0_4_i8.Tpo" -c -o maxloc0_4_i8.obj `if test -f 'generated/maxloc0_4_i8.c'; then $(CYGPATH_W) 'generated/maxloc0_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_i8.Tpo" "$(DEPDIR)/maxloc0_4_i8.Po"; else rm -f "$(DEPDIR)/maxloc0_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_i8.c' object='maxloc0_4_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_i8.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_i8.obj `if test -f 'generated/maxloc0_4_i8.c'; then $(CYGPATH_W) 'generated/maxloc0_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_i8.c'; fi` + +maxloc0_4_i8.lo: generated/maxloc0_4_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_i8.lo -MD -MP -MF "$(DEPDIR)/maxloc0_4_i8.Tpo" -c -o maxloc0_4_i8.lo `test -f 'generated/maxloc0_4_i8.c' || echo '$(srcdir)/'`generated/maxloc0_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_i8.Tpo" "$(DEPDIR)/maxloc0_4_i8.Plo"; else rm -f "$(DEPDIR)/maxloc0_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_i8.c' object='maxloc0_4_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_i8.Plo' tmpdepfile='$(DEPDIR)/maxloc0_4_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_i8.lo `test -f 'generated/maxloc0_4_i8.c' || echo '$(srcdir)/'`generated/maxloc0_4_i8.c + +maxloc0_8_i8.o: generated/maxloc0_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_i8.o -MD -MP -MF "$(DEPDIR)/maxloc0_8_i8.Tpo" -c -o maxloc0_8_i8.o `test -f 'generated/maxloc0_8_i8.c' || echo '$(srcdir)/'`generated/maxloc0_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_i8.Tpo" "$(DEPDIR)/maxloc0_8_i8.Po"; else rm -f "$(DEPDIR)/maxloc0_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_i8.c' object='maxloc0_8_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_i8.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_i8.o `test -f 'generated/maxloc0_8_i8.c' || echo '$(srcdir)/'`generated/maxloc0_8_i8.c + +maxloc0_8_i8.obj: generated/maxloc0_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_i8.obj -MD -MP -MF "$(DEPDIR)/maxloc0_8_i8.Tpo" -c -o maxloc0_8_i8.obj `if test -f 'generated/maxloc0_8_i8.c'; then $(CYGPATH_W) 'generated/maxloc0_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_i8.Tpo" "$(DEPDIR)/maxloc0_8_i8.Po"; else rm -f "$(DEPDIR)/maxloc0_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_i8.c' object='maxloc0_8_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_i8.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_i8.obj `if test -f 'generated/maxloc0_8_i8.c'; then $(CYGPATH_W) 'generated/maxloc0_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_i8.c'; fi` + +maxloc0_8_i8.lo: generated/maxloc0_8_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_i8.lo -MD -MP -MF "$(DEPDIR)/maxloc0_8_i8.Tpo" -c -o maxloc0_8_i8.lo `test -f 'generated/maxloc0_8_i8.c' || echo '$(srcdir)/'`generated/maxloc0_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_i8.Tpo" "$(DEPDIR)/maxloc0_8_i8.Plo"; else rm -f "$(DEPDIR)/maxloc0_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_i8.c' object='maxloc0_8_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_i8.Plo' tmpdepfile='$(DEPDIR)/maxloc0_8_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_i8.lo `test -f 'generated/maxloc0_8_i8.c' || echo '$(srcdir)/'`generated/maxloc0_8_i8.c + +maxloc0_4_r4.o: generated/maxloc0_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_r4.o -MD -MP -MF "$(DEPDIR)/maxloc0_4_r4.Tpo" -c -o maxloc0_4_r4.o `test -f 'generated/maxloc0_4_r4.c' || echo '$(srcdir)/'`generated/maxloc0_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_r4.Tpo" "$(DEPDIR)/maxloc0_4_r4.Po"; else rm -f "$(DEPDIR)/maxloc0_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_r4.c' object='maxloc0_4_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_r4.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_r4.o `test -f 'generated/maxloc0_4_r4.c' || echo '$(srcdir)/'`generated/maxloc0_4_r4.c + +maxloc0_4_r4.obj: generated/maxloc0_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_r4.obj -MD -MP -MF "$(DEPDIR)/maxloc0_4_r4.Tpo" -c -o maxloc0_4_r4.obj `if test -f 'generated/maxloc0_4_r4.c'; then $(CYGPATH_W) 'generated/maxloc0_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_r4.Tpo" "$(DEPDIR)/maxloc0_4_r4.Po"; else rm -f "$(DEPDIR)/maxloc0_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_r4.c' object='maxloc0_4_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_r4.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_r4.obj `if test -f 'generated/maxloc0_4_r4.c'; then $(CYGPATH_W) 'generated/maxloc0_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_r4.c'; fi` + +maxloc0_4_r4.lo: generated/maxloc0_4_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_r4.lo -MD -MP -MF "$(DEPDIR)/maxloc0_4_r4.Tpo" -c -o maxloc0_4_r4.lo `test -f 'generated/maxloc0_4_r4.c' || echo '$(srcdir)/'`generated/maxloc0_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_r4.Tpo" "$(DEPDIR)/maxloc0_4_r4.Plo"; else rm -f "$(DEPDIR)/maxloc0_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_r4.c' object='maxloc0_4_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_r4.Plo' tmpdepfile='$(DEPDIR)/maxloc0_4_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_r4.lo `test -f 'generated/maxloc0_4_r4.c' || echo '$(srcdir)/'`generated/maxloc0_4_r4.c + +maxloc0_8_r4.o: generated/maxloc0_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_r4.o -MD -MP -MF "$(DEPDIR)/maxloc0_8_r4.Tpo" -c -o maxloc0_8_r4.o `test -f 'generated/maxloc0_8_r4.c' || echo '$(srcdir)/'`generated/maxloc0_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_r4.Tpo" "$(DEPDIR)/maxloc0_8_r4.Po"; else rm -f "$(DEPDIR)/maxloc0_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_r4.c' object='maxloc0_8_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_r4.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_r4.o `test -f 'generated/maxloc0_8_r4.c' || echo '$(srcdir)/'`generated/maxloc0_8_r4.c + +maxloc0_8_r4.obj: generated/maxloc0_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_r4.obj -MD -MP -MF "$(DEPDIR)/maxloc0_8_r4.Tpo" -c -o maxloc0_8_r4.obj `if test -f 'generated/maxloc0_8_r4.c'; then $(CYGPATH_W) 'generated/maxloc0_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_r4.Tpo" "$(DEPDIR)/maxloc0_8_r4.Po"; else rm -f "$(DEPDIR)/maxloc0_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_r4.c' object='maxloc0_8_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_r4.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_r4.obj `if test -f 'generated/maxloc0_8_r4.c'; then $(CYGPATH_W) 'generated/maxloc0_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_r4.c'; fi` + +maxloc0_8_r4.lo: generated/maxloc0_8_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_r4.lo -MD -MP -MF "$(DEPDIR)/maxloc0_8_r4.Tpo" -c -o maxloc0_8_r4.lo `test -f 'generated/maxloc0_8_r4.c' || echo '$(srcdir)/'`generated/maxloc0_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_r4.Tpo" "$(DEPDIR)/maxloc0_8_r4.Plo"; else rm -f "$(DEPDIR)/maxloc0_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_r4.c' object='maxloc0_8_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_r4.Plo' tmpdepfile='$(DEPDIR)/maxloc0_8_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_r4.lo `test -f 'generated/maxloc0_8_r4.c' || echo '$(srcdir)/'`generated/maxloc0_8_r4.c + +maxloc0_4_r8.o: generated/maxloc0_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_r8.o -MD -MP -MF "$(DEPDIR)/maxloc0_4_r8.Tpo" -c -o maxloc0_4_r8.o `test -f 'generated/maxloc0_4_r8.c' || echo '$(srcdir)/'`generated/maxloc0_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_r8.Tpo" "$(DEPDIR)/maxloc0_4_r8.Po"; else rm -f "$(DEPDIR)/maxloc0_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_r8.c' object='maxloc0_4_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_r8.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_r8.o `test -f 'generated/maxloc0_4_r8.c' || echo '$(srcdir)/'`generated/maxloc0_4_r8.c + +maxloc0_4_r8.obj: generated/maxloc0_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_r8.obj -MD -MP -MF "$(DEPDIR)/maxloc0_4_r8.Tpo" -c -o maxloc0_4_r8.obj `if test -f 'generated/maxloc0_4_r8.c'; then $(CYGPATH_W) 'generated/maxloc0_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_r8.Tpo" "$(DEPDIR)/maxloc0_4_r8.Po"; else rm -f "$(DEPDIR)/maxloc0_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_r8.c' object='maxloc0_4_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_r8.Po' tmpdepfile='$(DEPDIR)/maxloc0_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_r8.obj `if test -f 'generated/maxloc0_4_r8.c'; then $(CYGPATH_W) 'generated/maxloc0_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_4_r8.c'; fi` + +maxloc0_4_r8.lo: generated/maxloc0_4_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_4_r8.lo -MD -MP -MF "$(DEPDIR)/maxloc0_4_r8.Tpo" -c -o maxloc0_4_r8.lo `test -f 'generated/maxloc0_4_r8.c' || echo '$(srcdir)/'`generated/maxloc0_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_4_r8.Tpo" "$(DEPDIR)/maxloc0_4_r8.Plo"; else rm -f "$(DEPDIR)/maxloc0_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_4_r8.c' object='maxloc0_4_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_4_r8.Plo' tmpdepfile='$(DEPDIR)/maxloc0_4_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_4_r8.lo `test -f 'generated/maxloc0_4_r8.c' || echo '$(srcdir)/'`generated/maxloc0_4_r8.c + +maxloc0_8_r8.o: generated/maxloc0_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_r8.o -MD -MP -MF "$(DEPDIR)/maxloc0_8_r8.Tpo" -c -o maxloc0_8_r8.o `test -f 'generated/maxloc0_8_r8.c' || echo '$(srcdir)/'`generated/maxloc0_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_r8.Tpo" "$(DEPDIR)/maxloc0_8_r8.Po"; else rm -f "$(DEPDIR)/maxloc0_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_r8.c' object='maxloc0_8_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_r8.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_r8.o `test -f 'generated/maxloc0_8_r8.c' || echo '$(srcdir)/'`generated/maxloc0_8_r8.c + +maxloc0_8_r8.obj: generated/maxloc0_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_r8.obj -MD -MP -MF "$(DEPDIR)/maxloc0_8_r8.Tpo" -c -o maxloc0_8_r8.obj `if test -f 'generated/maxloc0_8_r8.c'; then $(CYGPATH_W) 'generated/maxloc0_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_r8.Tpo" "$(DEPDIR)/maxloc0_8_r8.Po"; else rm -f "$(DEPDIR)/maxloc0_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_r8.c' object='maxloc0_8_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_r8.Po' tmpdepfile='$(DEPDIR)/maxloc0_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_r8.obj `if test -f 'generated/maxloc0_8_r8.c'; then $(CYGPATH_W) 'generated/maxloc0_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc0_8_r8.c'; fi` + +maxloc0_8_r8.lo: generated/maxloc0_8_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc0_8_r8.lo -MD -MP -MF "$(DEPDIR)/maxloc0_8_r8.Tpo" -c -o maxloc0_8_r8.lo `test -f 'generated/maxloc0_8_r8.c' || echo '$(srcdir)/'`generated/maxloc0_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc0_8_r8.Tpo" "$(DEPDIR)/maxloc0_8_r8.Plo"; else rm -f "$(DEPDIR)/maxloc0_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc0_8_r8.c' object='maxloc0_8_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc0_8_r8.Plo' tmpdepfile='$(DEPDIR)/maxloc0_8_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc0_8_r8.lo `test -f 'generated/maxloc0_8_r8.c' || echo '$(srcdir)/'`generated/maxloc0_8_r8.c + +maxloc1_4_i4.o: generated/maxloc1_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_i4.o -MD -MP -MF "$(DEPDIR)/maxloc1_4_i4.Tpo" -c -o maxloc1_4_i4.o `test -f 'generated/maxloc1_4_i4.c' || echo '$(srcdir)/'`generated/maxloc1_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_i4.Tpo" "$(DEPDIR)/maxloc1_4_i4.Po"; else rm -f "$(DEPDIR)/maxloc1_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_i4.c' object='maxloc1_4_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_i4.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_i4.o `test -f 'generated/maxloc1_4_i4.c' || echo '$(srcdir)/'`generated/maxloc1_4_i4.c + +maxloc1_4_i4.obj: generated/maxloc1_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_i4.obj -MD -MP -MF "$(DEPDIR)/maxloc1_4_i4.Tpo" -c -o maxloc1_4_i4.obj `if test -f 'generated/maxloc1_4_i4.c'; then $(CYGPATH_W) 'generated/maxloc1_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_i4.Tpo" "$(DEPDIR)/maxloc1_4_i4.Po"; else rm -f "$(DEPDIR)/maxloc1_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_i4.c' object='maxloc1_4_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_i4.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_i4.obj `if test -f 'generated/maxloc1_4_i4.c'; then $(CYGPATH_W) 'generated/maxloc1_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_i4.c'; fi` + +maxloc1_4_i4.lo: generated/maxloc1_4_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_i4.lo -MD -MP -MF "$(DEPDIR)/maxloc1_4_i4.Tpo" -c -o maxloc1_4_i4.lo `test -f 'generated/maxloc1_4_i4.c' || echo '$(srcdir)/'`generated/maxloc1_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_i4.Tpo" "$(DEPDIR)/maxloc1_4_i4.Plo"; else rm -f "$(DEPDIR)/maxloc1_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_i4.c' object='maxloc1_4_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_i4.Plo' tmpdepfile='$(DEPDIR)/maxloc1_4_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_i4.lo `test -f 'generated/maxloc1_4_i4.c' || echo '$(srcdir)/'`generated/maxloc1_4_i4.c + +maxloc1_8_i4.o: generated/maxloc1_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_i4.o -MD -MP -MF "$(DEPDIR)/maxloc1_8_i4.Tpo" -c -o maxloc1_8_i4.o `test -f 'generated/maxloc1_8_i4.c' || echo '$(srcdir)/'`generated/maxloc1_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_i4.Tpo" "$(DEPDIR)/maxloc1_8_i4.Po"; else rm -f "$(DEPDIR)/maxloc1_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_i4.c' object='maxloc1_8_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_i4.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_i4.o `test -f 'generated/maxloc1_8_i4.c' || echo '$(srcdir)/'`generated/maxloc1_8_i4.c + +maxloc1_8_i4.obj: generated/maxloc1_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_i4.obj -MD -MP -MF "$(DEPDIR)/maxloc1_8_i4.Tpo" -c -o maxloc1_8_i4.obj `if test -f 'generated/maxloc1_8_i4.c'; then $(CYGPATH_W) 'generated/maxloc1_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_i4.Tpo" "$(DEPDIR)/maxloc1_8_i4.Po"; else rm -f "$(DEPDIR)/maxloc1_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_i4.c' object='maxloc1_8_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_i4.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_i4.obj `if test -f 'generated/maxloc1_8_i4.c'; then $(CYGPATH_W) 'generated/maxloc1_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_i4.c'; fi` + +maxloc1_8_i4.lo: generated/maxloc1_8_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_i4.lo -MD -MP -MF "$(DEPDIR)/maxloc1_8_i4.Tpo" -c -o maxloc1_8_i4.lo `test -f 'generated/maxloc1_8_i4.c' || echo '$(srcdir)/'`generated/maxloc1_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_i4.Tpo" "$(DEPDIR)/maxloc1_8_i4.Plo"; else rm -f "$(DEPDIR)/maxloc1_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_i4.c' object='maxloc1_8_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_i4.Plo' tmpdepfile='$(DEPDIR)/maxloc1_8_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_i4.lo `test -f 'generated/maxloc1_8_i4.c' || echo '$(srcdir)/'`generated/maxloc1_8_i4.c + +maxloc1_4_i8.o: generated/maxloc1_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_i8.o -MD -MP -MF "$(DEPDIR)/maxloc1_4_i8.Tpo" -c -o maxloc1_4_i8.o `test -f 'generated/maxloc1_4_i8.c' || echo '$(srcdir)/'`generated/maxloc1_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_i8.Tpo" "$(DEPDIR)/maxloc1_4_i8.Po"; else rm -f "$(DEPDIR)/maxloc1_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_i8.c' object='maxloc1_4_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_i8.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_i8.o `test -f 'generated/maxloc1_4_i8.c' || echo '$(srcdir)/'`generated/maxloc1_4_i8.c + +maxloc1_4_i8.obj: generated/maxloc1_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_i8.obj -MD -MP -MF "$(DEPDIR)/maxloc1_4_i8.Tpo" -c -o maxloc1_4_i8.obj `if test -f 'generated/maxloc1_4_i8.c'; then $(CYGPATH_W) 'generated/maxloc1_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_i8.Tpo" "$(DEPDIR)/maxloc1_4_i8.Po"; else rm -f "$(DEPDIR)/maxloc1_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_i8.c' object='maxloc1_4_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_i8.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_i8.obj `if test -f 'generated/maxloc1_4_i8.c'; then $(CYGPATH_W) 'generated/maxloc1_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_i8.c'; fi` + +maxloc1_4_i8.lo: generated/maxloc1_4_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_i8.lo -MD -MP -MF "$(DEPDIR)/maxloc1_4_i8.Tpo" -c -o maxloc1_4_i8.lo `test -f 'generated/maxloc1_4_i8.c' || echo '$(srcdir)/'`generated/maxloc1_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_i8.Tpo" "$(DEPDIR)/maxloc1_4_i8.Plo"; else rm -f "$(DEPDIR)/maxloc1_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_i8.c' object='maxloc1_4_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_i8.Plo' tmpdepfile='$(DEPDIR)/maxloc1_4_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_i8.lo `test -f 'generated/maxloc1_4_i8.c' || echo '$(srcdir)/'`generated/maxloc1_4_i8.c + +maxloc1_8_i8.o: generated/maxloc1_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_i8.o -MD -MP -MF "$(DEPDIR)/maxloc1_8_i8.Tpo" -c -o maxloc1_8_i8.o `test -f 'generated/maxloc1_8_i8.c' || echo '$(srcdir)/'`generated/maxloc1_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_i8.Tpo" "$(DEPDIR)/maxloc1_8_i8.Po"; else rm -f "$(DEPDIR)/maxloc1_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_i8.c' object='maxloc1_8_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_i8.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_i8.o `test -f 'generated/maxloc1_8_i8.c' || echo '$(srcdir)/'`generated/maxloc1_8_i8.c + +maxloc1_8_i8.obj: generated/maxloc1_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_i8.obj -MD -MP -MF "$(DEPDIR)/maxloc1_8_i8.Tpo" -c -o maxloc1_8_i8.obj `if test -f 'generated/maxloc1_8_i8.c'; then $(CYGPATH_W) 'generated/maxloc1_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_i8.Tpo" "$(DEPDIR)/maxloc1_8_i8.Po"; else rm -f "$(DEPDIR)/maxloc1_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_i8.c' object='maxloc1_8_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_i8.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_i8.obj `if test -f 'generated/maxloc1_8_i8.c'; then $(CYGPATH_W) 'generated/maxloc1_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_i8.c'; fi` + +maxloc1_8_i8.lo: generated/maxloc1_8_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_i8.lo -MD -MP -MF "$(DEPDIR)/maxloc1_8_i8.Tpo" -c -o maxloc1_8_i8.lo `test -f 'generated/maxloc1_8_i8.c' || echo '$(srcdir)/'`generated/maxloc1_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_i8.Tpo" "$(DEPDIR)/maxloc1_8_i8.Plo"; else rm -f "$(DEPDIR)/maxloc1_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_i8.c' object='maxloc1_8_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_i8.Plo' tmpdepfile='$(DEPDIR)/maxloc1_8_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_i8.lo `test -f 'generated/maxloc1_8_i8.c' || echo '$(srcdir)/'`generated/maxloc1_8_i8.c + +maxloc1_4_r4.o: generated/maxloc1_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_r4.o -MD -MP -MF "$(DEPDIR)/maxloc1_4_r4.Tpo" -c -o maxloc1_4_r4.o `test -f 'generated/maxloc1_4_r4.c' || echo '$(srcdir)/'`generated/maxloc1_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_r4.Tpo" "$(DEPDIR)/maxloc1_4_r4.Po"; else rm -f "$(DEPDIR)/maxloc1_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_r4.c' object='maxloc1_4_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_r4.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_r4.o `test -f 'generated/maxloc1_4_r4.c' || echo '$(srcdir)/'`generated/maxloc1_4_r4.c + +maxloc1_4_r4.obj: generated/maxloc1_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_r4.obj -MD -MP -MF "$(DEPDIR)/maxloc1_4_r4.Tpo" -c -o maxloc1_4_r4.obj `if test -f 'generated/maxloc1_4_r4.c'; then $(CYGPATH_W) 'generated/maxloc1_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_r4.Tpo" "$(DEPDIR)/maxloc1_4_r4.Po"; else rm -f "$(DEPDIR)/maxloc1_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_r4.c' object='maxloc1_4_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_r4.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_r4.obj `if test -f 'generated/maxloc1_4_r4.c'; then $(CYGPATH_W) 'generated/maxloc1_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_r4.c'; fi` + +maxloc1_4_r4.lo: generated/maxloc1_4_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_r4.lo -MD -MP -MF "$(DEPDIR)/maxloc1_4_r4.Tpo" -c -o maxloc1_4_r4.lo `test -f 'generated/maxloc1_4_r4.c' || echo '$(srcdir)/'`generated/maxloc1_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_r4.Tpo" "$(DEPDIR)/maxloc1_4_r4.Plo"; else rm -f "$(DEPDIR)/maxloc1_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_r4.c' object='maxloc1_4_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_r4.Plo' tmpdepfile='$(DEPDIR)/maxloc1_4_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_r4.lo `test -f 'generated/maxloc1_4_r4.c' || echo '$(srcdir)/'`generated/maxloc1_4_r4.c + +maxloc1_8_r4.o: generated/maxloc1_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_r4.o -MD -MP -MF "$(DEPDIR)/maxloc1_8_r4.Tpo" -c -o maxloc1_8_r4.o `test -f 'generated/maxloc1_8_r4.c' || echo '$(srcdir)/'`generated/maxloc1_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_r4.Tpo" "$(DEPDIR)/maxloc1_8_r4.Po"; else rm -f "$(DEPDIR)/maxloc1_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_r4.c' object='maxloc1_8_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_r4.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_r4.o `test -f 'generated/maxloc1_8_r4.c' || echo '$(srcdir)/'`generated/maxloc1_8_r4.c + +maxloc1_8_r4.obj: generated/maxloc1_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_r4.obj -MD -MP -MF "$(DEPDIR)/maxloc1_8_r4.Tpo" -c -o maxloc1_8_r4.obj `if test -f 'generated/maxloc1_8_r4.c'; then $(CYGPATH_W) 'generated/maxloc1_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_r4.Tpo" "$(DEPDIR)/maxloc1_8_r4.Po"; else rm -f "$(DEPDIR)/maxloc1_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_r4.c' object='maxloc1_8_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_r4.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_r4.obj `if test -f 'generated/maxloc1_8_r4.c'; then $(CYGPATH_W) 'generated/maxloc1_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_r4.c'; fi` + +maxloc1_8_r4.lo: generated/maxloc1_8_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_r4.lo -MD -MP -MF "$(DEPDIR)/maxloc1_8_r4.Tpo" -c -o maxloc1_8_r4.lo `test -f 'generated/maxloc1_8_r4.c' || echo '$(srcdir)/'`generated/maxloc1_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_r4.Tpo" "$(DEPDIR)/maxloc1_8_r4.Plo"; else rm -f "$(DEPDIR)/maxloc1_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_r4.c' object='maxloc1_8_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_r4.Plo' tmpdepfile='$(DEPDIR)/maxloc1_8_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_r4.lo `test -f 'generated/maxloc1_8_r4.c' || echo '$(srcdir)/'`generated/maxloc1_8_r4.c + +maxloc1_4_r8.o: generated/maxloc1_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_r8.o -MD -MP -MF "$(DEPDIR)/maxloc1_4_r8.Tpo" -c -o maxloc1_4_r8.o `test -f 'generated/maxloc1_4_r8.c' || echo '$(srcdir)/'`generated/maxloc1_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_r8.Tpo" "$(DEPDIR)/maxloc1_4_r8.Po"; else rm -f "$(DEPDIR)/maxloc1_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_r8.c' object='maxloc1_4_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_r8.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_r8.o `test -f 'generated/maxloc1_4_r8.c' || echo '$(srcdir)/'`generated/maxloc1_4_r8.c + +maxloc1_4_r8.obj: generated/maxloc1_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_r8.obj -MD -MP -MF "$(DEPDIR)/maxloc1_4_r8.Tpo" -c -o maxloc1_4_r8.obj `if test -f 'generated/maxloc1_4_r8.c'; then $(CYGPATH_W) 'generated/maxloc1_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_r8.Tpo" "$(DEPDIR)/maxloc1_4_r8.Po"; else rm -f "$(DEPDIR)/maxloc1_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_r8.c' object='maxloc1_4_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_r8.Po' tmpdepfile='$(DEPDIR)/maxloc1_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_r8.obj `if test -f 'generated/maxloc1_4_r8.c'; then $(CYGPATH_W) 'generated/maxloc1_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_4_r8.c'; fi` + +maxloc1_4_r8.lo: generated/maxloc1_4_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_4_r8.lo -MD -MP -MF "$(DEPDIR)/maxloc1_4_r8.Tpo" -c -o maxloc1_4_r8.lo `test -f 'generated/maxloc1_4_r8.c' || echo '$(srcdir)/'`generated/maxloc1_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_4_r8.Tpo" "$(DEPDIR)/maxloc1_4_r8.Plo"; else rm -f "$(DEPDIR)/maxloc1_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_4_r8.c' object='maxloc1_4_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_4_r8.Plo' tmpdepfile='$(DEPDIR)/maxloc1_4_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_4_r8.lo `test -f 'generated/maxloc1_4_r8.c' || echo '$(srcdir)/'`generated/maxloc1_4_r8.c + +maxloc1_8_r8.o: generated/maxloc1_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_r8.o -MD -MP -MF "$(DEPDIR)/maxloc1_8_r8.Tpo" -c -o maxloc1_8_r8.o `test -f 'generated/maxloc1_8_r8.c' || echo '$(srcdir)/'`generated/maxloc1_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_r8.Tpo" "$(DEPDIR)/maxloc1_8_r8.Po"; else rm -f "$(DEPDIR)/maxloc1_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_r8.c' object='maxloc1_8_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_r8.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_r8.o `test -f 'generated/maxloc1_8_r8.c' || echo '$(srcdir)/'`generated/maxloc1_8_r8.c + +maxloc1_8_r8.obj: generated/maxloc1_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_r8.obj -MD -MP -MF "$(DEPDIR)/maxloc1_8_r8.Tpo" -c -o maxloc1_8_r8.obj `if test -f 'generated/maxloc1_8_r8.c'; then $(CYGPATH_W) 'generated/maxloc1_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_r8.Tpo" "$(DEPDIR)/maxloc1_8_r8.Po"; else rm -f "$(DEPDIR)/maxloc1_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_r8.c' object='maxloc1_8_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_r8.Po' tmpdepfile='$(DEPDIR)/maxloc1_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_r8.obj `if test -f 'generated/maxloc1_8_r8.c'; then $(CYGPATH_W) 'generated/maxloc1_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxloc1_8_r8.c'; fi` + +maxloc1_8_r8.lo: generated/maxloc1_8_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxloc1_8_r8.lo -MD -MP -MF "$(DEPDIR)/maxloc1_8_r8.Tpo" -c -o maxloc1_8_r8.lo `test -f 'generated/maxloc1_8_r8.c' || echo '$(srcdir)/'`generated/maxloc1_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxloc1_8_r8.Tpo" "$(DEPDIR)/maxloc1_8_r8.Plo"; else rm -f "$(DEPDIR)/maxloc1_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxloc1_8_r8.c' object='maxloc1_8_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxloc1_8_r8.Plo' tmpdepfile='$(DEPDIR)/maxloc1_8_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxloc1_8_r8.lo `test -f 'generated/maxloc1_8_r8.c' || echo '$(srcdir)/'`generated/maxloc1_8_r8.c + +maxval_i4.o: generated/maxval_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_i4.o -MD -MP -MF "$(DEPDIR)/maxval_i4.Tpo" -c -o maxval_i4.o `test -f 'generated/maxval_i4.c' || echo '$(srcdir)/'`generated/maxval_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_i4.Tpo" "$(DEPDIR)/maxval_i4.Po"; else rm -f "$(DEPDIR)/maxval_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_i4.c' object='maxval_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_i4.Po' tmpdepfile='$(DEPDIR)/maxval_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_i4.o `test -f 'generated/maxval_i4.c' || echo '$(srcdir)/'`generated/maxval_i4.c + +maxval_i4.obj: generated/maxval_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_i4.obj -MD -MP -MF "$(DEPDIR)/maxval_i4.Tpo" -c -o maxval_i4.obj `if test -f 'generated/maxval_i4.c'; then $(CYGPATH_W) 'generated/maxval_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_i4.Tpo" "$(DEPDIR)/maxval_i4.Po"; else rm -f "$(DEPDIR)/maxval_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_i4.c' object='maxval_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_i4.Po' tmpdepfile='$(DEPDIR)/maxval_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_i4.obj `if test -f 'generated/maxval_i4.c'; then $(CYGPATH_W) 'generated/maxval_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_i4.c'; fi` + +maxval_i4.lo: generated/maxval_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_i4.lo -MD -MP -MF "$(DEPDIR)/maxval_i4.Tpo" -c -o maxval_i4.lo `test -f 'generated/maxval_i4.c' || echo '$(srcdir)/'`generated/maxval_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_i4.Tpo" "$(DEPDIR)/maxval_i4.Plo"; else rm -f "$(DEPDIR)/maxval_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_i4.c' object='maxval_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_i4.Plo' tmpdepfile='$(DEPDIR)/maxval_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_i4.lo `test -f 'generated/maxval_i4.c' || echo '$(srcdir)/'`generated/maxval_i4.c + +maxval_i8.o: generated/maxval_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_i8.o -MD -MP -MF "$(DEPDIR)/maxval_i8.Tpo" -c -o maxval_i8.o `test -f 'generated/maxval_i8.c' || echo '$(srcdir)/'`generated/maxval_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_i8.Tpo" "$(DEPDIR)/maxval_i8.Po"; else rm -f "$(DEPDIR)/maxval_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_i8.c' object='maxval_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_i8.Po' tmpdepfile='$(DEPDIR)/maxval_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_i8.o `test -f 'generated/maxval_i8.c' || echo '$(srcdir)/'`generated/maxval_i8.c + +maxval_i8.obj: generated/maxval_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_i8.obj -MD -MP -MF "$(DEPDIR)/maxval_i8.Tpo" -c -o maxval_i8.obj `if test -f 'generated/maxval_i8.c'; then $(CYGPATH_W) 'generated/maxval_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_i8.Tpo" "$(DEPDIR)/maxval_i8.Po"; else rm -f "$(DEPDIR)/maxval_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_i8.c' object='maxval_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_i8.Po' tmpdepfile='$(DEPDIR)/maxval_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_i8.obj `if test -f 'generated/maxval_i8.c'; then $(CYGPATH_W) 'generated/maxval_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_i8.c'; fi` + +maxval_i8.lo: generated/maxval_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_i8.lo -MD -MP -MF "$(DEPDIR)/maxval_i8.Tpo" -c -o maxval_i8.lo `test -f 'generated/maxval_i8.c' || echo '$(srcdir)/'`generated/maxval_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_i8.Tpo" "$(DEPDIR)/maxval_i8.Plo"; else rm -f "$(DEPDIR)/maxval_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_i8.c' object='maxval_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_i8.Plo' tmpdepfile='$(DEPDIR)/maxval_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_i8.lo `test -f 'generated/maxval_i8.c' || echo '$(srcdir)/'`generated/maxval_i8.c + +maxval_r4.o: generated/maxval_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_r4.o -MD -MP -MF "$(DEPDIR)/maxval_r4.Tpo" -c -o maxval_r4.o `test -f 'generated/maxval_r4.c' || echo '$(srcdir)/'`generated/maxval_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_r4.Tpo" "$(DEPDIR)/maxval_r4.Po"; else rm -f "$(DEPDIR)/maxval_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_r4.c' object='maxval_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_r4.Po' tmpdepfile='$(DEPDIR)/maxval_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_r4.o `test -f 'generated/maxval_r4.c' || echo '$(srcdir)/'`generated/maxval_r4.c + +maxval_r4.obj: generated/maxval_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_r4.obj -MD -MP -MF "$(DEPDIR)/maxval_r4.Tpo" -c -o maxval_r4.obj `if test -f 'generated/maxval_r4.c'; then $(CYGPATH_W) 'generated/maxval_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_r4.Tpo" "$(DEPDIR)/maxval_r4.Po"; else rm -f "$(DEPDIR)/maxval_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_r4.c' object='maxval_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_r4.Po' tmpdepfile='$(DEPDIR)/maxval_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_r4.obj `if test -f 'generated/maxval_r4.c'; then $(CYGPATH_W) 'generated/maxval_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_r4.c'; fi` + +maxval_r4.lo: generated/maxval_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_r4.lo -MD -MP -MF "$(DEPDIR)/maxval_r4.Tpo" -c -o maxval_r4.lo `test -f 'generated/maxval_r4.c' || echo '$(srcdir)/'`generated/maxval_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_r4.Tpo" "$(DEPDIR)/maxval_r4.Plo"; else rm -f "$(DEPDIR)/maxval_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_r4.c' object='maxval_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_r4.Plo' tmpdepfile='$(DEPDIR)/maxval_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_r4.lo `test -f 'generated/maxval_r4.c' || echo '$(srcdir)/'`generated/maxval_r4.c + +maxval_r8.o: generated/maxval_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_r8.o -MD -MP -MF "$(DEPDIR)/maxval_r8.Tpo" -c -o maxval_r8.o `test -f 'generated/maxval_r8.c' || echo '$(srcdir)/'`generated/maxval_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_r8.Tpo" "$(DEPDIR)/maxval_r8.Po"; else rm -f "$(DEPDIR)/maxval_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_r8.c' object='maxval_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_r8.Po' tmpdepfile='$(DEPDIR)/maxval_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_r8.o `test -f 'generated/maxval_r8.c' || echo '$(srcdir)/'`generated/maxval_r8.c + +maxval_r8.obj: generated/maxval_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_r8.obj -MD -MP -MF "$(DEPDIR)/maxval_r8.Tpo" -c -o maxval_r8.obj `if test -f 'generated/maxval_r8.c'; then $(CYGPATH_W) 'generated/maxval_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_r8.Tpo" "$(DEPDIR)/maxval_r8.Po"; else rm -f "$(DEPDIR)/maxval_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_r8.c' object='maxval_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_r8.Po' tmpdepfile='$(DEPDIR)/maxval_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_r8.obj `if test -f 'generated/maxval_r8.c'; then $(CYGPATH_W) 'generated/maxval_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/maxval_r8.c'; fi` + +maxval_r8.lo: generated/maxval_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT maxval_r8.lo -MD -MP -MF "$(DEPDIR)/maxval_r8.Tpo" -c -o maxval_r8.lo `test -f 'generated/maxval_r8.c' || echo '$(srcdir)/'`generated/maxval_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/maxval_r8.Tpo" "$(DEPDIR)/maxval_r8.Plo"; else rm -f "$(DEPDIR)/maxval_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/maxval_r8.c' object='maxval_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/maxval_r8.Plo' tmpdepfile='$(DEPDIR)/maxval_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o maxval_r8.lo `test -f 'generated/maxval_r8.c' || echo '$(srcdir)/'`generated/maxval_r8.c + +minloc0_4_i4.o: generated/minloc0_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_i4.o -MD -MP -MF "$(DEPDIR)/minloc0_4_i4.Tpo" -c -o minloc0_4_i4.o `test -f 'generated/minloc0_4_i4.c' || echo '$(srcdir)/'`generated/minloc0_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_i4.Tpo" "$(DEPDIR)/minloc0_4_i4.Po"; else rm -f "$(DEPDIR)/minloc0_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_i4.c' object='minloc0_4_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_i4.Po' tmpdepfile='$(DEPDIR)/minloc0_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_i4.o `test -f 'generated/minloc0_4_i4.c' || echo '$(srcdir)/'`generated/minloc0_4_i4.c + +minloc0_4_i4.obj: generated/minloc0_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_i4.obj -MD -MP -MF "$(DEPDIR)/minloc0_4_i4.Tpo" -c -o minloc0_4_i4.obj `if test -f 'generated/minloc0_4_i4.c'; then $(CYGPATH_W) 'generated/minloc0_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_i4.Tpo" "$(DEPDIR)/minloc0_4_i4.Po"; else rm -f "$(DEPDIR)/minloc0_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_i4.c' object='minloc0_4_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_i4.Po' tmpdepfile='$(DEPDIR)/minloc0_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_i4.obj `if test -f 'generated/minloc0_4_i4.c'; then $(CYGPATH_W) 'generated/minloc0_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_i4.c'; fi` + +minloc0_4_i4.lo: generated/minloc0_4_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_i4.lo -MD -MP -MF "$(DEPDIR)/minloc0_4_i4.Tpo" -c -o minloc0_4_i4.lo `test -f 'generated/minloc0_4_i4.c' || echo '$(srcdir)/'`generated/minloc0_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_i4.Tpo" "$(DEPDIR)/minloc0_4_i4.Plo"; else rm -f "$(DEPDIR)/minloc0_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_i4.c' object='minloc0_4_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_i4.Plo' tmpdepfile='$(DEPDIR)/minloc0_4_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_i4.lo `test -f 'generated/minloc0_4_i4.c' || echo '$(srcdir)/'`generated/minloc0_4_i4.c + +minloc0_8_i4.o: generated/minloc0_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_i4.o -MD -MP -MF "$(DEPDIR)/minloc0_8_i4.Tpo" -c -o minloc0_8_i4.o `test -f 'generated/minloc0_8_i4.c' || echo '$(srcdir)/'`generated/minloc0_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_i4.Tpo" "$(DEPDIR)/minloc0_8_i4.Po"; else rm -f "$(DEPDIR)/minloc0_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_i4.c' object='minloc0_8_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_i4.Po' tmpdepfile='$(DEPDIR)/minloc0_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_i4.o `test -f 'generated/minloc0_8_i4.c' || echo '$(srcdir)/'`generated/minloc0_8_i4.c + +minloc0_8_i4.obj: generated/minloc0_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_i4.obj -MD -MP -MF "$(DEPDIR)/minloc0_8_i4.Tpo" -c -o minloc0_8_i4.obj `if test -f 'generated/minloc0_8_i4.c'; then $(CYGPATH_W) 'generated/minloc0_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_i4.Tpo" "$(DEPDIR)/minloc0_8_i4.Po"; else rm -f "$(DEPDIR)/minloc0_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_i4.c' object='minloc0_8_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_i4.Po' tmpdepfile='$(DEPDIR)/minloc0_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_i4.obj `if test -f 'generated/minloc0_8_i4.c'; then $(CYGPATH_W) 'generated/minloc0_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_i4.c'; fi` + +minloc0_8_i4.lo: generated/minloc0_8_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_i4.lo -MD -MP -MF "$(DEPDIR)/minloc0_8_i4.Tpo" -c -o minloc0_8_i4.lo `test -f 'generated/minloc0_8_i4.c' || echo '$(srcdir)/'`generated/minloc0_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_i4.Tpo" "$(DEPDIR)/minloc0_8_i4.Plo"; else rm -f "$(DEPDIR)/minloc0_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_i4.c' object='minloc0_8_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_i4.Plo' tmpdepfile='$(DEPDIR)/minloc0_8_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_i4.lo `test -f 'generated/minloc0_8_i4.c' || echo '$(srcdir)/'`generated/minloc0_8_i4.c + +minloc0_4_i8.o: generated/minloc0_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_i8.o -MD -MP -MF "$(DEPDIR)/minloc0_4_i8.Tpo" -c -o minloc0_4_i8.o `test -f 'generated/minloc0_4_i8.c' || echo '$(srcdir)/'`generated/minloc0_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_i8.Tpo" "$(DEPDIR)/minloc0_4_i8.Po"; else rm -f "$(DEPDIR)/minloc0_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_i8.c' object='minloc0_4_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_i8.Po' tmpdepfile='$(DEPDIR)/minloc0_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_i8.o `test -f 'generated/minloc0_4_i8.c' || echo '$(srcdir)/'`generated/minloc0_4_i8.c + +minloc0_4_i8.obj: generated/minloc0_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_i8.obj -MD -MP -MF "$(DEPDIR)/minloc0_4_i8.Tpo" -c -o minloc0_4_i8.obj `if test -f 'generated/minloc0_4_i8.c'; then $(CYGPATH_W) 'generated/minloc0_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_i8.Tpo" "$(DEPDIR)/minloc0_4_i8.Po"; else rm -f "$(DEPDIR)/minloc0_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_i8.c' object='minloc0_4_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_i8.Po' tmpdepfile='$(DEPDIR)/minloc0_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_i8.obj `if test -f 'generated/minloc0_4_i8.c'; then $(CYGPATH_W) 'generated/minloc0_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_i8.c'; fi` + +minloc0_4_i8.lo: generated/minloc0_4_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_i8.lo -MD -MP -MF "$(DEPDIR)/minloc0_4_i8.Tpo" -c -o minloc0_4_i8.lo `test -f 'generated/minloc0_4_i8.c' || echo '$(srcdir)/'`generated/minloc0_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_i8.Tpo" "$(DEPDIR)/minloc0_4_i8.Plo"; else rm -f "$(DEPDIR)/minloc0_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_i8.c' object='minloc0_4_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_i8.Plo' tmpdepfile='$(DEPDIR)/minloc0_4_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_i8.lo `test -f 'generated/minloc0_4_i8.c' || echo '$(srcdir)/'`generated/minloc0_4_i8.c + +minloc0_8_i8.o: generated/minloc0_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_i8.o -MD -MP -MF "$(DEPDIR)/minloc0_8_i8.Tpo" -c -o minloc0_8_i8.o `test -f 'generated/minloc0_8_i8.c' || echo '$(srcdir)/'`generated/minloc0_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_i8.Tpo" "$(DEPDIR)/minloc0_8_i8.Po"; else rm -f "$(DEPDIR)/minloc0_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_i8.c' object='minloc0_8_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_i8.Po' tmpdepfile='$(DEPDIR)/minloc0_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_i8.o `test -f 'generated/minloc0_8_i8.c' || echo '$(srcdir)/'`generated/minloc0_8_i8.c + +minloc0_8_i8.obj: generated/minloc0_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_i8.obj -MD -MP -MF "$(DEPDIR)/minloc0_8_i8.Tpo" -c -o minloc0_8_i8.obj `if test -f 'generated/minloc0_8_i8.c'; then $(CYGPATH_W) 'generated/minloc0_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_i8.Tpo" "$(DEPDIR)/minloc0_8_i8.Po"; else rm -f "$(DEPDIR)/minloc0_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_i8.c' object='minloc0_8_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_i8.Po' tmpdepfile='$(DEPDIR)/minloc0_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_i8.obj `if test -f 'generated/minloc0_8_i8.c'; then $(CYGPATH_W) 'generated/minloc0_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_i8.c'; fi` + +minloc0_8_i8.lo: generated/minloc0_8_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_i8.lo -MD -MP -MF "$(DEPDIR)/minloc0_8_i8.Tpo" -c -o minloc0_8_i8.lo `test -f 'generated/minloc0_8_i8.c' || echo '$(srcdir)/'`generated/minloc0_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_i8.Tpo" "$(DEPDIR)/minloc0_8_i8.Plo"; else rm -f "$(DEPDIR)/minloc0_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_i8.c' object='minloc0_8_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_i8.Plo' tmpdepfile='$(DEPDIR)/minloc0_8_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_i8.lo `test -f 'generated/minloc0_8_i8.c' || echo '$(srcdir)/'`generated/minloc0_8_i8.c + +minloc0_4_r4.o: generated/minloc0_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_r4.o -MD -MP -MF "$(DEPDIR)/minloc0_4_r4.Tpo" -c -o minloc0_4_r4.o `test -f 'generated/minloc0_4_r4.c' || echo '$(srcdir)/'`generated/minloc0_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_r4.Tpo" "$(DEPDIR)/minloc0_4_r4.Po"; else rm -f "$(DEPDIR)/minloc0_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_r4.c' object='minloc0_4_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_r4.Po' tmpdepfile='$(DEPDIR)/minloc0_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_r4.o `test -f 'generated/minloc0_4_r4.c' || echo '$(srcdir)/'`generated/minloc0_4_r4.c + +minloc0_4_r4.obj: generated/minloc0_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_r4.obj -MD -MP -MF "$(DEPDIR)/minloc0_4_r4.Tpo" -c -o minloc0_4_r4.obj `if test -f 'generated/minloc0_4_r4.c'; then $(CYGPATH_W) 'generated/minloc0_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_r4.Tpo" "$(DEPDIR)/minloc0_4_r4.Po"; else rm -f "$(DEPDIR)/minloc0_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_r4.c' object='minloc0_4_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_r4.Po' tmpdepfile='$(DEPDIR)/minloc0_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_r4.obj `if test -f 'generated/minloc0_4_r4.c'; then $(CYGPATH_W) 'generated/minloc0_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_r4.c'; fi` + +minloc0_4_r4.lo: generated/minloc0_4_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_r4.lo -MD -MP -MF "$(DEPDIR)/minloc0_4_r4.Tpo" -c -o minloc0_4_r4.lo `test -f 'generated/minloc0_4_r4.c' || echo '$(srcdir)/'`generated/minloc0_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_r4.Tpo" "$(DEPDIR)/minloc0_4_r4.Plo"; else rm -f "$(DEPDIR)/minloc0_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_r4.c' object='minloc0_4_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_r4.Plo' tmpdepfile='$(DEPDIR)/minloc0_4_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_r4.lo `test -f 'generated/minloc0_4_r4.c' || echo '$(srcdir)/'`generated/minloc0_4_r4.c + +minloc0_8_r4.o: generated/minloc0_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_r4.o -MD -MP -MF "$(DEPDIR)/minloc0_8_r4.Tpo" -c -o minloc0_8_r4.o `test -f 'generated/minloc0_8_r4.c' || echo '$(srcdir)/'`generated/minloc0_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_r4.Tpo" "$(DEPDIR)/minloc0_8_r4.Po"; else rm -f "$(DEPDIR)/minloc0_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_r4.c' object='minloc0_8_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_r4.Po' tmpdepfile='$(DEPDIR)/minloc0_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_r4.o `test -f 'generated/minloc0_8_r4.c' || echo '$(srcdir)/'`generated/minloc0_8_r4.c + +minloc0_8_r4.obj: generated/minloc0_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_r4.obj -MD -MP -MF "$(DEPDIR)/minloc0_8_r4.Tpo" -c -o minloc0_8_r4.obj `if test -f 'generated/minloc0_8_r4.c'; then $(CYGPATH_W) 'generated/minloc0_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_r4.Tpo" "$(DEPDIR)/minloc0_8_r4.Po"; else rm -f "$(DEPDIR)/minloc0_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_r4.c' object='minloc0_8_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_r4.Po' tmpdepfile='$(DEPDIR)/minloc0_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_r4.obj `if test -f 'generated/minloc0_8_r4.c'; then $(CYGPATH_W) 'generated/minloc0_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_r4.c'; fi` + +minloc0_8_r4.lo: generated/minloc0_8_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_r4.lo -MD -MP -MF "$(DEPDIR)/minloc0_8_r4.Tpo" -c -o minloc0_8_r4.lo `test -f 'generated/minloc0_8_r4.c' || echo '$(srcdir)/'`generated/minloc0_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_r4.Tpo" "$(DEPDIR)/minloc0_8_r4.Plo"; else rm -f "$(DEPDIR)/minloc0_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_r4.c' object='minloc0_8_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_r4.Plo' tmpdepfile='$(DEPDIR)/minloc0_8_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_r4.lo `test -f 'generated/minloc0_8_r4.c' || echo '$(srcdir)/'`generated/minloc0_8_r4.c + +minloc0_4_r8.o: generated/minloc0_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_r8.o -MD -MP -MF "$(DEPDIR)/minloc0_4_r8.Tpo" -c -o minloc0_4_r8.o `test -f 'generated/minloc0_4_r8.c' || echo '$(srcdir)/'`generated/minloc0_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_r8.Tpo" "$(DEPDIR)/minloc0_4_r8.Po"; else rm -f "$(DEPDIR)/minloc0_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_r8.c' object='minloc0_4_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_r8.Po' tmpdepfile='$(DEPDIR)/minloc0_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_r8.o `test -f 'generated/minloc0_4_r8.c' || echo '$(srcdir)/'`generated/minloc0_4_r8.c + +minloc0_4_r8.obj: generated/minloc0_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_r8.obj -MD -MP -MF "$(DEPDIR)/minloc0_4_r8.Tpo" -c -o minloc0_4_r8.obj `if test -f 'generated/minloc0_4_r8.c'; then $(CYGPATH_W) 'generated/minloc0_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_r8.Tpo" "$(DEPDIR)/minloc0_4_r8.Po"; else rm -f "$(DEPDIR)/minloc0_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_r8.c' object='minloc0_4_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_r8.Po' tmpdepfile='$(DEPDIR)/minloc0_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_r8.obj `if test -f 'generated/minloc0_4_r8.c'; then $(CYGPATH_W) 'generated/minloc0_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_4_r8.c'; fi` + +minloc0_4_r8.lo: generated/minloc0_4_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_4_r8.lo -MD -MP -MF "$(DEPDIR)/minloc0_4_r8.Tpo" -c -o minloc0_4_r8.lo `test -f 'generated/minloc0_4_r8.c' || echo '$(srcdir)/'`generated/minloc0_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_4_r8.Tpo" "$(DEPDIR)/minloc0_4_r8.Plo"; else rm -f "$(DEPDIR)/minloc0_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_4_r8.c' object='minloc0_4_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_4_r8.Plo' tmpdepfile='$(DEPDIR)/minloc0_4_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_4_r8.lo `test -f 'generated/minloc0_4_r8.c' || echo '$(srcdir)/'`generated/minloc0_4_r8.c + +minloc0_8_r8.o: generated/minloc0_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_r8.o -MD -MP -MF "$(DEPDIR)/minloc0_8_r8.Tpo" -c -o minloc0_8_r8.o `test -f 'generated/minloc0_8_r8.c' || echo '$(srcdir)/'`generated/minloc0_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_r8.Tpo" "$(DEPDIR)/minloc0_8_r8.Po"; else rm -f "$(DEPDIR)/minloc0_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_r8.c' object='minloc0_8_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_r8.Po' tmpdepfile='$(DEPDIR)/minloc0_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_r8.o `test -f 'generated/minloc0_8_r8.c' || echo '$(srcdir)/'`generated/minloc0_8_r8.c + +minloc0_8_r8.obj: generated/minloc0_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_r8.obj -MD -MP -MF "$(DEPDIR)/minloc0_8_r8.Tpo" -c -o minloc0_8_r8.obj `if test -f 'generated/minloc0_8_r8.c'; then $(CYGPATH_W) 'generated/minloc0_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_r8.Tpo" "$(DEPDIR)/minloc0_8_r8.Po"; else rm -f "$(DEPDIR)/minloc0_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_r8.c' object='minloc0_8_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_r8.Po' tmpdepfile='$(DEPDIR)/minloc0_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_r8.obj `if test -f 'generated/minloc0_8_r8.c'; then $(CYGPATH_W) 'generated/minloc0_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc0_8_r8.c'; fi` + +minloc0_8_r8.lo: generated/minloc0_8_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc0_8_r8.lo -MD -MP -MF "$(DEPDIR)/minloc0_8_r8.Tpo" -c -o minloc0_8_r8.lo `test -f 'generated/minloc0_8_r8.c' || echo '$(srcdir)/'`generated/minloc0_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc0_8_r8.Tpo" "$(DEPDIR)/minloc0_8_r8.Plo"; else rm -f "$(DEPDIR)/minloc0_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc0_8_r8.c' object='minloc0_8_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc0_8_r8.Plo' tmpdepfile='$(DEPDIR)/minloc0_8_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc0_8_r8.lo `test -f 'generated/minloc0_8_r8.c' || echo '$(srcdir)/'`generated/minloc0_8_r8.c + +minloc1_4_i4.o: generated/minloc1_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_i4.o -MD -MP -MF "$(DEPDIR)/minloc1_4_i4.Tpo" -c -o minloc1_4_i4.o `test -f 'generated/minloc1_4_i4.c' || echo '$(srcdir)/'`generated/minloc1_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_i4.Tpo" "$(DEPDIR)/minloc1_4_i4.Po"; else rm -f "$(DEPDIR)/minloc1_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_i4.c' object='minloc1_4_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_i4.Po' tmpdepfile='$(DEPDIR)/minloc1_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_i4.o `test -f 'generated/minloc1_4_i4.c' || echo '$(srcdir)/'`generated/minloc1_4_i4.c + +minloc1_4_i4.obj: generated/minloc1_4_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_i4.obj -MD -MP -MF "$(DEPDIR)/minloc1_4_i4.Tpo" -c -o minloc1_4_i4.obj `if test -f 'generated/minloc1_4_i4.c'; then $(CYGPATH_W) 'generated/minloc1_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_i4.Tpo" "$(DEPDIR)/minloc1_4_i4.Po"; else rm -f "$(DEPDIR)/minloc1_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_i4.c' object='minloc1_4_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_i4.Po' tmpdepfile='$(DEPDIR)/minloc1_4_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_i4.obj `if test -f 'generated/minloc1_4_i4.c'; then $(CYGPATH_W) 'generated/minloc1_4_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_i4.c'; fi` + +minloc1_4_i4.lo: generated/minloc1_4_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_i4.lo -MD -MP -MF "$(DEPDIR)/minloc1_4_i4.Tpo" -c -o minloc1_4_i4.lo `test -f 'generated/minloc1_4_i4.c' || echo '$(srcdir)/'`generated/minloc1_4_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_i4.Tpo" "$(DEPDIR)/minloc1_4_i4.Plo"; else rm -f "$(DEPDIR)/minloc1_4_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_i4.c' object='minloc1_4_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_i4.Plo' tmpdepfile='$(DEPDIR)/minloc1_4_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_i4.lo `test -f 'generated/minloc1_4_i4.c' || echo '$(srcdir)/'`generated/minloc1_4_i4.c + +minloc1_8_i4.o: generated/minloc1_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_i4.o -MD -MP -MF "$(DEPDIR)/minloc1_8_i4.Tpo" -c -o minloc1_8_i4.o `test -f 'generated/minloc1_8_i4.c' || echo '$(srcdir)/'`generated/minloc1_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_i4.Tpo" "$(DEPDIR)/minloc1_8_i4.Po"; else rm -f "$(DEPDIR)/minloc1_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_i4.c' object='minloc1_8_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_i4.Po' tmpdepfile='$(DEPDIR)/minloc1_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_i4.o `test -f 'generated/minloc1_8_i4.c' || echo '$(srcdir)/'`generated/minloc1_8_i4.c + +minloc1_8_i4.obj: generated/minloc1_8_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_i4.obj -MD -MP -MF "$(DEPDIR)/minloc1_8_i4.Tpo" -c -o minloc1_8_i4.obj `if test -f 'generated/minloc1_8_i4.c'; then $(CYGPATH_W) 'generated/minloc1_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_i4.Tpo" "$(DEPDIR)/minloc1_8_i4.Po"; else rm -f "$(DEPDIR)/minloc1_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_i4.c' object='minloc1_8_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_i4.Po' tmpdepfile='$(DEPDIR)/minloc1_8_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_i4.obj `if test -f 'generated/minloc1_8_i4.c'; then $(CYGPATH_W) 'generated/minloc1_8_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_i4.c'; fi` + +minloc1_8_i4.lo: generated/minloc1_8_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_i4.lo -MD -MP -MF "$(DEPDIR)/minloc1_8_i4.Tpo" -c -o minloc1_8_i4.lo `test -f 'generated/minloc1_8_i4.c' || echo '$(srcdir)/'`generated/minloc1_8_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_i4.Tpo" "$(DEPDIR)/minloc1_8_i4.Plo"; else rm -f "$(DEPDIR)/minloc1_8_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_i4.c' object='minloc1_8_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_i4.Plo' tmpdepfile='$(DEPDIR)/minloc1_8_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_i4.lo `test -f 'generated/minloc1_8_i4.c' || echo '$(srcdir)/'`generated/minloc1_8_i4.c + +minloc1_4_i8.o: generated/minloc1_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_i8.o -MD -MP -MF "$(DEPDIR)/minloc1_4_i8.Tpo" -c -o minloc1_4_i8.o `test -f 'generated/minloc1_4_i8.c' || echo '$(srcdir)/'`generated/minloc1_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_i8.Tpo" "$(DEPDIR)/minloc1_4_i8.Po"; else rm -f "$(DEPDIR)/minloc1_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_i8.c' object='minloc1_4_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_i8.Po' tmpdepfile='$(DEPDIR)/minloc1_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_i8.o `test -f 'generated/minloc1_4_i8.c' || echo '$(srcdir)/'`generated/minloc1_4_i8.c + +minloc1_4_i8.obj: generated/minloc1_4_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_i8.obj -MD -MP -MF "$(DEPDIR)/minloc1_4_i8.Tpo" -c -o minloc1_4_i8.obj `if test -f 'generated/minloc1_4_i8.c'; then $(CYGPATH_W) 'generated/minloc1_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_i8.Tpo" "$(DEPDIR)/minloc1_4_i8.Po"; else rm -f "$(DEPDIR)/minloc1_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_i8.c' object='minloc1_4_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_i8.Po' tmpdepfile='$(DEPDIR)/minloc1_4_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_i8.obj `if test -f 'generated/minloc1_4_i8.c'; then $(CYGPATH_W) 'generated/minloc1_4_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_i8.c'; fi` + +minloc1_4_i8.lo: generated/minloc1_4_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_i8.lo -MD -MP -MF "$(DEPDIR)/minloc1_4_i8.Tpo" -c -o minloc1_4_i8.lo `test -f 'generated/minloc1_4_i8.c' || echo '$(srcdir)/'`generated/minloc1_4_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_i8.Tpo" "$(DEPDIR)/minloc1_4_i8.Plo"; else rm -f "$(DEPDIR)/minloc1_4_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_i8.c' object='minloc1_4_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_i8.Plo' tmpdepfile='$(DEPDIR)/minloc1_4_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_i8.lo `test -f 'generated/minloc1_4_i8.c' || echo '$(srcdir)/'`generated/minloc1_4_i8.c + +minloc1_8_i8.o: generated/minloc1_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_i8.o -MD -MP -MF "$(DEPDIR)/minloc1_8_i8.Tpo" -c -o minloc1_8_i8.o `test -f 'generated/minloc1_8_i8.c' || echo '$(srcdir)/'`generated/minloc1_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_i8.Tpo" "$(DEPDIR)/minloc1_8_i8.Po"; else rm -f "$(DEPDIR)/minloc1_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_i8.c' object='minloc1_8_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_i8.Po' tmpdepfile='$(DEPDIR)/minloc1_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_i8.o `test -f 'generated/minloc1_8_i8.c' || echo '$(srcdir)/'`generated/minloc1_8_i8.c + +minloc1_8_i8.obj: generated/minloc1_8_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_i8.obj -MD -MP -MF "$(DEPDIR)/minloc1_8_i8.Tpo" -c -o minloc1_8_i8.obj `if test -f 'generated/minloc1_8_i8.c'; then $(CYGPATH_W) 'generated/minloc1_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_i8.Tpo" "$(DEPDIR)/minloc1_8_i8.Po"; else rm -f "$(DEPDIR)/minloc1_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_i8.c' object='minloc1_8_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_i8.Po' tmpdepfile='$(DEPDIR)/minloc1_8_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_i8.obj `if test -f 'generated/minloc1_8_i8.c'; then $(CYGPATH_W) 'generated/minloc1_8_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_i8.c'; fi` + +minloc1_8_i8.lo: generated/minloc1_8_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_i8.lo -MD -MP -MF "$(DEPDIR)/minloc1_8_i8.Tpo" -c -o minloc1_8_i8.lo `test -f 'generated/minloc1_8_i8.c' || echo '$(srcdir)/'`generated/minloc1_8_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_i8.Tpo" "$(DEPDIR)/minloc1_8_i8.Plo"; else rm -f "$(DEPDIR)/minloc1_8_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_i8.c' object='minloc1_8_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_i8.Plo' tmpdepfile='$(DEPDIR)/minloc1_8_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_i8.lo `test -f 'generated/minloc1_8_i8.c' || echo '$(srcdir)/'`generated/minloc1_8_i8.c + +minloc1_4_r4.o: generated/minloc1_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_r4.o -MD -MP -MF "$(DEPDIR)/minloc1_4_r4.Tpo" -c -o minloc1_4_r4.o `test -f 'generated/minloc1_4_r4.c' || echo '$(srcdir)/'`generated/minloc1_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_r4.Tpo" "$(DEPDIR)/minloc1_4_r4.Po"; else rm -f "$(DEPDIR)/minloc1_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_r4.c' object='minloc1_4_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_r4.Po' tmpdepfile='$(DEPDIR)/minloc1_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_r4.o `test -f 'generated/minloc1_4_r4.c' || echo '$(srcdir)/'`generated/minloc1_4_r4.c + +minloc1_4_r4.obj: generated/minloc1_4_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_r4.obj -MD -MP -MF "$(DEPDIR)/minloc1_4_r4.Tpo" -c -o minloc1_4_r4.obj `if test -f 'generated/minloc1_4_r4.c'; then $(CYGPATH_W) 'generated/minloc1_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_r4.Tpo" "$(DEPDIR)/minloc1_4_r4.Po"; else rm -f "$(DEPDIR)/minloc1_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_r4.c' object='minloc1_4_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_r4.Po' tmpdepfile='$(DEPDIR)/minloc1_4_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_r4.obj `if test -f 'generated/minloc1_4_r4.c'; then $(CYGPATH_W) 'generated/minloc1_4_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_r4.c'; fi` + +minloc1_4_r4.lo: generated/minloc1_4_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_r4.lo -MD -MP -MF "$(DEPDIR)/minloc1_4_r4.Tpo" -c -o minloc1_4_r4.lo `test -f 'generated/minloc1_4_r4.c' || echo '$(srcdir)/'`generated/minloc1_4_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_r4.Tpo" "$(DEPDIR)/minloc1_4_r4.Plo"; else rm -f "$(DEPDIR)/minloc1_4_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_r4.c' object='minloc1_4_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_r4.Plo' tmpdepfile='$(DEPDIR)/minloc1_4_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_r4.lo `test -f 'generated/minloc1_4_r4.c' || echo '$(srcdir)/'`generated/minloc1_4_r4.c + +minloc1_8_r4.o: generated/minloc1_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_r4.o -MD -MP -MF "$(DEPDIR)/minloc1_8_r4.Tpo" -c -o minloc1_8_r4.o `test -f 'generated/minloc1_8_r4.c' || echo '$(srcdir)/'`generated/minloc1_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_r4.Tpo" "$(DEPDIR)/minloc1_8_r4.Po"; else rm -f "$(DEPDIR)/minloc1_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_r4.c' object='minloc1_8_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_r4.Po' tmpdepfile='$(DEPDIR)/minloc1_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_r4.o `test -f 'generated/minloc1_8_r4.c' || echo '$(srcdir)/'`generated/minloc1_8_r4.c + +minloc1_8_r4.obj: generated/minloc1_8_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_r4.obj -MD -MP -MF "$(DEPDIR)/minloc1_8_r4.Tpo" -c -o minloc1_8_r4.obj `if test -f 'generated/minloc1_8_r4.c'; then $(CYGPATH_W) 'generated/minloc1_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_r4.Tpo" "$(DEPDIR)/minloc1_8_r4.Po"; else rm -f "$(DEPDIR)/minloc1_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_r4.c' object='minloc1_8_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_r4.Po' tmpdepfile='$(DEPDIR)/minloc1_8_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_r4.obj `if test -f 'generated/minloc1_8_r4.c'; then $(CYGPATH_W) 'generated/minloc1_8_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_r4.c'; fi` + +minloc1_8_r4.lo: generated/minloc1_8_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_r4.lo -MD -MP -MF "$(DEPDIR)/minloc1_8_r4.Tpo" -c -o minloc1_8_r4.lo `test -f 'generated/minloc1_8_r4.c' || echo '$(srcdir)/'`generated/minloc1_8_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_r4.Tpo" "$(DEPDIR)/minloc1_8_r4.Plo"; else rm -f "$(DEPDIR)/minloc1_8_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_r4.c' object='minloc1_8_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_r4.Plo' tmpdepfile='$(DEPDIR)/minloc1_8_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_r4.lo `test -f 'generated/minloc1_8_r4.c' || echo '$(srcdir)/'`generated/minloc1_8_r4.c + +minloc1_4_r8.o: generated/minloc1_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_r8.o -MD -MP -MF "$(DEPDIR)/minloc1_4_r8.Tpo" -c -o minloc1_4_r8.o `test -f 'generated/minloc1_4_r8.c' || echo '$(srcdir)/'`generated/minloc1_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_r8.Tpo" "$(DEPDIR)/minloc1_4_r8.Po"; else rm -f "$(DEPDIR)/minloc1_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_r8.c' object='minloc1_4_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_r8.Po' tmpdepfile='$(DEPDIR)/minloc1_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_r8.o `test -f 'generated/minloc1_4_r8.c' || echo '$(srcdir)/'`generated/minloc1_4_r8.c + +minloc1_4_r8.obj: generated/minloc1_4_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_r8.obj -MD -MP -MF "$(DEPDIR)/minloc1_4_r8.Tpo" -c -o minloc1_4_r8.obj `if test -f 'generated/minloc1_4_r8.c'; then $(CYGPATH_W) 'generated/minloc1_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_r8.Tpo" "$(DEPDIR)/minloc1_4_r8.Po"; else rm -f "$(DEPDIR)/minloc1_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_r8.c' object='minloc1_4_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_r8.Po' tmpdepfile='$(DEPDIR)/minloc1_4_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_r8.obj `if test -f 'generated/minloc1_4_r8.c'; then $(CYGPATH_W) 'generated/minloc1_4_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_4_r8.c'; fi` + +minloc1_4_r8.lo: generated/minloc1_4_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_4_r8.lo -MD -MP -MF "$(DEPDIR)/minloc1_4_r8.Tpo" -c -o minloc1_4_r8.lo `test -f 'generated/minloc1_4_r8.c' || echo '$(srcdir)/'`generated/minloc1_4_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_4_r8.Tpo" "$(DEPDIR)/minloc1_4_r8.Plo"; else rm -f "$(DEPDIR)/minloc1_4_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_4_r8.c' object='minloc1_4_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_4_r8.Plo' tmpdepfile='$(DEPDIR)/minloc1_4_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_4_r8.lo `test -f 'generated/minloc1_4_r8.c' || echo '$(srcdir)/'`generated/minloc1_4_r8.c + +minloc1_8_r8.o: generated/minloc1_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_r8.o -MD -MP -MF "$(DEPDIR)/minloc1_8_r8.Tpo" -c -o minloc1_8_r8.o `test -f 'generated/minloc1_8_r8.c' || echo '$(srcdir)/'`generated/minloc1_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_r8.Tpo" "$(DEPDIR)/minloc1_8_r8.Po"; else rm -f "$(DEPDIR)/minloc1_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_r8.c' object='minloc1_8_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_r8.Po' tmpdepfile='$(DEPDIR)/minloc1_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_r8.o `test -f 'generated/minloc1_8_r8.c' || echo '$(srcdir)/'`generated/minloc1_8_r8.c + +minloc1_8_r8.obj: generated/minloc1_8_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_r8.obj -MD -MP -MF "$(DEPDIR)/minloc1_8_r8.Tpo" -c -o minloc1_8_r8.obj `if test -f 'generated/minloc1_8_r8.c'; then $(CYGPATH_W) 'generated/minloc1_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_r8.Tpo" "$(DEPDIR)/minloc1_8_r8.Po"; else rm -f "$(DEPDIR)/minloc1_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_r8.c' object='minloc1_8_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_r8.Po' tmpdepfile='$(DEPDIR)/minloc1_8_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_r8.obj `if test -f 'generated/minloc1_8_r8.c'; then $(CYGPATH_W) 'generated/minloc1_8_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minloc1_8_r8.c'; fi` + +minloc1_8_r8.lo: generated/minloc1_8_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minloc1_8_r8.lo -MD -MP -MF "$(DEPDIR)/minloc1_8_r8.Tpo" -c -o minloc1_8_r8.lo `test -f 'generated/minloc1_8_r8.c' || echo '$(srcdir)/'`generated/minloc1_8_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minloc1_8_r8.Tpo" "$(DEPDIR)/minloc1_8_r8.Plo"; else rm -f "$(DEPDIR)/minloc1_8_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minloc1_8_r8.c' object='minloc1_8_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minloc1_8_r8.Plo' tmpdepfile='$(DEPDIR)/minloc1_8_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minloc1_8_r8.lo `test -f 'generated/minloc1_8_r8.c' || echo '$(srcdir)/'`generated/minloc1_8_r8.c + +minval_i4.o: generated/minval_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_i4.o -MD -MP -MF "$(DEPDIR)/minval_i4.Tpo" -c -o minval_i4.o `test -f 'generated/minval_i4.c' || echo '$(srcdir)/'`generated/minval_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_i4.Tpo" "$(DEPDIR)/minval_i4.Po"; else rm -f "$(DEPDIR)/minval_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_i4.c' object='minval_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_i4.Po' tmpdepfile='$(DEPDIR)/minval_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_i4.o `test -f 'generated/minval_i4.c' || echo '$(srcdir)/'`generated/minval_i4.c + +minval_i4.obj: generated/minval_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_i4.obj -MD -MP -MF "$(DEPDIR)/minval_i4.Tpo" -c -o minval_i4.obj `if test -f 'generated/minval_i4.c'; then $(CYGPATH_W) 'generated/minval_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_i4.Tpo" "$(DEPDIR)/minval_i4.Po"; else rm -f "$(DEPDIR)/minval_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_i4.c' object='minval_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_i4.Po' tmpdepfile='$(DEPDIR)/minval_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_i4.obj `if test -f 'generated/minval_i4.c'; then $(CYGPATH_W) 'generated/minval_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_i4.c'; fi` + +minval_i4.lo: generated/minval_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_i4.lo -MD -MP -MF "$(DEPDIR)/minval_i4.Tpo" -c -o minval_i4.lo `test -f 'generated/minval_i4.c' || echo '$(srcdir)/'`generated/minval_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_i4.Tpo" "$(DEPDIR)/minval_i4.Plo"; else rm -f "$(DEPDIR)/minval_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_i4.c' object='minval_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_i4.Plo' tmpdepfile='$(DEPDIR)/minval_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_i4.lo `test -f 'generated/minval_i4.c' || echo '$(srcdir)/'`generated/minval_i4.c + +minval_i8.o: generated/minval_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_i8.o -MD -MP -MF "$(DEPDIR)/minval_i8.Tpo" -c -o minval_i8.o `test -f 'generated/minval_i8.c' || echo '$(srcdir)/'`generated/minval_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_i8.Tpo" "$(DEPDIR)/minval_i8.Po"; else rm -f "$(DEPDIR)/minval_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_i8.c' object='minval_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_i8.Po' tmpdepfile='$(DEPDIR)/minval_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_i8.o `test -f 'generated/minval_i8.c' || echo '$(srcdir)/'`generated/minval_i8.c + +minval_i8.obj: generated/minval_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_i8.obj -MD -MP -MF "$(DEPDIR)/minval_i8.Tpo" -c -o minval_i8.obj `if test -f 'generated/minval_i8.c'; then $(CYGPATH_W) 'generated/minval_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_i8.Tpo" "$(DEPDIR)/minval_i8.Po"; else rm -f "$(DEPDIR)/minval_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_i8.c' object='minval_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_i8.Po' tmpdepfile='$(DEPDIR)/minval_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_i8.obj `if test -f 'generated/minval_i8.c'; then $(CYGPATH_W) 'generated/minval_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_i8.c'; fi` + +minval_i8.lo: generated/minval_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_i8.lo -MD -MP -MF "$(DEPDIR)/minval_i8.Tpo" -c -o minval_i8.lo `test -f 'generated/minval_i8.c' || echo '$(srcdir)/'`generated/minval_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_i8.Tpo" "$(DEPDIR)/minval_i8.Plo"; else rm -f "$(DEPDIR)/minval_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_i8.c' object='minval_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_i8.Plo' tmpdepfile='$(DEPDIR)/minval_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_i8.lo `test -f 'generated/minval_i8.c' || echo '$(srcdir)/'`generated/minval_i8.c + +minval_r4.o: generated/minval_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_r4.o -MD -MP -MF "$(DEPDIR)/minval_r4.Tpo" -c -o minval_r4.o `test -f 'generated/minval_r4.c' || echo '$(srcdir)/'`generated/minval_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_r4.Tpo" "$(DEPDIR)/minval_r4.Po"; else rm -f "$(DEPDIR)/minval_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_r4.c' object='minval_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_r4.Po' tmpdepfile='$(DEPDIR)/minval_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_r4.o `test -f 'generated/minval_r4.c' || echo '$(srcdir)/'`generated/minval_r4.c + +minval_r4.obj: generated/minval_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_r4.obj -MD -MP -MF "$(DEPDIR)/minval_r4.Tpo" -c -o minval_r4.obj `if test -f 'generated/minval_r4.c'; then $(CYGPATH_W) 'generated/minval_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_r4.Tpo" "$(DEPDIR)/minval_r4.Po"; else rm -f "$(DEPDIR)/minval_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_r4.c' object='minval_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_r4.Po' tmpdepfile='$(DEPDIR)/minval_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_r4.obj `if test -f 'generated/minval_r4.c'; then $(CYGPATH_W) 'generated/minval_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_r4.c'; fi` + +minval_r4.lo: generated/minval_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_r4.lo -MD -MP -MF "$(DEPDIR)/minval_r4.Tpo" -c -o minval_r4.lo `test -f 'generated/minval_r4.c' || echo '$(srcdir)/'`generated/minval_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_r4.Tpo" "$(DEPDIR)/minval_r4.Plo"; else rm -f "$(DEPDIR)/minval_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_r4.c' object='minval_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_r4.Plo' tmpdepfile='$(DEPDIR)/minval_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_r4.lo `test -f 'generated/minval_r4.c' || echo '$(srcdir)/'`generated/minval_r4.c + +minval_r8.o: generated/minval_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_r8.o -MD -MP -MF "$(DEPDIR)/minval_r8.Tpo" -c -o minval_r8.o `test -f 'generated/minval_r8.c' || echo '$(srcdir)/'`generated/minval_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_r8.Tpo" "$(DEPDIR)/minval_r8.Po"; else rm -f "$(DEPDIR)/minval_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_r8.c' object='minval_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_r8.Po' tmpdepfile='$(DEPDIR)/minval_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_r8.o `test -f 'generated/minval_r8.c' || echo '$(srcdir)/'`generated/minval_r8.c + +minval_r8.obj: generated/minval_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_r8.obj -MD -MP -MF "$(DEPDIR)/minval_r8.Tpo" -c -o minval_r8.obj `if test -f 'generated/minval_r8.c'; then $(CYGPATH_W) 'generated/minval_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_r8.Tpo" "$(DEPDIR)/minval_r8.Po"; else rm -f "$(DEPDIR)/minval_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_r8.c' object='minval_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_r8.Po' tmpdepfile='$(DEPDIR)/minval_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_r8.obj `if test -f 'generated/minval_r8.c'; then $(CYGPATH_W) 'generated/minval_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/minval_r8.c'; fi` + +minval_r8.lo: generated/minval_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minval_r8.lo -MD -MP -MF "$(DEPDIR)/minval_r8.Tpo" -c -o minval_r8.lo `test -f 'generated/minval_r8.c' || echo '$(srcdir)/'`generated/minval_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/minval_r8.Tpo" "$(DEPDIR)/minval_r8.Plo"; else rm -f "$(DEPDIR)/minval_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/minval_r8.c' object='minval_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/minval_r8.Plo' tmpdepfile='$(DEPDIR)/minval_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minval_r8.lo `test -f 'generated/minval_r8.c' || echo '$(srcdir)/'`generated/minval_r8.c + +product_i4.o: generated/product_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_i4.o -MD -MP -MF "$(DEPDIR)/product_i4.Tpo" -c -o product_i4.o `test -f 'generated/product_i4.c' || echo '$(srcdir)/'`generated/product_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_i4.Tpo" "$(DEPDIR)/product_i4.Po"; else rm -f "$(DEPDIR)/product_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_i4.c' object='product_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_i4.Po' tmpdepfile='$(DEPDIR)/product_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_i4.o `test -f 'generated/product_i4.c' || echo '$(srcdir)/'`generated/product_i4.c + +product_i4.obj: generated/product_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_i4.obj -MD -MP -MF "$(DEPDIR)/product_i4.Tpo" -c -o product_i4.obj `if test -f 'generated/product_i4.c'; then $(CYGPATH_W) 'generated/product_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_i4.Tpo" "$(DEPDIR)/product_i4.Po"; else rm -f "$(DEPDIR)/product_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_i4.c' object='product_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_i4.Po' tmpdepfile='$(DEPDIR)/product_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_i4.obj `if test -f 'generated/product_i4.c'; then $(CYGPATH_W) 'generated/product_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_i4.c'; fi` + +product_i4.lo: generated/product_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_i4.lo -MD -MP -MF "$(DEPDIR)/product_i4.Tpo" -c -o product_i4.lo `test -f 'generated/product_i4.c' || echo '$(srcdir)/'`generated/product_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_i4.Tpo" "$(DEPDIR)/product_i4.Plo"; else rm -f "$(DEPDIR)/product_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_i4.c' object='product_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_i4.Plo' tmpdepfile='$(DEPDIR)/product_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_i4.lo `test -f 'generated/product_i4.c' || echo '$(srcdir)/'`generated/product_i4.c + +product_i8.o: generated/product_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_i8.o -MD -MP -MF "$(DEPDIR)/product_i8.Tpo" -c -o product_i8.o `test -f 'generated/product_i8.c' || echo '$(srcdir)/'`generated/product_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_i8.Tpo" "$(DEPDIR)/product_i8.Po"; else rm -f "$(DEPDIR)/product_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_i8.c' object='product_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_i8.Po' tmpdepfile='$(DEPDIR)/product_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_i8.o `test -f 'generated/product_i8.c' || echo '$(srcdir)/'`generated/product_i8.c + +product_i8.obj: generated/product_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_i8.obj -MD -MP -MF "$(DEPDIR)/product_i8.Tpo" -c -o product_i8.obj `if test -f 'generated/product_i8.c'; then $(CYGPATH_W) 'generated/product_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_i8.Tpo" "$(DEPDIR)/product_i8.Po"; else rm -f "$(DEPDIR)/product_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_i8.c' object='product_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_i8.Po' tmpdepfile='$(DEPDIR)/product_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_i8.obj `if test -f 'generated/product_i8.c'; then $(CYGPATH_W) 'generated/product_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_i8.c'; fi` + +product_i8.lo: generated/product_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_i8.lo -MD -MP -MF "$(DEPDIR)/product_i8.Tpo" -c -o product_i8.lo `test -f 'generated/product_i8.c' || echo '$(srcdir)/'`generated/product_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_i8.Tpo" "$(DEPDIR)/product_i8.Plo"; else rm -f "$(DEPDIR)/product_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_i8.c' object='product_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_i8.Plo' tmpdepfile='$(DEPDIR)/product_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_i8.lo `test -f 'generated/product_i8.c' || echo '$(srcdir)/'`generated/product_i8.c + +product_r4.o: generated/product_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_r4.o -MD -MP -MF "$(DEPDIR)/product_r4.Tpo" -c -o product_r4.o `test -f 'generated/product_r4.c' || echo '$(srcdir)/'`generated/product_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_r4.Tpo" "$(DEPDIR)/product_r4.Po"; else rm -f "$(DEPDIR)/product_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_r4.c' object='product_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_r4.Po' tmpdepfile='$(DEPDIR)/product_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_r4.o `test -f 'generated/product_r4.c' || echo '$(srcdir)/'`generated/product_r4.c + +product_r4.obj: generated/product_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_r4.obj -MD -MP -MF "$(DEPDIR)/product_r4.Tpo" -c -o product_r4.obj `if test -f 'generated/product_r4.c'; then $(CYGPATH_W) 'generated/product_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_r4.Tpo" "$(DEPDIR)/product_r4.Po"; else rm -f "$(DEPDIR)/product_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_r4.c' object='product_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_r4.Po' tmpdepfile='$(DEPDIR)/product_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_r4.obj `if test -f 'generated/product_r4.c'; then $(CYGPATH_W) 'generated/product_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_r4.c'; fi` + +product_r4.lo: generated/product_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_r4.lo -MD -MP -MF "$(DEPDIR)/product_r4.Tpo" -c -o product_r4.lo `test -f 'generated/product_r4.c' || echo '$(srcdir)/'`generated/product_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_r4.Tpo" "$(DEPDIR)/product_r4.Plo"; else rm -f "$(DEPDIR)/product_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_r4.c' object='product_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_r4.Plo' tmpdepfile='$(DEPDIR)/product_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_r4.lo `test -f 'generated/product_r4.c' || echo '$(srcdir)/'`generated/product_r4.c + +product_r8.o: generated/product_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_r8.o -MD -MP -MF "$(DEPDIR)/product_r8.Tpo" -c -o product_r8.o `test -f 'generated/product_r8.c' || echo '$(srcdir)/'`generated/product_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_r8.Tpo" "$(DEPDIR)/product_r8.Po"; else rm -f "$(DEPDIR)/product_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_r8.c' object='product_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_r8.Po' tmpdepfile='$(DEPDIR)/product_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_r8.o `test -f 'generated/product_r8.c' || echo '$(srcdir)/'`generated/product_r8.c + +product_r8.obj: generated/product_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_r8.obj -MD -MP -MF "$(DEPDIR)/product_r8.Tpo" -c -o product_r8.obj `if test -f 'generated/product_r8.c'; then $(CYGPATH_W) 'generated/product_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_r8.Tpo" "$(DEPDIR)/product_r8.Po"; else rm -f "$(DEPDIR)/product_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_r8.c' object='product_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_r8.Po' tmpdepfile='$(DEPDIR)/product_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_r8.obj `if test -f 'generated/product_r8.c'; then $(CYGPATH_W) 'generated/product_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_r8.c'; fi` + +product_r8.lo: generated/product_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_r8.lo -MD -MP -MF "$(DEPDIR)/product_r8.Tpo" -c -o product_r8.lo `test -f 'generated/product_r8.c' || echo '$(srcdir)/'`generated/product_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_r8.Tpo" "$(DEPDIR)/product_r8.Plo"; else rm -f "$(DEPDIR)/product_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_r8.c' object='product_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_r8.Plo' tmpdepfile='$(DEPDIR)/product_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_r8.lo `test -f 'generated/product_r8.c' || echo '$(srcdir)/'`generated/product_r8.c + +product_c4.o: generated/product_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_c4.o -MD -MP -MF "$(DEPDIR)/product_c4.Tpo" -c -o product_c4.o `test -f 'generated/product_c4.c' || echo '$(srcdir)/'`generated/product_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_c4.Tpo" "$(DEPDIR)/product_c4.Po"; else rm -f "$(DEPDIR)/product_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_c4.c' object='product_c4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_c4.Po' tmpdepfile='$(DEPDIR)/product_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_c4.o `test -f 'generated/product_c4.c' || echo '$(srcdir)/'`generated/product_c4.c + +product_c4.obj: generated/product_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_c4.obj -MD -MP -MF "$(DEPDIR)/product_c4.Tpo" -c -o product_c4.obj `if test -f 'generated/product_c4.c'; then $(CYGPATH_W) 'generated/product_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_c4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_c4.Tpo" "$(DEPDIR)/product_c4.Po"; else rm -f "$(DEPDIR)/product_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_c4.c' object='product_c4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_c4.Po' tmpdepfile='$(DEPDIR)/product_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_c4.obj `if test -f 'generated/product_c4.c'; then $(CYGPATH_W) 'generated/product_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_c4.c'; fi` + +product_c4.lo: generated/product_c4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_c4.lo -MD -MP -MF "$(DEPDIR)/product_c4.Tpo" -c -o product_c4.lo `test -f 'generated/product_c4.c' || echo '$(srcdir)/'`generated/product_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_c4.Tpo" "$(DEPDIR)/product_c4.Plo"; else rm -f "$(DEPDIR)/product_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_c4.c' object='product_c4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_c4.Plo' tmpdepfile='$(DEPDIR)/product_c4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_c4.lo `test -f 'generated/product_c4.c' || echo '$(srcdir)/'`generated/product_c4.c + +product_c8.o: generated/product_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_c8.o -MD -MP -MF "$(DEPDIR)/product_c8.Tpo" -c -o product_c8.o `test -f 'generated/product_c8.c' || echo '$(srcdir)/'`generated/product_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_c8.Tpo" "$(DEPDIR)/product_c8.Po"; else rm -f "$(DEPDIR)/product_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_c8.c' object='product_c8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_c8.Po' tmpdepfile='$(DEPDIR)/product_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_c8.o `test -f 'generated/product_c8.c' || echo '$(srcdir)/'`generated/product_c8.c + +product_c8.obj: generated/product_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_c8.obj -MD -MP -MF "$(DEPDIR)/product_c8.Tpo" -c -o product_c8.obj `if test -f 'generated/product_c8.c'; then $(CYGPATH_W) 'generated/product_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_c8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_c8.Tpo" "$(DEPDIR)/product_c8.Po"; else rm -f "$(DEPDIR)/product_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_c8.c' object='product_c8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_c8.Po' tmpdepfile='$(DEPDIR)/product_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_c8.obj `if test -f 'generated/product_c8.c'; then $(CYGPATH_W) 'generated/product_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/product_c8.c'; fi` + +product_c8.lo: generated/product_c8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT product_c8.lo -MD -MP -MF "$(DEPDIR)/product_c8.Tpo" -c -o product_c8.lo `test -f 'generated/product_c8.c' || echo '$(srcdir)/'`generated/product_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/product_c8.Tpo" "$(DEPDIR)/product_c8.Plo"; else rm -f "$(DEPDIR)/product_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/product_c8.c' object='product_c8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/product_c8.Plo' tmpdepfile='$(DEPDIR)/product_c8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o product_c8.lo `test -f 'generated/product_c8.c' || echo '$(srcdir)/'`generated/product_c8.c + +sum_i4.o: generated/sum_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_i4.o -MD -MP -MF "$(DEPDIR)/sum_i4.Tpo" -c -o sum_i4.o `test -f 'generated/sum_i4.c' || echo '$(srcdir)/'`generated/sum_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_i4.Tpo" "$(DEPDIR)/sum_i4.Po"; else rm -f "$(DEPDIR)/sum_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_i4.c' object='sum_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_i4.Po' tmpdepfile='$(DEPDIR)/sum_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_i4.o `test -f 'generated/sum_i4.c' || echo '$(srcdir)/'`generated/sum_i4.c + +sum_i4.obj: generated/sum_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_i4.obj -MD -MP -MF "$(DEPDIR)/sum_i4.Tpo" -c -o sum_i4.obj `if test -f 'generated/sum_i4.c'; then $(CYGPATH_W) 'generated/sum_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_i4.Tpo" "$(DEPDIR)/sum_i4.Po"; else rm -f "$(DEPDIR)/sum_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_i4.c' object='sum_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_i4.Po' tmpdepfile='$(DEPDIR)/sum_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_i4.obj `if test -f 'generated/sum_i4.c'; then $(CYGPATH_W) 'generated/sum_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_i4.c'; fi` + +sum_i4.lo: generated/sum_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_i4.lo -MD -MP -MF "$(DEPDIR)/sum_i4.Tpo" -c -o sum_i4.lo `test -f 'generated/sum_i4.c' || echo '$(srcdir)/'`generated/sum_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_i4.Tpo" "$(DEPDIR)/sum_i4.Plo"; else rm -f "$(DEPDIR)/sum_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_i4.c' object='sum_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_i4.Plo' tmpdepfile='$(DEPDIR)/sum_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_i4.lo `test -f 'generated/sum_i4.c' || echo '$(srcdir)/'`generated/sum_i4.c + +sum_i8.o: generated/sum_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_i8.o -MD -MP -MF "$(DEPDIR)/sum_i8.Tpo" -c -o sum_i8.o `test -f 'generated/sum_i8.c' || echo '$(srcdir)/'`generated/sum_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_i8.Tpo" "$(DEPDIR)/sum_i8.Po"; else rm -f "$(DEPDIR)/sum_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_i8.c' object='sum_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_i8.Po' tmpdepfile='$(DEPDIR)/sum_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_i8.o `test -f 'generated/sum_i8.c' || echo '$(srcdir)/'`generated/sum_i8.c + +sum_i8.obj: generated/sum_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_i8.obj -MD -MP -MF "$(DEPDIR)/sum_i8.Tpo" -c -o sum_i8.obj `if test -f 'generated/sum_i8.c'; then $(CYGPATH_W) 'generated/sum_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_i8.Tpo" "$(DEPDIR)/sum_i8.Po"; else rm -f "$(DEPDIR)/sum_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_i8.c' object='sum_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_i8.Po' tmpdepfile='$(DEPDIR)/sum_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_i8.obj `if test -f 'generated/sum_i8.c'; then $(CYGPATH_W) 'generated/sum_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_i8.c'; fi` + +sum_i8.lo: generated/sum_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_i8.lo -MD -MP -MF "$(DEPDIR)/sum_i8.Tpo" -c -o sum_i8.lo `test -f 'generated/sum_i8.c' || echo '$(srcdir)/'`generated/sum_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_i8.Tpo" "$(DEPDIR)/sum_i8.Plo"; else rm -f "$(DEPDIR)/sum_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_i8.c' object='sum_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_i8.Plo' tmpdepfile='$(DEPDIR)/sum_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_i8.lo `test -f 'generated/sum_i8.c' || echo '$(srcdir)/'`generated/sum_i8.c + +sum_r4.o: generated/sum_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_r4.o -MD -MP -MF "$(DEPDIR)/sum_r4.Tpo" -c -o sum_r4.o `test -f 'generated/sum_r4.c' || echo '$(srcdir)/'`generated/sum_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_r4.Tpo" "$(DEPDIR)/sum_r4.Po"; else rm -f "$(DEPDIR)/sum_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_r4.c' object='sum_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_r4.Po' tmpdepfile='$(DEPDIR)/sum_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_r4.o `test -f 'generated/sum_r4.c' || echo '$(srcdir)/'`generated/sum_r4.c + +sum_r4.obj: generated/sum_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_r4.obj -MD -MP -MF "$(DEPDIR)/sum_r4.Tpo" -c -o sum_r4.obj `if test -f 'generated/sum_r4.c'; then $(CYGPATH_W) 'generated/sum_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_r4.Tpo" "$(DEPDIR)/sum_r4.Po"; else rm -f "$(DEPDIR)/sum_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_r4.c' object='sum_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_r4.Po' tmpdepfile='$(DEPDIR)/sum_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_r4.obj `if test -f 'generated/sum_r4.c'; then $(CYGPATH_W) 'generated/sum_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_r4.c'; fi` + +sum_r4.lo: generated/sum_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_r4.lo -MD -MP -MF "$(DEPDIR)/sum_r4.Tpo" -c -o sum_r4.lo `test -f 'generated/sum_r4.c' || echo '$(srcdir)/'`generated/sum_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_r4.Tpo" "$(DEPDIR)/sum_r4.Plo"; else rm -f "$(DEPDIR)/sum_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_r4.c' object='sum_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_r4.Plo' tmpdepfile='$(DEPDIR)/sum_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_r4.lo `test -f 'generated/sum_r4.c' || echo '$(srcdir)/'`generated/sum_r4.c + +sum_r8.o: generated/sum_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_r8.o -MD -MP -MF "$(DEPDIR)/sum_r8.Tpo" -c -o sum_r8.o `test -f 'generated/sum_r8.c' || echo '$(srcdir)/'`generated/sum_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_r8.Tpo" "$(DEPDIR)/sum_r8.Po"; else rm -f "$(DEPDIR)/sum_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_r8.c' object='sum_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_r8.Po' tmpdepfile='$(DEPDIR)/sum_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_r8.o `test -f 'generated/sum_r8.c' || echo '$(srcdir)/'`generated/sum_r8.c + +sum_r8.obj: generated/sum_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_r8.obj -MD -MP -MF "$(DEPDIR)/sum_r8.Tpo" -c -o sum_r8.obj `if test -f 'generated/sum_r8.c'; then $(CYGPATH_W) 'generated/sum_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_r8.Tpo" "$(DEPDIR)/sum_r8.Po"; else rm -f "$(DEPDIR)/sum_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_r8.c' object='sum_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_r8.Po' tmpdepfile='$(DEPDIR)/sum_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_r8.obj `if test -f 'generated/sum_r8.c'; then $(CYGPATH_W) 'generated/sum_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_r8.c'; fi` + +sum_r8.lo: generated/sum_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_r8.lo -MD -MP -MF "$(DEPDIR)/sum_r8.Tpo" -c -o sum_r8.lo `test -f 'generated/sum_r8.c' || echo '$(srcdir)/'`generated/sum_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_r8.Tpo" "$(DEPDIR)/sum_r8.Plo"; else rm -f "$(DEPDIR)/sum_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_r8.c' object='sum_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_r8.Plo' tmpdepfile='$(DEPDIR)/sum_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_r8.lo `test -f 'generated/sum_r8.c' || echo '$(srcdir)/'`generated/sum_r8.c + +sum_c4.o: generated/sum_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_c4.o -MD -MP -MF "$(DEPDIR)/sum_c4.Tpo" -c -o sum_c4.o `test -f 'generated/sum_c4.c' || echo '$(srcdir)/'`generated/sum_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_c4.Tpo" "$(DEPDIR)/sum_c4.Po"; else rm -f "$(DEPDIR)/sum_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_c4.c' object='sum_c4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_c4.Po' tmpdepfile='$(DEPDIR)/sum_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_c4.o `test -f 'generated/sum_c4.c' || echo '$(srcdir)/'`generated/sum_c4.c + +sum_c4.obj: generated/sum_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_c4.obj -MD -MP -MF "$(DEPDIR)/sum_c4.Tpo" -c -o sum_c4.obj `if test -f 'generated/sum_c4.c'; then $(CYGPATH_W) 'generated/sum_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_c4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_c4.Tpo" "$(DEPDIR)/sum_c4.Po"; else rm -f "$(DEPDIR)/sum_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_c4.c' object='sum_c4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_c4.Po' tmpdepfile='$(DEPDIR)/sum_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_c4.obj `if test -f 'generated/sum_c4.c'; then $(CYGPATH_W) 'generated/sum_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_c4.c'; fi` + +sum_c4.lo: generated/sum_c4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_c4.lo -MD -MP -MF "$(DEPDIR)/sum_c4.Tpo" -c -o sum_c4.lo `test -f 'generated/sum_c4.c' || echo '$(srcdir)/'`generated/sum_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_c4.Tpo" "$(DEPDIR)/sum_c4.Plo"; else rm -f "$(DEPDIR)/sum_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_c4.c' object='sum_c4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_c4.Plo' tmpdepfile='$(DEPDIR)/sum_c4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_c4.lo `test -f 'generated/sum_c4.c' || echo '$(srcdir)/'`generated/sum_c4.c + +sum_c8.o: generated/sum_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_c8.o -MD -MP -MF "$(DEPDIR)/sum_c8.Tpo" -c -o sum_c8.o `test -f 'generated/sum_c8.c' || echo '$(srcdir)/'`generated/sum_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_c8.Tpo" "$(DEPDIR)/sum_c8.Po"; else rm -f "$(DEPDIR)/sum_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_c8.c' object='sum_c8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_c8.Po' tmpdepfile='$(DEPDIR)/sum_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_c8.o `test -f 'generated/sum_c8.c' || echo '$(srcdir)/'`generated/sum_c8.c + +sum_c8.obj: generated/sum_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_c8.obj -MD -MP -MF "$(DEPDIR)/sum_c8.Tpo" -c -o sum_c8.obj `if test -f 'generated/sum_c8.c'; then $(CYGPATH_W) 'generated/sum_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_c8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_c8.Tpo" "$(DEPDIR)/sum_c8.Po"; else rm -f "$(DEPDIR)/sum_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_c8.c' object='sum_c8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_c8.Po' tmpdepfile='$(DEPDIR)/sum_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_c8.obj `if test -f 'generated/sum_c8.c'; then $(CYGPATH_W) 'generated/sum_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/sum_c8.c'; fi` + +sum_c8.lo: generated/sum_c8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sum_c8.lo -MD -MP -MF "$(DEPDIR)/sum_c8.Tpo" -c -o sum_c8.lo `test -f 'generated/sum_c8.c' || echo '$(srcdir)/'`generated/sum_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/sum_c8.Tpo" "$(DEPDIR)/sum_c8.Plo"; else rm -f "$(DEPDIR)/sum_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/sum_c8.c' object='sum_c8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/sum_c8.Plo' tmpdepfile='$(DEPDIR)/sum_c8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sum_c8.lo `test -f 'generated/sum_c8.c' || echo '$(srcdir)/'`generated/sum_c8.c + +dotprod_i4.o: generated/dotprod_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_i4.o -MD -MP -MF "$(DEPDIR)/dotprod_i4.Tpo" -c -o dotprod_i4.o `test -f 'generated/dotprod_i4.c' || echo '$(srcdir)/'`generated/dotprod_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_i4.Tpo" "$(DEPDIR)/dotprod_i4.Po"; else rm -f "$(DEPDIR)/dotprod_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_i4.c' object='dotprod_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_i4.Po' tmpdepfile='$(DEPDIR)/dotprod_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_i4.o `test -f 'generated/dotprod_i4.c' || echo '$(srcdir)/'`generated/dotprod_i4.c + +dotprod_i4.obj: generated/dotprod_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_i4.obj -MD -MP -MF "$(DEPDIR)/dotprod_i4.Tpo" -c -o dotprod_i4.obj `if test -f 'generated/dotprod_i4.c'; then $(CYGPATH_W) 'generated/dotprod_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_i4.Tpo" "$(DEPDIR)/dotprod_i4.Po"; else rm -f "$(DEPDIR)/dotprod_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_i4.c' object='dotprod_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_i4.Po' tmpdepfile='$(DEPDIR)/dotprod_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_i4.obj `if test -f 'generated/dotprod_i4.c'; then $(CYGPATH_W) 'generated/dotprod_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_i4.c'; fi` + +dotprod_i4.lo: generated/dotprod_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_i4.lo -MD -MP -MF "$(DEPDIR)/dotprod_i4.Tpo" -c -o dotprod_i4.lo `test -f 'generated/dotprod_i4.c' || echo '$(srcdir)/'`generated/dotprod_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_i4.Tpo" "$(DEPDIR)/dotprod_i4.Plo"; else rm -f "$(DEPDIR)/dotprod_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_i4.c' object='dotprod_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_i4.Plo' tmpdepfile='$(DEPDIR)/dotprod_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_i4.lo `test -f 'generated/dotprod_i4.c' || echo '$(srcdir)/'`generated/dotprod_i4.c + +dotprod_i8.o: generated/dotprod_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_i8.o -MD -MP -MF "$(DEPDIR)/dotprod_i8.Tpo" -c -o dotprod_i8.o `test -f 'generated/dotprod_i8.c' || echo '$(srcdir)/'`generated/dotprod_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_i8.Tpo" "$(DEPDIR)/dotprod_i8.Po"; else rm -f "$(DEPDIR)/dotprod_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_i8.c' object='dotprod_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_i8.Po' tmpdepfile='$(DEPDIR)/dotprod_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_i8.o `test -f 'generated/dotprod_i8.c' || echo '$(srcdir)/'`generated/dotprod_i8.c + +dotprod_i8.obj: generated/dotprod_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_i8.obj -MD -MP -MF "$(DEPDIR)/dotprod_i8.Tpo" -c -o dotprod_i8.obj `if test -f 'generated/dotprod_i8.c'; then $(CYGPATH_W) 'generated/dotprod_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_i8.Tpo" "$(DEPDIR)/dotprod_i8.Po"; else rm -f "$(DEPDIR)/dotprod_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_i8.c' object='dotprod_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_i8.Po' tmpdepfile='$(DEPDIR)/dotprod_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_i8.obj `if test -f 'generated/dotprod_i8.c'; then $(CYGPATH_W) 'generated/dotprod_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_i8.c'; fi` + +dotprod_i8.lo: generated/dotprod_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_i8.lo -MD -MP -MF "$(DEPDIR)/dotprod_i8.Tpo" -c -o dotprod_i8.lo `test -f 'generated/dotprod_i8.c' || echo '$(srcdir)/'`generated/dotprod_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_i8.Tpo" "$(DEPDIR)/dotprod_i8.Plo"; else rm -f "$(DEPDIR)/dotprod_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_i8.c' object='dotprod_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_i8.Plo' tmpdepfile='$(DEPDIR)/dotprod_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_i8.lo `test -f 'generated/dotprod_i8.c' || echo '$(srcdir)/'`generated/dotprod_i8.c + +dotprod_r4.o: generated/dotprod_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_r4.o -MD -MP -MF "$(DEPDIR)/dotprod_r4.Tpo" -c -o dotprod_r4.o `test -f 'generated/dotprod_r4.c' || echo '$(srcdir)/'`generated/dotprod_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_r4.Tpo" "$(DEPDIR)/dotprod_r4.Po"; else rm -f "$(DEPDIR)/dotprod_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_r4.c' object='dotprod_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_r4.Po' tmpdepfile='$(DEPDIR)/dotprod_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_r4.o `test -f 'generated/dotprod_r4.c' || echo '$(srcdir)/'`generated/dotprod_r4.c + +dotprod_r4.obj: generated/dotprod_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_r4.obj -MD -MP -MF "$(DEPDIR)/dotprod_r4.Tpo" -c -o dotprod_r4.obj `if test -f 'generated/dotprod_r4.c'; then $(CYGPATH_W) 'generated/dotprod_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_r4.Tpo" "$(DEPDIR)/dotprod_r4.Po"; else rm -f "$(DEPDIR)/dotprod_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_r4.c' object='dotprod_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_r4.Po' tmpdepfile='$(DEPDIR)/dotprod_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_r4.obj `if test -f 'generated/dotprod_r4.c'; then $(CYGPATH_W) 'generated/dotprod_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_r4.c'; fi` + +dotprod_r4.lo: generated/dotprod_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_r4.lo -MD -MP -MF "$(DEPDIR)/dotprod_r4.Tpo" -c -o dotprod_r4.lo `test -f 'generated/dotprod_r4.c' || echo '$(srcdir)/'`generated/dotprod_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_r4.Tpo" "$(DEPDIR)/dotprod_r4.Plo"; else rm -f "$(DEPDIR)/dotprod_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_r4.c' object='dotprod_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_r4.Plo' tmpdepfile='$(DEPDIR)/dotprod_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_r4.lo `test -f 'generated/dotprod_r4.c' || echo '$(srcdir)/'`generated/dotprod_r4.c + +dotprod_r8.o: generated/dotprod_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_r8.o -MD -MP -MF "$(DEPDIR)/dotprod_r8.Tpo" -c -o dotprod_r8.o `test -f 'generated/dotprod_r8.c' || echo '$(srcdir)/'`generated/dotprod_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_r8.Tpo" "$(DEPDIR)/dotprod_r8.Po"; else rm -f "$(DEPDIR)/dotprod_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_r8.c' object='dotprod_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_r8.Po' tmpdepfile='$(DEPDIR)/dotprod_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_r8.o `test -f 'generated/dotprod_r8.c' || echo '$(srcdir)/'`generated/dotprod_r8.c + +dotprod_r8.obj: generated/dotprod_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_r8.obj -MD -MP -MF "$(DEPDIR)/dotprod_r8.Tpo" -c -o dotprod_r8.obj `if test -f 'generated/dotprod_r8.c'; then $(CYGPATH_W) 'generated/dotprod_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_r8.Tpo" "$(DEPDIR)/dotprod_r8.Po"; else rm -f "$(DEPDIR)/dotprod_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_r8.c' object='dotprod_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_r8.Po' tmpdepfile='$(DEPDIR)/dotprod_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_r8.obj `if test -f 'generated/dotprod_r8.c'; then $(CYGPATH_W) 'generated/dotprod_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_r8.c'; fi` + +dotprod_r8.lo: generated/dotprod_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_r8.lo -MD -MP -MF "$(DEPDIR)/dotprod_r8.Tpo" -c -o dotprod_r8.lo `test -f 'generated/dotprod_r8.c' || echo '$(srcdir)/'`generated/dotprod_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_r8.Tpo" "$(DEPDIR)/dotprod_r8.Plo"; else rm -f "$(DEPDIR)/dotprod_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_r8.c' object='dotprod_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_r8.Plo' tmpdepfile='$(DEPDIR)/dotprod_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_r8.lo `test -f 'generated/dotprod_r8.c' || echo '$(srcdir)/'`generated/dotprod_r8.c + +dotprod_l4.o: generated/dotprod_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_l4.o -MD -MP -MF "$(DEPDIR)/dotprod_l4.Tpo" -c -o dotprod_l4.o `test -f 'generated/dotprod_l4.c' || echo '$(srcdir)/'`generated/dotprod_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_l4.Tpo" "$(DEPDIR)/dotprod_l4.Po"; else rm -f "$(DEPDIR)/dotprod_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_l4.c' object='dotprod_l4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_l4.Po' tmpdepfile='$(DEPDIR)/dotprod_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_l4.o `test -f 'generated/dotprod_l4.c' || echo '$(srcdir)/'`generated/dotprod_l4.c + +dotprod_l4.obj: generated/dotprod_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_l4.obj -MD -MP -MF "$(DEPDIR)/dotprod_l4.Tpo" -c -o dotprod_l4.obj `if test -f 'generated/dotprod_l4.c'; then $(CYGPATH_W) 'generated/dotprod_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_l4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_l4.Tpo" "$(DEPDIR)/dotprod_l4.Po"; else rm -f "$(DEPDIR)/dotprod_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_l4.c' object='dotprod_l4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_l4.Po' tmpdepfile='$(DEPDIR)/dotprod_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_l4.obj `if test -f 'generated/dotprod_l4.c'; then $(CYGPATH_W) 'generated/dotprod_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_l4.c'; fi` + +dotprod_l4.lo: generated/dotprod_l4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_l4.lo -MD -MP -MF "$(DEPDIR)/dotprod_l4.Tpo" -c -o dotprod_l4.lo `test -f 'generated/dotprod_l4.c' || echo '$(srcdir)/'`generated/dotprod_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_l4.Tpo" "$(DEPDIR)/dotprod_l4.Plo"; else rm -f "$(DEPDIR)/dotprod_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_l4.c' object='dotprod_l4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_l4.Plo' tmpdepfile='$(DEPDIR)/dotprod_l4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_l4.lo `test -f 'generated/dotprod_l4.c' || echo '$(srcdir)/'`generated/dotprod_l4.c + +dotprod_l8.o: generated/dotprod_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_l8.o -MD -MP -MF "$(DEPDIR)/dotprod_l8.Tpo" -c -o dotprod_l8.o `test -f 'generated/dotprod_l8.c' || echo '$(srcdir)/'`generated/dotprod_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_l8.Tpo" "$(DEPDIR)/dotprod_l8.Po"; else rm -f "$(DEPDIR)/dotprod_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_l8.c' object='dotprod_l8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_l8.Po' tmpdepfile='$(DEPDIR)/dotprod_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_l8.o `test -f 'generated/dotprod_l8.c' || echo '$(srcdir)/'`generated/dotprod_l8.c + +dotprod_l8.obj: generated/dotprod_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_l8.obj -MD -MP -MF "$(DEPDIR)/dotprod_l8.Tpo" -c -o dotprod_l8.obj `if test -f 'generated/dotprod_l8.c'; then $(CYGPATH_W) 'generated/dotprod_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_l8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_l8.Tpo" "$(DEPDIR)/dotprod_l8.Po"; else rm -f "$(DEPDIR)/dotprod_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_l8.c' object='dotprod_l8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_l8.Po' tmpdepfile='$(DEPDIR)/dotprod_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_l8.obj `if test -f 'generated/dotprod_l8.c'; then $(CYGPATH_W) 'generated/dotprod_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_l8.c'; fi` + +dotprod_l8.lo: generated/dotprod_l8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_l8.lo -MD -MP -MF "$(DEPDIR)/dotprod_l8.Tpo" -c -o dotprod_l8.lo `test -f 'generated/dotprod_l8.c' || echo '$(srcdir)/'`generated/dotprod_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_l8.Tpo" "$(DEPDIR)/dotprod_l8.Plo"; else rm -f "$(DEPDIR)/dotprod_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_l8.c' object='dotprod_l8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_l8.Plo' tmpdepfile='$(DEPDIR)/dotprod_l8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_l8.lo `test -f 'generated/dotprod_l8.c' || echo '$(srcdir)/'`generated/dotprod_l8.c + +dotprod_c4.o: generated/dotprod_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_c4.o -MD -MP -MF "$(DEPDIR)/dotprod_c4.Tpo" -c -o dotprod_c4.o `test -f 'generated/dotprod_c4.c' || echo '$(srcdir)/'`generated/dotprod_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_c4.Tpo" "$(DEPDIR)/dotprod_c4.Po"; else rm -f "$(DEPDIR)/dotprod_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_c4.c' object='dotprod_c4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_c4.Po' tmpdepfile='$(DEPDIR)/dotprod_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_c4.o `test -f 'generated/dotprod_c4.c' || echo '$(srcdir)/'`generated/dotprod_c4.c + +dotprod_c4.obj: generated/dotprod_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_c4.obj -MD -MP -MF "$(DEPDIR)/dotprod_c4.Tpo" -c -o dotprod_c4.obj `if test -f 'generated/dotprod_c4.c'; then $(CYGPATH_W) 'generated/dotprod_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_c4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_c4.Tpo" "$(DEPDIR)/dotprod_c4.Po"; else rm -f "$(DEPDIR)/dotprod_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_c4.c' object='dotprod_c4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_c4.Po' tmpdepfile='$(DEPDIR)/dotprod_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_c4.obj `if test -f 'generated/dotprod_c4.c'; then $(CYGPATH_W) 'generated/dotprod_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_c4.c'; fi` + +dotprod_c4.lo: generated/dotprod_c4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_c4.lo -MD -MP -MF "$(DEPDIR)/dotprod_c4.Tpo" -c -o dotprod_c4.lo `test -f 'generated/dotprod_c4.c' || echo '$(srcdir)/'`generated/dotprod_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_c4.Tpo" "$(DEPDIR)/dotprod_c4.Plo"; else rm -f "$(DEPDIR)/dotprod_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_c4.c' object='dotprod_c4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_c4.Plo' tmpdepfile='$(DEPDIR)/dotprod_c4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_c4.lo `test -f 'generated/dotprod_c4.c' || echo '$(srcdir)/'`generated/dotprod_c4.c + +dotprod_c8.o: generated/dotprod_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_c8.o -MD -MP -MF "$(DEPDIR)/dotprod_c8.Tpo" -c -o dotprod_c8.o `test -f 'generated/dotprod_c8.c' || echo '$(srcdir)/'`generated/dotprod_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_c8.Tpo" "$(DEPDIR)/dotprod_c8.Po"; else rm -f "$(DEPDIR)/dotprod_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_c8.c' object='dotprod_c8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_c8.Po' tmpdepfile='$(DEPDIR)/dotprod_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_c8.o `test -f 'generated/dotprod_c8.c' || echo '$(srcdir)/'`generated/dotprod_c8.c + +dotprod_c8.obj: generated/dotprod_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_c8.obj -MD -MP -MF "$(DEPDIR)/dotprod_c8.Tpo" -c -o dotprod_c8.obj `if test -f 'generated/dotprod_c8.c'; then $(CYGPATH_W) 'generated/dotprod_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_c8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_c8.Tpo" "$(DEPDIR)/dotprod_c8.Po"; else rm -f "$(DEPDIR)/dotprod_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_c8.c' object='dotprod_c8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_c8.Po' tmpdepfile='$(DEPDIR)/dotprod_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_c8.obj `if test -f 'generated/dotprod_c8.c'; then $(CYGPATH_W) 'generated/dotprod_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/dotprod_c8.c'; fi` + +dotprod_c8.lo: generated/dotprod_c8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dotprod_c8.lo -MD -MP -MF "$(DEPDIR)/dotprod_c8.Tpo" -c -o dotprod_c8.lo `test -f 'generated/dotprod_c8.c' || echo '$(srcdir)/'`generated/dotprod_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/dotprod_c8.Tpo" "$(DEPDIR)/dotprod_c8.Plo"; else rm -f "$(DEPDIR)/dotprod_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/dotprod_c8.c' object='dotprod_c8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/dotprod_c8.Plo' tmpdepfile='$(DEPDIR)/dotprod_c8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dotprod_c8.lo `test -f 'generated/dotprod_c8.c' || echo '$(srcdir)/'`generated/dotprod_c8.c + +matmul_i4.o: generated/matmul_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_i4.o -MD -MP -MF "$(DEPDIR)/matmul_i4.Tpo" -c -o matmul_i4.o `test -f 'generated/matmul_i4.c' || echo '$(srcdir)/'`generated/matmul_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_i4.Tpo" "$(DEPDIR)/matmul_i4.Po"; else rm -f "$(DEPDIR)/matmul_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_i4.c' object='matmul_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_i4.Po' tmpdepfile='$(DEPDIR)/matmul_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_i4.o `test -f 'generated/matmul_i4.c' || echo '$(srcdir)/'`generated/matmul_i4.c + +matmul_i4.obj: generated/matmul_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_i4.obj -MD -MP -MF "$(DEPDIR)/matmul_i4.Tpo" -c -o matmul_i4.obj `if test -f 'generated/matmul_i4.c'; then $(CYGPATH_W) 'generated/matmul_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_i4.Tpo" "$(DEPDIR)/matmul_i4.Po"; else rm -f "$(DEPDIR)/matmul_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_i4.c' object='matmul_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_i4.Po' tmpdepfile='$(DEPDIR)/matmul_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_i4.obj `if test -f 'generated/matmul_i4.c'; then $(CYGPATH_W) 'generated/matmul_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_i4.c'; fi` + +matmul_i4.lo: generated/matmul_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_i4.lo -MD -MP -MF "$(DEPDIR)/matmul_i4.Tpo" -c -o matmul_i4.lo `test -f 'generated/matmul_i4.c' || echo '$(srcdir)/'`generated/matmul_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_i4.Tpo" "$(DEPDIR)/matmul_i4.Plo"; else rm -f "$(DEPDIR)/matmul_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_i4.c' object='matmul_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_i4.Plo' tmpdepfile='$(DEPDIR)/matmul_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_i4.lo `test -f 'generated/matmul_i4.c' || echo '$(srcdir)/'`generated/matmul_i4.c + +matmul_i8.o: generated/matmul_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_i8.o -MD -MP -MF "$(DEPDIR)/matmul_i8.Tpo" -c -o matmul_i8.o `test -f 'generated/matmul_i8.c' || echo '$(srcdir)/'`generated/matmul_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_i8.Tpo" "$(DEPDIR)/matmul_i8.Po"; else rm -f "$(DEPDIR)/matmul_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_i8.c' object='matmul_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_i8.Po' tmpdepfile='$(DEPDIR)/matmul_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_i8.o `test -f 'generated/matmul_i8.c' || echo '$(srcdir)/'`generated/matmul_i8.c + +matmul_i8.obj: generated/matmul_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_i8.obj -MD -MP -MF "$(DEPDIR)/matmul_i8.Tpo" -c -o matmul_i8.obj `if test -f 'generated/matmul_i8.c'; then $(CYGPATH_W) 'generated/matmul_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_i8.Tpo" "$(DEPDIR)/matmul_i8.Po"; else rm -f "$(DEPDIR)/matmul_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_i8.c' object='matmul_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_i8.Po' tmpdepfile='$(DEPDIR)/matmul_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_i8.obj `if test -f 'generated/matmul_i8.c'; then $(CYGPATH_W) 'generated/matmul_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_i8.c'; fi` + +matmul_i8.lo: generated/matmul_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_i8.lo -MD -MP -MF "$(DEPDIR)/matmul_i8.Tpo" -c -o matmul_i8.lo `test -f 'generated/matmul_i8.c' || echo '$(srcdir)/'`generated/matmul_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_i8.Tpo" "$(DEPDIR)/matmul_i8.Plo"; else rm -f "$(DEPDIR)/matmul_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_i8.c' object='matmul_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_i8.Plo' tmpdepfile='$(DEPDIR)/matmul_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_i8.lo `test -f 'generated/matmul_i8.c' || echo '$(srcdir)/'`generated/matmul_i8.c + +matmul_r4.o: generated/matmul_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_r4.o -MD -MP -MF "$(DEPDIR)/matmul_r4.Tpo" -c -o matmul_r4.o `test -f 'generated/matmul_r4.c' || echo '$(srcdir)/'`generated/matmul_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_r4.Tpo" "$(DEPDIR)/matmul_r4.Po"; else rm -f "$(DEPDIR)/matmul_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_r4.c' object='matmul_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_r4.Po' tmpdepfile='$(DEPDIR)/matmul_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_r4.o `test -f 'generated/matmul_r4.c' || echo '$(srcdir)/'`generated/matmul_r4.c + +matmul_r4.obj: generated/matmul_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_r4.obj -MD -MP -MF "$(DEPDIR)/matmul_r4.Tpo" -c -o matmul_r4.obj `if test -f 'generated/matmul_r4.c'; then $(CYGPATH_W) 'generated/matmul_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_r4.Tpo" "$(DEPDIR)/matmul_r4.Po"; else rm -f "$(DEPDIR)/matmul_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_r4.c' object='matmul_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_r4.Po' tmpdepfile='$(DEPDIR)/matmul_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_r4.obj `if test -f 'generated/matmul_r4.c'; then $(CYGPATH_W) 'generated/matmul_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_r4.c'; fi` + +matmul_r4.lo: generated/matmul_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_r4.lo -MD -MP -MF "$(DEPDIR)/matmul_r4.Tpo" -c -o matmul_r4.lo `test -f 'generated/matmul_r4.c' || echo '$(srcdir)/'`generated/matmul_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_r4.Tpo" "$(DEPDIR)/matmul_r4.Plo"; else rm -f "$(DEPDIR)/matmul_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_r4.c' object='matmul_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_r4.Plo' tmpdepfile='$(DEPDIR)/matmul_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_r4.lo `test -f 'generated/matmul_r4.c' || echo '$(srcdir)/'`generated/matmul_r4.c + +matmul_r8.o: generated/matmul_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_r8.o -MD -MP -MF "$(DEPDIR)/matmul_r8.Tpo" -c -o matmul_r8.o `test -f 'generated/matmul_r8.c' || echo '$(srcdir)/'`generated/matmul_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_r8.Tpo" "$(DEPDIR)/matmul_r8.Po"; else rm -f "$(DEPDIR)/matmul_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_r8.c' object='matmul_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_r8.Po' tmpdepfile='$(DEPDIR)/matmul_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_r8.o `test -f 'generated/matmul_r8.c' || echo '$(srcdir)/'`generated/matmul_r8.c + +matmul_r8.obj: generated/matmul_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_r8.obj -MD -MP -MF "$(DEPDIR)/matmul_r8.Tpo" -c -o matmul_r8.obj `if test -f 'generated/matmul_r8.c'; then $(CYGPATH_W) 'generated/matmul_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_r8.Tpo" "$(DEPDIR)/matmul_r8.Po"; else rm -f "$(DEPDIR)/matmul_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_r8.c' object='matmul_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_r8.Po' tmpdepfile='$(DEPDIR)/matmul_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_r8.obj `if test -f 'generated/matmul_r8.c'; then $(CYGPATH_W) 'generated/matmul_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_r8.c'; fi` + +matmul_r8.lo: generated/matmul_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_r8.lo -MD -MP -MF "$(DEPDIR)/matmul_r8.Tpo" -c -o matmul_r8.lo `test -f 'generated/matmul_r8.c' || echo '$(srcdir)/'`generated/matmul_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_r8.Tpo" "$(DEPDIR)/matmul_r8.Plo"; else rm -f "$(DEPDIR)/matmul_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_r8.c' object='matmul_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_r8.Plo' tmpdepfile='$(DEPDIR)/matmul_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_r8.lo `test -f 'generated/matmul_r8.c' || echo '$(srcdir)/'`generated/matmul_r8.c + +matmul_c4.o: generated/matmul_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_c4.o -MD -MP -MF "$(DEPDIR)/matmul_c4.Tpo" -c -o matmul_c4.o `test -f 'generated/matmul_c4.c' || echo '$(srcdir)/'`generated/matmul_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_c4.Tpo" "$(DEPDIR)/matmul_c4.Po"; else rm -f "$(DEPDIR)/matmul_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_c4.c' object='matmul_c4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_c4.Po' tmpdepfile='$(DEPDIR)/matmul_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_c4.o `test -f 'generated/matmul_c4.c' || echo '$(srcdir)/'`generated/matmul_c4.c + +matmul_c4.obj: generated/matmul_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_c4.obj -MD -MP -MF "$(DEPDIR)/matmul_c4.Tpo" -c -o matmul_c4.obj `if test -f 'generated/matmul_c4.c'; then $(CYGPATH_W) 'generated/matmul_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_c4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_c4.Tpo" "$(DEPDIR)/matmul_c4.Po"; else rm -f "$(DEPDIR)/matmul_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_c4.c' object='matmul_c4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_c4.Po' tmpdepfile='$(DEPDIR)/matmul_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_c4.obj `if test -f 'generated/matmul_c4.c'; then $(CYGPATH_W) 'generated/matmul_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_c4.c'; fi` + +matmul_c4.lo: generated/matmul_c4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_c4.lo -MD -MP -MF "$(DEPDIR)/matmul_c4.Tpo" -c -o matmul_c4.lo `test -f 'generated/matmul_c4.c' || echo '$(srcdir)/'`generated/matmul_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_c4.Tpo" "$(DEPDIR)/matmul_c4.Plo"; else rm -f "$(DEPDIR)/matmul_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_c4.c' object='matmul_c4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_c4.Plo' tmpdepfile='$(DEPDIR)/matmul_c4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_c4.lo `test -f 'generated/matmul_c4.c' || echo '$(srcdir)/'`generated/matmul_c4.c + +matmul_c8.o: generated/matmul_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_c8.o -MD -MP -MF "$(DEPDIR)/matmul_c8.Tpo" -c -o matmul_c8.o `test -f 'generated/matmul_c8.c' || echo '$(srcdir)/'`generated/matmul_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_c8.Tpo" "$(DEPDIR)/matmul_c8.Po"; else rm -f "$(DEPDIR)/matmul_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_c8.c' object='matmul_c8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_c8.Po' tmpdepfile='$(DEPDIR)/matmul_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_c8.o `test -f 'generated/matmul_c8.c' || echo '$(srcdir)/'`generated/matmul_c8.c + +matmul_c8.obj: generated/matmul_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_c8.obj -MD -MP -MF "$(DEPDIR)/matmul_c8.Tpo" -c -o matmul_c8.obj `if test -f 'generated/matmul_c8.c'; then $(CYGPATH_W) 'generated/matmul_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_c8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_c8.Tpo" "$(DEPDIR)/matmul_c8.Po"; else rm -f "$(DEPDIR)/matmul_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_c8.c' object='matmul_c8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_c8.Po' tmpdepfile='$(DEPDIR)/matmul_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_c8.obj `if test -f 'generated/matmul_c8.c'; then $(CYGPATH_W) 'generated/matmul_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_c8.c'; fi` + +matmul_c8.lo: generated/matmul_c8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_c8.lo -MD -MP -MF "$(DEPDIR)/matmul_c8.Tpo" -c -o matmul_c8.lo `test -f 'generated/matmul_c8.c' || echo '$(srcdir)/'`generated/matmul_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_c8.Tpo" "$(DEPDIR)/matmul_c8.Plo"; else rm -f "$(DEPDIR)/matmul_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_c8.c' object='matmul_c8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_c8.Plo' tmpdepfile='$(DEPDIR)/matmul_c8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_c8.lo `test -f 'generated/matmul_c8.c' || echo '$(srcdir)/'`generated/matmul_c8.c + +matmul_l4.o: generated/matmul_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_l4.o -MD -MP -MF "$(DEPDIR)/matmul_l4.Tpo" -c -o matmul_l4.o `test -f 'generated/matmul_l4.c' || echo '$(srcdir)/'`generated/matmul_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_l4.Tpo" "$(DEPDIR)/matmul_l4.Po"; else rm -f "$(DEPDIR)/matmul_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_l4.c' object='matmul_l4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_l4.Po' tmpdepfile='$(DEPDIR)/matmul_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_l4.o `test -f 'generated/matmul_l4.c' || echo '$(srcdir)/'`generated/matmul_l4.c + +matmul_l4.obj: generated/matmul_l4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_l4.obj -MD -MP -MF "$(DEPDIR)/matmul_l4.Tpo" -c -o matmul_l4.obj `if test -f 'generated/matmul_l4.c'; then $(CYGPATH_W) 'generated/matmul_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_l4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_l4.Tpo" "$(DEPDIR)/matmul_l4.Po"; else rm -f "$(DEPDIR)/matmul_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_l4.c' object='matmul_l4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_l4.Po' tmpdepfile='$(DEPDIR)/matmul_l4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_l4.obj `if test -f 'generated/matmul_l4.c'; then $(CYGPATH_W) 'generated/matmul_l4.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_l4.c'; fi` + +matmul_l4.lo: generated/matmul_l4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_l4.lo -MD -MP -MF "$(DEPDIR)/matmul_l4.Tpo" -c -o matmul_l4.lo `test -f 'generated/matmul_l4.c' || echo '$(srcdir)/'`generated/matmul_l4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_l4.Tpo" "$(DEPDIR)/matmul_l4.Plo"; else rm -f "$(DEPDIR)/matmul_l4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_l4.c' object='matmul_l4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_l4.Plo' tmpdepfile='$(DEPDIR)/matmul_l4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_l4.lo `test -f 'generated/matmul_l4.c' || echo '$(srcdir)/'`generated/matmul_l4.c + +matmul_l8.o: generated/matmul_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_l8.o -MD -MP -MF "$(DEPDIR)/matmul_l8.Tpo" -c -o matmul_l8.o `test -f 'generated/matmul_l8.c' || echo '$(srcdir)/'`generated/matmul_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_l8.Tpo" "$(DEPDIR)/matmul_l8.Po"; else rm -f "$(DEPDIR)/matmul_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_l8.c' object='matmul_l8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_l8.Po' tmpdepfile='$(DEPDIR)/matmul_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_l8.o `test -f 'generated/matmul_l8.c' || echo '$(srcdir)/'`generated/matmul_l8.c + +matmul_l8.obj: generated/matmul_l8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_l8.obj -MD -MP -MF "$(DEPDIR)/matmul_l8.Tpo" -c -o matmul_l8.obj `if test -f 'generated/matmul_l8.c'; then $(CYGPATH_W) 'generated/matmul_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_l8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_l8.Tpo" "$(DEPDIR)/matmul_l8.Po"; else rm -f "$(DEPDIR)/matmul_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_l8.c' object='matmul_l8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_l8.Po' tmpdepfile='$(DEPDIR)/matmul_l8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_l8.obj `if test -f 'generated/matmul_l8.c'; then $(CYGPATH_W) 'generated/matmul_l8.c'; else $(CYGPATH_W) '$(srcdir)/generated/matmul_l8.c'; fi` + +matmul_l8.lo: generated/matmul_l8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT matmul_l8.lo -MD -MP -MF "$(DEPDIR)/matmul_l8.Tpo" -c -o matmul_l8.lo `test -f 'generated/matmul_l8.c' || echo '$(srcdir)/'`generated/matmul_l8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/matmul_l8.Tpo" "$(DEPDIR)/matmul_l8.Plo"; else rm -f "$(DEPDIR)/matmul_l8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/matmul_l8.c' object='matmul_l8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/matmul_l8.Plo' tmpdepfile='$(DEPDIR)/matmul_l8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o matmul_l8.lo `test -f 'generated/matmul_l8.c' || echo '$(srcdir)/'`generated/matmul_l8.c + +transpose_i4.o: generated/transpose_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_i4.o -MD -MP -MF "$(DEPDIR)/transpose_i4.Tpo" -c -o transpose_i4.o `test -f 'generated/transpose_i4.c' || echo '$(srcdir)/'`generated/transpose_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_i4.Tpo" "$(DEPDIR)/transpose_i4.Po"; else rm -f "$(DEPDIR)/transpose_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/transpose_i4.c' object='transpose_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_i4.Po' tmpdepfile='$(DEPDIR)/transpose_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_i4.o `test -f 'generated/transpose_i4.c' || echo '$(srcdir)/'`generated/transpose_i4.c + +transpose_i4.obj: generated/transpose_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_i4.obj -MD -MP -MF "$(DEPDIR)/transpose_i4.Tpo" -c -o transpose_i4.obj `if test -f 'generated/transpose_i4.c'; then $(CYGPATH_W) 'generated/transpose_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/transpose_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_i4.Tpo" "$(DEPDIR)/transpose_i4.Po"; else rm -f "$(DEPDIR)/transpose_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/transpose_i4.c' object='transpose_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_i4.Po' tmpdepfile='$(DEPDIR)/transpose_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_i4.obj `if test -f 'generated/transpose_i4.c'; then $(CYGPATH_W) 'generated/transpose_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/transpose_i4.c'; fi` + +transpose_i4.lo: generated/transpose_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_i4.lo -MD -MP -MF "$(DEPDIR)/transpose_i4.Tpo" -c -o transpose_i4.lo `test -f 'generated/transpose_i4.c' || echo '$(srcdir)/'`generated/transpose_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_i4.Tpo" "$(DEPDIR)/transpose_i4.Plo"; else rm -f "$(DEPDIR)/transpose_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/transpose_i4.c' object='transpose_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_i4.Plo' tmpdepfile='$(DEPDIR)/transpose_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_i4.lo `test -f 'generated/transpose_i4.c' || echo '$(srcdir)/'`generated/transpose_i4.c + +transpose_i8.o: generated/transpose_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_i8.o -MD -MP -MF "$(DEPDIR)/transpose_i8.Tpo" -c -o transpose_i8.o `test -f 'generated/transpose_i8.c' || echo '$(srcdir)/'`generated/transpose_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_i8.Tpo" "$(DEPDIR)/transpose_i8.Po"; else rm -f "$(DEPDIR)/transpose_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/transpose_i8.c' object='transpose_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_i8.Po' tmpdepfile='$(DEPDIR)/transpose_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_i8.o `test -f 'generated/transpose_i8.c' || echo '$(srcdir)/'`generated/transpose_i8.c + +transpose_i8.obj: generated/transpose_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_i8.obj -MD -MP -MF "$(DEPDIR)/transpose_i8.Tpo" -c -o transpose_i8.obj `if test -f 'generated/transpose_i8.c'; then $(CYGPATH_W) 'generated/transpose_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/transpose_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_i8.Tpo" "$(DEPDIR)/transpose_i8.Po"; else rm -f "$(DEPDIR)/transpose_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/transpose_i8.c' object='transpose_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_i8.Po' tmpdepfile='$(DEPDIR)/transpose_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_i8.obj `if test -f 'generated/transpose_i8.c'; then $(CYGPATH_W) 'generated/transpose_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/transpose_i8.c'; fi` + +transpose_i8.lo: generated/transpose_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_i8.lo -MD -MP -MF "$(DEPDIR)/transpose_i8.Tpo" -c -o transpose_i8.lo `test -f 'generated/transpose_i8.c' || echo '$(srcdir)/'`generated/transpose_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_i8.Tpo" "$(DEPDIR)/transpose_i8.Plo"; else rm -f "$(DEPDIR)/transpose_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/transpose_i8.c' object='transpose_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_i8.Plo' tmpdepfile='$(DEPDIR)/transpose_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_i8.lo `test -f 'generated/transpose_i8.c' || echo '$(srcdir)/'`generated/transpose_i8.c + +shape_i4.o: generated/shape_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT shape_i4.o -MD -MP -MF "$(DEPDIR)/shape_i4.Tpo" -c -o shape_i4.o `test -f 'generated/shape_i4.c' || echo '$(srcdir)/'`generated/shape_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/shape_i4.Tpo" "$(DEPDIR)/shape_i4.Po"; else rm -f "$(DEPDIR)/shape_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/shape_i4.c' object='shape_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/shape_i4.Po' tmpdepfile='$(DEPDIR)/shape_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shape_i4.o `test -f 'generated/shape_i4.c' || echo '$(srcdir)/'`generated/shape_i4.c + +shape_i4.obj: generated/shape_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT shape_i4.obj -MD -MP -MF "$(DEPDIR)/shape_i4.Tpo" -c -o shape_i4.obj `if test -f 'generated/shape_i4.c'; then $(CYGPATH_W) 'generated/shape_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/shape_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/shape_i4.Tpo" "$(DEPDIR)/shape_i4.Po"; else rm -f "$(DEPDIR)/shape_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/shape_i4.c' object='shape_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/shape_i4.Po' tmpdepfile='$(DEPDIR)/shape_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shape_i4.obj `if test -f 'generated/shape_i4.c'; then $(CYGPATH_W) 'generated/shape_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/shape_i4.c'; fi` + +shape_i4.lo: generated/shape_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT shape_i4.lo -MD -MP -MF "$(DEPDIR)/shape_i4.Tpo" -c -o shape_i4.lo `test -f 'generated/shape_i4.c' || echo '$(srcdir)/'`generated/shape_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/shape_i4.Tpo" "$(DEPDIR)/shape_i4.Plo"; else rm -f "$(DEPDIR)/shape_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/shape_i4.c' object='shape_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/shape_i4.Plo' tmpdepfile='$(DEPDIR)/shape_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shape_i4.lo `test -f 'generated/shape_i4.c' || echo '$(srcdir)/'`generated/shape_i4.c + +shape_i8.o: generated/shape_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT shape_i8.o -MD -MP -MF "$(DEPDIR)/shape_i8.Tpo" -c -o shape_i8.o `test -f 'generated/shape_i8.c' || echo '$(srcdir)/'`generated/shape_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/shape_i8.Tpo" "$(DEPDIR)/shape_i8.Po"; else rm -f "$(DEPDIR)/shape_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/shape_i8.c' object='shape_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/shape_i8.Po' tmpdepfile='$(DEPDIR)/shape_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shape_i8.o `test -f 'generated/shape_i8.c' || echo '$(srcdir)/'`generated/shape_i8.c + +shape_i8.obj: generated/shape_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT shape_i8.obj -MD -MP -MF "$(DEPDIR)/shape_i8.Tpo" -c -o shape_i8.obj `if test -f 'generated/shape_i8.c'; then $(CYGPATH_W) 'generated/shape_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/shape_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/shape_i8.Tpo" "$(DEPDIR)/shape_i8.Po"; else rm -f "$(DEPDIR)/shape_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/shape_i8.c' object='shape_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/shape_i8.Po' tmpdepfile='$(DEPDIR)/shape_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shape_i8.obj `if test -f 'generated/shape_i8.c'; then $(CYGPATH_W) 'generated/shape_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/shape_i8.c'; fi` + +shape_i8.lo: generated/shape_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT shape_i8.lo -MD -MP -MF "$(DEPDIR)/shape_i8.Tpo" -c -o shape_i8.lo `test -f 'generated/shape_i8.c' || echo '$(srcdir)/'`generated/shape_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/shape_i8.Tpo" "$(DEPDIR)/shape_i8.Plo"; else rm -f "$(DEPDIR)/shape_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/shape_i8.c' object='shape_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/shape_i8.Plo' tmpdepfile='$(DEPDIR)/shape_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o shape_i8.lo `test -f 'generated/shape_i8.c' || echo '$(srcdir)/'`generated/shape_i8.c + +eoshift1_4.o: generated/eoshift1_4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift1_4.o -MD -MP -MF "$(DEPDIR)/eoshift1_4.Tpo" -c -o eoshift1_4.o `test -f 'generated/eoshift1_4.c' || echo '$(srcdir)/'`generated/eoshift1_4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift1_4.Tpo" "$(DEPDIR)/eoshift1_4.Po"; else rm -f "$(DEPDIR)/eoshift1_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift1_4.c' object='eoshift1_4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift1_4.Po' tmpdepfile='$(DEPDIR)/eoshift1_4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift1_4.o `test -f 'generated/eoshift1_4.c' || echo '$(srcdir)/'`generated/eoshift1_4.c + +eoshift1_4.obj: generated/eoshift1_4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift1_4.obj -MD -MP -MF "$(DEPDIR)/eoshift1_4.Tpo" -c -o eoshift1_4.obj `if test -f 'generated/eoshift1_4.c'; then $(CYGPATH_W) 'generated/eoshift1_4.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift1_4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift1_4.Tpo" "$(DEPDIR)/eoshift1_4.Po"; else rm -f "$(DEPDIR)/eoshift1_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift1_4.c' object='eoshift1_4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift1_4.Po' tmpdepfile='$(DEPDIR)/eoshift1_4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift1_4.obj `if test -f 'generated/eoshift1_4.c'; then $(CYGPATH_W) 'generated/eoshift1_4.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift1_4.c'; fi` + +eoshift1_4.lo: generated/eoshift1_4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift1_4.lo -MD -MP -MF "$(DEPDIR)/eoshift1_4.Tpo" -c -o eoshift1_4.lo `test -f 'generated/eoshift1_4.c' || echo '$(srcdir)/'`generated/eoshift1_4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift1_4.Tpo" "$(DEPDIR)/eoshift1_4.Plo"; else rm -f "$(DEPDIR)/eoshift1_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift1_4.c' object='eoshift1_4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift1_4.Plo' tmpdepfile='$(DEPDIR)/eoshift1_4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift1_4.lo `test -f 'generated/eoshift1_4.c' || echo '$(srcdir)/'`generated/eoshift1_4.c + +eoshift1_8.o: generated/eoshift1_8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift1_8.o -MD -MP -MF "$(DEPDIR)/eoshift1_8.Tpo" -c -o eoshift1_8.o `test -f 'generated/eoshift1_8.c' || echo '$(srcdir)/'`generated/eoshift1_8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift1_8.Tpo" "$(DEPDIR)/eoshift1_8.Po"; else rm -f "$(DEPDIR)/eoshift1_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift1_8.c' object='eoshift1_8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift1_8.Po' tmpdepfile='$(DEPDIR)/eoshift1_8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift1_8.o `test -f 'generated/eoshift1_8.c' || echo '$(srcdir)/'`generated/eoshift1_8.c + +eoshift1_8.obj: generated/eoshift1_8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift1_8.obj -MD -MP -MF "$(DEPDIR)/eoshift1_8.Tpo" -c -o eoshift1_8.obj `if test -f 'generated/eoshift1_8.c'; then $(CYGPATH_W) 'generated/eoshift1_8.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift1_8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift1_8.Tpo" "$(DEPDIR)/eoshift1_8.Po"; else rm -f "$(DEPDIR)/eoshift1_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift1_8.c' object='eoshift1_8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift1_8.Po' tmpdepfile='$(DEPDIR)/eoshift1_8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift1_8.obj `if test -f 'generated/eoshift1_8.c'; then $(CYGPATH_W) 'generated/eoshift1_8.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift1_8.c'; fi` + +eoshift1_8.lo: generated/eoshift1_8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift1_8.lo -MD -MP -MF "$(DEPDIR)/eoshift1_8.Tpo" -c -o eoshift1_8.lo `test -f 'generated/eoshift1_8.c' || echo '$(srcdir)/'`generated/eoshift1_8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift1_8.Tpo" "$(DEPDIR)/eoshift1_8.Plo"; else rm -f "$(DEPDIR)/eoshift1_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift1_8.c' object='eoshift1_8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift1_8.Plo' tmpdepfile='$(DEPDIR)/eoshift1_8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift1_8.lo `test -f 'generated/eoshift1_8.c' || echo '$(srcdir)/'`generated/eoshift1_8.c + +eoshift3_4.o: generated/eoshift3_4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift3_4.o -MD -MP -MF "$(DEPDIR)/eoshift3_4.Tpo" -c -o eoshift3_4.o `test -f 'generated/eoshift3_4.c' || echo '$(srcdir)/'`generated/eoshift3_4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift3_4.Tpo" "$(DEPDIR)/eoshift3_4.Po"; else rm -f "$(DEPDIR)/eoshift3_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift3_4.c' object='eoshift3_4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift3_4.Po' tmpdepfile='$(DEPDIR)/eoshift3_4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift3_4.o `test -f 'generated/eoshift3_4.c' || echo '$(srcdir)/'`generated/eoshift3_4.c + +eoshift3_4.obj: generated/eoshift3_4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift3_4.obj -MD -MP -MF "$(DEPDIR)/eoshift3_4.Tpo" -c -o eoshift3_4.obj `if test -f 'generated/eoshift3_4.c'; then $(CYGPATH_W) 'generated/eoshift3_4.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift3_4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift3_4.Tpo" "$(DEPDIR)/eoshift3_4.Po"; else rm -f "$(DEPDIR)/eoshift3_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift3_4.c' object='eoshift3_4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift3_4.Po' tmpdepfile='$(DEPDIR)/eoshift3_4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift3_4.obj `if test -f 'generated/eoshift3_4.c'; then $(CYGPATH_W) 'generated/eoshift3_4.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift3_4.c'; fi` + +eoshift3_4.lo: generated/eoshift3_4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift3_4.lo -MD -MP -MF "$(DEPDIR)/eoshift3_4.Tpo" -c -o eoshift3_4.lo `test -f 'generated/eoshift3_4.c' || echo '$(srcdir)/'`generated/eoshift3_4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift3_4.Tpo" "$(DEPDIR)/eoshift3_4.Plo"; else rm -f "$(DEPDIR)/eoshift3_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift3_4.c' object='eoshift3_4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift3_4.Plo' tmpdepfile='$(DEPDIR)/eoshift3_4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift3_4.lo `test -f 'generated/eoshift3_4.c' || echo '$(srcdir)/'`generated/eoshift3_4.c + +eoshift3_8.o: generated/eoshift3_8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift3_8.o -MD -MP -MF "$(DEPDIR)/eoshift3_8.Tpo" -c -o eoshift3_8.o `test -f 'generated/eoshift3_8.c' || echo '$(srcdir)/'`generated/eoshift3_8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift3_8.Tpo" "$(DEPDIR)/eoshift3_8.Po"; else rm -f "$(DEPDIR)/eoshift3_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift3_8.c' object='eoshift3_8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift3_8.Po' tmpdepfile='$(DEPDIR)/eoshift3_8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift3_8.o `test -f 'generated/eoshift3_8.c' || echo '$(srcdir)/'`generated/eoshift3_8.c + +eoshift3_8.obj: generated/eoshift3_8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift3_8.obj -MD -MP -MF "$(DEPDIR)/eoshift3_8.Tpo" -c -o eoshift3_8.obj `if test -f 'generated/eoshift3_8.c'; then $(CYGPATH_W) 'generated/eoshift3_8.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift3_8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift3_8.Tpo" "$(DEPDIR)/eoshift3_8.Po"; else rm -f "$(DEPDIR)/eoshift3_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift3_8.c' object='eoshift3_8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift3_8.Po' tmpdepfile='$(DEPDIR)/eoshift3_8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift3_8.obj `if test -f 'generated/eoshift3_8.c'; then $(CYGPATH_W) 'generated/eoshift3_8.c'; else $(CYGPATH_W) '$(srcdir)/generated/eoshift3_8.c'; fi` + +eoshift3_8.lo: generated/eoshift3_8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift3_8.lo -MD -MP -MF "$(DEPDIR)/eoshift3_8.Tpo" -c -o eoshift3_8.lo `test -f 'generated/eoshift3_8.c' || echo '$(srcdir)/'`generated/eoshift3_8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift3_8.Tpo" "$(DEPDIR)/eoshift3_8.Plo"; else rm -f "$(DEPDIR)/eoshift3_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/eoshift3_8.c' object='eoshift3_8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift3_8.Plo' tmpdepfile='$(DEPDIR)/eoshift3_8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift3_8.lo `test -f 'generated/eoshift3_8.c' || echo '$(srcdir)/'`generated/eoshift3_8.c + +cshift1_4.o: generated/cshift1_4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift1_4.o -MD -MP -MF "$(DEPDIR)/cshift1_4.Tpo" -c -o cshift1_4.o `test -f 'generated/cshift1_4.c' || echo '$(srcdir)/'`generated/cshift1_4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift1_4.Tpo" "$(DEPDIR)/cshift1_4.Po"; else rm -f "$(DEPDIR)/cshift1_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/cshift1_4.c' object='cshift1_4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift1_4.Po' tmpdepfile='$(DEPDIR)/cshift1_4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift1_4.o `test -f 'generated/cshift1_4.c' || echo '$(srcdir)/'`generated/cshift1_4.c + +cshift1_4.obj: generated/cshift1_4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift1_4.obj -MD -MP -MF "$(DEPDIR)/cshift1_4.Tpo" -c -o cshift1_4.obj `if test -f 'generated/cshift1_4.c'; then $(CYGPATH_W) 'generated/cshift1_4.c'; else $(CYGPATH_W) '$(srcdir)/generated/cshift1_4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift1_4.Tpo" "$(DEPDIR)/cshift1_4.Po"; else rm -f "$(DEPDIR)/cshift1_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/cshift1_4.c' object='cshift1_4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift1_4.Po' tmpdepfile='$(DEPDIR)/cshift1_4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift1_4.obj `if test -f 'generated/cshift1_4.c'; then $(CYGPATH_W) 'generated/cshift1_4.c'; else $(CYGPATH_W) '$(srcdir)/generated/cshift1_4.c'; fi` + +cshift1_4.lo: generated/cshift1_4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift1_4.lo -MD -MP -MF "$(DEPDIR)/cshift1_4.Tpo" -c -o cshift1_4.lo `test -f 'generated/cshift1_4.c' || echo '$(srcdir)/'`generated/cshift1_4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift1_4.Tpo" "$(DEPDIR)/cshift1_4.Plo"; else rm -f "$(DEPDIR)/cshift1_4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/cshift1_4.c' object='cshift1_4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift1_4.Plo' tmpdepfile='$(DEPDIR)/cshift1_4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift1_4.lo `test -f 'generated/cshift1_4.c' || echo '$(srcdir)/'`generated/cshift1_4.c + +cshift1_8.o: generated/cshift1_8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift1_8.o -MD -MP -MF "$(DEPDIR)/cshift1_8.Tpo" -c -o cshift1_8.o `test -f 'generated/cshift1_8.c' || echo '$(srcdir)/'`generated/cshift1_8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift1_8.Tpo" "$(DEPDIR)/cshift1_8.Po"; else rm -f "$(DEPDIR)/cshift1_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/cshift1_8.c' object='cshift1_8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift1_8.Po' tmpdepfile='$(DEPDIR)/cshift1_8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift1_8.o `test -f 'generated/cshift1_8.c' || echo '$(srcdir)/'`generated/cshift1_8.c + +cshift1_8.obj: generated/cshift1_8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift1_8.obj -MD -MP -MF "$(DEPDIR)/cshift1_8.Tpo" -c -o cshift1_8.obj `if test -f 'generated/cshift1_8.c'; then $(CYGPATH_W) 'generated/cshift1_8.c'; else $(CYGPATH_W) '$(srcdir)/generated/cshift1_8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift1_8.Tpo" "$(DEPDIR)/cshift1_8.Po"; else rm -f "$(DEPDIR)/cshift1_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/cshift1_8.c' object='cshift1_8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift1_8.Po' tmpdepfile='$(DEPDIR)/cshift1_8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift1_8.obj `if test -f 'generated/cshift1_8.c'; then $(CYGPATH_W) 'generated/cshift1_8.c'; else $(CYGPATH_W) '$(srcdir)/generated/cshift1_8.c'; fi` + +cshift1_8.lo: generated/cshift1_8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift1_8.lo -MD -MP -MF "$(DEPDIR)/cshift1_8.Tpo" -c -o cshift1_8.lo `test -f 'generated/cshift1_8.c' || echo '$(srcdir)/'`generated/cshift1_8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift1_8.Tpo" "$(DEPDIR)/cshift1_8.Plo"; else rm -f "$(DEPDIR)/cshift1_8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/cshift1_8.c' object='cshift1_8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift1_8.Plo' tmpdepfile='$(DEPDIR)/cshift1_8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift1_8.lo `test -f 'generated/cshift1_8.c' || echo '$(srcdir)/'`generated/cshift1_8.c + +reshape_i4.o: generated/reshape_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_i4.o -MD -MP -MF "$(DEPDIR)/reshape_i4.Tpo" -c -o reshape_i4.o `test -f 'generated/reshape_i4.c' || echo '$(srcdir)/'`generated/reshape_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_i4.Tpo" "$(DEPDIR)/reshape_i4.Po"; else rm -f "$(DEPDIR)/reshape_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/reshape_i4.c' object='reshape_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_i4.Po' tmpdepfile='$(DEPDIR)/reshape_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_i4.o `test -f 'generated/reshape_i4.c' || echo '$(srcdir)/'`generated/reshape_i4.c + +reshape_i4.obj: generated/reshape_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_i4.obj -MD -MP -MF "$(DEPDIR)/reshape_i4.Tpo" -c -o reshape_i4.obj `if test -f 'generated/reshape_i4.c'; then $(CYGPATH_W) 'generated/reshape_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/reshape_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_i4.Tpo" "$(DEPDIR)/reshape_i4.Po"; else rm -f "$(DEPDIR)/reshape_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/reshape_i4.c' object='reshape_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_i4.Po' tmpdepfile='$(DEPDIR)/reshape_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_i4.obj `if test -f 'generated/reshape_i4.c'; then $(CYGPATH_W) 'generated/reshape_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/reshape_i4.c'; fi` + +reshape_i4.lo: generated/reshape_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_i4.lo -MD -MP -MF "$(DEPDIR)/reshape_i4.Tpo" -c -o reshape_i4.lo `test -f 'generated/reshape_i4.c' || echo '$(srcdir)/'`generated/reshape_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_i4.Tpo" "$(DEPDIR)/reshape_i4.Plo"; else rm -f "$(DEPDIR)/reshape_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/reshape_i4.c' object='reshape_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_i4.Plo' tmpdepfile='$(DEPDIR)/reshape_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_i4.lo `test -f 'generated/reshape_i4.c' || echo '$(srcdir)/'`generated/reshape_i4.c + +reshape_i8.o: generated/reshape_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_i8.o -MD -MP -MF "$(DEPDIR)/reshape_i8.Tpo" -c -o reshape_i8.o `test -f 'generated/reshape_i8.c' || echo '$(srcdir)/'`generated/reshape_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_i8.Tpo" "$(DEPDIR)/reshape_i8.Po"; else rm -f "$(DEPDIR)/reshape_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/reshape_i8.c' object='reshape_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_i8.Po' tmpdepfile='$(DEPDIR)/reshape_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_i8.o `test -f 'generated/reshape_i8.c' || echo '$(srcdir)/'`generated/reshape_i8.c + +reshape_i8.obj: generated/reshape_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_i8.obj -MD -MP -MF "$(DEPDIR)/reshape_i8.Tpo" -c -o reshape_i8.obj `if test -f 'generated/reshape_i8.c'; then $(CYGPATH_W) 'generated/reshape_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/reshape_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_i8.Tpo" "$(DEPDIR)/reshape_i8.Po"; else rm -f "$(DEPDIR)/reshape_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/reshape_i8.c' object='reshape_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_i8.Po' tmpdepfile='$(DEPDIR)/reshape_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_i8.obj `if test -f 'generated/reshape_i8.c'; then $(CYGPATH_W) 'generated/reshape_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/reshape_i8.c'; fi` + +reshape_i8.lo: generated/reshape_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_i8.lo -MD -MP -MF "$(DEPDIR)/reshape_i8.Tpo" -c -o reshape_i8.lo `test -f 'generated/reshape_i8.c' || echo '$(srcdir)/'`generated/reshape_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_i8.Tpo" "$(DEPDIR)/reshape_i8.Plo"; else rm -f "$(DEPDIR)/reshape_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/reshape_i8.c' object='reshape_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_i8.Plo' tmpdepfile='$(DEPDIR)/reshape_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_i8.lo `test -f 'generated/reshape_i8.c' || echo '$(srcdir)/'`generated/reshape_i8.c + +in_pack_i4.o: generated/in_pack_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_i4.o -MD -MP -MF "$(DEPDIR)/in_pack_i4.Tpo" -c -o in_pack_i4.o `test -f 'generated/in_pack_i4.c' || echo '$(srcdir)/'`generated/in_pack_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_i4.Tpo" "$(DEPDIR)/in_pack_i4.Po"; else rm -f "$(DEPDIR)/in_pack_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_pack_i4.c' object='in_pack_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_i4.Po' tmpdepfile='$(DEPDIR)/in_pack_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_i4.o `test -f 'generated/in_pack_i4.c' || echo '$(srcdir)/'`generated/in_pack_i4.c + +in_pack_i4.obj: generated/in_pack_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_i4.obj -MD -MP -MF "$(DEPDIR)/in_pack_i4.Tpo" -c -o in_pack_i4.obj `if test -f 'generated/in_pack_i4.c'; then $(CYGPATH_W) 'generated/in_pack_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_pack_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_i4.Tpo" "$(DEPDIR)/in_pack_i4.Po"; else rm -f "$(DEPDIR)/in_pack_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_pack_i4.c' object='in_pack_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_i4.Po' tmpdepfile='$(DEPDIR)/in_pack_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_i4.obj `if test -f 'generated/in_pack_i4.c'; then $(CYGPATH_W) 'generated/in_pack_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_pack_i4.c'; fi` + +in_pack_i4.lo: generated/in_pack_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_i4.lo -MD -MP -MF "$(DEPDIR)/in_pack_i4.Tpo" -c -o in_pack_i4.lo `test -f 'generated/in_pack_i4.c' || echo '$(srcdir)/'`generated/in_pack_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_i4.Tpo" "$(DEPDIR)/in_pack_i4.Plo"; else rm -f "$(DEPDIR)/in_pack_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_pack_i4.c' object='in_pack_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_i4.Plo' tmpdepfile='$(DEPDIR)/in_pack_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_i4.lo `test -f 'generated/in_pack_i4.c' || echo '$(srcdir)/'`generated/in_pack_i4.c + +in_pack_i8.o: generated/in_pack_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_i8.o -MD -MP -MF "$(DEPDIR)/in_pack_i8.Tpo" -c -o in_pack_i8.o `test -f 'generated/in_pack_i8.c' || echo '$(srcdir)/'`generated/in_pack_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_i8.Tpo" "$(DEPDIR)/in_pack_i8.Po"; else rm -f "$(DEPDIR)/in_pack_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_pack_i8.c' object='in_pack_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_i8.Po' tmpdepfile='$(DEPDIR)/in_pack_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_i8.o `test -f 'generated/in_pack_i8.c' || echo '$(srcdir)/'`generated/in_pack_i8.c + +in_pack_i8.obj: generated/in_pack_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_i8.obj -MD -MP -MF "$(DEPDIR)/in_pack_i8.Tpo" -c -o in_pack_i8.obj `if test -f 'generated/in_pack_i8.c'; then $(CYGPATH_W) 'generated/in_pack_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_pack_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_i8.Tpo" "$(DEPDIR)/in_pack_i8.Po"; else rm -f "$(DEPDIR)/in_pack_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_pack_i8.c' object='in_pack_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_i8.Po' tmpdepfile='$(DEPDIR)/in_pack_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_i8.obj `if test -f 'generated/in_pack_i8.c'; then $(CYGPATH_W) 'generated/in_pack_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_pack_i8.c'; fi` + +in_pack_i8.lo: generated/in_pack_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_i8.lo -MD -MP -MF "$(DEPDIR)/in_pack_i8.Tpo" -c -o in_pack_i8.lo `test -f 'generated/in_pack_i8.c' || echo '$(srcdir)/'`generated/in_pack_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_i8.Tpo" "$(DEPDIR)/in_pack_i8.Plo"; else rm -f "$(DEPDIR)/in_pack_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_pack_i8.c' object='in_pack_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_i8.Plo' tmpdepfile='$(DEPDIR)/in_pack_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_i8.lo `test -f 'generated/in_pack_i8.c' || echo '$(srcdir)/'`generated/in_pack_i8.c + +in_unpack_i4.o: generated/in_unpack_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_i4.o -MD -MP -MF "$(DEPDIR)/in_unpack_i4.Tpo" -c -o in_unpack_i4.o `test -f 'generated/in_unpack_i4.c' || echo '$(srcdir)/'`generated/in_unpack_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_i4.Tpo" "$(DEPDIR)/in_unpack_i4.Po"; else rm -f "$(DEPDIR)/in_unpack_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_unpack_i4.c' object='in_unpack_i4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_i4.Po' tmpdepfile='$(DEPDIR)/in_unpack_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_i4.o `test -f 'generated/in_unpack_i4.c' || echo '$(srcdir)/'`generated/in_unpack_i4.c + +in_unpack_i4.obj: generated/in_unpack_i4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_i4.obj -MD -MP -MF "$(DEPDIR)/in_unpack_i4.Tpo" -c -o in_unpack_i4.obj `if test -f 'generated/in_unpack_i4.c'; then $(CYGPATH_W) 'generated/in_unpack_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_unpack_i4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_i4.Tpo" "$(DEPDIR)/in_unpack_i4.Po"; else rm -f "$(DEPDIR)/in_unpack_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_unpack_i4.c' object='in_unpack_i4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_i4.Po' tmpdepfile='$(DEPDIR)/in_unpack_i4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_i4.obj `if test -f 'generated/in_unpack_i4.c'; then $(CYGPATH_W) 'generated/in_unpack_i4.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_unpack_i4.c'; fi` + +in_unpack_i4.lo: generated/in_unpack_i4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_i4.lo -MD -MP -MF "$(DEPDIR)/in_unpack_i4.Tpo" -c -o in_unpack_i4.lo `test -f 'generated/in_unpack_i4.c' || echo '$(srcdir)/'`generated/in_unpack_i4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_i4.Tpo" "$(DEPDIR)/in_unpack_i4.Plo"; else rm -f "$(DEPDIR)/in_unpack_i4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_unpack_i4.c' object='in_unpack_i4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_i4.Plo' tmpdepfile='$(DEPDIR)/in_unpack_i4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_i4.lo `test -f 'generated/in_unpack_i4.c' || echo '$(srcdir)/'`generated/in_unpack_i4.c + +in_unpack_i8.o: generated/in_unpack_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_i8.o -MD -MP -MF "$(DEPDIR)/in_unpack_i8.Tpo" -c -o in_unpack_i8.o `test -f 'generated/in_unpack_i8.c' || echo '$(srcdir)/'`generated/in_unpack_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_i8.Tpo" "$(DEPDIR)/in_unpack_i8.Po"; else rm -f "$(DEPDIR)/in_unpack_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_unpack_i8.c' object='in_unpack_i8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_i8.Po' tmpdepfile='$(DEPDIR)/in_unpack_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_i8.o `test -f 'generated/in_unpack_i8.c' || echo '$(srcdir)/'`generated/in_unpack_i8.c + +in_unpack_i8.obj: generated/in_unpack_i8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_i8.obj -MD -MP -MF "$(DEPDIR)/in_unpack_i8.Tpo" -c -o in_unpack_i8.obj `if test -f 'generated/in_unpack_i8.c'; then $(CYGPATH_W) 'generated/in_unpack_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_unpack_i8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_i8.Tpo" "$(DEPDIR)/in_unpack_i8.Po"; else rm -f "$(DEPDIR)/in_unpack_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_unpack_i8.c' object='in_unpack_i8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_i8.Po' tmpdepfile='$(DEPDIR)/in_unpack_i8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_i8.obj `if test -f 'generated/in_unpack_i8.c'; then $(CYGPATH_W) 'generated/in_unpack_i8.c'; else $(CYGPATH_W) '$(srcdir)/generated/in_unpack_i8.c'; fi` + +in_unpack_i8.lo: generated/in_unpack_i8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_i8.lo -MD -MP -MF "$(DEPDIR)/in_unpack_i8.Tpo" -c -o in_unpack_i8.lo `test -f 'generated/in_unpack_i8.c' || echo '$(srcdir)/'`generated/in_unpack_i8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_i8.Tpo" "$(DEPDIR)/in_unpack_i8.Plo"; else rm -f "$(DEPDIR)/in_unpack_i8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/in_unpack_i8.c' object='in_unpack_i8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_i8.Plo' tmpdepfile='$(DEPDIR)/in_unpack_i8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_i8.lo `test -f 'generated/in_unpack_i8.c' || echo '$(srcdir)/'`generated/in_unpack_i8.c + +exponent_r4.o: generated/exponent_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exponent_r4.o -MD -MP -MF "$(DEPDIR)/exponent_r4.Tpo" -c -o exponent_r4.o `test -f 'generated/exponent_r4.c' || echo '$(srcdir)/'`generated/exponent_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exponent_r4.Tpo" "$(DEPDIR)/exponent_r4.Po"; else rm -f "$(DEPDIR)/exponent_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exponent_r4.c' object='exponent_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exponent_r4.Po' tmpdepfile='$(DEPDIR)/exponent_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exponent_r4.o `test -f 'generated/exponent_r4.c' || echo '$(srcdir)/'`generated/exponent_r4.c + +exponent_r4.obj: generated/exponent_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exponent_r4.obj -MD -MP -MF "$(DEPDIR)/exponent_r4.Tpo" -c -o exponent_r4.obj `if test -f 'generated/exponent_r4.c'; then $(CYGPATH_W) 'generated/exponent_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/exponent_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exponent_r4.Tpo" "$(DEPDIR)/exponent_r4.Po"; else rm -f "$(DEPDIR)/exponent_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exponent_r4.c' object='exponent_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exponent_r4.Po' tmpdepfile='$(DEPDIR)/exponent_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exponent_r4.obj `if test -f 'generated/exponent_r4.c'; then $(CYGPATH_W) 'generated/exponent_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/exponent_r4.c'; fi` + +exponent_r4.lo: generated/exponent_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exponent_r4.lo -MD -MP -MF "$(DEPDIR)/exponent_r4.Tpo" -c -o exponent_r4.lo `test -f 'generated/exponent_r4.c' || echo '$(srcdir)/'`generated/exponent_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exponent_r4.Tpo" "$(DEPDIR)/exponent_r4.Plo"; else rm -f "$(DEPDIR)/exponent_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exponent_r4.c' object='exponent_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exponent_r4.Plo' tmpdepfile='$(DEPDIR)/exponent_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exponent_r4.lo `test -f 'generated/exponent_r4.c' || echo '$(srcdir)/'`generated/exponent_r4.c + +exponent_r8.o: generated/exponent_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exponent_r8.o -MD -MP -MF "$(DEPDIR)/exponent_r8.Tpo" -c -o exponent_r8.o `test -f 'generated/exponent_r8.c' || echo '$(srcdir)/'`generated/exponent_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exponent_r8.Tpo" "$(DEPDIR)/exponent_r8.Po"; else rm -f "$(DEPDIR)/exponent_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exponent_r8.c' object='exponent_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exponent_r8.Po' tmpdepfile='$(DEPDIR)/exponent_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exponent_r8.o `test -f 'generated/exponent_r8.c' || echo '$(srcdir)/'`generated/exponent_r8.c + +exponent_r8.obj: generated/exponent_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exponent_r8.obj -MD -MP -MF "$(DEPDIR)/exponent_r8.Tpo" -c -o exponent_r8.obj `if test -f 'generated/exponent_r8.c'; then $(CYGPATH_W) 'generated/exponent_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/exponent_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exponent_r8.Tpo" "$(DEPDIR)/exponent_r8.Po"; else rm -f "$(DEPDIR)/exponent_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exponent_r8.c' object='exponent_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exponent_r8.Po' tmpdepfile='$(DEPDIR)/exponent_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exponent_r8.obj `if test -f 'generated/exponent_r8.c'; then $(CYGPATH_W) 'generated/exponent_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/exponent_r8.c'; fi` + +exponent_r8.lo: generated/exponent_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exponent_r8.lo -MD -MP -MF "$(DEPDIR)/exponent_r8.Tpo" -c -o exponent_r8.lo `test -f 'generated/exponent_r8.c' || echo '$(srcdir)/'`generated/exponent_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exponent_r8.Tpo" "$(DEPDIR)/exponent_r8.Plo"; else rm -f "$(DEPDIR)/exponent_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exponent_r8.c' object='exponent_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exponent_r8.Plo' tmpdepfile='$(DEPDIR)/exponent_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exponent_r8.lo `test -f 'generated/exponent_r8.c' || echo '$(srcdir)/'`generated/exponent_r8.c + +fraction_r4.o: generated/fraction_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fraction_r4.o -MD -MP -MF "$(DEPDIR)/fraction_r4.Tpo" -c -o fraction_r4.o `test -f 'generated/fraction_r4.c' || echo '$(srcdir)/'`generated/fraction_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fraction_r4.Tpo" "$(DEPDIR)/fraction_r4.Po"; else rm -f "$(DEPDIR)/fraction_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/fraction_r4.c' object='fraction_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/fraction_r4.Po' tmpdepfile='$(DEPDIR)/fraction_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fraction_r4.o `test -f 'generated/fraction_r4.c' || echo '$(srcdir)/'`generated/fraction_r4.c + +fraction_r4.obj: generated/fraction_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fraction_r4.obj -MD -MP -MF "$(DEPDIR)/fraction_r4.Tpo" -c -o fraction_r4.obj `if test -f 'generated/fraction_r4.c'; then $(CYGPATH_W) 'generated/fraction_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/fraction_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fraction_r4.Tpo" "$(DEPDIR)/fraction_r4.Po"; else rm -f "$(DEPDIR)/fraction_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/fraction_r4.c' object='fraction_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/fraction_r4.Po' tmpdepfile='$(DEPDIR)/fraction_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fraction_r4.obj `if test -f 'generated/fraction_r4.c'; then $(CYGPATH_W) 'generated/fraction_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/fraction_r4.c'; fi` + +fraction_r4.lo: generated/fraction_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fraction_r4.lo -MD -MP -MF "$(DEPDIR)/fraction_r4.Tpo" -c -o fraction_r4.lo `test -f 'generated/fraction_r4.c' || echo '$(srcdir)/'`generated/fraction_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fraction_r4.Tpo" "$(DEPDIR)/fraction_r4.Plo"; else rm -f "$(DEPDIR)/fraction_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/fraction_r4.c' object='fraction_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/fraction_r4.Plo' tmpdepfile='$(DEPDIR)/fraction_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fraction_r4.lo `test -f 'generated/fraction_r4.c' || echo '$(srcdir)/'`generated/fraction_r4.c + +fraction_r8.o: generated/fraction_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fraction_r8.o -MD -MP -MF "$(DEPDIR)/fraction_r8.Tpo" -c -o fraction_r8.o `test -f 'generated/fraction_r8.c' || echo '$(srcdir)/'`generated/fraction_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fraction_r8.Tpo" "$(DEPDIR)/fraction_r8.Po"; else rm -f "$(DEPDIR)/fraction_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/fraction_r8.c' object='fraction_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/fraction_r8.Po' tmpdepfile='$(DEPDIR)/fraction_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fraction_r8.o `test -f 'generated/fraction_r8.c' || echo '$(srcdir)/'`generated/fraction_r8.c + +fraction_r8.obj: generated/fraction_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fraction_r8.obj -MD -MP -MF "$(DEPDIR)/fraction_r8.Tpo" -c -o fraction_r8.obj `if test -f 'generated/fraction_r8.c'; then $(CYGPATH_W) 'generated/fraction_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/fraction_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fraction_r8.Tpo" "$(DEPDIR)/fraction_r8.Po"; else rm -f "$(DEPDIR)/fraction_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/fraction_r8.c' object='fraction_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/fraction_r8.Po' tmpdepfile='$(DEPDIR)/fraction_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fraction_r8.obj `if test -f 'generated/fraction_r8.c'; then $(CYGPATH_W) 'generated/fraction_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/fraction_r8.c'; fi` + +fraction_r8.lo: generated/fraction_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fraction_r8.lo -MD -MP -MF "$(DEPDIR)/fraction_r8.Tpo" -c -o fraction_r8.lo `test -f 'generated/fraction_r8.c' || echo '$(srcdir)/'`generated/fraction_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/fraction_r8.Tpo" "$(DEPDIR)/fraction_r8.Plo"; else rm -f "$(DEPDIR)/fraction_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/fraction_r8.c' object='fraction_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/fraction_r8.Plo' tmpdepfile='$(DEPDIR)/fraction_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fraction_r8.lo `test -f 'generated/fraction_r8.c' || echo '$(srcdir)/'`generated/fraction_r8.c + +nearest_r4.o: generated/nearest_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nearest_r4.o -MD -MP -MF "$(DEPDIR)/nearest_r4.Tpo" -c -o nearest_r4.o `test -f 'generated/nearest_r4.c' || echo '$(srcdir)/'`generated/nearest_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nearest_r4.Tpo" "$(DEPDIR)/nearest_r4.Po"; else rm -f "$(DEPDIR)/nearest_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/nearest_r4.c' object='nearest_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/nearest_r4.Po' tmpdepfile='$(DEPDIR)/nearest_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nearest_r4.o `test -f 'generated/nearest_r4.c' || echo '$(srcdir)/'`generated/nearest_r4.c + +nearest_r4.obj: generated/nearest_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nearest_r4.obj -MD -MP -MF "$(DEPDIR)/nearest_r4.Tpo" -c -o nearest_r4.obj `if test -f 'generated/nearest_r4.c'; then $(CYGPATH_W) 'generated/nearest_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/nearest_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nearest_r4.Tpo" "$(DEPDIR)/nearest_r4.Po"; else rm -f "$(DEPDIR)/nearest_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/nearest_r4.c' object='nearest_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/nearest_r4.Po' tmpdepfile='$(DEPDIR)/nearest_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nearest_r4.obj `if test -f 'generated/nearest_r4.c'; then $(CYGPATH_W) 'generated/nearest_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/nearest_r4.c'; fi` + +nearest_r4.lo: generated/nearest_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nearest_r4.lo -MD -MP -MF "$(DEPDIR)/nearest_r4.Tpo" -c -o nearest_r4.lo `test -f 'generated/nearest_r4.c' || echo '$(srcdir)/'`generated/nearest_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nearest_r4.Tpo" "$(DEPDIR)/nearest_r4.Plo"; else rm -f "$(DEPDIR)/nearest_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/nearest_r4.c' object='nearest_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/nearest_r4.Plo' tmpdepfile='$(DEPDIR)/nearest_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nearest_r4.lo `test -f 'generated/nearest_r4.c' || echo '$(srcdir)/'`generated/nearest_r4.c + +nearest_r8.o: generated/nearest_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nearest_r8.o -MD -MP -MF "$(DEPDIR)/nearest_r8.Tpo" -c -o nearest_r8.o `test -f 'generated/nearest_r8.c' || echo '$(srcdir)/'`generated/nearest_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nearest_r8.Tpo" "$(DEPDIR)/nearest_r8.Po"; else rm -f "$(DEPDIR)/nearest_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/nearest_r8.c' object='nearest_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/nearest_r8.Po' tmpdepfile='$(DEPDIR)/nearest_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nearest_r8.o `test -f 'generated/nearest_r8.c' || echo '$(srcdir)/'`generated/nearest_r8.c + +nearest_r8.obj: generated/nearest_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nearest_r8.obj -MD -MP -MF "$(DEPDIR)/nearest_r8.Tpo" -c -o nearest_r8.obj `if test -f 'generated/nearest_r8.c'; then $(CYGPATH_W) 'generated/nearest_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/nearest_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nearest_r8.Tpo" "$(DEPDIR)/nearest_r8.Po"; else rm -f "$(DEPDIR)/nearest_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/nearest_r8.c' object='nearest_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/nearest_r8.Po' tmpdepfile='$(DEPDIR)/nearest_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nearest_r8.obj `if test -f 'generated/nearest_r8.c'; then $(CYGPATH_W) 'generated/nearest_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/nearest_r8.c'; fi` + +nearest_r8.lo: generated/nearest_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nearest_r8.lo -MD -MP -MF "$(DEPDIR)/nearest_r8.Tpo" -c -o nearest_r8.lo `test -f 'generated/nearest_r8.c' || echo '$(srcdir)/'`generated/nearest_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/nearest_r8.Tpo" "$(DEPDIR)/nearest_r8.Plo"; else rm -f "$(DEPDIR)/nearest_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/nearest_r8.c' object='nearest_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/nearest_r8.Plo' tmpdepfile='$(DEPDIR)/nearest_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nearest_r8.lo `test -f 'generated/nearest_r8.c' || echo '$(srcdir)/'`generated/nearest_r8.c + +set_exponent_r4.o: generated/set_exponent_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_exponent_r4.o -MD -MP -MF "$(DEPDIR)/set_exponent_r4.Tpo" -c -o set_exponent_r4.o `test -f 'generated/set_exponent_r4.c' || echo '$(srcdir)/'`generated/set_exponent_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_exponent_r4.Tpo" "$(DEPDIR)/set_exponent_r4.Po"; else rm -f "$(DEPDIR)/set_exponent_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/set_exponent_r4.c' object='set_exponent_r4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/set_exponent_r4.Po' tmpdepfile='$(DEPDIR)/set_exponent_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_exponent_r4.o `test -f 'generated/set_exponent_r4.c' || echo '$(srcdir)/'`generated/set_exponent_r4.c + +set_exponent_r4.obj: generated/set_exponent_r4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_exponent_r4.obj -MD -MP -MF "$(DEPDIR)/set_exponent_r4.Tpo" -c -o set_exponent_r4.obj `if test -f 'generated/set_exponent_r4.c'; then $(CYGPATH_W) 'generated/set_exponent_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/set_exponent_r4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_exponent_r4.Tpo" "$(DEPDIR)/set_exponent_r4.Po"; else rm -f "$(DEPDIR)/set_exponent_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/set_exponent_r4.c' object='set_exponent_r4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/set_exponent_r4.Po' tmpdepfile='$(DEPDIR)/set_exponent_r4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_exponent_r4.obj `if test -f 'generated/set_exponent_r4.c'; then $(CYGPATH_W) 'generated/set_exponent_r4.c'; else $(CYGPATH_W) '$(srcdir)/generated/set_exponent_r4.c'; fi` + +set_exponent_r4.lo: generated/set_exponent_r4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_exponent_r4.lo -MD -MP -MF "$(DEPDIR)/set_exponent_r4.Tpo" -c -o set_exponent_r4.lo `test -f 'generated/set_exponent_r4.c' || echo '$(srcdir)/'`generated/set_exponent_r4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_exponent_r4.Tpo" "$(DEPDIR)/set_exponent_r4.Plo"; else rm -f "$(DEPDIR)/set_exponent_r4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/set_exponent_r4.c' object='set_exponent_r4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/set_exponent_r4.Plo' tmpdepfile='$(DEPDIR)/set_exponent_r4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_exponent_r4.lo `test -f 'generated/set_exponent_r4.c' || echo '$(srcdir)/'`generated/set_exponent_r4.c + +set_exponent_r8.o: generated/set_exponent_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_exponent_r8.o -MD -MP -MF "$(DEPDIR)/set_exponent_r8.Tpo" -c -o set_exponent_r8.o `test -f 'generated/set_exponent_r8.c' || echo '$(srcdir)/'`generated/set_exponent_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_exponent_r8.Tpo" "$(DEPDIR)/set_exponent_r8.Po"; else rm -f "$(DEPDIR)/set_exponent_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/set_exponent_r8.c' object='set_exponent_r8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/set_exponent_r8.Po' tmpdepfile='$(DEPDIR)/set_exponent_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_exponent_r8.o `test -f 'generated/set_exponent_r8.c' || echo '$(srcdir)/'`generated/set_exponent_r8.c + +set_exponent_r8.obj: generated/set_exponent_r8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_exponent_r8.obj -MD -MP -MF "$(DEPDIR)/set_exponent_r8.Tpo" -c -o set_exponent_r8.obj `if test -f 'generated/set_exponent_r8.c'; then $(CYGPATH_W) 'generated/set_exponent_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/set_exponent_r8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_exponent_r8.Tpo" "$(DEPDIR)/set_exponent_r8.Po"; else rm -f "$(DEPDIR)/set_exponent_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/set_exponent_r8.c' object='set_exponent_r8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/set_exponent_r8.Po' tmpdepfile='$(DEPDIR)/set_exponent_r8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_exponent_r8.obj `if test -f 'generated/set_exponent_r8.c'; then $(CYGPATH_W) 'generated/set_exponent_r8.c'; else $(CYGPATH_W) '$(srcdir)/generated/set_exponent_r8.c'; fi` + +set_exponent_r8.lo: generated/set_exponent_r8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT set_exponent_r8.lo -MD -MP -MF "$(DEPDIR)/set_exponent_r8.Tpo" -c -o set_exponent_r8.lo `test -f 'generated/set_exponent_r8.c' || echo '$(srcdir)/'`generated/set_exponent_r8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/set_exponent_r8.Tpo" "$(DEPDIR)/set_exponent_r8.Plo"; else rm -f "$(DEPDIR)/set_exponent_r8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/set_exponent_r8.c' object='set_exponent_r8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/set_exponent_r8.Plo' tmpdepfile='$(DEPDIR)/set_exponent_r8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o set_exponent_r8.lo `test -f 'generated/set_exponent_r8.c' || echo '$(srcdir)/'`generated/set_exponent_r8.c + +backspace.o: io/backspace.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backspace.o -MD -MP -MF "$(DEPDIR)/backspace.Tpo" -c -o backspace.o `test -f 'io/backspace.c' || echo '$(srcdir)/'`io/backspace.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/backspace.Tpo" "$(DEPDIR)/backspace.Po"; else rm -f "$(DEPDIR)/backspace.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/backspace.c' object='backspace.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/backspace.Po' tmpdepfile='$(DEPDIR)/backspace.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backspace.o `test -f 'io/backspace.c' || echo '$(srcdir)/'`io/backspace.c + +backspace.obj: io/backspace.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backspace.obj -MD -MP -MF "$(DEPDIR)/backspace.Tpo" -c -o backspace.obj `if test -f 'io/backspace.c'; then $(CYGPATH_W) 'io/backspace.c'; else $(CYGPATH_W) '$(srcdir)/io/backspace.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/backspace.Tpo" "$(DEPDIR)/backspace.Po"; else rm -f "$(DEPDIR)/backspace.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/backspace.c' object='backspace.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/backspace.Po' tmpdepfile='$(DEPDIR)/backspace.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backspace.obj `if test -f 'io/backspace.c'; then $(CYGPATH_W) 'io/backspace.c'; else $(CYGPATH_W) '$(srcdir)/io/backspace.c'; fi` + +backspace.lo: io/backspace.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backspace.lo -MD -MP -MF "$(DEPDIR)/backspace.Tpo" -c -o backspace.lo `test -f 'io/backspace.c' || echo '$(srcdir)/'`io/backspace.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/backspace.Tpo" "$(DEPDIR)/backspace.Plo"; else rm -f "$(DEPDIR)/backspace.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/backspace.c' object='backspace.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/backspace.Plo' tmpdepfile='$(DEPDIR)/backspace.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backspace.lo `test -f 'io/backspace.c' || echo '$(srcdir)/'`io/backspace.c + +close.o: io/close.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT close.o -MD -MP -MF "$(DEPDIR)/close.Tpo" -c -o close.o `test -f 'io/close.c' || echo '$(srcdir)/'`io/close.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/close.Tpo" "$(DEPDIR)/close.Po"; else rm -f "$(DEPDIR)/close.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/close.c' object='close.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/close.Po' tmpdepfile='$(DEPDIR)/close.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o close.o `test -f 'io/close.c' || echo '$(srcdir)/'`io/close.c + +close.obj: io/close.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT close.obj -MD -MP -MF "$(DEPDIR)/close.Tpo" -c -o close.obj `if test -f 'io/close.c'; then $(CYGPATH_W) 'io/close.c'; else $(CYGPATH_W) '$(srcdir)/io/close.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/close.Tpo" "$(DEPDIR)/close.Po"; else rm -f "$(DEPDIR)/close.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/close.c' object='close.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/close.Po' tmpdepfile='$(DEPDIR)/close.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o close.obj `if test -f 'io/close.c'; then $(CYGPATH_W) 'io/close.c'; else $(CYGPATH_W) '$(srcdir)/io/close.c'; fi` + +close.lo: io/close.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT close.lo -MD -MP -MF "$(DEPDIR)/close.Tpo" -c -o close.lo `test -f 'io/close.c' || echo '$(srcdir)/'`io/close.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/close.Tpo" "$(DEPDIR)/close.Plo"; else rm -f "$(DEPDIR)/close.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/close.c' object='close.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/close.Plo' tmpdepfile='$(DEPDIR)/close.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o close.lo `test -f 'io/close.c' || echo '$(srcdir)/'`io/close.c + +endfile.o: io/endfile.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT endfile.o -MD -MP -MF "$(DEPDIR)/endfile.Tpo" -c -o endfile.o `test -f 'io/endfile.c' || echo '$(srcdir)/'`io/endfile.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/endfile.Tpo" "$(DEPDIR)/endfile.Po"; else rm -f "$(DEPDIR)/endfile.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/endfile.c' object='endfile.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/endfile.Po' tmpdepfile='$(DEPDIR)/endfile.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o endfile.o `test -f 'io/endfile.c' || echo '$(srcdir)/'`io/endfile.c + +endfile.obj: io/endfile.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT endfile.obj -MD -MP -MF "$(DEPDIR)/endfile.Tpo" -c -o endfile.obj `if test -f 'io/endfile.c'; then $(CYGPATH_W) 'io/endfile.c'; else $(CYGPATH_W) '$(srcdir)/io/endfile.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/endfile.Tpo" "$(DEPDIR)/endfile.Po"; else rm -f "$(DEPDIR)/endfile.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/endfile.c' object='endfile.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/endfile.Po' tmpdepfile='$(DEPDIR)/endfile.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o endfile.obj `if test -f 'io/endfile.c'; then $(CYGPATH_W) 'io/endfile.c'; else $(CYGPATH_W) '$(srcdir)/io/endfile.c'; fi` + +endfile.lo: io/endfile.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT endfile.lo -MD -MP -MF "$(DEPDIR)/endfile.Tpo" -c -o endfile.lo `test -f 'io/endfile.c' || echo '$(srcdir)/'`io/endfile.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/endfile.Tpo" "$(DEPDIR)/endfile.Plo"; else rm -f "$(DEPDIR)/endfile.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/endfile.c' object='endfile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/endfile.Plo' tmpdepfile='$(DEPDIR)/endfile.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o endfile.lo `test -f 'io/endfile.c' || echo '$(srcdir)/'`io/endfile.c + +format.o: io/format.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT format.o -MD -MP -MF "$(DEPDIR)/format.Tpo" -c -o format.o `test -f 'io/format.c' || echo '$(srcdir)/'`io/format.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/format.Tpo" "$(DEPDIR)/format.Po"; else rm -f "$(DEPDIR)/format.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/format.c' object='format.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/format.Po' tmpdepfile='$(DEPDIR)/format.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o format.o `test -f 'io/format.c' || echo '$(srcdir)/'`io/format.c + +format.obj: io/format.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT format.obj -MD -MP -MF "$(DEPDIR)/format.Tpo" -c -o format.obj `if test -f 'io/format.c'; then $(CYGPATH_W) 'io/format.c'; else $(CYGPATH_W) '$(srcdir)/io/format.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/format.Tpo" "$(DEPDIR)/format.Po"; else rm -f "$(DEPDIR)/format.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/format.c' object='format.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/format.Po' tmpdepfile='$(DEPDIR)/format.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o format.obj `if test -f 'io/format.c'; then $(CYGPATH_W) 'io/format.c'; else $(CYGPATH_W) '$(srcdir)/io/format.c'; fi` + +format.lo: io/format.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT format.lo -MD -MP -MF "$(DEPDIR)/format.Tpo" -c -o format.lo `test -f 'io/format.c' || echo '$(srcdir)/'`io/format.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/format.Tpo" "$(DEPDIR)/format.Plo"; else rm -f "$(DEPDIR)/format.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/format.c' object='format.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/format.Plo' tmpdepfile='$(DEPDIR)/format.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o format.lo `test -f 'io/format.c' || echo '$(srcdir)/'`io/format.c + +inquire.o: io/inquire.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inquire.o -MD -MP -MF "$(DEPDIR)/inquire.Tpo" -c -o inquire.o `test -f 'io/inquire.c' || echo '$(srcdir)/'`io/inquire.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/inquire.Tpo" "$(DEPDIR)/inquire.Po"; else rm -f "$(DEPDIR)/inquire.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/inquire.c' object='inquire.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/inquire.Po' tmpdepfile='$(DEPDIR)/inquire.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inquire.o `test -f 'io/inquire.c' || echo '$(srcdir)/'`io/inquire.c + +inquire.obj: io/inquire.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inquire.obj -MD -MP -MF "$(DEPDIR)/inquire.Tpo" -c -o inquire.obj `if test -f 'io/inquire.c'; then $(CYGPATH_W) 'io/inquire.c'; else $(CYGPATH_W) '$(srcdir)/io/inquire.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/inquire.Tpo" "$(DEPDIR)/inquire.Po"; else rm -f "$(DEPDIR)/inquire.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/inquire.c' object='inquire.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/inquire.Po' tmpdepfile='$(DEPDIR)/inquire.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inquire.obj `if test -f 'io/inquire.c'; then $(CYGPATH_W) 'io/inquire.c'; else $(CYGPATH_W) '$(srcdir)/io/inquire.c'; fi` + +inquire.lo: io/inquire.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT inquire.lo -MD -MP -MF "$(DEPDIR)/inquire.Tpo" -c -o inquire.lo `test -f 'io/inquire.c' || echo '$(srcdir)/'`io/inquire.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/inquire.Tpo" "$(DEPDIR)/inquire.Plo"; else rm -f "$(DEPDIR)/inquire.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/inquire.c' object='inquire.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/inquire.Plo' tmpdepfile='$(DEPDIR)/inquire.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inquire.lo `test -f 'io/inquire.c' || echo '$(srcdir)/'`io/inquire.c + +list_read.o: io/list_read.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT list_read.o -MD -MP -MF "$(DEPDIR)/list_read.Tpo" -c -o list_read.o `test -f 'io/list_read.c' || echo '$(srcdir)/'`io/list_read.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/list_read.Tpo" "$(DEPDIR)/list_read.Po"; else rm -f "$(DEPDIR)/list_read.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/list_read.c' object='list_read.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/list_read.Po' tmpdepfile='$(DEPDIR)/list_read.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o list_read.o `test -f 'io/list_read.c' || echo '$(srcdir)/'`io/list_read.c + +list_read.obj: io/list_read.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT list_read.obj -MD -MP -MF "$(DEPDIR)/list_read.Tpo" -c -o list_read.obj `if test -f 'io/list_read.c'; then $(CYGPATH_W) 'io/list_read.c'; else $(CYGPATH_W) '$(srcdir)/io/list_read.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/list_read.Tpo" "$(DEPDIR)/list_read.Po"; else rm -f "$(DEPDIR)/list_read.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/list_read.c' object='list_read.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/list_read.Po' tmpdepfile='$(DEPDIR)/list_read.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o list_read.obj `if test -f 'io/list_read.c'; then $(CYGPATH_W) 'io/list_read.c'; else $(CYGPATH_W) '$(srcdir)/io/list_read.c'; fi` + +list_read.lo: io/list_read.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT list_read.lo -MD -MP -MF "$(DEPDIR)/list_read.Tpo" -c -o list_read.lo `test -f 'io/list_read.c' || echo '$(srcdir)/'`io/list_read.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/list_read.Tpo" "$(DEPDIR)/list_read.Plo"; else rm -f "$(DEPDIR)/list_read.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/list_read.c' object='list_read.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/list_read.Plo' tmpdepfile='$(DEPDIR)/list_read.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o list_read.lo `test -f 'io/list_read.c' || echo '$(srcdir)/'`io/list_read.c + +lock.o: io/lock.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock.o -MD -MP -MF "$(DEPDIR)/lock.Tpo" -c -o lock.o `test -f 'io/lock.c' || echo '$(srcdir)/'`io/lock.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lock.Tpo" "$(DEPDIR)/lock.Po"; else rm -f "$(DEPDIR)/lock.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/lock.c' object='lock.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/lock.Po' tmpdepfile='$(DEPDIR)/lock.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lock.o `test -f 'io/lock.c' || echo '$(srcdir)/'`io/lock.c + +lock.obj: io/lock.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock.obj -MD -MP -MF "$(DEPDIR)/lock.Tpo" -c -o lock.obj `if test -f 'io/lock.c'; then $(CYGPATH_W) 'io/lock.c'; else $(CYGPATH_W) '$(srcdir)/io/lock.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lock.Tpo" "$(DEPDIR)/lock.Po"; else rm -f "$(DEPDIR)/lock.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/lock.c' object='lock.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/lock.Po' tmpdepfile='$(DEPDIR)/lock.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lock.obj `if test -f 'io/lock.c'; then $(CYGPATH_W) 'io/lock.c'; else $(CYGPATH_W) '$(srcdir)/io/lock.c'; fi` + +lock.lo: io/lock.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lock.lo -MD -MP -MF "$(DEPDIR)/lock.Tpo" -c -o lock.lo `test -f 'io/lock.c' || echo '$(srcdir)/'`io/lock.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/lock.Tpo" "$(DEPDIR)/lock.Plo"; else rm -f "$(DEPDIR)/lock.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/lock.c' object='lock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/lock.Plo' tmpdepfile='$(DEPDIR)/lock.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lock.lo `test -f 'io/lock.c' || echo '$(srcdir)/'`io/lock.c + +open.o: io/open.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT open.o -MD -MP -MF "$(DEPDIR)/open.Tpo" -c -o open.o `test -f 'io/open.c' || echo '$(srcdir)/'`io/open.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/open.Tpo" "$(DEPDIR)/open.Po"; else rm -f "$(DEPDIR)/open.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/open.c' object='open.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/open.Po' tmpdepfile='$(DEPDIR)/open.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o open.o `test -f 'io/open.c' || echo '$(srcdir)/'`io/open.c + +open.obj: io/open.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT open.obj -MD -MP -MF "$(DEPDIR)/open.Tpo" -c -o open.obj `if test -f 'io/open.c'; then $(CYGPATH_W) 'io/open.c'; else $(CYGPATH_W) '$(srcdir)/io/open.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/open.Tpo" "$(DEPDIR)/open.Po"; else rm -f "$(DEPDIR)/open.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/open.c' object='open.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/open.Po' tmpdepfile='$(DEPDIR)/open.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o open.obj `if test -f 'io/open.c'; then $(CYGPATH_W) 'io/open.c'; else $(CYGPATH_W) '$(srcdir)/io/open.c'; fi` + +open.lo: io/open.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT open.lo -MD -MP -MF "$(DEPDIR)/open.Tpo" -c -o open.lo `test -f 'io/open.c' || echo '$(srcdir)/'`io/open.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/open.Tpo" "$(DEPDIR)/open.Plo"; else rm -f "$(DEPDIR)/open.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/open.c' object='open.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/open.Plo' tmpdepfile='$(DEPDIR)/open.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o open.lo `test -f 'io/open.c' || echo '$(srcdir)/'`io/open.c + +read.o: io/read.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT read.o -MD -MP -MF "$(DEPDIR)/read.Tpo" -c -o read.o `test -f 'io/read.c' || echo '$(srcdir)/'`io/read.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/read.Tpo" "$(DEPDIR)/read.Po"; else rm -f "$(DEPDIR)/read.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/read.c' object='read.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/read.Po' tmpdepfile='$(DEPDIR)/read.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o read.o `test -f 'io/read.c' || echo '$(srcdir)/'`io/read.c + +read.obj: io/read.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT read.obj -MD -MP -MF "$(DEPDIR)/read.Tpo" -c -o read.obj `if test -f 'io/read.c'; then $(CYGPATH_W) 'io/read.c'; else $(CYGPATH_W) '$(srcdir)/io/read.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/read.Tpo" "$(DEPDIR)/read.Po"; else rm -f "$(DEPDIR)/read.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/read.c' object='read.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/read.Po' tmpdepfile='$(DEPDIR)/read.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o read.obj `if test -f 'io/read.c'; then $(CYGPATH_W) 'io/read.c'; else $(CYGPATH_W) '$(srcdir)/io/read.c'; fi` + +read.lo: io/read.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT read.lo -MD -MP -MF "$(DEPDIR)/read.Tpo" -c -o read.lo `test -f 'io/read.c' || echo '$(srcdir)/'`io/read.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/read.Tpo" "$(DEPDIR)/read.Plo"; else rm -f "$(DEPDIR)/read.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/read.c' object='read.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/read.Plo' tmpdepfile='$(DEPDIR)/read.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o read.lo `test -f 'io/read.c' || echo '$(srcdir)/'`io/read.c + +rewind.o: io/rewind.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rewind.o -MD -MP -MF "$(DEPDIR)/rewind.Tpo" -c -o rewind.o `test -f 'io/rewind.c' || echo '$(srcdir)/'`io/rewind.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rewind.Tpo" "$(DEPDIR)/rewind.Po"; else rm -f "$(DEPDIR)/rewind.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/rewind.c' object='rewind.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/rewind.Po' tmpdepfile='$(DEPDIR)/rewind.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rewind.o `test -f 'io/rewind.c' || echo '$(srcdir)/'`io/rewind.c + +rewind.obj: io/rewind.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rewind.obj -MD -MP -MF "$(DEPDIR)/rewind.Tpo" -c -o rewind.obj `if test -f 'io/rewind.c'; then $(CYGPATH_W) 'io/rewind.c'; else $(CYGPATH_W) '$(srcdir)/io/rewind.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rewind.Tpo" "$(DEPDIR)/rewind.Po"; else rm -f "$(DEPDIR)/rewind.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/rewind.c' object='rewind.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/rewind.Po' tmpdepfile='$(DEPDIR)/rewind.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rewind.obj `if test -f 'io/rewind.c'; then $(CYGPATH_W) 'io/rewind.c'; else $(CYGPATH_W) '$(srcdir)/io/rewind.c'; fi` + +rewind.lo: io/rewind.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rewind.lo -MD -MP -MF "$(DEPDIR)/rewind.Tpo" -c -o rewind.lo `test -f 'io/rewind.c' || echo '$(srcdir)/'`io/rewind.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rewind.Tpo" "$(DEPDIR)/rewind.Plo"; else rm -f "$(DEPDIR)/rewind.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/rewind.c' object='rewind.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/rewind.Plo' tmpdepfile='$(DEPDIR)/rewind.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rewind.lo `test -f 'io/rewind.c' || echo '$(srcdir)/'`io/rewind.c + +transfer.o: io/transfer.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transfer.o -MD -MP -MF "$(DEPDIR)/transfer.Tpo" -c -o transfer.o `test -f 'io/transfer.c' || echo '$(srcdir)/'`io/transfer.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transfer.Tpo" "$(DEPDIR)/transfer.Po"; else rm -f "$(DEPDIR)/transfer.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/transfer.c' object='transfer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transfer.Po' tmpdepfile='$(DEPDIR)/transfer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transfer.o `test -f 'io/transfer.c' || echo '$(srcdir)/'`io/transfer.c + +transfer.obj: io/transfer.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transfer.obj -MD -MP -MF "$(DEPDIR)/transfer.Tpo" -c -o transfer.obj `if test -f 'io/transfer.c'; then $(CYGPATH_W) 'io/transfer.c'; else $(CYGPATH_W) '$(srcdir)/io/transfer.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transfer.Tpo" "$(DEPDIR)/transfer.Po"; else rm -f "$(DEPDIR)/transfer.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/transfer.c' object='transfer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transfer.Po' tmpdepfile='$(DEPDIR)/transfer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transfer.obj `if test -f 'io/transfer.c'; then $(CYGPATH_W) 'io/transfer.c'; else $(CYGPATH_W) '$(srcdir)/io/transfer.c'; fi` + +transfer.lo: io/transfer.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transfer.lo -MD -MP -MF "$(DEPDIR)/transfer.Tpo" -c -o transfer.lo `test -f 'io/transfer.c' || echo '$(srcdir)/'`io/transfer.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transfer.Tpo" "$(DEPDIR)/transfer.Plo"; else rm -f "$(DEPDIR)/transfer.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/transfer.c' object='transfer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transfer.Plo' tmpdepfile='$(DEPDIR)/transfer.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transfer.lo `test -f 'io/transfer.c' || echo '$(srcdir)/'`io/transfer.c + +unit.o: io/unit.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit.o -MD -MP -MF "$(DEPDIR)/unit.Tpo" -c -o unit.o `test -f 'io/unit.c' || echo '$(srcdir)/'`io/unit.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unit.Tpo" "$(DEPDIR)/unit.Po"; else rm -f "$(DEPDIR)/unit.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/unit.c' object='unit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unit.Po' tmpdepfile='$(DEPDIR)/unit.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit.o `test -f 'io/unit.c' || echo '$(srcdir)/'`io/unit.c + +unit.obj: io/unit.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit.obj -MD -MP -MF "$(DEPDIR)/unit.Tpo" -c -o unit.obj `if test -f 'io/unit.c'; then $(CYGPATH_W) 'io/unit.c'; else $(CYGPATH_W) '$(srcdir)/io/unit.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unit.Tpo" "$(DEPDIR)/unit.Po"; else rm -f "$(DEPDIR)/unit.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/unit.c' object='unit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unit.Po' tmpdepfile='$(DEPDIR)/unit.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit.obj `if test -f 'io/unit.c'; then $(CYGPATH_W) 'io/unit.c'; else $(CYGPATH_W) '$(srcdir)/io/unit.c'; fi` + +unit.lo: io/unit.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unit.lo -MD -MP -MF "$(DEPDIR)/unit.Tpo" -c -o unit.lo `test -f 'io/unit.c' || echo '$(srcdir)/'`io/unit.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unit.Tpo" "$(DEPDIR)/unit.Plo"; else rm -f "$(DEPDIR)/unit.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/unit.c' object='unit.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unit.Plo' tmpdepfile='$(DEPDIR)/unit.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unit.lo `test -f 'io/unit.c' || echo '$(srcdir)/'`io/unit.c + +unix.o: io/unix.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unix.o -MD -MP -MF "$(DEPDIR)/unix.Tpo" -c -o unix.o `test -f 'io/unix.c' || echo '$(srcdir)/'`io/unix.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unix.Tpo" "$(DEPDIR)/unix.Po"; else rm -f "$(DEPDIR)/unix.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/unix.c' object='unix.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unix.Po' tmpdepfile='$(DEPDIR)/unix.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unix.o `test -f 'io/unix.c' || echo '$(srcdir)/'`io/unix.c + +unix.obj: io/unix.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unix.obj -MD -MP -MF "$(DEPDIR)/unix.Tpo" -c -o unix.obj `if test -f 'io/unix.c'; then $(CYGPATH_W) 'io/unix.c'; else $(CYGPATH_W) '$(srcdir)/io/unix.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unix.Tpo" "$(DEPDIR)/unix.Po"; else rm -f "$(DEPDIR)/unix.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/unix.c' object='unix.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unix.Po' tmpdepfile='$(DEPDIR)/unix.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unix.obj `if test -f 'io/unix.c'; then $(CYGPATH_W) 'io/unix.c'; else $(CYGPATH_W) '$(srcdir)/io/unix.c'; fi` + +unix.lo: io/unix.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unix.lo -MD -MP -MF "$(DEPDIR)/unix.Tpo" -c -o unix.lo `test -f 'io/unix.c' || echo '$(srcdir)/'`io/unix.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unix.Tpo" "$(DEPDIR)/unix.Plo"; else rm -f "$(DEPDIR)/unix.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/unix.c' object='unix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unix.Plo' tmpdepfile='$(DEPDIR)/unix.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unix.lo `test -f 'io/unix.c' || echo '$(srcdir)/'`io/unix.c + +write.o: io/write.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT write.o -MD -MP -MF "$(DEPDIR)/write.Tpo" -c -o write.o `test -f 'io/write.c' || echo '$(srcdir)/'`io/write.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/write.Tpo" "$(DEPDIR)/write.Po"; else rm -f "$(DEPDIR)/write.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/write.c' object='write.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/write.Po' tmpdepfile='$(DEPDIR)/write.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o write.o `test -f 'io/write.c' || echo '$(srcdir)/'`io/write.c + +write.obj: io/write.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT write.obj -MD -MP -MF "$(DEPDIR)/write.Tpo" -c -o write.obj `if test -f 'io/write.c'; then $(CYGPATH_W) 'io/write.c'; else $(CYGPATH_W) '$(srcdir)/io/write.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/write.Tpo" "$(DEPDIR)/write.Po"; else rm -f "$(DEPDIR)/write.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/write.c' object='write.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/write.Po' tmpdepfile='$(DEPDIR)/write.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o write.obj `if test -f 'io/write.c'; then $(CYGPATH_W) 'io/write.c'; else $(CYGPATH_W) '$(srcdir)/io/write.c'; fi` + +write.lo: io/write.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT write.lo -MD -MP -MF "$(DEPDIR)/write.Tpo" -c -o write.lo `test -f 'io/write.c' || echo '$(srcdir)/'`io/write.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/write.Tpo" "$(DEPDIR)/write.Plo"; else rm -f "$(DEPDIR)/write.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io/write.c' object='write.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/write.Plo' tmpdepfile='$(DEPDIR)/write.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o write.lo `test -f 'io/write.c' || echo '$(srcdir)/'`io/write.c + +associated.o: intrinsics/associated.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT associated.o -MD -MP -MF "$(DEPDIR)/associated.Tpo" -c -o associated.o `test -f 'intrinsics/associated.c' || echo '$(srcdir)/'`intrinsics/associated.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/associated.Tpo" "$(DEPDIR)/associated.Po"; else rm -f "$(DEPDIR)/associated.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/associated.c' object='associated.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/associated.Po' tmpdepfile='$(DEPDIR)/associated.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o associated.o `test -f 'intrinsics/associated.c' || echo '$(srcdir)/'`intrinsics/associated.c + +associated.obj: intrinsics/associated.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT associated.obj -MD -MP -MF "$(DEPDIR)/associated.Tpo" -c -o associated.obj `if test -f 'intrinsics/associated.c'; then $(CYGPATH_W) 'intrinsics/associated.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/associated.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/associated.Tpo" "$(DEPDIR)/associated.Po"; else rm -f "$(DEPDIR)/associated.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/associated.c' object='associated.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/associated.Po' tmpdepfile='$(DEPDIR)/associated.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o associated.obj `if test -f 'intrinsics/associated.c'; then $(CYGPATH_W) 'intrinsics/associated.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/associated.c'; fi` + +associated.lo: intrinsics/associated.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT associated.lo -MD -MP -MF "$(DEPDIR)/associated.Tpo" -c -o associated.lo `test -f 'intrinsics/associated.c' || echo '$(srcdir)/'`intrinsics/associated.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/associated.Tpo" "$(DEPDIR)/associated.Plo"; else rm -f "$(DEPDIR)/associated.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/associated.c' object='associated.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/associated.Plo' tmpdepfile='$(DEPDIR)/associated.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o associated.lo `test -f 'intrinsics/associated.c' || echo '$(srcdir)/'`intrinsics/associated.c + +abort.o: intrinsics/abort.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT abort.o -MD -MP -MF "$(DEPDIR)/abort.Tpo" -c -o abort.o `test -f 'intrinsics/abort.c' || echo '$(srcdir)/'`intrinsics/abort.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/abort.Tpo" "$(DEPDIR)/abort.Po"; else rm -f "$(DEPDIR)/abort.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/abort.c' object='abort.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/abort.Po' tmpdepfile='$(DEPDIR)/abort.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o abort.o `test -f 'intrinsics/abort.c' || echo '$(srcdir)/'`intrinsics/abort.c + +abort.obj: intrinsics/abort.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT abort.obj -MD -MP -MF "$(DEPDIR)/abort.Tpo" -c -o abort.obj `if test -f 'intrinsics/abort.c'; then $(CYGPATH_W) 'intrinsics/abort.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/abort.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/abort.Tpo" "$(DEPDIR)/abort.Po"; else rm -f "$(DEPDIR)/abort.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/abort.c' object='abort.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/abort.Po' tmpdepfile='$(DEPDIR)/abort.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o abort.obj `if test -f 'intrinsics/abort.c'; then $(CYGPATH_W) 'intrinsics/abort.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/abort.c'; fi` + +abort.lo: intrinsics/abort.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT abort.lo -MD -MP -MF "$(DEPDIR)/abort.Tpo" -c -o abort.lo `test -f 'intrinsics/abort.c' || echo '$(srcdir)/'`intrinsics/abort.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/abort.Tpo" "$(DEPDIR)/abort.Plo"; else rm -f "$(DEPDIR)/abort.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/abort.c' object='abort.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/abort.Plo' tmpdepfile='$(DEPDIR)/abort.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o abort.lo `test -f 'intrinsics/abort.c' || echo '$(srcdir)/'`intrinsics/abort.c + +cpu_time.o: intrinsics/cpu_time.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cpu_time.o -MD -MP -MF "$(DEPDIR)/cpu_time.Tpo" -c -o cpu_time.o `test -f 'intrinsics/cpu_time.c' || echo '$(srcdir)/'`intrinsics/cpu_time.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cpu_time.Tpo" "$(DEPDIR)/cpu_time.Po"; else rm -f "$(DEPDIR)/cpu_time.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/cpu_time.c' object='cpu_time.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cpu_time.Po' tmpdepfile='$(DEPDIR)/cpu_time.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cpu_time.o `test -f 'intrinsics/cpu_time.c' || echo '$(srcdir)/'`intrinsics/cpu_time.c + +cpu_time.obj: intrinsics/cpu_time.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cpu_time.obj -MD -MP -MF "$(DEPDIR)/cpu_time.Tpo" -c -o cpu_time.obj `if test -f 'intrinsics/cpu_time.c'; then $(CYGPATH_W) 'intrinsics/cpu_time.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/cpu_time.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cpu_time.Tpo" "$(DEPDIR)/cpu_time.Po"; else rm -f "$(DEPDIR)/cpu_time.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/cpu_time.c' object='cpu_time.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cpu_time.Po' tmpdepfile='$(DEPDIR)/cpu_time.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cpu_time.obj `if test -f 'intrinsics/cpu_time.c'; then $(CYGPATH_W) 'intrinsics/cpu_time.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/cpu_time.c'; fi` + +cpu_time.lo: intrinsics/cpu_time.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cpu_time.lo -MD -MP -MF "$(DEPDIR)/cpu_time.Tpo" -c -o cpu_time.lo `test -f 'intrinsics/cpu_time.c' || echo '$(srcdir)/'`intrinsics/cpu_time.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cpu_time.Tpo" "$(DEPDIR)/cpu_time.Plo"; else rm -f "$(DEPDIR)/cpu_time.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/cpu_time.c' object='cpu_time.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cpu_time.Plo' tmpdepfile='$(DEPDIR)/cpu_time.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cpu_time.lo `test -f 'intrinsics/cpu_time.c' || echo '$(srcdir)/'`intrinsics/cpu_time.c + +cshift0.o: intrinsics/cshift0.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift0.o -MD -MP -MF "$(DEPDIR)/cshift0.Tpo" -c -o cshift0.o `test -f 'intrinsics/cshift0.c' || echo '$(srcdir)/'`intrinsics/cshift0.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift0.Tpo" "$(DEPDIR)/cshift0.Po"; else rm -f "$(DEPDIR)/cshift0.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/cshift0.c' object='cshift0.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift0.Po' tmpdepfile='$(DEPDIR)/cshift0.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift0.o `test -f 'intrinsics/cshift0.c' || echo '$(srcdir)/'`intrinsics/cshift0.c + +cshift0.obj: intrinsics/cshift0.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift0.obj -MD -MP -MF "$(DEPDIR)/cshift0.Tpo" -c -o cshift0.obj `if test -f 'intrinsics/cshift0.c'; then $(CYGPATH_W) 'intrinsics/cshift0.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/cshift0.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift0.Tpo" "$(DEPDIR)/cshift0.Po"; else rm -f "$(DEPDIR)/cshift0.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/cshift0.c' object='cshift0.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift0.Po' tmpdepfile='$(DEPDIR)/cshift0.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift0.obj `if test -f 'intrinsics/cshift0.c'; then $(CYGPATH_W) 'intrinsics/cshift0.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/cshift0.c'; fi` + +cshift0.lo: intrinsics/cshift0.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cshift0.lo -MD -MP -MF "$(DEPDIR)/cshift0.Tpo" -c -o cshift0.lo `test -f 'intrinsics/cshift0.c' || echo '$(srcdir)/'`intrinsics/cshift0.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cshift0.Tpo" "$(DEPDIR)/cshift0.Plo"; else rm -f "$(DEPDIR)/cshift0.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/cshift0.c' object='cshift0.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/cshift0.Plo' tmpdepfile='$(DEPDIR)/cshift0.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cshift0.lo `test -f 'intrinsics/cshift0.c' || echo '$(srcdir)/'`intrinsics/cshift0.c + +eoshift0.o: intrinsics/eoshift0.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift0.o -MD -MP -MF "$(DEPDIR)/eoshift0.Tpo" -c -o eoshift0.o `test -f 'intrinsics/eoshift0.c' || echo '$(srcdir)/'`intrinsics/eoshift0.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift0.Tpo" "$(DEPDIR)/eoshift0.Po"; else rm -f "$(DEPDIR)/eoshift0.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/eoshift0.c' object='eoshift0.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift0.Po' tmpdepfile='$(DEPDIR)/eoshift0.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift0.o `test -f 'intrinsics/eoshift0.c' || echo '$(srcdir)/'`intrinsics/eoshift0.c + +eoshift0.obj: intrinsics/eoshift0.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift0.obj -MD -MP -MF "$(DEPDIR)/eoshift0.Tpo" -c -o eoshift0.obj `if test -f 'intrinsics/eoshift0.c'; then $(CYGPATH_W) 'intrinsics/eoshift0.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/eoshift0.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift0.Tpo" "$(DEPDIR)/eoshift0.Po"; else rm -f "$(DEPDIR)/eoshift0.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/eoshift0.c' object='eoshift0.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift0.Po' tmpdepfile='$(DEPDIR)/eoshift0.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift0.obj `if test -f 'intrinsics/eoshift0.c'; then $(CYGPATH_W) 'intrinsics/eoshift0.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/eoshift0.c'; fi` + +eoshift0.lo: intrinsics/eoshift0.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift0.lo -MD -MP -MF "$(DEPDIR)/eoshift0.Tpo" -c -o eoshift0.lo `test -f 'intrinsics/eoshift0.c' || echo '$(srcdir)/'`intrinsics/eoshift0.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift0.Tpo" "$(DEPDIR)/eoshift0.Plo"; else rm -f "$(DEPDIR)/eoshift0.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/eoshift0.c' object='eoshift0.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift0.Plo' tmpdepfile='$(DEPDIR)/eoshift0.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift0.lo `test -f 'intrinsics/eoshift0.c' || echo '$(srcdir)/'`intrinsics/eoshift0.c + +eoshift2.o: intrinsics/eoshift2.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift2.o -MD -MP -MF "$(DEPDIR)/eoshift2.Tpo" -c -o eoshift2.o `test -f 'intrinsics/eoshift2.c' || echo '$(srcdir)/'`intrinsics/eoshift2.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift2.Tpo" "$(DEPDIR)/eoshift2.Po"; else rm -f "$(DEPDIR)/eoshift2.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/eoshift2.c' object='eoshift2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift2.Po' tmpdepfile='$(DEPDIR)/eoshift2.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift2.o `test -f 'intrinsics/eoshift2.c' || echo '$(srcdir)/'`intrinsics/eoshift2.c + +eoshift2.obj: intrinsics/eoshift2.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift2.obj -MD -MP -MF "$(DEPDIR)/eoshift2.Tpo" -c -o eoshift2.obj `if test -f 'intrinsics/eoshift2.c'; then $(CYGPATH_W) 'intrinsics/eoshift2.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/eoshift2.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift2.Tpo" "$(DEPDIR)/eoshift2.Po"; else rm -f "$(DEPDIR)/eoshift2.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/eoshift2.c' object='eoshift2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift2.Po' tmpdepfile='$(DEPDIR)/eoshift2.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift2.obj `if test -f 'intrinsics/eoshift2.c'; then $(CYGPATH_W) 'intrinsics/eoshift2.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/eoshift2.c'; fi` + +eoshift2.lo: intrinsics/eoshift2.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eoshift2.lo -MD -MP -MF "$(DEPDIR)/eoshift2.Tpo" -c -o eoshift2.lo `test -f 'intrinsics/eoshift2.c' || echo '$(srcdir)/'`intrinsics/eoshift2.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/eoshift2.Tpo" "$(DEPDIR)/eoshift2.Plo"; else rm -f "$(DEPDIR)/eoshift2.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/eoshift2.c' object='eoshift2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/eoshift2.Plo' tmpdepfile='$(DEPDIR)/eoshift2.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eoshift2.lo `test -f 'intrinsics/eoshift2.c' || echo '$(srcdir)/'`intrinsics/eoshift2.c + +ishftc.o: intrinsics/ishftc.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ishftc.o -MD -MP -MF "$(DEPDIR)/ishftc.Tpo" -c -o ishftc.o `test -f 'intrinsics/ishftc.c' || echo '$(srcdir)/'`intrinsics/ishftc.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ishftc.Tpo" "$(DEPDIR)/ishftc.Po"; else rm -f "$(DEPDIR)/ishftc.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/ishftc.c' object='ishftc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ishftc.Po' tmpdepfile='$(DEPDIR)/ishftc.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ishftc.o `test -f 'intrinsics/ishftc.c' || echo '$(srcdir)/'`intrinsics/ishftc.c + +ishftc.obj: intrinsics/ishftc.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ishftc.obj -MD -MP -MF "$(DEPDIR)/ishftc.Tpo" -c -o ishftc.obj `if test -f 'intrinsics/ishftc.c'; then $(CYGPATH_W) 'intrinsics/ishftc.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/ishftc.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ishftc.Tpo" "$(DEPDIR)/ishftc.Po"; else rm -f "$(DEPDIR)/ishftc.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/ishftc.c' object='ishftc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ishftc.Po' tmpdepfile='$(DEPDIR)/ishftc.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ishftc.obj `if test -f 'intrinsics/ishftc.c'; then $(CYGPATH_W) 'intrinsics/ishftc.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/ishftc.c'; fi` + +ishftc.lo: intrinsics/ishftc.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ishftc.lo -MD -MP -MF "$(DEPDIR)/ishftc.Tpo" -c -o ishftc.lo `test -f 'intrinsics/ishftc.c' || echo '$(srcdir)/'`intrinsics/ishftc.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ishftc.Tpo" "$(DEPDIR)/ishftc.Plo"; else rm -f "$(DEPDIR)/ishftc.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/ishftc.c' object='ishftc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/ishftc.Plo' tmpdepfile='$(DEPDIR)/ishftc.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ishftc.lo `test -f 'intrinsics/ishftc.c' || echo '$(srcdir)/'`intrinsics/ishftc.c + +pack_generic.o: intrinsics/pack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pack_generic.o -MD -MP -MF "$(DEPDIR)/pack_generic.Tpo" -c -o pack_generic.o `test -f 'intrinsics/pack_generic.c' || echo '$(srcdir)/'`intrinsics/pack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/pack_generic.Tpo" "$(DEPDIR)/pack_generic.Po"; else rm -f "$(DEPDIR)/pack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/pack_generic.c' object='pack_generic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/pack_generic.Po' tmpdepfile='$(DEPDIR)/pack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pack_generic.o `test -f 'intrinsics/pack_generic.c' || echo '$(srcdir)/'`intrinsics/pack_generic.c + +pack_generic.obj: intrinsics/pack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pack_generic.obj -MD -MP -MF "$(DEPDIR)/pack_generic.Tpo" -c -o pack_generic.obj `if test -f 'intrinsics/pack_generic.c'; then $(CYGPATH_W) 'intrinsics/pack_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/pack_generic.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/pack_generic.Tpo" "$(DEPDIR)/pack_generic.Po"; else rm -f "$(DEPDIR)/pack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/pack_generic.c' object='pack_generic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/pack_generic.Po' tmpdepfile='$(DEPDIR)/pack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pack_generic.obj `if test -f 'intrinsics/pack_generic.c'; then $(CYGPATH_W) 'intrinsics/pack_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/pack_generic.c'; fi` + +pack_generic.lo: intrinsics/pack_generic.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pack_generic.lo -MD -MP -MF "$(DEPDIR)/pack_generic.Tpo" -c -o pack_generic.lo `test -f 'intrinsics/pack_generic.c' || echo '$(srcdir)/'`intrinsics/pack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/pack_generic.Tpo" "$(DEPDIR)/pack_generic.Plo"; else rm -f "$(DEPDIR)/pack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/pack_generic.c' object='pack_generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/pack_generic.Plo' tmpdepfile='$(DEPDIR)/pack_generic.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pack_generic.lo `test -f 'intrinsics/pack_generic.c' || echo '$(srcdir)/'`intrinsics/pack_generic.c + +size.o: intrinsics/size.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT size.o -MD -MP -MF "$(DEPDIR)/size.Tpo" -c -o size.o `test -f 'intrinsics/size.c' || echo '$(srcdir)/'`intrinsics/size.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/size.Tpo" "$(DEPDIR)/size.Po"; else rm -f "$(DEPDIR)/size.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/size.c' object='size.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/size.Po' tmpdepfile='$(DEPDIR)/size.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o size.o `test -f 'intrinsics/size.c' || echo '$(srcdir)/'`intrinsics/size.c + +size.obj: intrinsics/size.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT size.obj -MD -MP -MF "$(DEPDIR)/size.Tpo" -c -o size.obj `if test -f 'intrinsics/size.c'; then $(CYGPATH_W) 'intrinsics/size.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/size.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/size.Tpo" "$(DEPDIR)/size.Po"; else rm -f "$(DEPDIR)/size.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/size.c' object='size.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/size.Po' tmpdepfile='$(DEPDIR)/size.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o size.obj `if test -f 'intrinsics/size.c'; then $(CYGPATH_W) 'intrinsics/size.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/size.c'; fi` + +size.lo: intrinsics/size.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT size.lo -MD -MP -MF "$(DEPDIR)/size.Tpo" -c -o size.lo `test -f 'intrinsics/size.c' || echo '$(srcdir)/'`intrinsics/size.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/size.Tpo" "$(DEPDIR)/size.Plo"; else rm -f "$(DEPDIR)/size.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/size.c' object='size.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/size.Plo' tmpdepfile='$(DEPDIR)/size.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o size.lo `test -f 'intrinsics/size.c' || echo '$(srcdir)/'`intrinsics/size.c + +spread_generic.o: intrinsics/spread_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_generic.o -MD -MP -MF "$(DEPDIR)/spread_generic.Tpo" -c -o spread_generic.o `test -f 'intrinsics/spread_generic.c' || echo '$(srcdir)/'`intrinsics/spread_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spread_generic.Tpo" "$(DEPDIR)/spread_generic.Po"; else rm -f "$(DEPDIR)/spread_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/spread_generic.c' object='spread_generic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/spread_generic.Po' tmpdepfile='$(DEPDIR)/spread_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_generic.o `test -f 'intrinsics/spread_generic.c' || echo '$(srcdir)/'`intrinsics/spread_generic.c + +spread_generic.obj: intrinsics/spread_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_generic.obj -MD -MP -MF "$(DEPDIR)/spread_generic.Tpo" -c -o spread_generic.obj `if test -f 'intrinsics/spread_generic.c'; then $(CYGPATH_W) 'intrinsics/spread_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/spread_generic.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spread_generic.Tpo" "$(DEPDIR)/spread_generic.Po"; else rm -f "$(DEPDIR)/spread_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/spread_generic.c' object='spread_generic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/spread_generic.Po' tmpdepfile='$(DEPDIR)/spread_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_generic.obj `if test -f 'intrinsics/spread_generic.c'; then $(CYGPATH_W) 'intrinsics/spread_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/spread_generic.c'; fi` + +spread_generic.lo: intrinsics/spread_generic.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spread_generic.lo -MD -MP -MF "$(DEPDIR)/spread_generic.Tpo" -c -o spread_generic.lo `test -f 'intrinsics/spread_generic.c' || echo '$(srcdir)/'`intrinsics/spread_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/spread_generic.Tpo" "$(DEPDIR)/spread_generic.Plo"; else rm -f "$(DEPDIR)/spread_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/spread_generic.c' object='spread_generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/spread_generic.Plo' tmpdepfile='$(DEPDIR)/spread_generic.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spread_generic.lo `test -f 'intrinsics/spread_generic.c' || echo '$(srcdir)/'`intrinsics/spread_generic.c + +string_intrinsics.o: intrinsics/string_intrinsics.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT string_intrinsics.o -MD -MP -MF "$(DEPDIR)/string_intrinsics.Tpo" -c -o string_intrinsics.o `test -f 'intrinsics/string_intrinsics.c' || echo '$(srcdir)/'`intrinsics/string_intrinsics.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/string_intrinsics.Tpo" "$(DEPDIR)/string_intrinsics.Po"; else rm -f "$(DEPDIR)/string_intrinsics.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/string_intrinsics.c' object='string_intrinsics.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/string_intrinsics.Po' tmpdepfile='$(DEPDIR)/string_intrinsics.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o string_intrinsics.o `test -f 'intrinsics/string_intrinsics.c' || echo '$(srcdir)/'`intrinsics/string_intrinsics.c + +string_intrinsics.obj: intrinsics/string_intrinsics.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT string_intrinsics.obj -MD -MP -MF "$(DEPDIR)/string_intrinsics.Tpo" -c -o string_intrinsics.obj `if test -f 'intrinsics/string_intrinsics.c'; then $(CYGPATH_W) 'intrinsics/string_intrinsics.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/string_intrinsics.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/string_intrinsics.Tpo" "$(DEPDIR)/string_intrinsics.Po"; else rm -f "$(DEPDIR)/string_intrinsics.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/string_intrinsics.c' object='string_intrinsics.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/string_intrinsics.Po' tmpdepfile='$(DEPDIR)/string_intrinsics.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o string_intrinsics.obj `if test -f 'intrinsics/string_intrinsics.c'; then $(CYGPATH_W) 'intrinsics/string_intrinsics.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/string_intrinsics.c'; fi` + +string_intrinsics.lo: intrinsics/string_intrinsics.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT string_intrinsics.lo -MD -MP -MF "$(DEPDIR)/string_intrinsics.Tpo" -c -o string_intrinsics.lo `test -f 'intrinsics/string_intrinsics.c' || echo '$(srcdir)/'`intrinsics/string_intrinsics.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/string_intrinsics.Tpo" "$(DEPDIR)/string_intrinsics.Plo"; else rm -f "$(DEPDIR)/string_intrinsics.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/string_intrinsics.c' object='string_intrinsics.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/string_intrinsics.Plo' tmpdepfile='$(DEPDIR)/string_intrinsics.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o string_intrinsics.lo `test -f 'intrinsics/string_intrinsics.c' || echo '$(srcdir)/'`intrinsics/string_intrinsics.c + +random.o: intrinsics/random.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT random.o -MD -MP -MF "$(DEPDIR)/random.Tpo" -c -o random.o `test -f 'intrinsics/random.c' || echo '$(srcdir)/'`intrinsics/random.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/random.Tpo" "$(DEPDIR)/random.Po"; else rm -f "$(DEPDIR)/random.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/random.c' object='random.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/random.Po' tmpdepfile='$(DEPDIR)/random.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o random.o `test -f 'intrinsics/random.c' || echo '$(srcdir)/'`intrinsics/random.c + +random.obj: intrinsics/random.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT random.obj -MD -MP -MF "$(DEPDIR)/random.Tpo" -c -o random.obj `if test -f 'intrinsics/random.c'; then $(CYGPATH_W) 'intrinsics/random.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/random.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/random.Tpo" "$(DEPDIR)/random.Po"; else rm -f "$(DEPDIR)/random.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/random.c' object='random.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/random.Po' tmpdepfile='$(DEPDIR)/random.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o random.obj `if test -f 'intrinsics/random.c'; then $(CYGPATH_W) 'intrinsics/random.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/random.c'; fi` + +random.lo: intrinsics/random.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT random.lo -MD -MP -MF "$(DEPDIR)/random.Tpo" -c -o random.lo `test -f 'intrinsics/random.c' || echo '$(srcdir)/'`intrinsics/random.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/random.Tpo" "$(DEPDIR)/random.Plo"; else rm -f "$(DEPDIR)/random.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/random.c' object='random.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/random.Plo' tmpdepfile='$(DEPDIR)/random.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o random.lo `test -f 'intrinsics/random.c' || echo '$(srcdir)/'`intrinsics/random.c + +reshape_generic.o: intrinsics/reshape_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_generic.o -MD -MP -MF "$(DEPDIR)/reshape_generic.Tpo" -c -o reshape_generic.o `test -f 'intrinsics/reshape_generic.c' || echo '$(srcdir)/'`intrinsics/reshape_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_generic.Tpo" "$(DEPDIR)/reshape_generic.Po"; else rm -f "$(DEPDIR)/reshape_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/reshape_generic.c' object='reshape_generic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_generic.Po' tmpdepfile='$(DEPDIR)/reshape_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_generic.o `test -f 'intrinsics/reshape_generic.c' || echo '$(srcdir)/'`intrinsics/reshape_generic.c + +reshape_generic.obj: intrinsics/reshape_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_generic.obj -MD -MP -MF "$(DEPDIR)/reshape_generic.Tpo" -c -o reshape_generic.obj `if test -f 'intrinsics/reshape_generic.c'; then $(CYGPATH_W) 'intrinsics/reshape_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/reshape_generic.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_generic.Tpo" "$(DEPDIR)/reshape_generic.Po"; else rm -f "$(DEPDIR)/reshape_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/reshape_generic.c' object='reshape_generic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_generic.Po' tmpdepfile='$(DEPDIR)/reshape_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_generic.obj `if test -f 'intrinsics/reshape_generic.c'; then $(CYGPATH_W) 'intrinsics/reshape_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/reshape_generic.c'; fi` + +reshape_generic.lo: intrinsics/reshape_generic.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_generic.lo -MD -MP -MF "$(DEPDIR)/reshape_generic.Tpo" -c -o reshape_generic.lo `test -f 'intrinsics/reshape_generic.c' || echo '$(srcdir)/'`intrinsics/reshape_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_generic.Tpo" "$(DEPDIR)/reshape_generic.Plo"; else rm -f "$(DEPDIR)/reshape_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/reshape_generic.c' object='reshape_generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_generic.Plo' tmpdepfile='$(DEPDIR)/reshape_generic.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_generic.lo `test -f 'intrinsics/reshape_generic.c' || echo '$(srcdir)/'`intrinsics/reshape_generic.c + +reshape_packed.o: intrinsics/reshape_packed.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_packed.o -MD -MP -MF "$(DEPDIR)/reshape_packed.Tpo" -c -o reshape_packed.o `test -f 'intrinsics/reshape_packed.c' || echo '$(srcdir)/'`intrinsics/reshape_packed.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_packed.Tpo" "$(DEPDIR)/reshape_packed.Po"; else rm -f "$(DEPDIR)/reshape_packed.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/reshape_packed.c' object='reshape_packed.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_packed.Po' tmpdepfile='$(DEPDIR)/reshape_packed.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_packed.o `test -f 'intrinsics/reshape_packed.c' || echo '$(srcdir)/'`intrinsics/reshape_packed.c + +reshape_packed.obj: intrinsics/reshape_packed.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_packed.obj -MD -MP -MF "$(DEPDIR)/reshape_packed.Tpo" -c -o reshape_packed.obj `if test -f 'intrinsics/reshape_packed.c'; then $(CYGPATH_W) 'intrinsics/reshape_packed.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/reshape_packed.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_packed.Tpo" "$(DEPDIR)/reshape_packed.Po"; else rm -f "$(DEPDIR)/reshape_packed.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/reshape_packed.c' object='reshape_packed.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_packed.Po' tmpdepfile='$(DEPDIR)/reshape_packed.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_packed.obj `if test -f 'intrinsics/reshape_packed.c'; then $(CYGPATH_W) 'intrinsics/reshape_packed.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/reshape_packed.c'; fi` + +reshape_packed.lo: intrinsics/reshape_packed.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT reshape_packed.lo -MD -MP -MF "$(DEPDIR)/reshape_packed.Tpo" -c -o reshape_packed.lo `test -f 'intrinsics/reshape_packed.c' || echo '$(srcdir)/'`intrinsics/reshape_packed.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/reshape_packed.Tpo" "$(DEPDIR)/reshape_packed.Plo"; else rm -f "$(DEPDIR)/reshape_packed.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/reshape_packed.c' object='reshape_packed.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/reshape_packed.Plo' tmpdepfile='$(DEPDIR)/reshape_packed.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o reshape_packed.lo `test -f 'intrinsics/reshape_packed.c' || echo '$(srcdir)/'`intrinsics/reshape_packed.c + +transpose_generic.o: intrinsics/transpose_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_generic.o -MD -MP -MF "$(DEPDIR)/transpose_generic.Tpo" -c -o transpose_generic.o `test -f 'intrinsics/transpose_generic.c' || echo '$(srcdir)/'`intrinsics/transpose_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_generic.Tpo" "$(DEPDIR)/transpose_generic.Po"; else rm -f "$(DEPDIR)/transpose_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/transpose_generic.c' object='transpose_generic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_generic.Po' tmpdepfile='$(DEPDIR)/transpose_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_generic.o `test -f 'intrinsics/transpose_generic.c' || echo '$(srcdir)/'`intrinsics/transpose_generic.c + +transpose_generic.obj: intrinsics/transpose_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_generic.obj -MD -MP -MF "$(DEPDIR)/transpose_generic.Tpo" -c -o transpose_generic.obj `if test -f 'intrinsics/transpose_generic.c'; then $(CYGPATH_W) 'intrinsics/transpose_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/transpose_generic.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_generic.Tpo" "$(DEPDIR)/transpose_generic.Po"; else rm -f "$(DEPDIR)/transpose_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/transpose_generic.c' object='transpose_generic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_generic.Po' tmpdepfile='$(DEPDIR)/transpose_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_generic.obj `if test -f 'intrinsics/transpose_generic.c'; then $(CYGPATH_W) 'intrinsics/transpose_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/transpose_generic.c'; fi` + +transpose_generic.lo: intrinsics/transpose_generic.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT transpose_generic.lo -MD -MP -MF "$(DEPDIR)/transpose_generic.Tpo" -c -o transpose_generic.lo `test -f 'intrinsics/transpose_generic.c' || echo '$(srcdir)/'`intrinsics/transpose_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/transpose_generic.Tpo" "$(DEPDIR)/transpose_generic.Plo"; else rm -f "$(DEPDIR)/transpose_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/transpose_generic.c' object='transpose_generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/transpose_generic.Plo' tmpdepfile='$(DEPDIR)/transpose_generic.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o transpose_generic.lo `test -f 'intrinsics/transpose_generic.c' || echo '$(srcdir)/'`intrinsics/transpose_generic.c + +unpack_generic.o: intrinsics/unpack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unpack_generic.o -MD -MP -MF "$(DEPDIR)/unpack_generic.Tpo" -c -o unpack_generic.o `test -f 'intrinsics/unpack_generic.c' || echo '$(srcdir)/'`intrinsics/unpack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unpack_generic.Tpo" "$(DEPDIR)/unpack_generic.Po"; else rm -f "$(DEPDIR)/unpack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/unpack_generic.c' object='unpack_generic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unpack_generic.Po' tmpdepfile='$(DEPDIR)/unpack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unpack_generic.o `test -f 'intrinsics/unpack_generic.c' || echo '$(srcdir)/'`intrinsics/unpack_generic.c + +unpack_generic.obj: intrinsics/unpack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unpack_generic.obj -MD -MP -MF "$(DEPDIR)/unpack_generic.Tpo" -c -o unpack_generic.obj `if test -f 'intrinsics/unpack_generic.c'; then $(CYGPATH_W) 'intrinsics/unpack_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/unpack_generic.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unpack_generic.Tpo" "$(DEPDIR)/unpack_generic.Po"; else rm -f "$(DEPDIR)/unpack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/unpack_generic.c' object='unpack_generic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unpack_generic.Po' tmpdepfile='$(DEPDIR)/unpack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unpack_generic.obj `if test -f 'intrinsics/unpack_generic.c'; then $(CYGPATH_W) 'intrinsics/unpack_generic.c'; else $(CYGPATH_W) '$(srcdir)/intrinsics/unpack_generic.c'; fi` + +unpack_generic.lo: intrinsics/unpack_generic.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT unpack_generic.lo -MD -MP -MF "$(DEPDIR)/unpack_generic.Tpo" -c -o unpack_generic.lo `test -f 'intrinsics/unpack_generic.c' || echo '$(srcdir)/'`intrinsics/unpack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/unpack_generic.Tpo" "$(DEPDIR)/unpack_generic.Plo"; else rm -f "$(DEPDIR)/unpack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='intrinsics/unpack_generic.c' object='unpack_generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/unpack_generic.Plo' tmpdepfile='$(DEPDIR)/unpack_generic.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o unpack_generic.lo `test -f 'intrinsics/unpack_generic.c' || echo '$(srcdir)/'`intrinsics/unpack_generic.c + +in_pack_generic.o: runtime/in_pack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_generic.o -MD -MP -MF "$(DEPDIR)/in_pack_generic.Tpo" -c -o in_pack_generic.o `test -f 'runtime/in_pack_generic.c' || echo '$(srcdir)/'`runtime/in_pack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_generic.Tpo" "$(DEPDIR)/in_pack_generic.Po"; else rm -f "$(DEPDIR)/in_pack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/in_pack_generic.c' object='in_pack_generic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_generic.Po' tmpdepfile='$(DEPDIR)/in_pack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_generic.o `test -f 'runtime/in_pack_generic.c' || echo '$(srcdir)/'`runtime/in_pack_generic.c + +in_pack_generic.obj: runtime/in_pack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_generic.obj -MD -MP -MF "$(DEPDIR)/in_pack_generic.Tpo" -c -o in_pack_generic.obj `if test -f 'runtime/in_pack_generic.c'; then $(CYGPATH_W) 'runtime/in_pack_generic.c'; else $(CYGPATH_W) '$(srcdir)/runtime/in_pack_generic.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_generic.Tpo" "$(DEPDIR)/in_pack_generic.Po"; else rm -f "$(DEPDIR)/in_pack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/in_pack_generic.c' object='in_pack_generic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_generic.Po' tmpdepfile='$(DEPDIR)/in_pack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_generic.obj `if test -f 'runtime/in_pack_generic.c'; then $(CYGPATH_W) 'runtime/in_pack_generic.c'; else $(CYGPATH_W) '$(srcdir)/runtime/in_pack_generic.c'; fi` + +in_pack_generic.lo: runtime/in_pack_generic.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_pack_generic.lo -MD -MP -MF "$(DEPDIR)/in_pack_generic.Tpo" -c -o in_pack_generic.lo `test -f 'runtime/in_pack_generic.c' || echo '$(srcdir)/'`runtime/in_pack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_pack_generic.Tpo" "$(DEPDIR)/in_pack_generic.Plo"; else rm -f "$(DEPDIR)/in_pack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/in_pack_generic.c' object='in_pack_generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_pack_generic.Plo' tmpdepfile='$(DEPDIR)/in_pack_generic.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_pack_generic.lo `test -f 'runtime/in_pack_generic.c' || echo '$(srcdir)/'`runtime/in_pack_generic.c + +in_unpack_generic.o: runtime/in_unpack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_generic.o -MD -MP -MF "$(DEPDIR)/in_unpack_generic.Tpo" -c -o in_unpack_generic.o `test -f 'runtime/in_unpack_generic.c' || echo '$(srcdir)/'`runtime/in_unpack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_generic.Tpo" "$(DEPDIR)/in_unpack_generic.Po"; else rm -f "$(DEPDIR)/in_unpack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/in_unpack_generic.c' object='in_unpack_generic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_generic.Po' tmpdepfile='$(DEPDIR)/in_unpack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_generic.o `test -f 'runtime/in_unpack_generic.c' || echo '$(srcdir)/'`runtime/in_unpack_generic.c + +in_unpack_generic.obj: runtime/in_unpack_generic.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_generic.obj -MD -MP -MF "$(DEPDIR)/in_unpack_generic.Tpo" -c -o in_unpack_generic.obj `if test -f 'runtime/in_unpack_generic.c'; then $(CYGPATH_W) 'runtime/in_unpack_generic.c'; else $(CYGPATH_W) '$(srcdir)/runtime/in_unpack_generic.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_generic.Tpo" "$(DEPDIR)/in_unpack_generic.Po"; else rm -f "$(DEPDIR)/in_unpack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/in_unpack_generic.c' object='in_unpack_generic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_generic.Po' tmpdepfile='$(DEPDIR)/in_unpack_generic.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_generic.obj `if test -f 'runtime/in_unpack_generic.c'; then $(CYGPATH_W) 'runtime/in_unpack_generic.c'; else $(CYGPATH_W) '$(srcdir)/runtime/in_unpack_generic.c'; fi` + +in_unpack_generic.lo: runtime/in_unpack_generic.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT in_unpack_generic.lo -MD -MP -MF "$(DEPDIR)/in_unpack_generic.Tpo" -c -o in_unpack_generic.lo `test -f 'runtime/in_unpack_generic.c' || echo '$(srcdir)/'`runtime/in_unpack_generic.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/in_unpack_generic.Tpo" "$(DEPDIR)/in_unpack_generic.Plo"; else rm -f "$(DEPDIR)/in_unpack_generic.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/in_unpack_generic.c' object='in_unpack_generic.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/in_unpack_generic.Plo' tmpdepfile='$(DEPDIR)/in_unpack_generic.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o in_unpack_generic.lo `test -f 'runtime/in_unpack_generic.c' || echo '$(srcdir)/'`runtime/in_unpack_generic.c + +trig_c4.o: generated/trig_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trig_c4.o -MD -MP -MF "$(DEPDIR)/trig_c4.Tpo" -c -o trig_c4.o `test -f 'generated/trig_c4.c' || echo '$(srcdir)/'`generated/trig_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/trig_c4.Tpo" "$(DEPDIR)/trig_c4.Po"; else rm -f "$(DEPDIR)/trig_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/trig_c4.c' object='trig_c4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/trig_c4.Po' tmpdepfile='$(DEPDIR)/trig_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trig_c4.o `test -f 'generated/trig_c4.c' || echo '$(srcdir)/'`generated/trig_c4.c + +trig_c4.obj: generated/trig_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trig_c4.obj -MD -MP -MF "$(DEPDIR)/trig_c4.Tpo" -c -o trig_c4.obj `if test -f 'generated/trig_c4.c'; then $(CYGPATH_W) 'generated/trig_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/trig_c4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/trig_c4.Tpo" "$(DEPDIR)/trig_c4.Po"; else rm -f "$(DEPDIR)/trig_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/trig_c4.c' object='trig_c4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/trig_c4.Po' tmpdepfile='$(DEPDIR)/trig_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trig_c4.obj `if test -f 'generated/trig_c4.c'; then $(CYGPATH_W) 'generated/trig_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/trig_c4.c'; fi` + +trig_c4.lo: generated/trig_c4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trig_c4.lo -MD -MP -MF "$(DEPDIR)/trig_c4.Tpo" -c -o trig_c4.lo `test -f 'generated/trig_c4.c' || echo '$(srcdir)/'`generated/trig_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/trig_c4.Tpo" "$(DEPDIR)/trig_c4.Plo"; else rm -f "$(DEPDIR)/trig_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/trig_c4.c' object='trig_c4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/trig_c4.Plo' tmpdepfile='$(DEPDIR)/trig_c4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trig_c4.lo `test -f 'generated/trig_c4.c' || echo '$(srcdir)/'`generated/trig_c4.c + +trig_c8.o: generated/trig_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trig_c8.o -MD -MP -MF "$(DEPDIR)/trig_c8.Tpo" -c -o trig_c8.o `test -f 'generated/trig_c8.c' || echo '$(srcdir)/'`generated/trig_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/trig_c8.Tpo" "$(DEPDIR)/trig_c8.Po"; else rm -f "$(DEPDIR)/trig_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/trig_c8.c' object='trig_c8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/trig_c8.Po' tmpdepfile='$(DEPDIR)/trig_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trig_c8.o `test -f 'generated/trig_c8.c' || echo '$(srcdir)/'`generated/trig_c8.c + +trig_c8.obj: generated/trig_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trig_c8.obj -MD -MP -MF "$(DEPDIR)/trig_c8.Tpo" -c -o trig_c8.obj `if test -f 'generated/trig_c8.c'; then $(CYGPATH_W) 'generated/trig_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/trig_c8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/trig_c8.Tpo" "$(DEPDIR)/trig_c8.Po"; else rm -f "$(DEPDIR)/trig_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/trig_c8.c' object='trig_c8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/trig_c8.Po' tmpdepfile='$(DEPDIR)/trig_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trig_c8.obj `if test -f 'generated/trig_c8.c'; then $(CYGPATH_W) 'generated/trig_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/trig_c8.c'; fi` + +trig_c8.lo: generated/trig_c8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT trig_c8.lo -MD -MP -MF "$(DEPDIR)/trig_c8.Tpo" -c -o trig_c8.lo `test -f 'generated/trig_c8.c' || echo '$(srcdir)/'`generated/trig_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/trig_c8.Tpo" "$(DEPDIR)/trig_c8.Plo"; else rm -f "$(DEPDIR)/trig_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/trig_c8.c' object='trig_c8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/trig_c8.Plo' tmpdepfile='$(DEPDIR)/trig_c8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trig_c8.lo `test -f 'generated/trig_c8.c' || echo '$(srcdir)/'`generated/trig_c8.c + +exp_c4.o: generated/exp_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exp_c4.o -MD -MP -MF "$(DEPDIR)/exp_c4.Tpo" -c -o exp_c4.o `test -f 'generated/exp_c4.c' || echo '$(srcdir)/'`generated/exp_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exp_c4.Tpo" "$(DEPDIR)/exp_c4.Po"; else rm -f "$(DEPDIR)/exp_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exp_c4.c' object='exp_c4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exp_c4.Po' tmpdepfile='$(DEPDIR)/exp_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exp_c4.o `test -f 'generated/exp_c4.c' || echo '$(srcdir)/'`generated/exp_c4.c + +exp_c4.obj: generated/exp_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exp_c4.obj -MD -MP -MF "$(DEPDIR)/exp_c4.Tpo" -c -o exp_c4.obj `if test -f 'generated/exp_c4.c'; then $(CYGPATH_W) 'generated/exp_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/exp_c4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exp_c4.Tpo" "$(DEPDIR)/exp_c4.Po"; else rm -f "$(DEPDIR)/exp_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exp_c4.c' object='exp_c4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exp_c4.Po' tmpdepfile='$(DEPDIR)/exp_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exp_c4.obj `if test -f 'generated/exp_c4.c'; then $(CYGPATH_W) 'generated/exp_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/exp_c4.c'; fi` + +exp_c4.lo: generated/exp_c4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exp_c4.lo -MD -MP -MF "$(DEPDIR)/exp_c4.Tpo" -c -o exp_c4.lo `test -f 'generated/exp_c4.c' || echo '$(srcdir)/'`generated/exp_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exp_c4.Tpo" "$(DEPDIR)/exp_c4.Plo"; else rm -f "$(DEPDIR)/exp_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exp_c4.c' object='exp_c4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exp_c4.Plo' tmpdepfile='$(DEPDIR)/exp_c4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exp_c4.lo `test -f 'generated/exp_c4.c' || echo '$(srcdir)/'`generated/exp_c4.c + +exp_c8.o: generated/exp_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exp_c8.o -MD -MP -MF "$(DEPDIR)/exp_c8.Tpo" -c -o exp_c8.o `test -f 'generated/exp_c8.c' || echo '$(srcdir)/'`generated/exp_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exp_c8.Tpo" "$(DEPDIR)/exp_c8.Po"; else rm -f "$(DEPDIR)/exp_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exp_c8.c' object='exp_c8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exp_c8.Po' tmpdepfile='$(DEPDIR)/exp_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exp_c8.o `test -f 'generated/exp_c8.c' || echo '$(srcdir)/'`generated/exp_c8.c + +exp_c8.obj: generated/exp_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exp_c8.obj -MD -MP -MF "$(DEPDIR)/exp_c8.Tpo" -c -o exp_c8.obj `if test -f 'generated/exp_c8.c'; then $(CYGPATH_W) 'generated/exp_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/exp_c8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exp_c8.Tpo" "$(DEPDIR)/exp_c8.Po"; else rm -f "$(DEPDIR)/exp_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exp_c8.c' object='exp_c8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exp_c8.Po' tmpdepfile='$(DEPDIR)/exp_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exp_c8.obj `if test -f 'generated/exp_c8.c'; then $(CYGPATH_W) 'generated/exp_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/exp_c8.c'; fi` + +exp_c8.lo: generated/exp_c8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT exp_c8.lo -MD -MP -MF "$(DEPDIR)/exp_c8.Tpo" -c -o exp_c8.lo `test -f 'generated/exp_c8.c' || echo '$(srcdir)/'`generated/exp_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/exp_c8.Tpo" "$(DEPDIR)/exp_c8.Plo"; else rm -f "$(DEPDIR)/exp_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/exp_c8.c' object='exp_c8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/exp_c8.Plo' tmpdepfile='$(DEPDIR)/exp_c8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o exp_c8.lo `test -f 'generated/exp_c8.c' || echo '$(srcdir)/'`generated/exp_c8.c + +hyp_c4.o: generated/hyp_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hyp_c4.o -MD -MP -MF "$(DEPDIR)/hyp_c4.Tpo" -c -o hyp_c4.o `test -f 'generated/hyp_c4.c' || echo '$(srcdir)/'`generated/hyp_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hyp_c4.Tpo" "$(DEPDIR)/hyp_c4.Po"; else rm -f "$(DEPDIR)/hyp_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/hyp_c4.c' object='hyp_c4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/hyp_c4.Po' tmpdepfile='$(DEPDIR)/hyp_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hyp_c4.o `test -f 'generated/hyp_c4.c' || echo '$(srcdir)/'`generated/hyp_c4.c + +hyp_c4.obj: generated/hyp_c4.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hyp_c4.obj -MD -MP -MF "$(DEPDIR)/hyp_c4.Tpo" -c -o hyp_c4.obj `if test -f 'generated/hyp_c4.c'; then $(CYGPATH_W) 'generated/hyp_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/hyp_c4.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hyp_c4.Tpo" "$(DEPDIR)/hyp_c4.Po"; else rm -f "$(DEPDIR)/hyp_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/hyp_c4.c' object='hyp_c4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/hyp_c4.Po' tmpdepfile='$(DEPDIR)/hyp_c4.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hyp_c4.obj `if test -f 'generated/hyp_c4.c'; then $(CYGPATH_W) 'generated/hyp_c4.c'; else $(CYGPATH_W) '$(srcdir)/generated/hyp_c4.c'; fi` + +hyp_c4.lo: generated/hyp_c4.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hyp_c4.lo -MD -MP -MF "$(DEPDIR)/hyp_c4.Tpo" -c -o hyp_c4.lo `test -f 'generated/hyp_c4.c' || echo '$(srcdir)/'`generated/hyp_c4.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hyp_c4.Tpo" "$(DEPDIR)/hyp_c4.Plo"; else rm -f "$(DEPDIR)/hyp_c4.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/hyp_c4.c' object='hyp_c4.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/hyp_c4.Plo' tmpdepfile='$(DEPDIR)/hyp_c4.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hyp_c4.lo `test -f 'generated/hyp_c4.c' || echo '$(srcdir)/'`generated/hyp_c4.c + +hyp_c8.o: generated/hyp_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hyp_c8.o -MD -MP -MF "$(DEPDIR)/hyp_c8.Tpo" -c -o hyp_c8.o `test -f 'generated/hyp_c8.c' || echo '$(srcdir)/'`generated/hyp_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hyp_c8.Tpo" "$(DEPDIR)/hyp_c8.Po"; else rm -f "$(DEPDIR)/hyp_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/hyp_c8.c' object='hyp_c8.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/hyp_c8.Po' tmpdepfile='$(DEPDIR)/hyp_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hyp_c8.o `test -f 'generated/hyp_c8.c' || echo '$(srcdir)/'`generated/hyp_c8.c + +hyp_c8.obj: generated/hyp_c8.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hyp_c8.obj -MD -MP -MF "$(DEPDIR)/hyp_c8.Tpo" -c -o hyp_c8.obj `if test -f 'generated/hyp_c8.c'; then $(CYGPATH_W) 'generated/hyp_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/hyp_c8.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hyp_c8.Tpo" "$(DEPDIR)/hyp_c8.Po"; else rm -f "$(DEPDIR)/hyp_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/hyp_c8.c' object='hyp_c8.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/hyp_c8.Po' tmpdepfile='$(DEPDIR)/hyp_c8.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hyp_c8.obj `if test -f 'generated/hyp_c8.c'; then $(CYGPATH_W) 'generated/hyp_c8.c'; else $(CYGPATH_W) '$(srcdir)/generated/hyp_c8.c'; fi` + +hyp_c8.lo: generated/hyp_c8.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hyp_c8.lo -MD -MP -MF "$(DEPDIR)/hyp_c8.Tpo" -c -o hyp_c8.lo `test -f 'generated/hyp_c8.c' || echo '$(srcdir)/'`generated/hyp_c8.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/hyp_c8.Tpo" "$(DEPDIR)/hyp_c8.Plo"; else rm -f "$(DEPDIR)/hyp_c8.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='generated/hyp_c8.c' object='hyp_c8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/hyp_c8.Plo' tmpdepfile='$(DEPDIR)/hyp_c8.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hyp_c8.lo `test -f 'generated/hyp_c8.c' || echo '$(srcdir)/'`generated/hyp_c8.c + +.f90.o: + $(F77COMPILE) -c -o $@ $< + +.f90.obj: + $(F77COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.f90.lo: + $(LTF77COMPILE) -c -o $@ $< + +selected_kind.o: intrinsics/selected_kind.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o selected_kind.o `test -f 'intrinsics/selected_kind.f90' || echo '$(srcdir)/'`intrinsics/selected_kind.f90 + +selected_kind.obj: intrinsics/selected_kind.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o selected_kind.obj `if test -f 'intrinsics/selected_kind.f90'; then $(CYGPATH_W) 'intrinsics/selected_kind.f90'; else $(CYGPATH_W) '$(srcdir)/intrinsics/selected_kind.f90'; fi` + +selected_kind.lo: intrinsics/selected_kind.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o selected_kind.lo `test -f 'intrinsics/selected_kind.f90' || echo '$(srcdir)/'`intrinsics/selected_kind.f90 + +_abs_c4.o: generated/_abs_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_c4.o `test -f 'generated/_abs_c4.f90' || echo '$(srcdir)/'`generated/_abs_c4.f90 + +_abs_c4.obj: generated/_abs_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_c4.obj `if test -f 'generated/_abs_c4.f90'; then $(CYGPATH_W) 'generated/_abs_c4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_abs_c4.f90'; fi` + +_abs_c4.lo: generated/_abs_c4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_c4.lo `test -f 'generated/_abs_c4.f90' || echo '$(srcdir)/'`generated/_abs_c4.f90 + +_abs_c8.o: generated/_abs_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_c8.o `test -f 'generated/_abs_c8.f90' || echo '$(srcdir)/'`generated/_abs_c8.f90 + +_abs_c8.obj: generated/_abs_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_c8.obj `if test -f 'generated/_abs_c8.f90'; then $(CYGPATH_W) 'generated/_abs_c8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_abs_c8.f90'; fi` + +_abs_c8.lo: generated/_abs_c8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_c8.lo `test -f 'generated/_abs_c8.f90' || echo '$(srcdir)/'`generated/_abs_c8.f90 + +_abs_i4.o: generated/_abs_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_i4.o `test -f 'generated/_abs_i4.f90' || echo '$(srcdir)/'`generated/_abs_i4.f90 + +_abs_i4.obj: generated/_abs_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_i4.obj `if test -f 'generated/_abs_i4.f90'; then $(CYGPATH_W) 'generated/_abs_i4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_abs_i4.f90'; fi` + +_abs_i4.lo: generated/_abs_i4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_i4.lo `test -f 'generated/_abs_i4.f90' || echo '$(srcdir)/'`generated/_abs_i4.f90 + +_abs_i8.o: generated/_abs_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_i8.o `test -f 'generated/_abs_i8.f90' || echo '$(srcdir)/'`generated/_abs_i8.f90 + +_abs_i8.obj: generated/_abs_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_i8.obj `if test -f 'generated/_abs_i8.f90'; then $(CYGPATH_W) 'generated/_abs_i8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_abs_i8.f90'; fi` + +_abs_i8.lo: generated/_abs_i8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_i8.lo `test -f 'generated/_abs_i8.f90' || echo '$(srcdir)/'`generated/_abs_i8.f90 + +_abs_r4.o: generated/_abs_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_r4.o `test -f 'generated/_abs_r4.f90' || echo '$(srcdir)/'`generated/_abs_r4.f90 + +_abs_r4.obj: generated/_abs_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_r4.obj `if test -f 'generated/_abs_r4.f90'; then $(CYGPATH_W) 'generated/_abs_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_abs_r4.f90'; fi` + +_abs_r4.lo: generated/_abs_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_r4.lo `test -f 'generated/_abs_r4.f90' || echo '$(srcdir)/'`generated/_abs_r4.f90 + +_abs_r8.o: generated/_abs_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_r8.o `test -f 'generated/_abs_r8.f90' || echo '$(srcdir)/'`generated/_abs_r8.f90 + +_abs_r8.obj: generated/_abs_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_r8.obj `if test -f 'generated/_abs_r8.f90'; then $(CYGPATH_W) 'generated/_abs_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_abs_r8.f90'; fi` + +_abs_r8.lo: generated/_abs_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _abs_r8.lo `test -f 'generated/_abs_r8.f90' || echo '$(srcdir)/'`generated/_abs_r8.f90 + +_exp_r4.o: generated/_exp_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_r4.o `test -f 'generated/_exp_r4.f90' || echo '$(srcdir)/'`generated/_exp_r4.f90 + +_exp_r4.obj: generated/_exp_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_r4.obj `if test -f 'generated/_exp_r4.f90'; then $(CYGPATH_W) 'generated/_exp_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_exp_r4.f90'; fi` + +_exp_r4.lo: generated/_exp_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_r4.lo `test -f 'generated/_exp_r4.f90' || echo '$(srcdir)/'`generated/_exp_r4.f90 + +_exp_r8.o: generated/_exp_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_r8.o `test -f 'generated/_exp_r8.f90' || echo '$(srcdir)/'`generated/_exp_r8.f90 + +_exp_r8.obj: generated/_exp_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_r8.obj `if test -f 'generated/_exp_r8.f90'; then $(CYGPATH_W) 'generated/_exp_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_exp_r8.f90'; fi` + +_exp_r8.lo: generated/_exp_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_r8.lo `test -f 'generated/_exp_r8.f90' || echo '$(srcdir)/'`generated/_exp_r8.f90 + +_exp_c4.o: generated/_exp_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_c4.o `test -f 'generated/_exp_c4.f90' || echo '$(srcdir)/'`generated/_exp_c4.f90 + +_exp_c4.obj: generated/_exp_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_c4.obj `if test -f 'generated/_exp_c4.f90'; then $(CYGPATH_W) 'generated/_exp_c4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_exp_c4.f90'; fi` + +_exp_c4.lo: generated/_exp_c4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_c4.lo `test -f 'generated/_exp_c4.f90' || echo '$(srcdir)/'`generated/_exp_c4.f90 + +_exp_c8.o: generated/_exp_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_c8.o `test -f 'generated/_exp_c8.f90' || echo '$(srcdir)/'`generated/_exp_c8.f90 + +_exp_c8.obj: generated/_exp_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_c8.obj `if test -f 'generated/_exp_c8.f90'; then $(CYGPATH_W) 'generated/_exp_c8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_exp_c8.f90'; fi` + +_exp_c8.lo: generated/_exp_c8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _exp_c8.lo `test -f 'generated/_exp_c8.f90' || echo '$(srcdir)/'`generated/_exp_c8.f90 + +_log_r4.o: generated/_log_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_r4.o `test -f 'generated/_log_r4.f90' || echo '$(srcdir)/'`generated/_log_r4.f90 + +_log_r4.obj: generated/_log_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_r4.obj `if test -f 'generated/_log_r4.f90'; then $(CYGPATH_W) 'generated/_log_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_log_r4.f90'; fi` + +_log_r4.lo: generated/_log_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_r4.lo `test -f 'generated/_log_r4.f90' || echo '$(srcdir)/'`generated/_log_r4.f90 + +_log_r8.o: generated/_log_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_r8.o `test -f 'generated/_log_r8.f90' || echo '$(srcdir)/'`generated/_log_r8.f90 + +_log_r8.obj: generated/_log_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_r8.obj `if test -f 'generated/_log_r8.f90'; then $(CYGPATH_W) 'generated/_log_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_log_r8.f90'; fi` + +_log_r8.lo: generated/_log_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_r8.lo `test -f 'generated/_log_r8.f90' || echo '$(srcdir)/'`generated/_log_r8.f90 + +_log_c4.o: generated/_log_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_c4.o `test -f 'generated/_log_c4.f90' || echo '$(srcdir)/'`generated/_log_c4.f90 + +_log_c4.obj: generated/_log_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_c4.obj `if test -f 'generated/_log_c4.f90'; then $(CYGPATH_W) 'generated/_log_c4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_log_c4.f90'; fi` + +_log_c4.lo: generated/_log_c4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_c4.lo `test -f 'generated/_log_c4.f90' || echo '$(srcdir)/'`generated/_log_c4.f90 + +_log_c8.o: generated/_log_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_c8.o `test -f 'generated/_log_c8.f90' || echo '$(srcdir)/'`generated/_log_c8.f90 + +_log_c8.obj: generated/_log_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_c8.obj `if test -f 'generated/_log_c8.f90'; then $(CYGPATH_W) 'generated/_log_c8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_log_c8.f90'; fi` + +_log_c8.lo: generated/_log_c8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log_c8.lo `test -f 'generated/_log_c8.f90' || echo '$(srcdir)/'`generated/_log_c8.f90 + +_log10_r4.o: generated/_log10_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log10_r4.o `test -f 'generated/_log10_r4.f90' || echo '$(srcdir)/'`generated/_log10_r4.f90 + +_log10_r4.obj: generated/_log10_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log10_r4.obj `if test -f 'generated/_log10_r4.f90'; then $(CYGPATH_W) 'generated/_log10_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_log10_r4.f90'; fi` + +_log10_r4.lo: generated/_log10_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log10_r4.lo `test -f 'generated/_log10_r4.f90' || echo '$(srcdir)/'`generated/_log10_r4.f90 + +_log10_r8.o: generated/_log10_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log10_r8.o `test -f 'generated/_log10_r8.f90' || echo '$(srcdir)/'`generated/_log10_r8.f90 + +_log10_r8.obj: generated/_log10_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log10_r8.obj `if test -f 'generated/_log10_r8.f90'; then $(CYGPATH_W) 'generated/_log10_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_log10_r8.f90'; fi` + +_log10_r8.lo: generated/_log10_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _log10_r8.lo `test -f 'generated/_log10_r8.f90' || echo '$(srcdir)/'`generated/_log10_r8.f90 + +_sqrt_r4.o: generated/_sqrt_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_r4.o `test -f 'generated/_sqrt_r4.f90' || echo '$(srcdir)/'`generated/_sqrt_r4.f90 + +_sqrt_r4.obj: generated/_sqrt_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_r4.obj `if test -f 'generated/_sqrt_r4.f90'; then $(CYGPATH_W) 'generated/_sqrt_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sqrt_r4.f90'; fi` + +_sqrt_r4.lo: generated/_sqrt_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_r4.lo `test -f 'generated/_sqrt_r4.f90' || echo '$(srcdir)/'`generated/_sqrt_r4.f90 + +_sqrt_r8.o: generated/_sqrt_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_r8.o `test -f 'generated/_sqrt_r8.f90' || echo '$(srcdir)/'`generated/_sqrt_r8.f90 + +_sqrt_r8.obj: generated/_sqrt_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_r8.obj `if test -f 'generated/_sqrt_r8.f90'; then $(CYGPATH_W) 'generated/_sqrt_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sqrt_r8.f90'; fi` + +_sqrt_r8.lo: generated/_sqrt_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_r8.lo `test -f 'generated/_sqrt_r8.f90' || echo '$(srcdir)/'`generated/_sqrt_r8.f90 + +_sqrt_c4.o: generated/_sqrt_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_c4.o `test -f 'generated/_sqrt_c4.f90' || echo '$(srcdir)/'`generated/_sqrt_c4.f90 + +_sqrt_c4.obj: generated/_sqrt_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_c4.obj `if test -f 'generated/_sqrt_c4.f90'; then $(CYGPATH_W) 'generated/_sqrt_c4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sqrt_c4.f90'; fi` + +_sqrt_c4.lo: generated/_sqrt_c4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_c4.lo `test -f 'generated/_sqrt_c4.f90' || echo '$(srcdir)/'`generated/_sqrt_c4.f90 + +_sqrt_c8.o: generated/_sqrt_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_c8.o `test -f 'generated/_sqrt_c8.f90' || echo '$(srcdir)/'`generated/_sqrt_c8.f90 + +_sqrt_c8.obj: generated/_sqrt_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_c8.obj `if test -f 'generated/_sqrt_c8.f90'; then $(CYGPATH_W) 'generated/_sqrt_c8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sqrt_c8.f90'; fi` + +_sqrt_c8.lo: generated/_sqrt_c8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sqrt_c8.lo `test -f 'generated/_sqrt_c8.f90' || echo '$(srcdir)/'`generated/_sqrt_c8.f90 + +_asin_r4.o: generated/_asin_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _asin_r4.o `test -f 'generated/_asin_r4.f90' || echo '$(srcdir)/'`generated/_asin_r4.f90 + +_asin_r4.obj: generated/_asin_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _asin_r4.obj `if test -f 'generated/_asin_r4.f90'; then $(CYGPATH_W) 'generated/_asin_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_asin_r4.f90'; fi` + +_asin_r4.lo: generated/_asin_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _asin_r4.lo `test -f 'generated/_asin_r4.f90' || echo '$(srcdir)/'`generated/_asin_r4.f90 + +_asin_r8.o: generated/_asin_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _asin_r8.o `test -f 'generated/_asin_r8.f90' || echo '$(srcdir)/'`generated/_asin_r8.f90 + +_asin_r8.obj: generated/_asin_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _asin_r8.obj `if test -f 'generated/_asin_r8.f90'; then $(CYGPATH_W) 'generated/_asin_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_asin_r8.f90'; fi` + +_asin_r8.lo: generated/_asin_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _asin_r8.lo `test -f 'generated/_asin_r8.f90' || echo '$(srcdir)/'`generated/_asin_r8.f90 + +_acos_r4.o: generated/_acos_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _acos_r4.o `test -f 'generated/_acos_r4.f90' || echo '$(srcdir)/'`generated/_acos_r4.f90 + +_acos_r4.obj: generated/_acos_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _acos_r4.obj `if test -f 'generated/_acos_r4.f90'; then $(CYGPATH_W) 'generated/_acos_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_acos_r4.f90'; fi` + +_acos_r4.lo: generated/_acos_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _acos_r4.lo `test -f 'generated/_acos_r4.f90' || echo '$(srcdir)/'`generated/_acos_r4.f90 + +_acos_r8.o: generated/_acos_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _acos_r8.o `test -f 'generated/_acos_r8.f90' || echo '$(srcdir)/'`generated/_acos_r8.f90 + +_acos_r8.obj: generated/_acos_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _acos_r8.obj `if test -f 'generated/_acos_r8.f90'; then $(CYGPATH_W) 'generated/_acos_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_acos_r8.f90'; fi` + +_acos_r8.lo: generated/_acos_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _acos_r8.lo `test -f 'generated/_acos_r8.f90' || echo '$(srcdir)/'`generated/_acos_r8.f90 + +_atan_r4.o: generated/_atan_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan_r4.o `test -f 'generated/_atan_r4.f90' || echo '$(srcdir)/'`generated/_atan_r4.f90 + +_atan_r4.obj: generated/_atan_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan_r4.obj `if test -f 'generated/_atan_r4.f90'; then $(CYGPATH_W) 'generated/_atan_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_atan_r4.f90'; fi` + +_atan_r4.lo: generated/_atan_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan_r4.lo `test -f 'generated/_atan_r4.f90' || echo '$(srcdir)/'`generated/_atan_r4.f90 + +_atan_r8.o: generated/_atan_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan_r8.o `test -f 'generated/_atan_r8.f90' || echo '$(srcdir)/'`generated/_atan_r8.f90 + +_atan_r8.obj: generated/_atan_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan_r8.obj `if test -f 'generated/_atan_r8.f90'; then $(CYGPATH_W) 'generated/_atan_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_atan_r8.f90'; fi` + +_atan_r8.lo: generated/_atan_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan_r8.lo `test -f 'generated/_atan_r8.f90' || echo '$(srcdir)/'`generated/_atan_r8.f90 + +_sin_r4.o: generated/_sin_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_r4.o `test -f 'generated/_sin_r4.f90' || echo '$(srcdir)/'`generated/_sin_r4.f90 + +_sin_r4.obj: generated/_sin_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_r4.obj `if test -f 'generated/_sin_r4.f90'; then $(CYGPATH_W) 'generated/_sin_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sin_r4.f90'; fi` + +_sin_r4.lo: generated/_sin_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_r4.lo `test -f 'generated/_sin_r4.f90' || echo '$(srcdir)/'`generated/_sin_r4.f90 + +_sin_r8.o: generated/_sin_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_r8.o `test -f 'generated/_sin_r8.f90' || echo '$(srcdir)/'`generated/_sin_r8.f90 + +_sin_r8.obj: generated/_sin_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_r8.obj `if test -f 'generated/_sin_r8.f90'; then $(CYGPATH_W) 'generated/_sin_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sin_r8.f90'; fi` + +_sin_r8.lo: generated/_sin_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_r8.lo `test -f 'generated/_sin_r8.f90' || echo '$(srcdir)/'`generated/_sin_r8.f90 + +_sin_c4.o: generated/_sin_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_c4.o `test -f 'generated/_sin_c4.f90' || echo '$(srcdir)/'`generated/_sin_c4.f90 + +_sin_c4.obj: generated/_sin_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_c4.obj `if test -f 'generated/_sin_c4.f90'; then $(CYGPATH_W) 'generated/_sin_c4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sin_c4.f90'; fi` + +_sin_c4.lo: generated/_sin_c4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_c4.lo `test -f 'generated/_sin_c4.f90' || echo '$(srcdir)/'`generated/_sin_c4.f90 + +_sin_c8.o: generated/_sin_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_c8.o `test -f 'generated/_sin_c8.f90' || echo '$(srcdir)/'`generated/_sin_c8.f90 + +_sin_c8.obj: generated/_sin_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_c8.obj `if test -f 'generated/_sin_c8.f90'; then $(CYGPATH_W) 'generated/_sin_c8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sin_c8.f90'; fi` + +_sin_c8.lo: generated/_sin_c8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sin_c8.lo `test -f 'generated/_sin_c8.f90' || echo '$(srcdir)/'`generated/_sin_c8.f90 + +_cos_r4.o: generated/_cos_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_r4.o `test -f 'generated/_cos_r4.f90' || echo '$(srcdir)/'`generated/_cos_r4.f90 + +_cos_r4.obj: generated/_cos_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_r4.obj `if test -f 'generated/_cos_r4.f90'; then $(CYGPATH_W) 'generated/_cos_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_cos_r4.f90'; fi` + +_cos_r4.lo: generated/_cos_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_r4.lo `test -f 'generated/_cos_r4.f90' || echo '$(srcdir)/'`generated/_cos_r4.f90 + +_cos_r8.o: generated/_cos_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_r8.o `test -f 'generated/_cos_r8.f90' || echo '$(srcdir)/'`generated/_cos_r8.f90 + +_cos_r8.obj: generated/_cos_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_r8.obj `if test -f 'generated/_cos_r8.f90'; then $(CYGPATH_W) 'generated/_cos_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_cos_r8.f90'; fi` + +_cos_r8.lo: generated/_cos_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_r8.lo `test -f 'generated/_cos_r8.f90' || echo '$(srcdir)/'`generated/_cos_r8.f90 + +_cos_c4.o: generated/_cos_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_c4.o `test -f 'generated/_cos_c4.f90' || echo '$(srcdir)/'`generated/_cos_c4.f90 + +_cos_c4.obj: generated/_cos_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_c4.obj `if test -f 'generated/_cos_c4.f90'; then $(CYGPATH_W) 'generated/_cos_c4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_cos_c4.f90'; fi` + +_cos_c4.lo: generated/_cos_c4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_c4.lo `test -f 'generated/_cos_c4.f90' || echo '$(srcdir)/'`generated/_cos_c4.f90 + +_cos_c8.o: generated/_cos_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_c8.o `test -f 'generated/_cos_c8.f90' || echo '$(srcdir)/'`generated/_cos_c8.f90 + +_cos_c8.obj: generated/_cos_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_c8.obj `if test -f 'generated/_cos_c8.f90'; then $(CYGPATH_W) 'generated/_cos_c8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_cos_c8.f90'; fi` + +_cos_c8.lo: generated/_cos_c8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cos_c8.lo `test -f 'generated/_cos_c8.f90' || echo '$(srcdir)/'`generated/_cos_c8.f90 + +_tan_r4.o: generated/_tan_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tan_r4.o `test -f 'generated/_tan_r4.f90' || echo '$(srcdir)/'`generated/_tan_r4.f90 + +_tan_r4.obj: generated/_tan_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tan_r4.obj `if test -f 'generated/_tan_r4.f90'; then $(CYGPATH_W) 'generated/_tan_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_tan_r4.f90'; fi` + +_tan_r4.lo: generated/_tan_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tan_r4.lo `test -f 'generated/_tan_r4.f90' || echo '$(srcdir)/'`generated/_tan_r4.f90 + +_tan_r8.o: generated/_tan_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tan_r8.o `test -f 'generated/_tan_r8.f90' || echo '$(srcdir)/'`generated/_tan_r8.f90 + +_tan_r8.obj: generated/_tan_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tan_r8.obj `if test -f 'generated/_tan_r8.f90'; then $(CYGPATH_W) 'generated/_tan_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_tan_r8.f90'; fi` + +_tan_r8.lo: generated/_tan_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tan_r8.lo `test -f 'generated/_tan_r8.f90' || echo '$(srcdir)/'`generated/_tan_r8.f90 + +_sinh_r4.o: generated/_sinh_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sinh_r4.o `test -f 'generated/_sinh_r4.f90' || echo '$(srcdir)/'`generated/_sinh_r4.f90 + +_sinh_r4.obj: generated/_sinh_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sinh_r4.obj `if test -f 'generated/_sinh_r4.f90'; then $(CYGPATH_W) 'generated/_sinh_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sinh_r4.f90'; fi` + +_sinh_r4.lo: generated/_sinh_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sinh_r4.lo `test -f 'generated/_sinh_r4.f90' || echo '$(srcdir)/'`generated/_sinh_r4.f90 + +_sinh_r8.o: generated/_sinh_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sinh_r8.o `test -f 'generated/_sinh_r8.f90' || echo '$(srcdir)/'`generated/_sinh_r8.f90 + +_sinh_r8.obj: generated/_sinh_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sinh_r8.obj `if test -f 'generated/_sinh_r8.f90'; then $(CYGPATH_W) 'generated/_sinh_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sinh_r8.f90'; fi` + +_sinh_r8.lo: generated/_sinh_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sinh_r8.lo `test -f 'generated/_sinh_r8.f90' || echo '$(srcdir)/'`generated/_sinh_r8.f90 + +_cosh_r4.o: generated/_cosh_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cosh_r4.o `test -f 'generated/_cosh_r4.f90' || echo '$(srcdir)/'`generated/_cosh_r4.f90 + +_cosh_r4.obj: generated/_cosh_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cosh_r4.obj `if test -f 'generated/_cosh_r4.f90'; then $(CYGPATH_W) 'generated/_cosh_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_cosh_r4.f90'; fi` + +_cosh_r4.lo: generated/_cosh_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cosh_r4.lo `test -f 'generated/_cosh_r4.f90' || echo '$(srcdir)/'`generated/_cosh_r4.f90 + +_cosh_r8.o: generated/_cosh_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cosh_r8.o `test -f 'generated/_cosh_r8.f90' || echo '$(srcdir)/'`generated/_cosh_r8.f90 + +_cosh_r8.obj: generated/_cosh_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cosh_r8.obj `if test -f 'generated/_cosh_r8.f90'; then $(CYGPATH_W) 'generated/_cosh_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_cosh_r8.f90'; fi` + +_cosh_r8.lo: generated/_cosh_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _cosh_r8.lo `test -f 'generated/_cosh_r8.f90' || echo '$(srcdir)/'`generated/_cosh_r8.f90 + +_tanh_r4.o: generated/_tanh_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tanh_r4.o `test -f 'generated/_tanh_r4.f90' || echo '$(srcdir)/'`generated/_tanh_r4.f90 + +_tanh_r4.obj: generated/_tanh_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tanh_r4.obj `if test -f 'generated/_tanh_r4.f90'; then $(CYGPATH_W) 'generated/_tanh_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_tanh_r4.f90'; fi` + +_tanh_r4.lo: generated/_tanh_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tanh_r4.lo `test -f 'generated/_tanh_r4.f90' || echo '$(srcdir)/'`generated/_tanh_r4.f90 + +_tanh_r8.o: generated/_tanh_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tanh_r8.o `test -f 'generated/_tanh_r8.f90' || echo '$(srcdir)/'`generated/_tanh_r8.f90 + +_tanh_r8.obj: generated/_tanh_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tanh_r8.obj `if test -f 'generated/_tanh_r8.f90'; then $(CYGPATH_W) 'generated/_tanh_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_tanh_r8.f90'; fi` + +_tanh_r8.lo: generated/_tanh_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _tanh_r8.lo `test -f 'generated/_tanh_r8.f90' || echo '$(srcdir)/'`generated/_tanh_r8.f90 + +_conjg_c4.o: generated/_conjg_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _conjg_c4.o `test -f 'generated/_conjg_c4.f90' || echo '$(srcdir)/'`generated/_conjg_c4.f90 + +_conjg_c4.obj: generated/_conjg_c4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _conjg_c4.obj `if test -f 'generated/_conjg_c4.f90'; then $(CYGPATH_W) 'generated/_conjg_c4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_conjg_c4.f90'; fi` + +_conjg_c4.lo: generated/_conjg_c4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _conjg_c4.lo `test -f 'generated/_conjg_c4.f90' || echo '$(srcdir)/'`generated/_conjg_c4.f90 + +_conjg_c8.o: generated/_conjg_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _conjg_c8.o `test -f 'generated/_conjg_c8.f90' || echo '$(srcdir)/'`generated/_conjg_c8.f90 + +_conjg_c8.obj: generated/_conjg_c8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _conjg_c8.obj `if test -f 'generated/_conjg_c8.f90'; then $(CYGPATH_W) 'generated/_conjg_c8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_conjg_c8.f90'; fi` + +_conjg_c8.lo: generated/_conjg_c8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _conjg_c8.lo `test -f 'generated/_conjg_c8.f90' || echo '$(srcdir)/'`generated/_conjg_c8.f90 + +_aint_r4.o: generated/_aint_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _aint_r4.o `test -f 'generated/_aint_r4.f90' || echo '$(srcdir)/'`generated/_aint_r4.f90 + +_aint_r4.obj: generated/_aint_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _aint_r4.obj `if test -f 'generated/_aint_r4.f90'; then $(CYGPATH_W) 'generated/_aint_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_aint_r4.f90'; fi` + +_aint_r4.lo: generated/_aint_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _aint_r4.lo `test -f 'generated/_aint_r4.f90' || echo '$(srcdir)/'`generated/_aint_r4.f90 + +_aint_r8.o: generated/_aint_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _aint_r8.o `test -f 'generated/_aint_r8.f90' || echo '$(srcdir)/'`generated/_aint_r8.f90 + +_aint_r8.obj: generated/_aint_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _aint_r8.obj `if test -f 'generated/_aint_r8.f90'; then $(CYGPATH_W) 'generated/_aint_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_aint_r8.f90'; fi` + +_aint_r8.lo: generated/_aint_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _aint_r8.lo `test -f 'generated/_aint_r8.f90' || echo '$(srcdir)/'`generated/_aint_r8.f90 + +_anint_r4.o: generated/_anint_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _anint_r4.o `test -f 'generated/_anint_r4.f90' || echo '$(srcdir)/'`generated/_anint_r4.f90 + +_anint_r4.obj: generated/_anint_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _anint_r4.obj `if test -f 'generated/_anint_r4.f90'; then $(CYGPATH_W) 'generated/_anint_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_anint_r4.f90'; fi` + +_anint_r4.lo: generated/_anint_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _anint_r4.lo `test -f 'generated/_anint_r4.f90' || echo '$(srcdir)/'`generated/_anint_r4.f90 + +_anint_r8.o: generated/_anint_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _anint_r8.o `test -f 'generated/_anint_r8.f90' || echo '$(srcdir)/'`generated/_anint_r8.f90 + +_anint_r8.obj: generated/_anint_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _anint_r8.obj `if test -f 'generated/_anint_r8.f90'; then $(CYGPATH_W) 'generated/_anint_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_anint_r8.f90'; fi` + +_anint_r8.lo: generated/_anint_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _anint_r8.lo `test -f 'generated/_anint_r8.f90' || echo '$(srcdir)/'`generated/_anint_r8.f90 + +_sign_i4.o: generated/_sign_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_i4.o `test -f 'generated/_sign_i4.f90' || echo '$(srcdir)/'`generated/_sign_i4.f90 + +_sign_i4.obj: generated/_sign_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_i4.obj `if test -f 'generated/_sign_i4.f90'; then $(CYGPATH_W) 'generated/_sign_i4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sign_i4.f90'; fi` + +_sign_i4.lo: generated/_sign_i4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_i4.lo `test -f 'generated/_sign_i4.f90' || echo '$(srcdir)/'`generated/_sign_i4.f90 + +_sign_i8.o: generated/_sign_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_i8.o `test -f 'generated/_sign_i8.f90' || echo '$(srcdir)/'`generated/_sign_i8.f90 + +_sign_i8.obj: generated/_sign_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_i8.obj `if test -f 'generated/_sign_i8.f90'; then $(CYGPATH_W) 'generated/_sign_i8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sign_i8.f90'; fi` + +_sign_i8.lo: generated/_sign_i8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_i8.lo `test -f 'generated/_sign_i8.f90' || echo '$(srcdir)/'`generated/_sign_i8.f90 + +_sign_r4.o: generated/_sign_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_r4.o `test -f 'generated/_sign_r4.f90' || echo '$(srcdir)/'`generated/_sign_r4.f90 + +_sign_r4.obj: generated/_sign_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_r4.obj `if test -f 'generated/_sign_r4.f90'; then $(CYGPATH_W) 'generated/_sign_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sign_r4.f90'; fi` + +_sign_r4.lo: generated/_sign_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_r4.lo `test -f 'generated/_sign_r4.f90' || echo '$(srcdir)/'`generated/_sign_r4.f90 + +_sign_r8.o: generated/_sign_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_r8.o `test -f 'generated/_sign_r8.f90' || echo '$(srcdir)/'`generated/_sign_r8.f90 + +_sign_r8.obj: generated/_sign_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_r8.obj `if test -f 'generated/_sign_r8.f90'; then $(CYGPATH_W) 'generated/_sign_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_sign_r8.f90'; fi` + +_sign_r8.lo: generated/_sign_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _sign_r8.lo `test -f 'generated/_sign_r8.f90' || echo '$(srcdir)/'`generated/_sign_r8.f90 + +_dim_i4.o: generated/_dim_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_i4.o `test -f 'generated/_dim_i4.f90' || echo '$(srcdir)/'`generated/_dim_i4.f90 + +_dim_i4.obj: generated/_dim_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_i4.obj `if test -f 'generated/_dim_i4.f90'; then $(CYGPATH_W) 'generated/_dim_i4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_dim_i4.f90'; fi` + +_dim_i4.lo: generated/_dim_i4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_i4.lo `test -f 'generated/_dim_i4.f90' || echo '$(srcdir)/'`generated/_dim_i4.f90 + +_dim_i8.o: generated/_dim_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_i8.o `test -f 'generated/_dim_i8.f90' || echo '$(srcdir)/'`generated/_dim_i8.f90 + +_dim_i8.obj: generated/_dim_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_i8.obj `if test -f 'generated/_dim_i8.f90'; then $(CYGPATH_W) 'generated/_dim_i8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_dim_i8.f90'; fi` + +_dim_i8.lo: generated/_dim_i8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_i8.lo `test -f 'generated/_dim_i8.f90' || echo '$(srcdir)/'`generated/_dim_i8.f90 + +_dim_r4.o: generated/_dim_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_r4.o `test -f 'generated/_dim_r4.f90' || echo '$(srcdir)/'`generated/_dim_r4.f90 + +_dim_r4.obj: generated/_dim_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_r4.obj `if test -f 'generated/_dim_r4.f90'; then $(CYGPATH_W) 'generated/_dim_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_dim_r4.f90'; fi` + +_dim_r4.lo: generated/_dim_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_r4.lo `test -f 'generated/_dim_r4.f90' || echo '$(srcdir)/'`generated/_dim_r4.f90 + +_dim_r8.o: generated/_dim_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_r8.o `test -f 'generated/_dim_r8.f90' || echo '$(srcdir)/'`generated/_dim_r8.f90 + +_dim_r8.obj: generated/_dim_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_r8.obj `if test -f 'generated/_dim_r8.f90'; then $(CYGPATH_W) 'generated/_dim_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_dim_r8.f90'; fi` + +_dim_r8.lo: generated/_dim_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _dim_r8.lo `test -f 'generated/_dim_r8.f90' || echo '$(srcdir)/'`generated/_dim_r8.f90 + +_atan2_r4.o: generated/_atan2_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan2_r4.o `test -f 'generated/_atan2_r4.f90' || echo '$(srcdir)/'`generated/_atan2_r4.f90 + +_atan2_r4.obj: generated/_atan2_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan2_r4.obj `if test -f 'generated/_atan2_r4.f90'; then $(CYGPATH_W) 'generated/_atan2_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_atan2_r4.f90'; fi` + +_atan2_r4.lo: generated/_atan2_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan2_r4.lo `test -f 'generated/_atan2_r4.f90' || echo '$(srcdir)/'`generated/_atan2_r4.f90 + +_atan2_r8.o: generated/_atan2_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan2_r8.o `test -f 'generated/_atan2_r8.f90' || echo '$(srcdir)/'`generated/_atan2_r8.f90 + +_atan2_r8.obj: generated/_atan2_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan2_r8.obj `if test -f 'generated/_atan2_r8.f90'; then $(CYGPATH_W) 'generated/_atan2_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_atan2_r8.f90'; fi` + +_atan2_r8.lo: generated/_atan2_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _atan2_r8.lo `test -f 'generated/_atan2_r8.f90' || echo '$(srcdir)/'`generated/_atan2_r8.f90 + +_mod_i4.o: generated/_mod_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_i4.o `test -f 'generated/_mod_i4.f90' || echo '$(srcdir)/'`generated/_mod_i4.f90 + +_mod_i4.obj: generated/_mod_i4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_i4.obj `if test -f 'generated/_mod_i4.f90'; then $(CYGPATH_W) 'generated/_mod_i4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_mod_i4.f90'; fi` + +_mod_i4.lo: generated/_mod_i4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_i4.lo `test -f 'generated/_mod_i4.f90' || echo '$(srcdir)/'`generated/_mod_i4.f90 + +_mod_i8.o: generated/_mod_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_i8.o `test -f 'generated/_mod_i8.f90' || echo '$(srcdir)/'`generated/_mod_i8.f90 + +_mod_i8.obj: generated/_mod_i8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_i8.obj `if test -f 'generated/_mod_i8.f90'; then $(CYGPATH_W) 'generated/_mod_i8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_mod_i8.f90'; fi` + +_mod_i8.lo: generated/_mod_i8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_i8.lo `test -f 'generated/_mod_i8.f90' || echo '$(srcdir)/'`generated/_mod_i8.f90 + +_mod_r4.o: generated/_mod_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_r4.o `test -f 'generated/_mod_r4.f90' || echo '$(srcdir)/'`generated/_mod_r4.f90 + +_mod_r4.obj: generated/_mod_r4.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_r4.obj `if test -f 'generated/_mod_r4.f90'; then $(CYGPATH_W) 'generated/_mod_r4.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_mod_r4.f90'; fi` + +_mod_r4.lo: generated/_mod_r4.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_r4.lo `test -f 'generated/_mod_r4.f90' || echo '$(srcdir)/'`generated/_mod_r4.f90 + +_mod_r8.o: generated/_mod_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_r8.o `test -f 'generated/_mod_r8.f90' || echo '$(srcdir)/'`generated/_mod_r8.f90 + +_mod_r8.obj: generated/_mod_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_r8.obj `if test -f 'generated/_mod_r8.f90'; then $(CYGPATH_W) 'generated/_mod_r8.f90'; else $(CYGPATH_W) '$(srcdir)/generated/_mod_r8.f90'; fi` + +_mod_r8.lo: generated/_mod_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o _mod_r8.lo `test -f 'generated/_mod_r8.f90' || echo '$(srcdir)/'`generated/_mod_r8.f90 + +dprod_r8.o: intrinsics/dprod_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o dprod_r8.o `test -f 'intrinsics/dprod_r8.f90' || echo '$(srcdir)/'`intrinsics/dprod_r8.f90 + +dprod_r8.obj: intrinsics/dprod_r8.f90 + $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o dprod_r8.obj `if test -f 'intrinsics/dprod_r8.f90'; then $(CYGPATH_W) 'intrinsics/dprod_r8.f90'; else $(CYGPATH_W) '$(srcdir)/intrinsics/dprod_r8.f90'; fi` + +dprod_r8.lo: intrinsics/dprod_r8.f90 + $(LIBTOOL) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS) -c -o dprod_r8.lo `test -f 'intrinsics/dprod_r8.f90' || echo '$(srcdir)/'`intrinsics/dprod_r8.f90 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/.. $(distdir)/m4 + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + $(AMTAR) chof - $(distdir) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + $(AMTAR) chof - $(distdir) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(AMTAR) xf - ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(AMTAR) xf - ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && $(mkdir_p) "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) config.h +installdirs: + $(mkdir_p) $(DESTDIR)$(libdir) +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool ctags dist \ + dist-all dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip \ + distcheck distclean distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libLTLIBRARIES + + +@MAINTAINER_MODE_TRUE@$(i_all_c): m4/all.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 all.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_any_c): m4/any.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 any.m4> $@ + +@MAINTAINER_MODE_TRUE@$(i_count_c): m4/count.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 count.m4> $@ + +@MAINTAINER_MODE_TRUE@$(i_maxloc0_c): m4/maxloc0.m4 $(I_M4_DEPS0) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 maxloc0.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_maxloc1_c): m4/maxloc1.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 maxloc1.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_maxval_c): m4/maxval.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 maxval.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_minloc0_c): m4/minloc0.m4 $(I_M4_DEPS0) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 minloc0.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_minloc1_c): m4/minloc1.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 minloc1.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_minval_c): m4/minval.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 minval.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_product_c): m4/product.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 product.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_sum_c): m4/sum.m4 $(I_M4_DEPS1) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 sum.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_dotprod_c): m4/dotprod.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 dotprod.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_dotprodl_c): m4/dotprodl.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 dotprodl.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_dotprodc_c): m4/dotprodc.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 dotprodc.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_matmul_c): m4/matmul.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 matmul.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_matmull_c): m4/matmull.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 matmull.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_transpose_c): m4/transpose.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 transpose.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_shape_c): m4/shape.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 shape.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_reshape_c): m4/reshape.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 reshape.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_eoshift1_c): m4/eoshift1.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 eoshift1.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_eoshift3_c): m4/eoshift3.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 eoshift3.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_cshift1_c): m4/cshift1.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 cshift1.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(in_pack_c): m4/in_pack.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 in_pack.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(in_unpack_c): m4/in_unpack.m4 $(I_M4_DEPS) +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 in_unpack.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_exponent_c): m4/exponent.m4 m4/mtype.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 exponent.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_fraction_c): m4/fraction.m4 m4/mtype.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 fraction.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_nearest_c): m4/nearest.m4 m4/mtype.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 nearest.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(i_set_exponent_c): m4/set_exponent.m4 m4/mtype.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 set_exponent.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(gfor_math_trig_c): m4/ctrig.m4 m4/mtype.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 ctrig.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(gfor_math_exp_c): m4/cexp.m4 m4/mtype.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 cexp.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(gfor_math_hyp_c): m4/chyp.m4 m4/mtype.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 chyp.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(gfor_built_specific_src): m4/specific.m4 m4/head.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 specific.m4 > $@ + +@MAINTAINER_MODE_TRUE@$(gfor_built_specific2_src): m4/specific2.m4 m4/head.m4 +@MAINTAINER_MODE_TRUE@ m4 -Dfile=$@ -I$(srcdir)/m4 specific2.m4 > $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libgfortran/NEWS b/libgfortran/NEWS new file mode 100644 index 00000000000..96c59e5d663 --- /dev/null +++ b/libgfortran/NEWS @@ -0,0 +1 @@ +No Gnus is good Gnus diff --git a/libgfortran/README b/libgfortran/README new file mode 100644 index 00000000000..1a5de1d0436 --- /dev/null +++ b/libgfortran/README @@ -0,0 +1,14 @@ +This is the GNU Fortran 95 Runtime library (libgfortran). +It is intended to be compiled as part of GCC. + +Programs must be linked with "-lgfortran -lm". The 'gfortran' driver does this +automatically. + +You'll need to apply gcc_config.patch to your top level GCC source directory. +This tells the the GCC configure system about libgfor. This patch can confuse +patch as it contains a filename with a '-' in it. use "patch -p1" to avoid this +problem. + +For more information about GNU Fortran 95, see http://gcc-g95.sourceforge.net + +Paul Brook diff --git a/libgfortran/acinclude.m4 b/libgfortran/acinclude.m4 new file mode 100644 index 00000000000..8e6b1bc79b4 --- /dev/null +++ b/libgfortran/acinclude.m4 @@ -0,0 +1,85 @@ +dnl Check: +dnl * If we have gettimeofday; +dnl * If we have struct timezone for use in calling it; +dnl * If calling it with a timezone pointer actually works -- this is deemed +dnl obsolete or undefined on some systems which say you should use a null +dnl pointer -- and undefine HAVE_TIMEZONE if so; +dnl * Whether it only takes one arg. +AC_DEFUN([LIBGFOR_GETTIMEOFDAY], [ + AC_CHECK_FUNCS(gettimeofday) + if test "$ac_cv_func_gettimeofday" = yes; then + AC_CACHE_CHECK([for struct timezone], gfor_cv_struct_timezone, + [AC_TRY_COMPILE([#include ], + [struct timezone tz;], + gfor_cv_struct_timezone=yes, gfor_cv_struct_timezone=no)]) + if test $gfor_cv_struct_timezone = yes; then + dnl It may be that we can't call gettimeofday with a non-null pointer. + dnl In that case we'll lie about struct timezone. + AC_TRY_RUN([ +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif +main () +{ + struct timeval time; + struct timezone dummy; + if (gettimeofday (&time, &dummy)) + exit (1); + else + exit (0); +}], + [gfor_have_struct_timezone=yes], [gfor_have_struct_timezone=no], + [gfor_have_struct_timezone=yes]) + if test $gfor_have_struct_timezone = yes; then + AC_DEFINE(HAVE_TIMEZONE, 1, [Do we have struct timezone]) + fi + fi + AC_REQUIRE([AC_HEADER_TIME]) + AC_CACHE_CHECK(whether gettimeofday can accept two arguments, + emacs_cv_gettimeofday_two_arguments, + AC_TRY_LINK([ +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + ], + [ + struct timeval time; +#ifdef HAVE_TIMEZONE + struct timezone dummy; +#define DUMMY &dummy +#else +#define DUMMY NULL +#endif + gettimeofday (&time, DUMMY);], + emacs_cv_gettimeofday_two_arguments=yes, + emacs_cv_gettimeofday_two_arguments=no)) + if test $emacs_cv_gettimeofday_two_arguments = no; then + AC_DEFINE(GETTIMEOFDAY_ONE_ARGUMENT, 1, + [Does gettimeofday take a single argument]) + fi + fi]) + +sinclude(../libtool.m4) +dnl The lines below arrange for aclocal not to bring an installed +dnl libtool.m4 into aclocal.m4, while still arranging for automake to +dnl add a definition of LIBTOOL to Makefile.in. +ifelse(,,,[AC_SUBST(LIBTOOL) +AC_DEFUN([AM_PROG_LIBTOOL]) +AC_DEFUN([AC_LIBTOOL_DLOPEN]) +AC_DEFUN([AC_PROG_LD]) +]) + diff --git a/libgfortran/aclocal.m4 b/libgfortran/aclocal.m4 new file mode 100644 index 00000000000..45216f1a196 --- /dev/null +++ b/libgfortran/aclocal.m4 @@ -0,0 +1,958 @@ +# generated automatically by aclocal 1.8.2 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# -*- Autoconf -*- +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. +# Generated from amversion.in; do not edit by hand. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.8"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.8.2])]) + +# AM_AUX_DIR_EXPAND + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 6 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]) +fi])]) + +# serial 6 -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + : > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # (even with -Werror). So we grep stderr for any message + # that says an option was ignored. + if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +#serial 2 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + grep '^DEP_FILES *= *[[^ @%:@]]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 7 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# This macro actually does too much some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 11 + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_MISSING_PROG(AMTAR, tar) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl + +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# -*- Autoconf -*- +# Copyright (C) 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 1 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004 +# Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +AC_DEFUN([AM_MAINTAINER_MODE], +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# -*- Autoconf -*- + + +# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. + +# Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p -- . 2>/dev/null; then + # Keeping the `.' argument allows $(mkdir_p) to be used without + # argument. Indeed, we sometimes output rules like + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. + # (`test -n '$(somedir)' && $(mkdir_p) $(somedir)' is a more + # expensive solution, as it forces Make to start a sub-shell.) + mkdir_p='mkdir -p -- .' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 2 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# +# Check to make sure that the build environment is sane. +# + +# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# serial 3 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# AM_PROG_INSTALL_STRIP + +# Copyright (C) 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +m4_include([acinclude.m4]) diff --git a/libgfortran/config.h.in b/libgfortran/config.h.in new file mode 100644 index 00000000000..1c686978abf --- /dev/null +++ b/libgfortran/config.h.in @@ -0,0 +1,106 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Does gettimeofday take a single argument */ +#undef GETTIMEOFDAY_ONE_ARGUMENT + +/* complex.h exists */ +#undef HAVE_COMPLEX_H + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MATH_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAMS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the `times' function. */ +#undef HAVE_TIMES + +/* Do we have struct timezone */ +#undef HAVE_TIMEZONE + +/* Define to 1 if you have the header file. */ +#undef HAVE_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define to `long' if does not define. */ +#undef off_t diff --git a/libgfortran/configure b/libgfortran/configure new file mode 100755 index 00000000000..099ab80a610 --- /dev/null +++ b/libgfortran/configure @@ -0,0 +1,8133 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for GNU Fortran Runtime Library 0.2. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='GNU Fortran Runtime Library' +PACKAGE_TARNAME='libgfortran' +PACKAGE_VERSION='0.2' +PACKAGE_STRING='GNU Fortran Runtime Library 0.2' +PACKAGE_BUGREPORT='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT enable_shared enable_static CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE F77 FFLAGS ac_ct_F77 CPP EGREP MATH_OBJ AR RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os LN_S LIBTOOL LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_F77_set=${F77+set} +ac_env_F77_value=$F77 +ac_cv_env_F77_set=${F77+set} +ac_cv_env_F77_value=$F77 +ac_env_FFLAGS_set=${FFLAGS+set} +ac_env_FFLAGS_value=$FFLAGS +ac_cv_env_FFLAGS_set=${FFLAGS+set} +ac_cv_env_FFLAGS_value=$FFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures GNU Fortran Runtime Library 0.2 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of GNU Fortran Runtime Library 0.2:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-cmath Include complex math functions + --enable-shared=PKGS build shared libraries default=yes + --enable-static=PKGS build static libraries default=yes + --enable-fast-install=PKGS optimize for fast installation default=yes + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld default=no + --with-pic try to use only PIC/non-PIC objects default=use both + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + F77 Fortran 77 compiler command + FFLAGS Fortran 77 compiler flags + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd "$ac_popdir" + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +GNU Fortran Runtime Library configure 0.2 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by GNU Fortran Runtime Library $as_me 0.2, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + +am__api_version="1.8" +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p -- . 2>/dev/null; then + # Keeping the `.' argument allows $(mkdir_p) to be used without + # argument. Indeed, we sometimes output rules like + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. + # (`test -n '$(somedir)' && $(mkdir_p) $(somedir)' is a more + # expensive solution, as it forces Make to start a sub-shell.) + mkdir_p='mkdir -p -- .' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='libgfortran' + VERSION='0.2' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. + + + + ac_config_headers="$ac_config_headers config.h" + +echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi; + echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 +echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6 + + +if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + + + + +# check for compiler +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + : > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # (even with -Werror). So we grep stderr for any message + # that says an option was ignored. + if grep 'ignoring option' conftest.err >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +if test "x$GCC" = "xyes"; then + CFLAGS="$CFLAGS -Wall" +fi + +# We need gfortran to compile parts of the library +# We can't use AC_PROG_F77 because it expects a fully working gfortran. +#AC_PROG_F77(gfortran) +F77="$GFORTRAN" +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in gfortran + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$F77"; then + ac_cv_prog_F77="$F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_F77="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +F77=$ac_cv_prog_F77 +if test -n "$F77"; then + echo "$as_me:$LINENO: result: $F77" >&5 +echo "${ECHO_T}$F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$F77" && break + done +fi +if test -z "$F77"; then + ac_ct_F77=$F77 + for ac_prog in gfortran +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_F77"; then + ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_F77="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_F77=$ac_cv_prog_ac_ct_F77 +if test -n "$ac_ct_F77"; then + echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 +echo "${ECHO_T}$ac_ct_F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_F77" && break +done + + F77=$ac_ct_F77 +fi + + +# Provide some information about the compiler. +echo "$as_me:2983:" \ + "checking for Fortran 77 compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +rm -f a.out + +# If we don't use `.F' as extension, the preprocessor is not run on the +# input file. (Note that this only needs to work for GNU compilers.) +ac_save_ext=$ac_ext +ac_ext=F +echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6 +if test "${ac_cv_f77_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF + program main +#ifndef __GNUC__ + choke me +#endif + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_f77_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6 +ac_ext=$ac_save_ext +ac_test_FFLAGS=${FFLAGS+set} +ac_save_FFLAGS=$FFLAGS +FFLAGS= +echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 +echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_f77_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + FFLAGS=-g +cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_f77_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_f77_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 +echo "${ECHO_T}$ac_cv_prog_f77_g" >&6 +if test "$ac_test_FFLAGS" = set; then + FFLAGS=$ac_save_FFLAGS +elif test $ac_cv_prog_f77_g = yes; then + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-g -O2" + else + FFLAGS="-g" + fi +else + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-O2" + else + FFLAGS= + fi +fi + +G77=`test $ac_compiler_gnu = yes && echo yes` +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +FFLAGS="$FFLAGS -Wall -fno-repack-arrays -fno-underscoring" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + +for ac_header in stdlib.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------------------ ## +## Report this to the GNU Fortran Runtime Library lists. ## +## ------------------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_func in getpagesize +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +echo "$as_me:$LINENO: checking for working mmap" >&5 +echo $ECHO_N "checking for working mmap... $ECHO_C" >&6 +if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_mmap_fixed_mapped=no +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +/* malloc might have been renamed as rpl_malloc. */ +#undef malloc + +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the file system buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propagated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ + +#include +#include + +#if !STDC_HEADERS && !HAVE_STDLIB_H +char *malloc (); +#endif + +/* This mess was copied from the GNU getpagesize.h. */ +#if !HAVE_GETPAGESIZE +/* Assume that all systems that can run configure have sys/param.h. */ +# if !HAVE_SYS_PARAM_H +# define HAVE_SYS_PARAM_H 1 +# endif + +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# if HAVE_SYS_PARAM_H +# include +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +int +main () +{ + char *data, *data2, *data3; + int i, pagesize; + int fd; + + pagesize = getpagesize (); + + /* First, make a file with some known garbage in it. */ + data = (char *) malloc (pagesize); + if (!data) + exit (1); + for (i = 0; i < pagesize; ++i) + *(data + i) = rand (); + umask (0); + fd = creat ("conftest.mmap", 0600); + if (fd < 0) + exit (1); + if (write (fd, data, pagesize) != pagesize) + exit (1); + close (fd); + + /* Next, try to mmap the file at a fixed address which already has + something else allocated at it. If we can, also make sure that + we see the same garbage. */ + fd = open ("conftest.mmap", O_RDWR); + if (fd < 0) + exit (1); + data2 = (char *) malloc (2 * pagesize); + if (!data2) + exit (1); + data2 += (pagesize - ((long) data2 & (pagesize - 1))) & (pagesize - 1); + if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + exit (1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + exit (1); + + /* Finally, make sure that changes to the mapped area do not + percolate back to the file as seen by read(). (This is a bug on + some variants of i386 svr4.0.) */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = (char *) malloc (pagesize); + if (!data3) + exit (1); + if (read (fd, data3, pagesize) != pagesize) + exit (1); + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + exit (1); + close (fd); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_mmap_fixed_mapped=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_mmap_fixed_mapped=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mmap_fixed_mapped" >&5 +echo "${ECHO_T}$ac_cv_func_mmap_fixed_mapped" >&6 +if test $ac_cv_func_mmap_fixed_mapped = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MMAP 1 +_ACEOF + +fi +rm -f conftest.mmap + +echo "$as_me:$LINENO: checking for off_t" >&5 +echo $ECHO_N "checking for off_t... $ECHO_C" >&6 +if test "${ac_cv_type_off_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((off_t *) 0) + return 0; +if (sizeof (off_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_off_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_off_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 +echo "${ECHO_T}$ac_cv_type_off_t" >&6 +if test $ac_cv_type_off_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define off_t long +_ACEOF + +fi + + +# Check for install +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +# check header files +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + + + + + + +for ac_header in stdlib.h stdio.h string.h stddef.h math.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------------------ ## +## Report this to the GNU Fortran Runtime Library lists. ## +## ------------------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + +for ac_header in time.h sys/params.h sys/time.h sys/times.h sys/resource.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------------------ ## +## Report this to the GNU Fortran Runtime Library lists. ## +## ------------------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +if test "${ac_cv_header_complex_h+set}" = set; then + echo "$as_me:$LINENO: checking for complex.h" >&5 +echo $ECHO_N "checking for complex.h... $ECHO_C" >&6 +if test "${ac_cv_header_complex_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_complex_h" >&5 +echo "${ECHO_T}$ac_cv_header_complex_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking complex.h usability" >&5 +echo $ECHO_N "checking complex.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking complex.h presence" >&5 +echo $ECHO_N "checking complex.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: complex.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: complex.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: complex.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: complex.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: complex.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: complex.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: complex.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: complex.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: complex.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: complex.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: complex.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: complex.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: complex.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: complex.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: complex.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: complex.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------------------ ## +## Report this to the GNU Fortran Runtime Library lists. ## +## ------------------------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for complex.h" >&5 +echo $ECHO_N "checking for complex.h... $ECHO_C" >&6 +if test "${ac_cv_header_complex_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_complex_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_complex_h" >&5 +echo "${ECHO_T}$ac_cv_header_complex_h" >&6 + +fi +if test $ac_cv_header_complex_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_COMPLEX_H 1 +_ACEOF + +fi + + +# Check for complex math functions +echo "$as_me:$LINENO: checking for csin in -lm" >&5 +echo $ECHO_N "checking for csin in -lm... $ECHO_C" >&6 +if test "${ac_cv_lib_m_csin+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char csin (); +int +main () +{ +csin (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_m_csin=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_m_csin=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_m_csin" >&5 +echo "${ECHO_T}$ac_cv_lib_m_csin" >&6 +if test $ac_cv_lib_m_csin = yes; then + need_math="no" +else + need_math="yes" +fi + + +# Check for complex math functions in -lmx also +echo "$as_me:$LINENO: checking for csin in -lmx" >&5 +echo $ECHO_N "checking for csin in -lmx... $ECHO_C" >&6 +if test "${ac_cv_lib_mx_csin+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmx $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char csin (); +int +main () +{ +csin (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_mx_csin=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_mx_csin=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_mx_csin" >&5 +echo "${ECHO_T}$ac_cv_lib_mx_csin" >&6 +if test $ac_cv_lib_mx_csin = yes; then + need_math="no" +else + need_math="yes" +fi + + + + +for ac_func in getrusage times +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# Let the user override this +# Check whether --enable-cmath or --disable-cmath was given. +if test "${enable_cmath+set}" = set; then + enableval="$enable_cmath" + need_math=$enableval +fi; +if test "$need_math" = "yes"; then + { echo "$as_me:$LINENO: Including complex math functions in libgfor" >&5 +echo "$as_me: Including complex math functions in libgfor" >&6;}; + extra_math_obj='$(gfor_cmath_obj)' +fi + +MATH_OBJ="$extra_math_obj" + + +echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 +echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6 +if test "${ac_cv_header_time+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_time=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_time=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 +echo "${ECHO_T}$ac_cv_header_time" >&6 +if test $ac_cv_header_time = yes; then + +cat >>confdefs.h <<\_ACEOF +#define TIME_WITH_SYS_TIME 1 +_ACEOF + +fi + + + +for ac_func in gettimeofday +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + if test "$ac_cv_func_gettimeofday" = yes; then + echo "$as_me:$LINENO: checking for struct timezone" >&5 +echo $ECHO_N "checking for struct timezone... $ECHO_C" >&6 +if test "${gfor_cv_struct_timezone+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +struct timezone tz; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + gfor_cv_struct_timezone=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +gfor_cv_struct_timezone=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $gfor_cv_struct_timezone" >&5 +echo "${ECHO_T}$gfor_cv_struct_timezone" >&6 + if test $gfor_cv_struct_timezone = yes; then + if test "$cross_compiling" = yes; then + gfor_have_struct_timezone=yes +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif +main () +{ + struct timeval time; + struct timezone dummy; + if (gettimeofday (&time, &dummy)) + exit (1); + else + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + gfor_have_struct_timezone=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +gfor_have_struct_timezone=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + if test $gfor_have_struct_timezone = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_TIMEZONE 1 +_ACEOF + + fi + fi + + echo "$as_me:$LINENO: checking whether gettimeofday can accept two arguments" >&5 +echo $ECHO_N "checking whether gettimeofday can accept two arguments... $ECHO_C" >&6 +if test "${emacs_cv_gettimeofday_two_arguments+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +int +main () +{ + + struct timeval time; +#ifdef HAVE_TIMEZONE + struct timezone dummy; +#define DUMMY &dummy +#else +#define DUMMY NULL +#endif + gettimeofday (&time, DUMMY); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + emacs_cv_gettimeofday_two_arguments=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +emacs_cv_gettimeofday_two_arguments=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $emacs_cv_gettimeofday_two_arguments" >&5 +echo "${ECHO_T}$emacs_cv_gettimeofday_two_arguments" >&6 + if test $emacs_cv_gettimeofday_two_arguments = no; then + +cat >>confdefs.h <<\_ACEOF +#define GETTIMEOFDAY_ONE_ARGUMENT 1 +_ACEOF + + fi + fi + +test "$AR" || AR=ar + +if test "$RANLIB"; then : + +else + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +fi + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_shared=yes +fi; +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_static=yes +fi; +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_fast_install=yes +fi; +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by GCC" >&5 +echo $ECHO_N "checking for ld used by GCC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + echo "$as_me:$LINENO: result: $LD" >&5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + +echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi + +NM="$lt_cv_path_NM" +echo "$as_me:$LINENO: result: $NM" >&5 +echo "${ECHO_T}$NM" >&6 + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:$LINENO: checking how to recognise dependant libraries" >&5 +echo $ECHO_N "checking how to recognise dependant libraries... $ECHO_C" >&6 +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [regex]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* |pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + # this will be overwritten by pass_all, but leave it in just in case + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.012) + lt_cv_file_magic_test_file='/System/Library/Frameworks/System.framework/System' + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* ) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + case $host_cpu in + hppa*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + esac + ;; + +irix5* | irix6*) + case $host_os in + irix5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + case $host_cpu in + alpha* | mips* | hppa* | i*86 | powerpc* | sparc* | ia64* ) + lt_cv_deplibs_check_method=pass_all ;; + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$' + fi + ;; + +newsos6) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv5uw[78]* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + esac + ;; +esac + +fi +echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method + + + + +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + + +# Check for any special flags to pass to ltconfig. +libtool_flags="--cache-file=$cache_file" +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$GCC" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$lt_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi; +test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic" +test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 6309 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case "`/usr/bin/file conftest.o`" in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +lt_cv_cc_needs_belf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + + +esac + + +# Save cache, so that ltconfig can load it +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +AR="$AR" LTCC="$CC" CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \ +|| { { echo "$as_me:$LINENO: error: libtool configure failed" >&5 +echo "$as_me: error: libtool configure failed" >&2;} + { (exit 1); exit 1; }; } + +# Reload cache, that may have been modified by ltconfig +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh $ac_aux_dir/ltcf-c.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log + + + + + + + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + + ac_config_files="$ac_config_files Makefile" +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by GNU Fortran Runtime Library $as_me 0.2, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +GNU Fortran Runtime Library config.status 0.2 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CYGPATH_W@,$CYGPATH_W,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@AMTAR@,$AMTAR,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@mkdir_p@,$mkdir_p,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;t t +s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t +s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t +s,@MAINT@,$MAINT,;t t +s,@enable_shared@,$enable_shared,;t t +s,@enable_static@,$enable_static,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t +s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@F77@,$F77,;t t +s,@FFLAGS@,$FFLAGS,;t t +s,@ac_ct_F77@,$ac_ct_F77,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@MATH_OBJ@,$MATH_OBJ,;t t +s,@AR@,$AR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@LN_S@,$LN_S,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null || +$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X$ac_file : 'X\(//\)[^/]' \| \ + X$ac_file : 'X\(//\)$' \| \ + X$ac_file : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X$ac_file | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'`/stamp-h$_am_stamp_count +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + grep '^DEP_FILES *= *[^ #]' < "$mf" > /dev/null || continue + # Extract the definition of DEP_FILES from the Makefile without + # running `make'. + DEPDIR=`sed -n -e '/^DEPDIR = / s///p' < "$mf"` + test -z "$DEPDIR" && continue + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n -e '/^U = / s///p' < "$mf"` + test -d "$dirpart/$DEPDIR" || mkdir "$dirpart/$DEPDIR" + # We invoke sed twice because it is the simplest approach to + # changing $(DEPDIR) to its actual value in the expansion. + for file in `sed -n -e ' + /^DEP_FILES = .*\\\\$/ { + s/^DEP_FILES = // + :loop + s/\\\\$// + p + n + /\\\\$/ b loop + p + } + /^DEP_FILES = / s/^DEP_FILES = //p' < "$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + + diff --git a/libgfortran/configure.in b/libgfortran/configure.in new file mode 100644 index 00000000000..63e5cf8b5e4 --- /dev/null +++ b/libgfortran/configure.in @@ -0,0 +1,88 @@ +dnl configure.in for libgfor +dnl Copyright Free Software Foundation +dnl Released under the LGPL + +dnl The rest of gcc uses autoconf 2.13, but we really need more, hence: +AC_PREREQ(2.54) + +AC_INIT([GNU Fortran Runtime Library], 0.2,,[libgfortran]) +AM_INIT_AUTOMAKE() +AM_CONFIG_HEADER(config.h) +AM_MAINTAINER_MODE + +AC_SUBST(enable_shared) +AC_SUBST(enable_static) + +# check for compiler +AC_PROG_CC +dnl Add -Wall if using gcc +if test "x$GCC" = "xyes"; then + CFLAGS="$CFLAGS -Wall" +fi + +# We need gfortran to compile parts of the library +# We can't use AC_PROG_F77 because it expects a fully working gfortran. +#AC_PROG_F77(gfortran) +F77="$GFORTRAN" +AC_PROG_F77(gfortran) +FFLAGS="$FFLAGS -Wall -fno-repack-arrays -fno-underscoring" + +AC_FUNC_MMAP +AC_TYPE_OFF_T + +# Check for install +AC_PROG_INSTALL + +# check header files +AC_STDC_HEADERS +AC_HAVE_HEADERS(stdlib.h stdio.h string.h stddef.h math.h unistd.h) +AC_CHECK_HEADERS(time.h sys/params.h sys/time.h sys/times.h sys/resource.h) +AC_CHECK_HEADER([complex.h],[AC_DEFINE([HAVE_COMPLEX_H], [1], [complex.h exists])]) +# Check for complex math functions +AC_CHECK_LIB([m],[csin],[need_math="no"],[need_math="yes"]) + +# Check for complex math functions in -lmx also +AC_CHECK_LIB([mx],[csin],[need_math="no"],[need_math="yes"]) + +dnl Checks for library functions. +AC_CHECK_FUNCS(getrusage times) + +# Let the user override this +AC_ARG_ENABLE(cmath, + AC_HELP_STRING([--enable-cmath],[Include complex math functions]), + [need_math=$enableval]) +if test "$need_math" = "yes"; then + AC_MSG_NOTICE([Including complex math functions in libgfor]); + extra_math_obj='$(gfor_cmath_obj)' +fi + +AC_SUBST([MATH_OBJ],["$extra_math_obj"]) + +dnl The standard autoconf HAVE_STRUCT_TIMEZONE doesn't actually check +dnl for struct timezone, as you might think. We also need to check how +dnl to call gettimeofday if we have it. +LIBGFOR_GETTIMEOFDAY + +dnl These should be inherited in the recursive make, but ensure they are +dnl defined: +test "$AR" || AR=ar +AC_SUBST(AR) +if test "$RANLIB"; then : + AC_SUBST(RANLIB) +else + AC_PROG_RANLIB +fi + +dnl Don't pull is system libtool.m4, it conflicts with the gcc version. +dnl if test "$LIBTOOL"; then : +dnl AC_SUBST(LIBTOOL) +dnl else +dnl AC_PROG_LIBTOOL +dnl fi +AM_PROG_LIBTOOL + +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +AC_OUTPUT(Makefile) + diff --git a/libgfortran/fmain.c b/libgfortran/fmain.c new file mode 100644 index 00000000000..ec621256df1 --- /dev/null +++ b/libgfortran/fmain.c @@ -0,0 +1,22 @@ +#include "config.h" +#include "libgfortran.h" + +/* The main Fortran program actually is a function, called MAIN__. + We call it from the main() function in this file. */ +void MAIN__ (void); + +/* Main procedure for fortran programs. All we do is set up the environment + for the Fortran program. */ +int +main (int argc, char *argv[]) +{ + /* Set up the runtime environment. */ + set_args (argc, argv); + + /* Call the Fortran main program. Internally this is a function + called MAIN__ */ + MAIN__ (); + + /* Bye-bye! */ + return 0; +} diff --git a/libgfortran/generated/_abs_c4.f90 b/libgfortran/generated/_abs_c4.f90 new file mode 100644 index 00000000000..ed5e3c15693 --- /dev/null +++ b/libgfortran/generated/_abs_c4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__abs_c4 (parm) + complex (kind=4), intent (in) :: parm + complex (kind=4) :: specific__abs_c4 + + specific__abs_c4 = abs (parm) +end function diff --git a/libgfortran/generated/_abs_c8.f90 b/libgfortran/generated/_abs_c8.f90 new file mode 100644 index 00000000000..714064cd8a1 --- /dev/null +++ b/libgfortran/generated/_abs_c8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__abs_c8 (parm) + complex (kind=8), intent (in) :: parm + complex (kind=8) :: specific__abs_c8 + + specific__abs_c8 = abs (parm) +end function diff --git a/libgfortran/generated/_abs_i4.f90 b/libgfortran/generated/_abs_i4.f90 new file mode 100644 index 00000000000..146ec072bd8 --- /dev/null +++ b/libgfortran/generated/_abs_i4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__abs_i4 (parm) + integer (kind=4), intent (in) :: parm + integer (kind=4) :: specific__abs_i4 + + specific__abs_i4 = abs (parm) +end function diff --git a/libgfortran/generated/_abs_i8.f90 b/libgfortran/generated/_abs_i8.f90 new file mode 100644 index 00000000000..033ec30e94c --- /dev/null +++ b/libgfortran/generated/_abs_i8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__abs_i8 (parm) + integer (kind=8), intent (in) :: parm + integer (kind=8) :: specific__abs_i8 + + specific__abs_i8 = abs (parm) +end function diff --git a/libgfortran/generated/_abs_r4.f90 b/libgfortran/generated/_abs_r4.f90 new file mode 100644 index 00000000000..18f3f6b2ccf --- /dev/null +++ b/libgfortran/generated/_abs_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__abs_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__abs_r4 + + specific__abs_r4 = abs (parm) +end function diff --git a/libgfortran/generated/_abs_r8.f90 b/libgfortran/generated/_abs_r8.f90 new file mode 100644 index 00000000000..3dc1c8b3e84 --- /dev/null +++ b/libgfortran/generated/_abs_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__abs_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__abs_r8 + + specific__abs_r8 = abs (parm) +end function diff --git a/libgfortran/generated/_acos_r4.f90 b/libgfortran/generated/_acos_r4.f90 new file mode 100644 index 00000000000..2f49b3093c2 --- /dev/null +++ b/libgfortran/generated/_acos_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__acos_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__acos_r4 + + specific__acos_r4 = acos (parm) +end function diff --git a/libgfortran/generated/_acos_r8.f90 b/libgfortran/generated/_acos_r8.f90 new file mode 100644 index 00000000000..d285c4566d6 --- /dev/null +++ b/libgfortran/generated/_acos_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__acos_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__acos_r8 + + specific__acos_r8 = acos (parm) +end function diff --git a/libgfortran/generated/_aint_r4.f90 b/libgfortran/generated/_aint_r4.f90 new file mode 100644 index 00000000000..5c2b641707b --- /dev/null +++ b/libgfortran/generated/_aint_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__aint_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__aint_r4 + + specific__aint_r4 = aint (parm) +end function diff --git a/libgfortran/generated/_aint_r8.f90 b/libgfortran/generated/_aint_r8.f90 new file mode 100644 index 00000000000..65c675458c3 --- /dev/null +++ b/libgfortran/generated/_aint_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__aint_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__aint_r8 + + specific__aint_r8 = aint (parm) +end function diff --git a/libgfortran/generated/_anint_r4.f90 b/libgfortran/generated/_anint_r4.f90 new file mode 100644 index 00000000000..9056f0077d9 --- /dev/null +++ b/libgfortran/generated/_anint_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__anint_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__anint_r4 + + specific__anint_r4 = anint (parm) +end function diff --git a/libgfortran/generated/_anint_r8.f90 b/libgfortran/generated/_anint_r8.f90 new file mode 100644 index 00000000000..46d87e07934 --- /dev/null +++ b/libgfortran/generated/_anint_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__anint_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__anint_r8 + + specific__anint_r8 = anint (parm) +end function diff --git a/libgfortran/generated/_asin_r4.f90 b/libgfortran/generated/_asin_r4.f90 new file mode 100644 index 00000000000..bf4dfa48304 --- /dev/null +++ b/libgfortran/generated/_asin_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__asin_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__asin_r4 + + specific__asin_r4 = asin (parm) +end function diff --git a/libgfortran/generated/_asin_r8.f90 b/libgfortran/generated/_asin_r8.f90 new file mode 100644 index 00000000000..37adbc64a68 --- /dev/null +++ b/libgfortran/generated/_asin_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__asin_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__asin_r8 + + specific__asin_r8 = asin (parm) +end function diff --git a/libgfortran/generated/_atan2_r4.f90 b/libgfortran/generated/_atan2_r4.f90 new file mode 100644 index 00000000000..fddda221f12 --- /dev/null +++ b/libgfortran/generated/_atan2_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__atan2_r4 (p1, p2) + real (kind=4), intent (in) :: p1, p2 + real (kind=4) :: specific__atan2_r4 + + specific__atan2_r4 = atan2 (p1, p2) +end function diff --git a/libgfortran/generated/_atan2_r8.f90 b/libgfortran/generated/_atan2_r8.f90 new file mode 100644 index 00000000000..76ec23c0ad4 --- /dev/null +++ b/libgfortran/generated/_atan2_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__atan2_r8 (p1, p2) + real (kind=8), intent (in) :: p1, p2 + real (kind=8) :: specific__atan2_r8 + + specific__atan2_r8 = atan2 (p1, p2) +end function diff --git a/libgfortran/generated/_atan_r4.f90 b/libgfortran/generated/_atan_r4.f90 new file mode 100644 index 00000000000..0918d7f3f12 --- /dev/null +++ b/libgfortran/generated/_atan_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__atan_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__atan_r4 + + specific__atan_r4 = atan (parm) +end function diff --git a/libgfortran/generated/_atan_r8.f90 b/libgfortran/generated/_atan_r8.f90 new file mode 100644 index 00000000000..71fe2e730c2 --- /dev/null +++ b/libgfortran/generated/_atan_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__atan_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__atan_r8 + + specific__atan_r8 = atan (parm) +end function diff --git a/libgfortran/generated/_conjg_c4.f90 b/libgfortran/generated/_conjg_c4.f90 new file mode 100644 index 00000000000..3d799ffd372 --- /dev/null +++ b/libgfortran/generated/_conjg_c4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__conjg_c4 (parm) + complex (kind=4), intent (in) :: parm + complex (kind=4) :: specific__conjg_c4 + + specific__conjg_c4 = conjg (parm) +end function diff --git a/libgfortran/generated/_conjg_c8.f90 b/libgfortran/generated/_conjg_c8.f90 new file mode 100644 index 00000000000..a8d4957c369 --- /dev/null +++ b/libgfortran/generated/_conjg_c8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__conjg_c8 (parm) + complex (kind=8), intent (in) :: parm + complex (kind=8) :: specific__conjg_c8 + + specific__conjg_c8 = conjg (parm) +end function diff --git a/libgfortran/generated/_cos_c4.f90 b/libgfortran/generated/_cos_c4.f90 new file mode 100644 index 00000000000..40f772a96fe --- /dev/null +++ b/libgfortran/generated/_cos_c4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__cos_c4 (parm) + complex (kind=4), intent (in) :: parm + complex (kind=4) :: specific__cos_c4 + + specific__cos_c4 = cos (parm) +end function diff --git a/libgfortran/generated/_cos_c8.f90 b/libgfortran/generated/_cos_c8.f90 new file mode 100644 index 00000000000..7ae0d1ed7e3 --- /dev/null +++ b/libgfortran/generated/_cos_c8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__cos_c8 (parm) + complex (kind=8), intent (in) :: parm + complex (kind=8) :: specific__cos_c8 + + specific__cos_c8 = cos (parm) +end function diff --git a/libgfortran/generated/_cos_r4.f90 b/libgfortran/generated/_cos_r4.f90 new file mode 100644 index 00000000000..186900ed05a --- /dev/null +++ b/libgfortran/generated/_cos_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__cos_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__cos_r4 + + specific__cos_r4 = cos (parm) +end function diff --git a/libgfortran/generated/_cos_r8.f90 b/libgfortran/generated/_cos_r8.f90 new file mode 100644 index 00000000000..6842d9109f0 --- /dev/null +++ b/libgfortran/generated/_cos_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__cos_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__cos_r8 + + specific__cos_r8 = cos (parm) +end function diff --git a/libgfortran/generated/_cosh_r4.f90 b/libgfortran/generated/_cosh_r4.f90 new file mode 100644 index 00000000000..2e40c85f2f1 --- /dev/null +++ b/libgfortran/generated/_cosh_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__cosh_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__cosh_r4 + + specific__cosh_r4 = cosh (parm) +end function diff --git a/libgfortran/generated/_cosh_r8.f90 b/libgfortran/generated/_cosh_r8.f90 new file mode 100644 index 00000000000..ef1ab85b0d0 --- /dev/null +++ b/libgfortran/generated/_cosh_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__cosh_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__cosh_r8 + + specific__cosh_r8 = cosh (parm) +end function diff --git a/libgfortran/generated/_dim_i4.f90 b/libgfortran/generated/_dim_i4.f90 new file mode 100644 index 00000000000..e46a34f46ff --- /dev/null +++ b/libgfortran/generated/_dim_i4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__dim_i4 (p1, p2) + integer (kind=4), intent (in) :: p1, p2 + integer (kind=4) :: specific__dim_i4 + + specific__dim_i4 = dim (p1, p2) +end function diff --git a/libgfortran/generated/_dim_i8.f90 b/libgfortran/generated/_dim_i8.f90 new file mode 100644 index 00000000000..fa823280b83 --- /dev/null +++ b/libgfortran/generated/_dim_i8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__dim_i8 (p1, p2) + integer (kind=8), intent (in) :: p1, p2 + integer (kind=8) :: specific__dim_i8 + + specific__dim_i8 = dim (p1, p2) +end function diff --git a/libgfortran/generated/_dim_r4.f90 b/libgfortran/generated/_dim_r4.f90 new file mode 100644 index 00000000000..1841ae7a033 --- /dev/null +++ b/libgfortran/generated/_dim_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__dim_r4 (p1, p2) + real (kind=4), intent (in) :: p1, p2 + real (kind=4) :: specific__dim_r4 + + specific__dim_r4 = dim (p1, p2) +end function diff --git a/libgfortran/generated/_dim_r8.f90 b/libgfortran/generated/_dim_r8.f90 new file mode 100644 index 00000000000..8de846adce2 --- /dev/null +++ b/libgfortran/generated/_dim_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__dim_r8 (p1, p2) + real (kind=8), intent (in) :: p1, p2 + real (kind=8) :: specific__dim_r8 + + specific__dim_r8 = dim (p1, p2) +end function diff --git a/libgfortran/generated/_exp_c4.f90 b/libgfortran/generated/_exp_c4.f90 new file mode 100644 index 00000000000..530be220218 --- /dev/null +++ b/libgfortran/generated/_exp_c4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__exp_c4 (parm) + complex (kind=4), intent (in) :: parm + complex (kind=4) :: specific__exp_c4 + + specific__exp_c4 = exp (parm) +end function diff --git a/libgfortran/generated/_exp_c8.f90 b/libgfortran/generated/_exp_c8.f90 new file mode 100644 index 00000000000..933c5606253 --- /dev/null +++ b/libgfortran/generated/_exp_c8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__exp_c8 (parm) + complex (kind=8), intent (in) :: parm + complex (kind=8) :: specific__exp_c8 + + specific__exp_c8 = exp (parm) +end function diff --git a/libgfortran/generated/_exp_r4.f90 b/libgfortran/generated/_exp_r4.f90 new file mode 100644 index 00000000000..ec56a495c45 --- /dev/null +++ b/libgfortran/generated/_exp_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__exp_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__exp_r4 + + specific__exp_r4 = exp (parm) +end function diff --git a/libgfortran/generated/_exp_r8.f90 b/libgfortran/generated/_exp_r8.f90 new file mode 100644 index 00000000000..fcd8d7d15a4 --- /dev/null +++ b/libgfortran/generated/_exp_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__exp_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__exp_r8 + + specific__exp_r8 = exp (parm) +end function diff --git a/libgfortran/generated/_log10_r4.f90 b/libgfortran/generated/_log10_r4.f90 new file mode 100644 index 00000000000..0d0d854db41 --- /dev/null +++ b/libgfortran/generated/_log10_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__log10_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__log10_r4 + + specific__log10_r4 = log10 (parm) +end function diff --git a/libgfortran/generated/_log10_r8.f90 b/libgfortran/generated/_log10_r8.f90 new file mode 100644 index 00000000000..360e9b59c54 --- /dev/null +++ b/libgfortran/generated/_log10_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__log10_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__log10_r8 + + specific__log10_r8 = log10 (parm) +end function diff --git a/libgfortran/generated/_log_c4.f90 b/libgfortran/generated/_log_c4.f90 new file mode 100644 index 00000000000..615c00a0272 --- /dev/null +++ b/libgfortran/generated/_log_c4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__log_c4 (parm) + complex (kind=4), intent (in) :: parm + complex (kind=4) :: specific__log_c4 + + specific__log_c4 = log (parm) +end function diff --git a/libgfortran/generated/_log_c8.f90 b/libgfortran/generated/_log_c8.f90 new file mode 100644 index 00000000000..38c757cb1b9 --- /dev/null +++ b/libgfortran/generated/_log_c8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__log_c8 (parm) + complex (kind=8), intent (in) :: parm + complex (kind=8) :: specific__log_c8 + + specific__log_c8 = log (parm) +end function diff --git a/libgfortran/generated/_log_r4.f90 b/libgfortran/generated/_log_r4.f90 new file mode 100644 index 00000000000..5cbe7d1a92e --- /dev/null +++ b/libgfortran/generated/_log_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__log_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__log_r4 + + specific__log_r4 = log (parm) +end function diff --git a/libgfortran/generated/_log_r8.f90 b/libgfortran/generated/_log_r8.f90 new file mode 100644 index 00000000000..7e0491297fd --- /dev/null +++ b/libgfortran/generated/_log_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__log_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__log_r8 + + specific__log_r8 = log (parm) +end function diff --git a/libgfortran/generated/_mod_i4.f90 b/libgfortran/generated/_mod_i4.f90 new file mode 100644 index 00000000000..396502960d0 --- /dev/null +++ b/libgfortran/generated/_mod_i4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__mod_i4 (p1, p2) + integer (kind=4), intent (in) :: p1, p2 + integer (kind=4) :: specific__mod_i4 + + specific__mod_i4 = mod (p1, p2) +end function diff --git a/libgfortran/generated/_mod_i8.f90 b/libgfortran/generated/_mod_i8.f90 new file mode 100644 index 00000000000..57552abb569 --- /dev/null +++ b/libgfortran/generated/_mod_i8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__mod_i8 (p1, p2) + integer (kind=8), intent (in) :: p1, p2 + integer (kind=8) :: specific__mod_i8 + + specific__mod_i8 = mod (p1, p2) +end function diff --git a/libgfortran/generated/_mod_r4.f90 b/libgfortran/generated/_mod_r4.f90 new file mode 100644 index 00000000000..6fe164fa645 --- /dev/null +++ b/libgfortran/generated/_mod_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__mod_r4 (p1, p2) + real (kind=4), intent (in) :: p1, p2 + real (kind=4) :: specific__mod_r4 + + specific__mod_r4 = mod (p1, p2) +end function diff --git a/libgfortran/generated/_mod_r8.f90 b/libgfortran/generated/_mod_r8.f90 new file mode 100644 index 00000000000..4857a66130b --- /dev/null +++ b/libgfortran/generated/_mod_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__mod_r8 (p1, p2) + real (kind=8), intent (in) :: p1, p2 + real (kind=8) :: specific__mod_r8 + + specific__mod_r8 = mod (p1, p2) +end function diff --git a/libgfortran/generated/_sign_i4.f90 b/libgfortran/generated/_sign_i4.f90 new file mode 100644 index 00000000000..db695b19ac7 --- /dev/null +++ b/libgfortran/generated/_sign_i4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sign_i4 (p1, p2) + integer (kind=4), intent (in) :: p1, p2 + integer (kind=4) :: specific__sign_i4 + + specific__sign_i4 = sign (p1, p2) +end function diff --git a/libgfortran/generated/_sign_i8.f90 b/libgfortran/generated/_sign_i8.f90 new file mode 100644 index 00000000000..d46ebb7ca49 --- /dev/null +++ b/libgfortran/generated/_sign_i8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sign_i8 (p1, p2) + integer (kind=8), intent (in) :: p1, p2 + integer (kind=8) :: specific__sign_i8 + + specific__sign_i8 = sign (p1, p2) +end function diff --git a/libgfortran/generated/_sign_r4.f90 b/libgfortran/generated/_sign_r4.f90 new file mode 100644 index 00000000000..fe68f510f11 --- /dev/null +++ b/libgfortran/generated/_sign_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sign_r4 (p1, p2) + real (kind=4), intent (in) :: p1, p2 + real (kind=4) :: specific__sign_r4 + + specific__sign_r4 = sign (p1, p2) +end function diff --git a/libgfortran/generated/_sign_r8.f90 b/libgfortran/generated/_sign_r8.f90 new file mode 100644 index 00000000000..3a0f109fdd6 --- /dev/null +++ b/libgfortran/generated/_sign_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sign_r8 (p1, p2) + real (kind=8), intent (in) :: p1, p2 + real (kind=8) :: specific__sign_r8 + + specific__sign_r8 = sign (p1, p2) +end function diff --git a/libgfortran/generated/_sin_c4.f90 b/libgfortran/generated/_sin_c4.f90 new file mode 100644 index 00000000000..7d9cb36e5a3 --- /dev/null +++ b/libgfortran/generated/_sin_c4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sin_c4 (parm) + complex (kind=4), intent (in) :: parm + complex (kind=4) :: specific__sin_c4 + + specific__sin_c4 = sin (parm) +end function diff --git a/libgfortran/generated/_sin_c8.f90 b/libgfortran/generated/_sin_c8.f90 new file mode 100644 index 00000000000..d9d929628eb --- /dev/null +++ b/libgfortran/generated/_sin_c8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sin_c8 (parm) + complex (kind=8), intent (in) :: parm + complex (kind=8) :: specific__sin_c8 + + specific__sin_c8 = sin (parm) +end function diff --git a/libgfortran/generated/_sin_r4.f90 b/libgfortran/generated/_sin_r4.f90 new file mode 100644 index 00000000000..f531afc774e --- /dev/null +++ b/libgfortran/generated/_sin_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sin_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__sin_r4 + + specific__sin_r4 = sin (parm) +end function diff --git a/libgfortran/generated/_sin_r8.f90 b/libgfortran/generated/_sin_r8.f90 new file mode 100644 index 00000000000..d385d5c365a --- /dev/null +++ b/libgfortran/generated/_sin_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sin_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__sin_r8 + + specific__sin_r8 = sin (parm) +end function diff --git a/libgfortran/generated/_sinh_r4.f90 b/libgfortran/generated/_sinh_r4.f90 new file mode 100644 index 00000000000..24f1fa80154 --- /dev/null +++ b/libgfortran/generated/_sinh_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sinh_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__sinh_r4 + + specific__sinh_r4 = sinh (parm) +end function diff --git a/libgfortran/generated/_sinh_r8.f90 b/libgfortran/generated/_sinh_r8.f90 new file mode 100644 index 00000000000..6b166de8d22 --- /dev/null +++ b/libgfortran/generated/_sinh_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sinh_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__sinh_r8 + + specific__sinh_r8 = sinh (parm) +end function diff --git a/libgfortran/generated/_sqrt_c4.f90 b/libgfortran/generated/_sqrt_c4.f90 new file mode 100644 index 00000000000..2377f25b498 --- /dev/null +++ b/libgfortran/generated/_sqrt_c4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sqrt_c4 (parm) + complex (kind=4), intent (in) :: parm + complex (kind=4) :: specific__sqrt_c4 + + specific__sqrt_c4 = sqrt (parm) +end function diff --git a/libgfortran/generated/_sqrt_c8.f90 b/libgfortran/generated/_sqrt_c8.f90 new file mode 100644 index 00000000000..c32da20f164 --- /dev/null +++ b/libgfortran/generated/_sqrt_c8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sqrt_c8 (parm) + complex (kind=8), intent (in) :: parm + complex (kind=8) :: specific__sqrt_c8 + + specific__sqrt_c8 = sqrt (parm) +end function diff --git a/libgfortran/generated/_sqrt_r4.f90 b/libgfortran/generated/_sqrt_r4.f90 new file mode 100644 index 00000000000..62416e79d34 --- /dev/null +++ b/libgfortran/generated/_sqrt_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sqrt_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__sqrt_r4 + + specific__sqrt_r4 = sqrt (parm) +end function diff --git a/libgfortran/generated/_sqrt_r8.f90 b/libgfortran/generated/_sqrt_r8.f90 new file mode 100644 index 00000000000..3928cd46383 --- /dev/null +++ b/libgfortran/generated/_sqrt_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__sqrt_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__sqrt_r8 + + specific__sqrt_r8 = sqrt (parm) +end function diff --git a/libgfortran/generated/_tan_r4.f90 b/libgfortran/generated/_tan_r4.f90 new file mode 100644 index 00000000000..aaf26b19175 --- /dev/null +++ b/libgfortran/generated/_tan_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__tan_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__tan_r4 + + specific__tan_r4 = tan (parm) +end function diff --git a/libgfortran/generated/_tan_r8.f90 b/libgfortran/generated/_tan_r8.f90 new file mode 100644 index 00000000000..eca6d228355 --- /dev/null +++ b/libgfortran/generated/_tan_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__tan_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__tan_r8 + + specific__tan_r8 = tan (parm) +end function diff --git a/libgfortran/generated/_tanh_r4.f90 b/libgfortran/generated/_tanh_r4.f90 new file mode 100644 index 00000000000..b027ed6c251 --- /dev/null +++ b/libgfortran/generated/_tanh_r4.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__tanh_r4 (parm) + real (kind=4), intent (in) :: parm + real (kind=4) :: specific__tanh_r4 + + specific__tanh_r4 = tanh (parm) +end function diff --git a/libgfortran/generated/_tanh_r8.f90 b/libgfortran/generated/_tanh_r8.f90 new file mode 100644 index 00000000000..a5bbf18fefd --- /dev/null +++ b/libgfortran/generated/_tanh_r8.f90 @@ -0,0 +1,29 @@ +! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated. + + +elemental function specific__tanh_r8 (parm) + real (kind=8), intent (in) :: parm + real (kind=8) :: specific__tanh_r8 + + specific__tanh_r8 = tanh (parm) +end function diff --git a/libgfortran/generated/all_l4.c b/libgfortran/generated/all_l4.c new file mode 100644 index 00000000000..5bfeeab328e --- /dev/null +++ b/libgfortran/generated/all_l4.c @@ -0,0 +1,133 @@ +/* Implementation of the ALL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__all_l4 (gfc_array_l4 * retarray, gfc_array_l4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_4 *base; + GFC_LOGICAL_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_4 *src; + GFC_LOGICAL_4 result; + src = base; + { + + /* Return true only if all the elements are set. */ + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (! *src) + { + result = 0; + break; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/all_l8.c b/libgfortran/generated/all_l8.c new file mode 100644 index 00000000000..b47b128dbba --- /dev/null +++ b/libgfortran/generated/all_l8.c @@ -0,0 +1,133 @@ +/* Implementation of the ALL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__all_l8 (gfc_array_l8 * retarray, gfc_array_l8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_8 *base; + GFC_LOGICAL_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_8 *src; + GFC_LOGICAL_8 result; + src = base; + { + + /* Return true only if all the elements are set. */ + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (! *src) + { + result = 0; + break; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/any_l4.c b/libgfortran/generated/any_l4.c new file mode 100644 index 00000000000..6abb9025e11 --- /dev/null +++ b/libgfortran/generated/any_l4.c @@ -0,0 +1,133 @@ +/* Implementation of the ANY intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__any_l4 (gfc_array_l4 * retarray, gfc_array_l4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_4 *base; + GFC_LOGICAL_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_4 *src; + GFC_LOGICAL_4 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + /* Return true if any of the elements are set. */ + if (*src) + { + result = 1; + break; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/any_l8.c b/libgfortran/generated/any_l8.c new file mode 100644 index 00000000000..20e0c4693a0 --- /dev/null +++ b/libgfortran/generated/any_l8.c @@ -0,0 +1,133 @@ +/* Implementation of the ANY intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__any_l8 (gfc_array_l8 * retarray, gfc_array_l8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_8 *base; + GFC_LOGICAL_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_8 *src; + GFC_LOGICAL_8 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + /* Return true if any of the elements are set. */ + if (*src) + { + result = 1; + break; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/count_4_l4.c b/libgfortran/generated/count_4_l4.c new file mode 100644 index 00000000000..959c8b8a371 --- /dev/null +++ b/libgfortran/generated/count_4_l4.c @@ -0,0 +1,129 @@ +/* Implementation of the COUNT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__count_4_l4 (gfc_array_i4 * retarray, gfc_array_l4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src) + result++; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/count_4_l8.c b/libgfortran/generated/count_4_l8.c new file mode 100644 index 00000000000..3879e9bee78 --- /dev/null +++ b/libgfortran/generated/count_4_l8.c @@ -0,0 +1,129 @@ +/* Implementation of the COUNT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__count_4_l8 (gfc_array_i4 * retarray, gfc_array_l8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_8 *src; + GFC_INTEGER_4 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src) + result++; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/count_8_l4.c b/libgfortran/generated/count_8_l4.c new file mode 100644 index 00000000000..67b6ec32280 --- /dev/null +++ b/libgfortran/generated/count_8_l4.c @@ -0,0 +1,129 @@ +/* Implementation of the COUNT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__count_8_l4 (gfc_array_i8 * retarray, gfc_array_l4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_4 *src; + GFC_INTEGER_8 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src) + result++; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/count_8_l8.c b/libgfortran/generated/count_8_l8.c new file mode 100644 index 00000000000..93d6c2d281a --- /dev/null +++ b/libgfortran/generated/count_8_l8.c @@ -0,0 +1,129 @@ +/* Implementation of the COUNT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__count_8_l8 (gfc_array_i8 * retarray, gfc_array_l8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_LOGICAL_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_LOGICAL_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src) + result++; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/cshift1_4.c b/libgfortran/generated/cshift1_4.c new file mode 100644 index 00000000000..9375074db2a --- /dev/null +++ b/libgfortran/generated/cshift1_4.c @@ -0,0 +1,170 @@ +/* Implementation of the CSHIFT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Feng Wang + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +__cshift1_4 (const gfc_array_char * ret, const gfc_array_char * array, + const gfc_array_i4 * h, const GFC_INTEGER_4 * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + /* h.* indicates the shift array. */ + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const GFC_INTEGER_4 *hptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + GFC_INTEGER_4 sh; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array)) + runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'"); + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + +/* Initialized for avoiding compiler warnings. */ + roffset = size; + soffset = size; + len = 0; + + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + + while (rptr) + { + /* Do the shift for this dimension. */ + sh = *hptr; + sh = (div (sh, len)).rem; + if (sh < 0) + sh += len; + + src = &sptr[sh * soffset]; + dest = rptr; + + for (n = 0; n < len; n++) + { + memcpy (dest, src, size); + dest += roffset; + if (n == len - sh - 1) + src = sptr; + else + src += soffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/cshift1_8.c b/libgfortran/generated/cshift1_8.c new file mode 100644 index 00000000000..7303d560440 --- /dev/null +++ b/libgfortran/generated/cshift1_8.c @@ -0,0 +1,170 @@ +/* Implementation of the CSHIFT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Feng Wang + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +__cshift1_8 (const gfc_array_char * ret, const gfc_array_char * array, + const gfc_array_i8 * h, const GFC_INTEGER_8 * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + /* h.* indicates the shift array. */ + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const GFC_INTEGER_8 *hptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + GFC_INTEGER_8 sh; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array)) + runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'"); + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + +/* Initialized for avoiding compiler warnings. */ + roffset = size; + soffset = size; + len = 0; + + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + + while (rptr) + { + /* Do the shift for this dimension. */ + sh = *hptr; + sh = (div (sh, len)).rem; + if (sh < 0) + sh += len; + + src = &sptr[sh * soffset]; + dest = rptr; + + for (n = 0; n < len; n++) + { + memcpy (dest, src, size); + dest += roffset; + if (n == len - sh - 1) + src = sptr; + else + src += soffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/dotprod_c4.c b/libgfortran/generated/dotprod_c4.c new file mode 100644 index 00000000000..9812ab4e3c8 --- /dev/null +++ b/libgfortran/generated/dotprod_c4.c @@ -0,0 +1,67 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + and Feng Wang + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +GFC_COMPLEX_4 +__dot_product_c4 (gfc_array_c4 * a, gfc_array_c4 * b) +{ + GFC_COMPLEX_4 *pa; + GFC_COMPLEX_4 *pb; + GFC_COMPLEX_4 res; + GFC_COMPLEX_4 conjga; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; + + while (count--) + { + COMPLEX_ASSIGN(conjga, REALPART (*pa), -IMAGPART (*pa)); + res += conjga * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/generated/dotprod_c8.c b/libgfortran/generated/dotprod_c8.c new file mode 100644 index 00000000000..fde18021400 --- /dev/null +++ b/libgfortran/generated/dotprod_c8.c @@ -0,0 +1,67 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + and Feng Wang + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +GFC_COMPLEX_8 +__dot_product_c8 (gfc_array_c8 * a, gfc_array_c8 * b) +{ + GFC_COMPLEX_8 *pa; + GFC_COMPLEX_8 *pb; + GFC_COMPLEX_8 res; + GFC_COMPLEX_8 conjga; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; + + while (count--) + { + COMPLEX_ASSIGN(conjga, REALPART (*pa), -IMAGPART (*pa)); + res += conjga * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/generated/dotprod_i4.c b/libgfortran/generated/dotprod_i4.c new file mode 100644 index 00000000000..374d9251300 --- /dev/null +++ b/libgfortran/generated/dotprod_i4.c @@ -0,0 +1,64 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +GFC_INTEGER_4 +__dot_product_i4 (gfc_array_i4 * a, gfc_array_i4 * b) +{ + GFC_INTEGER_4 *pa; + GFC_INTEGER_4 *pb; + GFC_INTEGER_4 res; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; + + while (count--) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/generated/dotprod_i8.c b/libgfortran/generated/dotprod_i8.c new file mode 100644 index 00000000000..6702a1d489c --- /dev/null +++ b/libgfortran/generated/dotprod_i8.c @@ -0,0 +1,64 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +GFC_INTEGER_8 +__dot_product_i8 (gfc_array_i8 * a, gfc_array_i8 * b) +{ + GFC_INTEGER_8 *pa; + GFC_INTEGER_8 *pb; + GFC_INTEGER_8 res; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; + + while (count--) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/generated/dotprod_l4.c b/libgfortran/generated/dotprod_l4.c new file mode 100644 index 00000000000..292c0386cd1 --- /dev/null +++ b/libgfortran/generated/dotprod_l4.c @@ -0,0 +1,74 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +GFC_LOGICAL_4 +__dot_product_l4 (gfc_array_l4 * a, gfc_array_l4 * b) +{ + GFC_LOGICAL_4 *pa; + GFC_LOGICAL_4 *pb; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + + pa = a->data; + if (GFC_DESCRIPTOR_SIZE (a) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (a) == 8); + pa = GFOR_POINTER_L8_TO_L4 (pa); + astride <<= 1; + } + pb = b->data; + if (GFC_DESCRIPTOR_SIZE (b) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (b) == 8); + pb = GFOR_POINTER_L8_TO_L4 (pb); + bstride <<= 1; + } + + while (count--) + { + if (*pa && *pb) + return 1; + + pa += astride; + pb += bstride; + } + + return 0; +} + diff --git a/libgfortran/generated/dotprod_l8.c b/libgfortran/generated/dotprod_l8.c new file mode 100644 index 00000000000..4316607a3e5 --- /dev/null +++ b/libgfortran/generated/dotprod_l8.c @@ -0,0 +1,74 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +GFC_LOGICAL_8 +__dot_product_l8 (gfc_array_l4 * a, gfc_array_l4 * b) +{ + GFC_LOGICAL_4 *pa; + GFC_LOGICAL_4 *pb; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + + pa = a->data; + if (GFC_DESCRIPTOR_SIZE (a) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (a) == 8); + pa = GFOR_POINTER_L8_TO_L4 (pa); + astride <<= 1; + } + pb = b->data; + if (GFC_DESCRIPTOR_SIZE (b) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (b) == 8); + pb = GFOR_POINTER_L8_TO_L4 (pb); + bstride <<= 1; + } + + while (count--) + { + if (*pa && *pb) + return 1; + + pa += astride; + pb += bstride; + } + + return 0; +} + diff --git a/libgfortran/generated/dotprod_r4.c b/libgfortran/generated/dotprod_r4.c new file mode 100644 index 00000000000..1edfea36e6e --- /dev/null +++ b/libgfortran/generated/dotprod_r4.c @@ -0,0 +1,64 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +GFC_REAL_4 +__dot_product_r4 (gfc_array_r4 * a, gfc_array_r4 * b) +{ + GFC_REAL_4 *pa; + GFC_REAL_4 *pb; + GFC_REAL_4 res; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; + + while (count--) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/generated/dotprod_r8.c b/libgfortran/generated/dotprod_r8.c new file mode 100644 index 00000000000..bf35710272b --- /dev/null +++ b/libgfortran/generated/dotprod_r8.c @@ -0,0 +1,64 @@ +/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +GFC_REAL_8 +__dot_product_r8 (gfc_array_r8 * a, gfc_array_r8 * b) +{ + GFC_REAL_8 *pa; + GFC_REAL_8 *pb; + GFC_REAL_8 res; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; + + while (count--) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/generated/eoshift1_4.c b/libgfortran/generated/eoshift1_4.c new file mode 100644 index 00000000000..05b1af682e0 --- /dev/null +++ b/libgfortran/generated/eoshift1_4.c @@ -0,0 +1,178 @@ +/* Implementation of the EOSHIFT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +void +__eoshift1_4 (const gfc_array_char * ret, const gfc_array_char * array, + const gfc_array_i4 * h, const char * pbound, const GFC_INTEGER_4 * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + /* h.* indicates the shift array. */ + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const GFC_INTEGER_4 *hptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + GFC_INTEGER_4 sh; + GFC_INTEGER_4 delta; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + if (!pbound) + pbound = zeros; + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + + while (rptr) + { + /* Do the shift for this dimension. */ + sh = *hptr; + delta = (sh >= 0) ? sh: -sh; + if (sh > 0) + { + src = &sptr[delta * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[delta * roffset]; + } + for (n = 0; n < len - delta; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (sh < 0) + dest = rptr; + n = delta; + + while (n--) + { + memcpy (dest, pbound, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/eoshift1_8.c b/libgfortran/generated/eoshift1_8.c new file mode 100644 index 00000000000..f74c022f178 --- /dev/null +++ b/libgfortran/generated/eoshift1_8.c @@ -0,0 +1,178 @@ +/* Implementation of the EOSHIFT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +void +__eoshift1_8 (const gfc_array_char * ret, const gfc_array_char * array, + const gfc_array_i8 * h, const char * pbound, const GFC_INTEGER_8 * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + /* h.* indicates the shift array. */ + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const GFC_INTEGER_8 *hptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + GFC_INTEGER_8 sh; + GFC_INTEGER_8 delta; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + if (!pbound) + pbound = zeros; + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + + while (rptr) + { + /* Do the shift for this dimension. */ + sh = *hptr; + delta = (sh >= 0) ? sh: -sh; + if (sh > 0) + { + src = &sptr[delta * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[delta * roffset]; + } + for (n = 0; n < len - delta; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (sh < 0) + dest = rptr; + n = delta; + + while (n--) + { + memcpy (dest, pbound, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/eoshift3_4.c b/libgfortran/generated/eoshift3_4.c new file mode 100644 index 00000000000..07c2d9e965e --- /dev/null +++ b/libgfortran/generated/eoshift3_4.c @@ -0,0 +1,193 @@ +/* Implementation of the EOSHIFT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +void +__eoshift3_4 (gfc_array_char * ret, gfc_array_char * array, + gfc_array_i4 * h, const gfc_array_char * bound, GFC_INTEGER_4 * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + /* h.* indicates the shift array. */ + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const GFC_INTEGER_4 *hptr; + /* b.* indicates the bound array. */ + index_type bstride[GFC_MAX_DIMENSIONS - 1]; + index_type bstride0; + const char *bptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + GFC_INTEGER_4 sh; + GFC_INTEGER_4 delta; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + if (bound) + bstride[n] = bound->dim[n].stride; + else + bstride[n] = 0; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + if (bound && bstride[0] == 0) + bstride[0] = size; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + bstride0 = bstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + if (bound) + bptr = bound->data; + else + bptr = zeros; + + while (rptr) + { + /* Do the shift for this dimension. */ + sh = *hptr; + delta = (sh >= 0) ? sh: -sh; + if (sh > 0) + { + src = &sptr[delta * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[delta * roffset]; + } + for (n = 0; n < len - delta; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (sh < 0) + dest = rptr; + n = delta; + + while (n--) + { + memcpy (dest, bptr, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + bptr += bstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + bptr -= bstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + bptr += bstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/eoshift3_8.c b/libgfortran/generated/eoshift3_8.c new file mode 100644 index 00000000000..fcb161df39a --- /dev/null +++ b/libgfortran/generated/eoshift3_8.c @@ -0,0 +1,193 @@ +/* Implementation of the EOSHIFT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +void +__eoshift3_8 (gfc_array_char * ret, gfc_array_char * array, + gfc_array_i8 * h, const gfc_array_char * bound, GFC_INTEGER_8 * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + /* h.* indicates the shift array. */ + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const GFC_INTEGER_8 *hptr; + /* b.* indicates the bound array. */ + index_type bstride[GFC_MAX_DIMENSIONS - 1]; + index_type bstride0; + const char *bptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + GFC_INTEGER_8 sh; + GFC_INTEGER_8 delta; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + if (bound) + bstride[n] = bound->dim[n].stride; + else + bstride[n] = 0; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + if (bound && bstride[0] == 0) + bstride[0] = size; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + bstride0 = bstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + if (bound) + bptr = bound->data; + else + bptr = zeros; + + while (rptr) + { + /* Do the shift for this dimension. */ + sh = *hptr; + delta = (sh >= 0) ? sh: -sh; + if (sh > 0) + { + src = &sptr[delta * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[delta * roffset]; + } + for (n = 0; n < len - delta; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (sh < 0) + dest = rptr; + n = delta; + + while (n--) + { + memcpy (dest, bptr, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + bptr += bstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + bptr -= bstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + bptr += bstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/exp_c4.c b/libgfortran/generated/exp_c4.c new file mode 100644 index 00000000000..d95213446ee --- /dev/null +++ b/libgfortran/generated/exp_c4.c @@ -0,0 +1,139 @@ +/* Complex exponential functions + Copyright 2002, 2004 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +/* z = a + ib */ +/* Absolute value. */ +GFC_REAL_4 +cabsf (GFC_COMPLEX_4 z) +{ + return hypotf (REALPART (z), IMAGPART (z)); +} + +/* Complex argument. The angle made with the +ve real axis. Range 0-2pi. */ +GFC_REAL_4 +cargf (GFC_COMPLEX_4 z) +{ + GFC_REAL_4 arg; + + arg = atan2f (IMAGPART (z), REALPART (z)); + if (arg < 0) + return arg + 2 * M_PI; + else + return arg; +} + +/* exp(z) = exp(a)*(cos(b) + isin(b)) */ +GFC_COMPLEX_4 +cexpf (GFC_COMPLEX_4 z) +{ + GFC_REAL_4 a; + GFC_REAL_4 b; + GFC_COMPLEX_4 v; + + a = REALPART (z); + b = IMAGPART (z); + COMPLEX_ASSIGN (v, cosf (b), sinf (b)); + return expf (a) * v; +} + +/* log(z) = log (cabs(z)) + i*carg(z) */ +GFC_COMPLEX_4 +clogf (GFC_COMPLEX_4 z) +{ + GFC_COMPLEX_4 v; + + COMPLEX_ASSIGN (v, logf (cabsf (z)), cargf (z)); + return v; +} + +/* log10(z) = log10 (cabs(z)) + i*carg(z) */ +GFC_COMPLEX_4 +clog10f (GFC_COMPLEX_4 z) +{ + GFC_COMPLEX_4 v; + + COMPLEX_ASSIGN (v, log10f (cabsf (z)), cargf (z)); + return v; +} + +/* pow(base, power) = cexp (power * clog (base)) */ +GFC_COMPLEX_4 +cpowf (GFC_COMPLEX_4 base, GFC_COMPLEX_4 power) +{ + return cexpf (power * clogf (base)); +} + +/* sqrt(z). Algorithm pulled from glibc. */ +GFC_COMPLEX_4 +csqrtf (GFC_COMPLEX_4 z) +{ + GFC_REAL_4 re; + GFC_REAL_4 im; + GFC_COMPLEX_4 v; + + re = REALPART (z); + im = IMAGPART (z); + if (im == 0.0) + { + if (re < 0.0) + { + COMPLEX_ASSIGN (v, 0.0, copysignf (sqrtf (-re), im)); + } + else + { + COMPLEX_ASSIGN (v, fabsf (sqrt (re)), + copysignf (0.0, im)); + } + } + else if (re == 0.0) + { + GFC_REAL_4 r; + + r = sqrtf (0.5 * fabs (im)); + + COMPLEX_ASSIGN (v, copysignf (r, im), r); + } + else + { + GFC_REAL_4 d, r, s; + + d = hypotf (re, im); + /* Use the identity 2 Re res Im res = Im x + to avoid cancellation error in d +/- Re x. */ + if (re > 0) + { + r = sqrtf (0.5 * d + 0.5 * re); + s = (0.5 * im) / r; + } + else + { + s = sqrtf (0.5 * d - 0.5 * re); + r = fabsf ((0.5 * im) / s); + } + + COMPLEX_ASSIGN (v, r, copysignf (s, im)); + } + return v; +} + diff --git a/libgfortran/generated/exp_c8.c b/libgfortran/generated/exp_c8.c new file mode 100644 index 00000000000..74cbbdc5145 --- /dev/null +++ b/libgfortran/generated/exp_c8.c @@ -0,0 +1,139 @@ +/* Complex exponential functions + Copyright 2002, 2004 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +/* z = a + ib */ +/* Absolute value. */ +GFC_REAL_8 +cabs (GFC_COMPLEX_8 z) +{ + return hypot (REALPART (z), IMAGPART (z)); +} + +/* Complex argument. The angle made with the +ve real axis. Range 0-2pi. */ +GFC_REAL_8 +carg (GFC_COMPLEX_8 z) +{ + GFC_REAL_8 arg; + + arg = atan2 (IMAGPART (z), REALPART (z)); + if (arg < 0) + return arg + 2 * M_PI; + else + return arg; +} + +/* exp(z) = exp(a)*(cos(b) + isin(b)) */ +GFC_COMPLEX_8 +cexp (GFC_COMPLEX_8 z) +{ + GFC_REAL_8 a; + GFC_REAL_8 b; + GFC_COMPLEX_8 v; + + a = REALPART (z); + b = IMAGPART (z); + COMPLEX_ASSIGN (v, cos (b), sin (b)); + return exp (a) * v; +} + +/* log(z) = log (cabs(z)) + i*carg(z) */ +GFC_COMPLEX_8 +clog (GFC_COMPLEX_8 z) +{ + GFC_COMPLEX_8 v; + + COMPLEX_ASSIGN (v, log (cabs (z)), carg (z)); + return v; +} + +/* log10(z) = log10 (cabs(z)) + i*carg(z) */ +GFC_COMPLEX_8 +clog10 (GFC_COMPLEX_8 z) +{ + GFC_COMPLEX_8 v; + + COMPLEX_ASSIGN (v, log10 (cabs (z)), carg (z)); + return v; +} + +/* pow(base, power) = cexp (power * clog (base)) */ +GFC_COMPLEX_8 +cpow (GFC_COMPLEX_8 base, GFC_COMPLEX_8 power) +{ + return cexp (power * clog (base)); +} + +/* sqrt(z). Algorithm pulled from glibc. */ +GFC_COMPLEX_8 +csqrt (GFC_COMPLEX_8 z) +{ + GFC_REAL_8 re; + GFC_REAL_8 im; + GFC_COMPLEX_8 v; + + re = REALPART (z); + im = IMAGPART (z); + if (im == 0.0) + { + if (re < 0.0) + { + COMPLEX_ASSIGN (v, 0.0, copysign (sqrt (-re), im)); + } + else + { + COMPLEX_ASSIGN (v, fabs (sqrt (re)), + copysign (0.0, im)); + } + } + else if (re == 0.0) + { + GFC_REAL_8 r; + + r = sqrt (0.5 * fabs (im)); + + COMPLEX_ASSIGN (v, copysign (r, im), r); + } + else + { + GFC_REAL_8 d, r, s; + + d = hypot (re, im); + /* Use the identity 2 Re res Im res = Im x + to avoid cancellation error in d +/- Re x. */ + if (re > 0) + { + r = sqrt (0.5 * d + 0.5 * re); + s = (0.5 * im) / r; + } + else + { + s = sqrt (0.5 * d - 0.5 * re); + r = fabs ((0.5 * im) / s); + } + + COMPLEX_ASSIGN (v, r, copysign (s, im)); + } + return v; +} + diff --git a/libgfortran/generated/exponent_r4.c b/libgfortran/generated/exponent_r4.c new file mode 100644 index 00000000000..34e76b65edb --- /dev/null +++ b/libgfortran/generated/exponent_r4.c @@ -0,0 +1,31 @@ +/* Implementation of the EXPONENT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +GFC_INTEGER_4 +prefix(exponent_r4) (GFC_REAL_4 s) +{ + int ret; + frexpf (s, &ret); + return ret; +} diff --git a/libgfortran/generated/exponent_r8.c b/libgfortran/generated/exponent_r8.c new file mode 100644 index 00000000000..8a4101efd66 --- /dev/null +++ b/libgfortran/generated/exponent_r8.c @@ -0,0 +1,31 @@ +/* Implementation of the EXPONENT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +GFC_INTEGER_4 +prefix(exponent_r8) (GFC_REAL_8 s) +{ + int ret; + frexp (s, &ret); + return ret; +} diff --git a/libgfortran/generated/fraction_r4.c b/libgfortran/generated/fraction_r4.c new file mode 100644 index 00000000000..a86e8292c71 --- /dev/null +++ b/libgfortran/generated/fraction_r4.c @@ -0,0 +1,30 @@ +/* Implementation of the FRACTION intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +GFC_REAL_4 +prefix(fraction_r4) (GFC_REAL_4 s) +{ + int dummy_exp; + return frexpf (s, &dummy_exp); +} diff --git a/libgfortran/generated/fraction_r8.c b/libgfortran/generated/fraction_r8.c new file mode 100644 index 00000000000..613c6ac702c --- /dev/null +++ b/libgfortran/generated/fraction_r8.c @@ -0,0 +1,30 @@ +/* Implementation of the FRACTION intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +GFC_REAL_8 +prefix(fraction_r8) (GFC_REAL_8 s) +{ + int dummy_exp; + return frexp (s, &dummy_exp); +} diff --git a/libgfortran/generated/hyp_c4.c b/libgfortran/generated/hyp_c4.c new file mode 100644 index 00000000000..ac6c1e03131 --- /dev/null +++ b/libgfortran/generated/hyp_c4.c @@ -0,0 +1,71 @@ +/* Complex hyperbolic functions + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +/* Complex number z = a + ib. */ + +/* sinh(z) = sinh(a)cos(b) + icosh(a)sin(b) */ +GFC_COMPLEX_4 +csinhf (GFC_COMPLEX_4 a) +{ + GFC_REAL_4 r; + GFC_REAL_4 i; + GFC_COMPLEX_4 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, sinhf (r) * cosf (i), coshf (r) * sinf (i)); + return v; +} + +/* cosh(z) = cosh(a)cos(b) - isinh(a)sin(b) */ +GFC_COMPLEX_4 +ccoshf (GFC_COMPLEX_4 a) +{ + GFC_REAL_4 r; + GFC_REAL_4 i; + GFC_COMPLEX_4 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, coshf (r) * cosf (i), - (sinhf (r) * sinf (i))); + return v; +} + +/* tanh(z) = (tanh(a) + itan(b)) / (1 - itanh(a)tan(b)) */ +GFC_COMPLEX_4 +ctanhf (GFC_COMPLEX_4 a) +{ + GFC_REAL_4 rt; + GFC_REAL_4 it; + GFC_COMPLEX_4 n; + GFC_COMPLEX_4 d; + + rt = tanhf (REALPART (a)); + it = tanf (IMAGPART (a)); + COMPLEX_ASSIGN (n, rt, it); + COMPLEX_ASSIGN (d, 1, - (rt * it)); + + return n / d; +} + diff --git a/libgfortran/generated/hyp_c8.c b/libgfortran/generated/hyp_c8.c new file mode 100644 index 00000000000..b3793054941 --- /dev/null +++ b/libgfortran/generated/hyp_c8.c @@ -0,0 +1,71 @@ +/* Complex hyperbolic functions + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +/* Complex number z = a + ib. */ + +/* sinh(z) = sinh(a)cos(b) + icosh(a)sin(b) */ +GFC_COMPLEX_8 +csinh (GFC_COMPLEX_8 a) +{ + GFC_REAL_8 r; + GFC_REAL_8 i; + GFC_COMPLEX_8 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, sinh (r) * cos (i), cosh (r) * sin (i)); + return v; +} + +/* cosh(z) = cosh(a)cos(b) - isinh(a)sin(b) */ +GFC_COMPLEX_8 +ccosh (GFC_COMPLEX_8 a) +{ + GFC_REAL_8 r; + GFC_REAL_8 i; + GFC_COMPLEX_8 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, cosh (r) * cos (i), - (sinh (r) * sin (i))); + return v; +} + +/* tanh(z) = (tanh(a) + itan(b)) / (1 - itanh(a)tan(b)) */ +GFC_COMPLEX_8 +ctanh (GFC_COMPLEX_8 a) +{ + GFC_REAL_8 rt; + GFC_REAL_8 it; + GFC_COMPLEX_8 n; + GFC_COMPLEX_8 d; + + rt = tanh (REALPART (a)); + it = tan (IMAGPART (a)); + COMPLEX_ASSIGN (n, rt, it); + COMPLEX_ASSIGN (d, 1, - (rt * it)); + + return n / d; +} + diff --git a/libgfortran/generated/in_pack_i4.c b/libgfortran/generated/in_pack_i4.c new file mode 100644 index 00000000000..f11295718fc --- /dev/null +++ b/libgfortran/generated/in_pack_i4.c @@ -0,0 +1,115 @@ +/* Helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfortran; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +/* Allocates a block of memory with internal_malloc if the array needs + repacking. */ + +GFC_INTEGER_4 * +internal_pack_4 (gfc_array_i4 * source) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type ssize; + const GFC_INTEGER_4 *src; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *destptr; + int n; + int packed; + + if (source->dim[0].stride == 0) + { + source->dim[0].stride = 1; + return source->data; + } + + dim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + packed = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = source->dim[n].stride; + extent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (extent[n] <= 0) + { + /* Do nothing. */ + packed = 1; + break; + } + + if (ssize != stride[n]) + packed = 0; + + ssize *= extent[n]; + } + + if (packed) + return source->data; + + /* Allocate storage for the destination. */ + destptr = (GFC_INTEGER_4 *)internal_malloc_size (ssize * 4); + dest = destptr; + src = source->data; + stride0 = stride[0]; + + + while (src) + { + /* Copy the data. */ + *(dest++) = *src; + /* Advance to the next element. */ + src += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= stride[n] * extent[n]; + n++; + if (n == dim) + { + src = NULL; + break; + } + else + { + count[n]++; + src += stride[n]; + } + } + } + return destptr; +} + diff --git a/libgfortran/generated/in_pack_i8.c b/libgfortran/generated/in_pack_i8.c new file mode 100644 index 00000000000..82609272e4a --- /dev/null +++ b/libgfortran/generated/in_pack_i8.c @@ -0,0 +1,115 @@ +/* Helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfortran; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +/* Allocates a block of memory with internal_malloc if the array needs + repacking. */ + +GFC_INTEGER_8 * +internal_pack_8 (gfc_array_i8 * source) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type ssize; + const GFC_INTEGER_8 *src; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *destptr; + int n; + int packed; + + if (source->dim[0].stride == 0) + { + source->dim[0].stride = 1; + return source->data; + } + + dim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + packed = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = source->dim[n].stride; + extent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (extent[n] <= 0) + { + /* Do nothing. */ + packed = 1; + break; + } + + if (ssize != stride[n]) + packed = 0; + + ssize *= extent[n]; + } + + if (packed) + return source->data; + + /* Allocate storage for the destination. */ + destptr = (GFC_INTEGER_8 *)internal_malloc_size (ssize * 8); + dest = destptr; + src = source->data; + stride0 = stride[0]; + + + while (src) + { + /* Copy the data. */ + *(dest++) = *src; + /* Advance to the next element. */ + src += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= stride[n] * extent[n]; + n++; + if (n == dim) + { + src = NULL; + break; + } + else + { + count[n]++; + src += stride[n]; + } + } + } + return destptr; +} + diff --git a/libgfortran/generated/in_unpack_i4.c b/libgfortran/generated/in_unpack_i4.c new file mode 100644 index 00000000000..b0b7e7bc06d --- /dev/null +++ b/libgfortran/generated/in_unpack_i4.c @@ -0,0 +1,102 @@ +/* Helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +internal_unpack_4 (gfc_array_i4 * d, const GFC_INTEGER_4 * src) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type dsize; + GFC_INTEGER_4 *dest; + int n; + + dest = d->data; + if (src == dest || !src) + return; + + if (d->dim[0].stride == 0) + d->dim[0].stride = 1; + + dim = GFC_DESCRIPTOR_RANK (d); + dsize = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = d->dim[n].stride; + extent[n] = d->dim[n].ubound + 1 - d->dim[n].lbound; + if (extent[n] <= 0) + abort (); + + if (dsize == stride[n]) + dsize *= extent[n]; + else + dsize = 0; + } + + if (dsize != 0) + { + memcpy (dest, src, dsize * 4); + return; + } + + stride0 = stride[0]; + + while (dest) + { + /* Copy the data. */ + *dest = *(src++); + /* Advance to the next element. */ + dest += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + dest -= stride[n] * extent[n]; + n++; + if (n == dim) + { + dest = NULL; + break; + } + else + { + count[n]++; + dest += stride[n]; + } + } + } +} + diff --git a/libgfortran/generated/in_unpack_i8.c b/libgfortran/generated/in_unpack_i8.c new file mode 100644 index 00000000000..962c05b6caa --- /dev/null +++ b/libgfortran/generated/in_unpack_i8.c @@ -0,0 +1,102 @@ +/* Helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +internal_unpack_8 (gfc_array_i8 * d, const GFC_INTEGER_8 * src) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type dsize; + GFC_INTEGER_8 *dest; + int n; + + dest = d->data; + if (src == dest || !src) + return; + + if (d->dim[0].stride == 0) + d->dim[0].stride = 1; + + dim = GFC_DESCRIPTOR_RANK (d); + dsize = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = d->dim[n].stride; + extent[n] = d->dim[n].ubound + 1 - d->dim[n].lbound; + if (extent[n] <= 0) + abort (); + + if (dsize == stride[n]) + dsize *= extent[n]; + else + dsize = 0; + } + + if (dsize != 0) + { + memcpy (dest, src, dsize * 8); + return; + } + + stride0 = stride[0]; + + while (dest) + { + /* Copy the data. */ + *dest = *(src++); + /* Advance to the next element. */ + dest += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + dest -= stride[n] * extent[n]; + n++; + if (n == dim) + { + dest = NULL; + break; + } + else + { + count[n]++; + dest += stride[n]; + } + } + } +} + diff --git a/libgfortran/generated/matmul_c4.c b/libgfortran/generated/matmul_c4.c new file mode 100644 index 00000000000..beb4453024e --- /dev/null +++ b/libgfortran/generated/matmul_c4.c @@ -0,0 +1,138 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_c4 (gfc_array_c4 * retarray, gfc_array_c4 * a, gfc_array_c4 * b) +{ + GFC_COMPLEX_4 *abase; + GFC_COMPLEX_4 *bbase; + GFC_COMPLEX_4 *dest; + GFC_COMPLEX_4 res; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_COMPLEX_4 *pa; + GFC_COMPLEX_4 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + bbase = b->data; + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + res = 0; + + for (n = 0; n < count; n++) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + *dest = res; + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/matmul_c8.c b/libgfortran/generated/matmul_c8.c new file mode 100644 index 00000000000..a306764d4b9 --- /dev/null +++ b/libgfortran/generated/matmul_c8.c @@ -0,0 +1,138 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_c8 (gfc_array_c8 * retarray, gfc_array_c8 * a, gfc_array_c8 * b) +{ + GFC_COMPLEX_8 *abase; + GFC_COMPLEX_8 *bbase; + GFC_COMPLEX_8 *dest; + GFC_COMPLEX_8 res; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_COMPLEX_8 *pa; + GFC_COMPLEX_8 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + bbase = b->data; + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + res = 0; + + for (n = 0; n < count; n++) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + *dest = res; + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/matmul_i4.c b/libgfortran/generated/matmul_i4.c new file mode 100644 index 00000000000..44b30a4e140 --- /dev/null +++ b/libgfortran/generated/matmul_i4.c @@ -0,0 +1,138 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_i4 (gfc_array_i4 * retarray, gfc_array_i4 * a, gfc_array_i4 * b) +{ + GFC_INTEGER_4 *abase; + GFC_INTEGER_4 *bbase; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 res; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_INTEGER_4 *pa; + GFC_INTEGER_4 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + bbase = b->data; + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + res = 0; + + for (n = 0; n < count; n++) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + *dest = res; + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/matmul_i8.c b/libgfortran/generated/matmul_i8.c new file mode 100644 index 00000000000..1ca78276478 --- /dev/null +++ b/libgfortran/generated/matmul_i8.c @@ -0,0 +1,138 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_i8 (gfc_array_i8 * retarray, gfc_array_i8 * a, gfc_array_i8 * b) +{ + GFC_INTEGER_8 *abase; + GFC_INTEGER_8 *bbase; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 res; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_INTEGER_8 *pa; + GFC_INTEGER_8 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + bbase = b->data; + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + res = 0; + + for (n = 0; n < count; n++) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + *dest = res; + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/matmul_l4.c b/libgfortran/generated/matmul_l4.c new file mode 100644 index 00000000000..f141b651000 --- /dev/null +++ b/libgfortran/generated/matmul_l4.c @@ -0,0 +1,151 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_l4 (gfc_array_l4 * retarray, gfc_array_l4 * a, gfc_array_l4 * b) +{ + GFC_INTEGER_4 *abase; + GFC_INTEGER_4 *bbase; + GFC_LOGICAL_4 *dest; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_INTEGER_4 *pa; + GFC_INTEGER_4 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + if (GFC_DESCRIPTOR_SIZE (a) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (a) == 8); + abase = GFOR_POINTER_L8_TO_L4 (abase); + astride <<= 1; + } + bbase = b->data; + if (GFC_DESCRIPTOR_SIZE (b) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (b) == 8); + bbase = GFOR_POINTER_L8_TO_L4 (bbase); + bstride <<= 1; + } + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + *dest = 0; + + for (n = 0; n < count; n++) + { + if (*pa && *pb) + { + *dest = 1; + break; + } + pa += astride; + pb += bstride; + } + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/matmul_l8.c b/libgfortran/generated/matmul_l8.c new file mode 100644 index 00000000000..49243afd9ad --- /dev/null +++ b/libgfortran/generated/matmul_l8.c @@ -0,0 +1,151 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_l8 (gfc_array_l8 * retarray, gfc_array_l4 * a, gfc_array_l4 * b) +{ + GFC_INTEGER_4 *abase; + GFC_INTEGER_4 *bbase; + GFC_LOGICAL_8 *dest; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_INTEGER_4 *pa; + GFC_INTEGER_4 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + if (GFC_DESCRIPTOR_SIZE (a) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (a) == 8); + abase = GFOR_POINTER_L8_TO_L4 (abase); + astride <<= 1; + } + bbase = b->data; + if (GFC_DESCRIPTOR_SIZE (b) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (b) == 8); + bbase = GFOR_POINTER_L8_TO_L4 (bbase); + bstride <<= 1; + } + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + *dest = 0; + + for (n = 0; n < count; n++) + { + if (*pa && *pb) + { + *dest = 1; + break; + } + pa += astride; + pb += bstride; + } + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/matmul_r4.c b/libgfortran/generated/matmul_r4.c new file mode 100644 index 00000000000..dea706bb7d1 --- /dev/null +++ b/libgfortran/generated/matmul_r4.c @@ -0,0 +1,138 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_r4 (gfc_array_r4 * retarray, gfc_array_r4 * a, gfc_array_r4 * b) +{ + GFC_REAL_4 *abase; + GFC_REAL_4 *bbase; + GFC_REAL_4 *dest; + GFC_REAL_4 res; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_REAL_4 *pa; + GFC_REAL_4 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + bbase = b->data; + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + res = 0; + + for (n = 0; n < count; n++) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + *dest = res; + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/matmul_r8.c b/libgfortran/generated/matmul_r8.c new file mode 100644 index 00000000000..dfe4841615a --- /dev/null +++ b/libgfortran/generated/matmul_r8.c @@ -0,0 +1,138 @@ +/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +__matmul_r8 (gfc_array_r8 * retarray, gfc_array_r8 * a, gfc_array_r8 * b) +{ + GFC_REAL_8 *abase; + GFC_REAL_8 *bbase; + GFC_REAL_8 *dest; + GFC_REAL_8 res; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_REAL_8 *pa; + GFC_REAL_8 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + bbase = b->data; + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + res = 0; + + for (n = 0; n < count; n++) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + *dest = res; + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/generated/maxloc0_4_i4.c b/libgfortran/generated/maxloc0_4_i4.c new file mode 100644 index 00000000000..94f6f4f7080 --- /dev/null +++ b/libgfortran/generated/maxloc0_4_i4.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 maxval; + + maxval = -GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 maxval; + + maxval = -GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc0_4_i8.c b/libgfortran/generated/maxloc0_4_i8.c new file mode 100644 index 00000000000..f5fb1ea55db --- /dev/null +++ b/libgfortran/generated/maxloc0_4_i8.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 maxval; + + maxval = -GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 maxval; + + maxval = -GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc0_4_r4.c b/libgfortran/generated/maxloc0_4_r4.c new file mode 100644 index 00000000000..cb77fa6eeca --- /dev/null +++ b/libgfortran/generated/maxloc0_4_r4.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 maxval; + + maxval = -GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 maxval; + + maxval = -GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc0_4_r8.c b/libgfortran/generated/maxloc0_4_r8.c new file mode 100644 index 00000000000..9491823b908 --- /dev/null +++ b/libgfortran/generated/maxloc0_4_r8.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 maxval; + + maxval = -GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 maxval; + + maxval = -GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc0_8_i4.c b/libgfortran/generated/maxloc0_8_i4.c new file mode 100644 index 00000000000..c851bc408e9 --- /dev/null +++ b/libgfortran/generated/maxloc0_8_i4.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 maxval; + + maxval = -GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 maxval; + + maxval = -GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc0_8_i8.c b/libgfortran/generated/maxloc0_8_i8.c new file mode 100644 index 00000000000..6a151a22073 --- /dev/null +++ b/libgfortran/generated/maxloc0_8_i8.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 maxval; + + maxval = -GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 maxval; + + maxval = -GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc0_8_r4.c b/libgfortran/generated/maxloc0_8_r4.c new file mode 100644 index 00000000000..dc4d3b6cff5 --- /dev/null +++ b/libgfortran/generated/maxloc0_8_r4.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 maxval; + + maxval = -GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 maxval; + + maxval = -GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc0_8_r8.c b/libgfortran/generated/maxloc0_8_r8.c new file mode 100644 index 00000000000..00525645460 --- /dev/null +++ b/libgfortran/generated/maxloc0_8_r8.c @@ -0,0 +1,230 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__maxloc0_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 maxval; + + maxval = -GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mmaxloc0_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 maxval; + + maxval = -GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/maxloc1_4_i4.c b/libgfortran/generated/maxloc1_4_i4.c new file mode 100644 index 00000000000..4f412099412 --- /dev/null +++ b/libgfortran/generated/maxloc1_4_i4.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_INTEGER_4 maxval; + maxval = -GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_4 maxval; + maxval = -GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxloc1_4_i8.c b/libgfortran/generated/maxloc1_4_i8.c new file mode 100644 index 00000000000..f5dd241d7b7 --- /dev/null +++ b/libgfortran/generated/maxloc1_4_i8.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_INTEGER_8 maxval; + maxval = -GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_8 maxval; + maxval = -GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxloc1_4_r4.c b/libgfortran/generated/maxloc1_4_r4.c new file mode 100644 index 00000000000..503cf6ad201 --- /dev/null +++ b/libgfortran/generated/maxloc1_4_r4.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_REAL_4 maxval; + maxval = -GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_REAL_4 maxval; + maxval = -GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxloc1_4_r8.c b/libgfortran/generated/maxloc1_4_r8.c new file mode 100644 index 00000000000..08445db76e9 --- /dev/null +++ b/libgfortran/generated/maxloc1_4_r8.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_REAL_8 maxval; + maxval = -GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_REAL_8 maxval; + maxval = -GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxloc1_8_i4.c b/libgfortran/generated/maxloc1_8_i4.c new file mode 100644 index 00000000000..5ec2525a9c2 --- /dev/null +++ b/libgfortran/generated/maxloc1_8_i4.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_INTEGER_4 maxval; + maxval = -GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_4 maxval; + maxval = -GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxloc1_8_i8.c b/libgfortran/generated/maxloc1_8_i8.c new file mode 100644 index 00000000000..8f7203b8654 --- /dev/null +++ b/libgfortran/generated/maxloc1_8_i8.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_INTEGER_8 maxval; + maxval = -GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_8 maxval; + maxval = -GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxloc1_8_r4.c b/libgfortran/generated/maxloc1_8_r4.c new file mode 100644 index 00000000000..2e80e4b3429 --- /dev/null +++ b/libgfortran/generated/maxloc1_8_r4.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_REAL_4 maxval; + maxval = -GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_REAL_4 maxval; + maxval = -GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxloc1_8_r8.c b/libgfortran/generated/maxloc1_8_r8.c new file mode 100644 index 00000000000..611ef048564 --- /dev/null +++ b/libgfortran/generated/maxloc1_8_r8.c @@ -0,0 +1,266 @@ +/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__maxloc1_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_REAL_8 maxval; + maxval = -GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxloc1_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_REAL_8 maxval; + maxval = -GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > maxval) + { + maxval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxval_i4.c b/libgfortran/generated/maxval_i4.c new file mode 100644 index 00000000000..78802553c25 --- /dev/null +++ b/libgfortran/generated/maxval_i4.c @@ -0,0 +1,255 @@ +/* Implementation of the MAXVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__maxval_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + result = -GFC_INTEGER_4_HUGE; + if (len <= 0) + *dest = -GFC_INTEGER_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxval_i4 (gfc_array_i4 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + result = -GFC_INTEGER_4_HUGE; + if (len <= 0) + *dest = -GFC_INTEGER_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxval_i8.c b/libgfortran/generated/maxval_i8.c new file mode 100644 index 00000000000..af433ea5dc2 --- /dev/null +++ b/libgfortran/generated/maxval_i8.c @@ -0,0 +1,255 @@ +/* Implementation of the MAXVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__maxval_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + result = -GFC_INTEGER_8_HUGE; + if (len <= 0) + *dest = -GFC_INTEGER_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxval_i8 (gfc_array_i8 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + result = -GFC_INTEGER_8_HUGE; + if (len <= 0) + *dest = -GFC_INTEGER_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxval_r4.c b/libgfortran/generated/maxval_r4.c new file mode 100644 index 00000000000..3877b323b0f --- /dev/null +++ b/libgfortran/generated/maxval_r4.c @@ -0,0 +1,255 @@ +/* Implementation of the MAXVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__maxval_r4 (gfc_array_r4 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_REAL_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_REAL_4 result; + src = base; + { + + result = -GFC_REAL_4_HUGE; + if (len <= 0) + *dest = -GFC_REAL_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxval_r4 (gfc_array_r4 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_4 result; + src = base; + msrc = mbase; + { + + result = -GFC_REAL_4_HUGE; + if (len <= 0) + *dest = -GFC_REAL_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/maxval_r8.c b/libgfortran/generated/maxval_r8.c new file mode 100644 index 00000000000..b5c01062e6a --- /dev/null +++ b/libgfortran/generated/maxval_r8.c @@ -0,0 +1,255 @@ +/* Implementation of the MAXVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__maxval_r8 (gfc_array_r8 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_REAL_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_REAL_8 result; + src = base; + { + + result = -GFC_REAL_8_HUGE; + if (len <= 0) + *dest = -GFC_REAL_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mmaxval_r8 (gfc_array_r8 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_8 result; + src = base; + msrc = mbase; + { + + result = -GFC_REAL_8_HUGE; + if (len <= 0) + *dest = -GFC_REAL_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src > result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc0_4_i4.c b/libgfortran/generated/minloc0_4_i4.c new file mode 100644 index 00000000000..5407f4cb63c --- /dev/null +++ b/libgfortran/generated/minloc0_4_i4.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 minval; + + minval = GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 minval; + + minval = GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc0_4_i8.c b/libgfortran/generated/minloc0_4_i8.c new file mode 100644 index 00000000000..b0c58293eb8 --- /dev/null +++ b/libgfortran/generated/minloc0_4_i8.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 minval; + + minval = GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 minval; + + minval = GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc0_4_r4.c b/libgfortran/generated/minloc0_4_r4.c new file mode 100644 index 00000000000..175f9c8967b --- /dev/null +++ b/libgfortran/generated/minloc0_4_r4.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 minval; + + minval = GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 minval; + + minval = GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc0_4_r8.c b/libgfortran/generated/minloc0_4_r8.c new file mode 100644 index 00000000000..01f44a570f5 --- /dev/null +++ b/libgfortran/generated/minloc0_4_r8.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 minval; + + minval = GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 minval; + + minval = GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc0_8_i4.c b/libgfortran/generated/minloc0_8_i4.c new file mode 100644 index 00000000000..0d4410338d7 --- /dev/null +++ b/libgfortran/generated/minloc0_8_i4.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 minval; + + minval = GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_4 minval; + + minval = GFC_INTEGER_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc0_8_i8.c b/libgfortran/generated/minloc0_8_i8.c new file mode 100644 index 00000000000..83ef0399dac --- /dev/null +++ b/libgfortran/generated/minloc0_8_i8.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 minval; + + minval = GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_INTEGER_8 minval; + + minval = GFC_INTEGER_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc0_8_r4.c b/libgfortran/generated/minloc0_8_r4.c new file mode 100644 index 00000000000..36868e40333 --- /dev/null +++ b/libgfortran/generated/minloc0_8_r4.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 minval; + + minval = GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_4 minval; + + minval = GFC_REAL_4_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc0_8_r8.c b/libgfortran/generated/minloc0_8_r8.c new file mode 100644 index 00000000000..5f0c48a68ae --- /dev/null +++ b/libgfortran/generated/minloc0_8_r8.c @@ -0,0 +1,230 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + + +void +__minloc0_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_REAL_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 minval; + + minval = GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +} + +void +__mminloc0_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + GFC_INTEGER_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { + + GFC_REAL_8 minval; + + minval = GFC_REAL_8_HUGE; + + while (base) + { + { + /* Implementation start. */ + + if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + } + /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +} diff --git a/libgfortran/generated/minloc1_4_i4.c b/libgfortran/generated/minloc1_4_i4.c new file mode 100644 index 00000000000..b3e56f0cc60 --- /dev/null +++ b/libgfortran/generated/minloc1_4_i4.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_INTEGER_4 minval; + minval = GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_4_i4 (gfc_array_i4 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_4 minval; + minval = GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc1_4_i8.c b/libgfortran/generated/minloc1_4_i8.c new file mode 100644 index 00000000000..b2fce929561 --- /dev/null +++ b/libgfortran/generated/minloc1_4_i8.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_INTEGER_8 minval; + minval = GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_4_i8 (gfc_array_i4 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_8 minval; + minval = GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc1_4_r4.c b/libgfortran/generated/minloc1_4_r4.c new file mode 100644 index 00000000000..d7f9ff6a627 --- /dev/null +++ b/libgfortran/generated/minloc1_4_r4.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_REAL_4 minval; + minval = GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_4_r4 (gfc_array_i4 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_REAL_4 minval; + minval = GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc1_4_r8.c b/libgfortran/generated/minloc1_4_r8.c new file mode 100644 index 00000000000..66146ae5d8b --- /dev/null +++ b/libgfortran/generated/minloc1_4_r8.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_INTEGER_4 result; + src = base; + { + + GFC_REAL_8 minval; + minval = GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_4_r8 (gfc_array_i4 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + GFC_REAL_8 minval; + minval = GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_4)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc1_8_i4.c b/libgfortran/generated/minloc1_8_i4.c new file mode 100644 index 00000000000..a5edad58492 --- /dev/null +++ b/libgfortran/generated/minloc1_8_i4.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_INTEGER_4 minval; + minval = GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_8_i4 (gfc_array_i8 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_4 minval; + minval = GFC_INTEGER_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc1_8_i8.c b/libgfortran/generated/minloc1_8_i8.c new file mode 100644 index 00000000000..55f1ce268f0 --- /dev/null +++ b/libgfortran/generated/minloc1_8_i8.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_INTEGER_8 minval; + minval = GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_8_i8 (gfc_array_i8 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_INTEGER_8 minval; + minval = GFC_INTEGER_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc1_8_r4.c b/libgfortran/generated/minloc1_8_r4.c new file mode 100644 index 00000000000..3f7eb16bf78 --- /dev/null +++ b/libgfortran/generated/minloc1_8_r4.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_REAL_4 minval; + minval = GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_8_r4 (gfc_array_i8 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_REAL_4 minval; + minval = GFC_REAL_4_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minloc1_8_r8.c b/libgfortran/generated/minloc1_8_r8.c new file mode 100644 index 00000000000..19cb41d7acc --- /dev/null +++ b/libgfortran/generated/minloc1_8_r8.c @@ -0,0 +1,266 @@ +/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" + + +void +__minloc1_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + GFC_REAL_8 minval; + minval = GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminloc1_8_r8 (gfc_array_i8 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + GFC_REAL_8 minval; + minval = GFC_REAL_8_HUGE; + result = 1; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < minval) + { + minval = *src; + result = (GFC_INTEGER_8)n + 1; + } + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minval_i4.c b/libgfortran/generated/minval_i4.c new file mode 100644 index 00000000000..0bd7f5698c1 --- /dev/null +++ b/libgfortran/generated/minval_i4.c @@ -0,0 +1,255 @@ +/* Implementation of the MINVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__minval_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + result = GFC_INTEGER_4_HUGE; + if (len <= 0) + *dest = GFC_INTEGER_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminval_i4 (gfc_array_i4 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + result = GFC_INTEGER_4_HUGE; + if (len <= 0) + *dest = GFC_INTEGER_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minval_i8.c b/libgfortran/generated/minval_i8.c new file mode 100644 index 00000000000..7f686f33658 --- /dev/null +++ b/libgfortran/generated/minval_i8.c @@ -0,0 +1,255 @@ +/* Implementation of the MINVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__minval_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + result = GFC_INTEGER_8_HUGE; + if (len <= 0) + *dest = GFC_INTEGER_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminval_i8 (gfc_array_i8 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + result = GFC_INTEGER_8_HUGE; + if (len <= 0) + *dest = GFC_INTEGER_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minval_r4.c b/libgfortran/generated/minval_r4.c new file mode 100644 index 00000000000..2ea19e451d3 --- /dev/null +++ b/libgfortran/generated/minval_r4.c @@ -0,0 +1,255 @@ +/* Implementation of the MINVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__minval_r4 (gfc_array_r4 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_REAL_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_REAL_4 result; + src = base; + { + + result = GFC_REAL_4_HUGE; + if (len <= 0) + *dest = GFC_REAL_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminval_r4 (gfc_array_r4 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_4 result; + src = base; + msrc = mbase; + { + + result = GFC_REAL_4_HUGE; + if (len <= 0) + *dest = GFC_REAL_4_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/minval_r8.c b/libgfortran/generated/minval_r8.c new file mode 100644 index 00000000000..4ed8ce1d0aa --- /dev/null +++ b/libgfortran/generated/minval_r8.c @@ -0,0 +1,255 @@ +/* Implementation of the MINVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + + +void +__minval_r8 (gfc_array_r8 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_REAL_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_REAL_8 result; + src = base; + { + + result = GFC_REAL_8_HUGE; + if (len <= 0) + *dest = GFC_REAL_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta) + { + + if (*src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mminval_r8 (gfc_array_r8 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_8 result; + src = base; + msrc = mbase; + { + + result = GFC_REAL_8_HUGE; + if (len <= 0) + *dest = GFC_REAL_8_HUGE; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc && *src < result) + result = *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/nearest_r4.c b/libgfortran/generated/nearest_r4.c new file mode 100644 index 00000000000..cafc02f21f2 --- /dev/null +++ b/libgfortran/generated/nearest_r4.c @@ -0,0 +1,38 @@ +/* Implementation of the NEAREST intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include +#include "libgfortran.h" + + +GFC_REAL_4 +prefix(nearest_r4) (GFC_REAL_4 s, GFC_REAL_4 dir) +{ + dir = copysignf (__builtin_inff (), dir); + if (FLT_EVAL_METHOD != 0) + { + /* ??? Work around glibc bug on x86. */ + volatile GFC_REAL_4 r = nextafterf (s, dir); + return r; + } + else + return nextafterf (s, dir); +} diff --git a/libgfortran/generated/nearest_r8.c b/libgfortran/generated/nearest_r8.c new file mode 100644 index 00000000000..54a374546df --- /dev/null +++ b/libgfortran/generated/nearest_r8.c @@ -0,0 +1,38 @@ +/* Implementation of the NEAREST intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include +#include "libgfortran.h" + + +GFC_REAL_8 +prefix(nearest_r8) (GFC_REAL_8 s, GFC_REAL_8 dir) +{ + dir = copysign (__builtin_inf (), dir); + if (FLT_EVAL_METHOD != 0) + { + /* ??? Work around glibc bug on x86. */ + volatile GFC_REAL_8 r = nextafter (s, dir); + return r; + } + else + return nextafter (s, dir); +} diff --git a/libgfortran/generated/product_c4.c b/libgfortran/generated/product_c4.c new file mode 100644 index 00000000000..b12a047d7a6 --- /dev/null +++ b/libgfortran/generated/product_c4.c @@ -0,0 +1,253 @@ +/* Implementation of the PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__product_c4 (gfc_array_c4 * retarray, gfc_array_c4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_4 *base; + GFC_COMPLEX_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_COMPLEX_4 *src; + GFC_COMPLEX_4 result; + src = base; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mproduct_c4 (gfc_array_c4 * retarray, gfc_array_c4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_4 *dest; + GFC_COMPLEX_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_COMPLEX_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_COMPLEX_4 result; + src = base; + msrc = mbase; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/product_c8.c b/libgfortran/generated/product_c8.c new file mode 100644 index 00000000000..6e88972109a --- /dev/null +++ b/libgfortran/generated/product_c8.c @@ -0,0 +1,253 @@ +/* Implementation of the PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__product_c8 (gfc_array_c8 * retarray, gfc_array_c8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_8 *base; + GFC_COMPLEX_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_COMPLEX_8 *src; + GFC_COMPLEX_8 result; + src = base; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mproduct_c8 (gfc_array_c8 * retarray, gfc_array_c8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_8 *dest; + GFC_COMPLEX_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_COMPLEX_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_COMPLEX_8 result; + src = base; + msrc = mbase; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/product_i4.c b/libgfortran/generated/product_i4.c new file mode 100644 index 00000000000..229087f6941 --- /dev/null +++ b/libgfortran/generated/product_i4.c @@ -0,0 +1,253 @@ +/* Implementation of the PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__product_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mproduct_i4 (gfc_array_i4 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/product_i8.c b/libgfortran/generated/product_i8.c new file mode 100644 index 00000000000..16ef0a05b3c --- /dev/null +++ b/libgfortran/generated/product_i8.c @@ -0,0 +1,253 @@ +/* Implementation of the PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__product_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mproduct_i8 (gfc_array_i8 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/product_r4.c b/libgfortran/generated/product_r4.c new file mode 100644 index 00000000000..5761b2ed86d --- /dev/null +++ b/libgfortran/generated/product_r4.c @@ -0,0 +1,253 @@ +/* Implementation of the PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__product_r4 (gfc_array_r4 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_REAL_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_REAL_4 result; + src = base; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mproduct_r4 (gfc_array_r4 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_4 result; + src = base; + msrc = mbase; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/product_r8.c b/libgfortran/generated/product_r8.c new file mode 100644 index 00000000000..d00c970e61f --- /dev/null +++ b/libgfortran/generated/product_r8.c @@ -0,0 +1,253 @@ +/* Implementation of the PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__product_r8 (gfc_array_r8 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_REAL_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_REAL_8 result; + src = base; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__mproduct_r8 (gfc_array_r8 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_8 result; + src = base; + msrc = mbase; + { + + result = 1; + if (len <= 0) + *dest = 1; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result *= *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/reshape_i4.c b/libgfortran/generated/reshape_i4.c new file mode 100644 index 00000000000..7da866cf5d0 --- /dev/null +++ b/libgfortran/generated/reshape_i4.c @@ -0,0 +1,225 @@ +/* Implementation of the RESHAPE + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(1, index_type) shape_type; + +/* The shape parameter is ignored. We can currently deduce the shape from the + return array. */ +void +__reshape_4 (gfc_array_i4 * ret, gfc_array_i4 * source, shape_type * shape, + gfc_array_i4 * pad, shape_type * order) +{ + /* r.* indicates the return array. */ + index_type rcount[GFC_MAX_DIMENSIONS - 1]; + index_type rextent[GFC_MAX_DIMENSIONS - 1]; + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type rdim; + index_type rsize; + GFC_INTEGER_4 *rptr; + /* s.* indicates the source array. */ + index_type scount[GFC_MAX_DIMENSIONS - 1]; + index_type sextent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type sdim; + index_type ssize; + const GFC_INTEGER_4 *sptr; + /* p.* indicates the pad array. */ + index_type pcount[GFC_MAX_DIMENSIONS - 1]; + index_type pextent[GFC_MAX_DIMENSIONS - 1]; + index_type pstride[GFC_MAX_DIMENSIONS - 1]; + index_type pdim; + index_type psize; + const GFC_INTEGER_4 *pptr; + + const GFC_INTEGER_4 *src; + int n; + int dim; + + if (ret->dim[0].stride == 0) + ret->dim[0].stride = 1; + if (source->dim[0].stride == 0) + source->dim[0].stride = 1; + if (shape->dim[0].stride == 0) + shape->dim[0].stride = 1; + if (pad && pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + if (order && order->dim[0].stride == 0) + order->dim[0].stride = 1; + + rdim = GFC_DESCRIPTOR_RANK (ret); + rsize = 1; + for (n = 0; n < rdim; n++) + { + if (order) + dim = order->data[n * order->dim[0].stride] - 1; + else + dim = n; + + rcount[n] = 0; + rstride[n] = ret->dim[dim].stride; + rextent[n] = ret->dim[dim].ubound + 1 - ret->dim[dim].lbound; + + if (rextent[n] != shape->data[dim * shape->dim[0].stride]) + runtime_error ("shape and target do not conform"); + + if (rsize == rstride[n]) + rsize *= rextent[n]; + else + rsize = 0; + if (rextent[dim] <= 0) + return; + } + + sdim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + for (n = 0; n < sdim; n++) + { + scount[n] = 0; + sstride[n] = source->dim[n].stride; + sextent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (sextent[n] <= 0) + abort (); + + if (ssize == sstride[n]) + ssize *= sextent[n]; + else + ssize = 0; + } + + if (pad) + { + if (pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + pdim = GFC_DESCRIPTOR_RANK (pad); + psize = 1; + for (n = 0; n < pdim; n++) + { + pcount[n] = 0; + pstride[n] = pad->dim[n].stride; + pextent[n] = pad->dim[n].ubound + 1 - pad->dim[n].lbound; + if (pextent[n] <= 0) + abort (); + if (psize == pstride[n]) + psize *= pextent[n]; + else + psize = 0; + } + pptr = pad->data; + } + else + { + pdim = 0; + psize = 1; + pptr = NULL; + } + + if (rsize != 0 && ssize != 0 && psize != 0) + { + rsize *= 4; + ssize *= 4; + psize *= 4; + reshape_packed ((char *)ret->data, rsize, (char *)source->data, + ssize, pad ? (char *)pad->data : NULL, psize); + return; + } + rptr = ret->data; + src = sptr = source->data; + rstride0 = rstride[0]; + sstride0 = sstride[0]; + + while (rptr) + { + /* Select between the source and pad arrays. */ + *rptr = *src; + /* Advance to the next element. */ + rptr += rstride0; + src += sstride0; + rcount[0]++; + scount[0]++; + /* Advance to the next destination element. */ + n = 0; + while (rcount[n] == rextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + rcount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * rextent[n]; + n++; + if (n == rdim) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + rcount[n]++; + rptr += rstride[n]; + } + } + /* Advance to the next source element. */ + n = 0; + while (scount[n] == sextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + scount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= sstride[n] * sextent[n]; + n++; + if (n == sdim) + { + if (sptr && pad) + { + /* Switch to the pad array. */ + sptr = NULL; + sdim = pdim; + for (dim = 0; dim < pdim; dim++) + { + scount[dim] = pcount[dim]; + sextent[dim] = pextent[dim]; + sstride[dim] = pstride[dim]; + sstride0 = sstride[0]; + } + } + /* We now start again from the beginning of the pad array. */ + src = pptr; + break; + } + else + { + scount[n]++; + src += sstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/reshape_i8.c b/libgfortran/generated/reshape_i8.c new file mode 100644 index 00000000000..f4e40197d82 --- /dev/null +++ b/libgfortran/generated/reshape_i8.c @@ -0,0 +1,225 @@ +/* Implementation of the RESHAPE + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(1, index_type) shape_type; + +/* The shape parameter is ignored. We can currently deduce the shape from the + return array. */ +void +__reshape_8 (gfc_array_i8 * ret, gfc_array_i8 * source, shape_type * shape, + gfc_array_i8 * pad, shape_type * order) +{ + /* r.* indicates the return array. */ + index_type rcount[GFC_MAX_DIMENSIONS - 1]; + index_type rextent[GFC_MAX_DIMENSIONS - 1]; + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type rdim; + index_type rsize; + GFC_INTEGER_8 *rptr; + /* s.* indicates the source array. */ + index_type scount[GFC_MAX_DIMENSIONS - 1]; + index_type sextent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type sdim; + index_type ssize; + const GFC_INTEGER_8 *sptr; + /* p.* indicates the pad array. */ + index_type pcount[GFC_MAX_DIMENSIONS - 1]; + index_type pextent[GFC_MAX_DIMENSIONS - 1]; + index_type pstride[GFC_MAX_DIMENSIONS - 1]; + index_type pdim; + index_type psize; + const GFC_INTEGER_8 *pptr; + + const GFC_INTEGER_8 *src; + int n; + int dim; + + if (ret->dim[0].stride == 0) + ret->dim[0].stride = 1; + if (source->dim[0].stride == 0) + source->dim[0].stride = 1; + if (shape->dim[0].stride == 0) + shape->dim[0].stride = 1; + if (pad && pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + if (order && order->dim[0].stride == 0) + order->dim[0].stride = 1; + + rdim = GFC_DESCRIPTOR_RANK (ret); + rsize = 1; + for (n = 0; n < rdim; n++) + { + if (order) + dim = order->data[n * order->dim[0].stride] - 1; + else + dim = n; + + rcount[n] = 0; + rstride[n] = ret->dim[dim].stride; + rextent[n] = ret->dim[dim].ubound + 1 - ret->dim[dim].lbound; + + if (rextent[n] != shape->data[dim * shape->dim[0].stride]) + runtime_error ("shape and target do not conform"); + + if (rsize == rstride[n]) + rsize *= rextent[n]; + else + rsize = 0; + if (rextent[dim] <= 0) + return; + } + + sdim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + for (n = 0; n < sdim; n++) + { + scount[n] = 0; + sstride[n] = source->dim[n].stride; + sextent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (sextent[n] <= 0) + abort (); + + if (ssize == sstride[n]) + ssize *= sextent[n]; + else + ssize = 0; + } + + if (pad) + { + if (pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + pdim = GFC_DESCRIPTOR_RANK (pad); + psize = 1; + for (n = 0; n < pdim; n++) + { + pcount[n] = 0; + pstride[n] = pad->dim[n].stride; + pextent[n] = pad->dim[n].ubound + 1 - pad->dim[n].lbound; + if (pextent[n] <= 0) + abort (); + if (psize == pstride[n]) + psize *= pextent[n]; + else + psize = 0; + } + pptr = pad->data; + } + else + { + pdim = 0; + psize = 1; + pptr = NULL; + } + + if (rsize != 0 && ssize != 0 && psize != 0) + { + rsize *= 8; + ssize *= 8; + psize *= 8; + reshape_packed ((char *)ret->data, rsize, (char *)source->data, + ssize, pad ? (char *)pad->data : NULL, psize); + return; + } + rptr = ret->data; + src = sptr = source->data; + rstride0 = rstride[0]; + sstride0 = sstride[0]; + + while (rptr) + { + /* Select between the source and pad arrays. */ + *rptr = *src; + /* Advance to the next element. */ + rptr += rstride0; + src += sstride0; + rcount[0]++; + scount[0]++; + /* Advance to the next destination element. */ + n = 0; + while (rcount[n] == rextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + rcount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * rextent[n]; + n++; + if (n == rdim) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + rcount[n]++; + rptr += rstride[n]; + } + } + /* Advance to the next source element. */ + n = 0; + while (scount[n] == sextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + scount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= sstride[n] * sextent[n]; + n++; + if (n == sdim) + { + if (sptr && pad) + { + /* Switch to the pad array. */ + sptr = NULL; + sdim = pdim; + for (dim = 0; dim < pdim; dim++) + { + scount[dim] = pcount[dim]; + sextent[dim] = pextent[dim]; + sstride[dim] = pstride[dim]; + sstride0 = sstride[0]; + } + } + /* We now start again from the beginning of the pad array. */ + src = pptr; + break; + } + else + { + scount[n]++; + src += sstride[n]; + } + } + } +} + diff --git a/libgfortran/generated/set_exponent_r4.c b/libgfortran/generated/set_exponent_r4.c new file mode 100644 index 00000000000..32717e22305 --- /dev/null +++ b/libgfortran/generated/set_exponent_r4.c @@ -0,0 +1,30 @@ +/* Implementation of the SET_EXPONENT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +GFC_REAL_4 +prefix(set_exponent_r4) (GFC_REAL_4 s, GFC_INTEGER_4 i) +{ + int dummy_exp; + return scalbnf (frexpf (s, &dummy_exp), i); +} diff --git a/libgfortran/generated/set_exponent_r8.c b/libgfortran/generated/set_exponent_r8.c new file mode 100644 index 00000000000..ad2a97d837b --- /dev/null +++ b/libgfortran/generated/set_exponent_r8.c @@ -0,0 +1,30 @@ +/* Implementation of the SET_EXPONENT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +GFC_REAL_8 +prefix(set_exponent_r8) (GFC_REAL_8 s, GFC_INTEGER_4 i) +{ + int dummy_exp; + return scalbn (frexp (s, &dummy_exp), i); +} diff --git a/libgfortran/generated/shape_i4.c b/libgfortran/generated/shape_i4.c new file mode 100644 index 00000000000..03446912f61 --- /dev/null +++ b/libgfortran/generated/shape_i4.c @@ -0,0 +1,43 @@ +/* Implementation of the SHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +void +__shape_4 (gfc_array_i4 * ret, const gfc_array_i4 * array) +{ + int n; + index_type stride; + + stride = ret->dim[0].stride; + if (stride == 0) + stride = 1; + + for (n = 0; n < GFC_DESCRIPTOR_RANK (array); n++) + { + ret->data[n * stride] = + array->dim[n].ubound + 1 - array->dim[n].lbound; + } +} + diff --git a/libgfortran/generated/shape_i8.c b/libgfortran/generated/shape_i8.c new file mode 100644 index 00000000000..bd7490016ae --- /dev/null +++ b/libgfortran/generated/shape_i8.c @@ -0,0 +1,43 @@ +/* Implementation of the SHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + +void +__shape_8 (gfc_array_i8 * ret, const gfc_array_i8 * array) +{ + int n; + index_type stride; + + stride = ret->dim[0].stride; + if (stride == 0) + stride = 1; + + for (n = 0; n < GFC_DESCRIPTOR_RANK (array); n++) + { + ret->data[n * stride] = + array->dim[n].ubound + 1 - array->dim[n].lbound; + } +} + diff --git a/libgfortran/generated/sum_c4.c b/libgfortran/generated/sum_c4.c new file mode 100644 index 00000000000..a6e05b2a4c9 --- /dev/null +++ b/libgfortran/generated/sum_c4.c @@ -0,0 +1,252 @@ +/* Implementation of the SUM intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__sum_c4 (gfc_array_c4 * retarray, gfc_array_c4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_4 *base; + GFC_COMPLEX_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_COMPLEX_4 *src; + GFC_COMPLEX_4 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__msum_c4 (gfc_array_c4 * retarray, gfc_array_c4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_4 *dest; + GFC_COMPLEX_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_COMPLEX_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_COMPLEX_4 result; + src = base; + msrc = mbase; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} diff --git a/libgfortran/generated/sum_c8.c b/libgfortran/generated/sum_c8.c new file mode 100644 index 00000000000..f65002a091b --- /dev/null +++ b/libgfortran/generated/sum_c8.c @@ -0,0 +1,252 @@ +/* Implementation of the SUM intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__sum_c8 (gfc_array_c8 * retarray, gfc_array_c8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_8 *base; + GFC_COMPLEX_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_COMPLEX_8 *src; + GFC_COMPLEX_8 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__msum_c8 (gfc_array_c8 * retarray, gfc_array_c8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_COMPLEX_8 *dest; + GFC_COMPLEX_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_COMPLEX_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_COMPLEX_8 result; + src = base; + msrc = mbase; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} diff --git a/libgfortran/generated/sum_i4.c b/libgfortran/generated/sum_i4.c new file mode 100644 index 00000000000..a15e0d4804f --- /dev/null +++ b/libgfortran/generated/sum_i4.c @@ -0,0 +1,252 @@ +/* Implementation of the SUM intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__sum_i4 (gfc_array_i4 * retarray, gfc_array_i4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *base; + GFC_INTEGER_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_4 *src; + GFC_INTEGER_4 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__msum_i4 (gfc_array_i4 * retarray, gfc_array_i4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_4 *dest; + GFC_INTEGER_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_4 result; + src = base; + msrc = mbase; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} diff --git a/libgfortran/generated/sum_i8.c b/libgfortran/generated/sum_i8.c new file mode 100644 index 00000000000..2ad5f4ac822 --- /dev/null +++ b/libgfortran/generated/sum_i8.c @@ -0,0 +1,252 @@ +/* Implementation of the SUM intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__sum_i8 (gfc_array_i8 * retarray, gfc_array_i8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *base; + GFC_INTEGER_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_INTEGER_8 *src; + GFC_INTEGER_8 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__msum_i8 (gfc_array_i8 * retarray, gfc_array_i8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_INTEGER_8 *dest; + GFC_INTEGER_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_INTEGER_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_INTEGER_8 result; + src = base; + msrc = mbase; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} diff --git a/libgfortran/generated/sum_r4.c b/libgfortran/generated/sum_r4.c new file mode 100644 index 00000000000..3b637183256 --- /dev/null +++ b/libgfortran/generated/sum_r4.c @@ -0,0 +1,252 @@ +/* Implementation of the SUM intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__sum_r4 (gfc_array_r4 * retarray, gfc_array_r4 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *base; + GFC_REAL_4 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_4 *src; + GFC_REAL_4 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__msum_r4 (gfc_array_r4 * retarray, gfc_array_r4 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_4 *dest; + GFC_REAL_4 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_4 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_4 result; + src = base; + msrc = mbase; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} diff --git a/libgfortran/generated/sum_r8.c b/libgfortran/generated/sum_r8.c new file mode 100644 index 00000000000..3aa550bbe8f --- /dev/null +++ b/libgfortran/generated/sum_r8.c @@ -0,0 +1,252 @@ +/* Implementation of the SUM intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" + + +void +__sum_r8 (gfc_array_r8 * retarray, gfc_array_r8 *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *base; + GFC_REAL_8 *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + GFC_REAL_8 *src; + GFC_REAL_8 result; + src = base; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta) + { + + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +} + +void +__msum_r8 (gfc_array_r8 * retarray, gfc_array_r8 * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + GFC_REAL_8 *dest; + GFC_REAL_8 *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + GFC_REAL_8 *src; + GFC_LOGICAL_4 *msrc; + GFC_REAL_8 result; + src = base; + msrc = mbase; + { + + result = 0; + if (len <= 0) + *dest = 0; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { + + if (*msrc) + result += *src; + } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +} diff --git a/libgfortran/generated/transpose_i4.c b/libgfortran/generated/transpose_i4.c new file mode 100644 index 00000000000..184243f21d4 --- /dev/null +++ b/libgfortran/generated/transpose_i4.c @@ -0,0 +1,69 @@ +/* Implementation of the TRANSPOSE intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Tobias Schlüter + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include "libgfortran.h" + +void +__transpose_4 (gfc_array_i4 * ret, gfc_array_i4 * source) +{ + /* r.* indicates the return array. */ + index_type rxstride, rystride; + GFC_INTEGER_4 *rptr; + /* s.* indicates the source array. */ + index_type sxstride, systride; + const GFC_INTEGER_4 *sptr; + + index_type xcount, ycount; + index_type x, y; + + assert (GFC_DESCRIPTOR_RANK (source) == 2); + + if (ret->dim[0].stride == 0) + ret->dim[0].stride = 1; + if (source->dim[0].stride == 0) + source->dim[0].stride = 1; + + sxstride = source->dim[0].stride; + systride = source->dim[1].stride; + xcount = source->dim[0].ubound + 1 - source->dim[0].lbound; + ycount = source->dim[1].ubound + 1 - source->dim[1].lbound; + + rxstride = ret->dim[0].stride; + rystride = ret->dim[1].stride; + + rptr = ret->data; + sptr = source->data; + + for (y=0; y < ycount; y++) + { + for (x=0; x < xcount; x++) + { + *rptr = *sptr; + + sptr += sxstride; + rptr += rystride; + } + sptr += systride - (sxstride * xcount); + rptr += rxstride - (rystride * xcount); + } +} diff --git a/libgfortran/generated/transpose_i8.c b/libgfortran/generated/transpose_i8.c new file mode 100644 index 00000000000..2dcaa000889 --- /dev/null +++ b/libgfortran/generated/transpose_i8.c @@ -0,0 +1,69 @@ +/* Implementation of the TRANSPOSE intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Tobias Schlüter + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include "libgfortran.h" + +void +__transpose_8 (gfc_array_i8 * ret, gfc_array_i8 * source) +{ + /* r.* indicates the return array. */ + index_type rxstride, rystride; + GFC_INTEGER_8 *rptr; + /* s.* indicates the source array. */ + index_type sxstride, systride; + const GFC_INTEGER_8 *sptr; + + index_type xcount, ycount; + index_type x, y; + + assert (GFC_DESCRIPTOR_RANK (source) == 2); + + if (ret->dim[0].stride == 0) + ret->dim[0].stride = 1; + if (source->dim[0].stride == 0) + source->dim[0].stride = 1; + + sxstride = source->dim[0].stride; + systride = source->dim[1].stride; + xcount = source->dim[0].ubound + 1 - source->dim[0].lbound; + ycount = source->dim[1].ubound + 1 - source->dim[1].lbound; + + rxstride = ret->dim[0].stride; + rystride = ret->dim[1].stride; + + rptr = ret->data; + sptr = source->data; + + for (y=0; y < ycount; y++) + { + for (x=0; x < xcount; x++) + { + *rptr = *sptr; + + sptr += sxstride; + rptr += rystride; + } + sptr += systride - (sxstride * xcount); + rptr += rxstride - (rystride * xcount); + } +} diff --git a/libgfortran/generated/trig_c4.c b/libgfortran/generated/trig_c4.c new file mode 100644 index 00000000000..14d12c40144 --- /dev/null +++ b/libgfortran/generated/trig_c4.c @@ -0,0 +1,71 @@ +/* Complex trig functions + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +/* Complex number z = a + ib. */ + +/* sin(z) = sin(a)cosh(b) + icos(a)sinh(b) */ +GFC_COMPLEX_4 +csinf (GFC_COMPLEX_4 a) +{ + GFC_REAL_4 r; + GFC_REAL_4 i; + GFC_COMPLEX_4 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, sinf (r) * coshf (i), cosf (r) * sinhf (i)); + return v; +} + +/* cos(z) = cos(a)cosh(b) - isin(a)sinh(b) */ +GFC_COMPLEX_4 +ccosf (GFC_COMPLEX_4 a) +{ + GFC_REAL_4 r; + GFC_REAL_4 i; + GFC_COMPLEX_4 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, cosf (r) * coshf (i), - (sinf (r) * sinhf (i))); + return v; +} + +/* tan(z) = (tan(a) + itanh(b)) / (1 - itan(a)tanh(b)) */ +GFC_COMPLEX_4 +ctanf (GFC_COMPLEX_4 a) +{ + GFC_REAL_4 rt; + GFC_REAL_4 it; + GFC_COMPLEX_4 n; + GFC_COMPLEX_4 d; + + rt = tanf (REALPART (a)); + it = tanhf (IMAGPART (a)); + COMPLEX_ASSIGN (n, rt, it); + COMPLEX_ASSIGN (d , 1, - (rt * it)); + + return n / d; +} + diff --git a/libgfortran/generated/trig_c8.c b/libgfortran/generated/trig_c8.c new file mode 100644 index 00000000000..cea4872bdfc --- /dev/null +++ b/libgfortran/generated/trig_c8.c @@ -0,0 +1,71 @@ +/* Complex trig functions + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h" + + +/* Complex number z = a + ib. */ + +/* sin(z) = sin(a)cosh(b) + icos(a)sinh(b) */ +GFC_COMPLEX_8 +csin (GFC_COMPLEX_8 a) +{ + GFC_REAL_8 r; + GFC_REAL_8 i; + GFC_COMPLEX_8 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, sin (r) * cosh (i), cos (r) * sinh (i)); + return v; +} + +/* cos(z) = cos(a)cosh(b) - isin(a)sinh(b) */ +GFC_COMPLEX_8 +ccos (GFC_COMPLEX_8 a) +{ + GFC_REAL_8 r; + GFC_REAL_8 i; + GFC_COMPLEX_8 v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, cos (r) * cosh (i), - (sin (r) * sinh (i))); + return v; +} + +/* tan(z) = (tan(a) + itanh(b)) / (1 - itan(a)tanh(b)) */ +GFC_COMPLEX_8 +ctan (GFC_COMPLEX_8 a) +{ + GFC_REAL_8 rt; + GFC_REAL_8 it; + GFC_COMPLEX_8 n; + GFC_COMPLEX_8 d; + + rt = tan (REALPART (a)); + it = tanh (IMAGPART (a)); + COMPLEX_ASSIGN (n, rt, it); + COMPLEX_ASSIGN (d , 1, - (rt * it)); + + return n / d; +} + diff --git a/libgfortran/intrinsics/abort.c b/libgfortran/intrinsics/abort.c new file mode 100644 index 00000000000..26a25362a7d --- /dev/null +++ b/libgfortran/intrinsics/abort.c @@ -0,0 +1,31 @@ +/* Implementation of the ABORT intrinsic. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "libgfortran.h" +#include + + +void prefix(abort) (void); + +void prefix(abort) () +{ + abort (); +} + diff --git a/libgfortran/intrinsics/associated.c b/libgfortran/intrinsics/associated.c new file mode 100644 index 00000000000..ba52a205d12 --- /dev/null +++ b/libgfortran/intrinsics/associated.c @@ -0,0 +1,50 @@ +/* Implementation of the ASSOCIATED intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by kejia Zhao (CCRG) + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "libgfortran.h" + +#define associated prefix(associated) + +enum { FALSE = 0, TRUE = 1 }; + + +GFC_LOGICAL_4 +associated (const gfc_array_void *pointer, const gfc_array_void *target) +{ + int n, rank; + + if (GFC_DESCRIPTOR_DATA (pointer) != GFC_DESCRIPTOR_DATA (target)) + return FALSE; + if (GFC_DESCRIPTOR_DTYPE (pointer) != GFC_DESCRIPTOR_DTYPE (target)) + return FALSE; + + rank = GFC_DESCRIPTOR_RANK (pointer); + for (n = 0; n < rank; n++) + { + if (pointer->dim[n].stride != target->dim[n].stride) + return FALSE; + if ((pointer->dim[n].ubound - pointer->dim[n].lbound) + != (target->dim[n].ubound - target->dim[n].lbound)) + return FALSE; + } + + return TRUE; +} diff --git a/libgfortran/intrinsics/cpu_time.c b/libgfortran/intrinsics/cpu_time.c new file mode 100644 index 00000000000..9fd954b9a71 --- /dev/null +++ b/libgfortran/intrinsics/cpu_time.c @@ -0,0 +1,116 @@ +/* Implementation of the CPU_TIME intrinsic. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include "libgfortran.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +/* The CPU_TIME intrinsic to "compare different algorithms on the same + computer or discover which parts are the most expensive", so we + need a way to get the CPU time with the finest resolution possible. + We can only be accurate up to microseconds. + + As usual with UNIX systems, unfortunately no single way is + available for all systems. */ + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# ifdef HAVE_TIME_H +# include +# endif +# endif +#endif + +/* The most accurate way to get the CPU time is getrusage (). + If we have times(), that's good enough, too. */ +#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) +# include +#else +/* For times(), we _must_ know the number of clock ticks per second. */ +# if defined (HAVE_TIMES) && (defined (HZ) || defined (_SC_CLK_TCK) || defined (CLK_TCK)) +# ifdef HAVE_SYS_PARAM_H +# include +# endif +# include +# ifndef HZ +# if defined _SC_CLK_TCK +# define HZ sysconf(_SC_CLK_TCK) +# else +# define HZ CLK_TCK +# endif +# endif +# endif /* HAVE_TIMES etc. */ +#endif /* HAVE_GETRUSAGE && HAVE_SYS_RESOURCE_H */ + +#if defined (__GNUC__) && (__GNUC__ >= 3) +# define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__)) +#else +# define ATTRIBUTE_ALWAYS_INLINE +#endif + +static inline void __cpu_time_1 (long *, long *) ATTRIBUTE_ALWAYS_INLINE; + +/* Helper function for the actual implementation of the CPU_TIME + intrnsic. Returns a CPU time in microseconds or -1 if no CPU time + could be computed. */ +static inline void +__cpu_time_1 (long *sec, long *usec) +{ +#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) + struct rusage usage; + getrusage (0, &usage); + *sec = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec; + *usec = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec; +#else /* ! HAVE_GETRUSAGE || ! HAVE_SYS_RESOURCE_H */ +#ifdef HAVE_TIMES + struct tms buf; + times (&buf); + *sec = 0; + *usec = (buf.tms_utime + buf.tms_stime) * (1000000 / HZ); +#else /* ! HAVE_TIMES */ + /* We have nothing to go on. Return -1. */ + *sec = -1; + *usec = 0; +#endif /* HAVE_TIMES */ +#endif /* HAVE_GETRUSAGE */ +} + +#undef CPU_TIME +#define CPU_TIME(KIND) \ +void prefix(cpu_time_##KIND) (GFC_REAL_##KIND *__time) \ +{ \ + long sec, usec; \ + __cpu_time_1 (&sec, &usec); \ + *__time = (GFC_REAL_##KIND) sec + \ + ((GFC_REAL_##KIND) usec) * 1.e-6; \ +} + +CPU_TIME(4) +CPU_TIME(8) + diff --git a/libgfortran/intrinsics/cshift0.c b/libgfortran/intrinsics/cshift0.c new file mode 100644 index 00000000000..5a2c8caabe4 --- /dev/null +++ b/libgfortran/intrinsics/cshift0.c @@ -0,0 +1,169 @@ +/* Generic implementation of the CSHIFT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Feng Wang + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +/* TODO: make this work for large shifts when + sizeof(int) < sizeof (index_type). */ + +static void +__cshift0 (const gfc_array_char * ret, const gfc_array_char * array, + int shift, int which) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + + if (which < 1 || which > GFC_DESCRIPTOR_RANK (array)) + runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'"); + + size = GFC_DESCRIPTOR_SIZE (ret); + + which = which - 1; + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + +/* Initialized for avoiding compiler warnings. */ + roffset = size; + soffset = size; + len = 0; + + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + rptr = ret->data; + sptr = array->data; + + shift = (div (shift, len)).rem; + if (shift < 0) + shift += len; + + while (rptr) + { + /* Do the shift for this dimension. */ + src = &sptr[shift * soffset]; + dest = rptr; + for (n = 0; n < len; n++) + { + memcpy (dest, src, size); + dest += roffset; + if (n == len - shift - 1) + src = sptr; + else + src += soffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + } + } + } +} + + +void +__cshift0_4 (const gfc_array_char * ret, const gfc_array_char * array, + const GFC_INTEGER_4 * pshift, const GFC_INTEGER_4 * pdim) +{ + __cshift0 (ret, array, *pshift, pdim ? *pdim : 1); +} + + +void +__cshift0_8 (const gfc_array_char * ret, const gfc_array_char * array, + const GFC_INTEGER_8 * pshift, const GFC_INTEGER_8 * pdim) +{ + __cshift0 (ret, array, *pshift, pdim ? *pdim : 1); +} + diff --git a/libgfortran/intrinsics/dprod_r8.f90 b/libgfortran/intrinsics/dprod_r8.f90 new file mode 100644 index 00000000000..d0f2063d142 --- /dev/null +++ b/libgfortran/intrinsics/dprod_r8.f90 @@ -0,0 +1,27 @@ +! Copyright 2003 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfortran). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. + + +elemental function specific__dprod_r8 (p1, p2) + real (kind=4), intent (in) :: p1, p2 + real (kind=8) :: specific__dprod_r8 + + specific__dprod_r8 = dprod (p1, p2) +end function diff --git a/libgfortran/intrinsics/eoshift0.c b/libgfortran/intrinsics/eoshift0.c new file mode 100644 index 00000000000..f86f4bd883f --- /dev/null +++ b/libgfortran/intrinsics/eoshift0.c @@ -0,0 +1,188 @@ +/* Generic implementation of the RESHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* TODO: make this work for large shifts when + sizeof(int) < sizeof (index_type). */ + +static void +__eoshift0 (const gfc_array_char * ret, const gfc_array_char * array, + int shift, const char * pbound, int which) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + + if (!pbound) + pbound = zeros; + + size = GFC_DESCRIPTOR_SIZE (ret); + + which = which - 1; + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + rptr = ret->data; + sptr = array->data; + if (shift > 0) + len = len - shift; + else + len = len + shift; + + while (rptr) + { + /* Do the shift for this dimension. */ + if (shift > 0) + { + src = &sptr[shift * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[-shift * roffset]; + } + for (n = 0; n < len; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (shift >= 0) + { + n = shift; + } + else + { + dest = rptr; + n = -shift; + } + + while (n--) + { + memcpy (dest, pbound, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + } + } + } +} + + +void +__eoshift0_4 (const gfc_array_char * ret, const gfc_array_char * array, + const GFC_INTEGER_4 * pshift, const char * pbound, + const GFC_INTEGER_4 * pdim) +{ + __eoshift0 (ret, array, *pshift, pbound, pdim ? *pdim : 1); +} + + +void +__eoshift0_8 (const gfc_array_char * ret, const gfc_array_char * array, + const GFC_INTEGER_8 * pshift, const char * pbound, + const GFC_INTEGER_8 * pdim) +{ + __eoshift0 (ret, array, *pshift, pbound, pdim ? *pdim : 1); +} + diff --git a/libgfortran/intrinsics/eoshift2.c b/libgfortran/intrinsics/eoshift2.c new file mode 100644 index 00000000000..038588f78d2 --- /dev/null +++ b/libgfortran/intrinsics/eoshift2.c @@ -0,0 +1,204 @@ +/* Generic implementation of the RESHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* TODO: make this work for large shifts when + sizeof(int) < sizeof (index_type). */ + +static void +__eoshift2 (const gfc_array_char * ret, const gfc_array_char * array, + int shift, const gfc_array_char * bound, int which) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; + /* b.* indicates the bound array. */ + index_type bstride[GFC_MAX_DIMENSIONS - 1]; + index_type bstride0; + const char *bptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + + size = GFC_DESCRIPTOR_SIZE (ret); + + which = which - 1; + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + if (bound) + bstride[n] = bound->dim[n].stride * size; + else + bstride[n] = 0; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (bound && bstride[0] == 0) + bstride[0] = size; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + bstride0 = bstride[0]; + rptr = ret->data; + sptr = array->data; + if (bound) + bptr = bound->data; + else + bptr = zeros; + + if (shift > 0) + len = len - shift; + else + len = len + shift; + + while (rptr) + { + /* Do the shift for this dimension. */ + if (shift > 0) + { + src = &sptr[shift * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[-shift * roffset]; + } + for (n = 0; n < len; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (shift >= 0) + { + n = shift; + } + else + { + dest = rptr; + n = -shift; + } + + while (n--) + { + memcpy (dest, bptr, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + bptr += bstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + bptr -= bstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + bptr += bstride[n]; + } + } + } +} + + +void +__eoshift2_4 (const gfc_array_char * ret, const gfc_array_char * array, + const GFC_INTEGER_4 * pshift, const gfc_array_char * bound, + const GFC_INTEGER_4 * pdim) +{ + __eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1); +} + + +void +__eoshift2_8 (const gfc_array_char * ret, const gfc_array_char * array, + const GFC_INTEGER_8 * pshift, const gfc_array_char * bound, + const GFC_INTEGER_8 * pdim) +{ + __eoshift2 (ret, array, *pshift, bound, pdim ? *pdim : 1); +} + diff --git a/libgfortran/intrinsics/ishftc.c b/libgfortran/intrinsics/ishftc.c new file mode 100644 index 00000000000..0bb3d422eb2 --- /dev/null +++ b/libgfortran/intrinsics/ishftc.c @@ -0,0 +1,64 @@ +/* Implementation of ishftc intrinsic. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "libgfortran.h" + +#define ishftc4 prefix(ishftc4) +GFC_INTEGER_4 ishftc4 (GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4); + +#define ishftc8 prefix(ishftc8) +GFC_INTEGER_8 ishftc8 (GFC_INTEGER_8, GFC_INTEGER_8, GFC_INTEGER_8); + +GFC_INTEGER_4 +ishftc4 (GFC_INTEGER_4 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size) +{ + GFC_INTEGER_4 mask; + GFC_UINTEGER_4 bits; + + if (shift < 0) + shift = shift + size; + + if (shift == 0 || shift == size) + return i; + + mask = (~(GFC_INTEGER_4)0) << size; + bits = i & ~mask; + return (i & mask) | (bits >> (size - shift)) | ((i << shift) & ~mask); +} + + +GFC_INTEGER_8 +ishftc8 (GFC_INTEGER_8 i, GFC_INTEGER_8 shift, GFC_INTEGER_8 size) +{ + GFC_INTEGER_8 mask; + GFC_UINTEGER_8 bits; + + if (shift < 0) + shift = shift + size; + + if (shift == 0 || shift == size) + return i; + + mask = (~(GFC_INTEGER_8)0) << size; + bits = i & ~mask; + return (i & mask) | (bits >> (size - shift)) | ((i << shift) & ~mask); +} + diff --git a/libgfortran/intrinsics/pack_generic.c b/libgfortran/intrinsics/pack_generic.c new file mode 100644 index 00000000000..08c022e4e74 --- /dev/null +++ b/libgfortran/intrinsics/pack_generic.c @@ -0,0 +1,146 @@ +/* Generic implementation of the RESHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +__pack (const gfc_array_char * ret, const gfc_array_char * array, + const gfc_array_l4 * mask, const gfc_array_char * vector) +{ + /* r.* indicates the return array. */ + index_type rstride0; + char *rptr; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type sstride0; + const char *sptr; + /* m.* indicates the mask array. */ + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type mstride0; + const GFC_LOGICAL_4 *mptr; + + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type n; + index_type dim; + index_type size; + index_type nelem; + + size = GFC_DESCRIPTOR_SIZE (array); + dim = GFC_DESCRIPTOR_RANK (array); + for (n = 0; n < dim; n++) + { + count[n] = 0; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + sstride[n] = array->dim[n].stride * size; + mstride[n] = mask->dim[n].stride; + } + if (sstride[0] == 0) + sstride[0] = size; + if (mstride[0] == 0) + mstride[0] = 1; + + rstride0 = ret->dim[0].stride * size; + if (rstride0 == 0) + rstride0 = size; + sstride0 = sstride[0]; + mstride0 = mstride[0]; + rptr = ret->data; + sptr = array->data; + mptr = mask->data; + + /* Use the same loop for both logical types. */ + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + if (GFC_DESCRIPTOR_SIZE (mask) != 8) + runtime_error ("Funny sized logical array"); + for (n = 0; n < dim; n++) + mstride[n] <<= 1; + mstride0 <<= 1; + mptr = GFOR_POINTER_L8_TO_L4 (mptr); + } + + while (sptr) + { + /* Test this element. */ + if (*mptr) + { + /* Add it. */ + memcpy (rptr, sptr, size); + rptr += rstride0; + } + /* Advance to the next element. */ + sptr += sstride0; + mptr += mstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + sptr -= sstride[n] * extent[n]; + mptr -= mstride[n] * extent[n]; + n++; + if (n >= dim) + { + /* Break out of the loop. */ + sptr = NULL; + break; + } + else + { + count[n]++; + sptr += sstride[n]; + mptr += mstride[n]; + } + } + } + + /* Add any remaining elements from VECTOR. */ + if (vector) + { + n = vector->dim[0].ubound + 1 - vector->dim[0].lbound; + nelem = ((rptr - ret->data) / rstride0); + if (n > nelem) + { + sstride0 = vector->dim[0].stride * size; + if (sstride0 == 0) + sstride0 = size; + + sptr = vector->data + sstride0 * nelem; + n -= nelem; + while (n--) + { + memcpy (rptr, sptr, size); + rptr += rstride0; + sptr += sstride0; + } + } + } +} + diff --git a/libgfortran/intrinsics/random.c b/libgfortran/intrinsics/random.c new file mode 100644 index 00000000000..b578148f469 --- /dev/null +++ b/libgfortran/intrinsics/random.c @@ -0,0 +1,362 @@ +/* Implementation of the RANDOM intrinsics + Copyright 2002 Free Software Foundation, Inc. + Contributed by Lars Segerlund + + The algorithm was taken from the paper : + + Mersenne Twister: 623-dimensionally equidistributed + uniform pseudorandom generator. + + by: Makoto Matsumoto + Takuji Nishimura + + Which appeared in the: ACM Transactions on Modelling and Computer + Simulations: Special Issue on Uniform Random Number + Generation. ( Early in 1998 ). + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include "libgfortran.h" + +/*Use the 'big' generator by default ( period -> 2**19937 ). */ + +#define MT19937 + +/* Define the necessary constants for the algorithm. */ + +#ifdef MT19937 +enum constants +{ + N = 624, M = 397, R = 19, TU = 11, TS = 7, TT = 15, TL = 17 +}; +#define M_A 0x9908B0DF +#define T_B 0x9D2C5680 +#define T_C 0xEFC60000 +#else +enum constants +{ + N = 351, M = 175, R = 19, TU = 11, TS = 7, TT = 15, TL = 17 +}; +#define M_A 0xE4BD75F5 +#define T_B 0x655E5280 +#define T_C 0xFFD58000 +#endif + +static int i = N; +static unsigned int seed[N]; + +/* This is the routine which handles the seeding of the generator, + and also reading and writing of the seed. */ + +#define random_seed prefix(random_seed) +void +random_seed (GFC_INTEGER_4 * size, const gfc_array_i4 * put, + const gfc_array_i4 * get) +{ + /* Initialize the seed in system dependent manner. */ + if (get == NULL && put == NULL && size == NULL) + { + int fd; + fd = open ("/dev/urandom", O_RDONLY); + if (fd == 0) + { + /* We dont have urandom. */ + GFC_UINTEGER_4 s = (GFC_UINTEGER_4) seed; + for (i = 0; i < N; i++) + { + s = s * 29943829 - 1; + seed[i] = s; + } + } + else + { + /* Using urandom, might have a length issue. */ + read (fd, &seed[0], sizeof (GFC_UINTEGER_4) * N); + close (fd); + } + return; + } + + /* Return the size of the seed */ + if (size != NULL) + { + *size = N; + return; + } + + /* if we have gotten to this pount we have a get or put + * now we check it the array fulfills the demands in the standard . + */ + + /* Set the seed to PUT data */ + if (put != NULL) + { + /* if the rank of the array is not 1 abort */ + if (GFC_DESCRIPTOR_RANK (put) != 1) + abort (); + + /* if the array is too small abort */ + if (((put->dim[0].ubound + 1 - put->dim[0].lbound)) < N) + abort (); + + /* If this is the case the array is a temporary */ + if (get->dim[0].stride == 0) + return; + + /* This code now should do correct strides. */ + for (i = 0; i < N; i++) + seed[i] = put->data[i * put->dim[0].stride]; + } + + /* Return the seed to GET data */ + if (get != NULL) + { + /* if the rank of the array is not 1 abort */ + if (GFC_DESCRIPTOR_RANK (get) != 1) + abort (); + + /* if the array is too small abort */ + if (((get->dim[0].ubound + 1 - get->dim[0].lbound)) < N) + abort (); + + /* If this is the case the array is a temporary */ + if (get->dim[0].stride == 0) + return; + + /* This code now should do correct strides. */ + for (i = 0; i < N; i++) + get->data[i * get->dim[0].stride] = seed[i]; + } +} + +/* Here is the internal routine which generates the random numbers + in 'batches' based upon the need for a new batch. + It's an integer based routine known as 'Mersenne Twister'. + This implementation still lacks 'tempering' and a good verification, + but gives very good metrics. */ + +static void +random_generate (void) +{ + /* 32 bits. */ + GFC_UINTEGER_4 y; + + /* Generate batch of N. */ + int k, m; + for (k = 0, m = M; k < N - 1; k++) + { + y = (seed[k] & (-1 << R)) | (seed[k + 1] & ((1u << R) - 1)); + seed[k] = seed[m] ^ (y >> 1) ^ (-(GFC_INTEGER_4) (y & 1) & M_A); + if (++m >= N) + m = 0; + } + + y = (seed[N - 1] & (-1 << R)) | (seed[0] & ((1u << R) - 1)); + seed[N - 1] = seed[M - 1] ^ (y >> 1) ^ (-(GFC_INTEGER_4) (y & 1) & M_A); + i = 0; +} + +/* A routine to return a REAL(KIND=4). */ + +#define random_r4 prefix(random_r4) +void +random_r4 (GFC_REAL_4 * harv) +{ + /* Regenerate if we need to. */ + if (i >= N) + random_generate (); + + /* Convert uint32 to REAL(KIND=4). */ + *harv = (GFC_REAL_4) ((GFC_REAL_4) (GFC_UINTEGER_4) seed[i++] / + (GFC_REAL_4) (~(GFC_UINTEGER_4) 0)); +} + +/* A routine to return a REAL(KIND=8). */ + +#define random_r8 prefix(random_r8) +void +random_r8 (GFC_REAL_8 * harv) +{ + /* Regenerate if we need to, may waste one 32-bit value. */ + if ((i + 1) >= N) + random_generate (); + + /* Convert two uint32 to a REAL(KIND=8). */ + *harv = ((GFC_REAL_8) ((((GFC_UINTEGER_8) seed[i+1]) << 32) + seed[i])) / + (GFC_REAL_8) (~(GFC_UINTEGER_8) 0); + i += 2; +} + +/* Code to handle arrays will follow here. */ + +/* REAL(KIND=4) REAL array. */ + +#define arandom_r4 prefix(arandom_r4) +void +arandom_r4 (gfc_array_r4 * harv) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + GFC_REAL_4 *dest; + int n; + + dest = harv->data; + + if (harv->dim[0].stride == 0) + harv->dim[0].stride = 1; + + dim = GFC_DESCRIPTOR_RANK (harv); + + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = harv->dim[n].stride; + extent[n] = harv->dim[n].ubound + 1 - harv->dim[n].lbound; + if (extent[n] <= 0) + return; + } + + stride0 = stride[0]; + + while (dest) + { + /* Set the elements. */ + + /* regenerate if we need to */ + if (i >= N) + random_generate (); + + /* Convert uint32 to float in a hopefully g95 compiant manner */ + *dest = (GFC_REAL_4) ((GFC_REAL_4) (GFC_UINTEGER_4) seed[i++] / + (GFC_REAL_4) (~(GFC_UINTEGER_4) 0)); + + /* Advance to the next element. */ + dest += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, + reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, + but this is a less + frequently used path so proabably not worth it. */ + dest -= stride[n] * extent[n]; + n++; + if (n == dim) + { + dest = NULL; + break; + } + else + { + count[n]++; + dest += stride[n]; + } + } + } +} + +/* REAL(KIND=8) array. */ + +#define arandom_r8 prefix(arandom_r8) +void +arandom_r8 (gfc_array_r8 * harv) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + GFC_REAL_8 *dest; + int n; + + dest = harv->data; + + if (harv->dim[0].stride == 0) + harv->dim[0].stride = 1; + + dim = GFC_DESCRIPTOR_RANK (harv); + + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = harv->dim[n].stride; + extent[n] = harv->dim[n].ubound + 1 - harv->dim[n].lbound; + if (extent[n] <= 0) + return; + } + + stride0 = stride[0]; + + while (dest) + { + /* Set the elements. */ + + /* regenerate if we need to, may waste one 32-bit value */ + if ((i + 1) >= N) + random_generate (); + + /* Convert two uint32 to a REAL(KIND=8). */ + *dest = ((GFC_REAL_8) ((((GFC_UINTEGER_8) seed[i+1]) << 32) + seed[i])) / + (GFC_REAL_8) (~(GFC_UINTEGER_8) 0); + i += 2; + + /* Advance to the next element. */ + dest += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, + reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, + but this is a less + frequently used path so proabably not worth it. */ + dest -= stride[n] * extent[n]; + n++; + if (n == dim) + { + dest = NULL; + break; + } + else + { + count[n]++; + dest += stride[n]; + } + } + } +} + diff --git a/libgfortran/intrinsics/reshape_generic.c b/libgfortran/intrinsics/reshape_generic.c new file mode 100644 index 00000000000..ca6f6aacd00 --- /dev/null +++ b/libgfortran/intrinsics/reshape_generic.c @@ -0,0 +1,231 @@ +/* Generic implementation of the RESHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR(1, index_type) shape_type; +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) parray; + + +/* The shape parameter is ignored. We can currently deduce the shape from the + return array. */ + +void +__reshape (parray * ret, parray * source, shape_type * shape, + parray * pad, shape_type * order) +{ + /* r.* indicates the return array. */ + index_type rcount[GFC_MAX_DIMENSIONS - 1]; + index_type rextent[GFC_MAX_DIMENSIONS - 1]; + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type rdim; + index_type rsize; + char *rptr; + /* s.* indicates the source array. */ + index_type scount[GFC_MAX_DIMENSIONS - 1]; + index_type sextent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type sdim; + index_type ssize; + const char *sptr; + /* p.* indicates the pad array. */ + index_type pcount[GFC_MAX_DIMENSIONS - 1]; + index_type pextent[GFC_MAX_DIMENSIONS - 1]; + index_type pstride[GFC_MAX_DIMENSIONS - 1]; + index_type pdim; + index_type psize; + const char *pptr; + + const char *src; + int n; + int dim; + int size; + + size = GFC_DESCRIPTOR_SIZE (ret); + if (ret->dim[0].stride == 0) + ret->dim[0].stride = 1; + if (source->dim[0].stride == 0) + source->dim[0].stride = 1; + if (shape->dim[0].stride == 0) + shape->dim[0].stride = 1; + if (pad && pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + if (order && order->dim[0].stride == 0) + order->dim[0].stride = 1; + + rdim = GFC_DESCRIPTOR_RANK (ret); + rsize = 1; + for (n = 0; n < rdim; n++) + { + if (order) + dim = order->data[n * order->dim[0].stride] - 1; + else + dim = n; + + rcount[n] = 0; + rstride[n] = ret->dim[dim].stride; + rextent[n] = ret->dim[dim].ubound + 1 - ret->dim[dim].lbound; + + if (rextent[n] != shape->data[dim * shape->dim[0].stride]) + runtime_error ("shape and target do not conform"); + + if (rsize == rstride[n]) + rsize *= rextent[n]; + else + rsize = 0; + if (rextent[dim] <= 0) + return; + } + + sdim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + for (n = 0; n < sdim; n++) + { + scount[n] = 0; + sstride[n] = source->dim[n].stride; + sextent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (sextent[n] <= 0) + abort (); + + if (rsize == sstride[n]) + ssize *= sextent[n]; + else + ssize = 0; + } + + if (pad) + { + if (pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + pdim = GFC_DESCRIPTOR_RANK (pad); + psize = 1; + for (n = 0; n < pdim; n++) + { + pcount[n] = 0; + pstride[n] = pad->dim[n].stride; + pextent[n] = pad->dim[n].ubound + 1 - pad->dim[n].lbound; + if (pextent[n] <= 0) + abort (); + if (psize == pstride[n]) + psize *= pextent[n]; + else + rsize = 0; + } + pptr = pad->data; + } + else + { + pdim = 0; + psize = 1; + pptr = NULL; + } + + if (rsize != 0 && ssize != 0 && psize != 0) + { + rsize *= size; + ssize *= size; + psize *= size; + reshape_packed (ret->data, rsize, source->data, ssize, + pad ? pad->data : NULL, psize); + return; + } + rptr = ret->data; + src = sptr = source->data; + rstride0 = rstride[0] * size; + sstride0 = sstride[0] * size; + + while (rptr) + { + /* Select between the source and pad arrays. */ + memcpy(rptr, src, size); + /* Advance to the next element. */ + rptr += rstride0; + src += sstride0; + rcount[0]++; + scount[0]++; + /* Advance to the next destination element. */ + n = 0; + while (rcount[n] == rextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + rcount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * rextent[n] * size; + n++; + if (n == rdim) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + rcount[n]++; + rptr += rstride[n] * size; + } + } + /* Advance to the next source element. */ + n = 0; + while (scount[n] == sextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + scount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= sstride[n] * sextent[n] * size; + n++; + if (n == sdim) + { + if (sptr && pad) + { + /* Switch to the pad array. */ + sptr = NULL; + sdim = pdim; + for (dim = 0; dim < pdim; dim++) + { + scount[dim] = pcount[dim]; + sextent[dim] = pextent[dim]; + sstride[dim] = pstride[dim]; + sstride0 = sstride[0] * size; + } + } + /* We now start again from the beginning of the pad array. */ + src = pptr; + break; + } + else + { + scount[n]++; + sptr += sstride[n] * size; + } + } + } +} + diff --git a/libgfortran/intrinsics/reshape_packed.c b/libgfortran/intrinsics/reshape_packed.c new file mode 100644 index 00000000000..eef885feb85 --- /dev/null +++ b/libgfortran/intrinsics/reshape_packed.c @@ -0,0 +1,46 @@ +/* Implementation of the RESHAPE intrinsic for packed arrays + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "libgfortran.h" + +#include + +/* Reshape function where all arrays are packed. Basically just memcpy. */ + +void +reshape_packed (char * ret, index_type rsize, const char * source, + index_type ssize, const char * pad, index_type psize) +{ + index_type size; + + size = (rsize > ssize) ? ssize : rsize; + memcpy (ret, source, size); + ret += size; + rsize -= size; + while (rsize > 0) + { + size = (rsize > psize) ? psize : rsize; + memcpy (ret, pad, size); + ret += size; + rsize -= size; + } +} diff --git a/libgfortran/intrinsics/selected_kind.f90 b/libgfortran/intrinsics/selected_kind.f90 new file mode 100644 index 00000000000..62d11c7f596 --- /dev/null +++ b/libgfortran/intrinsics/selected_kind.f90 @@ -0,0 +1,90 @@ +! Copyright 2003 Free Software Foundation, Inc. +! Contributed by Kejia Zhao +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! + +function selected_int_kind (r) + implicit none + integer, intent (in) :: r + integer :: selected_int_kind + integer :: i + ! Integer kind_range table + integer, parameter :: c = 4 + type :: int_info + integer :: kind + integer :: range + end type int_info + type (int_info), parameter :: int_infos (c) = & + (/int_info (1, range (0_1)), & + int_info (2, range (0_2)), & + int_info (4, range (0_4)), & + int_info (8, range (0_8))/) + + do i = 1, c + if (r <= int_infos (i) % range) then + selected_int_kind = int_infos (i) % kind + return + end if + end do + selected_int_kind = -1 + return +end function + +function selected_real_kind (p, r) + implicit none + integer, optional, intent (in) :: p, r + integer :: selected_real_kind + integer :: i, p2, r2 + logical :: found_p, found_r + ! Real kind_precision_range table + integer, parameter :: c = 2 + type :: real_info + integer :: kind + integer :: precision + integer :: range + end type real_info + type (real_info) :: real_infos (c) = & + (/real_info (4, precision (0.0_4), range (0.0_4)), & + real_info (8, precision (0.0_8), range (0.0_8))/) + + selected_real_kind = 0 + p2 = 0 + r2 = 0 + found_p = .false. + found_r = .false. + + if (present (p)) p2 = p + if (present (r)) r2 = r + + ! Assumes each type has a greater precision and range than previous one. + + do i = 1, c + if (p2 <= real_infos (i) % precision) found_p = .true. + if (r2 <= real_infos (i) % range) found_r = .true. + if (found_p .and. found_r) then + selected_real_kind = real_infos (i) % kind + return + end if + end do + + if (.not. (found_p)) selected_real_kind = selected_real_kind - 1 + if (.not. (found_r)) selected_real_kind = selected_real_kind - 2 + + return +end function diff --git a/libgfortran/intrinsics/size.c b/libgfortran/intrinsics/size.c new file mode 100644 index 00000000000..5664c304988 --- /dev/null +++ b/libgfortran/intrinsics/size.c @@ -0,0 +1,56 @@ +/* Implementation of the size intrinsic. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "libgfortran.h" + +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, void) array_t; + +#define size0 prefix(size0) +index_type size0 (const array_t * array) +{ + int n; + index_type size; + index_type len; + + size = 1; + for (n = 0; n < GFC_DESCRIPTOR_RANK (array); n++) + { + len = array->dim[n].ubound + 1 - array->dim[n].lbound; + if (len < 0) + len = 0; + size *= len; + } + return size; +} + +#define size1 prefix(size1) +index_type size1 (const array_t * array, index_type dim) +{ + index_type size; + + dim--; + + size = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (size < 0) + size = 0; + return size; +} + diff --git a/libgfortran/intrinsics/spread_generic.c b/libgfortran/intrinsics/spread_generic.c new file mode 100644 index 00000000000..a789c98448b --- /dev/null +++ b/libgfortran/intrinsics/spread_generic.c @@ -0,0 +1,118 @@ +/* Generic implementation of the RESHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +__spread (const gfc_array_char * ret, const gfc_array_char * source, + const index_type * along, const index_type * pncopies) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type rdelta; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + const char *sptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type n; + index_type dim; + index_type size; + index_type ncopies; + + size = GFC_DESCRIPTOR_SIZE (source); + dim = 0; + for (n = 0; n < GFC_DESCRIPTOR_RANK (ret); n++) + { + if (n == *along - 1) + { + rdelta = ret->dim[n].stride * size; + } + else + { + count[dim] = 0; + extent[dim] = source->dim[dim].ubound + 1 - source->dim[dim].lbound; + sstride[dim] = source->dim[dim].stride * size; + rstride[dim] = ret->dim[n].stride * size; + dim++; + } + } + dim = GFC_DESCRIPTOR_RANK (source); + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + + sstride0 = sstride[0]; + rstride0 = rstride[0]; + rptr = ret->data; + sptr = source->data; + ncopies = *pncopies; + + while (sptr) + { + /* Spread this element. */ + dest = rptr; + for (n = 0; n < ncopies; n++) + { + memcpy (dest, sptr, size); + dest += rdelta; + } + /* Advance to the next element. */ + sptr += sstride0; + rptr += rstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so probably not worth it. */ + sptr -= sstride[n] * extent[n]; + rptr -= rstride[n] * extent[n]; + n++; + if (n >= dim) + { + /* Break out of the loop. */ + sptr = NULL; + break; + } + else + { + count[n]++; + sptr += sstride[n]; + rptr += rstride[n]; + } + } + } +} + diff --git a/libgfortran/intrinsics/string_intrinsics.c b/libgfortran/intrinsics/string_intrinsics.c new file mode 100644 index 00000000000..999807ed1d0 --- /dev/null +++ b/libgfortran/intrinsics/string_intrinsics.c @@ -0,0 +1,394 @@ +/* String intrinsics helper functions. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Unlike what the name of this file suggests, we don't actually + implement the Fortran intrinsics here. At least, not with the + names they have in the standard. The functions here provide all + the support we need for the standard string intrinsics, and the + compiler translates the actual intrinsics calls to calls to + functions in this file. */ + +#include +#include + +#include "libgfortran.h" + + +/* String functions. */ + +#define copy_string prefix(copy_string) +void copy_string (GFC_INTEGER_4, char *, GFC_INTEGER_4, const char *); + +#define concat_string prefix(concat_string) +void concat_string (GFC_INTEGER_4, char *, + GFC_INTEGER_4, const char *, + GFC_INTEGER_4, const char *); + +#define string_len_trim prefix(string_len_trim) +GFC_INTEGER_4 string_len_trim (GFC_INTEGER_4, const char *); + +#define adjustl prefix(adjustl) +void adjustl (char *, GFC_INTEGER_4, const char *); + +#define adjustr prefix(adjustr) +void adjustr (char *, GFC_INTEGER_4, const char *); + +#define string_index prefix(string_index) +GFC_INTEGER_4 string_index (GFC_INTEGER_4, const char *, GFC_INTEGER_4, + const char *, GFC_LOGICAL_4); + +#define string_scan prefix(string_scan) +GFC_INTEGER_4 string_scan (GFC_INTEGER_4, const char *, GFC_INTEGER_4, + const char *, GFC_LOGICAL_4); + +#define string_verify prefix(string_verify) +GFC_INTEGER_4 string_verify (GFC_INTEGER_4, const char *, GFC_INTEGER_4, + const char *, GFC_LOGICAL_4); + +#define string_trim prefix(string_trim) +void string_trim (GFC_INTEGER_4 *, void **, GFC_INTEGER_4, const char *); + +#define string_repeat prefix(string_repeat) +void string_repeat (char *, GFC_INTEGER_4, const char *, GFC_INTEGER_4); + +/* The two areas may overlap so we use memmove. */ + +void +copy_string (GFC_INTEGER_4 destlen, char * dest, + GFC_INTEGER_4 srclen, const char * src) +{ + if (srclen >= destlen) + { + /* This will truncate if too long. */ + memmove (dest, src, destlen); + /*memcpy (dest, src, destlen);*/ + } + else + { + memmove (dest, src, srclen); + /*memcpy (dest, src, srclen);*/ + /* Pad with spaces. */ + memset (&dest[srclen], ' ', destlen - srclen); + } +} + + +/* Strings of unequal length are extended with pad characters. */ + +GFC_INTEGER_4 +compare_string (GFC_INTEGER_4 len1, const char * s1, + GFC_INTEGER_4 len2, const char * s2) +{ + int res; + const char *s; + int len; + + res = strncmp (s1, s2, (len1 < len2) ? len1 : len2); + if (res != 0) + return res; + + if (len1 == len2) + return 0; + + if (len1 < len2) + { + len = len2 - len1; + s = &s2[len1]; + res = -1; + } + else + { + len = len1 - len2; + s = &s1[len2]; + res = 1; + } + + while (len--) + { + if (*s != ' ') + { + if (*s > ' ') + return res; + else + return -res; + } + s++; + } + + return 0; +} + + +/* The destination and source should not overlap. */ + +void +concat_string (GFC_INTEGER_4 destlen, char * dest, + GFC_INTEGER_4 len1, const char * s1, + GFC_INTEGER_4 len2, const char * s2) +{ + if (len1 >= destlen) + { + memcpy (dest, s1, destlen); + return; + } + memcpy (dest, s1, len1); + dest += len1; + destlen -= len1; + + if (len2 >= destlen) + { + memcpy (dest, s2, destlen); + return; + } + + memcpy (dest, s2, len2); + memset (&dest[len2], ' ', destlen - len2); +} + + +/* Return string with all trailing blanks removed. */ + +void +string_trim (GFC_INTEGER_4 * len, void ** dest, GFC_INTEGER_4 slen, const char * src) +{ + int i; + + /* Determine length of result string. */ + for (i = slen - 1; i >= 0; i--) + { + if (src[i] != ' ') + break; + } + *len = i + 1; + + if (*len > 0) + { + /* Allocate space for result string. */ + *dest = internal_malloc (*len); + + /* copy string if necessary. */ + memmove (*dest, src, *len); + } +} + + +/* The length of a string not including trailing blanks. */ + +GFC_INTEGER_4 +string_len_trim (GFC_INTEGER_4 len, const char * s) +{ + int i; + + for (i = len - 1; i >= 0; i--) + { + if (s[i] != ' ') + break; + } + return i + 1; +} + + +/* Find a substring within a string. */ + +GFC_INTEGER_4 +string_index (GFC_INTEGER_4 slen, const char * str, GFC_INTEGER_4 sslen, + const char * sstr, GFC_LOGICAL_4 back) +{ + int start; + int last; + int i; + int delta; + + if (sslen == 0) + return 1; + + if (!back) + { + last = slen + 1 - sslen; + start = 0; + delta = 1; + } + else + { + last = -1; + start = slen - sslen; + delta = -1; + } + i = 0; + for (; start != last; start+= delta) + { + for (i = 0; i < sslen; i++) + { + if (str[start + i] != sstr[i]) + break; + } + if (i == sslen) + return (start + 1); + } + return 0; +} + + +/* Remove leading blanks from a string, padding at end. The src and dest + should not overlap. */ + +void +adjustl (char *dest, GFC_INTEGER_4 len, const char *src) +{ + int i; + + i = 0; + while (i 0) + memset (&dest[len - i], ' ', i); +} + + +/* Remove trailing blanks from a string. */ + +void +adjustr (char *dest, GFC_INTEGER_4 len, const char *src) +{ + int i; + + i = len; + while (i > 0 && src[i - 1] == ' ') + i++; + + if (i < len) + memcpy (&dest[len - i], &src, i); + if (i < len) + memset (dest, ' ', len - i); +} + + +/* Scan a string for any one of the characters in a set of characters. */ + +GFC_INTEGER_4 +string_scan (GFC_INTEGER_4 slen, const char * str, GFC_INTEGER_4 setlen, + const char * set, GFC_LOGICAL_4 back) +{ + int start; + int last; + int i; + int delta; + + if (slen == 0 || setlen == 0) + return 0; + + if (back) + { + last = 0; + start = slen - 1; + delta = -1; + } + else + { + last = slen - 1; + start = 0; + delta = 1; + } + + i = 0; + for (; start != last; start += delta) + { + for (i = 0; i < setlen; i++) + { + if (str[start] == set[i]) + return (start + 1); + } + } + + return 0; +} + + +/* Verify that a set of characters contains all the characters in a + string by indentifying the position of the first character in a + characters that dose not appear in a given set of characters. */ + +GFC_INTEGER_4 +string_verify (GFC_INTEGER_4 slen, const char * str, GFC_INTEGER_4 setlen, + const char * set, GFC_LOGICAL_4 back) +{ + int start; + int last; + int i; + int delta; + + if (slen == 0) + return 0; + + if (back) + { + last = 0; + start = slen - 1; + delta = -1; + } + else + { + last = slen - 1; + start = 0; + delta = 1; + } + i = 0; + for (; start != last; start += delta) + { + for (i = 0; i < setlen; i++) + { + if (str[start] == set[i]) + break; + } + if (i == setlen) + return (start + 1); + } + + return 0; +} + + +/* Concatenate several copies of a string. */ + +void +string_repeat (char * dest, GFC_INTEGER_4 slen, + const char * src, GFC_INTEGER_4 ncopies) +{ + int i; + + /* See if ncopies is valid. */ + if (ncopies < 0) + { + /* The error is already reported. */ + runtime_error ("Augument NCOPIES is negative."); + } + + /* Copy characters. */ + for (i = 0; i < ncopies; i++) + { + memmove (dest + (i * slen), src, slen); + } +} + diff --git a/libgfortran/intrinsics/transpose_generic.c b/libgfortran/intrinsics/transpose_generic.c new file mode 100644 index 00000000000..d72ae5a4b81 --- /dev/null +++ b/libgfortran/intrinsics/transpose_generic.c @@ -0,0 +1,74 @@ +/* Implementation of the TRANSPOSE intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Tobias Schlüter + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +__transpose (gfc_array_char * ret, gfc_array_char * source) +{ + /* r.* indicates the return array. */ + index_type rxstride, rystride; + char *rptr; + /* s.* indicates the source array. */ + index_type sxstride, systride; + const char *sptr; + + index_type xcount, ycount; + index_type x, y; + index_type size; + + assert (GFC_DESCRIPTOR_RANK (source) == 2 + && GFC_DESCRIPTOR_RANK (ret) == 2); + + size = GFC_DESCRIPTOR_SIZE (source); + sxstride = source->dim[0].stride * size; + if (sxstride == 0) + sxstride = size; + systride = source->dim[1].stride * size; + xcount = source->dim[0].ubound + 1 - source->dim[0].lbound; + ycount = source->dim[1].ubound + 1 - source->dim[1].lbound; + + rxstride = ret->dim[0].stride * size; + if (rxstride == 0) + rxstride = size; + rystride = ret->dim[1].stride * size; + + rptr = ret->data; + sptr = source->data; + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + memcpy (rptr, sptr, size); + + sptr += sxstride; + rptr += rystride; + } + sptr += systride - (sxstride * xcount); + rptr += rxstride - (rystride * xcount); + } +} + diff --git a/libgfortran/intrinsics/unpack_generic.c b/libgfortran/intrinsics/unpack_generic.c new file mode 100644 index 00000000000..3d02a3e6060 --- /dev/null +++ b/libgfortran/intrinsics/unpack_generic.c @@ -0,0 +1,154 @@ +/* Generic implementation of the RESHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +__unpack1 (const gfc_array_char * ret, const gfc_array_char * vector, + const gfc_array_l4 * mask, const gfc_array_char * field) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS]; + index_type rstride0; + char *rptr; + /* v.* indicates the vector array. */ + index_type vstride0; + char *vptr; + /* f.* indicates the field array. */ + index_type fstride[GFC_MAX_DIMENSIONS]; + index_type fstride0; + const char *fptr; + /* m.* indicates the mask array. */ + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type mstride0; + const GFC_LOGICAL_4 *mptr; + + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type n; + index_type dim; + index_type size; + index_type fsize; + + size = GFC_DESCRIPTOR_SIZE (ret); + /* A field element size of 0 actually means this is a scalar. */ + fsize = GFC_DESCRIPTOR_SIZE (field); + dim = GFC_DESCRIPTOR_RANK (ret); + for (n = 0; n < dim; n++) + { + count[n] = 0; + extent[n] = ret->dim[n].ubound + 1 - ret->dim[n].lbound; + rstride[n] = ret->dim[n].stride * size; + fstride[n] = field->dim[n].stride * fsize; + mstride[n] = mask->dim[n].stride; + } + if (rstride[0] == 0) + rstride[0] = size; + if (fstride[0] == 0) + fstride[0] = fsize; + if (mstride[0] == 0) + mstride[0] = 1; + + vstride0 = vector->dim[0].stride * size; + if (vstride0 == 0) + vstride0 = size; + rstride0 = rstride[0]; + fstride0 = fstride[0]; + mstride0 = mstride[0]; + rptr = ret->data; + fptr = field->data; + mptr = mask->data; + vptr = vector->data; + + + /* Use the same loop for both logical types. */ + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + if (GFC_DESCRIPTOR_SIZE (mask) != 8) + runtime_error ("Funny sized logical array"); + for (n = 0; n < dim; n++) + mstride[n] <<= 1; + mstride0 <<= 1; + mptr = GFOR_POINTER_L8_TO_L4 (mptr); + } + + while (rptr) + { + if (*mptr) + { + /* From vector. */ + memcpy (rptr, vptr, size); + vptr += vstride0; + } + else + { + /* From field. */ + memcpy (rptr, fptr, size); + } + /* Advance to the next element. */ + rptr += rstride0; + fptr += fstride0; + mptr += mstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + fptr -= fstride[n] * extent[n]; + mptr -= mstride[n] * extent[n]; + n++; + if (n >= dim) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + fptr += fstride[n]; + mptr += mstride[n]; + } + } + } +} + +void +__unpack0 (const gfc_array_char * ret, const gfc_array_char * vector, + const gfc_array_l4 * mask, char * field) +{ + gfc_array_char tmp; + + tmp.dtype = 0; + tmp.data = field; + __unpack1 (ret, vector, mask, &tmp); +} + diff --git a/libgfortran/io/backspace.c b/libgfortran/io/backspace.c new file mode 100644 index 00000000000..7502f1d4863 --- /dev/null +++ b/libgfortran/io/backspace.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "libgfortran.h" +#include "io.h" + +/* backspace.c -- Implement the BACKSPACE statement */ + +/* formatted_backspace(void)-- Move the file back one line. The + * current position is after the newline that terminates the previous + * record, and we have to sift backwards to find the newline before + * that or the start of the file, whichever comes first. */ + +#define READ_CHUNK 4096 + +static void +formatted_backspace (void) +{ + offset_t base; + char *p; + int n; + + base = file_position (current_unit->s) - 1; + + do + { + n = (base < READ_CHUNK) ? base : READ_CHUNK; + base -= n; + + p = salloc_r_at (current_unit->s, &n, base); + if (p == NULL) + goto io_error; + + /* Because we've moved backwords from the current position, it + * should not be possible to get a short read. Because it isn't + * clear what to do about such thing, we ignore the possibility. */ + + /* There is no memrchr() in the C library, so we have to do it + * ourselves. */ + + n--; + while (n >= 0) + { + if (p[n] == '\n') + { + base += n + 1; + goto done; + } + + n--; + } + + } + while (base != 0); + +/* base is the new pointer. Seek to it exactly */ + +done: + if (sseek (current_unit->s, base) == FAILURE) + goto io_error; + current_unit->last_record--; + + return; + +io_error: + generate_error (ERROR_OS, NULL); +} + + +/* unformatted_backspace()-- Move the file backwards for an + * unformatted sequential file. We are guaranteed to be between + * records on entry and we have to shift to the previous record. */ + +static void +unformatted_backspace (void) +{ + offset_t *p, new; + int length; + + length = sizeof (offset_t); + + p = (offset_t *) salloc_r_at (current_unit->s, &length, + file_position (current_unit->s) - length); + if (p == NULL) + goto io_error; + + new = file_position (current_unit->s) - *p - length; + if (sseek (current_unit->s, new) == FAILURE) + goto io_error; + + current_unit->last_record--; + return; + +io_error: + generate_error (ERROR_OS, NULL); +} + + +void +st_backspace (void) +{ + unit_t *u; + + library_start (); + + u = find_unit (ioparm.unit); + if (u == NULL) + { + generate_error (ERROR_BAD_UNIT, NULL); + goto done; + } + + current_unit = u; + + /* Ignore direct access. Non-advancing I/O is only allowed for + * formatted sequential I/O and the next direct access transfer + * repositions the file anyway. */ + + if (u->flags.access == ACCESS_DIRECT) + goto done; + + /* Check for special cases involving the ENDFILE record first */ + + if (u->endfile == AFTER_ENDFILE) + u->endfile = AT_ENDFILE; + else + { + if (u->current_record) + next_record (1); + + if (file_position (u->s) == 0) + goto done; /* Common special case */ + + if (u->flags.form == FORM_UNFORMATTED) + formatted_backspace (); + else + unformatted_backspace (); + } + +done: + library_end (); +} diff --git a/libgfortran/io/close.c b/libgfortran/io/close.c new file mode 100644 index 00000000000..9e2a5a398ce --- /dev/null +++ b/libgfortran/io/close.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "libgfortran.h" +#include "io.h" + +typedef enum +{ CLOSE_DELETE, CLOSE_KEEP, CLOSE_UNSPECIFIED } +close_status; + +static st_option status_opt[] = { + {"keep", CLOSE_KEEP}, + {"delete", CLOSE_DELETE}, + {NULL} +}; + + +void +st_close (void) +{ + close_status status; + unit_t *u; + + library_start (); + + status = (ioparm.status == NULL) ? CLOSE_UNSPECIFIED : + find_option (ioparm.status, ioparm.status_len, status_opt, + "Bad STATUS parameter in CLOSE statement"); + + if (ioparm.library_return != LIBRARY_OK) + return; + + u = find_unit (ioparm.unit); + if (u != NULL) + { + if (u->flags.status == STATUS_SCRATCH) + { + if (status == CLOSE_KEEP) + generate_error (ERROR_BAD_OPTION, + "Can't KEEP a scratch file on CLOSE"); + } + else + { + if (status == CLOSE_DELETE) + delete_file (u); + } + + close_unit (u); + } + + library_end (); +} diff --git a/libgfortran/io/endfile.c b/libgfortran/io/endfile.c new file mode 100644 index 00000000000..56f81f09909 --- /dev/null +++ b/libgfortran/io/endfile.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "libgfortran.h" +#include "io.h" + +/* endfile.c-- Implement the ENDFILE statement */ + +void +st_endfile (void) +{ + unit_t *u; + + library_start (); + + u = get_unit (0); + if (u != NULL) + { + current_unit = u; /* next_record() needs this set */ + if (u->current_record) + next_record (1); + + struncate (u->s); + u->endfile = AFTER_ENDFILE; + } + + library_end (); +} diff --git a/libgfortran/io/format.c b/libgfortran/io/format.c new file mode 100644 index 00000000000..caec1672da5 --- /dev/null +++ b/libgfortran/io/format.c @@ -0,0 +1,1285 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* format.c-- parse a FORMAT string into a binary format suitable for + * interpretation during I/O statements */ + +#include "config.h" +#include +#include +#include "libgfortran.h" +#include "io.h" + + + +/* Number of format nodes that we can store statically before we have + * to resort to dynamic allocation. The root node is array[0]. */ + +#define FARRAY_SIZE 200 + +static fnode *avail, array[FARRAY_SIZE]; + +/* Local variables for checking format strings. The saved_token is + * used to back up by a single format token during the parsing process. */ + +static char *format_string, *string; +static const char *error; +static format_token saved_token; +static int value, format_string_len, reversion_ok; + +static fnode *saved_format, colon_node = { FMT_COLON }; + +/* Error messages */ + +static char posint_required[] = "Positive width required in format", + period_required[] = "Period required in format", + nonneg_required[] = "Nonnegative width required in format", + unexpected_element[] = "Unexpected element in format", + unexpected_end[] = "Unexpected end of format string", + bad_string[] = "Unterminated character constant in format", + bad_hollerith[] = "Hollerith constant extends past the end of the format", + reversion_error[] = "Exhausted data descriptors in format"; + + +/* next_char()-- Return the next character in the format string. + * Returns -1 when the string is done. If the literal flag is set, + * spaces are significant, otherwise they are not. */ + +static int +next_char (int literal) +{ + int c; + + do + { + if (format_string_len == 0) + return -1; + + format_string_len--; + c = toupper (*format_string++); + } + while (c == ' ' && !literal); + + return c; +} + + +/* unget_char()-- Back up one character position. */ + +#define unget_char() { format_string--; format_string_len++; } + + +/* get_fnode()-- Allocate a new format node, inserting it into the + * current singly linked list. These are initially allocated from the + * static buffer. */ + +static fnode * +get_fnode (fnode ** head, fnode ** tail, format_token t) +{ + fnode *f; + + if (avail - array >= FARRAY_SIZE) + f = get_mem (sizeof (fnode)); + else + { + f = avail++; + memset (f, '\0', sizeof (fnode)); + } + + if (*head == NULL) + *head = *tail = f; + else + { + (*tail)->next = f; + *tail = f; + } + + f->format = t; + f->repeat = -1; + f->source = format_string; + return f; +} + + +/* free_fnode()-- Recursive function to free the given fnode and + * everything it points to. We only have to actually free something + * if it is outside of the static array. */ + +static void +free_fnode (fnode * f) +{ + fnode *next; + + for (; f; f = next) + { + next = f->next; + + if (f->format == FMT_LPAREN) + free_fnode (f->u.child); + if (f < array || f >= array + FARRAY_SIZE) + free_mem (f); + } +} + + +/* free_fnodes()-- Free the current tree of fnodes. We only have to + * traverse the tree if some nodes were allocated dynamically. */ + +void +free_fnodes (void) +{ + + if (avail - array >= FARRAY_SIZE) + free_fnode (&array[0]); + + avail = array; + memset(array, 0, sizeof(avail[0]) * FARRAY_SIZE); +} + + +/* format_lex()-- Simple lexical analyzer for getting the next token + * in a FORMAT string. We support a one-level token pushback in the + * saved_token variable. */ + +static format_token +format_lex (void) +{ + format_token token; + int negative_flag; + char c, delim; + + if (saved_token != FMT_NONE) + { + token = saved_token; + saved_token = FMT_NONE; + return token; + } + + negative_flag = 0; + c = next_char (0); + + switch (c) + { + case '-': + negative_flag = 1; + /* Fall Through */ + + case '+': + c = next_char (0); + if (!isdigit (c)) + { + token = FMT_UNKNOWN; + break; + } + + value = c - '0'; + + for (;;) + { + c = next_char (0); + if (!isdigit (c)) + break; + + value = 10 * value + c - '0'; + } + + unget_char (); + + if (negative_flag) + value = -value; + token = FMT_SIGNED_INT; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + value = c - '0'; + + for (;;) + { + c = next_char (0); + if (!isdigit (c)) + break; + + value = 10 * value + c - '0'; + } + + unget_char (); + token = (value == 0) ? FMT_ZERO : FMT_POSINT; + break; + + case '.': + token = FMT_PERIOD; + break; + + case ',': + token = FMT_COMMA; + break; + + case ':': + token = FMT_COLON; + break; + + case '/': + token = FMT_SLASH; + break; + + case '$': + token = FMT_DOLLAR; + break; + + case 'T': + switch (next_char (0)) + { + case 'L': + token = FMT_TL; + break; + case 'R': + token = FMT_TR; + break; + default: + token = FMT_T; + unget_char (); + break; + } + + break; + + case '(': + token = FMT_LPAREN; + break; + + case ')': + token = FMT_RPAREN; + break; + + case 'X': + token = FMT_X; + break; + + case 'S': + switch (next_char (0)) + { + case 'S': + token = FMT_SS; + break; + case 'P': + token = FMT_SP; + break; + default: + token = FMT_S; + unget_char (); + break; + } + + break; + + case 'B': + switch (next_char (0)) + { + case 'N': + token = FMT_BN; + break; + case 'Z': + token = FMT_BZ; + break; + default: + token = FMT_B; + unget_char (); + break; + } + + break; + + case '\'': + case '"': + delim = c; + + string = format_string; + value = 0; /* This is the length of the string */ + + for (;;) + { + c = next_char (1); + if (c == -1) + { + token = FMT_BADSTRING; + error = bad_string; + break; + } + + if (c == delim) + { + c = next_char (1); + + if (c == -1) + { + token = FMT_BADSTRING; + error = bad_string; + break; + } + + if (c != delim) + { + unget_char (); + token = FMT_STRING; + break; + } + } + + value++; + } + + break; + + case 'P': + token = FMT_P; + break; + + case 'I': + token = FMT_I; + break; + + case 'O': + token = FMT_O; + break; + + case 'Z': + token = FMT_Z; + break; + + case 'F': + token = FMT_F; + break; + + case 'E': + switch (next_char (0)) + { + case 'N': + token = FMT_EN; + break; + case 'S': + token = FMT_ES; + break; + default: + token = FMT_E; + unget_char (); + break; + } + + break; + + case 'G': + token = FMT_G; + break; + + case 'H': + token = FMT_H; + break; + + case 'L': + token = FMT_L; + break; + + case 'A': + token = FMT_A; + break; + + case 'D': + token = FMT_D; + break; + + case -1: + token = FMT_END; + break; + + default: + token = FMT_UNKNOWN; + break; + } + + return token; +} + + +/* parse_format_list()-- Parse a format list. Assumes that a left + * paren has already been seen. Returns a list representing the + * parenthesis node which contains the rest of the list. */ + +static fnode * +parse_format_list (void) +{ + fnode *head, *tail; + format_token t, u, t2; + int repeat; + + head = tail = NULL; + +/* Get the next format item */ + +format_item: + t = format_lex (); + switch (t) + { + case FMT_POSINT: + repeat = value; + + t = format_lex (); + switch (t) + { + case FMT_LPAREN: + get_fnode (&head, &tail, FMT_LPAREN); + tail->repeat = repeat; + tail->u.child = parse_format_list (); + if (error != NULL) + goto finished; + + goto between_desc; + + case FMT_SLASH: + get_fnode (&head, &tail, FMT_SLASH); + tail->repeat = repeat; + goto optional_comma; + + case FMT_X: + get_fnode (&head, &tail, FMT_X); + tail->repeat = 1; + tail->u.k = value; + goto between_desc; + + case FMT_P: + goto p_descriptor; + + default: + goto data_desc; + } + + case FMT_LPAREN: + get_fnode (&head, &tail, FMT_LPAREN); + tail->repeat = 1; + tail->u.child = parse_format_list (); + if (error != NULL) + goto finished; + + goto between_desc; + + case FMT_SIGNED_INT: /* Signed integer can only precede a P format. */ + case FMT_ZERO: /* Same for zero. */ + t = format_lex (); + if (t != FMT_P) + { + error = "Expected P edit descriptor in format"; + goto finished; + } + + p_descriptor: + get_fnode (&head, &tail, FMT_P); + tail->u.k = value; + + t = format_lex (); + if (t == FMT_F || t == FMT_EN || t == FMT_ES || t == FMT_D + || t == FMT_G || t == FMT_E) + { + repeat = 1; + goto data_desc; + } + + saved_token = t; + goto between_desc; + + case FMT_P: /* P and X require a prior number */ + error = "P descriptor requires leading scale factor"; + goto finished; + + case FMT_X: +/* + EXTENSION! + + If we would be pedantic in the library, we would have to reject + an X descriptor without an integer prefix: + + error = "X descriptor requires leading space count"; + goto finished; + + However, this is an extension supported by many Fortran compilers, + including Cray, HP, AIX, and IRIX. Therefore, we allow it in the + runtime library, and make the front end reject it if the compiler + is in pedantic mode. The interpretation of 'X' is '1X'. +*/ + get_fnode (&head, &tail, FMT_X); + tail->repeat = 1; + tail->u.k = 1; + goto between_desc; + + case FMT_STRING: + get_fnode (&head, &tail, FMT_STRING); + + tail->u.string.p = string; + tail->u.string.length = value; + tail->repeat = 1; + goto between_desc; + + case FMT_S: + case FMT_SS: + case FMT_SP: + case FMT_BN: + case FMT_BZ: + get_fnode (&head, &tail, t); + goto between_desc; + + case FMT_COLON: + get_fnode (&head, &tail, FMT_COLON); + goto optional_comma; + + case FMT_SLASH: + get_fnode (&head, &tail, FMT_SLASH); + tail->repeat = 1; + tail->u.r = 1; + goto optional_comma; + + case FMT_DOLLAR: + get_fnode (&head, &tail, FMT_DOLLAR); + goto between_desc; + + case FMT_T: + case FMT_TL: + case FMT_TR: + t2 = format_lex (); + if (t2 != FMT_POSINT) + { + error = posint_required; + goto finished; + } + get_fnode (&head, &tail, t); + tail->u.n = value; + tail->repeat = 1; + goto between_desc; + + case FMT_I: + case FMT_B: + case FMT_O: + case FMT_Z: + case FMT_E: + case FMT_EN: + case FMT_ES: + case FMT_D: + case FMT_L: + case FMT_A: + case FMT_F: + case FMT_G: + repeat = 1; + goto data_desc; + + case FMT_H: + get_fnode (&head, &tail, FMT_STRING); + + if (format_string_len < 1) + { + error = bad_hollerith; + goto finished; + } + + tail->u.string.p = format_string; + tail->u.string.length = 1; + tail->repeat = 1; + + format_string++; + format_string_len--; + + goto between_desc; + + case FMT_END: + error = unexpected_end; + goto finished; + + case FMT_BADSTRING: + goto finished; + + case FMT_RPAREN: + goto finished; + + default: + error = unexpected_element; + goto finished; + } + +/* In this state, t must currently be a data descriptor. Deal with + * things that can/must follow the descriptor */ + +data_desc: + switch (t) + { + case FMT_P: + t = format_lex (); + if (t == FMT_POSINT) + { + error = "Repeat count cannot follow P descriptor"; + goto finished; + } + + saved_token = t; + get_fnode (&head, &tail, FMT_P); + + goto optional_comma; + + case FMT_L: + t = format_lex (); + if (t != FMT_POSINT) + { + error = posint_required; + goto finished; + } + + get_fnode (&head, &tail, FMT_L); + tail->u.n = value; + tail->repeat = repeat; + break; + + case FMT_A: + t = format_lex (); + if (t != FMT_POSINT) + { + saved_token = t; + value = -1; /* Width not present */ + } + + get_fnode (&head, &tail, FMT_A); + tail->repeat = repeat; + tail->u.n = value; + break; + + case FMT_D: + case FMT_E: + case FMT_F: + case FMT_G: + case FMT_EN: + case FMT_ES: + get_fnode (&head, &tail, t); + tail->repeat = repeat; + + u = format_lex (); + if (t == FMT_F || g.mode == WRITING) + { + if (u != FMT_POSINT && u != FMT_ZERO) + { + error = nonneg_required; + goto finished; + } + } + else + { + if (u != FMT_POSINT) + { + error = posint_required; + goto finished; + } + } + + tail->u.real.w = value; + t2 = t; + t = format_lex (); + if (t != FMT_PERIOD) + { + error = period_required; + goto finished; + } + + t = format_lex (); + if (t != FMT_ZERO && t != FMT_POSINT) + { + error = nonneg_required; + goto finished; + } + + tail->u.real.d = value; + + if (t == FMT_D || t == FMT_F) + break; + + tail->u.real.e = -1; + +/* Look for optional exponent */ + + t = format_lex (); + if (t != FMT_E) + saved_token = t; + else + { + t = format_lex (); + if (t != FMT_POSINT) + { + error = "Positive exponent width required in format"; + goto finished; + } + + tail->u.real.e = value; + } + + break; + + case FMT_H: + if (repeat > format_string_len) + { + error = bad_hollerith; + goto finished; + } + + get_fnode (&head, &tail, FMT_STRING); + + tail->u.string.p = format_string; + tail->u.string.length = repeat; + tail->repeat = 1; + + format_string += value; + format_string_len -= repeat; + + break; + + case FMT_I: + case FMT_B: + case FMT_O: + case FMT_Z: + get_fnode (&head, &tail, t); + tail->repeat = repeat; + + t = format_lex (); + + if (g.mode == READING) + { + if (t != FMT_POSINT) + { + error = posint_required; + goto finished; + } + } + else + { + if (t != FMT_ZERO && t != FMT_POSINT) + { + error = nonneg_required; + goto finished; + } + } + + tail->u.integer.w = value; + tail->u.integer.m = -1; + + t = format_lex (); + if (t != FMT_PERIOD) + { + saved_token = t; + } + else + { + t = format_lex (); + if (t != FMT_ZERO && t != FMT_POSINT) + { + error = nonneg_required; + goto finished; + } + + tail->u.integer.m = value; + } + + if (tail->u.integer.w != 0 && tail->u.integer.m > tail->u.integer.w) + { + error = "Minimum digits exceeds field width"; + goto finished; + } + + break; + + default: + error = unexpected_element; + goto finished; + } + +/* Between a descriptor and what comes next */ +between_desc: + t = format_lex (); + switch (t) + { + case FMT_COMMA: + goto format_item; + + case FMT_RPAREN: + goto finished; + + case FMT_SLASH: + get_fnode (&head, &tail, FMT_SLASH); + tail->repeat = 1; + + /* Fall Through */ + + case FMT_COLON: + goto optional_comma; + + case FMT_END: + error = unexpected_end; + goto finished; + + default: + error = "Missing comma in format"; + goto finished; + } + +/* Optional comma is a weird between state where we've just finished + * reading a colon, slash or P descriptor. */ + +optional_comma: + t = format_lex (); + switch (t) + { + case FMT_COMMA: + break; + + case FMT_RPAREN: + goto finished; + + default: /* Assume that we have another format item */ + saved_token = t; + break; + } + + goto format_item; + +finished: + return head; +} + + +/* format_error()-- Generate an error message for a format statement. + * If the node that gives the location of the error is NULL, the error + * is assumed to happen at parse time, and the current location of the + * parser is shown. + * + * After freeing any dynamically allocated fnodes, generate a message + * showing where the problem is. We take extra care to print only the + * relevant part of the format if it is longer than a standard 80 + * column display. */ + +void +format_error (fnode * f, const char *message) +{ + int width, i, j, offset; + char *p, buffer[300]; + + if (f != NULL) + format_string = f->source; + + free_fnodes (); + + st_sprintf (buffer, "%s\n", message); + + j = format_string - ioparm.format; + + offset = (j > 60) ? j - 40 : 0; + + j -= offset; + width = ioparm.format_len - offset; + + if (width > 80) + width = 80; + + /* Show the format */ + + p = strchr (buffer, '\0'); + + memcpy (p, ioparm.format + offset, width); + + p += width; + *p++ = '\n'; + + /* Show where the problem is */ + + for (i = 1; i < j; i++) + *p++ = ' '; + + *p++ = '^'; + *p = '\0'; + + generate_error (ERROR_FORMAT, buffer); +} + + +/* parse_format()-- Parse a format string. */ + +void +parse_format (void) +{ + + format_string = ioparm.format; + format_string_len = ioparm.format_len; + + saved_token = FMT_NONE; + error = NULL; + +/* Initialize variables used during traversal of the tree */ + + reversion_ok = 0; + g.reversion_flag = 0; + saved_format = NULL; + +/* Allocate the first format node as the root of the tree */ + + avail = array; + + avail->format = FMT_LPAREN; + avail->repeat = 1; + avail++; + + if (format_lex () == FMT_LPAREN) + array[0].u.child = parse_format_list (); + else + error = "Missing initial left parenthesis in format"; + + if (error) + format_error (NULL, error); +} + + +/* revert()-- Do reversion of the format. Control reverts to the left + * parenthesis that matches the rightmost right parenthesis. From our + * tree structure, we are looking for the rightmost parenthesis node + * at the second level, the first level always being a single + * parenthesis node. If this node doesn't exit, we use the top + * level. */ + +static void +revert (void) +{ + fnode *f, *r; + + g.reversion_flag = 1; + + r = NULL; + + for (f = array[0].u.child; f; f = f->next) + if (f->format == FMT_LPAREN) + r = f; + + /* If r is NULL because no node was found, the whole tree will be used */ + + array[0].current = r; + array[0].count = 0; +} + + +/* next_format0()-- Get the next format node without worrying about + * reversion. Returns NULL when we hit the end of the list. + * Parenthesis nodes are incremented after the list has been + * exhausted, other nodes are incremented before they are returned. */ + +static fnode * +next_format0 (fnode * f) +{ + fnode *r; + + if (f == NULL) + return NULL; + + if (f->format != FMT_LPAREN) + { + f->count++; + if (f->count <= f->repeat) + return f; + + f->count = 0; + return NULL; + } + + /* Deal with a parenthesis node */ + + for (; f->count < f->repeat; f->count++) + { + if (f->current == NULL) + f->current = f->u.child; + + for (; f->current != NULL; f->current = f->current->next) + { + r = next_format0 (f->current); + if (r != NULL) + return r; + } + } + + f->count = 0; + return NULL; +} + + +/* next_format()-- Return the next format node. If the format list + * ends up being exhausted, we do reversion. Reversion is only + * allowed if the we've seen a data descriptor since the + * initialization or the last reversion. We return NULL if the there + * are no more data descriptors to return (which is an error + * condition). */ + +fnode * +next_format (void) +{ + format_token t; + fnode *f; + + if (saved_format != NULL) + { /* Deal with a pushed-back format node */ + f = saved_format; + saved_format = NULL; + goto done; + } + + f = next_format0 (&array[0]); + if (f == NULL) + { + if (!reversion_ok) + { + return NULL; + } + + reversion_ok = 0; + revert (); + + f = next_format0 (&array[0]); + if (f == NULL) + { + format_error (NULL, reversion_error); + return NULL; + } + + /* Push the first reverted token and return a colon node in case + * there are no more data items. */ + + saved_format = f; + return &colon_node; + } + + /* If this is a data edit descriptor, then reversion has become OK. */ + +done: + t = f->format; + + if (!reversion_ok && + (t == FMT_I || t == FMT_B || t == FMT_O || t == FMT_Z || t == FMT_F || + t == FMT_E || t == FMT_EN || t == FMT_ES || t == FMT_G || t == FMT_L || + t == FMT_A || t == FMT_D)) + reversion_ok = 1; + return f; +} + + +/* unget_format()-- Push the given format back so that it will be + * returned on the next call to next_format() without affecting + * counts. This is necessary when we've encountered a data + * descriptor, but don't know what the data item is yet. The format + * node is pushed back, and we return control to the main program, + * which calls the library back with the data item (or not). */ + +void +unget_format (fnode * f) +{ + + saved_format = f; +} + + + + +#if 0 + +static void dump_format1 (fnode * f); + +/* dump_format0()-- Dump a single format node */ + +void +dump_format0 (fnode * f) +{ + char *p; + int i; + + switch (f->format) + { + case FMT_COLON: + st_printf (" :"); + break; + case FMT_SLASH: + st_printf (" %d/", f->u.r); + break; + case FMT_DOLLAR: + st_printf (" $"); + break; + case FMT_T: + st_printf (" T%d", f->u.n); + break; + case FMT_TR: + st_printf (" TR%d", f->u.n); + break; + case FMT_TL: + st_printf (" TL%d", f->u.n); + break; + case FMT_X: + st_printf (" %dX", f->u.n); + break; + case FMT_S: + st_printf (" S"); + break; + case FMT_SS: + st_printf (" SS"); + break; + case FMT_SP: + st_printf (" SP"); + break; + + case FMT_LPAREN: + if (f->repeat == 1) + st_printf (" ("); + else + st_printf (" %d(", f->repeat); + + dump_format1 (f->u.child); + st_printf (" )"); + break; + + case FMT_STRING: + st_printf (" '"); + p = f->u.string.p; + for (i = f->u.string.length; i > 0; i--) + st_printf ("%c", *p++); + + st_printf ("'"); + break; + + case FMT_P: + st_printf (" %dP", f->u.k); + break; + case FMT_I: + st_printf (" %dI%d.%d", f->repeat, f->u.integer.w, f->u.integer.m); + break; + + case FMT_B: + st_printf (" %dB%d.%d", f->repeat, f->u.integer.w, f->u.integer.m); + break; + + case FMT_O: + st_printf (" %dO%d.%d", f->repeat, f->u.integer.w, f->u.integer.m); + break; + + case FMT_Z: + st_printf (" %dZ%d.%d", f->repeat, f->u.integer.w, f->u.integer.m); + break; + + case FMT_BN: + st_printf (" BN"); + break; + case FMT_BZ: + st_printf (" BZ"); + break; + case FMT_D: + st_printf (" %dD%d.%d", f->repeat, f->u.real.w, f->u.real.d); + break; + + case FMT_EN: + st_printf (" %dEN%d.%dE%d", f->repeat, f->u.real.w, f->u.real.d, + f->u.real.e); + break; + + case FMT_ES: + st_printf (" %dES%d.%dE%d", f->repeat, f->u.real.w, f->u.real.d, + f->u.real.e); + break; + + case FMT_F: + st_printf (" %dF%d.%d", f->repeat, f->u.real.w, f->u.real.d); + break; + + case FMT_E: + st_printf (" %dE%d.%dE%d", f->repeat, f->u.real.w, f->u.real.d, + f->u.real.e); + break; + + case FMT_G: + st_printf (" %dG%d.%dE%d", f->repeat, f->u.real.w, f->u.real.d, + f->u.real.e); + break; + + case FMT_L: + st_printf (" %dL%d", f->repeat, f->u.w); + break; + case FMT_A: + st_printf (" %dA%d", f->repeat, f->u.w); + break; + + default: + st_printf (" ???"); + break; + } +} + + +/* dump_format1()-- Dump a string of format nodes */ + +static void +dump_format1 (fnode * f) +{ + + for (; f; f = f->next) + dump_format1 (f); +} + +/* dump_format()-- Dump the whole format node tree */ + +void +dump_format (void) +{ + + st_printf ("format = "); + dump_format0 (&array[0]); + st_printf ("\n"); +} + + +void +next_test (void) +{ + fnode *f; + int i; + + for (i = 0; i < 20; i++) + { + f = next_format (); + if (f == NULL) + { + st_printf ("No format!\n"); + break; + } + + dump_format1 (f); + st_printf ("\n"); + } +} + +#endif diff --git a/libgfortran/io/inquire.c b/libgfortran/io/inquire.c new file mode 100644 index 00000000000..88e805ec96f --- /dev/null +++ b/libgfortran/io/inquire.c @@ -0,0 +1,371 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* Implement the non-IOLENGTH variant of the INQUIRY statement */ + +#include "config.h" +#include "libgfortran.h" +#include "io.h" + + +static char undefined[] = "UNDEFINED"; + + +/* inquire_via_unit()-- Inquiry via unit number. The unit might not exist. */ + +static void +inquire_via_unit (unit_t * u) +{ + const char *p; + + if (ioparm.exist != NULL) + *ioparm.exist = (u != NULL); + + if (ioparm.opened != NULL) + *ioparm.opened = (u != NULL); + + if (ioparm.number != NULL) + *ioparm.number = (u != NULL) ? u->unit_number : -1; + + if (ioparm.named != NULL) + *ioparm.named = (u != NULL && u->flags.status != STATUS_SCRATCH); + + if (ioparm.name != NULL && u != NULL && u->flags.status != STATUS_SCRATCH) + fstrcpy (ioparm.name, ioparm.name_len, u->file, u->file_len); + + if (ioparm.access != NULL) + { + if (u == NULL) + p = undefined; + else + switch (u->flags.access) + { + case ACCESS_SEQUENTIAL: + p = "SEQUENTIAL"; + break; + case ACCESS_DIRECT: + p = "DIRECT"; + break; + default: + internal_error ("inquire_via_unit(): Bad access"); + } + + cf_strcpy (ioparm.access, ioparm.access_len, p); + } + + if (ioparm.sequential != NULL) + { + p = (u == NULL) ? inquire_sequential (NULL, 0) : + inquire_sequential (u->file, u->file_len); + + cf_strcpy (ioparm.sequential, ioparm.sequential_len, p); + } + + if (ioparm.direct != NULL) + { + p = (u == NULL) ? inquire_direct (NULL, 0) : + inquire_direct (u->file, u->file_len); + + cf_strcpy (ioparm.direct, ioparm.direct_len, p); + } + + if (ioparm.form != NULL) + { + if (u == NULL) + p = undefined; + else + switch (u->flags.form) + { + case FORM_FORMATTED: + p = "FORMATTED"; + break; + case FORM_UNFORMATTED: + p = "UNFORMATTED"; + break; + default: + internal_error ("inquire_via_unit(): Bad form"); + } + + cf_strcpy (ioparm.form, ioparm.form_len, p); + } + + if (ioparm.formatted != NULL) + { + p = (u == NULL) ? inquire_formatted (NULL, 0) : + inquire_formatted (u->file, u->file_len); + + cf_strcpy (ioparm.formatted, ioparm.formatted_len, p); + } + + if (ioparm.unformatted != NULL) + { + p = (u == NULL) ? inquire_unformatted (NULL, 0) : + inquire_unformatted (u->file, u->file_len); + + cf_strcpy (ioparm.unformatted, ioparm.unformatted_len, p); + } + + if (ioparm.recl_out != NULL) + *ioparm.recl_out = (u != NULL) ? u->recl : 0; + + if (ioparm.nextrec != NULL) + *ioparm.nextrec = (u != NULL) ? u->last_record + 1 : 0; + + if (ioparm.blank != NULL) + { + if (u == NULL) + p = undefined; + else + switch (u->flags.blank) + { + case BLANK_NULL: + p = "NULL"; + break; + case BLANK_ZERO: + p = "ZERO"; + break; + default: + internal_error ("inquire_via_unit(): Bad blank"); + } + + cf_strcpy (ioparm.blank, ioparm.blank_len, p); + } + + if (ioparm.position != NULL) + { + if (u == NULL || u->flags.access == ACCESS_DIRECT) + p = undefined; + else + { + p = NULL; /* TODO: Try to decode what the standard says... */ + } + + cf_strcpy (ioparm.blank, ioparm.blank_len, p); + } + + if (ioparm.action != NULL) + { + if (u == NULL) + p = undefined; + else + switch (u->flags.action) + { + case ACTION_READ: + p = "READ"; + break; + case ACTION_WRITE: + p = "WRITE"; + break; + case ACTION_READWRITE: + p = "READWRITE"; + break; + default: + internal_error ("inquire_via_unit(): Bad action"); + } + + cf_strcpy (ioparm.action, ioparm.action_len, p); + } + + if (ioparm.read != NULL) + { + p = (u == NULL) ? inquire_read (NULL, 0) : + inquire_read (u->file, u->file_len); + + cf_strcpy (ioparm.read, ioparm.read_len, p); + } + + if (ioparm.write != NULL) + { + p = (u == NULL) ? inquire_write (NULL, 0) : + inquire_write (u->file, u->file_len); + + cf_strcpy (ioparm.write, ioparm.write_len, p); + } + + if (ioparm.readwrite != NULL) + { + p = (u == NULL) ? inquire_readwrite (NULL, 0) : + inquire_readwrite (u->file, u->file_len); + + cf_strcpy (ioparm.readwrite, ioparm.readwrite_len, p); + } + + if (ioparm.delim != NULL) + { + if (u == NULL || u->flags.form != FORM_FORMATTED) + p = undefined; + else + switch (u->flags.delim) + { + case DELIM_NONE: + p = "NONE"; + break; + case DELIM_QUOTE: + p = "QUOTE"; + break; + case DELIM_APOSTROPHE: + p = "APOSTROPHE"; + break; + default: + internal_error ("inquire_via_unit(): Bad delim"); + } + + cf_strcpy (ioparm.access, ioparm.access_len, p); + } + + if (ioparm.pad != NULL) + { + if (u == NULL || u->flags.form != FORM_FORMATTED) + p = undefined; + else + switch (u->flags.pad) + { + case PAD_NO: + p = "NO"; + break; + case PAD_YES: + p = "YES"; + break; + default: + internal_error ("inquire_via_unit(): Bad pad"); + } + + cf_strcpy (ioparm.pad, ioparm.pad_len, p); + } +} + + +/* inquire_via_filename()-- Inquiry via filename. This subroutine is + * only used if the filename is *not* connected to a unit number. */ + +static void +inquire_via_filename (void) +{ + const char *p; + + if (ioparm.exist != NULL) + *ioparm.exist = file_exists (); + + if (ioparm.opened != NULL) + *ioparm.opened = 0; + + if (ioparm.number != NULL) + *ioparm.number = -1; + + if (ioparm.named != NULL) + *ioparm.named = 1; + + if (ioparm.name != NULL) + fstrcpy (ioparm.name, ioparm.name_len, ioparm.file, ioparm.file_len); + + if (ioparm.access != NULL) + cf_strcpy (ioparm.access, ioparm.access_len, undefined); + + if (ioparm.sequential != NULL) + { + p = inquire_sequential (ioparm.file, ioparm.file_len); + cf_strcpy (ioparm.sequential, ioparm.sequential_len, p); + } + + if (ioparm.direct != NULL) + { + p = inquire_direct (ioparm.file, ioparm.file_len); + cf_strcpy (ioparm.direct, ioparm.direct_len, p); + } + + if (ioparm.form != NULL) + cf_strcpy (ioparm.form, ioparm.form_len, undefined); + + if (ioparm.formatted != NULL) + { + p = inquire_formatted (ioparm.file, ioparm.file_len); + cf_strcpy (ioparm.formatted, ioparm.formatted_len, p); + } + + if (ioparm.unformatted != NULL) + { + p = inquire_unformatted (ioparm.file, ioparm.file_len); + cf_strcpy (ioparm.unformatted, ioparm.unformatted_len, p); + } + + if (ioparm.recl_out != NULL) + *ioparm.recl_out = 0; + + if (ioparm.nextrec != NULL) + *ioparm.nextrec = 0; + + if (ioparm.blank != NULL) + cf_strcpy (ioparm.blank, ioparm.blank_len, undefined); + + if (ioparm.position != NULL) + cf_strcpy (ioparm.position, ioparm.position_len, undefined); + + if (ioparm.access != NULL) + cf_strcpy (ioparm.access, ioparm.access_len, undefined); + + if (ioparm.read != NULL) + { + p = inquire_read (ioparm.file, ioparm.file_len); + cf_strcpy (ioparm.read, ioparm.read_len, p); + } + + if (ioparm.write != NULL) + { + p = inquire_write (ioparm.file, ioparm.file_len); + cf_strcpy (ioparm.write, ioparm.write_len, p); + } + + if (ioparm.readwrite != NULL) + { + p = inquire_read (ioparm.file, ioparm.file_len); + cf_strcpy (ioparm.readwrite, ioparm.readwrite_len, p); + } + + if (ioparm.delim != NULL) + cf_strcpy (ioparm.delim, ioparm.delim_len, undefined); + + if (ioparm.pad != NULL) + cf_strcpy (ioparm.pad, ioparm.pad_len, undefined); + +} + + + +void +st_inquire (void) +{ + unit_t *u; + + library_start (); + + if (ioparm.file == NULL) + inquire_via_unit (find_unit (ioparm.unit)); + else + { + u = find_file (); + if (u == NULL) + inquire_via_filename (); + else + inquire_via_unit (u); + } + + library_end (); +} diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h new file mode 100644 index 00000000000..3b01912f09a --- /dev/null +++ b/libgfortran/io/io.h @@ -0,0 +1,653 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef GFOR_IO_H +#define GFOR_IO_H + +/* IO library include. */ + +#include +#include "libgfortran.h" +#define DEFAULT_TEMPDIR "/var/tmp" + +/* Basic types used in data transfers. */ + +typedef enum +{ BT_NULL, BT_INTEGER, BT_LOGICAL, BT_CHARACTER, BT_REAL, + BT_COMPLEX +} +bt; + + +typedef enum +{ SUCCESS = 1, FAILURE } +try; + +typedef struct stream +{ + char *(*alloc_w_at) (struct stream *, int *, offset_t); + char *(*alloc_r_at) (struct stream *, int *, offset_t); + try (*sfree) (struct stream *); + try (*close) (struct stream *); + try (*seek) (struct stream *, offset_t); + try (*truncate) (struct stream *); +} +stream; + + +/* Macros for doing file I/O given a stream. */ + +#define sfree(s) ((s)->sfree)(s) +#define sclose(s) ((s)->close)(s) + +#define salloc_r(s, len) ((s)->alloc_r_at)(s, len, -1) +#define salloc_w(s, len) ((s)->alloc_w_at)(s, len, -1) + +#define salloc_r_at(s, len, where) ((s)->alloc_r_at)(s, len, where) +#define salloc_w_at(s, len, where) ((s)->alloc_w_at)(s, len, where) + +#define sseek(s, pos) ((s)->seek)(s, pos) +#define struncate(s) ((s)->truncate)(s) + +/* Namelist represent object */ +/* + Namelist Records + &groupname object=value [,object=value].../ + or + &groupname object=value [,object=value]...&groupname + + Even more complex, during the execution of a program containing a + namelist READ statement, you can specify a question mark character(?) + or a question mark character preceded by an equal sign(=?) to get + the information of the namelist group. By '?', the name of variables + in the namelist will be displayed, by '=?', the name and value of + variables will be displayed. + + All these requirements need a new data structure to record all info + about the namelist. +*/ + +typedef struct namelist_type +{ + char * var_name; + void * mem_pos; + int value_acquired; + int len; + bt type; + struct namelist_type * next; +} +namelist_info; + +/* Options for the OPEN statement. */ + +typedef enum +{ ACCESS_SEQUENTIAL, ACCESS_DIRECT, + ACCESS_UNSPECIFIED +} +unit_access; + +typedef enum +{ ACTION_READ, ACTION_WRITE, ACTION_READWRITE, + ACTION_UNSPECIFIED +} +unit_action; + +typedef enum +{ BLANK_NULL, BLANK_ZERO, BLANK_UNSPECIFIED } +unit_blank; + +typedef enum +{ DELIM_NONE, DELIM_APOSTROPHE, DELIM_QUOTE, + DELIM_UNSPECIFIED +} +unit_delim; + +typedef enum +{ FORM_FORMATTED, FORM_UNFORMATTED, FORM_UNSPECIFIED } +unit_form; + +typedef enum +{ POSITION_ASIS, POSITION_REWIND, POSITION_APPEND, + POSITION_UNSPECIFIED +} +unit_position; + +typedef enum +{ STATUS_UNKNOWN, STATUS_OLD, STATUS_NEW, STATUS_SCRATCH, + STATUS_REPLACE, STATUS_UNSPECIFIED +} +unit_status; + +typedef enum +{ PAD_YES, PAD_NO, PAD_UNSPECIFIED } +unit_pad; + +typedef enum +{ ADVANCE_YES, ADVANCE_NO, ADVANCE_UNSPECIFIED } +unit_advance; + + + +/* Statement parameters. These are all the things that can appear in + an I/O statement. Some are inputs and some are outputs, but none + are both. All of these values are initially zeroed and are zeroed + at the end of a library statement. The relevant values need to be + set before entry to an I/O statement. This structure needs to be + duplicated by the back end. */ + +typedef struct +{ + int unit; + int err, end, eor, list_format; /* These are flags, not values. */ + +/* Return values from library statements. These are returned only if + the labels are specified in the statement itself and the condition + occurs. In most cases, none of the labels are specified and the + return value does not have to be checked. Must be consistent with + the front end. */ + + enum + { + LIBRARY_OK = 0, + LIBRARY_ERROR, + LIBRARY_END, + LIBRARY_EOR + } + library_return; + + int *iostat, *exist, *opened, *number, *named, rec, *nextrec, *size; + + int recl_in; + int *recl_out; + + char *file; + int file_len; + char *status; + int status_len; + char *access; + int access_len; + char *form; + int form_len; + char *blank; + int blank_len; + char *position; + int position_len; + char *action; + int action_len; + char *delim; + int delim_len; + char *pad; + int pad_len; + char *format; + int format_len; + char *advance; + int advance_len; + char *name; + int name_len; + char *internal_unit; + int internal_unit_len; + char *sequential; + int sequential_len; + char *direct; + int direct_len; + char *formatted; + int formatted_len; + char *unformatted; + int unformatted_len; + char *read; + int read_len; + char *write; + int write_len; + char *readwrite; + int readwrite_len; + +/* namelist related data */ + char * namelist_name; + int namelist_name_len; + int namelist_read_mode; +} +st_parameter; + + + +#define ioparm prefix(ioparm) +extern st_parameter ioparm; + +#define ionml prefix(ionml) +extern namelist_info * ionml; + +typedef struct +{ + unit_access access; + unit_action action; + unit_blank blank; + unit_delim delim; + unit_form form; + int is_notpadded; + unit_position position; + unit_status status; + unit_pad pad; +} +unit_flags; + + +/* The default value of record length is defined here. This value can + be overriden by the OPEN statement or by an environment variable. */ + +#define DEFAULT_RECL 10000 + + +typedef struct unit_t +{ + int unit_number; + + stream *s; + + struct unit_t *left, *right; /* Treap links. */ + int priority; + + int read_bad, current_record; + enum + { NO_ENDFILE, AT_ENDFILE, AFTER_ENDFILE } + endfile; + + unit_flags flags; + offset_t recl, last_record, maxrec, bytes_left; + + /* recl -- Record length of the file. + last_record -- Last record number read or written + maxrec -- Maximum record number in a direct access file + bytes_left -- Bytes left in current record. */ + + int file_len; + char file[1]; /* Filename is allocated at the end of the structure. */ +} +unit_t; + +/* Global variables. Putting these in a structure makes it easier to + maintain, particularly with the constraint of a prefix. */ + +typedef struct +{ + int in_library; /* Nonzero if a library call is being processed. */ + int size; /* Bytes processed by the current data-transfer statement. */ + offset_t max_offset; /* Maximum file offset. */ + int item_count; /* Item number in a formatted data transfer. */ + int reversion_flag; /* Format reversion has occurred. */ + int first_item; + + unit_t *unit_root; + int seen_dollar; + + enum {READING, WRITING} mode; + + unit_blank blank_status; + enum {SIGN_S, SIGN_SS, SIGN_SP} sign_status; + int scale_factor; + jmp_buf eof_jump; +} +global_t; + + +#define g prefix(g) +extern global_t g; + + +#define current_unit prefix(current_unit) +extern unit_t *current_unit; + +/* Format tokens. Only about half of these can be stored in the + format nodes. */ + +typedef enum +{ + FMT_NONE = 0, FMT_UNKNOWN, FMT_SIGNED_INT, FMT_ZERO, FMT_POSINT, FMT_PERIOD, + FMT_COMMA, FMT_COLON, FMT_SLASH, FMT_DOLLAR, FMT_T, FMT_TR, FMT_TL, + FMT_LPAREN, FMT_RPAREN, FMT_X, FMT_S, FMT_SS, FMT_SP, FMT_STRING, + FMT_BADSTRING, FMT_P, FMT_I, FMT_B, FMT_BN, FMT_BZ, FMT_O, FMT_Z, FMT_F, + FMT_E, FMT_EN, FMT_ES, FMT_G, FMT_L, FMT_A, FMT_D, FMT_H, FMT_END +} +format_token; + + +/* Format nodes. A format string is converted into a tree of these + structures, which is traversed as part of a data transfer statement. */ + +typedef struct fnode +{ + format_token format; + int repeat; + struct fnode *next; + char *source; + + union + { + struct + { + int w, d, e; + } + real; + + struct + { + int length; + char *p; + } + string; + + struct + { + int w, m; + } + integer; + + int w; + int k; + int r; + int n; + + struct fnode *child; + } + u; + + /* Members for traversing the tree during data transfer. */ + + int count; + struct fnode *current; + +} +fnode; + + +/* unix.c */ + +#define sys_exit prefix(sys_exit) +void sys_exit (int) __attribute__ ((noreturn)); + +#define move_pos_offset prefix(move_pos_offset) +int move_pos_offset (stream *, int); + +#define get_oserror prefix(get_oserror) +const char *get_oserror (void); + +#define compare_files prefix(compare_files) +int compare_files (stream *, stream *); + +#define init_error_stream prefix(init_error_stream) +stream *init_error_stream (void); + +#define open_external prefix(open_external) +stream *open_external (unit_action, unit_status); + +#define open_internal prefix(open_internal) +stream *open_internal (char *, int); + +#define input_stream prefix(input_stream) +stream *input_stream (void); + +#define output_stream prefix(output_stream) +stream *output_stream (void); + +#define compare_file_filename prefix(compare_file_filename) +int compare_file_filename (stream *, const char *, int); + +#define find_file prefix(find_file) +unit_t *find_file (void); + +#define stream_at_bof prefix(stream_at_bof) +int stream_at_bof (stream *); + +#define stream_at_eof prefix(stream_at_eof) +int stream_at_eof (stream *); + +#define delete_file prefix(delete_file) +int delete_file (unit_t *); + +#define file_exists prefix(file_exists) +int file_exists (void); + +#define inquire_sequential prefix(inquire_sequential) +const char *inquire_sequential (const char *, int); + +#define inquire_direct prefix(inquire_direct) +const char *inquire_direct (const char *, int); + +#define inquire_formatted prefix(inquire_formatted) +const char *inquire_formatted (const char *, int); + +#define inquire_unformatted prefix(inquire_unformatted) +const char *inquire_unformatted (const char *, int); + +#define inquire_read prefix(inquire_read) +const char *inquire_read (const char *, int); + +#define inquire_write prefix(inquire_write) +const char *inquire_write (const char *, int); + +#define inquire_readwrite prefix(inquire_readwrite) +const char *inquire_readwrite (const char *, int); + +#define file_length prefix(file_length) +offset_t file_length (stream *); + +#define file_position prefix(file_position) +offset_t file_position (stream *); + +#define is_seekable prefix(is_seekable) +int is_seekable (stream *); + +#define empty_internal_buffer prefix(empty_internal_buffer) +void empty_internal_buffer(stream *); + + +/* unit.c */ + +#define insert_unit prefix(insert_unix) +void insert_unit (unit_t *); + +#define close_unit prefix(close_unit) +int close_unit (unit_t *); + +#define is_internal_unit prefix(is_internal_unit) +int is_internal_unit (void); + +#define find_unit prefix(find_unit) +unit_t *find_unit (int); + +#define get_unit prefix(get_unit) +unit_t *get_unit (int); + +/* open.c */ + +#define test_endfile prefix(test_endfile) +void test_endfile (unit_t *); + +#define new_unit prefix(new_unit) +void new_unit (unit_flags *); + +/* format.c */ + +#define parse_format prefix(parse_format) +void parse_format (void); + +#define next_format prefix(next_format) +fnode *next_format (void); + +#define unget_format prefix(unget_format) +void unget_format (fnode *); + +#define format_error prefix(format_error) +void format_error (fnode *, const char *); + +#define free_fnodes prefix(free_fnodes) +void free_fnodes (void); + +/* transfer.c */ + +#define SCRATCH_SIZE 300 + +#define scratch prefix(scratch) +extern char scratch[]; + +#define type_name prefix(type_name) +const char *type_name (bt); + +#define read_block prefix(read_block) +void *read_block (int *); + +#define write_block prefix(write_block) +void *write_block (int); + +#define transfer_integer prefix(transfer_integer) +void transfer_integer (void *, int); + +#define transfer_real prefix(transfer_real) +void transfer_real (void *, int); + +#define transfer_logical prefix(transfer_logical) +void transfer_logical (void *, int); + +#define transfer_character prefix(transfer_character) +void transfer_character (void *, int); + +#define transfer_complex prefix(transfer_complex) +void transfer_complex (void *, int); + +#define next_record prefix(next_record) +void next_record (int); + +#define st_set_nml_var_int prefix(st_set_nml_var_int) +void st_set_nml_var_int (void * , char * , int , int ); + +#define st_set_nml_var_float prefix(st_set_nml_var_float) +void st_set_nml_var_float (void * , char * , int , int ); + +#define st_set_nml_var_char prefix(st_set_nml_var_char) +void st_set_nml_var_char (void * , char * , int , int ); + +#define st_set_nml_var_complex prefix(st_set_nml_var_complex) +void st_set_nml_var_complex (void * , char * , int , int ); + +#define st_set_nml_var_log prefix(st_set_nml_var_log) +void st_set_nml_var_log (void * , char * , int , int ); + +/* read.c */ + +#define set_integer prefix(set_integer) +void set_integer (void *, int64_t, int); + +#define max_value prefix(max_value) +uint64_t max_value (int, int); + +#define convert_real prefix(convert_real) +int convert_real (void *, const char *, int); + +#define read_a prefix(read_a) +void read_a (fnode *, char *, int); + +#define read_f prefix(read_f) +void read_f (fnode *, char *, int); + +#define read_l prefix(read_l) +void read_l (fnode *, char *, int); + +#define read_x prefix(read_x) +void read_x (fnode *); + +#define read_radix prefix(read_radix) +void read_radix (fnode *, char *, int, int); + +#define read_decimal prefix(read_decimal) +void read_decimal (fnode *, char *, int); + +/* list_read.c */ + +#define list_formatted_read prefix(list_formatted_read) +void list_formatted_read (bt, void *, int); + +#define finish_list_read prefix(finish_list_read) +void finish_list_read (void); + +#define init_at_eol prefix(init_at_eol) +void init_at_eol(); + +#define namelist_read prefix(namelist_read) +void namelist_read(); + +#define namelist_write prefix(namelist_write) +void namelist_write(); + +/* write.c */ + +#define write_a prefix(write_a) +void write_a (fnode *, const char *, int); + +#define write_b prefix(write_b) +void write_b (fnode *, const char *, int); + +#define write_d prefix(write_d) +void write_d (fnode *, const char *, int); + +#define write_e prefix(write_e) +void write_e (fnode *, const char *, int); + +#define write_en prefix(write_en) +void write_en (fnode *, const char *, int); + +#define write_es prefix(write_es) +void write_es (fnode *, const char *, int); + +#define write_f prefix(write_f) +void write_f (fnode *, const char *, int); + +#define write_i prefix(write_i) +void write_i (fnode *, const char *, int); + +#define write_l prefix(write_l) +void write_l (fnode *, char *, int); + +#define write_o prefix(write_o) +void write_o (fnode *, const char *, int); + +#define write_x prefix(write_x) +void write_x (fnode *); + +#define write_z prefix(write_z) +void write_z (fnode *, const char *, int); + +#define list_formatted_write prefix(list_formatted_write) +void list_formatted_write (bt, void *, int); + + +#define st_open prefix(st_open) +#define st_close prefix(st_close) +#define st_inquire prefix(st_inquire) +#define st_rewind prefix(st_rewind) +#define st_read prefix(st_read) +#define st_read_done prefix(st_read_done) +#define st_write prefix(st_write) +#define st_write_done prefix(st_write_done) +#define st_backspace prefix(st_backspace) +#define st_endfile prefix(st_endfile) + + +void __MAIN (void); + +#endif diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c new file mode 100644 index 00000000000..2b62d31007c --- /dev/null +++ b/libgfortran/io/list_read.c @@ -0,0 +1,1531 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include +#include +#include "libgfortran.h" +#include "io.h" + + +/* List directed input. Several parsing subroutines are practically + * reimplemented from formatted input, the reason being that there are + * all kinds of small differences between formatted and list directed + * parsing. */ + + +/* Subroutines for reading characters from the input. Because a + * repeat count is ambiguous with an integer, we have to read the + * whole digit string before seeing if there is a '*' which signals + * the repeat count. Since we can have a lot of potential leading + * zeros, we have to be able to back up by arbitrary amount. Because + * the input might not be seekable, we have to buffer the data + * ourselves. Data is buffered in scratch[] until it becomes too + * large, after which we start allocating memory on the heap. */ + +static int repeat_count, saved_length, saved_used, input_complete, at_eol; +static int comma_flag, namelist_mode; + +static char last_char, *saved_string; +static bt saved_type; + + + +/* Storage area for values except for strings. Must be large enough + * to hold a complex value (two reals) of the largest kind */ + +static char value[20]; + +#define CASE_DIGITS case '0': case '1': case '2': case '3': case '4': \ + case '5': case '6': case '7': case '8': case '9' + +#define CASE_SEPARATORS case ' ': case ',': case '/': case '\n': case '\t' + +/* This macro assumes that we're operating on a variable */ + +#define is_separator(c) (c == '/' || c == ',' || c == '\n' || c == ' ' \ + || c == '\t') + +/* Maximum repeat count. Less than ten times the maximum signed int32. */ + +#define MAX_REPEAT 200000000 + + +/* push_char()-- Save a character to a string buffer, enlarging it as + * necessary. */ + +static void +push_char (char c) +{ + char *new; + + if (saved_string == NULL) + { + saved_string = scratch; + memset (saved_string,0,SCRATCH_SIZE); + saved_length = SCRATCH_SIZE; + saved_used = 0; + } + + if (saved_used >= saved_length) + { + saved_length = 2 * saved_length; + new = get_mem (2 * saved_length); + + memset (new,0,2 * saved_length); + + memcpy (new, saved_string, saved_used); + if (saved_string != scratch) + free_mem (saved_string); + + saved_string = new; + } + + saved_string[saved_used++] = c; +} + + +/* free_saved()-- Free the input buffer if necessary. */ + +static void +free_saved (void) +{ + + if (saved_string == NULL) + return; + + if (saved_string != scratch) + free_mem (saved_string); + + saved_string = NULL; +} + + +static char +next_char (void) +{ + int length; + char c, *p; + + if (last_char != '\0') + { + at_eol = 0; + c = last_char; + last_char = '\0'; + goto done; + } + + length = 1; + + p = salloc_r (current_unit->s, &length); + if (p == NULL) + { + generate_error (ERROR_OS, NULL); + return '\0'; + } + + if (length == 0) + longjmp (g.eof_jump, 1); + c = *p; + +done: + at_eol = (c == '\n'); + return c; +} + + +/* unget_char()-- Push a character back onto the input */ + +static void +unget_char (char c) +{ + + last_char = c; +} + + +/* eat_spaces()-- Skip over spaces in the input. Returns the nonspace + * character that terminated the eating and also places it back on the + * input. */ + +static char +eat_spaces (void) +{ + char c; + + do + { + c = next_char (); + } + while (c == ' ' || c == '\t'); + + unget_char (c); + return c; +} + + +/* eat_separator()-- Skip over a separator. Technically, we don't + * always eat the whole separator. This is because if we've processed + * the last input item, then a separator is unnecessary. Plus the + * fact that operating systems usually deliver console input on a line + * basis. + * + * The upshot is that if we see a newline as part of reading a + * separator, we stop reading. If there are more input items, we + * continue reading the separator with finish_separator() which takes + * care of the fact that we may or may not have seen a comma as part + * of the separator. */ + +static void +eat_separator (void) +{ + char c; + + eat_spaces (); + comma_flag = 0; + + c = next_char (); + switch (c) + { + case ',': + comma_flag = 1; + eat_spaces (); + break; + + case '/': + input_complete = 1; + next_record (0); + break; + + case '\n': + break; + + case '!': + if (namelist_mode) + { /* Eat a namelist comment */ + do + c = next_char (); + while (c != '\n'); + + break; + } + + /* Fall Through */ + + default: + unget_char (c); + break; + } +} + + +/* finish_separator()-- Finish processing a separator that was + * interrupted by a newline. If we're here, then another data item is + * present, so we finish what we started on the previous line. */ + +static void +finish_separator (void) +{ + char c; + +restart: + eat_spaces (); + + c = next_char (); + switch (c) + { + case ',': + if (comma_flag) + unget_char (c); + else + { + c = eat_spaces (); + if (c == '\n') + goto restart; + } + + break; + + case '/': + input_complete = 1; + next_record (0); + break; + + case '\n': + goto restart; + + case '!': + if (namelist_mode) + { + do + c = next_char (); + while (c != '\n'); + + goto restart; + } + + default: + unget_char (c); + break; + } +} + + +/* convert_integer()-- Convert an unsigned string to an integer. The + * length value is -1 if we are working on a repeat count. Returns + * nonzero if we have a range problem. As a side effect, frees the + * saved_string. */ + +static int +convert_integer (int length, int negative) +{ + char c, *buffer, message[100]; + int m; + int64_t v, max, max10; + + buffer = saved_string; + v = 0; + + max = (length == -1) ? MAX_REPEAT : max_value (length, 1); + max10 = max / 10; + + for (;;) + { + c = *buffer++; + if (c == '\0') + break; + c -= '0'; + + if (v > max10) + goto overflow; + v = 10 * v; + + if (v > max - c) + goto overflow; + v += c; + } + + m = 0; + + if (length != -1) + { + if (negative) + v = -v; + set_integer (value, v, length); + } + else + { + repeat_count = v; + + if (repeat_count == 0) + { + st_sprintf (message, "Zero repeat count in item %d of list input", + g.item_count); + + generate_error (ERROR_READ_VALUE, message); + m = 1; + } + } + + free_saved (); + return m; + +overflow: + if (length == -1) + st_sprintf (message, "Repeat count overflow in item %d of list input", + g.item_count); + else + st_sprintf (message, "Integer overflow while reading item %d", + g.item_count); + + free_saved (); + generate_error (ERROR_READ_VALUE, message); + + return 1; +} + + +/* parse_repeat()-- Parse a repeat count for logical and complex + * values which cannot begin with a digit. Returns nonzero if we are + * done, zero if we should continue on. */ + +static int +parse_repeat (void) +{ + char c, message[100]; + int repeat; + + c = next_char (); + switch (c) + { + CASE_DIGITS: + repeat = c - '0'; + break; + + CASE_SEPARATORS: + unget_char (c); + eat_separator (); + return 1; + + default: + unget_char (c); + return 0; + } + + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + repeat = 10 * repeat + c - '0'; + + if (repeat > MAX_REPEAT) + { + st_sprintf (message, + "Repeat count overflow in item %d of list input", + g.item_count); + + generate_error (ERROR_READ_VALUE, message); + return 1; + } + + break; + + case '*': + if (repeat == 0) + { + st_sprintf (message, + "Zero repeat count in item %d of list input", + g.item_count); + + generate_error (ERROR_READ_VALUE, message); + return 1; + } + + goto done; + + default: + goto bad_repeat; + } + } + +done: + repeat_count = repeat; + return 0; + +bad_repeat: + st_sprintf (message, "Bad repeat count in item %d of list input", + g.item_count); + + generate_error (ERROR_READ_VALUE, message); + return 1; +} + + +/* read_logical()-- Read a logical character on the input */ + +static void +read_logical (int length) +{ + char c, message[100]; + int v; + + if (parse_repeat ()) + return; + + c = next_char (); + switch (c) + { + case 't': + case 'T': + v = 1; + break; + case 'f': + case 'F': + v = 0; + break; + + case '.': + c = next_char (); + switch (c) + { + case 't': + case 'T': + v = 1; + break; + case 'f': + case 'F': + v = 0; + break; + default: + goto bad_logical; + } + + break; + + CASE_SEPARATORS: + unget_char (c); + eat_separator (); + return; /* Null value */ + + default: + goto bad_logical; + } + + saved_type = BT_LOGICAL; + saved_length = length; + + /* Eat trailing garbage */ + + do + { + c = next_char (); + } + while (!is_separator (c)); + + unget_char (c); + eat_separator (); + free_saved (); + set_integer ((int *) value, v, length); + + return; + +bad_logical: + st_sprintf (message, "Bad logical value while reading item %d", + g.item_count); + + generate_error (ERROR_READ_VALUE, message); +} + + +/* read_integer()-- Reading integers is tricky because we can actually + * be reading a repeat count. We have to store the characters in a + * buffer because we could be reading an integer that is larger than the + * default int used for repeat counts. */ + +static void +read_integer (int length) +{ + char c, message[100]; + int negative; + + negative = 0; + + c = next_char (); + switch (c) + { + case '-': + negative = 1; + /* Fall through */ + + case '+': + c = next_char (); + goto get_integer; + + CASE_SEPARATORS: /* Single null */ + unget_char (c); + eat_separator (); + return; + + CASE_DIGITS: + push_char (c); + break; + + default: + goto bad_integer; + } + + /* Take care of what may be a repeat count */ + + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + case '*': + push_char ('\0'); + goto repeat; + + CASE_SEPARATORS: /* Not a repeat count */ + goto done; + + default: + goto bad_integer; + } + } + +repeat: + if (convert_integer (-1, 0)) + return; + +/* Get the real integer */ + + c = next_char (); + switch (c) + { + CASE_DIGITS: + break; + + CASE_SEPARATORS: + unget_char (c); + eat_separator (); + return; + + case '-': + negative = 1; + /* Fall through */ + + case '+': + c = next_char (); + break; + } + +get_integer: + if (!isdigit (c)) + goto bad_integer; + push_char (c); + + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + CASE_SEPARATORS: + goto done; + + default: + goto bad_integer; + } + } + +bad_integer: + free_saved (); + + st_sprintf (message, "Bad integer for item %d in list input", g.item_count); + generate_error (ERROR_READ_VALUE, message); + + return; + +done: + unget_char (c); + eat_separator (); + + push_char ('\0'); + if (convert_integer (length, negative)) + { + free_saved (); + return; + } + + free_saved (); + saved_type = BT_INTEGER; +} + + +/* read_character()-- Read a character variable */ + +static void +read_character (int length) +{ + char c, quote, message[100]; + + quote = ' '; /* Space means no quote character */ + + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + CASE_SEPARATORS: + unget_char (c); /* NULL value */ + eat_separator (); + return; + + case '"': + case '\'': + quote = c; + goto get_string; + + default: + push_char (c); + goto get_string; + } + +/* Deal with a possible repeat count */ + + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + CASE_SEPARATORS: + unget_char (c); + goto done; /* String was only digits! */ + + case '*': + push_char ('\0'); + goto got_repeat; + + default: + push_char (c); + goto get_string; /* Not a repeat count after all */ + } + } + +got_repeat: + if (convert_integer (-1, 0)) + return; + + /* Now get the real string */ + + c = next_char (); + switch (c) + { + CASE_SEPARATORS: + unget_char (c); /* repeated NULL values */ + eat_separator (); + return; + + case '"': + case '\'': + quote = c; + break; + + default: + push_char (c); + break; + } + +get_string: + for (;;) + { + c = next_char (); + switch (c) + { + case '"': + case '\'': + if (c != quote) + { + push_char (c); + break; + } + + /* See if we have a doubled quote character or the end of the string */ + + c = next_char (); + if (c == quote) + { + push_char (quote); + break; + } + + unget_char (c); + goto done; + + CASE_SEPARATORS: + if (quote == ' ') + { + unget_char (c); + goto done; + } + + if (c != '\n') + push_char (c); + break; + + default: + push_char (c); + break; + } + } + +/* At this point, we have to have a separator, or else the string is invalid */ + +done: + c = next_char (); + if (is_separator (c)) + { + unget_char (c); + eat_separator (); + saved_type = BT_CHARACTER; + } + else + { + free_saved (); + st_sprintf (message, "Invalid string input in item %d", g.item_count); + generate_error (ERROR_READ_VALUE, message); + } +} + + +/* parse_real()-- Parse a component of a complex constant or a real + * number that we are sure is already there. This is a straight real + * number parser. */ + +static int +parse_real (void *buffer, int length) +{ + char c, message[100]; + int m, seen_dp; + + c = next_char (); + if (c == '-' || c == '+') + { + push_char (c); + c = next_char (); + } + + if (!isdigit (c) && c != '.') + goto bad; + + push_char (c); + + seen_dp = (c == '.') ? 1 : 0; + + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + case '.': + if (seen_dp) + goto bad; + + seen_dp = 1; + push_char (c); + break; + + case 'e': + case 'E': + case 'd': + case 'D': + push_char ('e'); + goto exp1; + + case '-': + case '+': + push_char ('e'); + push_char (c); + c = next_char (); + goto exp2; + + CASE_SEPARATORS: + unget_char (c); + goto done; + + default: + goto done; + } + } + +exp1: + c = next_char (); + if (c != '-' && c != '+') + push_char ('+'); + else + { + push_char (c); + c = next_char (); + } + +exp2: + if (!isdigit (c)) + goto bad; + push_char (c); + + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + CASE_SEPARATORS: + unget_char (c); + goto done; + + default: + goto done; + } + } + +done: + unget_char (c); + push_char ('\0'); + + m = convert_real (buffer, saved_string, length); + free_saved (); + + return m; + +bad: + free_saved (); + st_sprintf (message, "Bad floating point number for item %d", g.item_count); + generate_error (ERROR_READ_VALUE, message); + + return 1; +} + + +/* read_complex()-- Reading a complex number is straightforward + * because we can tell what it is right away. */ + +static void +read_complex (int length) +{ + char message[100]; + char c; + + if (parse_repeat ()) + return; + + c = next_char (); + switch (c) + { + case '(': + break; + + CASE_SEPARATORS: + unget_char (c); + eat_separator (); + return; + + default: + goto bad_complex; + } + + eat_spaces (); + if (parse_real (value, length)) + return; + + eat_spaces (); + if (next_char () != ',') + goto bad_complex; + + eat_spaces (); + if (parse_real (value + length, length)) + return; + + eat_spaces (); + if (next_char () != ')') + goto bad_complex; + + c = next_char (); + if (!is_separator (c)) + goto bad_complex; + + unget_char (c); + eat_separator (); + + free_saved (); + saved_type = BT_COMPLEX; + return; + +bad_complex: + st_sprintf (message, "Bad complex value in item %d of list input", + g.item_count); + + generate_error (ERROR_READ_VALUE, message); +} + + +/* read_real()-- Parse a real number with a possible repeat count. */ + +static void +read_real (int length) +{ + char c, message[100]; + int seen_dp; + + seen_dp = 0; + + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + case '.': + push_char (c); + seen_dp = 1; + break; + + case '+': + case '-': + goto got_sign; + + CASE_SEPARATORS: + unget_char (c); /* Single null */ + eat_separator (); + return; + + default: + goto bad_real; + } + + /* Get the digit string that might be a repeat count */ + + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + case '.': + if (seen_dp) + goto bad_real; + + seen_dp = 1; + push_char (c); + goto real_loop; + + case 'E': + case 'e': + case 'D': + case 'd': + goto exp1; + + case '+': + case '-': + push_char ('e'); + push_char (c); + c = next_char (); + goto exp2; + + case '*': + push_char ('\0'); + goto got_repeat; + + CASE_SEPARATORS: + if (c != '\n') + unget_char (c); /* Real number that is just a digit-string */ + goto done; + + default: + goto bad_real; + } + } + +got_repeat: + if (convert_integer (-1, 0)) + return; + +/* Now get the number itself */ + + c = next_char (); + if (is_separator (c)) + { /* Repeated null value */ + unget_char (c); + eat_separator (); + return; + } + + if (c != '-' && c != '+') + push_char ('+'); + else + { + got_sign: + push_char (c); + c = next_char (); + } + + if (!isdigit (c) && c != '.') + goto bad_real; + + if (c == '.') + { + if (seen_dp) + goto bad_real; + else + seen_dp = 1; + } + + push_char (c); + +real_loop: + for (;;) + { + c = next_char (); + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + CASE_SEPARATORS: + goto done; + + case '.': + if (seen_dp) + goto bad_real; + + seen_dp = 1; + push_char (c); + break; + + case 'E': + case 'e': + case 'D': + case 'd': + goto exp1; + + case '+': + case '-': + push_char ('e'); + push_char (c); + c = next_char (); + goto exp2; + + default: + goto bad_real; + } + } + +exp1: + push_char ('e'); + + c = next_char (); + if (c != '+' && c != '-') + push_char ('+'); + else + { + push_char (c); + c = next_char (); + } + +exp2: + if (!isdigit (c)) + goto bad_real; + push_char (c); + + for (;;) + { + c = next_char (); + + switch (c) + { + CASE_DIGITS: + push_char (c); + break; + + CASE_SEPARATORS: + unget_char (c); + eat_separator (); + goto done; + + default: + goto bad_real; + } + } + +done: + push_char ('\0'); + if (convert_real (value, saved_string, length)) + return; + + free_saved (); + saved_type = BT_REAL; + return; + +bad_real: + st_sprintf (message, "Bad real number in item %d of list input", + g.item_count); + + generate_error (ERROR_READ_VALUE, message); +} + + +/* check_type()-- Check the current type against the saved type to + * make sure they are compatible. Returns nonzero if incompatible. */ + +static int +check_type (bt type, int len) +{ + char message[100]; + + if (saved_type != BT_NULL && saved_type != type) + { + st_sprintf (message, "Read type %s where %s was expected for item %d", + type_name (saved_type), type_name (type), g.item_count); + + generate_error (ERROR_READ_VALUE, message); + return 1; + } + + if (saved_type == BT_NULL || saved_type == BT_CHARACTER) + return 0; + + if (saved_length != len) + { + st_sprintf (message, + "Read kind %d %s where kind %d is required for item %d", + saved_length, type_name (saved_type), len, g.item_count); + generate_error (ERROR_READ_VALUE, message); + return 1; + } + + return 0; +} + + +/* list_formatted_read()-- Top level data transfer subroutine for list + * reads. Because we have to deal with repeat counts, the data item + * is always saved after reading, usually in the value[] array. If a + * repeat count is greater than one, we copy the data item multiple + * times. */ + +void +list_formatted_read (bt type, void *p, int len) +{ + char c; + int m; + + namelist_mode = 0; + + if (setjmp (g.eof_jump)) + { + generate_error (ERROR_END, NULL); + return; + } + + if (g.first_item) + { + g.first_item = 0; + input_complete = 0; + repeat_count = 1; + at_eol = 0; + + c = eat_spaces (); + if (is_separator (c)) + { /* Found a null value */ + eat_separator (); + repeat_count = 0; + if (at_eol) + finish_separator (); + else + return; + } + + } + else + { + if (input_complete) + return; + + if (repeat_count > 0) + { + if (check_type (type, len)) + return; + goto set_value; + } + + if (at_eol) + finish_separator (); + else + eat_spaces (); + + saved_type = BT_NULL; + repeat_count = 1; + } + + + switch (type) + { + case BT_INTEGER: + read_integer (len); + break; + case BT_LOGICAL: + read_logical (len); + break; + case BT_CHARACTER: + read_character (len); + break; + case BT_REAL: + read_real (len); + break; + case BT_COMPLEX: + read_complex (len); + break; + default: + internal_error ("Bad type for list read"); + } + + if (saved_type != BT_CHARACTER && saved_type != BT_NULL) + saved_length = len; + + if (ioparm.library_return != LIBRARY_OK) + return; + +set_value: + switch (saved_type) + { + case BT_COMPLEX: + len = 2 * len; + /* Fall through */ + + case BT_INTEGER: + case BT_REAL: + case BT_LOGICAL: + memcpy (p, value, len); + break; + + case BT_CHARACTER: + m = (len < saved_used) ? len : saved_used; + memcpy (p, saved_string, m); + + if (m < len) + memset (((char *) p) + m, ' ', len - m); + break; + + case BT_NULL: + break; + } + + if (--repeat_count <= 0) + free_saved (); +} + +void +init_at_eol() +{ + at_eol = 0; +} + +/* finish_list_read()-- Finish a list read */ + +void +finish_list_read (void) +{ + char c; + + free_saved (); + + if (at_eol) + { + at_eol = 0; + return; + } + + + do + { + c = next_char (); + } + while (c != '\n'); +} + +static namelist_info * +find_nml_node (char * var_name) +{ + namelist_info * t = ionml; + while (t != NULL) + { + if (strcmp (var_name,t->var_name) == 0) + { + t->value_acquired = 1; + return t; + } + t = t->next; + } + return NULL; +} + +static void +match_namelist_name (char *name, int len) +{ + int name_len; + char c; + char * namelist_name = name; + + name_len = 0; + /* Match the name of the namelist */ + + if (tolower (next_char ()) != tolower (namelist_name[name_len++])) + { + wrong_name: + generate_error (ERROR_READ_VALUE, "Wrong namelist name found"); + return; + } + + while (name_len < len) + { + c = next_char (); + if (tolower (c) != tolower (namelist_name[name_len++])) + goto wrong_name; + } +} + + +/******************************************************************** + Namelist reads +********************************************************************/ + +/* namelist_read()-- Process a namelist read. This subroutine + * initializes things, positions to the first element and */ + +void +namelist_read (void) +{ + char c; + int name_matched, next_name ; + namelist_info * nl; + int len, m; + void * p; + + namelist_mode = 1; + + if (setjmp (g.eof_jump)) + { + generate_error (ERROR_END, NULL); + return; + } + +restart: + c = next_char (); + switch (c) + { + case ' ': + goto restart; + case '!': + do + c = next_char (); + while (c != '\n'); + + goto restart; + + case '&': + break; + + default: + generate_error (ERROR_READ_VALUE, "Invalid character in namelist"); + return; + } + + /* Match the name of the namelist */ + match_namelist_name(ioparm.namelist_name, ioparm.namelist_name_len); + + /* Ready to read namelist elements */ + for (;;) + { + c = next_char (); + switch (c) + { + case '&': + match_namelist_name("end",3); + return; + case '\\': + return; + case ' ': + case '\n': + case '\t': + break; + case ',': + next_name = 1; + break; + + case '=': + name_matched = 1; + nl = find_nml_node (saved_string); + if (nl == NULL) + internal_error ("Can not found a valid namelist var!"); + free_saved(); + + len = nl->len; + p = nl->mem_pos; + switch (nl->type) + { + case BT_INTEGER: + read_integer (len); + break; + case BT_LOGICAL: + read_logical (len); + break; + case BT_CHARACTER: + read_character (len); + break; + case BT_REAL: + read_real (len); + break; + case BT_COMPLEX: + read_complex (len); + break; + default: + internal_error ("Bad type for namelist read"); + } + + switch (saved_type) + { + case BT_COMPLEX: + len = 2 * len; + /* Fall through */ + + case BT_INTEGER: + case BT_REAL: + case BT_LOGICAL: + memcpy (p, value, len); + break; + + case BT_CHARACTER: + m = (len < saved_used) ? len : saved_used; + memcpy (p, saved_string, m); + + if (m < len) + memset (((char *) p) + m, ' ', len - m); + break; + + case BT_NULL: + break; + } + + break; + + default : + push_char(c); + break; + } + } +} + diff --git a/libgfortran/io/lock.c b/libgfortran/io/lock.c new file mode 100644 index 00000000000..1d3f06912e0 --- /dev/null +++ b/libgfortran/io/lock.c @@ -0,0 +1,84 @@ +/* Thread/recursion locking + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook and Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include "libgfortran.h" +#include "io.h" + +st_parameter ioparm; +namelist_info * ionml; +global_t g; + + +/* library_start()-- Called with a library call is entered. */ + +void +library_start (void) +{ + + if (g.in_library) + internal_error ("Recursive library calls not allowed"); + +/* The in_library flag indicates whether we're currently processing a + * library call. Some calls leave immediately, but READ and WRITE + * processing return control to the caller but are still considered to + * stay within the library. */ + + g.in_library = 1; + + if (ioparm.iostat != NULL && ioparm.library_return == LIBRARY_OK) + *ioparm.iostat = ERROR_OK; + + ioparm.library_return = LIBRARY_OK; +} + + +/* library_end()-- Called when a library call is complete in order to + * clean up for the next call. */ + +void +library_end (void) +{ + int t; + namelist_info * t1, *t2; + + g.in_library = 0; + filename = NULL; + line = 0; + + t = ioparm.library_return; + if (ionml != NULL) + { + t1 = ionml; + while (t1 != NULL) + { + t2 = t1; + t1 = t1->next; + free_mem (t2); + } + } + + ionml = NULL; + memset (&ioparm, '\0', sizeof (ioparm)); + ioparm.library_return = t; +} + diff --git a/libgfortran/io/open.c b/libgfortran/io/open.c new file mode 100644 index 00000000000..e6fa50d776a --- /dev/null +++ b/libgfortran/io/open.c @@ -0,0 +1,528 @@ + +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" +#include "io.h" + + +static st_option access_opt[] = { + {"sequential", ACCESS_SEQUENTIAL}, + {"direct", ACCESS_DIRECT}, + {NULL} +}, action_opt[] = +{ + { + "read", ACTION_READ} + , + { + "write", ACTION_WRITE} + , + { + "readwrite", ACTION_READWRITE} + , + { + NULL} +} + +, blank_opt[] = +{ + { + "null", BLANK_NULL} + , + { + "zero", BLANK_ZERO} + , + { + NULL} +} + +, delim_opt[] = +{ + { + "none", DELIM_NONE} + , + { + "apostrophe", DELIM_APOSTROPHE} + , + { + "quote", DELIM_QUOTE} + , + { + NULL} +} + +, form_opt[] = +{ + { + "formatted", FORM_FORMATTED} + , + { + "unformatted", FORM_UNFORMATTED} + , + { + NULL} +} + +, position_opt[] = +{ + { + "asis", POSITION_ASIS} + , + { + "rewind", POSITION_REWIND} + , + { + "append", POSITION_APPEND} + , + { + NULL} +} + +, status_opt[] = +{ + { + "unknown", STATUS_UNKNOWN} + , + { + "old", STATUS_OLD} + , + { + "new", STATUS_NEW} + , + { + "replace", STATUS_REPLACE} + , + { + "scratch", STATUS_SCRATCH} + , + { + NULL} +} + +, pad_opt[] = +{ + { + "yes", PAD_YES} + , + { + "no", PAD_NO} + , + { + NULL} +}; + + +/* test_endfile()-- Given a unit, test to see if the file is + * positioned at the terminal point, and if so, change state from + * NO_ENDFILE flag to AT_ENDFILE. This prevents us from changing the + * state from AFTER_ENDFILE to AT_ENDFILE. */ + +void +test_endfile (unit_t * u) +{ + + if (u->endfile == NO_ENDFILE && file_length (u->s) == file_position (u->s)) + u->endfile = AT_ENDFILE; +} + + +/* edit_modes()-- Change the modes of a file, those that are allowed + * to be changed. */ + +static void +edit_modes (unit_t * u, unit_flags * flags) +{ + + /* Complain about attempts to change the unchangeable */ + + if (flags->status != STATUS_UNSPECIFIED && + u->flags.status != flags->position) + generate_error (ERROR_BAD_OPTION, + "Cannot change STATUS parameter in OPEN statement"); + + if (flags->access != ACCESS_UNSPECIFIED && u->flags.access != flags->access) + generate_error (ERROR_BAD_OPTION, + "Cannot change ACCESS parameter in OPEN statement"); + + if (flags->form != FORM_UNSPECIFIED && u->flags.form != flags->form) + generate_error (ERROR_BAD_OPTION, + "Cannot change FORM parameter in OPEN statement"); + + if (ioparm.recl_in != 0 && ioparm.recl_in != u->recl) + generate_error (ERROR_BAD_OPTION, + "Cannot change RECL parameter in OPEN statement"); + + if (flags->action != ACTION_UNSPECIFIED && u->flags.access != flags->access) + generate_error (ERROR_BAD_OPTION, + "Cannot change ACTION parameter in OPEN statement"); + + /* Status must be OLD if present */ + + if (flags->status != STATUS_UNSPECIFIED && flags->status != STATUS_OLD) + generate_error (ERROR_BAD_OPTION, + "OPEN statement must have a STATUS of OLD"); + + if (u->flags.form == FORM_UNFORMATTED) + { + if (flags->delim != DELIM_UNSPECIFIED) + generate_error (ERROR_OPTION_CONFLICT, + "DELIM parameter conflicts with UNFORMATTED form in " + "OPEN statement"); + + if (flags->blank != BLANK_UNSPECIFIED) + generate_error (ERROR_OPTION_CONFLICT, + "BLANK parameter conflicts with UNFORMATTED form in " + "OPEN statement"); + + if (flags->pad != PAD_UNSPECIFIED) + generate_error (ERROR_OPTION_CONFLICT, + "PAD paramter conflicts with UNFORMATTED form in " + "OPEN statement"); + } + + if (ioparm.library_return == LIBRARY_OK) + { /* Change the changeable */ + if (flags->blank != BLANK_UNSPECIFIED) + u->flags.blank = flags->blank; + if (flags->delim != DELIM_UNSPECIFIED) + u->flags.delim = flags->delim; + if (flags->pad != PAD_UNSPECIFIED) + u->flags.pad = flags->pad; + } + + /* Reposition the file if necessary. */ + + switch (flags->position) + { + case POSITION_UNSPECIFIED: + case POSITION_ASIS: + break; + + case POSITION_REWIND: + if (sseek (u->s, 0) == FAILURE) + goto seek_error; + + u->current_record = 0; + u->last_record = 0; + + test_endfile (u); /* We might be at the end */ + break; + + case POSITION_APPEND: + if (sseek (u->s, file_length (u->s)) == FAILURE) + goto seek_error; + + u->current_record = 0; + u->endfile = AT_ENDFILE; /* We are at the end */ + break; + + seek_error: + generate_error (ERROR_OS, NULL); + break; + } +} + + +/* new_unit()-- Open an unused unit */ + +void +new_unit (unit_flags * flags) +{ + unit_t *u; + stream *s; + char tmpname[5 /* fort. */ + 10 /* digits of unit number */ + 1 /* 0 */]; + + /* Change unspecifieds to defaults */ + + if (flags->access == ACCESS_UNSPECIFIED) + flags->access = ACCESS_SEQUENTIAL; + + if (flags->action == ACTION_UNSPECIFIED) + flags->action = ACTION_READWRITE; /* Processor dependent */ + + if (flags->form == FORM_UNSPECIFIED) + flags->form = (flags->access == ACCESS_SEQUENTIAL) + ? FORM_FORMATTED : FORM_UNFORMATTED; + + + if (flags->delim == DELIM_UNSPECIFIED) + flags->delim = DELIM_NONE; + else + { + if (flags->form == FORM_UNFORMATTED) + { + generate_error (ERROR_OPTION_CONFLICT, + "DELIM parameter conflicts with UNFORMATTED form in " + "OPEN statement"); + goto cleanup; + } + } + + if (flags->blank == BLANK_UNSPECIFIED) + flags->blank = BLANK_NULL; + else + { + if (flags->form == FORM_UNFORMATTED) + { + generate_error (ERROR_OPTION_CONFLICT, + "BLANK parameter conflicts with UNFORMATTED form in " + "OPEN statement"); + goto cleanup; + } + } + + if (flags->pad == PAD_UNSPECIFIED) + flags->pad = PAD_YES; + else + { + if (flags->form == FORM_UNFORMATTED) + { + generate_error (ERROR_OPTION_CONFLICT, + "PAD paramter conflicts with UNFORMATTED form in " + "OPEN statement"); + goto cleanup; + } + } + + if (flags->position != POSITION_ASIS && flags->access == ACCESS_DIRECT) + { + generate_error (ERROR_OPTION_CONFLICT, + "ACCESS parameter conflicts with SEQUENTIAL access in " + "OPEN statement"); + goto cleanup; + } + else + if (flags->position == POSITION_UNSPECIFIED) + flags->position = POSITION_ASIS; + + + if (flags->status == STATUS_UNSPECIFIED) + flags->status = STATUS_UNKNOWN; + + /* Checks */ + + if (flags->access == ACCESS_DIRECT && ioparm.recl_in == 0) + { + generate_error (ERROR_MISSING_OPTION, + "Missing RECL parameter in OPEN statement"); + goto cleanup; + } + + if (ioparm.recl_in != 0 && ioparm.recl_in <= 0) + { + generate_error (ERROR_BAD_OPTION, + "RECL parameter is non-positive in OPEN statement"); + goto cleanup; + } + + switch (flags->status) + { + case STATUS_SCRATCH: + if (ioparm.file == NULL) + break; + + generate_error (ERROR_BAD_OPTION, + "FILE parameter must not be present in OPEN statement"); + return; + + case STATUS_OLD: + case STATUS_NEW: + case STATUS_REPLACE: + case STATUS_UNKNOWN: + if (ioparm.file != NULL) + break; + + ioparm.file = tmpname; + ioparm.file_len = sprintf(ioparm.file, "fort.%d", ioparm.unit); + break; + + default: + internal_error ("new_unit(): Bad status"); + } + + /* Make sure the file isn't already open someplace else */ + + if (find_file () != NULL) + { + generate_error (ERROR_ALREADY_OPEN, NULL); + goto cleanup; + } + + /* Open file */ + + s = open_external (flags->action, flags->status); + if (s == NULL) + { + generate_error (ERROR_OS, NULL); + goto cleanup; + } + + if (flags->status == STATUS_NEW || flags->status == STATUS_REPLACE) + flags->status = STATUS_OLD; + + /* Create the unit structure */ + + u = get_mem (sizeof (unit_t) + ioparm.file_len); + + u->unit_number = ioparm.unit; + u->s = s; + u->flags = *flags; + + /* Unspecified recl ends up with a processor dependent value */ + + u->recl = (ioparm.recl_in != 0) ? ioparm.recl_in : DEFAULT_RECL; + u->last_record = 0; + u->current_record = 0; + + /* If the file is direct access, calculate the maximum record number + * via a division now instead of letting the multiplication overflow + * later. */ + + if (flags->access == ACCESS_DIRECT) + u->maxrec = g.max_offset / u->recl; + + memmove (u->file, ioparm.file, ioparm.file_len); + u->file_len = ioparm.file_len; + + insert_unit (u); + + /* The file is now connected. Errors after this point leave the + * file connected. Curiously, the standard requires that the + * position specifier be ignored for new files so a newly connected + * file starts out that the initial point. We still need to figure + * out if the file is at the end or not. */ + + test_endfile (u); + +cleanup: + + /* Free memory associated with a temporary filename */ + + if (flags->status == STATUS_SCRATCH) + free_mem (ioparm.file); +} + + +/* already_open()-- Open a unit which is already open. This involves + * changing the modes or closing what is there now and opening the new + * file. */ + +static void +already_open (unit_t * u, unit_flags * flags) +{ + + if (ioparm.file == NULL) + { + edit_modes (u, flags); + return; + } + + /* If the file is connected to something else, close it and open a + * new unit */ + + if (!compare_file_filename (u->s, ioparm.file, ioparm.file_len)) + { + if (close_unit (u)) + { + generate_error (ERROR_OS, "Error closing file in OPEN statement"); + return; + } + + new_unit (flags); + return; + } + + edit_modes (u, flags); +} + + +/*************/ +/* open file */ + +void +st_open (void) +{ + unit_flags flags; + unit_t *u = NULL; + + library_start (); + + /* Decode options */ + + flags.access = (ioparm.access == NULL) ? ACCESS_UNSPECIFIED : + find_option (ioparm.access, ioparm.access_len, access_opt, + "Bad ACCESS parameter in OPEN statement"); + + flags.action = (ioparm.action == NULL) ? ACTION_UNSPECIFIED : + find_option (ioparm.action, ioparm.action_len, action_opt, + "Bad ACTION parameter in OPEN statement"); + + flags.blank = (ioparm.blank == NULL) ? BLANK_UNSPECIFIED : + find_option (ioparm.blank, ioparm.blank_len, blank_opt, + "Bad BLANK parameter in OPEN statement"); + + flags.delim = (ioparm.delim == NULL) ? DELIM_UNSPECIFIED : + find_option (ioparm.delim, ioparm.delim_len, delim_opt, + "Bad DELIM parameter in OPEN statement"); + + flags.pad = (ioparm.pad == NULL) ? PAD_UNSPECIFIED : + find_option (ioparm.pad, ioparm.pad_len, pad_opt, + "Bad PAD parameter in OPEN statement"); + + flags.form = (ioparm.form == NULL) ? FORM_UNSPECIFIED : + find_option (ioparm.form, ioparm.form_len, form_opt, + "Bad FORM parameter in OPEN statement"); + + flags.position = (ioparm.position == NULL) ? POSITION_UNSPECIFIED : + find_option (ioparm.position, ioparm.position_len, position_opt, + "Bad POSITION parameter in OPEN statement"); + + flags.status = (ioparm.status == NULL) ? STATUS_UNSPECIFIED : + find_option (ioparm.status, ioparm.status_len, status_opt, + "Bad STATUS parameter in OPEN statement"); + + if (ioparm.unit < 0) + generate_error (ERROR_BAD_OPTION, "Bad unit number in OPEN statement"); + + if (flags.position != POSITION_UNSPECIFIED && + u->flags.access == ACCESS_DIRECT) + generate_error (ERROR_BAD_OPTION, + "Cannot use POSITION with direct access files"); + + if (flags.position == POSITION_UNSPECIFIED) + flags.position = POSITION_ASIS; + + if (ioparm.library_return != LIBRARY_OK) + return; + + u = find_unit (ioparm.unit); + + if (u == NULL) + new_unit (&flags); + else + already_open (u, &flags); + + library_end (); +} diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c new file mode 100644 index 00000000000..3ce9f1d3a1a --- /dev/null +++ b/libgfortran/io/read.c @@ -0,0 +1,793 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h" +#include "io.h" + +/* read.c -- Deal with formatted reads */ + +/* set_integer()-- All of the integer assignments come here to + * actually place the value into memory. */ + +void +set_integer (void *dest, int64_t value, int length) +{ + + switch (length) + { + case 8: + *((int64_t *) dest) = value; + break; + case 4: + *((int32_t *) dest) = value; + break; + case 2: + *((int16_t *) dest) = value; + break; + case 1: + *((int8_t *) dest) = value; + break; + default: + internal_error ("Bad integer kind"); + } +} + + +/* max_value()-- Given a length (kind), return the maximum signed or + * unsigned value */ + +uint64_t +max_value (int length, int signed_flag) +{ + uint64_t value; + + switch (length) + { + case 8: + value = signed_flag ? 0x7fffffffffffffff : 0xffffffffffffffff; + break; + case 4: + value = signed_flag ? 0x7fffffff : 0xffffffff; + break; + case 2: + value = signed_flag ? 0x7fff : 0xffff; + break; + case 1: + value = signed_flag ? 0x7f : 0xff; + break; + default: + internal_error ("Bad integer kind"); + } + + return value; +} + + +/* convert_real()-- Convert a character representation of a floating + * point number to the machine number. Returns nonzero if there is a + * range problem during conversion. TODO: handle not-a-numbers and + * infinities. Handling of kind 4 is probably wrong because of double + * rounding. */ + +int +convert_real (void *dest, const char *buffer, int length) +{ + + errno = 0; + + switch (length) + { + case 4: + *((float *) dest) = (float) strtod (buffer, NULL); + break; + case 8: + *((double *) dest) = strtod (buffer, NULL); + break; + default: + internal_error ("Bad real number kind"); + } + + if (errno != 0) + { + generate_error (ERROR_READ_VALUE, + "Range error during floating point read"); + return 1; + } + + return 0; +} + +static int +convert_precision_real (void *dest, int sign, + char *buffer, int length, int exponent) +{ + int w, new_dp_pos, i, slen, k, dp; + char * p, c; + double fval; + float tf; + + fval =0.0; + tf = 0.0; + dp = 0; + new_dp_pos = 0; + + slen = strlen (buffer); + w = slen; + p = buffer; + +/* for (i = w - 1; i > 0; i --) + { + if (buffer[i] == '0' || buffer[i] == 0) + buffer[i] = 0; + else + break; + } +*/ + for (i = 0; i < w; i++) + { + if (buffer[i] == '.') + break; + } + + new_dp_pos = i; + new_dp_pos += exponent; + + while (w > 0) + { + c = *p; + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fval = fval * 10.0 + c - '0'; + p++; + w--; + break; + + case '.': + dp = 1; + p++; + w--; + break; + + default: + p++; + w--; + break; + } + } + + if (sign) + fval = - fval; + + i = new_dp_pos - slen + dp; + k = abs(i); + tf = 1.0; + + while (k > 0) + { + tf *= 10.0 ; + k -- ; + } + + if (fval != 0.0) + { + if (i < 0) + { + fval = fval / tf; + } + else + { + fval = fval * tf; + } + } + + switch (length) + { + case 4: + *((float *) dest) = (float)fval; + break; + case 8: + *((double *) dest) = fval; + break; + default: + internal_error ("Bad real number kind"); + } + + return 0; +} + + +/* read_l()-- Read a logical value */ + +void +read_l (fnode * f, char *dest, int length) +{ + char *p; + int w; + + w = f->u.w; + p = read_block (&w); + if (p == NULL) + return; + + while (*p == ' ') + { + if (--w == 0) + goto bad; + p++; + } + + if (*p == '.') + { + if (--w == 0) + goto bad; + p++; + } + + switch (*p) + { + case 't': + case 'T': + set_integer (dest, 1, length); + break; + case 'f': + case 'F': + set_integer (dest, 0, length); + break; + default: + bad: + generate_error (ERROR_READ_VALUE, "Bad value on logical read"); + break; + } +} + + +/* read_a()-- Read a character record. This one is pretty easy. */ + +void +read_a (fnode * f, char *p, int length) +{ + char *source; + int w, m, n; + + w = f->u.w; + if (w == -1) /* '(A)' edit descriptor */ + w = length; + + source = read_block (&w); + if (source == NULL) + return; + if (w > length) + source += (w - length); + + m = (w > length) ? length : w; + memcpy (p, source, m); + + n = length - w; + if (n > 0) + memset (p + m, ' ', n); +} + + +/* eat_leading_spaces()-- Given a character pointer and a width, + * ignore the leading spaces. */ + +static char * +eat_leading_spaces (int *width, char *p) +{ + + for (;;) + { + if (*width == 0 || *p != ' ') + break; + + (*width)--; + p++; + } + + return p; +} + + +static char +next_char (char **p, int *w) +{ + char c, *q; + + if (*w == 0) + return '\0'; + + q = *p; + c = *q++; + *p = q; + + (*w)--; + + if (c != ' ') + return c; + if (g.blank_status == BLANK_ZERO) + return '0'; + + /* At this point, the rest of the field has to be trailing blanks */ + + while (*w > 0) + { + if (*q++ != ' ') + return '?'; + (*w)--; + } + + *p = q; + return '\0'; +} + + +/* read_decimal()-- Read a decimal integer value. The values here are + * signed values. */ + +void +read_decimal (fnode * f, char *dest, int length) +{ + unsigned value, maxv, maxv_10; + int v, w, negative; + char c, *p; + + w = f->u.w; + p = read_block (&w); + if (p == NULL) + return; + + p = eat_leading_spaces (&w, p); + if (w == 0) + { + set_integer (dest, 0, length); + return; + } + + maxv = max_value (length, 1); + maxv_10 = maxv / 10; + + negative = 0; + value = 0; + + switch (*p) + { + case '-': + negative = 1; + /* Fall through */ + + case '+': + p++; + if (--w == 0) + goto bad; + /* Fall through */ + + default: + break; + } + + /* At this point we have a digit-string */ + value = 0; + + for (;;) + { + c = next_char (&p, &w); + if (c == '\0') + break; + + if (c < '0' || c > '9') + goto bad; + + if (value > maxv_10) + goto overflow; + + c -= '0'; + value = 10 * value; + + if (value > maxv - c) + goto overflow; + value += c; + } + + v = (signed int) value; + if (negative) + v = -v; + + set_integer (dest, v, length); + return; + +bad: + generate_error (ERROR_READ_VALUE, "Bad value during integer read"); + return; + +overflow: + generate_error (ERROR_READ_OVERFLOW, + "Value overflowed during integer read"); + return; +} + + +/* read_radix()-- This function reads values for non-decimal radixes. + * The difference here is that we treat the values here as unsigned + * values for the purposes of overflow. If minus sign is present and + * the top bit is set, the value will be incorrect. */ + +void +read_radix (fnode * f, char *dest, int length, int radix) +{ + unsigned value, maxv, maxv_r; + int v, w, negative; + char c, *p; + + w = f->u.w; + p = read_block (&w); + if (p == NULL) + return; + + p = eat_leading_spaces (&w, p); + if (w == 0) + { + set_integer (dest, 0, length); + return; + } + + maxv = max_value (length, 0); + maxv_r = maxv / radix; + + negative = 0; + value = 0; + + switch (*p) + { + case '-': + negative = 1; + /* Fall through */ + + case '+': + p++; + if (--w == 0) + goto bad; + /* Fall through */ + + default: + break; + } + + /* At this point we have a digit-string */ + value = 0; + + for (;;) + { + c = next_char (&p, &w); + if (c == '\0') + break; + + switch (radix) + { + case 2: + if (c < '0' || c > '1') + goto bad; + break; + + case 8: + if (c < '0' || c > '7') + goto bad; + break; + + case 16: + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + c = c - 'a' + '9' + 1; + break; + + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + c = c - 'A' + '9' + 1; + break; + + default: + goto bad; + } + + break; + } + + if (value > maxv_r) + goto overflow; + + c -= '0'; + value = radix * value; + + if (maxv - c < value) + goto overflow; + value += c; + } + + v = (signed int) value; + if (negative) + v = -v; + + set_integer (dest, v, length); + return; + +bad: + generate_error (ERROR_READ_VALUE, "Bad value during integer read"); + return; + +overflow: + generate_error (ERROR_READ_OVERFLOW, + "Value overflowed during integer read"); + return; +} + + +/* read_f()-- Read a floating point number with F-style editing, which + * is what all of the other floating point descriptors behave as. The + * tricky part is that optional spaces are allowed after an E or D, + * and the implicit decimal point if a decimal point is not present in + * the input. */ + +void +read_f (fnode * f, char *dest, int length) +{ + int w, seen_dp, exponent; + int exponent_sign, val_sign; + char *p, *buffer, *n; + + val_sign = 0; + seen_dp = 0; + w = f->u.w; + p = read_block (&w); + if (p == NULL) + return; + + p = eat_leading_spaces (&w, p); + if (w == 0) + { + switch (length) + { + case 4: + *((float *) dest) = 0.0; + break; + + case 8: + *((double *) dest) = 0.0; + break; + } + + return; + } + + if (w + 2 < SCRATCH_SIZE) + buffer = scratch; + else + buffer = get_mem (w + 2); + + memset(buffer, 0, w + 2); + + n = buffer; + + /* Optional sign */ + + if (*p == '-' || *p == '+') + { + if (*p == '-') + val_sign = 1; + p++; + + if (--w == 0) + goto bad_float; + } + + exponent_sign = 1; + + /* A digit (or a '.') is required at this point */ + + if (!isdigit (*p) && *p != '.') + goto bad_float; + + while (w > 0) + { + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + *n++ = *p++; + w--; + break; + + case '.': + if (seen_dp) + goto bad_float; + seen_dp = 1; + + *n++ = *p++; + w--; + break; + + case ' ': + if (g.blank_status == BLANK_ZERO) + *n++ = '0'; + p++; + w--; + break; + + case '-': + exponent_sign = -1; + /* Fall through */ + + case '+': + p++; + w--; + goto exp2; + + case 'd': + case 'e': + case 'D': + case 'E': + p++; + w--; + goto exp1; + + default: + goto bad_float; + } + } + +/* No exponent has been seen, so we use the current scale factor */ + + exponent = -g.scale_factor; + goto done; + +bad_float: + generate_error (ERROR_READ_VALUE, "Bad value during floating point read"); + if (buffer != scratch) + free_mem (buffer); + return; + +/* At this point the start of an exponent has been found */ + +exp1: + while (w > 0 && *p == ' ') + { + w--; + p++; + } + + switch (*p) + { + case '-': + exponent_sign = -1; + /* Fall through */ + + case '+': + p++; + w--; + break; + } + + if (w == 0) + goto bad_float; + +/* At this point a digit string is required. We calculate the value + * of the exponent in order to take account of the scale factor and + * the d parameter before explict conversion takes place. */ + +exp2: + if (!isdigit (*p)) + goto bad_float; + + exponent = *p - '0'; + p++; + w--; + + while (w > 0 && isdigit (*p)) + { + exponent = 10 * exponent + *p - '0'; + if (exponent > 999999) + goto bad_float; + + p++; + w--; + } + + /* Only allow trailing blanks */ + + while (w > 0) + { + if (*p != ' ') + goto bad_float; + p++; + w--; + } + + exponent = exponent * exponent_sign; + +done: + if (!seen_dp) + exponent -= f->u.real.d; + + /* The number is syntactically correct and ready for conversion. + * The only thing that can go wrong at this point is overflow or + * underflow. */ + + convert_precision_real (dest, val_sign, buffer, length, exponent); + + if (buffer != scratch) + free_mem (buffer); + + return; +} + + +/* read_x()-- Deal with the X/TR descriptor. We just read some data + * and never look at it. */ + +void +read_x (fnode * f) +{ + int n; + + n = f->u.n; + read_block (&n); +} diff --git a/libgfortran/io/rewind.c b/libgfortran/io/rewind.c new file mode 100644 index 00000000000..d068853cf3a --- /dev/null +++ b/libgfortran/io/rewind.c @@ -0,0 +1,56 @@ + +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include "libgfortran.h" +#include "io.h" + +/* rewind.c-- Implement the rewind statement */ + +void +st_rewind (void) +{ + unit_t *u; + + library_start (); + + u = find_unit (ioparm.unit); + if (u != NULL) + { + if (u->flags.access != ACCESS_SEQUENTIAL) + generate_error (ERROR_BAD_OPTION, + "Cannot REWIND a file opened for DIRECT access"); + else + { + if (g.mode==WRITING) + struncate(u->s); + u->last_record = 0; + if (sseek (u->s, 0) == FAILURE) + generate_error (ERROR_OS, NULL); + + u->endfile = NO_ENDFILE; + u->current_record = 0; + test_endfile (u); + } + } + + library_end (); +} diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c new file mode 100644 index 00000000000..b1f0ef10598 --- /dev/null +++ b/libgfortran/io/transfer.c @@ -0,0 +1,1498 @@ + +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +/* transfer.c -- Top level handling of data transfer statements. */ + +#include "config.h" +#include +#include "libgfortran.h" +#include "io.h" + + +/* Calling conventions: Data transfer statements are unlike other + * library calls in that they extend over several calls. + + * The first call is always a call to st_read() or st_write(). These + * subroutines return no status unless a namelist read or write is + * being done, in which case there is the usual status. No further + * calls are necessary in this case. + * + * For other sorts of data transfer, there are zero or more data + * transfer statement that depend on the format of the data transfer + * statement. + * + * transfer_integer + * transfer_logical + * transfer_character + * transfer_real + * transfer_complex + * + * These subroutines do not return status. + * + * The last call is a call to st_[read|write]_done(). While + * something can easily go wrong with the initial st_read() or + * st_write(), an error inhibits any data from actually being + * transferred. + */ + +unit_t *current_unit; +static int sf_seen_eor = 0; + +char scratch[SCRATCH_SIZE]; +static char *line_buffer = NULL; + +static unit_advance advance_status; + +static st_option advance_opt[] = { + {"yes", ADVANCE_YES}, + {"no", ADVANCE_NO}, + {NULL} +}; + + +static void (*transfer) (bt, void *, int); + + +typedef enum +{ FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL, + FORMATTED_DIRECT, UNFORMATTED_DIRECT +} +file_mode; + + +static file_mode +current_mode (void) +{ + file_mode m; + + if (current_unit->flags.access == ACCESS_DIRECT) + { + m = current_unit->flags.form == FORM_FORMATTED ? + FORMATTED_DIRECT : UNFORMATTED_DIRECT; + } + else + { + m = current_unit->flags.form == FORM_FORMATTED ? + FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL; + } + + return m; +} + + +/* Mid level data transfer statements. These subroutines do reading + * and writing in the style of salloc_r()/salloc_w() within the + * current record. */ + +/* read_sf()-- When reading sequential formatted records we have a + * problem. We don't know how long the line is until we read the + * trailing newline, and we don't want to read too much. If we read + * too much, we might have to do a physical seek backwards depending + * on how much data is present, and devices like terminals aren't + * seekable and would cause an I/O error. + * + * Given this, the solution is to read a byte at a time, stopping if + * we hit the newline. For small locations, we use a static buffer. + * For larger allocations, we are forced to allocate memory on the + * heap. Hopefully this won't happen very often. */ + +static char * +read_sf (int *length) +{ + static char data[SCRATCH_SIZE]; + char *base, *p, *q; + int n, unity; + + if (*length > SCRATCH_SIZE) + p = base = line_buffer = get_mem (*length); + else + p = base = data; + + memset(base,'\0',*length); + + current_unit->bytes_left = options.default_recl; + unity = 1; + n = 0; + + do + { + if (is_internal_unit()) + { + /* unity may be modified inside salloc_r if is_internal_unit() is true */ + unity = 1; + } + + q = salloc_r (current_unit->s, &unity); + if (q == NULL) + break; + + if (*q == '\n') + { + if (current_unit->unit_number == options.stdin_unit) + { + if (n <= 0) + continue; + } + /* Unexpected end of line */ + if (current_unit->flags.pad == PAD_NO) + { + generate_error (ERROR_EOR, NULL); + return NULL; + } + + current_unit->bytes_left = 0; + *length = n; + sf_seen_eor = 1; + break; + } + + n++; + *p++ = *q; + sf_seen_eor = 0; + } + while (n < *length); + + return base; +} + + +/* read_block()-- Function for reading the next couple of bytes from + * the current file, advancing the current position. We return a + * pointer to a buffer containing the bytes. We return NULL on end of + * record or end of file. + * + * If the read is short, then it is because the current record does not + * have enough data to satisfy the read request and the file was + * opened with PAD=YES. The caller must assume tailing spaces for + * short reads. */ + +void * +read_block (int *length) +{ + char *source; + int nread; + + if (current_unit->flags.form == FORM_FORMATTED && + current_unit->flags.access == ACCESS_SEQUENTIAL) + return read_sf (length); /* Special case */ + + if (current_unit->bytes_left < *length) + { + if (current_unit->flags.pad == PAD_NO) + { + generate_error (ERROR_EOR, NULL); /* Not enough data left */ + return NULL; + } + + *length = current_unit->bytes_left; + } + + current_unit->bytes_left -= *length; + + nread = *length; + source = salloc_r (current_unit->s, &nread); + + if (ioparm.size != NULL) + *ioparm.size += nread; + + if (nread != *length) + { /* Short read, this shouldn't happen */ + if (current_unit->flags.pad == PAD_YES) + *length = nread; + else + { + generate_error (ERROR_EOR, NULL); + source = NULL; + } + } + + return source; +} + + +/* write_block()-- Function for writing a block of bytes to the + * current file at the current position, advancing the file pointer. + * We are given a length and return a pointer to a buffer that the + * caller must (completely) fill in. Returns NULL on error. */ + +void * +write_block (int length) +{ + char *dest; + + if (!is_internal_unit() && current_unit->bytes_left < length) + { + generate_error (ERROR_EOR, NULL); + return NULL; + } + + current_unit->bytes_left -= length; + dest = salloc_w (current_unit->s, &length); + + if (ioparm.size != NULL) + *ioparm.size += length; + + return dest; +} + + +/* unformatted_read()-- Master function for unformatted reads. */ + +static void +unformatted_read (bt type, void *dest, int length) +{ + void *source; + int w; + w = length; + source = read_block (&w); + + if (source != NULL) + { + memcpy (dest, source, w); + if (length != w) + memset (((char *) dest) + w, ' ', length - w); + } +} + +static void +unformatted_write (bt type, void *source, int length) +{ + void *dest; + dest = write_block (length); + if (dest != NULL) + memcpy (dest, source, length); +} + + +/* type_name()-- Return a pointer to the name of a type. */ + +const char * +type_name (bt type) +{ + const char *p; + + switch (type) + { + case BT_INTEGER: + p = "INTEGER"; + break; + case BT_LOGICAL: + p = "LOGICAL"; + break; + case BT_CHARACTER: + p = "CHARACTER"; + break; + case BT_REAL: + p = "REAL"; + break; + case BT_COMPLEX: + p = "COMPLEX"; + break; + default: + internal_error ("type_name(): Bad type"); + } + + return p; +} + + +/* write_constant_string()-- write a constant string to the output. + * This is complicated because the string can have doubled delimiters + * in it. The length in the format node is the true length. */ + +static void +write_constant_string (fnode * f) +{ + char c, delimiter, *p, *q; + int length; + + length = f->u.string.length; + if (length == 0) + return; + + p = write_block (length); + if (p == NULL) + return; + + q = f->u.string.p; + delimiter = q[-1]; + + for (; length > 0; length--) + { + c = *p++ = *q++; + if (c == delimiter && c != 'H') + q++; /* Skip the doubled delimiter */ + } +} + + +/* require_type()-- Given actual and expected types in a formatted + * data transfer, make sure they agree. If not, an error message is + * generated. Returns nonzero if something went wrong. */ + +static int +require_type (bt expected, bt actual, fnode * f) +{ + char buffer[100]; + + if (actual == expected) + return 0; + + st_sprintf (buffer, "Expected %s for item %d in formatted transfer, got %s", + type_name (expected), g.item_count, type_name (actual)); + + format_error (f, buffer); + return 1; +} + + +/* formatted_transfer()-- This subroutine is the main loop for a + * formatted data transfer statement. It would be natural to + * implement this as a coroutine with the user program, but C makes + * that awkward. We loop, processesing format elements. When we + * actually have to transfer data instead of just setting flags, we + * return control to the user program which calls a subroutine that + * supplies the address and type of the next element, then comes back + * here to process it. */ + +static void +formatted_transfer (bt type, void *p, int len) +{ + int pos ,m ; + fnode *f; + int i, n; + int consume_data_flag; + + /* Change a complex data item into a pair of reals */ + + n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2); + if (type == BT_COMPLEX) + type = BT_REAL; + + /* If reversion has occurred and there is another real data item, + * then we have to move to the next record */ + + if (g.reversion_flag && n > 0) + { + g.reversion_flag = 0; + next_record (0); + } + for (;;) + { + consume_data_flag = 1 ; + if (ioparm.library_return != LIBRARY_OK) + break; + + f = next_format (); + if (f == NULL) + return; /* No data descriptors left (already raised) */ + + switch (f->format) + { + case FMT_I: + if (n == 0) + goto need_data; + if (require_type (BT_INTEGER, type, f)) + return; + + if (g.mode == READING) + read_decimal (f, p, len); + else + write_i (f, p, len); + + break; + + case FMT_B: + if (n == 0) + goto need_data; + if (require_type (BT_INTEGER, type, f)) + return; + + if (g.mode == READING) + read_radix (f, p, len, 2); + else + write_b (f, p, len); + + break; + + case FMT_O: + if (n == 0) + goto need_data; + + if (g.mode == READING) + read_radix (f, p, len, 8); + else + write_o (f, p, len); + + break; + + case FMT_Z: + if (n == 0) + goto need_data; + + if (g.mode == READING) + read_radix (f, p, len, 16); + else + write_z (f, p, len); + + break; + + case FMT_A: + if (n == 0) + goto need_data; + if (require_type (BT_CHARACTER, type, f)) + return; + + if (g.mode == READING) + read_a (f, p, len); + else + write_a (f, p, len); + + break; + + case FMT_L: + if (n == 0) + goto need_data; + + if (g.mode == READING) + read_l (f, p, len); + else + write_l (f, p, len); + + break; + + case FMT_D: + if (n == 0) + goto need_data; + if (require_type (BT_REAL, type, f)) + return; + + if (g.mode == READING) + read_f (f, p, len); + else + write_d (f, p, len); + + break; + + case FMT_E: + if (n == 0) + goto need_data; + if (require_type (BT_REAL, type, f)) + return; + + if (g.mode == READING) + read_f (f, p, len); + else + write_e (f, p, len); + break; + + case FMT_EN: + if (n == 0) + goto need_data; + if (require_type (BT_REAL, type, f)) + return; + + if (g.mode == READING) + read_f (f, p, len); + else + write_en (f, p, len); + + break; + + case FMT_ES: + if (n == 0) + goto need_data; + if (require_type (BT_REAL, type, f)) + return; + + if (g.mode == READING) + read_f (f, p, len); + else + write_es (f, p, len); + + break; + + case FMT_F: + if (n == 0) + goto need_data; + if (require_type (BT_REAL, type, f)) + return; + + if (g.mode == READING) + read_f (f, p, len); + else + write_f (f, p, len); + + break; + + case FMT_G: + if (n == 0) + goto need_data; + if (g.mode == READING) + switch (type) + { + case BT_INTEGER: + read_decimal (f, p, len); + break; + case BT_LOGICAL: + read_l (f, p, len); + break; + case BT_CHARACTER: + read_a (f, p, len); + break; + case BT_REAL: + read_f (f, p, len); + break; + default: + goto bad_type; + } + else + switch (type) + { + case BT_INTEGER: + write_i (f, p, len); + break; + case BT_LOGICAL: + write_l (f, p, len); + break; + case BT_CHARACTER: + write_a (f, p, len); + break; + case BT_REAL: + write_d (f, p, len); + break; + default: + bad_type: + internal_error ("formatted_transfer(): Bad type"); + } + + break; + + case FMT_STRING: + consume_data_flag = 0 ; + if (g.mode == READING) + { + format_error (f, "Constant string in input format"); + return; + } + write_constant_string (f); + break; + + /* Format codes that don't transfer data */ + case FMT_X: + case FMT_TR: + consume_data_flag = 0 ; + if (g.mode == READING) + read_x (f); + else + write_x (f); + + break; + + case FMT_T: + pos = f->u.n ; + pos= current_unit->recl - current_unit->bytes_left - pos; + /* fall through */ + + case FMT_TL: + consume_data_flag = 0 ; + pos = f->u.n ; + + if (pos < 0 || pos >= current_unit->recl ) + { + generate_error (ERROR_EOR, "T Or TL edit position error"); + break ; + } + m = pos - (current_unit->recl - current_unit->bytes_left); + + if (m == 0) + break; + + if (m > 0) + { + f->u.n = m; + if (g.mode == READING) + read_x (f); + else + write_x (f); + } + if (m < 0) + { + move_pos_offset (current_unit->s,m); + } + + break; + + case FMT_S: + consume_data_flag = 0 ; + g.sign_status = SIGN_S; + break; + + case FMT_SS: + consume_data_flag = 0 ; + g.sign_status = SIGN_SS; + break; + + case FMT_SP: + consume_data_flag = 0 ; + g.sign_status = SIGN_SP; + break; + + case FMT_BN: + consume_data_flag = 0 ; + g.blank_status = BLANK_NULL; + break; + + case FMT_BZ: + consume_data_flag = 0 ; + g.blank_status = BLANK_ZERO; + break; + + case FMT_P: + consume_data_flag = 0 ; + g.scale_factor = f->u.k; + break; + + case FMT_DOLLAR: + consume_data_flag = 0 ; + g.seen_dollar = 1; + break; + + case FMT_SLASH: + consume_data_flag = 0 ; + for (i = 0; i < f->repeat; i++) + next_record (0); + + break; + + case FMT_COLON: + /* A colon descriptor causes us to exit this loop (in particular + * preventing another / descriptor from being processed) unless there + * is another data item to be transferred. */ + consume_data_flag = 0 ; + if (n == 0) + return; + break; + + default: + internal_error ("Bad format node"); + } + + /* Free a buffer that we had to allocate during a sequential + * formatted read of a block that was larger than the static + * buffer. */ + + if (line_buffer != NULL) + { + free_mem (line_buffer); + line_buffer = NULL; + } + + /* Adjust the item count and data pointer */ + + if ((consume_data_flag > 0) && (n > 0)) + { + n--; + p = ((char *) p) + len; + } + } + + return; + +/* Come here when we need a data descriptor but don't have one. We + * push the current format node back onto the input, then return and + * let the user program call us back with the data. */ + +need_data: + unget_format (f); +} + + + +/* Data transfer entry points. The type of the data entity is + * implicit in the subroutine call. This prevents us from having to + * share a common enum with the compiler. */ + +void +transfer_integer (void *p, int kind) +{ + + g.item_count++; + if (ioparm.library_return != LIBRARY_OK) + return; + transfer (BT_INTEGER, p, kind); +} + + +void +transfer_real (void *p, int kind) +{ + + g.item_count++; + if (ioparm.library_return != LIBRARY_OK) + return; + transfer (BT_REAL, p, kind); +} + + +void +transfer_logical (void *p, int kind) +{ + + g.item_count++; + if (ioparm.library_return != LIBRARY_OK) + return; + transfer (BT_LOGICAL, p, kind); +} + + +void +transfer_character (void *p, int len) +{ + + g.item_count++; + if (ioparm.library_return != LIBRARY_OK) + return; + transfer (BT_CHARACTER, p, len); +} + + +void +transfer_complex (void *p, int kind) +{ + + g.item_count++; + if (ioparm.library_return != LIBRARY_OK) + return; + transfer (BT_COMPLEX, p, kind); +} + + +/* us_read()-- Preposition a sequential unformatted file while reading. */ + +static void +us_read (void) +{ + offset_t *p; + int n; + + n = sizeof (offset_t); + p = (offset_t *) salloc_r (current_unit->s, &n); + + if (p == NULL || n != sizeof (offset_t)) + { + generate_error (ERROR_BAD_US, NULL); + return; + } + + current_unit->bytes_left = *p; +} + + +/* us_write()-- Preposition a sequential unformatted file while + * writing. This amount to writing a bogus length that will be filled + * in later. */ + +static void +us_write (void) +{ + offset_t *p; + int length; + + length = sizeof (offset_t); + p = (offset_t *) salloc_w (current_unit->s, &length); + + if (p == NULL) + { + generate_error (ERROR_OS, NULL); + return; + } + + *p = 0; /* Bogus value for now */ + if (sfree (current_unit->s) == FAILURE) + generate_error (ERROR_OS, NULL); + + current_unit->bytes_left = current_unit->recl; +} + + +/* pre_position()-- position to the next record prior to transfer. We + * are assumed to be before the next record. We also calculate the + * bytes in the next record. */ + +static void +pre_position (void) +{ + + if (current_unit->current_record) + return; /* Already positioned */ + + switch (current_mode ()) + { + case UNFORMATTED_SEQUENTIAL: + if (g.mode == READING) + us_read (); + else + us_write (); + + break; + + case FORMATTED_SEQUENTIAL: + case FORMATTED_DIRECT: + case UNFORMATTED_DIRECT: + current_unit->bytes_left = current_unit->recl; + break; + } + + current_unit->current_record = 1; +} + + +/* data_transfer_init()-- Initialize things for a data transfer. This + * code is common for both reading and writing. */ + +static void +data_transfer_init (int read_flag) +{ + unit_flags u_flags; /* used for creating a unit if needed */ + + g.mode = read_flag ? READING : WRITING; + + if (ioparm.size != NULL) + *ioparm.size = 0; /* Initialize the count */ + + current_unit = get_unit (read_flag); + if (current_unit == NULL) + { /* open the unit with some default flags */ + memset (&u_flags, '\0', sizeof (u_flags)); + u_flags.access = ACCESS_SEQUENTIAL; + u_flags.action = ACTION_READWRITE; + u_flags.form = FORM_UNSPECIFIED; + u_flags.delim = DELIM_UNSPECIFIED; + u_flags.blank = BLANK_UNSPECIFIED; + u_flags.pad = PAD_UNSPECIFIED; + u_flags.status = STATUS_UNKNOWN; + new_unit(&u_flags); + current_unit = get_unit (read_flag); + } + + if (current_unit == NULL) + return; + + if (is_internal_unit() && g.mode==WRITING) + empty_internal_buffer (current_unit->s); + + /* Check the action */ + + if (read_flag && current_unit->flags.action == ACTION_WRITE) + generate_error (ERROR_BAD_ACTION, + "Cannot read from file opened for WRITE"); + + if (!read_flag && current_unit->flags.action == ACTION_READ) + generate_error (ERROR_BAD_ACTION, "Cannot write to file opened for READ"); + + if (ioparm.library_return != LIBRARY_OK) + return; + + /* Check the format */ + + if (ioparm.format) + parse_format (); + + if (ioparm.library_return != LIBRARY_OK) + return; + + if (current_unit->flags.form == FORM_UNFORMATTED + && (ioparm.format != NULL || ioparm.list_format)) + generate_error (ERROR_OPTION_CONFLICT, + "Format present for UNFORMATTED data transfer"); + + if (ioparm.namelist_name != NULL && ionml != NULL) + { + if(ioparm.format != NULL) + generate_error (ERROR_OPTION_CONFLICT, + "A format cannot be specified with a namelist"); + } + else if (current_unit->flags.form == FORM_FORMATTED && + ioparm.format == NULL && !ioparm.list_format) + generate_error (ERROR_OPTION_CONFLICT, + "Missing format for FORMATTED data transfer"); + + + if (is_internal_unit () && current_unit->flags.form == FORM_UNFORMATTED) + generate_error (ERROR_OPTION_CONFLICT, + "Internal file cannot be accessed by UNFORMATTED data transfer"); + + /* Check the record number */ + + if (current_unit->flags.access == ACCESS_DIRECT && ioparm.rec == 0) + { + generate_error (ERROR_MISSING_OPTION, + "Direct access data transfer requires record number"); + return; + } + + if (current_unit->flags.access == ACCESS_SEQUENTIAL && ioparm.rec != 0) + { + generate_error (ERROR_OPTION_CONFLICT, + "Record number not allowed for sequential access data transfer"); + return; + } + + /* Process the ADVANCE option */ + + advance_status = (ioparm.advance == NULL) ? ADVANCE_UNSPECIFIED : + find_option (ioparm.advance, ioparm.advance_len, advance_opt, + "Bad ADVANCE parameter in data transfer statement"); + + if (advance_status != ADVANCE_UNSPECIFIED) + { + if (current_unit->flags.access == ACCESS_DIRECT) + generate_error (ERROR_OPTION_CONFLICT, + "ADVANCE specification conflicts with sequential access"); + + if (is_internal_unit ()) + generate_error (ERROR_OPTION_CONFLICT, + "ADVANCE specification conflicts with internal file"); + + if (ioparm.format == NULL || ioparm.list_format) + generate_error (ERROR_OPTION_CONFLICT, + "ADVANCE specification requires an explicit format"); + } + + if (read_flag) + { + if (ioparm.eor != 0 && advance_status == ADVANCE_NO) + generate_error (ERROR_MISSING_OPTION, + "EOR specification requires an ADVANCE specification of NO"); + + if (ioparm.size != NULL && advance_status != ADVANCE_NO) + generate_error (ERROR_MISSING_OPTION, + "SIZE specification requires an ADVANCE specification of NO"); + + } + else + { /* Write constraints */ + + if (ioparm.end != 0) + generate_error (ERROR_OPTION_CONFLICT, + "END specification cannot appear in a write statement"); + + if (ioparm.eor != 0) + generate_error (ERROR_OPTION_CONFLICT, + "EOR specification cannot appear in a write statement"); + + if (ioparm.size != 0) + generate_error (ERROR_OPTION_CONFLICT, + "SIZE specification cannot appear in a write statement"); + } + + if (advance_status == ADVANCE_UNSPECIFIED) + advance_status = ADVANCE_YES; + if (ioparm.library_return != LIBRARY_OK) + return; + + /* Sanity checks on the record number */ + + if (ioparm.rec) + { + if (ioparm.rec <= 0) + { + generate_error (ERROR_BAD_OPTION, "Record number must be positive"); + return; + } + + if (ioparm.rec >= current_unit->maxrec) + { + generate_error (ERROR_BAD_OPTION, "Record number too large"); + return; + } + + /* Position the file */ + + if (sseek (current_unit->s, + (ioparm.rec - 1) * current_unit->recl) == FAILURE) + generate_error (ERROR_OS, NULL); + } + + /* Set the initial value of flags */ + + g.blank_status = current_unit->flags.blank; + g.sign_status = SIGN_S; + g.scale_factor = 0; + g.seen_dollar = 0; + g.first_item = 1; + g.item_count = 0; + + pre_position (); + + /* Set up the subroutine that will handle the transfers */ + + if (read_flag) + { + if (current_unit->flags.form == FORM_UNFORMATTED) + transfer = unformatted_read; + else + { + if (ioparm.list_format) + { + transfer = list_formatted_read; + init_at_eol(); + } + else + transfer = formatted_transfer; + } + } + else + { + if (current_unit->flags.form == FORM_UNFORMATTED) + transfer = unformatted_write; + else + { + if (ioparm.list_format) + transfer = list_formatted_write; + else + transfer = formatted_transfer; + } + } + + /* Make sure that we don't do a read after a nonadvancing write */ + + if (read_flag) + { + if (current_unit->read_bad) + { + generate_error (ERROR_BAD_OPTION, + "Cannot READ after a nonadvancing WRITE"); + return; + } + } + else + { + if (advance_status == ADVANCE_YES) + current_unit->read_bad = 1; + } + + /* Start the data transfer if we are doing a formatted transfer */ + if (current_unit->flags.form == FORM_FORMATTED && !ioparm.list_format + && ioparm.namelist_name == NULL && ionml == NULL) + + formatted_transfer (0, NULL, 0); + +} + + +/* next_record_r()-- Space to the next record for read mode. If the + * file is not seekable, we read MAX_READ chunks until we get to the + * right position. */ + +#define MAX_READ 4096 + +static void +next_record_r (int done) +{ + int rlength, length; + offset_t new; + char *p; + + switch (current_mode ()) + { + case UNFORMATTED_SEQUENTIAL: + current_unit->bytes_left += sizeof (offset_t); /* Skip over tail */ + + /* Fall through */ + + case FORMATTED_DIRECT: + case UNFORMATTED_DIRECT: + if (current_unit->bytes_left == 0) + break; + + if (is_seekable (current_unit->s)) + { + new = file_position (current_unit->s) + current_unit->bytes_left; + + /* Direct access files do not generate END conditions, only I/O errors */ + + if (sseek (current_unit->s, new) == FAILURE) + generate_error (ERROR_OS, NULL); + + } + else + { /* Seek by reading data */ + while (current_unit->bytes_left > 0) + { + rlength = length = (MAX_READ > current_unit->bytes_left) ? + MAX_READ : current_unit->bytes_left; + + p = salloc_r (current_unit->s, &rlength); + if (p == NULL) + { + generate_error (ERROR_OS, NULL); + break; + } + + current_unit->bytes_left -= length; + } + } + + break; + + case FORMATTED_SEQUENTIAL: + length = 1; + if (sf_seen_eor && done) + break; + + do + { + p = salloc_r (current_unit->s, &length); + + /*In case of internal file, there may not be any '\n'.*/ + if (is_internal_unit() && p == NULL) + { + break; + } + + if (p == NULL) + { + generate_error (ERROR_OS, NULL); + break; + } + + if (length == 0) + { + current_unit->endfile = AT_ENDFILE; + break; + } + } + while (*p != '\n'); + + break; + } + + if (current_unit->flags.access == ACCESS_SEQUENTIAL) + test_endfile (current_unit); +} + + +/* next_record_w()-- Position to the next record in write mode */ + +static void +next_record_w (int done) +{ + offset_t c, m; + int length; + char *p; + + switch (current_mode ()) + { + case FORMATTED_DIRECT: + case UNFORMATTED_DIRECT: + if (current_unit->bytes_left == 0) + break; + + length = current_unit->bytes_left; + + p = salloc_w (current_unit->s, &length); + if (p == NULL) + goto io_error; + + memset (p, ' ', current_unit->bytes_left); + if (sfree (current_unit->s) == FAILURE) + goto io_error; + + break; + + case UNFORMATTED_SEQUENTIAL: + m = current_unit->recl - current_unit->bytes_left; /* Bytes written */ + c = file_position (current_unit->s); + + length = sizeof (offset_t); + + /* Write the length tail */ + + p = salloc_w (current_unit->s, &length); + if (p == NULL) + goto io_error; + + *((offset_t *) p) = m; + if (sfree (current_unit->s) == FAILURE) + goto io_error; + + /* Seek to the head and overwrite the bogus length with the real length */ + + p = salloc_w_at (current_unit->s, &length, c - m - length); + if (p == NULL) + generate_error (ERROR_OS, NULL); + + *((offset_t *) p) = m; + if (sfree (current_unit->s) == FAILURE) + goto io_error; + + /* Seek past the end of the current record */ + + if (sseek (current_unit->s, c + sizeof (offset_t)) == FAILURE) + goto io_error; + + break; + + case FORMATTED_SEQUENTIAL: + length = 1; + p = salloc_w (current_unit->s, &length); + + if (!is_internal_unit()) + { + if (p) + *p = '\n'; /* no CR for internal writes */ + else + goto io_error; + } + + if (sfree (current_unit->s) == FAILURE) + goto io_error; + + break; + + io_error: + generate_error (ERROR_OS, NULL); + break; + } +} + + +/* next_record()-- Position to the next record, which means moving to + * the end of the current record. This can happen under several + * different conditions. If the done flag is not set, we get ready to + * process the next record. */ + +void +next_record (int done) +{ + + current_unit->read_bad = 0; + + if (g.mode == READING) + next_record_r (done); + else + next_record_w (done); + + current_unit->current_record = 0; + if (current_unit->flags.access == ACCESS_DIRECT) + current_unit->last_record = file_position (current_unit->s) + / current_unit->recl; + else + current_unit->last_record++; + + if (!done) + pre_position (); +} + + +/* Finalize the current data transfer. For a nonadvancing transfer, + * this means advancing to the next record. */ + +static void +finalize_transfer (void) +{ + + if (setjmp (g.eof_jump)) + { + generate_error (ERROR_END, NULL); + return; + } + + if ((ionml != NULL) && (ioparm.namelist_name != NULL)) + { + if (ioparm.namelist_read_mode) + namelist_read(); + else + namelist_write(); + } + + transfer = NULL; + if (current_unit == NULL) + return; + + if (ioparm.list_format && g.mode == READING) + finish_list_read (); + else + { + free_fnodes (); + + if (advance_status == ADVANCE_NO) + return; + next_record (1); + current_unit->current_record = 0; + } + + sfree (current_unit->s); +} + + +/* The READ statement */ + +void +st_read (void) +{ + + library_start (); + + data_transfer_init (1); + + /* Handle complications dealing with the endfile record. It is + * significant that this is the only place where ERROR_END is + * generated. Reading an end of file elsewhere is either end of + * record or an I/O error. */ + + if (current_unit->flags.access == ACCESS_SEQUENTIAL) + switch (current_unit->endfile) + { + case NO_ENDFILE: + break; + + case AT_ENDFILE: + if (!is_internal_unit()) + { + generate_error (ERROR_END, NULL); + current_unit->endfile = AFTER_ENDFILE; + } + break; + + case AFTER_ENDFILE: + generate_error (ERROR_ENDFILE, NULL); + break; + } +} + + +void +st_read_done (void) +{ + finalize_transfer (); + + library_end (); +} + + +void +st_write (void) +{ + + library_start (); + data_transfer_init (0); +} + + +void +st_write_done (void) +{ + + finalize_transfer (); + + /* Deal with endfile conditions associated with sequential files */ + + if (current_unit != NULL && current_unit->flags.access == ACCESS_SEQUENTIAL) + switch (current_unit->endfile) + { + case AT_ENDFILE: /* Remain at the endfile record */ + break; + + case AFTER_ENDFILE: + current_unit->endfile = AT_ENDFILE; /* Just at it now */ + break; + + case NO_ENDFILE: /* Get rid of whatever is after this record */ + if (struncate (current_unit->s) == FAILURE) + generate_error (ERROR_OS, NULL); + + current_unit->endfile = AT_ENDFILE; + break; + } + + library_end (); +} + + +static void +st_set_nml_var (void * var_addr, char * var_name, int var_name_len, + int kind, bt type) +{ + namelist_info *t1 = NULL, *t2 = NULL; + namelist_info *nml = (namelist_info *) get_mem (sizeof( + namelist_info )); + nml->mem_pos = var_addr; + nml->var_name = (char*) get_mem (var_name_len+1); + strncpy (nml->var_name,var_name,var_name_len); + nml->var_name[var_name_len] = 0; + nml->len = kind; + nml->type = type; + + nml->next = NULL; + + if (ionml == NULL) + ionml = nml; + else + { + t1 = ionml; + while (t1 != NULL) + { + t2 = t1; + t1 = t1->next; + } + t2->next = nml; + } +} + +void +st_set_nml_var_int (void * var_addr, char * var_name, int var_name_len, + int kind) +{ + st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_INTEGER); +} + +void +st_set_nml_var_float (void * var_addr, char * var_name, int var_name_len, + int kind) +{ + st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_REAL); +} + +void +st_set_nml_var_char (void * var_addr, char * var_name, int var_name_len, + int kind) +{ + st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_CHARACTER); +} + +void +st_set_nml_var_complex (void * var_addr, char * var_name, int var_name_len, + int kind) +{ + st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_COMPLEX); +} + +void +st_set_nml_var_log (void * var_addr, char * var_name, int var_name_len, + int kind) +{ + st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_LOGICAL); +} + diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c new file mode 100644 index 00000000000..87f9095b731 --- /dev/null +++ b/libgfortran/io/unit.c @@ -0,0 +1,380 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" +#include "io.h" + + +/* Subroutines related to units */ + + +#define CACHE_SIZE 3 +static unit_t internal_unit, *unit_cache[CACHE_SIZE]; + + +/* This implementation is based on Stefan Nilsson's article in the + * July 1997 Doctor Dobb's Journal, "Treaps in Java". */ + +/* pseudo_random()-- Simple linear congruential pseudorandom number + * generator. The period of this generator is 44071, which is plenty + * for our purposes. */ + +static int +pseudo_random (void) +{ + static int x0 = 5341; + + x0 = (22611 * x0 + 10) % 44071; + return x0; +} + + +/* rotate_left()-- Rotate the treap left */ + +static unit_t * +rotate_left (unit_t * t) +{ + unit_t *temp; + + temp = t->right; + t->right = t->right->left; + temp->left = t; + + return temp; +} + + +/* rotate_right()-- Rotate the treap right */ + +static unit_t * +rotate_right (unit_t * t) +{ + unit_t *temp; + + temp = t->left; + t->left = t->left->right; + temp->right = t; + + return temp; +} + + + +static int +compare (int a, int b) +{ + + if (a < b) + return -1; + if (a > b) + return 1; + + return 0; +} + + +/* insert()-- Recursive insertion function. Returns the updated treap. */ + +static unit_t * +insert (unit_t * new, unit_t * t) +{ + int c; + + if (t == NULL) + return new; + + c = compare (new->unit_number, t->unit_number); + + if (c < 0) + { + t->left = insert (new, t->left); + if (t->priority < t->left->priority) + t = rotate_right (t); + } + + if (c > 0) + { + t->right = insert (new, t->right); + if (t->priority < t->right->priority) + t = rotate_left (t); + } + + if (c == 0) + internal_error ("insert(): Duplicate key found!"); + + return t; +} + + +/* insert_unit()-- Given a new node, insert it into the treap. It is + * an error to insert a key that already exists. */ + +void +insert_unit (unit_t * new) +{ + + new->priority = pseudo_random (); + g.unit_root = insert (new, g.unit_root); +} + + +static unit_t * +delete_root (unit_t * t) +{ + unit_t *temp; + + if (t->left == NULL) + return t->right; + if (t->right == NULL) + return t->left; + + if (t->left->priority > t->right->priority) + { + temp = rotate_right (t); + temp->right = delete_root (t); + } + else + { + temp = rotate_left (t); + temp->left = delete_root (t); + } + + return temp; +} + + +/* delete_treap()-- Delete an element from a tree. The 'old' value + * does not necessarily have to point to the element to be deleted, it + * must just point to a treap structure with the key to be deleted. + * Returns the new root node of the tree. */ + +static unit_t * +delete_treap (unit_t * old, unit_t * t) +{ + int c; + + if (t == NULL) + return NULL; + + c = compare (old->unit_number, t->unit_number); + + if (c < 0) + t->left = delete_treap (old, t->left); + if (c > 0) + t->right = delete_treap (old, t->right); + if (c == 0) + t = delete_root (t); + + return t; +} + + +/* delete_unit()-- Delete a unit from a tree */ + +static void +delete_unit (unit_t * old) +{ + + g.unit_root = delete_treap (old, g.unit_root); +} + + +/* find_unit()-- Given an integer, return a pointer to the unit + * structure. Returns NULL if the unit does not exist. */ + +unit_t * +find_unit (int n) +{ + unit_t *p; + int c; + + for (c = 0; c < CACHE_SIZE; c++) + if (unit_cache[c] != NULL && unit_cache[c]->unit_number == n) + { + p = unit_cache[c]; + return p; + } + + p = g.unit_root; + while (p != NULL) + { + c = compare (n, p->unit_number); + if (c < 0) + p = p->left; + if (c > 0) + p = p->right; + if (c == 0) + break; + } + + if (p != NULL) + { + for (c = 0; c < CACHE_SIZE - 1; c++) + unit_cache[c] = unit_cache[c + 1]; + + unit_cache[CACHE_SIZE - 1] = p; + } + + return p; +} + +/* get_unit()-- Returns the unit structure associated with the integer + * unit or the internal file. */ + +unit_t * +get_unit (int read_flag) +{ + unit_t *u; + + if (ioparm.internal_unit != NULL) + { + internal_unit.s = + open_internal (ioparm.internal_unit, ioparm.internal_unit_len); + + /* Set flags for the internal unit */ + + internal_unit.flags.access = ACCESS_SEQUENTIAL; + internal_unit.flags.action = ACTION_READWRITE; + internal_unit.flags.form = FORM_FORMATTED; + internal_unit.flags.delim = DELIM_NONE; + + return &internal_unit; + } + + /* Has to be an external unit */ + + u = find_unit (ioparm.unit); + if (u != NULL) + return u; + + return NULL; +} + + +/* is_internal_unit()-- Determine if the current unit is internal or + * not */ + +int +is_internal_unit () +{ + + return current_unit == &internal_unit; +} + + + +/*************************/ +/* Initialize everything */ + +void +init_units (void) +{ + offset_t m, n; + unit_t *u; + int i; + + if (options.stdin_unit >= 0) + { /* STDIN */ + u = get_mem (sizeof (unit_t)); + + u->unit_number = options.stdin_unit; + u->s = input_stream (); + + u->flags.action = ACTION_READ; + + u->flags.access = ACCESS_SEQUENTIAL; + u->flags.form = FORM_FORMATTED; + u->flags.status = STATUS_OLD; + u->flags.blank = BLANK_ZERO; + u->flags.position = POSITION_ASIS; + + u->recl = options.default_recl; + u->endfile = NO_ENDFILE; + + insert_unit (u); + } + + if (options.stdout_unit >= 0) + { /* STDOUT */ + u = get_mem (sizeof (unit_t)); + + u->unit_number = options.stdout_unit; + u->s = output_stream (); + + u->flags.action = ACTION_WRITE; + + u->flags.access = ACCESS_SEQUENTIAL; + u->flags.form = FORM_FORMATTED; + u->flags.status = STATUS_OLD; + u->flags.blank = BLANK_ZERO; + u->flags.position = POSITION_ASIS; + + u->recl = options.default_recl; + u->endfile = AT_ENDFILE; + + insert_unit (u); + } + + /* Calculate the maximum file offset in a portable manner. + * max will be the largest signed number for the type offset_t. + * + * set a 1 in the LSB and keep a running sum, stopping at MSB-1 bit. */ + + g.max_offset = 0; + for (i=0; i < sizeof(g.max_offset) * 8 - 1; i++) + g.max_offset = g.max_offset + ((offset_t) 1 << i); + +} + + +/* close_unit()-- Close a unit. The stream is closed, and any memory + * associated with the stream is freed. Returns nonzero on I/O error. */ + +int +close_unit (unit_t * u) +{ + int i, rc; + + for (i = 0; i < CACHE_SIZE; i++) + if (unit_cache[i] == u) + unit_cache[i] = NULL; + + rc = (u->s == NULL) ? 0 : sclose (u->s) == FAILURE; + + delete_unit (u); + free_mem (u); + + return rc; +} + + +/* close_units()-- Delete units on completion. We just keep deleting + * the root of the treap until there is nothing left. */ + +void +close_units (void) +{ + + while (g.unit_root != NULL) + close_unit (g.unit_root); +} diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c new file mode 100644 index 00000000000..185608aba33 --- /dev/null +++ b/libgfortran/io/unix.c @@ -0,0 +1,1432 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Unix stream I/O module */ + +#include "config.h" +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "libgfortran.h" +#include "io.h" + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif + +/* This implementation of stream I/O is based on the paper: + * + * "Exploiting the advantages of mapped files for stream I/O", + * O. Krieger, M. Stumm and R. Umrau, "Proceedings of the 1992 Winter + * USENIX conference", p. 27-42. + * + * It differs in a number of ways from the version described in the + * paper. First of all, threads are not an issue during I/O and we + * also don't have to worry about having multiple regions, since + * fortran's I/O model only allows you to be one place at a time. + * + * On the other hand, we have to be able to writing at the end of a + * stream, read from the start of a stream or read and write blocks of + * bytes from an arbitrary position. After opening a file, a pointer + * to a stream structure is returned, which is used to handle file + * accesses until the file is closed. + * + * salloc_at_r(stream, len, where)-- Given a stream pointer, return a + * pointer to a block of memory that mirror the file at position + * 'where' that is 'len' bytes long. The len integer is updated to + * reflect how many bytes were actually read. The only reason for a + * short read is end of file. The file pointer is updated. The + * pointer is valid until the next call to salloc_*. + * + * salloc_at_w(stream, len, where)-- Given the stream pointer, returns + * a pointer to a block of memory that is updated to reflect the state + * of the file. The length of the buffer is always equal to that + * requested. The buffer must be completely set by the caller. When + * data has been written, the sfree() function must be called to + * indicate that the caller is done writing data to the buffer. This + * may or may not cause a physical write. + * + * Short forms of these are salloc_r() and salloc_w() which drop the + * 'where' parameter and use the current file pointer. */ + + +#define BUFFER_SIZE 8192 + +typedef struct +{ + stream st; + + int fd; + offset_t buffer_offset; /* File offset of the start of the buffer */ + offset_t physical_offset; /* Current physical file offset */ + offset_t logical_offset; /* Current logical file offset */ + offset_t dirty_offset; /* Start of modified bytes in buffer */ + offset_t file_length; /* Length of the file, -1 if not seekable. */ + + char *buffer; + int len; /* Physical length of the current buffer */ + int active; /* Length of valid bytes in the buffer */ + + int prot; + int ndirty; /* Dirty bytes starting at dirty_offset */ + + unsigned unbuffered:1, mmaped:1; + + char small_buffer[BUFFER_SIZE]; + +} +unix_stream; + +/*move_pos_offset()-- Move the record pointer right or left + *relative to current position */ + +int +move_pos_offset (stream* st, int pos_off) +{ + unix_stream * str = (unix_stream*)st; + if (pos_off < 0) + { + str->active += pos_off; + if (str->active < 0) + str->active = 0; + + str->logical_offset += pos_off; + + if (str->dirty_offset+str->ndirty > str->logical_offset) + { + if (str->ndirty + pos_off > 0) + str->ndirty += pos_off ; + else + { + str->dirty_offset += pos_off + pos_off; + str->ndirty = 0 ; + } + } + + return pos_off ; + } + return 0 ; +} + + +/* fix_fd()-- Given a file descriptor, make sure it is not one of the + * standard descriptors, returning a non-standard descriptor. If the + * user specifies that system errors should go to standard output, + * then closes standard output, we don't want the system errors to a + * file that has been given file descriptor 1 or 0. We want to send + * the error to the invalid descriptor. */ + +static int +fix_fd (int fd) +{ + int input, output, error; + + input = output = error = 0; + +/* Unix allocates the lowest descriptors first, so a loop is not + * required, but this order is. */ + + if (fd == STDIN_FILENO) + { + fd = dup (fd); + input = 1; + } + if (fd == STDOUT_FILENO) + { + fd = dup (fd); + output = 1; + } + if (fd == STDERR_FILENO) + { + fd = dup (fd); + error = 1; + } + + if (input) + close (STDIN_FILENO); + if (output) + close (STDOUT_FILENO); + if (error) + close (STDERR_FILENO); + + return fd; +} + + +/* write()-- Write a buffer to a descriptor, allowing for short writes */ + +static int +writen (int fd, char *buffer, int len) +{ + int n, n0; + + n0 = len; + + while (len > 0) + { + n = write (fd, buffer, len); + if (n < 0) + return n; + + buffer += n; + len -= n; + } + + return n0; +} + + +#if 0 +/* readn()-- Read bytes into a buffer, allowing for short reads. If + * fewer than len bytes are returned, it is because we've hit the end + * of file. */ + +static int +readn (int fd, char *buffer, int len) +{ + int nread, n; + + nread = 0; + + while (len > 0) + { + n = read (fd, buffer, len); + if (n < 0) + return n; + + if (n == 0) + return nread; + + buffer += n; + nread += n; + len -= n; + } + + return nread; +} +#endif + + +/* get_oserror()-- Get the most recent operating system error. For + * unix, this is errno. */ + +const char * +get_oserror (void) +{ + + return strerror (errno); +} + + +/* sys_exit()-- Terminate the program with an exit code */ + +void +sys_exit (int code) +{ + + exit (code); +} + + + +/********************************************************************* + File descriptor stream functions +*********************************************************************/ + +/* fd_flush()-- Write bytes that need to be written */ + +static try +fd_flush (unix_stream * s) +{ + + if (s->ndirty == 0) + return SUCCESS;; + + if (s->physical_offset != s->dirty_offset && + lseek (s->fd, s->dirty_offset, SEEK_SET) < 0) + return FAILURE; + + if (writen (s->fd, s->buffer + (s->dirty_offset - s->buffer_offset), + s->ndirty) < 0) + return FAILURE; + + s->physical_offset = s->dirty_offset + s->ndirty; + if (s->physical_offset > s->file_length) + s->file_length = s->physical_offset; + s->ndirty = 0; + + return SUCCESS; +} + + +/* fd_alloc()-- Arrange a buffer such that the salloc() request can be + * satisfied. This subroutine gets the buffer ready for whatever is + * to come next. */ + +static void +fd_alloc (unix_stream * s, offset_t where, int *len) +{ + char *new_buffer; + int n, read_len; + + if (*len <= BUFFER_SIZE) + { + new_buffer = s->small_buffer; + read_len = BUFFER_SIZE; + } + else + { + new_buffer = get_mem (*len); + read_len = *len; + } + + /* Salvage bytes currently within the buffer. This is important for + * devices that cannot seek. */ + + if (s->buffer != NULL && s->buffer_offset <= where && + where <= s->buffer_offset + s->active) + { + + n = s->active - (where - s->buffer_offset); + memmove (new_buffer, s->buffer + (where - s->buffer_offset), n); + + s->active = n; + } + else + { /* new buffer starts off empty */ + s->active = 0; + } + + s->buffer_offset = where; + + /* free the old buffer if necessary */ + + if (s->buffer != NULL && s->buffer != s->small_buffer) + free_mem (s->buffer); + + s->buffer = new_buffer; + s->len = read_len; + s->mmaped = 0; +} + + +/* fd_alloc_r_at()-- Allocate a stream buffer for reading. Either + * we've already buffered the data or we need to load it. Returns + * NULL on I/O error. */ + +static char * +fd_alloc_r_at (unix_stream * s, int *len, offset_t where) +{ + offset_t m; + int n; + + if (where == -1) + where = s->logical_offset; + + if (s->buffer != NULL && s->buffer_offset <= where && + where + *len <= s->buffer_offset + s->active) + { + + /* Return a position within the current buffer */ + + s->logical_offset = where + *len; + return s->buffer + where - s->buffer_offset; + } + + fd_alloc (s, where, len); + + m = where + s->active; + + if (s->physical_offset != m && lseek (s->fd, m, SEEK_SET) < 0) + return NULL; + + n = read (s->fd, s->buffer + s->active, s->len - s->active); + if (n < 0) + return NULL; + + s->physical_offset = where + n; + + s->active += n; + if (s->active < *len) + *len = s->active; /* Bytes actually available */ + + s->logical_offset = where + *len; + + return s->buffer; +} + + +/* fd_alloc_w_at()-- Allocate a stream buffer for writing. Either + * we've already buffered the data or we need to load it. */ + +static char * +fd_alloc_w_at (unix_stream * s, int *len, offset_t where) +{ + offset_t n; + + if (where == -1) + where = s->logical_offset; + + if (s->buffer == NULL || s->buffer_offset > where || + where + *len > s->buffer_offset + s->len) + { + + if (fd_flush (s) == FAILURE) + return NULL; + fd_alloc (s, where, len); + } + + /* Return a position within the current buffer */ + + if (s->ndirty == 0) + { /* First write into a clean buffer */ + s->dirty_offset = where; + s->ndirty = *len; + } + else + { + if (s->dirty_offset + s->ndirty == where) + s->ndirty += *len; + else + fd_flush (s); /* Can't combine two dirty blocks */ + } + + s->logical_offset = where + *len; + + n = s->logical_offset - s->buffer_offset; + if (n > s->active) + s->active = n; + + return s->buffer + where - s->buffer_offset; +} + + +static try +fd_sfree (unix_stream * s) +{ + + if (s->ndirty != 0 && + (s->buffer != s->small_buffer || options.all_unbuffered || + s->unbuffered)) + return fd_flush (s); + + return SUCCESS; +} + + +static int +fd_seek (unix_stream * s, offset_t offset) +{ + + s->physical_offset = s->logical_offset = offset; + + return (lseek (s->fd, offset, SEEK_SET) < 0) ? FAILURE : SUCCESS; +} + + +/* truncate_file()-- Given a unit, truncate the file at the current + * position. Sets the physical location to the new end of the file. + * Returns nonzero on error. */ + +static try +fd_truncate (unix_stream * s) +{ + + if (ftruncate (s->fd, s->logical_offset)) + return FAILURE; + + s->physical_offset = s->file_length = s->logical_offset; + + if (lseek (s->fd, s->file_length, SEEK_SET) == -1) + return FAILURE; + + return SUCCESS; +} + + +static try +fd_close (unix_stream * s) +{ + + if (fd_flush (s) == FAILURE) + return FAILURE; + + if (s->buffer != NULL && s->buffer != s->small_buffer) + free_mem (s->buffer); + + if (close (s->fd) < 0) + return FAILURE; + + free_mem (s); + + return SUCCESS; +} + + +static void +fd_open (unix_stream * s) +{ + + if (isatty (s->fd)) + s->unbuffered = 1; + + s->st.alloc_r_at = (void *) fd_alloc_r_at; + s->st.alloc_w_at = (void *) fd_alloc_w_at; + s->st.sfree = (void *) fd_sfree; + s->st.close = (void *) fd_close; + s->st.seek = (void *) fd_seek; + s->st.truncate = (void *) fd_truncate; + + s->buffer = NULL; +} + + +/********************************************************************* + mmap stream functions + + Because mmap() is not capable of extending a file, we have to keep + track of how long the file is. We also have to be able to detect end + of file conditions. If there are multiple writers to the file (which + can only happen outside the current program), things will get + confused. Then again, things will get confused anyway. + +*********************************************************************/ + +#if HAVE_MMAP + +static int page_size, page_mask; + +/* mmap_flush()-- Deletes a memory mapping if something is mapped. */ + +static try +mmap_flush (unix_stream * s) +{ + + if (!s->mmaped) + return fd_flush (s); + + if (s->buffer == NULL) + return SUCCESS; + + if (munmap (s->buffer, s->active)) + return FAILURE; + + s->buffer = NULL; + s->active = 0; + + return SUCCESS; +} + + +/* mmap_alloc()-- mmap() a section of the file. The whole section is + * guaranteed to be mappable. */ + +static try +mmap_alloc (unix_stream * s, offset_t where, int *len) +{ + offset_t offset; + int length; + char *p; + + if (mmap_flush (s) == FAILURE) + return FAILURE; + + offset = where & page_mask; /* Round down to the next page */ + + length = ((where - offset) & page_mask) + 2 * page_size; + + p = mmap (NULL, length, s->prot, MAP_SHARED, s->fd, offset); + if (p == (char *) MAP_FAILED) + return FAILURE; + + s->mmaped = 1; + s->buffer = p; + s->buffer_offset = offset; + s->active = length; + + return SUCCESS; +} + + +static char * +mmap_alloc_r_at (unix_stream * s, int *len, offset_t where) +{ + offset_t m; + + if (where == -1) + where = s->logical_offset; + + m = where + *len; + + if ((s->buffer == NULL || s->buffer_offset > where || + m > s->buffer_offset + s->active) && + mmap_alloc (s, where, len) == FAILURE) + return NULL; + + if (m > s->file_length) + { + *len = s->file_length - s->logical_offset; + s->logical_offset = s->file_length; + } + else + s->logical_offset = m; + + return s->buffer + (where - s->buffer_offset); +} + + +static char * +mmap_alloc_w_at (unix_stream * s, int *len, offset_t where) +{ + if (where == -1) + where = s->logical_offset; + + /* If we're extending the file, we have to use file descriptor + * methods. */ + + if (where + *len > s->file_length) + { + if (s->mmaped) + mmap_flush (s); + return fd_alloc_w_at (s, len, where); + } + + if ((s->buffer == NULL || s->buffer_offset > where || + where + *len > s->buffer_offset + s->active) && + mmap_alloc (s, where, len) == FAILURE) + return NULL; + + s->logical_offset = where + *len; + + return s->buffer + where - s->buffer_offset; +} + + +static int +mmap_seek (unix_stream * s, offset_t offset) +{ + + s->logical_offset = offset; + return SUCCESS; +} + + +static try +mmap_close (unix_stream * s) +{ + try t; + + t = mmap_flush (s); + + if (close (s->fd) < 0) + t = FAILURE; + free_mem (s); + + return t; +} + + +static try +mmap_sfree (unix_stream * s) +{ + + return SUCCESS; +} + + +/* mmap_open()-- mmap_specific open. If the particular file cannot be + * mmap()-ed, we fall back to the file descriptor functions. */ + +static try +mmap_open (unix_stream * s) +{ + char *p; + int i; + + page_size = getpagesize (); + page_mask = ~0; + + p = mmap (0, page_size, s->prot, MAP_SHARED, s->fd, 0); + if (p == (char *) MAP_FAILED) + { + fd_open (s); + return SUCCESS; + } + + munmap (p, page_size); + + i = page_size >> 1; + while (i != 0) + { + page_mask <<= 1; + i >>= 1; + } + + s->st.alloc_r_at = (void *) mmap_alloc_r_at; + s->st.alloc_w_at = (void *) mmap_alloc_w_at; + s->st.sfree = (void *) mmap_sfree; + s->st.close = (void *) mmap_close; + s->st.seek = (void *) mmap_seek; + s->st.truncate = (void *) fd_truncate; + + if (lseek (s->fd, s->file_length, SEEK_SET) < 0) + return FAILURE; + + return SUCCESS; +} + +#endif + + +/********************************************************************* + memory stream functions - These are used for internal files + + The idea here is that a single stream structure is created and all + requests must be satisfied from it. The location and size of the + buffer is the character variable supplied to the READ or WRITE + statement. + +*********************************************************************/ + + +static char * +mem_alloc_r_at (unix_stream * s, int *len, offset_t where) +{ + offset_t n; + + if (where == -1) + where = s->logical_offset; + + if (where < s->buffer_offset || where > s->buffer_offset + s->active) + return NULL; + + if (is_internal_unit() && where + *len > s->file_length) + return NULL; + + s->logical_offset = where + *len; + + n = (where - s->buffer_offset) - s->active; + if (*len > n) + *len = n; + + return s->buffer + (where - s->buffer_offset); +} + + +static char * +mem_alloc_w_at (unix_stream * s, int *len, offset_t where) +{ + offset_t m; + + if (where == -1) + where = s->logical_offset; + + m = where + *len; + + if (where < s->buffer_offset || m > s->buffer_offset + s->active) + return NULL; + + s->logical_offset = m; + + return s->buffer + (where - s->buffer_offset); +} + + +static int +mem_seek (unix_stream * s, offset_t offset) +{ + + if (offset > s->file_length) + { + errno = ESPIPE; + return FAILURE; + } + + s->logical_offset = offset; + return SUCCESS; +} + + +static int +mem_truncate (unix_stream * s) +{ + + return SUCCESS; +} + + +static try +mem_close (unix_stream * s) +{ + + return SUCCESS; +} + + +static try +mem_sfree (unix_stream * s) +{ + + return SUCCESS; +} + + + +/********************************************************************* + Public functions -- A reimplementation of this module needs to + define functional equivalents of the following. +*********************************************************************/ + +/* empty_internal_buffer()-- Zero the buffer of Internal file */ + +void +empty_internal_buffer(stream *strm) +{ + unix_stream * s = (unix_stream *) strm; + memset(s->buffer, ' ', s->file_length); +} + +/* open_internal()-- Returns a stream structure from an internal file */ + +stream * +open_internal (char *base, int length) +{ + unix_stream *s; + + s = get_mem (sizeof (unix_stream)); + + s->buffer = base; + s->buffer_offset = 0; + + s->logical_offset = 0; + s->active = s->file_length = length; + + s->st.alloc_r_at = (void *) mem_alloc_r_at; + s->st.alloc_w_at = (void *) mem_alloc_w_at; + s->st.sfree = (void *) mem_sfree; + s->st.close = (void *) mem_close; + s->st.seek = (void *) mem_seek; + s->st.truncate = (void *) mem_truncate; + + return (stream *) s; +} + + +/* fd_to_stream()-- Given an open file descriptor, build a stream + * around it. */ + +static stream * +fd_to_stream (int fd, int prot) +{ + struct stat statbuf; + unix_stream *s; + + s = get_mem (sizeof (unix_stream)); + + s->fd = fd; + s->buffer_offset = 0; + s->physical_offset = 0; + s->logical_offset = 0; + s->prot = prot; + + /* Get the current length of the file. */ + + fstat (fd, &statbuf); + s->file_length = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1; + +#if HAVE_MMAP + mmap_open (s); +#else + fd_open (s); +#endif + + return (stream *) s; +} + + +/* unpack_filename()-- Given a fortran string and a pointer to a + * buffer that is PATH_MAX characters, convert the fortran string to a + * C string in the buffer. Returns nonzero if this is not possible. */ + +static int +unpack_filename (char *cstring, const char *fstring, int len) +{ + + len = fstrlen (fstring, len); + if (len >= PATH_MAX) + return 1; + + memmove (cstring, fstring, len); + cstring[len] = '\0'; + + return 0; +} + + +/* tempfile()-- Generate a temporary filename for a scratch file and + * open it. mkstemp() opens the file for reading and writing, but the + * library mode prevents anything that is not allowed. The descriptor + * is returns, which is less than zero on error. The template is + * pointed to by ioparm.file, which is copied into the unit structure + * and freed later. */ + +static int +tempfile (void) +{ + const char *tempdir; + char *template; + int fd; + + tempdir = getenv ("GFORTRAN_TMPDIR"); + if (tempdir == NULL) + tempdir = getenv ("TMP"); + if (tempdir == NULL) + tempdir = DEFAULT_TEMPDIR; + + template = get_mem (strlen (tempdir) + 20); + + st_sprintf (template, "%s/gfortantmpXXXXXX", tempdir); + + fd = mkstemp (template); + + if (fd < 0) + free_mem (template); + else + { + ioparm.file = template; + ioparm.file_len = strlen (template); /* Don't include trailing nul */ + } + + return fd; +} + + +/* regular_file()-- Open a regular file. Returns the descriptor, which is less than zero on error. */ + +static int +regular_file (unit_action action, unit_status status) +{ + char path[PATH_MAX + 1]; + struct stat statbuf; + int mode; + + if (unpack_filename (path, ioparm.file, ioparm.file_len)) + { + errno = ENOENT; /* Fake an OS error */ + return -1; + } + + mode = 0; + + switch (action) + { + case ACTION_READ: + mode = O_RDONLY; + break; + + case ACTION_WRITE: + mode = O_WRONLY; + break; + + case ACTION_READWRITE: + mode = O_RDWR; + break; + + default: + internal_error ("regular_file(): Bad action"); + } + + switch (status) + { + case STATUS_NEW: + mode |= O_CREAT | O_EXCL; + break; + + case STATUS_OLD: /* file must exist, so check for its existence */ + if (stat (path, &statbuf) < 0) + return -1; + break; + + case STATUS_UNKNOWN: + case STATUS_SCRATCH: + mode |= O_CREAT; + break; + + case STATUS_REPLACE: + mode |= O_TRUNC; + break; + + default: + internal_error ("regular_file(): Bad status"); + } + + // mode |= O_LARGEFILE; + + return open (path, mode, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); +} + + +/* open_external()-- Open an external file, unix specific version. + * Returns NULL on operating system error. */ + +stream * +open_external (unit_action action, unit_status status) +{ + int fd, prot; + + fd = + (status == STATUS_SCRATCH) ? tempfile () : regular_file (action, status); + + if (fd < 0) + return NULL; + fd = fix_fd (fd); + + switch (action) + { + case ACTION_READ: + prot = PROT_READ; + break; + + case ACTION_WRITE: + prot = PROT_WRITE; + break; + + case ACTION_READWRITE: + prot = PROT_READ | PROT_WRITE; + break; + + default: + internal_error ("open_external(): Bad action"); + } + + /* If this is a scratch file, we can unlink it now and the file will + * go away when it is closed. */ + + if (status == STATUS_SCRATCH) + unlink (ioparm.file); + + return fd_to_stream (fd, prot); +} + + +/* input_stream()-- Return a stream pointer to the default input stream. + * Called on initialization. */ + +stream * +input_stream (void) +{ + + return fd_to_stream (STDIN_FILENO, PROT_READ); +} + + +/* output_stream()-- Return a stream pointer to the default input stream. + * Called on initialization. */ + +stream * +output_stream (void) +{ + + return fd_to_stream (STDOUT_FILENO, PROT_WRITE); +} + + +/* init_error_stream()-- Return a pointer to the error stream. This + * subroutine is called when the stream is needed, rather than at + * initialization. We want to work even if memory has been seriously + * corrupted. */ + +stream * +init_error_stream (void) +{ + static unix_stream error; + + memset (&error, '\0', sizeof (error)); + + error.fd = options.use_stderr ? STDERR_FILENO : STDOUT_FILENO; + + error.st.alloc_w_at = (void *) fd_alloc_w_at; + error.st.sfree = (void *) fd_sfree; + + error.unbuffered = 1; + error.buffer = error.small_buffer; + + return (stream *) & error; +} + + +/* compare_file_filename()-- Given an open stream and a fortran string + * that is a filename, figure out if the file is the same as the + * filename. */ + +int +compare_file_filename (stream * s, const char *name, int len) +{ + char path[PATH_MAX + 1]; + struct stat st1, st2; + + if (unpack_filename (path, name, len)) + return 0; /* Can't be the same */ + + /* If the filename doesn't exist, then there is no match with the + * existing file. */ + + if (stat (path, &st1) < 0) + return 0; + + fstat (((unix_stream *) s)->fd, &st2); + + return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino); +} + + +/* find_file0()-- Recursive work function for find_file() */ + +static unit_t * +find_file0 (unit_t * u, struct stat *st1) +{ + struct stat st2; + unit_t *v; + + if (u == NULL) + return NULL; + + if (fstat (((unix_stream *) u->s)->fd, &st2) >= 0 && + st1->st_dev == st2.st_dev && st1->st_ino == st2.st_ino) + return u; + + v = find_file0 (u->left, st1); + if (v != NULL) + return v; + + v = find_file0 (u->right, st1); + if (v != NULL) + return v; + + return NULL; +} + + +/* find_file()-- Take the current filename and see if there is a unit + * that has the file already open. Returns a pointer to the unit if so. */ + +unit_t * +find_file (void) +{ + char path[PATH_MAX + 1]; + struct stat statbuf; + + if (unpack_filename (path, ioparm.file, ioparm.file_len)) + return NULL; + + if (stat (path, &statbuf) < 0) + return NULL; + + return find_file0 (g.unit_root, &statbuf); +} + + +/* stream_at_bof()-- Returns nonzero if the stream is at the beginning + * of the file. */ + +int +stream_at_bof (stream * s) +{ + unix_stream *us; + + us = (unix_stream *) s; + + if (!us->mmaped) + return 0; /* File is not seekable */ + + return us->logical_offset == 0; +} + + +/* stream_at_eof()-- Returns nonzero if the stream is at the beginning + * of the file. */ + +int +stream_at_eof (stream * s) +{ + unix_stream *us; + + us = (unix_stream *) s; + + if (!us->mmaped) + return 0; /* File is not seekable */ + + return us->logical_offset == us->dirty_offset; +} + + +/* delete_file()-- Given a unit structure, delete the file associated + * with the unit. Returns nonzero if something went wrong. */ + +int +delete_file (unit_t * u) +{ + char path[PATH_MAX + 1]; + + if (unpack_filename (path, u->file, u->file_len)) + { /* Shouldn't be possible */ + errno = ENOENT; + return 1; + } + + return unlink (path); +} + + +/* file_exists()-- Returns nonzero if the current filename exists on + * the system */ + +int +file_exists (void) +{ + char path[PATH_MAX + 1]; + struct stat statbuf; + + if (unpack_filename (path, ioparm.file, ioparm.file_len)) + return 0; + + if (stat (path, &statbuf) < 0) + return 0; + + return 1; +} + + + +static const char *yes = "YES", *no = "NO", *unknown = "UNKNOWN"; + +/* inquire_sequential()-- Given a fortran string, determine if the + * file is suitable for sequential access. Returns a C-style + * string. */ + +const char * +inquire_sequential (const char *string, int len) +{ + char path[PATH_MAX + 1]; + struct stat statbuf; + + if (string == NULL || + unpack_filename (path, string, len) || stat (path, &statbuf) < 0) + return unknown; + + if (S_ISREG (statbuf.st_mode) || + S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)) + return yes; + + if (S_ISDIR (statbuf.st_mode) || S_ISBLK (statbuf.st_mode)) + return no; + + return unknown; +} + + +/* inquire_direct()-- Given a fortran string, determine if the file is + * suitable for direct access. Returns a C-style string. */ + +const char * +inquire_direct (const char *string, int len) +{ + char path[PATH_MAX + 1]; + struct stat statbuf; + + if (string == NULL || + unpack_filename (path, string, len) || stat (path, &statbuf) < 0) + return unknown; + + if (S_ISREG (statbuf.st_mode) || S_ISBLK (statbuf.st_mode)) + return yes; + + if (S_ISDIR (statbuf.st_mode) || + S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)) + return no; + + return unknown; +} + + +/* inquire_formatted()-- Given a fortran string, determine if the file + * is suitable for formatted form. Returns a C-style string. */ + +const char * +inquire_formatted (const char *string, int len) +{ + char path[PATH_MAX + 1]; + struct stat statbuf; + + if (string == NULL || + unpack_filename (path, string, len) || stat (path, &statbuf) < 0) + return unknown; + + if (S_ISREG (statbuf.st_mode) || + S_ISBLK (statbuf.st_mode) || + S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)) + return yes; + + if (S_ISDIR (statbuf.st_mode)) + return no; + + return unknown; +} + + +/* inquire_unformatted()-- Given a fortran string, determine if the file + * is suitable for unformatted form. Returns a C-style string. */ + +const char * +inquire_unformatted (const char *string, int len) +{ + + return inquire_formatted (string, len); +} + + +/* inquire_access()-- Given a fortran string, determine if the file is + * suitable for access. */ + +static const char * +inquire_access (const char *string, int len, int mode) +{ + char path[PATH_MAX + 1]; + + if (string == NULL || unpack_filename (path, string, len) || + access (path, mode) < 0) + return no; + + return yes; +} + + +/* inquire_read()-- Given a fortran string, determine if the file is + * suitable for READ access. */ + +const char * +inquire_read (const char *string, int len) +{ + + return inquire_access (string, len, R_OK); +} + + +/* inquire_write()-- Given a fortran string, determine if the file is + * suitable for READ access. */ + +const char * +inquire_write (const char *string, int len) +{ + + return inquire_access (string, len, W_OK); +} + + +/* inquire_readwrite()-- Given a fortran string, determine if the file is + * suitable for read and write access. */ + +const char * +inquire_readwrite (const char *string, int len) +{ + + return inquire_access (string, len, R_OK | W_OK); +} + + +/* file_length()-- Return the file length in bytes, -1 if unknown */ + +offset_t +file_length (stream * s) +{ + + return ((unix_stream *) s)->file_length; +} + + +/* file_position()-- Return the current position of the file */ + +offset_t +file_position (stream * s) +{ + + return ((unix_stream *) s)->logical_offset; +} + + +/* is_seekable()-- Return nonzero if the stream is seekable, zero if + * it is not */ + +int +is_seekable (stream * s) +{ + + return ((unix_stream *) s)->mmaped; +} + + +/* How files are stored: This is an operating-system specific issue, + and therefore belongs here. There are three cases to consider. + + Direct Access: + Records are written as block of bytes corresponding to the record + length of the file. This goes for both formatted and unformatted + records. Positioning is done explicitly for each data transfer, + so positioning is not much of an issue. + + Sequential Formatted: + Records are separated by newline characters. The newline character + is prohibited from appearing in a string. If it does, this will be + messed up on the next read. End of file is also the end of a record. + + Sequential Unformatted: + In this case, we are merely copying bytes to and from main storage, + yet we need to keep track of varying record lengths. We adopt + the solution used by f2c. Each record contains a pair of length + markers: + + Length of record n in bytes + Data of record n + Length of record n in bytes + + Length of record n+1 in bytes + Data of record n+1 + Length of record n+1 in bytes + + The length is stored at the end of a record to allow backspacing to the + previous record. Between data transfer statements, the file pointer + is left pointing to the first length of the current record. + + ENDFILE records are never explicitly stored. + +*/ diff --git a/libgfortran/io/write.c b/libgfortran/io/write.c new file mode 100644 index 00000000000..dd44f6e5f72 --- /dev/null +++ b/libgfortran/io/write.c @@ -0,0 +1,1129 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Libgfortran; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h" +#include "io.h" +#include + + +#define star_fill(p, n) memset(p, '*', n) + + +typedef enum +{ SIGN_NONE, SIGN_MINUS, SIGN_PLUS } +sign_t; + + +void +write_a (fnode * f, const char *source, int len) +{ + int wlen; + char *p; + + wlen = f->u.string.length < 0 ? len : f->u.string.length; + + p = write_block (wlen); + if (p == NULL) + return; + + if (wlen < len) + memcpy (p, source, wlen); + else + { + memcpy (p, source, len); + memset (p + len, ' ', wlen - len); + } +} + +static int64_t +extract_int (const void *p, int len) +{ + int64_t i = 0; + + if (p == NULL) + return i; + + switch (len) + { + case 1: + i = *((const int8_t *) p); + break; + case 2: + i = *((const int16_t *) p); + break; + case 4: + i = *((const int32_t *) p); + break; + case 8: + i = *((const int64_t *) p); + break; + default: + internal_error ("bad integer kind"); + } + + return i; +} + +static double +extract_real (const void *p, int len) +{ + double i = 0.0; + switch (len) + { + case 4: + i = *((const float *) p); + break; + case 8: + i = *((const double *) p); + break; + default: + internal_error ("bad real kind"); + } + return i; + +} + + +/* calculate sign()-- Given a flag that indicate if a value is + * negative or not, return a sign_t that gives the sign that we need + * to produce. */ + +static sign_t +calculate_sign (int negative_flag) +{ + sign_t s = SIGN_NONE; + + if (negative_flag) + s = SIGN_MINUS; + else + switch (g.sign_status) + { + case SIGN_SP: + s = SIGN_PLUS; + break; + case SIGN_SS: + s = SIGN_NONE; + break; + case SIGN_S: + s = options.optional_plus ? SIGN_PLUS : SIGN_NONE; + break; + } + + return s; +} + + +/* calculate_exp()-- returns the value of 10**d. */ + +static double +calculate_exp (int d) +{ + int i; + double r = 1.0; + + for (i = 0; i< (d >= 0 ? d : -d); i++) + r *= 10; + + r = (d >= 0) ? r : 1.0 / r; + + return r; +} + + +/* calculate_G_format()-- geneate corresponding I/O format for + FMT_G output. + The rules to translate FMT_G to FMT_E or FNT_F from DEC fortran + LRM (table 11-2, Chapter 11, "I/O Formatting", P11-25) is: + + Data Magnitude Equivalent Conversion + 0< m < 0.1-0.5*10**(-d-1) Ew.d[Ee] + m = 0 F(w-n).(d-1), n' ' + 0.1-0.5*10**(-d-1)<= m < 1-0.5*10**(-d) F(w-n).d, n' ' + 1-0.5*10**(-d)<= m < 10-0.5*10**(-d+1) F(w-n).(d-1), n' ' + 10-0.5*10**(-d+1)<= m < 100-0.5*10**(-d+2) F(w-n).(d-2), n' ' + ................ .......... + 10**(d-1)-0.5*10**(-1)<= m <10**d-0.5 F(w-n).0,n(' ') + m >= 10**d-0.5 Ew.d[Ee] + + notes: for Gw.d , n' ' means 4 blanks + for Gw.dEe, n' ' means e+2 blanks */ + +static fnode * +calculate_G_format (fnode *f, double value, int len, int *num_blank) +{ + int e = f->u.real.e; + int d = f->u.real.d; + int w = f->u.real.w; + fnode *newf; + double m, exp_d; + int low, high, mid; + int ubound, lbound; + + newf = get_mem (sizeof (fnode)); + + /* Absolute value. */ + m = (value > 0.0) ? value : -value; + + /* In case of the two data magnitude ranges, + generate E editing, Ew.d[Ee]. */ + exp_d = calculate_exp (d); + if ((m > 0.0 && m < 0.1 - 0.05 / (double) exp_d) + || (m >= (double) exp_d - 0.5 )) + { + newf->format = FMT_E; + newf->u.real.w = w; + newf->u.real.d = d; + newf->u.real.e = e; + *num_blank = e + 2; + return newf; + } + + /* Use binary search to find the data magnitude range. */ + mid = 0; + low = 0; + high = d + 1; + lbound = 0; + ubound = d + 1; + + while (low <= high) + { + double temp; + mid = (low + high) / 2; + + /* 0.1 * 10**mid - 0.5 * 10**(mid-d-1) */ + temp = 0.1 * calculate_exp (mid) - 0.5 * calculate_exp (mid - d - 1); + + if (m < temp) + { + ubound = mid; + if (ubound == lbound + 1) + break; + high = mid - 1; + } + else if (m > temp) + { + lbound = mid; + if (ubound == lbound + 1) + { + mid ++; + break; + } + low = mid + 1; + } + else + break; + } + + /* Generate the F editing. F(w-4).(-(mid-d-1)), 4' '. */ + newf->format = FMT_F; + newf->u.real.w = f->u.real.w - 4; + + /* Special case. */ + if (m == 0.0) + newf->u.real.d = d - 1; + else + newf->u.real.d = - (mid - d - 1); + + *num_blank = 4; + + /* For F editing, the scale factor is ignored. */ + g.scale_factor = 0; + return newf; +} + + +/* output_float() -- output a real number according to its format + which is FMT_G free */ + +static void +output_float (fnode *f, double value, int len) +{ + int w, d, e, e_new; + int digits; + int nsign, nblank, nesign; + int sca, neval, itmp; + char *p; + const char *q, *intstr, *base; + double n; + format_token ft; + char exp_char = 'E'; + int with_exp = 1; + int scale_flag = 1 ; + double minv = 0.0, maxv = 0.0; + sign_t sign = SIGN_NONE, esign = SIGN_NONE; + + int intval = 0, intlen = 0; + int j; + + /* EXP value for this number */ + neval = 0; + + /* Width of EXP and it's sign*/ + nesign = 0; + + ft = f->format; + w = f->u.real.w; + d = f->u.real.d + 1; + + /* Width of the EXP */ + e = 0; + + sca = g.scale_factor; + n = value; + + sign = calculate_sign (n < 0.0); + if (n < 0) + n = -n; + + /* Width of the sign for the whole number */ + nsign = (sign == SIGN_NONE ? 0 : 1); + + digits = 0; + if (ft != FMT_F) + { + e = f->u.real.e; + } + if (ft == FMT_F || ft == FMT_E || ft == FMT_D) + { + if (ft == FMT_F) + scale_flag = 0; + if (ft == FMT_D) + exp_char = 'D' ; + minv = 0.1; + maxv = 1.0; + + /* Here calculate the new val of the number with consideration + of Globle Scale value */ + while (sca > 0) + { + minv *= 10.0; + maxv *= 10.0; + n *= 10.0; + sca -- ; + neval --; + } + + /* Now calculate the new Exp value for this number */ + sca = g.scale_factor; + while(sca >= 1) + { + sca /= 10; + digits ++ ; + } + } + + if (ft == FMT_EN ) + { + minv = 1.0; + maxv = 1000.0; + } + if (ft == FMT_ES) + { + minv = 1.0; + maxv = 10.0; + } + + /* OK, let's scale the number to appropriate range */ + while (scale_flag && n > 0.0 && n < minv) + { + if (n < minv) + { + n = n * 10.0 ; + neval --; + } + } + while (scale_flag && n > 0.0 && n > maxv) + { + if (n > maxv) + { + n = n / 10.0 ; + neval ++; + } + } + + /* It is time to process the EXP part of the number. + Value of 'nesign' is 0 unless following codes is executed. + */ + if (ft != FMT_F) + { + /* Sign of the EXP value */ + if (neval >= 0) + esign = SIGN_PLUS; + else + { + esign = SIGN_MINUS; + neval = - neval ; + } + + /* Width of the EXP*/ + e_new = 0; + j = neval; + while (j > 0) + { + j = j / 10; + e_new ++ ; + } + if (e <= e_new) + e = e_new; + + /* Got the width of EXP */ + if (e < digits) + e = digits ; + + /* Minimum value of the width would be 2 */ + if (e < 2) + e = 2; + + nesign = 1 ; /* We must give a position for the 'exp_char' */ + if (e > 0) + nesign = e + nesign + (esign != SIGN_NONE ? 1 : 0); + } + + + intval = n; + intstr = itoa (intval); + intlen = strlen (intstr); + + q = rtoa (n, len, d); + digits = strlen (q); + + /* Select a width if none was specified. */ + if (w <= 0) + w = digits + nsign; + + p = write_block (w); + if (p == NULL) + return; + + base = p; + + nblank = w - (nsign + intlen + d + nesign); + if (nblank == -1 && ft != FMT_F) + { + with_exp = 0; + nesign -= 1; + nblank = w - (nsign + intlen + d + nesign); + } + /* don't let a leading '0' cause field overflow */ + if (nblank == -1 && ft == FMT_F && q[0] == '0') + { + q++; + nblank = 0; + } + + if (nblank < 0) + { + star_fill (p, w); + goto done; + } + memset (p, ' ', nblank); + p += nblank; + + switch (sign) + { + case SIGN_PLUS: + *p++ = '+'; + break; + case SIGN_MINUS: + *p++ = '-'; + break; + case SIGN_NONE: + break; + } + + memcpy (p, q, intlen + d + 1); + p += intlen + d; + + if (nesign > 0) + { + if (with_exp) + *p++ = exp_char; + switch (esign) + { + case SIGN_PLUS: + *p++ = '+'; + break; + case SIGN_MINUS: + *p++ = '-'; + break; + case SIGN_NONE: + break; + } + q = itoa (neval); + digits = strlen (q); + + for (itmp = 0; itmp < e - digits; itmp++) + *p++ = '0'; + memcpy (p, q, digits); + p[digits] = 0; + } + +done: + return ; +} + +void +write_l (fnode * f, char *source, int len) +{ + char *p; + int64_t n; + + p = write_block (f->u.w); + if (p == NULL) + return; + + memset (p, ' ', f->u.w - 1); + n = extract_int (source, len); + p[f->u.w - 1] = (n) ? 'T' : 'F'; +} + +/* write_float() -- output a real number according to its format */ + +static void +write_float (fnode *f, const char *source, int len) +{ + double n; + int nb =0, res; + char * p, fin; + fnode *f2 = NULL; + + n = extract_real (source, len); + + if (f->format != FMT_B && f->format != FMT_O && f->format != FMT_Z) + { + res = finite (n); + if (res == 0) + { + nb = f->u.real.w; + if (nb <= 4) + nb = 4; + p = write_block (nb); + memset (p, ' ' , 1); + + res = isinf (n); + if (res != 0) + { + if (res > 0) + fin = '+'; + else + fin = '-'; + + memset (p + 1, fin, nb - 1); + } + else + sprintf(p + 1, "NaN"); + return; + } + } + + if (f->format != FMT_G) + { + output_float (f, n, len); + } + else + { + f2 = calculate_G_format(f, n, len, &nb); + output_float (f2, n, len); + if (f2 != NULL) + free_mem(f2); + + if (nb > 0) + { + p = write_block (nb); + memset (p, ' ', nb); + } + } +} + + +static void +write_int (fnode *f, const char *source, int len, char *(*conv) (uint64_t)) +{ + uint32_t ns =0; + uint64_t n = 0; + int w, m, digits, nzero, nblank; + char *p, *q; + + w = f->u.integer.w; + m = f->u.integer.m; + + n = extract_int (source, len); + + /* Special case */ + + if (m == 0 && n == 0) + { + if (w == 0) + w = 1; + + p = write_block (w); + if (p == NULL) + return; + + memset (p, ' ', w); + goto done; + } + + + if (len < 8) + { + ns = n; + q = conv (ns); + } + else + q = conv (n); + + digits = strlen (q); + + /* Select a width if none was specified. The idea here is to always + * print something. */ + + if (w == 0) + w = ((digits < m) ? m : digits); + + p = write_block (w); + if (p == NULL) + return; + + nzero = 0; + if (digits < m) + nzero = m - digits; + + /* See if things will work */ + + nblank = w - (nzero + digits); + + if (nblank < 0) + { + star_fill (p, w); + goto done; + } + + memset (p, ' ', nblank); + p += nblank; + + memset (p, '0', nzero); + p += nzero; + + memcpy (p, q, digits); + +done: + return; +} + +static void +write_decimal (fnode *f, const char *source, int len, char *(*conv) (int64_t)) +{ + int64_t n = 0; + int w, m, digits, nsign, nzero, nblank; + char *p, *q; + sign_t sign; + + w = f->u.integer.w; + m = f->u.integer.m; + + n = extract_int (source, len); + + /* Special case */ + + if (m == 0 && n == 0) + { + if (w == 0) + w = 1; + + p = write_block (w); + if (p == NULL) + return; + + memset (p, ' ', w); + goto done; + } + + sign = calculate_sign (n < 0); + if (n < 0) + n = -n; + + nsign = sign == SIGN_NONE ? 0 : 1; + q = conv (n); + + digits = strlen (q); + + /* Select a width if none was specified. The idea here is to always + * print something. */ + + if (w == 0) + w = ((digits < m) ? m : digits) + nsign; + + p = write_block (w); + if (p == NULL) + return; + + nzero = 0; + if (digits < m) + nzero = m - digits; + + /* See if things will work */ + + nblank = w - (nsign + nzero + digits); + + if (nblank < 0) + { + star_fill (p, w); + goto done; + } + + memset (p, ' ', nblank); + p += nblank; + + switch (sign) + { + case SIGN_PLUS: + *p++ = '+'; + break; + case SIGN_MINUS: + *p++ = '-'; + break; + case SIGN_NONE: + break; + } + + memset (p, '0', nzero); + p += nzero; + + memcpy (p, q, digits); + +done: + return; +} + + +/* otoa()-- Convert unsigned octal to ascii */ + +static char * +otoa (uint64_t n) +{ + char *p; + + if (n == 0) + { + scratch[0] = '0'; + scratch[1] = '\0'; + return scratch; + } + + p = scratch + sizeof (SCRATCH_SIZE) - 1; + *p-- = '\0'; + + while (n != 0) + { + *p = '0' + (n & 7); + p -- ; + n >>= 3; + } + + return ++p; +} + + +/* btoa()-- Convert unsigned binary to ascii */ + +static char * +btoa (uint64_t n) +{ + char *p; + + if (n == 0) + { + scratch[0] = '0'; + scratch[1] = '\0'; + return scratch; + } + + p = scratch + sizeof (SCRATCH_SIZE) - 1; + *p-- = '\0'; + + while (n != 0) + { + *p-- = '0' + (n & 1); + n >>= 1; + } + + return ++p; +} + + +void +write_i (fnode * f, const char *p, int len) +{ + + write_decimal (f, p, len, (void *) itoa); +} + + +void +write_b (fnode * f, const char *p, int len) +{ + + write_int (f, p, len, btoa); +} + + +void +write_o (fnode * f, const char *p, int len) +{ + + write_int (f, p, len, otoa); +} + +void +write_z (fnode * f, const char *p, int len) +{ + + write_int (f, p, len, xtoa); +} + + +void +write_d (fnode *f, const char *p, int len) +{ + write_float (f, p, len); +} + + +void +write_e (fnode *f, const char *p, int len) +{ + write_float (f, p, len); +} + + +void +write_f (fnode *f, const char *p, int len) +{ + write_float (f, p, len); +} + + +void +write_en (fnode *f, const char *p, int len) +{ + write_float (f, p, len); +} + + +void +write_es (fnode *f, const char *p, int len) +{ + write_float (f, p, len); +} + + +/* write_x()-- Take care of the X/TR descriptor */ + +void +write_x (fnode * f) +{ + char *p; + + p = write_block (f->u.n); + if (p == NULL) + return; + + memset (p, ' ', f->u.n); +} + + +/* List-directed writing */ + + +/* write_char()-- Write a single character to the output. Returns + * nonzero if something goes wrong. */ + +static int +write_char (char c) +{ + char *p; + + p = write_block (1); + if (p == NULL) + return 1; + + *p = c; + + return 0; +} + + +/* write_logical()-- Write a list-directed logical value */ +/* Default logical output should be L2 + according to DEC fortran Manual. */ +static void +write_logical (const char *source, int length) +{ + write_char (' '); + write_char (extract_int (source, length) ? 'T' : 'F'); +} + + +/* write_integer()-- Write a list-directed integer value. */ + +static void +write_integer (const char *source, int length) +{ + char *p; + const char *q; + int digits; + int width = 12; + + q = itoa (extract_int (source, length)); + + digits = strlen (q); + + if(width < digits ) + width = digits ; + p = write_block (width) ; + + memset(p ,' ', width - digits) ; + memcpy (p + width - digits, q, digits); +} + + +/* write_character()-- Write a list-directed string. We have to worry + * about delimiting the strings if the file has been opened in that + * mode. */ + +static void +write_character (const char *source, int length) +{ + int i, extra; + char *p, d; + + switch (current_unit->flags.delim) + { + case DELIM_APOSTROPHE: + d = '\''; + break; + case DELIM_QUOTE: + d = '"'; + break; + default: + d = ' '; + break; + } + + if (d == ' ') + extra = 0; + else + { + extra = 2; + + for (i = 0; i < length; i++) + if (source[i] == d) + extra++; + } + + p = write_block (length + extra); + if (p == NULL) + return; + + if (d == ' ') + memcpy (p, source, length); + else + { + *p++ = d; + + for (i = 0; i < length; i++) + { + *p++ = source[i]; + if (source[i] == d) + *p++ = d; + } + + *p = d; + } +} + + +/* Output the Real number with default format. + According to DEC fortran LRM, default format for + REAL(4) is 1PG15.7E2, and for REAL(8) is 1PG25.15E3 */ + +static void +write_real (const char *source, int length) +{ + fnode f ; + int org_scale = g.scale_factor; + f.format = FMT_G; + g.scale_factor = 1; + if (length < 8) + { + f.u.real.w = 15; + f.u.real.d = 7; + f.u.real.e = 2; + } + else + { + f.u.real.w = 24; + f.u.real.d = 15; + f.u.real.e = 3; + } + write_float (&f, source , length); + g.scale_factor = org_scale; +} + + +static void +write_complex (const char *source, int len) +{ + + if (write_char ('(')) + return; + write_real (source, len); + + if (write_char (',')) + return; + write_real (source + len, len); + + write_char (')'); +} + + +/* write_separator()-- Write the separator between items. */ + +static void +write_separator (void) +{ + char *p; + + p = write_block (options.separator_len); + if (p == NULL) + return; + + memcpy (p, options.separator, options.separator_len); +} + + +/* list_formatted_write()-- Write an item with list formatting. + * TODO: handle skipping to the next record correctly, particularly + * with strings. */ + +void +list_formatted_write (bt type, void *p, int len) +{ + static int char_flag; + + if (current_unit == NULL) + return; + + if (g.first_item) + { + g.first_item = 0; + char_flag = 0; + } + else + { + if (type != BT_CHARACTER || !char_flag || + current_unit->flags.delim != DELIM_NONE) + write_separator (); + } + + switch (type) + { + case BT_INTEGER: + write_integer (p, len); + break; + case BT_LOGICAL: + write_logical (p, len); + break; + case BT_CHARACTER: + write_character (p, len); + break; + case BT_REAL: + write_real (p, len); + break; + case BT_COMPLEX: + write_complex (p, len); + break; + default: + internal_error ("list_formatted_write(): Bad type"); + } + + char_flag = (type == BT_CHARACTER); +} + +void +namelist_write (void) +{ + namelist_info * t1, *t2; + int len,num; + void * p; + + num = 0; + write_character("&",1); + write_character (ioparm.namelist_name, ioparm.namelist_name_len); + write_character("\n",1); + + if (ionml != NULL) + { + t1 = ionml; + while (t1 != NULL) + { + num ++; + t2 = t1; + t1 = t1->next; + write_character(t2->var_name, strlen(t2->var_name)); + write_character("=",1); + len = t2->len; + p = t2->mem_pos; + switch (t2->type) + { + case BT_INTEGER: + write_integer (p, len); + break; + case BT_LOGICAL: + write_logical (p, len); + break; + case BT_CHARACTER: + write_character (p, len); + break; + case BT_REAL: + write_real (p, len); + break; + case BT_COMPLEX: + write_complex (p, len); + break; + default: + internal_error ("Bad type for namelist write"); + } + write_character(",",1); + if (num > 5) + { + num = 0; + write_character("\n",1); + } + } + } + write_character("/",1); + +} + diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h new file mode 100644 index 00000000000..14a217a64f6 --- /dev/null +++ b/libgfortran/libgfortran.h @@ -0,0 +1,400 @@ +/* Common declarations for all of libgfor. + Copyright 2002, 2003 Free Software Foundation, Inc. + Contributed by Paul Brook , and + Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#ifndef LIBGFOR_H +#define LIBGFOR_H + +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327 +#endif + +#include "config.h" + +#if HAVE_COMPLEX_H +# include +#else +#define complex __complex__ +#endif + +#if HAVE_STDINT_H +#include +#endif + +#if HAVE_INTTYPES_H +#include +#endif + +#if HAVE_SYS_TYPES_H +#include +#endif +typedef off_t offset_t; + +#ifndef NULL +#define NULL (void *) 0 +#endif + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +/* For a library, a standard prefix is a requirement in order to + partition the namespace. It's ugly to look at and a pain to type, + so we hide it behind macros. */ +#define prefix(x) _gfortran_ ## x + +/* The only reliable way to get the offset of a field in a struct + in a system independent way is via this macro. */ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) +#endif + +/* TODO: find the C99 version of these an move into above ifdef. */ +#define REALPART(z) (__real__(z)) +#define IMAGPART(z) (__imag__(z)) +#define COMPLEX_ASSIGN(z_, r_, i_) {__real__(z_) = (r_); __imag__(z_) = (i_);} + +typedef int32_t GFC_INTEGER_4; +typedef int64_t GFC_INTEGER_8; +typedef uint32_t GFC_UINTEGER_4; +typedef uint64_t GFC_UINTEGER_8; +typedef GFC_INTEGER_4 GFC_LOGICAL_4; +typedef GFC_INTEGER_8 GFC_LOGICAL_8; +typedef float GFC_REAL_4; +typedef double GFC_REAL_8; +typedef complex float GFC_COMPLEX_4; +typedef complex double GFC_COMPLEX_8; + +typedef size_t index_type; + +/* This will be 0 on little-endian machines and one on big-endian machines. */ +#define l8_to_l4_offset prefix(l8_to_l4_offset) +extern int l8_to_l4_offset; + +#define GFOR_POINTER_L8_TO_L4(p8) \ + (l8_to_l4_offset + (GFC_LOGICAL_4 *)(p8)) + +#define GFC_INTEGER_4_HUGE \ + (GFC_INTEGER_4)((((GFC_UINTEGER_4)1) << 31) - 1) +#define GFC_INTEGER_8_HUGE \ + (GFC_INTEGER_8)((((GFC_UINTEGER_8)1) << 63) - 1) +#define GFC_REAL_4_HUGE FLT_MAX +#define GFC_REAL_8_HUGE DBL_MAX + +#ifndef GFC_MAX_DIMENSIONS +#define GFC_MAX_DIMENSIONS 7 +#endif + +typedef struct descriptor_dimension +{ + index_type stride; + index_type lbound; + index_type ubound; +} +descriptor_dimension; + +#define GFC_ARRAY_DESCRIPTOR(r, type) \ +struct {\ + type *data;\ + type *base;\ + index_type dtype;\ + descriptor_dimension dim[r];\ +} + +/* Commonly used array descriptor types. */ +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, void) gfc_array_void; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, char) gfc_array_char; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_INTEGER_4) gfc_array_i4; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_INTEGER_8) gfc_array_i8; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_REAL_4) gfc_array_r4; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_REAL_8) gfc_array_r8; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_COMPLEX_4) gfc_array_c4; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_COMPLEX_8) gfc_array_c8; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_LOGICAL_4) gfc_array_l4; +typedef GFC_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, GFC_LOGICAL_8) gfc_array_l8; + +#define GFC_DTYPE_RANK_MASK 0x07 +#define GFC_DTYPE_TYPE_SHIFT 3 +#define GFC_DTYPE_TYPE_MASK 0x38 +#define GFC_DTYPE_SIZE_SHIFT 6 + +enum +{ + GFC_DTYPE_UNKNOWN = 0, + GFC_DTYPE_INTEGER, + /* TODO: recognize logical types. */ + GFC_DTYPE_LOGICAL, + GFC_DTYPE_REAL, + GFC_DTYPE_COMPLEX, + GFC_DTYPE_DERIVED, + GFC_DTYPE_CHARACTER +}; + +#define GFC_DESCRIPTOR_RANK(desc) ((desc)->dtype & GFC_DTYPE_RANK_MASK) +#define GFC_DESCRIPTOR_TYPE(desc) (((desc)->dtype & GFC_DTYPE_TYPE_MASK) \ + >> GFC_DTYPE_TYPE_SHIFT) +#define GFC_DESCRIPTOR_SIZE(desc) ((desc)->dtype >> GFC_DTYPE_SIZE_SHIFT) +#define GFC_DESCRIPTOR_DATA(desc) ((desc)->data) +#define GFC_DESCRIPTOR_DTYPE(desc) ((desc)->dtype) + +/* Runtime library include. */ +#define stringize(x) expand_macro(x) +#define expand_macro(x) # x + +/* Runtime options structure. */ + +typedef struct +{ + int stdin_unit, stdout_unit, optional_plus; + int allocate_init_flag, allocate_init_value; + int locus; + + int separator_len; + const char *separator; + + int mem_check; + int use_stderr, all_unbuffered, default_recl; + + int fpu_round, fpu_precision, fpu_invalid, fpu_denormal, fpu_zerodiv, + fpu_overflow, fpu_underflow, fpu_precision_loss; + + int sighup, sigint; +} +options_t; + + +#define options prefix(options) +extern options_t options; + + +/* Structure for statement options. */ + +typedef struct +{ + const char *name; + int value; +} +st_option; + +/* Runtime errors. The EOR and EOF errors are required to be negative. */ + +typedef enum +{ + ERROR_FIRST = -3, /* Marker for the first error. */ + ERROR_EOR = -2, + ERROR_END = -1, + ERROR_OK = 0, /* Indicates success, must be zero. */ + ERROR_OS, /* Operating system error, more info in errno. */ + ERROR_OPTION_CONFLICT, + ERROR_BAD_OPTION, + ERROR_MISSING_OPTION, + ERROR_ALREADY_OPEN, + ERROR_BAD_UNIT, + ERROR_FORMAT, + ERROR_BAD_ACTION, + ERROR_ENDFILE, + ERROR_BAD_US, + ERROR_READ_VALUE, + ERROR_READ_OVERFLOW, + ERROR_LAST /* Not a real error, the last error # + 1. */ +} +error_codes; + + +/* The filename and line number don't go inside the globals structure. + They are set by the rest of the program and must be linked to. */ + +#define line prefix(line) +extern unsigned line; /* Location of the current libray call (optional). */ + +#define filename prefix(filename) +extern char *filename; + + +/* main.c */ + +#define library_start prefix(library_start) +void library_start (void); + +#define library_end prefix(library_end) +void library_end (void); + +#define set_args prefix(set_args) +void set_args (int, char **); + +#define get_args prefix(get_args) +void get_args (int *, char ***); + + +/* error.c */ +#define rtoa prefix(rtoa) +char *rtoa (double f, int length, int oprec); + +#define itoa prefix(itoa) +char *itoa (int64_t); + +#define xtoa prefix(xtoa) +char *xtoa (uint64_t); + +#define os_error prefix(os_error) +void os_error (const char *) __attribute__ ((noreturn)); + +#define show_locus prefix(show_locus) +void show_locus (void); + +#define runtime_error prefix(runtime_error) +void runtime_error (const char *) __attribute__ ((noreturn)); + +#define internal_error prefix(internal_error) +void internal_error (const char *) __attribute__ ((noreturn)); + +#define get_oserror prefix(get_oserror) +const char *get_oserror (void); + +#define write_error prefix(write_error) +void write_error (const char *); + +#define sys_exit prefix(sys_exit) +void sys_exit (int) __attribute__ ((noreturn)); + +#define st_printf prefix(st_printf) +int st_printf (const char *, ...) __attribute__ ((format (printf, 1, 2))); + +#define st_sprintf prefix(st_sprintf) +void st_sprintf (char *, const char *, ...) __attribute__ ((format (printf, 2, 3))); + +#define translate_error prefix(translate_error) +const char *translate_error (int); + +#define generate_error prefix(generate_error) +void generate_error (int, const char *); + + +/* memory.c */ + +#define memory_init prefix(memory_init) +void memory_init (void); + +#define runtime_cleanup prefix(runtime_cleanup) +void runtime_cleanup (void); + +#define get_mem prefix(get_mem) +void *get_mem (size_t) __attribute__ ((malloc)); + +#define free_mem prefix(free_mem) +void free_mem (void *); + +#define internal_malloc_size prefix(internal_malloc_size) +void *internal_malloc_size (size_t); + +#define internal_malloc prefix(internal_malloc) +void *internal_malloc (GFC_INTEGER_4); + +#define internal_malloc64 prefix(internal_malloc64) +void *internal_malloc64 (GFC_INTEGER_8); + +#define internal_free prefix(internal_free) +void internal_free (void *); + +#define allocate prefix(allocate) +void allocate (void **, GFC_INTEGER_4, GFC_INTEGER_4 *); + +#define allocate64 prefix(allocate64) +void allocate64 (void **, GFC_INTEGER_8, GFC_INTEGER_4 *); + +#define deallocate prefix(deallocate) +void deallocate (void **, GFC_INTEGER_4 *); + + +/* environ.c */ + +#define check_buffered prefix(check_buffered) +int check_buffered (int); + +#define init_variables prefix(init_variables) +void init_variables (void); + +#define show_variables prefix(show_variables) +void show_variables (void); + + +/* string.c */ + +#define find_option prefix(find_option) +int find_option (const char *, int, st_option *, const char *); + +#define fstrlen prefix(fstrlen) +int fstrlen (const char *, int); + +#define fstrcpy prefix(fstrcpy) +void fstrcpy (char *, int, const char *, int); + +#define cf_strcpy prefix(cf_strcpy) +void cf_strcpy (char *, int, const char *); + +/* io.c */ + +#define init_units prefix(init_units) +void init_units (void); + +#define close_units prefix(close_units) +void close_units (void); + +/* stop.c */ +#define stop_numeric prefix(stop_numeric) +void stop_numeric (GFC_INTEGER_4); + +/* reshape_packed.c */ +#define reshape_packed prefix(reshape_packed) +void reshape_packed (char *, index_type, const char *, index_type, + const char *, index_type); + +/* Repacking functions. */ +#define internal_pack prefix(internal_pack) +void *internal_pack (gfc_array_char *); + +#define internal_unpack prefix(internal_unpack) +void internal_unpack (gfc_array_char *, const void *); + +#define internal_pack_4 prefix(internal_pack_4) +GFC_INTEGER_4 *internal_pack_4 (gfc_array_i4 *); + +#define internal_pack_8 prefix(internal_pack_8) +GFC_INTEGER_8 *internal_pack_8 (gfc_array_i8 *); + +#define internal_unpack_4 prefix(internal_unpack_4) +void internal_unpack_4 (gfc_array_i4 *, const GFC_INTEGER_4 *); + +#define internal_unpack_8 prefix(internal_unpack_8) +void internal_unpack_8 (gfc_array_i8 *, const GFC_INTEGER_8 *); + +/* string_intrinsics.c */ + +#define compare_string prefix(compare_string) +GFC_INTEGER_4 compare_string (GFC_INTEGER_4, const char *, + GFC_INTEGER_4, const char *); + +#endif + diff --git a/libgfortran/m4/all.m4 b/libgfortran/m4/all.m4 new file mode 100644 index 00000000000..61a45ac345a --- /dev/null +++ b/libgfortran/m4/all.m4 @@ -0,0 +1,37 @@ +`/* Implementation of the ALL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(1, +` /* Return true only if all the elements are set. */ + result = 1;', +` if (! *src) + { + result = 0; + break; + }') + diff --git a/libgfortran/m4/any.m4 b/libgfortran/m4/any.m4 new file mode 100644 index 00000000000..cb79022a9e5 --- /dev/null +++ b/libgfortran/m4/any.m4 @@ -0,0 +1,37 @@ +`/* Implementation of the ANY intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(0, +` result = 0;', +` /* Return true if any of the elements are set. */ + if (*src) + { + result = 1; + break; + }') + diff --git a/libgfortran/m4/cexp.m4 b/libgfortran/m4/cexp.m4 new file mode 100644 index 00000000000..1d22b089a92 --- /dev/null +++ b/libgfortran/m4/cexp.m4 @@ -0,0 +1,140 @@ +`/* Complex exponential functions + Copyright 2002, 2004 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h"' + +include(`mtype.m4')dnl + +/* z = a + ib */ +/* Absolute value. */ +real_type +cabs`'q (complex_type z) +{ + return hypot`'q (REALPART (z), IMAGPART (z)); +} + +/* Complex argument. The angle made with the +ve real axis. Range 0-2pi. */ +real_type +carg`'q (complex_type z) +{ + real_type arg; + + arg = atan2`'q (IMAGPART (z), REALPART (z)); + if (arg < 0) + return arg + 2 * M_PI; + else + return arg; +} + +/* exp(z) = exp(a)*(cos(b) + isin(b)) */ +complex_type +cexp`'q (complex_type z) +{ + real_type a; + real_type b; + complex_type v; + + a = REALPART (z); + b = IMAGPART (z); + COMPLEX_ASSIGN (v, cos`'q (b), sin`'q (b)); + return exp`'q (a) * v; +} + +/* log(z) = log (cabs(z)) + i*carg(z) */ +complex_type +clog`'q (complex_type z) +{ + complex_type v; + + COMPLEX_ASSIGN (v, log`'q (cabs`'q (z)), carg`'q (z)); + return v; +} + +/* log10(z) = log10 (cabs(z)) + i*carg(z) */ +complex_type +clog10`'q (complex_type z) +{ + complex_type v; + + COMPLEX_ASSIGN (v, log10`'q (cabs`'q (z)), carg`'q (z)); + return v; +} + +/* pow(base, power) = cexp (power * clog (base)) */ +complex_type +cpow`'q (complex_type base, complex_type power) +{ + return cexp`'q (power * clog`'q (base)); +} + +/* sqrt(z). Algorithm pulled from glibc. */ +complex_type +csqrt`'q (complex_type z) +{ + real_type re; + real_type im; + complex_type v; + + re = REALPART (z); + im = IMAGPART (z); + if (im == 0.0) + { + if (re < 0.0) + { + COMPLEX_ASSIGN (v, 0.0, copysign`'q (sqrt`'q (-re), im)); + } + else + { + COMPLEX_ASSIGN (v, fabs`'q (sqrt (re)), + copysign`'q (0.0, im)); + } + } + else if (re == 0.0) + { + real_type r; + + r = sqrt`'q (0.5 * fabs (im)); + + COMPLEX_ASSIGN (v, copysign`'q (r, im), r); + } + else + { + real_type d, r, s; + + d = hypot`'q (re, im); + /* Use the identity 2 Re res Im res = Im x + to avoid cancellation error in d +/- Re x. */ + if (re > 0) + { + r = sqrt`'q (0.5 * d + 0.5 * re); + s = (0.5 * im) / r; + } + else + { + s = sqrt`'q (0.5 * d - 0.5 * re); + r = fabs`'q ((0.5 * im) / s); + } + + COMPLEX_ASSIGN (v, r, copysign`'q (s, im)); + } + return v; +} + diff --git a/libgfortran/m4/chyp.m4 b/libgfortran/m4/chyp.m4 new file mode 100644 index 00000000000..f6ee972ea52 --- /dev/null +++ b/libgfortran/m4/chyp.m4 @@ -0,0 +1,72 @@ +`/* Complex hyperbolic functions + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h"' + +include(`mtype.m4')dnl + +/* Complex number z = a + ib. */ + +/* sinh(z) = sinh(a)cos(b) + icosh(a)sin(b) */ +complex_type +csinh`'q (complex_type a) +{ + real_type r; + real_type i; + complex_type v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, sinh`'q (r) * cos`'q (i), cosh`'q (r) * sin`'q (i)); + return v; +} + +/* cosh(z) = cosh(a)cos(b) - isinh(a)sin(b) */ +complex_type +ccosh`'q (complex_type a) +{ + real_type r; + real_type i; + complex_type v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, cosh`'q (r) * cos`'q (i), - (sinh`'q (r) * sin`'q (i))); + return v; +} + +/* tanh(z) = (tanh(a) + itan(b)) / (1 - itanh(a)tan(b)) */ +complex_type +ctanh`'q (complex_type a) +{ + real_type rt; + real_type it; + complex_type n; + complex_type d; + + rt = tanh`'q (REALPART (a)); + it = tan`'q (IMAGPART (a)); + COMPLEX_ASSIGN (n, rt, it); + COMPLEX_ASSIGN (d, 1, - (rt * it)); + + return n / d; +} + diff --git a/libgfortran/m4/count.m4 b/libgfortran/m4/count.m4 new file mode 100644 index 00000000000..a5ea4735a9d --- /dev/null +++ b/libgfortran/m4/count.m4 @@ -0,0 +1,33 @@ +`/* Implementation of the COUNT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(0, +` result = 0;', +` if (*src) + result++;') + diff --git a/libgfortran/m4/cshift1.m4 b/libgfortran/m4/cshift1.m4 new file mode 100644 index 00000000000..382537b7029 --- /dev/null +++ b/libgfortran/m4/cshift1.m4 @@ -0,0 +1,175 @@ +`/* Implementation of the CSHIFT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Feng Wang + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(htype_kind, regexp(file, `_\([0-9]+\)\.', `\1'))dnl +define(htype_code,`i'rtype_name)dnl +define(htype,get_arraytype(i,htype_kind))dnl +define(htype_name, get_typename(i,htype_kind))dnl + +void +`__cshift1_'htype_kind (const gfc_array_char * ret, const gfc_array_char * array, + const htype * h, const htype_name * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; +` /* h.* indicates the shift array. */' + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const htype_name *hptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + htype_name sh; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + if (which < 0 || (which + 1) > GFC_DESCRIPTOR_RANK (array)) + runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'"); + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + +`/* Initialized for avoiding compiler warnings. */' + roffset = size; + soffset = size; + len = 0; + + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + + while (rptr) + { +` /* Do the shift for this dimension. */' + sh = *hptr; + sh = (div (sh, len)).rem; + if (sh < 0) + sh += len; + + src = &sptr[sh * soffset]; + dest = rptr; + + for (n = 0; n < len; n++) + { + memcpy (dest, src, size); + dest += roffset; + if (n == len - sh - 1) + src = sptr; + else + src += soffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + } + } + } +} + diff --git a/libgfortran/m4/ctrig.m4 b/libgfortran/m4/ctrig.m4 new file mode 100644 index 00000000000..d35e4500934 --- /dev/null +++ b/libgfortran/m4/ctrig.m4 @@ -0,0 +1,72 @@ +`/* Complex trig functions + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h"' + +include(`mtype.m4')dnl + +/* Complex number z = a + ib. */ + +/* sin(z) = sin(a)cosh(b) + icos(a)sinh(b) */ +complex_type +csin`'q (complex_type a) +{ + real_type r; + real_type i; + complex_type v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, sin`'q (r) * cosh`'q (i), cos`'q (r) * sinh`'q (i)); + return v; +} + +/* cos(z) = cos(a)cosh(b) - isin(a)sinh(b) */ +complex_type +ccos`'q (complex_type a) +{ + real_type r; + real_type i; + complex_type v; + + r = REALPART (a); + i = IMAGPART (a); + COMPLEX_ASSIGN (v, cos`'q (r) * cosh`'q (i), - (sin`'q (r) * sinh`'q (i))); + return v; +} + +/* tan(z) = (tan(a) + itanh(b)) / (1 - itan(a)tanh(b)) */ +complex_type +ctan`'q (complex_type a) +{ + real_type rt; + real_type it; + complex_type n; + complex_type d; + + rt = tan`'q (REALPART (a)); + it = tanh`'q (IMAGPART (a)); + COMPLEX_ASSIGN (n, rt, it); + COMPLEX_ASSIGN (d , 1, - (rt * it)); + + return n / d; +} + diff --git a/libgfortran/m4/dotprod.m4 b/libgfortran/m4/dotprod.m4 new file mode 100644 index 00000000000..051475f6c00 --- /dev/null +++ b/libgfortran/m4/dotprod.m4 @@ -0,0 +1,71 @@ +`/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_code, regexp(file, `_\([ir][0-9]+\)\.', `\1'))dnl +define(rtype_letter,substr(rtype_code, 0, 1))dnl +define(rtype_kind, substr(rtype_code, 1))dnl +define(rtype,get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_name, get_typename(rtype_letter, rtype_kind))dnl + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +rtype_name +`__dot_product_'rtype_code (rtype * a, rtype * b) +{ + rtype_name *pa; + rtype_name *pb; + rtype_name res; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; +sinclude(`dotprod_asm_'rtype_code`.m4')dnl + + while (count--) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/m4/dotprodc.m4 b/libgfortran/m4/dotprodc.m4 new file mode 100644 index 00000000000..0e77c0abfed --- /dev/null +++ b/libgfortran/m4/dotprodc.m4 @@ -0,0 +1,74 @@ +`/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + and Feng Wang + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_code, regexp(file, `_\(c[0-9]+\)\.', `\1'))dnl +define(rtype_letter,substr(rtype_code, 0, 1))dnl +define(rtype_kind, substr(rtype_code, 1))dnl +define(rtype,get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_name, get_typename(rtype_letter, rtype_kind))dnl + +typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) char_array; + +/* Both parameters will already have been converted to the result type. */ +rtype_name +`__dot_product_'rtype_code (rtype * a, rtype * b) +{ + rtype_name *pa; + rtype_name *pb; + rtype_name res; + rtype_name conjga; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + res = 0; + pa = a->data; + pb = b->data; +sinclude(`dotprod_asm_'rtype_code`.m4')dnl + + while (count--) + { + COMPLEX_ASSIGN(conjga, REALPART (*pa), -IMAGPART (*pa)); + res += conjga * *pb; + pa += astride; + pb += bstride; + } + + return res; +} + diff --git a/libgfortran/m4/dotprodl.m4 b/libgfortran/m4/dotprodl.m4 new file mode 100644 index 00000000000..7cbe6000471 --- /dev/null +++ b/libgfortran/m4/dotprodl.m4 @@ -0,0 +1,79 @@ +`/* Implementation of the DOT_PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_kind, regexp(file, `_l\([0-9]+\)\.', `\1'))dnl +define(rtype_code,`l'rtype_kind)dnl +define(rtype,get_arraytype(l,rtype_kind))dnl +define(rtype_name, get_typename(l, rtype_kind))dnl + +rtype_name +`__dot_product_'rtype_code (gfc_array_l4 * a, gfc_array_l4 * b) +{ + GFC_LOGICAL_4 *pa; + GFC_LOGICAL_4 *pb; + index_type count; + index_type astride; + index_type bstride; + + assert (GFC_DESCRIPTOR_RANK (a) == 1 + && GFC_DESCRIPTOR_RANK (b) == 1); + + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + + astride = a->dim[0].stride; + bstride = b->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + + pa = a->data; + if (GFC_DESCRIPTOR_SIZE (a) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (a) == 8); + pa = GFOR_POINTER_L8_TO_L4 (pa); + astride <<= 1; + } + pb = b->data; + if (GFC_DESCRIPTOR_SIZE (b) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (b) == 8); + pb = GFOR_POINTER_L8_TO_L4 (pb); + bstride <<= 1; + } + + while (count--) + { + if (*pa && *pb) + return 1; + + pa += astride; + pb += bstride; + } + + return 0; +} + diff --git a/libgfortran/m4/eoshift1.m4 b/libgfortran/m4/eoshift1.m4 new file mode 100644 index 00000000000..304d0038578 --- /dev/null +++ b/libgfortran/m4/eoshift1.m4 @@ -0,0 +1,183 @@ +`/* Implementation of the EOSHIFT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(htype_kind, regexp(file, `_\([0-9]+\)\.', `\1'))dnl +define(htype_code,`i'rtype_name)dnl +define(htype,get_arraytype(i,htype_kind))dnl +define(htype_name, get_typename(i,htype_kind))dnl + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +void +`__eoshift1_'htype_kind (const gfc_array_char * ret, const gfc_array_char * array, + const htype * h, const char * pbound, const htype_name * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; +` /* h.* indicates the shift array. */' + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const htype_name *hptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + htype_name sh; + htype_name delta; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + if (!pbound) + pbound = zeros; + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + + while (rptr) + { +` /* Do the shift for this dimension. */' + sh = *hptr; + delta = (sh >= 0) ? sh: -sh; + if (sh > 0) + { + src = &sptr[delta * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[delta * roffset]; + } + for (n = 0; n < len - delta; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (sh < 0) + dest = rptr; + n = delta; + + while (n--) + { + memcpy (dest, pbound, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + } + } + } +} + diff --git a/libgfortran/m4/eoshift3.m4 b/libgfortran/m4/eoshift3.m4 new file mode 100644 index 00000000000..b86a80c41ca --- /dev/null +++ b/libgfortran/m4/eoshift3.m4 @@ -0,0 +1,198 @@ +`/* Implementation of the EOSHIFT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(htype_kind, regexp(file, `_\([0-9]+\)\.', `\1'))dnl +define(htype_code,`i'rtype_name)dnl +define(htype,get_arraytype(i,htype_kind))dnl +define(htype_name, get_typename(i,htype_kind))dnl + +static const char zeros[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +void +`__eoshift3_'htype_kind (gfc_array_char * ret, gfc_array_char * array, + htype * h, const gfc_array_char * bound, htype_name * pwhich) +{ + /* r.* indicates the return array. */ + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type roffset; + char *rptr; + char *dest; + /* s.* indicates the source array. */ + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type soffset; + const char *sptr; + const char *src; +` /* h.* indicates the shift array. */' + index_type hstride[GFC_MAX_DIMENSIONS - 1]; + index_type hstride0; + const htype_name *hptr; + /* b.* indicates the bound array. */ + index_type bstride[GFC_MAX_DIMENSIONS - 1]; + index_type bstride0; + const char *bptr; + + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type dim; + index_type size; + index_type len; + index_type n; + int which; + htype_name sh; + htype_name delta; + + if (pwhich) + which = *pwhich - 1; + else + which = 0; + + size = GFC_DESCRIPTOR_SIZE (ret); + + extent[0] = 1; + count[0] = 0; + size = GFC_DESCRIPTOR_SIZE (array); + n = 0; + for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) + { + if (dim == which) + { + roffset = ret->dim[dim].stride * size; + if (roffset == 0) + roffset = size; + soffset = array->dim[dim].stride * size; + if (soffset == 0) + soffset = size; + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + } + else + { + count[n] = 0; + extent[n] = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + rstride[n] = ret->dim[dim].stride * size; + sstride[n] = array->dim[dim].stride * size; + + hstride[n] = h->dim[n].stride; + if (bound) + bstride[n] = bound->dim[n].stride; + else + bstride[n] = 0; + n++; + } + } + if (sstride[0] == 0) + sstride[0] = size; + if (rstride[0] == 0) + rstride[0] = size; + if (hstride[0] == 0) + hstride[0] = 1; + if (bound && bstride[0] == 0) + bstride[0] = size; + + dim = GFC_DESCRIPTOR_RANK (array); + rstride0 = rstride[0]; + sstride0 = sstride[0]; + hstride0 = hstride[0]; + bstride0 = bstride[0]; + rptr = ret->data; + sptr = array->data; + hptr = h->data; + if (bound) + bptr = bound->data; + else + bptr = zeros; + + while (rptr) + { +` /* Do the shift for this dimension. */' + sh = *hptr; + delta = (sh >= 0) ? sh: -sh; + if (sh > 0) + { + src = &sptr[delta * soffset]; + dest = rptr; + } + else + { + src = sptr; + dest = &rptr[delta * roffset]; + } + for (n = 0; n < len - delta; n++) + { + memcpy (dest, src, size); + dest += roffset; + src += soffset; + } + if (sh < 0) + dest = rptr; + n = delta; + + while (n--) + { + memcpy (dest, bptr, size); + dest += roffset; + } + + /* Advance to the next section. */ + rptr += rstride0; + sptr += sstride0; + hptr += hstride0; + bptr += bstride0; + count[0]++; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * extent[n]; + sptr -= sstride[n] * extent[n]; + hptr -= hstride[n] * extent[n]; + bptr -= bstride[n] * extent[n]; + n++; + if (n >= dim - 1) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + count[n]++; + rptr += rstride[n]; + sptr += sstride[n]; + hptr += hstride[n]; + bptr += bstride[n]; + } + } + } +} + diff --git a/libgfortran/m4/exponent.m4 b/libgfortran/m4/exponent.m4 new file mode 100644 index 00000000000..510f763292d --- /dev/null +++ b/libgfortran/m4/exponent.m4 @@ -0,0 +1,32 @@ +`/* Implementation of the EXPONENT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h"' + +include(`mtype.m4')dnl + +GFC_INTEGER_4 +prefix(exponent_r`'kind) (real_type s) +{ + int ret; + frexp`'q (s, &ret); + return ret; +} diff --git a/libgfortran/m4/fraction.m4 b/libgfortran/m4/fraction.m4 new file mode 100644 index 00000000000..c453e78ac41 --- /dev/null +++ b/libgfortran/m4/fraction.m4 @@ -0,0 +1,31 @@ +`/* Implementation of the FRACTION intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h"' + +include(`mtype.m4')dnl + +real_type +prefix(fraction_r`'kind) (real_type s) +{ + int dummy_exp; + return frexp`'q (s, &dummy_exp); +} diff --git a/libgfortran/m4/head.m4 b/libgfortran/m4/head.m4 new file mode 100644 index 00000000000..0b2f9eeaa63 --- /dev/null +++ b/libgfortran/m4/head.m4 @@ -0,0 +1,21 @@ +`! Copyright 2002 Free Software Foundation, Inc. +! Contributed by Paul Brook +! +!This file is part of the GNU Fortran 95 runtime library (libgfor). +! +!GNU libgfor is free software; you can redistribute it and/or +!modify it under the terms of the GNU Lesser General Public +!License as published by the Free Software Foundation; either +!version 2.1 of the License, or (at your option) any later version. +! +!GNU libgfor is distributed in the hope that it will be useful, +!but WITHOUT ANY WARRANTY; without even the implied warranty of +!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +!GNU Lesser General Public License for more details. +! +!You should have received a copy of the GNU Lesser General Public +!License along with libgfor; see the file COPYING. If not, +!write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +!Boston, MA 02111-1307, USA. +! +!This file is machine generated.' diff --git a/libgfortran/m4/iforeach.m4 b/libgfortran/m4/iforeach.m4 new file mode 100644 index 00000000000..2397036ba72 --- /dev/null +++ b/libgfortran/m4/iforeach.m4 @@ -0,0 +1,196 @@ +dnl Support macro file for intrinsic functions. +dnl Contains the generic sections of the array functions. +dnl This file is part of the GNU Fortran 95 Runtime Library (libgfortran) +dnl Distributed under the GNU LGPL. See COPYING for details. +define(START_FOREACH_FUNCTION, +`void +`__'name`'rtype_qual`_'type_code (rtype * retarray, atype *array) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + type_name *base; + rtype_name *dest; + index_type rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { +')dnl +define(START_FOREACH_BLOCK, +` while (base) + { + { + /* Implementation start. */ +')dnl +define(FINISH_FOREACH_FUNCTION, +` /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + } + } + } + } +}')dnl +define(START_MASKED_FOREACH_FUNCTION, +`void +`__m'name`'rtype_qual`_'type_code (rtype * retarray, atype *array, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS]; + index_type extent[GFC_MAX_DIMENSIONS]; + index_type sstride[GFC_MAX_DIMENSIONS]; + index_type mstride[GFC_MAX_DIMENSIONS]; + index_type dstride; + rtype_name *dest; + type_name *base; + GFC_LOGICAL_4 *mbase; + int rank; + index_type n; + + rank = GFC_DESCRIPTOR_RANK (array); + assert (rank > 0); + assert (GFC_DESCRIPTOR_RANK (retarray) == 1); + assert (retarray->dim[0].ubound + 1 - retarray->dim[0].lbound == rank); + assert (GFC_DESCRIPTOR_RANK (mask) == rank); + + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + dstride = retarray->dim[0].stride; + dest = retarray->data; + for (n = 0; n < rank; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + count[n] = 0; + if (extent[n] <= 0) + { + /* Set the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 0; + return; + } + } + + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + + /* Initialize the return value. */ + for (n = 0; n < rank; n++) + dest[n * dstride] = 1; + { +')dnl +define(START_MASKED_FOREACH_BLOCK, `START_FOREACH_BLOCK')dnl +define(FINISH_MASKED_FOREACH_FUNCTION, +` /* Implementation end. */ + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the loop. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + } + } + } + } +}')dnl +define(FOREACH_FUNCTION, +`START_FOREACH_FUNCTION +$1 +START_FOREACH_BLOCK +$2 +FINISH_FOREACH_FUNCTION')dnl +define(MASKED_FOREACH_FUNCTION, +`START_MASKED_FOREACH_FUNCTION +$1 +START_MASKED_FOREACH_BLOCK +$2 +FINISH_MASKED_FOREACH_FUNCTION')dnl diff --git a/libgfortran/m4/ifunction.m4 b/libgfortran/m4/ifunction.m4 new file mode 100644 index 00000000000..95445846185 --- /dev/null +++ b/libgfortran/m4/ifunction.m4 @@ -0,0 +1,256 @@ +dnl Support macro file for intrinsic functions. +dnl Contains the generic sections of the array functions. +dnl This file is part of the GNU Fortran 95 Runtime Library (libgfortran) +dnl Distributed under the GNU LGPL. See COPYING for details. +dnl +dnl Pass the implementation for a single section as the parameter to +dnl {MASK_}ARRAY_FUNCTION. +dnl The variables base, delta, and len describe the input section. +dnl For masked section the mask is described by mbase and mdelta. +dnl These should not be modified. The result should be stored in *dest. +dnl The names count, extent, sstride, dstride, base, dest, rank, dim +dnl retarray, array, pdim and mstride should not be used. +dnl The variable n is declared as index_type and may be used. +dnl Other variable declarations may be placed at the start of the code, +dnl The types of the array parameter and the return value are +dnl type_name and rtype_name respectively. +dnl Execution should be allowed to continue to the end of the block. +dnl You should not return or break from the inner loop of the implementation. +dnl Care should also be taken to avoid using the names defined in iparm.m4 +define(START_ARRAY_FUNCTION, +`void +`__'name`'rtype_qual`_'type_code (rtype * retarray, atype *array, index_type *pdim) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + type_name *base; + rtype_name *dest; + index_type rank; + index_type n; + index_type len; + index_type delta; + index_type dim; + + /* Make dim zero based to avoid confusion. */ + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + delta = array->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + len = 0; + } + + base = array->data; + dest = retarray->data; + + while (base) + { + type_name *src; + rtype_name result; + src = base; + { +')dnl +define(START_ARRAY_BLOCK, +` if (len <= 0) + *dest = '$1`; + else + { + for (n = 0; n < len; n++, src += delta) + { +')dnl +define(FINISH_ARRAY_FUNCTION, + ` } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + dest += dstride[n]; + } + } + } +}')dnl +define(START_MASKED_ARRAY_FUNCTION, +`void +`__m'name`'rtype_qual`_'type_code (rtype * retarray, atype * array, index_type *pdim, gfc_array_l4 * mask) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type dstride[GFC_MAX_DIMENSIONS - 1]; + index_type mstride[GFC_MAX_DIMENSIONS - 1]; + rtype_name *dest; + type_name *base; + GFC_LOGICAL_4 *mbase; + int rank; + int dim; + index_type n; + index_type len; + index_type delta; + index_type mdelta; + + dim = (*pdim) - 1; + rank = GFC_DESCRIPTOR_RANK (array) - 1; + assert (rank == GFC_DESCRIPTOR_RANK (retarray)); + if (array->dim[0].stride == 0) + array->dim[0].stride = 1; + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + + len = array->dim[dim].ubound + 1 - array->dim[dim].lbound; + if (len <= 0) + return; + delta = array->dim[dim].stride; + mdelta = mask->dim[dim].stride; + + for (n = 0; n < dim; n++) + { + sstride[n] = array->dim[n].stride; + mstride[n] = mask->dim[n].stride; + extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound; + } + for (n = dim; n < rank; n++) + { + sstride[n] = array->dim[n + 1].stride; + mstride[n] = mask->dim[n + 1].stride; + extent[n] = + array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound; + } + + for (n = 0; n < rank; n++) + { + count[n] = 0; + dstride[n] = retarray->dim[n].stride; + if (extent[n] <= 0) + return; + } + + dest = retarray->data; + base = array->data; + mbase = mask->data; + + if (GFC_DESCRIPTOR_SIZE (mask) != 4) + { + /* This allows the same loop to be used for all logical types. */ + assert (GFC_DESCRIPTOR_SIZE (mask) == 8); + for (n = 0; n < rank; n++) + mstride[n] <<= 1; + mdelta <<= 1; + mbase = (GFOR_POINTER_L8_TO_L4 (mbase)); + } + + while (base) + { + type_name *src; + GFC_LOGICAL_4 *msrc; + rtype_name result; + src = base; + msrc = mbase; + { +')dnl +define(START_MASKED_ARRAY_BLOCK, +` if (len <= 0) + *dest = '$1`; + else + { + for (n = 0; n < len; n++, src += delta, msrc += mdelta) + { +')dnl +define(FINISH_MASKED_ARRAY_FUNCTION, +` } + *dest = result; + } + } + /* Advance to the next element. */ + count[0]++; + base += sstride[0]; + mbase += mstride[0]; + dest += dstride[0]; + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + base -= sstride[n] * extent[n]; + mbase -= mstride[n] * extent[n]; + dest -= dstride[n] * extent[n]; + n++; + if (n == rank) + { + /* Break out of the look. */ + base = NULL; + break; + } + else + { + count[n]++; + base += sstride[n]; + mbase += mstride[n]; + dest += dstride[n]; + } + } + } +}')dnl +define(ARRAY_FUNCTION, +`START_ARRAY_FUNCTION +$2 +START_ARRAY_BLOCK($1) +$3 +FINISH_ARRAY_FUNCTION')dnl +define(MASKED_ARRAY_FUNCTION, +`START_MASKED_ARRAY_FUNCTION +$2 +START_MASKED_ARRAY_BLOCK($1) +$3 +FINISH_MASKED_ARRAY_FUNCTION')dnl diff --git a/libgfortran/m4/in_pack.m4 b/libgfortran/m4/in_pack.m4 new file mode 100644 index 00000000000..4998ed5f2db --- /dev/null +++ b/libgfortran/m4/in_pack.m4 @@ -0,0 +1,122 @@ +`/* Helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfortran; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_kind, regexp(file, `_.\([0-9]+\)\.', `\1'))dnl +define(rtype_letter, regexp(file, `_\(.\)[0-9]+\.', `\1'))dnl +define(rtype_code,rtype_letter`'rtype_name)dnl +define(rtype,get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_name, get_typename(rtype_letter, rtype_kind))dnl + + +/* Allocates a block of memory with internal_malloc if the array needs + repacking. */ + +dnl Only the kind (ie size) is used to name the function. +rtype_name * +`internal_pack_'rtype_kind (rtype * source) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type ssize; + const rtype_name *src; + rtype_name *dest; + rtype_name *destptr; + int n; + int packed; + + if (source->dim[0].stride == 0) + { + source->dim[0].stride = 1; + return source->data; + } + + dim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + packed = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = source->dim[n].stride; + extent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (extent[n] <= 0) + { + /* Do nothing. */ + packed = 1; + break; + } + + if (ssize != stride[n]) + packed = 0; + + ssize *= extent[n]; + } + + if (packed) + return source->data; + + /* Allocate storage for the destination. */ + destptr = (rtype_name *)internal_malloc_size (ssize * rtype_kind); + dest = destptr; + src = source->data; + stride0 = stride[0]; + + + while (src) + { + /* Copy the data. */ + *(dest++) = *src; + /* Advance to the next element. */ + src += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= stride[n] * extent[n]; + n++; + if (n == dim) + { + src = NULL; + break; + } + else + { + count[n]++; + src += stride[n]; + } + } + } + return destptr; +} + diff --git a/libgfortran/m4/in_unpack.m4 b/libgfortran/m4/in_unpack.m4 new file mode 100644 index 00000000000..fe344ca7d31 --- /dev/null +++ b/libgfortran/m4/in_unpack.m4 @@ -0,0 +1,109 @@ +`/* Helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_kind, regexp(file, `_.\([0-9]+\)\.', `\1'))dnl +define(rtype_letter, regexp(file, `_\(.\)[0-9]+\.', `\1'))dnl +define(rtype_code,rtype_letter`'rtype_name)dnl +define(rtype,get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_name, get_typename(rtype_letter, rtype_kind))dnl + +dnl Only the kind (ie size) is used to name the function. +void +`internal_unpack_'rtype_kind (rtype * d, const rtype_name * src) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type dsize; + rtype_name *dest; + int n; + + dest = d->data; + if (src == dest || !src) + return; + + if (d->dim[0].stride == 0) + d->dim[0].stride = 1; + + dim = GFC_DESCRIPTOR_RANK (d); + dsize = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = d->dim[n].stride; + extent[n] = d->dim[n].ubound + 1 - d->dim[n].lbound; + if (extent[n] <= 0) + abort (); + + if (dsize == stride[n]) + dsize *= extent[n]; + else + dsize = 0; + } + + if (dsize != 0) + { + memcpy (dest, src, dsize * rtype_kind); + return; + } + + stride0 = stride[0]; + + while (dest) + { + /* Copy the data. */ + *dest = *(src++); + /* Advance to the next element. */ + dest += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + dest -= stride[n] * extent[n]; + n++; + if (n == dim) + { + dest = NULL; + break; + } + else + { + count[n]++; + dest += stride[n]; + } + } + } +} + diff --git a/libgfortran/m4/iparm.m4 b/libgfortran/m4/iparm.m4 new file mode 100644 index 00000000000..6cbd7b247a8 --- /dev/null +++ b/libgfortran/m4/iparm.m4 @@ -0,0 +1,26 @@ +dnl Support macro file for intrinsic functions. +dnl Works out all the function types from the filename. +dnl This file is part of the GNU Fortran 95 Runtime Library (libgfortran) +dnl Distributed under the GNU LGPL. See COPYING for details. +dnl M4 macro file to get type names from filenames +include(`types.m4') +define(type_letter, regexp(file, `_\([irlc]\)[^_]*$', \1))dnl +define(type_kind, regexp(file, `_[irlc]\([0-9]*\)[^_]*$', \1))dnl +define(rtype_kind, regexp(file, `_\([0-9]*\)_[irlc][0-9]*[^_]*$', `\1'))dnl +define(type_code, type_letter`'type_kind)dnl +define(type_name, get_typename(type_letter,type_kind))dnl +define(atype, get_arraytype(type_letter,type_kind))dnl +ifelse(rtype_kind,, +`define(rtype_letter,type_letter)dnl +define(rtype_name, type_name)dnl +define(rtype_code, type_code)dnl +define(rtype, atype)dnl +define(rtype_qual,`')dnl +', +`define(rtype_letter,i)dnl +define(rtype_name, get_typename(rtype_letter,rtype_kind))dnl +define(rtype, get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_qual,`_'rtype_kind)dnl +')dnl +define(type_max, type_name`_HUGE')dnl +define(type_min, `-'type_max)dnl diff --git a/libgfortran/m4/matmul.m4 b/libgfortran/m4/matmul.m4 new file mode 100644 index 00000000000..fcf63a6504e --- /dev/null +++ b/libgfortran/m4/matmul.m4 @@ -0,0 +1,145 @@ +`/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_code, regexp(file, `_\([irc][0-9]+\)\.', `\1'))dnl +define(rtype_letter,substr(rtype_code, 0, 1))dnl +define(rtype_kind, substr(rtype_code, 1))dnl +define(rtype,get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_name, get_typename(rtype_letter, rtype_kind))dnl + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +`__matmul_'rtype_code (rtype * retarray, rtype * a, rtype * b) +{ + rtype_name *abase; + rtype_name *bbase; + rtype_name *dest; + rtype_name res; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + rtype_name *pa; + rtype_name *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + bbase = b->data; + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + +sinclude(`matmul_asm_'rtype_code`.m4')dnl + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + res = 0; + + for (n = 0; n < count; n++) + { + res += *pa * *pb; + pa += astride; + pb += bstride; + } + + *dest = res; + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/m4/matmull.m4 b/libgfortran/m4/matmull.m4 new file mode 100644 index 00000000000..e522a93faef --- /dev/null +++ b/libgfortran/m4/matmull.m4 @@ -0,0 +1,157 @@ +`/* Implementation of the MATMUL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_kind, regexp(file, `_l\([0-9]+\)\.', `\1'))dnl +define(rtype_code,`l'rtype_kind)dnl +define(rtype,get_arraytype(l,rtype_kind))dnl +define(rtype_name, get_typename(l, rtype_kind))dnl + +/* Dimensions: retarray(x,y) a(x, count) b(count,y). + Either a or b can be rank 1. In this case x or y is 1. */ +void +`__matmul_'rtype_code (rtype * retarray, gfc_array_l4 * a, gfc_array_l4 * b) +{ + GFC_INTEGER_4 *abase; + GFC_INTEGER_4 *bbase; + rtype_name *dest; + index_type rxstride; + index_type rystride; + index_type xcount; + index_type ycount; + index_type xstride; + index_type ystride; + index_type x; + index_type y; + + GFC_INTEGER_4 *pa; + GFC_INTEGER_4 *pb; + index_type astride; + index_type bstride; + index_type count; + index_type n; + + assert (GFC_DESCRIPTOR_RANK (a) == 2 + || GFC_DESCRIPTOR_RANK (b) == 2); + abase = a->data; + if (GFC_DESCRIPTOR_SIZE (a) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (a) == 8); + abase = GFOR_POINTER_L8_TO_L4 (abase); + astride <<= 1; + } + bbase = b->data; + if (GFC_DESCRIPTOR_SIZE (b) != 4) + { + assert (GFC_DESCRIPTOR_SIZE (b) == 8); + bbase = GFOR_POINTER_L8_TO_L4 (bbase); + bstride <<= 1; + } + dest = retarray->data; + + if (retarray->dim[0].stride == 0) + retarray->dim[0].stride = 1; + if (a->dim[0].stride == 0) + a->dim[0].stride = 1; + if (b->dim[0].stride == 0) + b->dim[0].stride = 1; + +sinclude(`matmul_asm_'rtype_code`.m4')dnl + + if (GFC_DESCRIPTOR_RANK (retarray) == 1) + { + rxstride = retarray->dim[0].stride; + rystride = rxstride; + } + else + { + rxstride = retarray->dim[0].stride; + rystride = retarray->dim[1].stride; + } + + /* If we have rank 1 parameters, zero the absent stride, and set the size to + one. */ + if (GFC_DESCRIPTOR_RANK (a) == 1) + { + astride = a->dim[0].stride; + count = a->dim[0].ubound + 1 - a->dim[0].lbound; + xstride = 0; + rxstride = 0; + xcount = 1; + } + else + { + astride = a->dim[1].stride; + count = a->dim[1].ubound + 1 - a->dim[1].lbound; + xstride = a->dim[0].stride; + xcount = a->dim[0].ubound + 1 - a->dim[0].lbound; + } + if (GFC_DESCRIPTOR_RANK (b) == 1) + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = 0; + rystride = 0; + ycount = 1; + } + else + { + bstride = b->dim[0].stride; + assert(count == b->dim[0].ubound + 1 - b->dim[0].lbound); + ystride = b->dim[1].stride; + ycount = b->dim[1].ubound + 1 - b->dim[1].lbound; + } + + for (y = 0; y < ycount; y++) + { + for (x = 0; x < xcount; x++) + { + /* Do the summation for this element. For real and integer types + this is the same as DOT_PRODUCT. For complex types we use do + a*b, not conjg(a)*b. */ + pa = abase; + pb = bbase; + *dest = 0; + + for (n = 0; n < count; n++) + { + if (*pa && *pb) + { + *dest = 1; + break; + } + pa += astride; + pb += bstride; + } + + dest += rxstride; + abase += xstride; + } + abase -= xstride * xcount; + bbase += ystride; + dest += rystride - (rxstride * xcount); + } +} + diff --git a/libgfortran/m4/maxloc0.m4 b/libgfortran/m4/maxloc0.m4 new file mode 100644 index 00000000000..89ecacb9656 --- /dev/null +++ b/libgfortran/m4/maxloc0.m4 @@ -0,0 +1,54 @@ +`/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(iforeach.m4)dnl + +FOREACH_FUNCTION( +` type_name maxval; + + maxval = type_min;' +, +` if (*base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + }') + +MASKED_FOREACH_FUNCTION( +` type_name maxval; + + maxval = type_min;' +, +` if (*mbase && *base > maxval) + { + maxval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + }') diff --git a/libgfortran/m4/maxloc1.m4 b/libgfortran/m4/maxloc1.m4 new file mode 100644 index 00000000000..0eb259f9c6d --- /dev/null +++ b/libgfortran/m4/maxloc1.m4 @@ -0,0 +1,50 @@ +`/* Implementation of the MAXLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(0, +` type_name maxval; + maxval = type_min; + result = 1;', +` if (*src > maxval) + { + maxval = *src; + result = (rtype_name)n + 1; + }') + +MASKED_ARRAY_FUNCTION(0, +` type_name maxval; + maxval = type_min; + result = 1;', +` if (*msrc && *src > maxval) + { + maxval = *src; + result = (rtype_name)n + 1; + }') + diff --git a/libgfortran/m4/maxval.m4 b/libgfortran/m4/maxval.m4 new file mode 100644 index 00000000000..b6a5666aae1 --- /dev/null +++ b/libgfortran/m4/maxval.m4 @@ -0,0 +1,39 @@ +`/* Implementation of the MAXVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(type_min, +` result = type_min;', +` if (*src > result) + result = *src;') + +MASKED_ARRAY_FUNCTION(type_min, +` result = type_min;', +` if (*msrc && *src > result) + result = *src;') + diff --git a/libgfortran/m4/minloc0.m4 b/libgfortran/m4/minloc0.m4 new file mode 100644 index 00000000000..5411418b68a --- /dev/null +++ b/libgfortran/m4/minloc0.m4 @@ -0,0 +1,54 @@ +`/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(iforeach.m4)dnl + +FOREACH_FUNCTION( +` type_name minval; + + minval = type_max;' +, +` if (*base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + }') + +MASKED_FOREACH_FUNCTION( +` type_name minval; + + minval = type_max;' +, +` if (*mbase && *base < minval) + { + minval = *base; + for (n = 0; n < rank; n++) + dest[n * dstride] = count[n] + 1; + }') diff --git a/libgfortran/m4/minloc1.m4 b/libgfortran/m4/minloc1.m4 new file mode 100644 index 00000000000..e3101c63861 --- /dev/null +++ b/libgfortran/m4/minloc1.m4 @@ -0,0 +1,50 @@ +`/* Implementation of the MINLOC intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(0, +` type_name minval; + minval = type_max; + result = 1;', +` if (*src < minval) + { + minval = *src; + result = (rtype_name)n + 1; + }') + +MASKED_ARRAY_FUNCTION(0, +` type_name minval; + minval = type_max; + result = 1;', +` if (*msrc && *src < minval) + { + minval = *src; + result = (rtype_name)n + 1; + }') + diff --git a/libgfortran/m4/minval.m4 b/libgfortran/m4/minval.m4 new file mode 100644 index 00000000000..2c1be2b88f9 --- /dev/null +++ b/libgfortran/m4/minval.m4 @@ -0,0 +1,39 @@ +`/* Implementation of the MINVAL intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(type_max, +` result = type_max;', +` if (*src < result) + result = *src;') + +MASKED_ARRAY_FUNCTION(type_max, +` result = type_max;', +` if (*msrc && *src < result) + result = *src;') + diff --git a/libgfortran/m4/mtype.m4 b/libgfortran/m4/mtype.m4 new file mode 100644 index 00000000000..84bf39f3561 --- /dev/null +++ b/libgfortran/m4/mtype.m4 @@ -0,0 +1,5 @@ +dnl Get type kind from filename. +define(kind,regexp(file, `_.\([0-9]+\).c$', `\1'))dnl +define(complex_type, `GFC_COMPLEX_'kind)dnl +define(real_type, `GFC_REAL_'kind)dnl +define(q,ifelse(kind,4,f,ifelse(kind,8,`',`_'kind)))dnl diff --git a/libgfortran/m4/nearest.m4 b/libgfortran/m4/nearest.m4 new file mode 100644 index 00000000000..5168d99c8e2 --- /dev/null +++ b/libgfortran/m4/nearest.m4 @@ -0,0 +1,39 @@ +`/* Implementation of the NEAREST intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include +#include "libgfortran.h"' + +include(`mtype.m4')dnl + +real_type +prefix(nearest_r`'kind) (real_type s, real_type dir) +{ + dir = copysign`'q (__builtin_inf`'q (), dir); + if (FLT_EVAL_METHOD != 0) + { + /* ??? Work around glibc bug on x86. */ + volatile real_type r = nextafter`'q (s, dir); + return r; + } + else + return nextafter`'q (s, dir); +} diff --git a/libgfortran/m4/product.m4 b/libgfortran/m4/product.m4 new file mode 100644 index 00000000000..bef9b8184eb --- /dev/null +++ b/libgfortran/m4/product.m4 @@ -0,0 +1,37 @@ +`/* Implementation of the PRODUCT intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(1, +` result = 1;', +` result *= *src;') + +MASKED_ARRAY_FUNCTION(1, +` result = 1;', +` if (*msrc) + result *= *src;') + diff --git a/libgfortran/m4/reshape.m4 b/libgfortran/m4/reshape.m4 new file mode 100644 index 00000000000..b8143fe24af --- /dev/null +++ b/libgfortran/m4/reshape.m4 @@ -0,0 +1,232 @@ +`/* Implementation of the RESHAPE + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_kind, regexp(file, `_.\([0-9]+\)\.', `\1'))dnl +define(rtype_letter, regexp(file, `_\(.\)[0-9]+\.', `\1'))dnl +define(rtype_code,rtype_letter`'rtype_name)dnl +define(rtype,get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_name, get_typename(rtype_letter, rtype_kind))dnl + +typedef GFC_ARRAY_DESCRIPTOR(1, index_type) shape_type; + +/* The shape parameter is ignored. We can currently deduce the shape from the + return array. */ +dnl Only the kind (ie size) is used to name the function. +void +`__reshape_'rtype_kind (rtype * ret, rtype * source, shape_type * shape, + rtype * pad, shape_type * order) +{ + /* r.* indicates the return array. */ + index_type rcount[GFC_MAX_DIMENSIONS - 1]; + index_type rextent[GFC_MAX_DIMENSIONS - 1]; + index_type rstride[GFC_MAX_DIMENSIONS - 1]; + index_type rstride0; + index_type rdim; + index_type rsize; + rtype_name *rptr; + /* s.* indicates the source array. */ + index_type scount[GFC_MAX_DIMENSIONS - 1]; + index_type sextent[GFC_MAX_DIMENSIONS - 1]; + index_type sstride[GFC_MAX_DIMENSIONS - 1]; + index_type sstride0; + index_type sdim; + index_type ssize; + const rtype_name *sptr; + /* p.* indicates the pad array. */ + index_type pcount[GFC_MAX_DIMENSIONS - 1]; + index_type pextent[GFC_MAX_DIMENSIONS - 1]; + index_type pstride[GFC_MAX_DIMENSIONS - 1]; + index_type pdim; + index_type psize; + const rtype_name *pptr; + + const rtype_name *src; + int n; + int dim; + + if (ret->dim[0].stride == 0) + ret->dim[0].stride = 1; + if (source->dim[0].stride == 0) + source->dim[0].stride = 1; + if (shape->dim[0].stride == 0) + shape->dim[0].stride = 1; + if (pad && pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + if (order && order->dim[0].stride == 0) + order->dim[0].stride = 1; + + rdim = GFC_DESCRIPTOR_RANK (ret); + rsize = 1; + for (n = 0; n < rdim; n++) + { + if (order) + dim = order->data[n * order->dim[0].stride] - 1; + else + dim = n; + + rcount[n] = 0; + rstride[n] = ret->dim[dim].stride; + rextent[n] = ret->dim[dim].ubound + 1 - ret->dim[dim].lbound; + + if (rextent[n] != shape->data[dim * shape->dim[0].stride]) + runtime_error ("shape and target do not conform"); + + if (rsize == rstride[n]) + rsize *= rextent[n]; + else + rsize = 0; + if (rextent[dim] <= 0) + return; + } + + sdim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + for (n = 0; n < sdim; n++) + { + scount[n] = 0; + sstride[n] = source->dim[n].stride; + sextent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (sextent[n] <= 0) + abort (); + + if (ssize == sstride[n]) + ssize *= sextent[n]; + else + ssize = 0; + } + + if (pad) + { + if (pad->dim[0].stride == 0) + pad->dim[0].stride = 1; + pdim = GFC_DESCRIPTOR_RANK (pad); + psize = 1; + for (n = 0; n < pdim; n++) + { + pcount[n] = 0; + pstride[n] = pad->dim[n].stride; + pextent[n] = pad->dim[n].ubound + 1 - pad->dim[n].lbound; + if (pextent[n] <= 0) + abort (); + if (psize == pstride[n]) + psize *= pextent[n]; + else + psize = 0; + } + pptr = pad->data; + } + else + { + pdim = 0; + psize = 1; + pptr = NULL; + } + + if (rsize != 0 && ssize != 0 && psize != 0) + { + rsize *= rtype_kind; + ssize *= rtype_kind; + psize *= rtype_kind; + reshape_packed ((char *)ret->data, rsize, (char *)source->data, + ssize, pad ? (char *)pad->data : NULL, psize); + return; + } + rptr = ret->data; + src = sptr = source->data; + rstride0 = rstride[0]; + sstride0 = sstride[0]; + + while (rptr) + { + /* Select between the source and pad arrays. */ + *rptr = *src; + /* Advance to the next element. */ + rptr += rstride0; + src += sstride0; + rcount[0]++; + scount[0]++; + /* Advance to the next destination element. */ + n = 0; + while (rcount[n] == rextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + rcount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + rptr -= rstride[n] * rextent[n]; + n++; + if (n == rdim) + { + /* Break out of the loop. */ + rptr = NULL; + break; + } + else + { + rcount[n]++; + rptr += rstride[n]; + } + } + /* Advance to the next source element. */ + n = 0; + while (scount[n] == sextent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + scount[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= sstride[n] * sextent[n]; + n++; + if (n == sdim) + { + if (sptr && pad) + { + /* Switch to the pad array. */ + sptr = NULL; + sdim = pdim; + for (dim = 0; dim < pdim; dim++) + { + scount[dim] = pcount[dim]; + sextent[dim] = pextent[dim]; + sstride[dim] = pstride[dim]; + sstride0 = sstride[0]; + } + } + /* We now start again from the beginning of the pad array. */ + src = pptr; + break; + } + else + { + scount[n]++; + src += sstride[n]; + } + } + } +} + diff --git a/libgfortran/m4/set_exponent.m4 b/libgfortran/m4/set_exponent.m4 new file mode 100644 index 00000000000..352a129865e --- /dev/null +++ b/libgfortran/m4/set_exponent.m4 @@ -0,0 +1,31 @@ +`/* Implementation of the SET_EXPONENT intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Richard Henderson . + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ +#include +#include "libgfortran.h"' + +include(`mtype.m4')dnl + +real_type +prefix(set_exponent_r`'kind) (real_type s, GFC_INTEGER_4 i) +{ + int dummy_exp; + return scalbn`'q (frexp`'q (s, &dummy_exp), i); +} diff --git a/libgfortran/m4/shape.m4 b/libgfortran/m4/shape.m4 new file mode 100644 index 00000000000..826077eabe7 --- /dev/null +++ b/libgfortran/m4/shape.m4 @@ -0,0 +1,48 @@ +`/* Implementation of the SHAPE intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_kind, regexp(file, `_i\([0-9]+\)\.', `\1'))dnl +define(rtype_code,`i'rtype_name)dnl +define(rtype,get_arraytype(i,rtype_kind))dnl +define(rtype_name, get_typename(i, rtype_kind))dnl + +void +`__shape_'rtype_kind (rtype * ret, const rtype * array) +{ + int n; + index_type stride; + + stride = ret->dim[0].stride; + if (stride == 0) + stride = 1; + + for (n = 0; n < GFC_DESCRIPTOR_RANK (array); n++) + { + ret->data[n * stride] = + array->dim[n].ubound + 1 - array->dim[n].lbound; + } +} + diff --git a/libgfortran/m4/specific.m4 b/libgfortran/m4/specific.m4 new file mode 100644 index 00000000000..bf88857ccf1 --- /dev/null +++ b/libgfortran/m4/specific.m4 @@ -0,0 +1,16 @@ +include(head.m4) +define(type_code,regexp(file,`_\([ircl][0-9]+\).f90',`\1'))dnl +define(type_letter,substr(type_code, 0, 1))dnl +define(type_kind,substr(type_code, 1))dnl +define(get_typename2, `$1 (kind=$2)')dnl +define(get_typename, `get_typename2(ifelse($1,i,integer,ifelse($1,r,real,ifelse($1,l,logical,ifelse($1,c,complex,unknown)))),`$2')')dnl +define(type_name, get_typename(type_letter,type_kind))dnl +define(name, regexp(regexp(file, `[^/]*$', `\&'), `^_\([^_]*\)_', `\1'))dnl +define(function_name,`specific__'name`_'type_code)dnl + +elemental function function_name (parm) + type_name, intent (in) :: parm + type_name :: function_name + + function_name = name (parm) +end function diff --git a/libgfortran/m4/specific2.m4 b/libgfortran/m4/specific2.m4 new file mode 100644 index 00000000000..ca0d831f5e0 --- /dev/null +++ b/libgfortran/m4/specific2.m4 @@ -0,0 +1,16 @@ +include(head.m4) +define(type_code,regexp(file,`_\([ircl][0-9]+\).f90',`\1'))dnl +define(type_letter,substr(type_code, 0, 1))dnl +define(type_kind,substr(type_code, 1))dnl +define(get_typename2, `$1 (kind=$2)')dnl +define(get_typename, `get_typename2(ifelse($1,i,integer,ifelse($1,r,real,ifelse($1,l,logical,ifelse($1,c,complex,unknown)))),`$2')')dnl +define(type_name, get_typename(type_letter,type_kind))dnl +define(name, regexp(regexp(file, `[^/]*$', `\&'), `^_\([^_]*\)_', `\1'))dnl +define(function_name,`specific__'name`_'type_code)dnl + +elemental function function_name (p1, p2) + type_name, intent (in) :: p1, p2 + type_name :: function_name + + function_name = name (p1, p2) +end function diff --git a/libgfortran/m4/sum.m4 b/libgfortran/m4/sum.m4 new file mode 100644 index 00000000000..0ea3477bf87 --- /dev/null +++ b/libgfortran/m4/sum.m4 @@ -0,0 +1,36 @@ +`/* Implementation of the SUM intrinsic + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include "libgfortran.h"' + +include(iparm.m4)dnl +include(ifunction.m4)dnl +ARRAY_FUNCTION(0, +` result = 0;', +` result += *src;') + +MASKED_ARRAY_FUNCTION(0, +` result = 0;', +` if (*msrc) + result += *src;') diff --git a/libgfortran/m4/transpose.m4 b/libgfortran/m4/transpose.m4 new file mode 100644 index 00000000000..35df64bf347 --- /dev/null +++ b/libgfortran/m4/transpose.m4 @@ -0,0 +1,75 @@ +`/* Implementation of the TRANSPOSE intrinsic + Copyright 2003 Free Software Foundation, Inc. + Contributed by Tobias Schlüter + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include "libgfortran.h"' +include(types.m4)dnl +define(rtype_kind, regexp(file, `_.\([0-9]+\)\.', `\1'))dnl +define(rtype_letter, regexp(file, `_\(.\)[0-9]+\.', `\1'))dnl +define(rtype_code,rtype_letter`'rtype_name)dnl +define(rtype,get_arraytype(rtype_letter,rtype_kind))dnl +define(rtype_name, get_typename(rtype_letter, rtype_kind))dnl + +void +`__transpose_'rtype_kind (rtype * ret, rtype * source) +{ + /* r.* indicates the return array. */ + index_type rxstride, rystride; + rtype_name *rptr; + /* s.* indicates the source array. */ + index_type sxstride, systride; + const rtype_name *sptr; + + index_type xcount, ycount; + index_type x, y; + + assert (GFC_DESCRIPTOR_RANK (source) == 2); + + if (ret->dim[0].stride == 0) + ret->dim[0].stride = 1; + if (source->dim[0].stride == 0) + source->dim[0].stride = 1; + + sxstride = source->dim[0].stride; + systride = source->dim[1].stride; + xcount = source->dim[0].ubound + 1 - source->dim[0].lbound; + ycount = source->dim[1].ubound + 1 - source->dim[1].lbound; + + rxstride = ret->dim[0].stride; + rystride = ret->dim[1].stride; + + rptr = ret->data; + sptr = source->data; + + for (y=0; y < ycount; y++) + { + for (x=0; x < xcount; x++) + { + *rptr = *sptr; + + sptr += sxstride; + rptr += rystride; + } + sptr += systride - (sxstride * xcount); + rptr += rxstride - (rystride * xcount); + } +} diff --git a/libgfortran/m4/types.m4 b/libgfortran/m4/types.m4 new file mode 100644 index 00000000000..cb808290c08 --- /dev/null +++ b/libgfortran/m4/types.m4 @@ -0,0 +1,4 @@ +define(get_typename2, `GFC_$1_$2')dnl +define(get_typename, `get_typename2(ifelse($1,i,INTEGER,ifelse($1,r,REAL,ifelse($1,l,LOGICAL,ifelse($1,c,COMPLEX,unknown)))),`$2')')dnl +define(get_arraytype, `gfc_array_$1$2')dnl +define(name, regexp(regexp(file, `[^/]*$', `\&'), `^\([^_]*\)_', `\1'))dnl diff --git a/libgfortran/runtime/environ.c b/libgfortran/runtime/environ.c new file mode 100644 index 00000000000..71419616920 --- /dev/null +++ b/libgfortran/runtime/environ.c @@ -0,0 +1,678 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with libgfor; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include + +#include "libgfortran.h" +#include "../io/io.h" + + +/* Environment scanner. Examine the environment for controlling minor + * aspects of the program's execution. Our philosophy here that the + * environment should not prevent the program from running, so an + * environment variable with a messed-up value will be interpreted in + * the default way. + * + * Most of the environment is checked early in the startup sequence, + * but other variables are checked during execution of the user's + * program. */ + +options_t options; + +extern char **environ; + +typedef struct variable +{ + const char *name; + int value, *var; + void (*init) (struct variable *); + void (*show) (struct variable *); + const char *desc; + int bad; +} +variable; + + +/* print_spaces()-- Print a particular number of spaces */ + +static void +print_spaces (int n) +{ + char buffer[80]; + int i; + + if (n <= 0) + return; + + for (i = 0; i < n; i++) + buffer[i] = ' '; + + buffer[i] = '\0'; + + st_printf (buffer); +} + + +/* var_source()-- Return a string that describes where the value of a + * variable comes from */ + +static const char * +var_source (variable * v) +{ + + if (getenv (v->name) == NULL) + return "Default"; + + if (v->bad) + return "Bad "; + + return "Set "; +} + + +/* init_integer()-- Initialize an integer environment variable */ + +static void +init_integer (variable * v) +{ + char *p, *q; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + for (q = p; *q; q++) + if (!isdigit (*q)) + { + v->bad = 1; + goto set_default; + } + + *v->var = atoi (p); + return; + +set_default: + *v->var = v->value; + return; +} + + +/* show_integer()-- Show an integer environment variable */ + +static void +show_integer (variable * v) +{ + + st_printf ("%s %d\n", var_source (v), *v->var); +} + + +/* init_boolean()-- Initialize a boolean environment variable. We + * only look at the first letter of the variable. */ + +static void +init_boolean (variable * v) +{ + char *p; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + if (*p == '1' || *p == 'Y' || *p == 'y') + { + *v->var = 1; + return; + } + + if (*p == '0' || *p == 'N' || *p == 'n') + { + *v->var = 0; + return; + } + + v->bad = 1; + +set_default: + *v->var = v->value; + return; +} + + +/* show_boolean()-- Show a boolean environment variable */ + +static void +show_boolean (variable * v) +{ + + st_printf ("%s %s\n", var_source (v), *v->var ? "Yes" : "No"); +} + + +/* init_mem()-- Initialize environment variables that have to do with + * how memory from an ALLOCATE statement is filled. A single flag + * enables filling and a second variable gives the value that is used + * to initialize the memory. */ + +static void +init_mem (variable * v) +{ + int offset, n; + char *p; + + p = getenv (v->name); + + options.allocate_init_flag = 0; /* The default */ + + if (p == NULL) + return; + + if (strcasecmp (p, "NONE") == 0) + return; + + /* IEEE-754 Quiet Not-a-Number that will work for single and double + * precision. Look for the 'f95' mantissa in debug dumps. */ + + if (strcasecmp (p, "NaN") == 0) + { + options.allocate_init_flag = 1; + options.allocate_init_value = 0xfff80f95; + return; + } + + /* Interpret the string as a hexadecimal constant */ + + n = 0; + while (*p) + { + if (!isxdigit (*p)) + { + v->bad = 1; + return; + } + + offset = '0'; + if (islower (*p)) + offset = 'a'; + if (isupper (*p)) + offset = 'A'; + + n = (n << 4) | (*p++ - offset); + } + + options.allocate_init_flag = 1; + options.allocate_init_value = n; +} + + +static void +show_mem (variable * v) +{ + char *p; + + p = getenv (v->name); + + st_printf ("%s ", var_source (v)); + + if (options.allocate_init_flag) + st_printf ("0x%x", options.allocate_init_value); + + st_printf ("\n"); +} + + +static void +init_sep (variable * v) +{ + int seen_comma; + char *p; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + v->bad = 1; + options.separator = p; + options.separator_len = strlen (p); + + /* Make sure the separator is valid */ + + if (options.separator_len == 0) + goto set_default; + seen_comma = 0; + + while (*p) + { + if (*p == ',') + { + if (seen_comma) + goto set_default; + seen_comma = 1; + p++; + continue; + } + + if (*p++ != ' ') + goto set_default; + } + + v->bad = 0; + return; + +set_default: + options.separator = " "; + options.separator_len = 1; +} + + +static void +show_sep (variable * v) +{ + + st_printf ("%s \"%s\"\n", var_source (v), options.separator); +} + + +static void +init_string (variable * v) +{ +} + +static void +show_string (variable * v) +{ + const char *p; + + p = getenv (v->name); + if (p == NULL) + p = ""; + + st_printf ("%s \"%s\"\n", var_source (v), p); +} + + +/* Structure for associating names and values. */ + +typedef struct +{ + const char *name; + int value; +} +choice; + + +enum +{ FP_ROUND_NEAREST, FP_ROUND_UP, FP_ROUND_DOWN, FP_ROUND_ZERO }; + +static choice rounding[] = { + {"NEAREST", FP_ROUND_NEAREST}, + {"UP", FP_ROUND_UP}, + {"DOWN", FP_ROUND_DOWN}, + {"ZERO", FP_ROUND_ZERO}, + {NULL} +}, precision[] = +{ + { + "24", 1} + , + { + "53", 2} + , + { + "64", 0} + , + { + NULL} +} + +, signal_choices[] = +{ + { + "IGNORE", 1} + , + { + "ABORT", 0} + , + { + NULL} +}; + + +static void +init_choice (variable * v, choice * c) +{ + char *p; + + p = getenv (v->name); + if (p == NULL) + goto set_default; + + for (; c->name; c++) + if (strcasecmp (c->name, p) == 0) + break; + + if (c->name == NULL) + { + v->bad = 1; + goto set_default; + } + + *v->var = c->value; + return; + +set_default: + *v->var = v->value; +} + + +static void +show_choice (variable * v, choice * c) +{ + + st_printf ("%s ", var_source (v)); + + for (; c->name; c++) + if (c->value == *v->var) + break; + + if (c->name) + st_printf ("%s\n", c->name); + else + st_printf ("(Unknown)\n"); + +} + + +static void +init_round (variable * v) +{ + init_choice (v, rounding); +} +static void +show_round (variable * v) +{ + show_choice (v, rounding); +} + +static void +init_precision (variable * v) +{ + init_choice (v, precision); +} +static void +show_precision (variable * v) +{ + show_choice (v, precision); +} + +static void +init_signal (variable * v) +{ + init_choice (v, signal_choices); +} +static void +show_signal (variable * v) +{ + show_choice (v, signal_choices); +} + + +static variable variable_table[] = { + {"GFORTRAN_STDIN_UNIT", 5, &options.stdin_unit, init_integer, show_integer, + "Unit number that will be preconnected to standard input\n" + "(No preconnection if negative)"}, + + {"GFORTRAN_STDOUT_UNIT", 6, &options.stdout_unit, init_integer, + show_integer, + "Unit number that will be preconnected to standard output\n" + "(No preconnection if negative)"}, + + {"GFORTRAN_USE_STDERR", 1, &options.use_stderr, init_boolean, + show_boolean, + "Sends library output to standard error instead of standard output."}, + + {"GFORTRAN_TMPDIR", 0, NULL, init_string, show_string, + "Directory for scratch files. Overrides the TMP environment variable\n" + "If TMP is not set " DEFAULT_TEMPDIR " is used."}, + + {"GFORTRAN_UNBUFFERED_ALL", 0, &options.all_unbuffered, init_boolean, + show_boolean, + "If TRUE, all output is unbuffered. This will slow down large writes " + "but can be\nuseful for forcing data to be displayed immediately."}, + + {"GFORTRAN_SHOW_LOCUS", 1, &options.locus, init_boolean, show_boolean, + "If TRUE, print filename and line number where runtime errors happen."}, + +/* GFORTRAN_NAME_xx (where xx is a unit number) gives the names of files + * preconnected to those units. */ + +/* GFORTRAN_UNBUFFERED_xx (where xx is a unit number) gives a boolean that is used + * to turn off buffering for that unit. */ + + {"GFORTRAN_OPTIONAL_PLUS", 0, &options.optional_plus, init_boolean, show_boolean, + "Print optional plus signs in numbers where permitted. Default FALSE."}, + + {"GFORTRAN_DEFAULT_RECL", DEFAULT_RECL, &options.default_recl, + init_integer, show_integer, + "Default maximum record length for sequential files. Most useful for\n" + "adjusting line length of preconnected units. Default " + stringize (DEFAULT_RECL)}, + + {"GFORTRAN_LIST_SEPARATOR", 0, NULL, init_sep, show_sep, + "Separatator to use when writing list output. May contain any number of " + "spaces\nand at most one comma. Default is a single space."}, + + /* Memory related controls */ + + {"GFORTRAN_MEM_INIT", 0, NULL, init_mem, show_mem, + "How to initialize allocated memory. Default value is NONE for no " + "initialization\n(faster), NAN for a Not-a-Number with the mantissa " + "0x40f95 or a custom\nhexadecimal value"}, + + {"GFORTRAN_MEM_CHECK", 0, &options.mem_check, init_boolean, show_boolean, + "Whether memory still allocated will be reported when the program ends."}, + + /* Signal handling (Unix). */ + + {"GFORTRAN_SIGHUP", 0, &options.sighup, init_signal, show_signal, + "Whether the program will IGNORE or ABORT on SIGHUP."}, + + {"GFORTRAN_SIGINT", 0, &options.sigint, init_signal, show_signal, + "Whether the program will IGNORE or ABORT on SIGINT."}, + + /* Floating point control */ + + {"GFORTRAN_FPU_ROUND", 0, &options.fpu_round, init_round, show_round, + "Set floating point rounding. Values are NEAREST, UP, DOWN, ZERO."}, + + {"GFORTRAN_FPU_PRECISION", 0, &options.fpu_precision, init_precision, + show_precision, + "Precision of intermediate results. Values are 24, 53 and 64."}, + + {"GFORTRAN_FPU_INVALID", 1, &options.fpu_invalid, init_boolean, + show_boolean, + "Raise a floating point exception on invalid FP operation."}, + + {"GFORTRAN_FPU_DENORMAL", 1, &options.fpu_denormal, init_boolean, + show_boolean, + "Raise a floating point exception when denormal numbers are encountered."}, + + {"GFORTRAN_FPU_ZERO", 0, &options.fpu_zerodiv, init_boolean, show_boolean, + "Raise a floating point exception when dividing by zero."}, + + {"GFORTRAN_FPU_OVERFLOW", 0, &options.fpu_overflow, init_boolean, + show_boolean, + "Raise a floating point exception on overflow."}, + + {"GFORTRAN_FPU_UNDERFLOW", 0, &options.fpu_underflow, init_boolean, + show_boolean, + "Raise a floating point exception on underflow."}, + + {"GFORTRAN_FPU_PRECISION", 0, &options.fpu_precision_loss, init_boolean, + show_boolean, + "Raise a floating point exception on precision loss."}, + + {NULL} +}; + + +/* init_variables()-- Initialize most runtime variables from + * environment variables. */ + +void +init_variables (void) +{ + variable *v; + + for (v = variable_table; v->name; v++) + v->init (v); +} + + +/* check_buffered()-- Given an unit number n, determine if an override + * for the stream exists. Returns zero for unbuffered, one for + * buffered or two for not set. */ + +int +check_buffered (int n) +{ + char name[40]; + variable v; + int rv; + + if (options.all_unbuffered) + return 0; + + strcpy (name, "GFORTRAN_UNBUFFERED_"); + strcat (name, itoa (n)); + + v.name = name; + v.value = 2; + v.var = &rv; + + init_boolean (&v); + + return rv; +} + + +/* pattern_scan()-- Given an environment string, check that the name + * has the same name as the pattern followed by an integer. On a + * match, a pointer to the value is returned and the integer pointed + * to by n is updated. Returns NULL on no match. */ + +static char * +pattern_scan (char *env, const char *pattern, int *n) +{ + char *p; + size_t len; + + len = strlen (pattern); + if (strncasecmp (env, pattern, len) != 0) + return NULL; + p = env + len; + + if (!isdigit (*p)) + return NULL; + + while (isdigit (*p)) + p++; + + if (*p != '=') + return NULL; + + *p = '\0'; + *n = atoi (env + len); + *p++ = '='; + + return p; +} + + +void +show_variables (void) +{ + char *p, **e; + variable *v; + int n; +/* TODO: print version number. */ + st_printf ("GNU Fortran 95 runtime library version " + "UNKNOWN" "\n\n"); + + st_printf ("Environment variables:\n"); + st_printf ("----------------------\n"); + + for (v = variable_table; v->name; v++) + { + n = st_printf ("%s", v->name); + print_spaces (25 - n); + + if (v->show == show_integer) + st_printf ("Integer "); + else if (v->show == show_boolean) + st_printf ("Boolean "); + else + st_printf ("String "); + + v->show (v); + st_printf ("%s\n\n", v->desc); + } + + st_printf ("\nDefault unit names (GFORTRAN_NAME_x):\n"); + + for (e = environ; *e; e++) + { + p = pattern_scan (*e, "GFORTRAN_NAME_", &n); + if (p == NULL) + continue; + st_printf ("GFORTRAN_NAME_%d %s\n", n, p); + } + + st_printf ("\nUnit buffering overrides (GFORTRAN_UNBUFFERED_x):\n"); + for (e = environ; *e; e++) + { + p = pattern_scan (*e, "GFORTRAN_UNBUFFERED_", &n); + if (p == NULL) + continue; + + st_printf ("GFORTRAN_UNBUFFERED_%d = %s\n", n, p); + } + + /* System error codes */ + + st_printf ("\nRuntime error codes:"); + st_printf ("\n--------------------\n"); + + for (n = ERROR_FIRST + 1; n < ERROR_LAST; n++) + if (n < 0 || n > 9) + st_printf ("%d %s\n", n, translate_error (n)); + else + st_printf (" %d %s\n", n, translate_error (n)); + + st_printf ("\nCommand line arguments:\n"); + st_printf (" --help Print this list\n"); + + /* st_printf(" --resume Resume program execution from dropfile\n"); */ + + sys_exit (0); +} diff --git a/libgfortran/runtime/error.c b/libgfortran/runtime/error.c new file mode 100644 index 00000000000..8cd980dff9a --- /dev/null +++ b/libgfortran/runtime/error.c @@ -0,0 +1,538 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with libgfor; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include "config.h" +#include +#include +#include +#include + +#include "libgfortran.h" +#include "../io/io.h" + +/* Error conditions. The tricky part here is printing a message when + * it is the I/O subsystem that is severely wounded. Our goal is to + * try and print something making the fewest assumptions possible, + * then try to clean up before actually exiting. + * + * The following exit conditions are defined: + * 0 Normal program exit. + * 1 Terminated because of operating system error. + * 2 Error in the runtime library + * 3 Internal error in runtime library + * 4 Error during error processing (very bad) + * + * Other error returns are reserved for the STOP statement with a numeric code. + */ + +/* locus variables. These are optionally set by a caller before a + * library subroutine is called. They are always cleared on exit so + * that files that report loci and those that do not can be linked + * together without reporting an erroneous position. */ + +char *filename; +unsigned line; + +static char buffer[32]; /* buffer for integer/ascii conversions */ + +/* rtoa()-- Real to ascii conversion for base 10 and below. + * Returns a pointer to a static buffer. */ + +char * +rtoa (double f, int length, int oprec) +{ + double n = f; + double fval, minval; + int negative, prec; + unsigned k; + char formats[16]; + + prec = 0; + negative = 0; + if (n < 0.0) + { + negative = 1; + n = -n; + } + + if (length >= 8) + minval = FLT_MIN; + else + minval = DBL_MIN; + + + if (n <= minval) + { + buffer[0] = '0'; + buffer[1] = '.'; + for (k = 2; k < 28 ; k++) + buffer[k] = '0'; + buffer[k+1] = '\0'; + return buffer; + } + fval = n; + while (fval > 1.0) + { + fval = fval / 10.0; + prec ++; + } + + prec = sizeof (buffer) - 2 - prec; + if (prec > 20) + prec = 20; + prec = prec > oprec ? oprec : prec ; + + if (negative) + sprintf (formats, "-%%.%df", prec); + else + sprintf (formats, "%%.%df", prec); + + sprintf (buffer, formats, n); + return buffer; +} + + +/* Returns a pointer to a static buffer. */ + +char * +itoa (int64_t n) +{ + int negative; + char *p; + + if (n == 0) + { + buffer[0] = '0'; + buffer[1] = '\0'; + return buffer; + } + + negative = 0; + if (n < 0) + { + negative = 1; + n = -n; + } + + p = buffer + sizeof (buffer) - 1; + *p-- = '\0'; + + while (n != 0) + { + *p-- = '0' + (n % 10); + n /= 10; + } + + if (negative) + *p-- = '-'; + return ++p; +} + + +/* xtoa()-- Integer to hexadecimal conversion. Returns a pointer to a + * static buffer. */ + +char * +xtoa (uint64_t n) +{ + int digit; + char *p; + + if (n == 0) + { + buffer[0] = '0'; + buffer[1] = '\0'; + return buffer; + } + + p = buffer + sizeof (buffer) - 1; + *p-- = '\0'; + + while (n != 0) + { + digit = n & 0xF; + if (digit > 9) + digit += 'A' - '0' - 10; + + *p-- = '0' + digit; + n >>= 4; + } + + return ++p; +} + + +/* st_printf()-- simple printf() function for streams that handles the + * formats %d, %s and %c. This function handles printing of error + * messages that originate within the library itself, not from a user + * program. */ + +int +st_printf (const char *format, ...) +{ + int count, total; + va_list arg; + char *p, *q; + stream *s; + + total = 0; + s = init_error_stream (); + va_start (arg, format); + + for (;;) + { + count = 0; + + while (format[count] != '%' && format[count] != '\0') + count++; + + if (count != 0) + { + p = salloc_w (s, &count); + memmove (p, format, count); + sfree (s); + } + + total += count; + format += count; + if (*format++ == '\0') + break; + + switch (*format) + { + case 'c': + count = 1; + + p = salloc_w (s, &count); + *p = (char) va_arg (arg, int); + + sfree (s); + break; + + case 'd': + q = itoa (va_arg (arg, int)); + count = strlen (q); + + p = salloc_w (s, &count); + memmove (p, q, count); + sfree (s); + break; + + case 'x': + q = xtoa (va_arg (arg, unsigned)); + count = strlen (q); + + p = salloc_w (s, &count); + memmove (p, q, count); + sfree (s); + break; + + case 's': + q = va_arg (arg, char *); + count = strlen (q); + + p = salloc_w (s, &count); + memmove (p, q, count); + sfree (s); + break; + + case '\0': + return total; + + default: + count = 2; + p = salloc_w (s, &count); + p[0] = format[-1]; + p[1] = format[0]; + sfree (s); + break; + } + + total += count; + format++; + } + + va_end (arg); + return total; +} + + +/* st_sprintf()-- Simple sprintf() for formatting memory buffers. */ + +void +st_sprintf (char *buffer, const char *format, ...) +{ + va_list arg; + char c, *p; + int count; + + va_start (arg, format); + + for (;;) + { + c = *format++; + if (c != '%') + { + *buffer++ = c; + if (c == '\0') + break; + continue; + } + + c = *format++; + switch (c) + { + case 'c': + *buffer++ = (char) va_arg (arg, int); + break; + + case 'd': + p = itoa (va_arg (arg, int)); + count = strlen (p); + + memcpy (buffer, p, count); + buffer += count; + break; + + case 's': + p = va_arg (arg, char *); + count = strlen (p); + + memcpy (buffer, p, count); + buffer += count; + break; + + default: + *buffer++ = c; + } + } + + va_end (arg); +} + + +/* show_locus()-- Print a line number and filename describing where + * something went wrong */ + +void +show_locus (void) +{ + + if (!options.locus || filename == NULL) + return; + + st_printf ("At line %d of file %s\n", line, filename); +} + + +/* recursion_check()-- It's possible for additional errors to occur + * during fatal error processing. We detect this condition here and + * exit with code 4 immediately. */ + +#define MAGIC 0x20DE8101 + +static void +recursion_check (void) +{ + static int magic = 0; + + if (magic == MAGIC) + sys_exit (4); /* Don't even try to print something at this point */ + + magic = MAGIC; +} + + +/* os_error()-- Operating system error. We get a message from the + * operating system, show it and leave. Some operating system errors + * are caught and processed by the library. If not, we come here. */ + +void +os_error (const char *message) +{ + + recursion_check (); + + show_locus (); + st_printf ("Operating system error: %s\n%s\n", get_oserror (), message); + + sys_exit (1); +} + + +/* void runtime_error()-- These are errors associated with an + * invalid fortran program. */ + +void +runtime_error (const char *message) +{ + + recursion_check (); + + show_locus (); + st_printf ("Fortran runtime error: %s\n", message); + + sys_exit (2); +} + + +/* void internal_error()-- These are this-can't-happen errors + * that indicate something deeply wrong. */ + +void +internal_error (const char *message) +{ + + recursion_check (); + + show_locus (); + st_printf ("Internal Error: %s\n", message); + sys_exit (3); +} + + +/* translate_error()-- Given an integer error code, return a string + * describing the error. */ + +const char * +translate_error (int code) +{ + const char *p; + + switch (code) + { + case ERROR_EOR: + p = "End of record"; + break; + + case ERROR_END: + p = "End of file"; + break; + + case ERROR_OK: + p = "Successful return"; + break; + + case ERROR_OS: + p = "Operating system error"; + break; + + case ERROR_BAD_OPTION: + p = "Bad statement option"; + break; + + case ERROR_MISSING_OPTION: + p = "Missing statement option"; + break; + + case ERROR_OPTION_CONFLICT: + p = "Conflicting statement options"; + break; + + case ERROR_ALREADY_OPEN: + p = "File already opened in another unit"; + break; + + case ERROR_BAD_UNIT: + p = "Unattached unit"; + break; + + case ERROR_FORMAT: + p = "FORMAT error"; + break; + + case ERROR_BAD_ACTION: + p = "Incorrect ACTION specified"; + break; + + case ERROR_ENDFILE: + p = "Read past ENDFILE record"; + break; + + case ERROR_BAD_US: + p = "Corrupt unformatted sequential file"; + break; + + case ERROR_READ_VALUE: + p = "Bad value during read"; + break; + + case ERROR_READ_OVERFLOW: + p = "Numeric overflow on read"; + break; + + default: + p = "Unknown error code"; + break; + } + + return p; +} + + +/* generate_error()-- Come here when an error happens. This + * subroutine is called if it is possible to continue on after the + * error. If an IOSTAT variable exists, we set it. If the IOSTAT or + * ERR label is present, we return, otherwise we terminate the program + * after print a message. The error code is always required but the + * message parameter can be NULL, in which case a string describing + * the most recent operating system error is used. */ + +void +generate_error (int family, const char *message) +{ + + if (ioparm.iostat != NULL) + { + *ioparm.iostat = family; + return; + } + + switch (family) + { + case ERROR_EOR: + ioparm.library_return = LIBRARY_EOR; + if (ioparm.eor != 0) + return; + break; + + case ERROR_END: + ioparm.library_return = LIBRARY_END; + if (ioparm.end != 0) + return; + break; + + default: + ioparm.library_return = LIBRARY_ERROR; + break; + } + + if (ioparm.err != 0) + return; + + /* Terminate the program */ + + if (message == NULL) + message = + (family == ERROR_OS) ? get_oserror () : translate_error (family); + + runtime_error (message); +} diff --git a/libgfortran/runtime/in_pack_generic.c b/libgfortran/runtime/in_pack_generic.c new file mode 100644 index 00000000000..8af4f3f0eb7 --- /dev/null +++ b/libgfortran/runtime/in_pack_generic.c @@ -0,0 +1,123 @@ +/* Generic helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void * +internal_pack (gfc_array_char * source) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type ssize; + const char *src; + char *dest; + void *destptr; + int n; + int packed; + index_type size; + + if (source->dim[0].stride == 0) + { + source->dim[0].stride = 1; + return source->data; + } + + size = GFC_DESCRIPTOR_SIZE (source); + switch (size) + { + case 4: + return internal_pack_4 ((gfc_array_i4 *)source); + + case 8: + return internal_pack_8 ((gfc_array_i8 *)source); + } + + dim = GFC_DESCRIPTOR_RANK (source); + ssize = 1; + packed = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = source->dim[n].stride; + extent[n] = source->dim[n].ubound + 1 - source->dim[n].lbound; + if (extent[n] <= 0) + { + /* Do nothing. */ + packed = 1; + break; + } + + if (ssize != stride[n]) + packed = 0; + + ssize *= extent[n]; + } + + if (packed) + return source->data; + + /* Allocate storage for the destination. */ + destptr = internal_malloc_size (ssize * size); + dest = (char *)destptr; + src = source->data; + stride0 = stride[0] * size; + + while (src) + { + /* Copy the data. */ + memcpy(dest, src, size); + /* Advance to the next element. */ + dest += size; + src += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + src -= stride[n] * extent[n] * size; + n++; + if (n == dim) + { + src = NULL; + break; + } + else + { + count[n]++; + src += stride[n] * size; + } + } + } + return destptr; +} + diff --git a/libgfortran/runtime/in_unpack_generic.c b/libgfortran/runtime/in_unpack_generic.c new file mode 100644 index 00000000000..82a6771906f --- /dev/null +++ b/libgfortran/runtime/in_unpack_generic.c @@ -0,0 +1,120 @@ +/* Generic helper function for repacking arrays. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Ligbfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include +#include +#include "libgfortran.h" + +void +internal_unpack (gfc_array_char * d, const void * s) +{ + index_type count[GFC_MAX_DIMENSIONS - 1]; + index_type extent[GFC_MAX_DIMENSIONS - 1]; + index_type stride[GFC_MAX_DIMENSIONS - 1]; + index_type stride0; + index_type dim; + index_type dsize; + char *dest; + const char *src; + int n; + int size; + + dest = d->data; + /* This check may be redundant, but do it anyway. */ + if (s == dest || !s) + return; + + size = GFC_DESCRIPTOR_SIZE (d); + switch (size) + { + case 4: + internal_unpack_4 ((gfc_array_i4 *)d, (const GFC_INTEGER_4 *)s); + return; + + case 8: + internal_unpack_8 ((gfc_array_i8 *)d, (const GFC_INTEGER_8 *)s); + return; + } + + if (d->dim[0].stride == 0) + d->dim[0].stride = 1; + + dim = GFC_DESCRIPTOR_RANK (d); + dsize = 1; + for (n = 0; n < dim; n++) + { + count[n] = 0; + stride[n] = d->dim[n].stride; + extent[n] = d->dim[n].ubound + 1 - d->dim[n].lbound; + if (extent[n] <= 0) + abort (); + + if (dsize == stride[n]) + dsize *= extent[n]; + else + dsize = 0; + } + + src = s; + + if (dsize != 0) + { + memcpy (dest, src, dsize * size); + return; + } + + stride0 = stride[0] * size; + + while (dest) + { + /* Copy the data. */ + memcpy (dest, src, size); + /* Advance to the next element. */ + src += size; + dest += stride0; + count[0]++; + /* Advance to the next source element. */ + n = 0; + while (count[n] == extent[n]) + { + /* When we get to the end of a dimension, reset it and increment + the next dimension. */ + count[n] = 0; + /* We could precalculate these products, but this is a less + frequently used path so proabably not worth it. */ + dest -= stride[n] * extent[n] * size; + n++; + if (n == dim) + { + dest = NULL; + break; + } + else + { + count[n]++; + dest += stride[n] * size; + } + } + } +} + diff --git a/libgfortran/runtime/main.c b/libgfortran/runtime/main.c new file mode 100644 index 00000000000..60c032b4fcb --- /dev/null +++ b/libgfortran/runtime/main.c @@ -0,0 +1,113 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Andy Vaught and Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with libgfor; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include + +#include "libgfortran.h" + +/* This is the offset (in bytes) required to cast from logical(8)* to + logical(4)*. and still get the same result. Will be 0 for little-endian + machines and 4 for big-endian machines. */ +int l8_to_l4_offset; + + +/* Figure out endianness for this machine. */ + +#define detetmine_endianness prefix(determine_endianness) +static void +determine_endianness (void) +{ + union + { + GFC_LOGICAL_8 l8; + GFC_LOGICAL_4 l4[2]; + } u; + + u.l8 = 1; + if (u.l4[0]) + l8_to_l4_offset = 0; + else if (u.l4[1]) + l8_to_l4_offset = 1; + else + runtime_error ("Unable to determine machine endianness"); +} + + +static int argc_save; +static char **argv_save; + +/* Set the saved values of the command line arguments. */ + +void +set_args (int argc, char **argv) +{ + argc_save = argc; + argv_save = argv; +} + +/* Retrieve the saved values of the command line arguments. */ + +void +get_args (int *argc, char ***argv) +{ + + *argc = argc_save; + *argv = argv_save; +} + + +/* Initialize the runtime library. */ + +static void __attribute__((constructor)) +init (void) +{ + /* Figure out the machine endianness. */ + determine_endianness (); + + /* Must be first */ + init_variables (); + + init_units (); + +#ifdef DEBUG + /* Check for special command lines. */ + + if (argc > 1 && strcmp (argv[1], "--help") == 0) + show_variables (); + +/* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume(); */ +#endif + + memory_init (); +} + + +/* Cleanup the runtime library. */ + +static void __attribute__((destructor)) +cleanup () +{ + close_units (); +} + diff --git a/libgfortran/runtime/memory.c b/libgfortran/runtime/memory.c new file mode 100644 index 00000000000..ca5eb15244b --- /dev/null +++ b/libgfortran/runtime/memory.c @@ -0,0 +1,312 @@ +/* Memory mamagement routines. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include "libgfortran.h" + +/* If GFC_CLEAR_MEMORY is defined, the memory allocation routines will + return memory that is guaranteed to be set to zero. This can have + a severe efficiency penalty, so it should never be set if good + performance is desired, but it can help when you're debugging code. */ +#define GFC_CLEAR_MEMORY + +/* If GFC_CHECK_MEMORY is defined, we do some sanity checks at runtime. + This causes small overhead, but again, it also helps debugging. */ +#define GFC_CHECK_MEMORY + +/* We use a double linked list of these structures to keep track of + the memory we allocate internally. We could also use this for user + allocated memory (ALLOCATE/DEALLOCATE). This should be stored in a + seperate list. */ +#define malloc_t prefix(malloc_t) +typedef struct malloc_t +{ + int magic; + int marker; + struct malloc_t *prev, *next; + + /* The start of the block. */ + void *data; +} +malloc_t; + +/* We try to make sure we don't get memory corruption by checking for + a magic number. */ +#define GFC_MALLOC_MAGIC 0x4d353941 /* "G95M" */ + +#define HEADER_SIZE offsetof (malloc_t, data) +#define DATA_POINTER(pheader) (&((pheader)->data)) +#define DATA_HEADER(pdata) ((malloc_t *)((char *) (pdata) - HEADER_SIZE)) + +/* The root of the circular double linked list for compiler generated + malloc calls. */ +static malloc_t mem_root; + + +void +memory_init (void) +{ + + /* The root should never be used directly, so don't set the magic. */ + mem_root.magic = 0; + mem_root.next = &mem_root; + mem_root.prev = &mem_root; + mem_root.marker = 0; +} + + +/* Doesn't actually do any cleaning up, just throws an error if something + has got out of sync somewhere. */ + +void +runtime_cleanup (void) +{ + /* Make sure all memory we've allocated is freed on exit. */ + if (mem_root.next != &mem_root) + runtime_error ("Unfreed memory on program termination"); +} + + + +void * +get_mem (size_t n) +{ + void *p; + +#ifdef GFC_CLEAR_MEMORY + p = (void *) calloc (n, 1); +#else +#define temp malloc +#undef malloc + p = (void *) malloc (n); +#define malloc temp +#undef temp +#endif + if (p == NULL) + os_error ("Memory allocation failed"); + + return p; +} + + +void +free_mem (void *p) +{ + + free (p); +} + + +/* Allocates a block of memory with a size of N bytes. N does not + include the size of the header. */ + +static malloc_t * +malloc_with_header (size_t n) +{ + malloc_t *newmem; + + n = n + HEADER_SIZE; + + newmem = (malloc_t *) get_mem (n); + + if (newmem) + { + newmem->magic = GFC_MALLOC_MAGIC; + newmem->marker = 0; + } + + return newmem; +} + + +/* Allocate memory for internal (compiler generated) use. */ + +void * +internal_malloc_size (size_t size) +{ + malloc_t *newmem; + + newmem = malloc_with_header (size); + + if (!newmem) + os_error ("Out of memory."); + + /* Add to end of list. */ + newmem->next = &mem_root; + newmem->prev = mem_root.prev; + mem_root.prev->next = newmem; + mem_root.prev = newmem; + + return DATA_POINTER (newmem); +} + + +void * +internal_malloc (GFC_INTEGER_4 size) +{ +#ifdef GFC_CHECK_MEMORY + /* Under normal circumstances, this is _never_ going to happen! */ + if (size <= 0) + runtime_error ("Attempt to allocate a non-positive amount of memory."); + +#endif + return internal_malloc_size ((size_t) size); +} + + +void * +internal_malloc64 (GFC_INTEGER_8 size) +{ +#ifdef GFC_CHECK_MEMORY + /* Under normal circumstances, this is _never_ going to happen! */ + if (size <= 0) + runtime_error ("Attempt to allocate a non-positive amount of memory."); +#endif + return internal_malloc_size ((size_t) size); +} + + +/* Free internally allocated memory. Pointer is NULLified. Also used to + free user allocated memory. */ +/* TODO: keep a list of previously allocated blocks and reuse them. */ + +void +internal_free (void *mem) +{ + malloc_t *m; + + if (!mem) + runtime_error ("Internal: Possible double free of temporary."); + + m = DATA_HEADER (mem); + + if (m->magic != GFC_MALLOC_MAGIC) + runtime_error ("Internal: No magic memblock marker. " + "Possible memory corruption"); + + /* Move markers up the chain, so they don't get lost. */ + m->prev->marker += m->marker; + /* Remove from list. */ + m->prev->next = m->next; + m->next->prev = m->prev; + + free (m); +} + + +/* User-allocate, one call for each member of the alloc-list of an + ALLOCATE statement. */ + +static void +allocate_size (void **mem, size_t size, GFC_INTEGER_4 * stat) +{ + malloc_t *newmem; + + if (!mem) + runtime_error ("Internal: NULL mem pointer in ALLOCATE."); + + newmem = malloc_with_header (size); + if (!newmem) + { + if (stat) + { + *stat = 1; + return; + } + else + runtime_error ("ALLOCATE: Out of memory."); + } + + /* We don't keep a list of these at the moment, so just link to itself. */ + newmem->next = newmem; + newmem->prev = newmem; + + (*mem) = DATA_POINTER (newmem); + + if (stat) + *stat = 0; +} + + +void +allocate (void **mem, GFC_INTEGER_4 size, GFC_INTEGER_4 * stat) +{ + + if (size < 0) + { + runtime_error ("Attempt to allocate negative amount of memory. " + "Possible integer overflow"); + abort (); + } + + allocate_size (mem, (size_t) size, stat); +} + + +void +allocate64 (void **mem, GFC_INTEGER_8 size, GFC_INTEGER_4 * stat) +{ + + if (size < 0) + { + runtime_error + ("ALLOCATE64: Attempt to allocate negative amount of memory. " + "Possible integer overflow"); + abort (); + } + + allocate_size (mem, (size_t) size, stat); +} + + +/* User-deallocate; pointer is NULLified. */ + +void +deallocate (void **mem, GFC_INTEGER_4 * stat) +{ + + if (!mem) + runtime_error ("Internal: NULL mem pointer in ALLOCATE."); + + if (!*mem) + { + if (stat) + { + *stat = 1; + return; + } + else + { + runtime_error + ("Internal: Attempt to DEALLOCATE unallocated memory."); + abort (); + } + } + + /* Just use the internal routine. */ + internal_free (*mem); + *mem = NULL; + + if (stat) + *stat = 0; +} + diff --git a/libgfortran/runtime/pause.c b/libgfortran/runtime/pause.c new file mode 100644 index 00000000000..9b8447f66c9 --- /dev/null +++ b/libgfortran/runtime/pause.c @@ -0,0 +1,71 @@ +/* Implementation of the STOP statement. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include +#include + +#include "libgfortran.h" + +#define pause_numeric prefix(pause_numeric) +#define pause_string prefix(pause_string) + +static void +do_pause (void) +{ + char buff[4]; + st_printf ("To resume execution, type go. " + "Other input will terminate the job.\n"); + + fgets(buff, 4, stdin); + if (strncmp(buff, "go\n", 3) != 0) + stop_numeric (-1); + st_printf ("RESUMED\n"); +} + +/* A numeric or blank STOP statement. */ +void +pause_numeric (GFC_INTEGER_4 code) +{ + show_locus (); + + if (code == -1) + st_printf ("PAUSE\n"); + else + st_printf ("PAUSE %d\n", (int)code); + + do_pause (); +} + + +void +pause_string (char *string, GFC_INTEGER_4 len) +{ + show_locus (); + + st_printf ("PAUSE "); + while (len--) + st_printf ("%c", *(string++)); + st_printf ("\n"); + + do_pause (); +} + diff --git a/libgfortran/runtime/select.c b/libgfortran/runtime/select.c new file mode 100644 index 00000000000..5ee873aefcb --- /dev/null +++ b/libgfortran/runtime/select.c @@ -0,0 +1,125 @@ +/* Implement the SELECT statement for character variables. + Contributed by Andy Vaught + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with libgfor; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "libgfortran.h" + +typedef struct +{ + char *low; + int low_len; + char *high; + int high_len; + void *address; +} +select_struct; + + +#define select_string prefix(select_string) + + +/* select_string()-- Given a selector string and a table of + * select_struct structures, return the address to jump to. */ + +void *select_string (select_struct *table, int table_len, void *default_jump, + const char *selector, int selector_len) +{ + select_struct *t; + int i, low, high, mid; + + if (table_len == 0) + return default_jump; + + /* Record the default address if present */ + + if (table->low == NULL && table->high == NULL) + { + default_jump = table->address; + + table++; + table_len--; + if (table_len == 0) + return default_jump; + } + + /* Try the high and low bounds if present. */ + + if (table->low == NULL) + { + if (compare_string (table->high_len, table->high, + selector_len, selector) >= 0) + return table->address; + + table++; + table_len--; + if (table_len == 0) + return default_jump; + } + + t = table + table_len - 1; + + if (t->high == NULL) + { + if (compare_string (t->low_len, t->low, + selector_len, selector) <= 0) + return t->address; + + table_len--; + if (table_len == 0) + return default_jump; + } + + /* At this point, the only table entries are bounded entries. Find + the right entry with a binary chop. */ + + low = -1; + high = table_len; + + while (low + 1 < high) + { + mid = (low + high) / 2; + + t = table + mid; + i = compare_string (t->low_len, t->low, selector_len, selector); + + if (i == 0) + return t->address; + + if (i < 0) + low = mid; + else + high = mid; + } + + /* The string now lies between the low indeces of the now-adjacent + high and low entries. Because it is less than the low entry of + 'high', it can't be that one. If low is still -1, then no + entries match. Otherwise, we have to check the high entry of + 'low'. */ + + if (low == -1) + return default_jump; + + t = table + low; + if (compare_string (selector_len, selector, + t->high_len, t->high) <= 0) + return t->address; + + return default_jump; +} diff --git a/libgfortran/runtime/stop.c b/libgfortran/runtime/stop.c new file mode 100644 index 00000000000..bc901bbad96 --- /dev/null +++ b/libgfortran/runtime/stop.c @@ -0,0 +1,56 @@ +/* Implementation of the STOP statement. + Copyright 2002 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with libgfor; see the file COPYING.LIB. If not, +write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include + +#include "libgfortran.h" + +#define stop_string prefix(stop_string) + +/* A numeric or blank STOP statement. */ +void +stop_numeric (GFC_INTEGER_4 code) +{ + show_locus (); + + if (code == -1) + st_printf ("STOP\n"); + else + st_printf ("STOP %d\n", (int)code); + + sys_exit (code); +} + + +void +stop_string (const char *string, GFC_INTEGER_4 len) +{ + show_locus (); + + st_printf ("STOP "); + while (len--) + st_printf ("%c", *(string++)); + st_printf ("\n"); + + sys_exit (0); +} + diff --git a/libgfortran/runtime/string.c b/libgfortran/runtime/string.c new file mode 100644 index 00000000000..bcd60928da6 --- /dev/null +++ b/libgfortran/runtime/string.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2002-2003 Free Software Foundation, Inc. + Contributed by Paul Brook + +This file is part of the GNU Fortran 95 runtime library (libgfor). + +Libgfor is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Libgfor is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with libgfor; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include "config.h" +#include + +#include "libgfortran.h" + + +/* Compare a C-style string with a fortran style string in a case-insensitive + manner. Used for decoding string options to various statements. Returns + zero if not equal, nonzero if equal. */ + +static int +compare0 (const char *s1, int s1_len, const char *s2) +{ + int i; + + if (strncasecmp (s1, s2, s1_len) != 0) + return 0; + + /* The rest of s1 needs to be blanks for equality. */ + + for (i = strlen (s2); i < s1_len; i++) + if (s1[i] != ' ') + return 0; + + return 1; +} + + +/* Given a fortran string, return its length exclusive of the trailing + spaces. */ +int +fstrlen (const char *string, int len) +{ + + for (len--; len >= 0; len--) + if (string[len] != ' ') + break; + + return len + 1; +} + + + +void +fstrcpy (char *dest, int destlen, const char *src, int srclen) +{ + + if (srclen >= destlen) + { + /* This will truncate if too long. */ + memcpy (dest, src, destlen); + } + else + { + memcpy (dest, src, srclen); + /* Pad with spaces. */ + memset (&dest[srclen], ' ', destlen - srclen); + } +} + + +void +cf_strcpy (char *dest, int dest_len, const char *src) +{ + int src_len; + + src_len = strlen (src); + + if (src_len >= dest_len) + { + /* This will truncate if too long. */ + memcpy (dest, src, dest_len); + } + else + { + memcpy (dest, src, src_len); + /* Pad with spaces. */ + memset (&dest[src_len], ' ', dest_len - src_len); + } +} + + +/* Given a fortran string and an array of st_option structures, search through + the array to find a match. If the option is not found, we generate an error + if no default is provided. */ + +int +find_option (const char *s1, int s1_len, st_option * opts, + const char *error_message) +{ + + for (; opts->name; opts++) + if (compare0 (s1, s1_len, opts->name)) + return opts->value; + + generate_error (ERROR_BAD_OPTION, error_message); + + return -1; +} + diff --git a/libmudflap/ChangeLog b/libmudflap/ChangeLog new file mode 100644 index 00000000000..eafa5eb3e57 --- /dev/null +++ b/libmudflap/ChangeLog @@ -0,0 +1,957 @@ +2004-03-25 Frank Ch. Eigler + + * mf-impl.h: Added libgcc license header. + +2004-03-20 Frank Ch. Eigler + + * mf-hooks[123].c, mf-runtime.c, mf-heuristics.c: + Added libgcc license header. + * mf-hooks3.c (__mf_0fn_pthread_create): Correct arg constness. + (pthread_create): Simplify stack allocation syntax. + +2004-03-08 Loren J. Rittle + + * mf-hooks2.c: Support FreeBSD. + (WRAP_gets): Avoid gets(). + * testsuite/libmudflap.c/pass-stratcliff.c: Do not + test unimplemented mem/str calls on FreeBSD. + * testsuite/libmudflap.c/pass21-frag.c: Do not include + on FreeBSD. + +2004-01-30 Frank Ch. Eigler + + * testsuite/libmudflap.c/pass36-frag.c: Add missing free() call. + * testsuite/libmudflap.c/pass46-frag.c: New test for -fmudflapir. + * testsuite/libmudflap.cth/cthfrags.exp: Add -DSTATIC to compiler + flags for static linking permutation. + * testsuite/libmudflap.cth/pass40-frag.c: When -DSTATIC, avoid + some pthreads code that croaks on linux glibc tls. + +2004-01-27 Frank Ch. Eigler + + * testsuite/libmudflap.c/fail31-frag.c, pass45-frag.c: New tests. + +2004-01-15 Frank Ch. Eigler + + * testsuite/libmudflap.c/pass44-frag.c: New test. + +2004-01-12 Frank Ch. Eigler + + * testsuite/libmudflap.c/fail{28,29,30}-frag.c: New tests. + +2004-01-08 Frank Ch. Eigler + + * testsuite/libmudflap.c/pass43-frag.c: Added missing program rc. + +2003-12-11 Frank Ch. Eigler + + * testsuite/libmudflap.c/pass42-frag.c, pass43-frag.c: New tests. + +2003-12-08 Andrew Pinski + + PR libmudflap/12670 + * configure.in: Add check for see if + socklen_t typedef is in sys/socket.h. + * mf-hooks1.c: Add define if socklen_t + is not typedef. + * mf-hooks2.c: Likewise. + * mf-hooks3.c: Likewise. + * config.h.in: Regen. + * configure: Regen. + +2003-12-08 Frank Ch. Eigler + + * mf-runtime.c (__mf_watch_or_not): Tweak tracing message. + * testsuite/libmudflap.c/fail21-frag.c: Defeat aliasing + optimizations. + * testsuite/libmudflap.c/pass25-frag.c: Ditto. + * testsuite/libmudflap.c/pass26-frag.c: Tolerate non-overlapping + (unoptimized) allocation of stack space. + +2003-12-07 Richard Henderson + + * testsuite/libmudflap.c/fail23-frag.c (main): Adjust addend to 11. + * testsuite/libmudflap.c/fail27-frag.c (foo): Mark noinline. + +2003-12-06 Andrew Pinski + + partial PR libmudflap/12670 + * mf-hooks1.c: Respect Darwin checks. Conditionalize POSIX_SOURCE. + * mf-hooks2.c: Likewise. + * mf-hooks3.c: Likewise. + +2003-11-19 Frank Ch. Eigler + + libstdc++/11696 + * mf-runtime.h.in: Switch to #pragma redefine_extname for + symbols interposed at compile time. + * testsuite/libmudflap.c++/pass41-frag.cxx: New test. + + libmudflap/12939 + * mf-hooks2.c (semctl): Tolerate FreeBSD. + + * configure.in: Reorganize check for . + * configure: Regenerated. + +2003-11-04 David Edelsohn + + * mf-runtime.c (_ALL_SOURCE): Define for AIX. + (_LARGE_FILE_API): Define for AIX. + * mf-hooks[123]: Same. + (_XOPEN_SOURCE_EXTENDED): Define to 1 for AIX. + +2003-10-21 David Edelsohn + + * mf-runtime.c (_XOPEN_SOURCE_EXTENDED): Define to 1 for AIX. + +2003-07-29 Frank Ch. Eigler + + 2003-07-29 Gerald Pfeifer + + * configure.in: Update check for union semun. + +2003-07-29 Gerald Pfeifer + + PR other/11673 + * mf-hooks2.c [WRAP_semctl]: Fix check for HAVE_UNION_SEMUN. + +2003-07-29 Frank Ch. Eigler + + PR other/11673 + * configure.in: Add checks for 64-bit LFS functions, struct semun + definition, for BSD compatibility. + * mf-hooks1.c: Respect BSD checks. Conditionalize POSIX_SOURCE. + * mf-hooks2.c: Ditto. Include for bcmp* decls. + * mf-hooks3.c: Ditto. + (pthread_create): Try MAP_ANON on platforms without the MAP_ANONYMOUS + mmap flag. + * configure, config.h.in: Regenerated. + +2003-07-23 Frank Ch. Eigler + + Multithreading fixes: + * mf-runtime.c (__mf_object): Store allocating/deallocating + thread id. + (options): Support new "-thread-stack" option. + Rename "-heur-argv-environ" option to "-heur-stdlib". + Disable "-lc-mask" and "-lc-shift" options. + (__mf_dynamic): Add function pointers for pthread_join/_exit. + (__assert_fail): New self-contained function for glibc. + * mf-hooks3.c: Essentially rewritten, particularly related to + use of __mf_pthread_info array. + (pthread_join, _exit): New hook functions. + * mf-impl.h (BEGIN_PROTECT): Handle starting_p case. + * testsuite/libmudflap.cth/pass40-frag.c: New test. + + Warning cleanups: + * mf-heuristics.c: Add type casts for tracing, sub calls. + * mf-impl.h (BEGIN_PROTECT): Redefine to omit result type. + Update all callers to declare explicit result holder. + (END_PROTECT): Removed. + * testsuite/*/*frags.exp: Clean up default MUDFLAP_OPTIONS. + +2003-07-15 Diego Novillo + + * testsuite/libmudflap.c/fail21-frag.c: Add volatile modifiers. + * testsuite/libmudflap.c/fail15-frag.c: Likewise. + * testsuite/libmudflap.c/fail13-frag.c: Likewise. + +2003-07-04 Frank Ch. Eigler + + * mf-hooks1.c, 2.c, 3.c: New file, splits up content from old ... + * mf-hooks: Removed. + * mf-impl.h (MF_VALIDATE_EXTENT, BEGIN_PROTECT, END_PROTECT): + Move these macros from old mf-hooks.c here. + * Makefile.am: Adapt to split-up hook sources for faster builds. + * Makefile.in: Regenerated. + + * mf-heuristics.c: Remove #if-0 block. + + * mf-impl.h (__mf_state): Reorganize declaration and implementation. + (__mf_starting_p): New state only for use while dlsym bootstrapping. + (CALL_REAL, __mf_init): Corresponding changes. + (TRACE, VERBOSE_TRACE): Include thread id and "mf:" prefix. Update + all callers to remove redundant "mf:" prefix. + * mf-runtime.h.in: #define a few reentrancy macros for libmudflapth. + * mf-hooks3.c: Rewrite chunks to support per-thread __mf_state value. + (__mf_pthread_info): Become a hash table. + + * testsuite/lib/mfdg.exp: Support new "dg-timeout" and + "dg-repetitions" directives to control test case execution. + * testsuite/libmudflap.cth/pass37-frag.c: Add timeout and repeat + options. + * testsuite/libmudflap.cth/pass39-frag.c: Ditto for this new test. + +2003-06-25 Frank Ch. Eigler + + * mf-hooks.c (alloca): Separate into stub. + (__mf_wrap_alloca_indirect): New function. Use CALL_REAL + malloc/free for alloca blocks. + (pthread_create): Tolerate failing pthread_attr_get* calls. + * mf-runtime.c (__mf_fini): Call __mf_wrap_alloca_indirect. + * mf-impl.h (CALL_WRAP): Remove macro. + * testsuite/libmudflap.c/pass21-frag.c: Include . + * testsuite/libmudflap.c/pass23-frag.c: Include more struct + padding for ia64 BIT_FIELD_REF constructs. + +2003-06-19 Frank Ch. Eigler + + * mf-hooks.c (struct pthread_info): Add "thread_errno" field. + (__mf_pthread_spawner, __mf_pthread_cleanup): Use it with GUESS + libmudflap object type. + * mf-runtime.c (__mfu_unregister): Correct cemetary logic to avoid + crashes on unregistering STATIC objects. + +2003-06-17 Frank Ch. Eigler + + Based on patch from Eyal Lebedinsky : + * mf-hooks.c (__mf_pthread_spawner): Register thread errno. + (time, strerror, fopen, fopen64, fclose, fread): New hooks. + (fwrite, fgetc, fgets, getc, gets, ungetc, fputc): New hooks. + (fputs, putc, puts, clearerr, feof, ferror, fileno): New hooks. + (printf, fprintf, sprintf, snprintf, vprintf, vfprintf): New hooks. + (vsprintf, vsnprintf, access, remove, fflush, fseek): New hooks. + (fseeko64, ftell, ftello64, rewind, fgetpos, fsetpos): New hooks. + (stat, stat64, fstat, lstat, mkfifo, setvbuf, setbuf): New hooks. + (setvbuf, opendir, closedir, readdir, recv, recvfrom): New hooks. + (recvmsg, send, sendto, sendmsg, setsockopt, getsockopt): New hooks. + (accept, bind, connect, gethostname, sethostname): New hooks. + (gethostbyname, wait, waitpid, popen, pclose, execve): New hooks. + (execv, execvp, system, dlopen, dlclose, dlerror, dlsym): New hooks. + (semop, semctl, shmctl, shmat, shmdt): New hooks. + * mf-runtime.h.in: Corresponding changes. + * mf-runtime.c (__mf_ini): Register stdio objects. Use STATIC type. + (opts) Rename heur_argv_environ to heur_std_data. + (__mf_wrap_main): Use STATIC type for argv/environ strings. + * Makefile.am: Corresponding changes. + * Makefile.in: Regenerated. + +2003-06-11 Frank Ch. Eigler + + * mf-heuristics.c (__mf_heuristic_check): Disable stack_bounds + heuristic for threaded case, and for non-x86-linux targets. + * mf-hooks.c (__mf_0fn_calloc): Provide a working dummy implementation + for use during pre-main() program startup. + (__mf_0fn_*): Make these functions non-static. + * mf-impl.h (DECLARE, CALL_REAL): Support calls to 0fn backup hook + functions. + * mf-runtime.c (__mf_state): Set initial state to "starting". + (__mf_resolve_single_dynamic): Tolerate repeated calls for same symbol. + (__wrap_main): New function to register argv[] and environ[] strings. + (__mf_ini): Call it. + (*): In all trace functions, use "%p" as formatter for uintptr_t. + + * testsuite/libmudflap.c/pass38-frag.c: New test case. + * testsuite/libmudflap.cth/pass37-frag.c: Improved test. + + * acinclude.m4: Add comments with aoliva's concerns about x86_64 + pass_all. + * aclocal.m4, configure: Regenerated. + +2003-06-04 Frank Ch. Eigler + + * acinclude.m4: Correct typo in AC_MSG_CHECKING. + * aclocal.m4, configure: Regenerated. + +2003-06-03 Frank Ch. Eigler + + * acinclude.m4: Force "pass_all" deplibs_check_method for libtool + for x86_64 target. Disable caching for this value. + * aclocal.m4, configure: Regenerated. + +2003-06-02 Frank Ch. Eigler + + * testsuite/libmudflap.c/pass38-frag.c: Deleted. -fwritable-strings + is about to become deprecated, and its present handling bugs are + unworthy of fixing. + +2003-05-30 Frank Ch. Eigler + + * testsuite/libmudflap.c/pass38-frag.c: New test for + -fwritable-strings. + +2003-05-23 Frank Ch. Eigler + + * mf-runtime.c (__mf_sigusr1_handle): Call unlocked variant of + __mf_report, asserting reentrant calling context. + +2003-05-23 Frank Ch. Eigler + + * mf-hooks.c (realloc): Correct reentrancy logic. + * testsuite/libmudflap.c/hook-allocstuff.c: New test case. + +2003-05-20 Frank Ch. Eigler + + * mf-hooks.c (LIBMUDFLAPTH_THREADS_MAX): New macro, replaces + PTHREAD_THREADS_MAX. Update users. + * mf-runtime.c (__mf_usage): Print [active] instead of [default] + for active options. + * testsuite/Makefile.am (all-local): Prime dejagnu site.exp file + with libmudflapth presence indicator. + * testsuite/Makefile.in: Regenerated. + +2003-05-16 Frank Ch. Eigler + + * Makefile.am (AM_CFLAGS): Remove "-ansi". + * configure.in: Remove silly no-pthreads => no-shared logic. + * Makefile.in, configure: Regenerated. + * mf-heuristics.c (__mf_heuristic_check): Remove reentrancy hacks. + * mf-hooks.c (BEGIN_PROTECT, END_PROTECT): Reorganize reentrancy + code. Count reentrancy events. + (all hook functions): Don't directly manipulate __mf_state variable. + Add TRACE calls to hook functions without them. + * mf-impl.h (LOCKTH): Try to count lock contention events. + (VERBOSE_TRACE, TRACE): Remove reentrancy hacks. + * mf-runtime.c (BEGIN_RECURSION_PROTECT, END_RECURSION_PROTECT): + Reorganize reentrancy code. + (external __mf_ entry points): Use RECURSION_PROTECT mechanism to + identify reentrancy with mutex holding times. + (internal __mfu_ entry points): Remove internal reentrancy code. + (__mf_init): Use ordinary locked calls. + (__mfu_report): Print the two new counts. + * testsuite/lib/libmudflap.exp: Filter out junk ld/pthreads messages. + * testsuite/libmudfap.cth/cthfrags.exp: New test driver. + * testsuite/libmudflap.cth/pass37-frag.c: New pthreads test. + * testsuite/libmudfap.cth/cfrags.exp: Adapt to new libmudflap + option defaults. + +2003-05-09 Frank Ch. Eigler + + * configure.in: Add pthread support, plus glibc and porting hacks. + * Makefile.am (LIBMUDFLAPTH): New conditional, to build -lmudflapth + from objects built into ./pth/. + * mf-runtime.c (__mfu_watch,register,...): Fork new unlocked + functions for internal entry points. Update callers to pick + locked vs. unlocked variants. + (__mf_resolve_single_dynamic): Extend to support symbol versioning + info coming in from a static data structure. + (*): Reorder miscellaneous declarations to group data vs functions. + (__mf_set_default_options): Simplify. + (__mf_usage): Mention threading status of host executable. + * mf-impl.h: Move max/min decls here. Reorganize __mf_dynamic + decls to match above. + (LOCKTH, UNLOCKTH): New macros for Big Libmudflap Lock management. + * mf-heuristics.c: Choose between locked/unlocked calls. Add + some lock/unlock markers. Remove some unused code. + * mf-hooks: Ditto. + (pthread_create): New hook function. + (__mf_pthread_cleanup, _spawner): New helper functions. + * configure. aclocal.m4, config.h.in, Makefile.in: Regenerated. + +2003-05-02 Frank Ch. Eigler + + * testsuite/libmudflap.c/fail27-frag.c: Add more volatile flags. + +2002-04-28 Frank Ch. Eigler + + * Makefile.am (HOOKOBJS): Add *time related hooks. + * configure.in: Look for pthreads.h header. + * mf-hooks.c (asctime, ctime, gmtime, localtime): New wrappers. + * mf-runtime.c: Begin sketching some pthreads support. + (__mf_usage): Check for -lpthread presence. + (__mf_unregister): Confirm matching unregistration base. + (__mf_find_objects_rec): Reduce unnecessary recursion. + * mf-runtime.h.in: Add "nothrow" attribute to functions. Add + #defines for new hook functions. + * mf-impl.h: Corresponding changes. + * config.h.in, configure, Makefile.in: Regenerated. + +2002-04-27 Diego Novillo + + * testsuite/libmudflap.c/fail1-frag.c: Add volatile + modifiers to prevent being optimized away. + * testsuite/libmudflap.c/fail10-frag.c: Likewise. + * testsuite/libmudflap.c/fail13-frag.c: Likewise. + * testsuite/libmudflap.c/fail14-frag.c: Likewise. + * testsuite/libmudflap.c/fail15-frag.c: Likewise. + * testsuite/libmudflap.c/fail2-frag.c: Likewise. + * testsuite/libmudflap.c/fail20-frag.c: Likewise. + * testsuite/libmudflap.c/fail3-frag.c: Likewise. + +2003-04-15 Frank Ch. Eigler + + * Makefile.am (libmudflap_la_LIBADD): Remove -ldl. + * configure.in: Look for uintptr_t and -ldl on target. + * mf-runtime.h.in: Adjust uintptr_t declaration logic. + * Makefile.in, aclocal.m4, configure, config.h.in: Regenerated. + * testsuite/Makefile.in: Regenerated. + * mf-runtime.c (__mf_sigusr1_respond): Tweak declaration and calls + for better C compliance. + +2003-04-15 Frank Ch. Eigler + + * mf-hooks.c (MF_VALIDATE_EXTENT): Remove unnecessary reentrancy + prevention code. + * mf-runtime.c (__mf_set_default_options): Turn off + check-initialization. + (__mf_describe_object): Shorten description. + * testsuite/libmudflap.c/fail25-frag.c: Turn on check-initialization. + +2003-04-07 Frank Ch. Eigler + + * mf-hooks.c (__mf_0fn_mmap): Correct return value, as per . + +2003-04-02 Frank Ch. Eigler + + * mf-hooks.c (BEGIN_PROTECT): Handle startup-time reentrant + calls specially. + (__mf_0fn_malloc ... _munmap): New dummy backup calls. + * mf-impl.h (CALL_BACKUP): New macros. + * mf-runtime.c (__mf_init): Tweak __mf_state during startup. + +2003-03-31 Frank Ch. Eigler + + * Makefile.am (AM_CFLAGS): Remove optimization flags. + (HOOKOBJS): Remove dlopen hook. + (libmudflap_la_LIBADD): Add -ldl. + * mf-hooks.c (dlopen): Remove hook. + * mf-impl.h (__mf_dynamic): Ditto. + * mf-runtime.c (__mf_resolve_dynamics): Ditto. + * Makefile.in: Regenerated. + +2003-03-28 Frank Ch. Eigler + + * configure.in: Check for target gettimeofday, signal, some headers. + * mf-impl.h (__mf_opts): Add new "sigusr1_report" field. Comment + out inop multi_threaded field. + * mf-runtime.c (options): Handle new "-sigusr1-report" option. + (__mf_set_options): Correct handling of "-help". + (__mf_sigusr1_respond): New function to manage SIGUSR1 response. + (__mf_check, __mf_register, __mf_unregister): Call it. + (__mf_insert_new_object, __mf_unregister): Respect HAVE_GETTIMEOFDAY. + (__mf_report_leaks): Make callable + (__mf_tree_analyze): Traverse in-order. Accumulate address bit + distribution statistics. + (__mf_adapt_cache): Rewrite shift guessing logic based on address + bit distributions. + * config.h.in, configure: Regenerated. + * testsuite/libmudflap.c/fail27-frag.c: New test. + * testsuite/libmudflap.c/pass36-frag.c: New test. + +2003-03-11 Frank Ch. Eigler + + * mf-runtime.h.in: Tweak. + * Makefile.am, configure.in: Tweak mf-runtime.h generation some more. + Don't use intermediate files nor AC_OUTPUT-time postprocessing. + * Makefile.in, testsuite/Makefile.in, configure: Regenerated. + +2003-03-10 Frank Ch. Eigler + + * configure.in: Tweak generation of mf-runtime.h some more. It + needs to work from both config.status and configure. + * configure: Regenerated. + +2003-03-10 Frank Ch. Eigler + + * Makefile.am: Reorganize hook file building. Add auto dependencies. + * configure.in: Tweak generation of mf-runtime.h. + * mf-runtime.h.in: Add new __MF_TYPE_HEAP_I. + * mf-hooks.c (*): Adapt to initialized-heap object type. + * mf-impl.h: Tweak cemetary boundaries. + * mf-runtime.c (__mf_check): Adapt to new initialized-heap object + type. + (__mf_insert_new_object, __mf_register, __mf_unregister): Ditto. + (__mf_describe_object, __mf_report_leaks, __mf_violation): Ditto. + * testsuite/lib/libmudflap.exp (includes): Include build tree. + * testsuite/libmudflap.c/pass{26,5}: Further adapt to initialization + checking. + * testsuite/.../fail{25,26}-frag.c: New tests. + * testsuite/.../pass{32,33,34,35}-frag.c: New tests. + * Makefile.in, configure: Regenerated. + +2003-03-05 Frank Ch. Eigler + + * mf-runtime.c (__mf_set_default_options): Turn on initialization + checking by default. + (__mf_insert_new_object): As a temporary hack, assume that new + objects registered on the stack start out initialized. + * testsuite/libmudflap.c/fail9,pass23,pass[6789]-*: Initialize + heap objects by hand. + +2003-03-05 Frank Ch. Eigler + + Switch to macro-style hooks for str*/mem*/b* functions. + * mf-runtime.h.in (__MF_TYPE_*): Moved some internal values out. + (mem*, str*, b*): Added macro-style hooks for _MUDFLAP case. + * mf-runtime.c: #include config.h to enable glibc backtraces again. + (__mf_set_default_options): Turn off heur_proc_map. + (*): Adapt to to macro-style hook functions. + (__mf_object_dead_head, __mf_object_cemetary): Correct bounds. + (__mf_check, __mf_register, __mf_unregister): Tweak tracing message. + (__mf_violation): Handle __MF_VIOL_WATCH. + * mf-impl.h (__MF_TYPE_*): Moved these internal values here. + (__mf_dynamic): Removed mem*/str*/b* functions. + (TRACE, VERBOSE_TRACE): Add reentrancy locking. + (WRAPPER2): New macro for macro-style hooks. + * mf-hooks.c: Convert mem*/str*/b* functions to simpler + macro-style hooks. + (BEGIN_PROTECT): Tweak tracing vs reentrancy-lock ordering. + * mf-heuristics.c: Adapt to macro-style hook functions. + Correct some comments. + * testsuite/lib/mfdg.exp (dg-test): Simplify result string for + output pattern tests. + * testsuite/libmudflap.c/fail[89]-frag.c: Elaborate output test. + * testsuite/libmudflap.c++/c++frags.exp: Enable non-static tests. + +2003-02-28 Frank Ch. Eigler + + * testsuite/libmudflap.c/fail23-frag.c, pass30-frag.c: New tests + for global array registration. + * testsuite/libmudflap.c++/fail24-frag.cxx, pass31-frag.cxx: Ditto. + * testsuite/libmudflap.c++/c++frags.exp: Tweak -static multilib hack. + +2003-02-27 Frank Ch. Eigler + + * Makefile.am: Add gross make bug workarounds. Tweaked + SUBDIRS and AM_CFLAGS. + * Makefile.in: Regenerated. + +2003-02-26 Frank Ch. Eigler + + Switch to dejagnu. + * configure.in (AC_PROG_CXX): Don't look for C++ any more. + * Makefile.am (TESTS): Remove simple automake testing. + * configure, Makefile.in: Regenerated. + (SUBDIRS): Include new testsuite/ directory. + * tests/*: Removed all files; moved bulk under: + * testsuite/*: New subdirectory tree. + * testsuite/libmudflap.c/cfrags.exp: New file, C test driver. + * testsuite/libmudflap.c++/c++frags.exp: New file, C++ test driver. + * testsuite/lib/libmudflap.exp: New file, derived from libstdc++. + * testsuite/lib/mfdg.exp: New file, derived from dejagnu. + * testsuite/config/default.exp: New file. + * testsuite/Makefile.am, Makefile.in: New files. + +2003-01-29 Frank Ch. Eigler + + * Makefile.am (TESTS_ENVIRONMENT): Remove redundant "-mode-check". + (TESTS): Add fail22 and pass29 tests. + * mf-runtime.h.in: Change API to take void*/size_t region parameters. + Add new access-type parameter for __mf_check. Move __MF_VIOL* out. + * mf-impl.h: Corresponding changes. Update CLAMP* macros for void* + values. Move __MF_VIOL* here. + * mf-runtime.c (*): Adapt to void*/size_t API in mf-runtime.h. + (check_initialization): New field in __mf_opts. Default off. + (read_count,write_count): New fields in __mf_object. + (__mf_check): Implement basic initialization checking. + (__mf_insert_new_object): Assume STATIC|GUESS regions are initialized. + (__mf_describe_object): Print new fields. + (__mf_violation): Identify check/read vs. check/write in messages. + * test/pass29-frag.c, test/fail22-frag.c: Basic tests for new + "-check-initialized" mudflap option. + * test/pass25-frag.c, test/fail21-frag.c: Adapt to API changes. + * mf-hooks.c (MF_VALIDATE_EXTENT): Add new access-type parameter. + Drop __FILE__/__LINE__ hack. Update callers. + (*): Adapt to new mf-runtime.h API. + * Makefile.in: regenerated. + +2003-01-24 Frank Ch. Eigler + + * configure.in: Build mf-runtime.h a more proper way. + * mf-hooks.c (strdup, strndup): Correct reentrancy logic. + * mf-runtime.c (verbose_violations): Turn on by default. + * mf-runtime.h.in: Remove some miscellaneous stuff ... + * mf-impl.h: ... and move it here. + * configure: Regenerated. + +2003-01-22 Frank Ch. Eigler + + * configure.in: Look for C++ compiler. + * test/*-frag.c, mf-driver.c: Reformatted with GNU indent and + fixed type warnings when built with C++. + * test/pass27-frag.cxx, pass28-frag.cxx: New C++ tests. + * Makefile.am (TESTS): Run them. + (*) Add new rules for building and running C++ tests. + (TESTFLAGS): Set new default to avoid libstdc++-v3 shlib issues. + * mf-runtime.h.in: Protect with extern "C". + * Makefile, configure: Regenerated. + +2003-01-06 Frank Ch. Eigler + + Portability improvements. + * configure.in: Look for glibc backtrace headers/functions. + * mf-hooks.c: Don't include any more. + * mf-runtime.c (__mf_set_options): Call more stdlib functions + via CALL_REAL. + (__mf_backtrace): Provide alternate baby implementation in + absence of glibc. + * test/mf-driver.c: Portability tweaks. + * acinclude.m4: New file, containing top level libtool.m4. + * aclocal.m4, configure, Makefile.in, config.h.in: Regenerated. + +2002-12-19 Frank Ch. Eigler + + * mf-runtime.h.in (HAVE_UINTPTR_T): Define unconditionally. + +2002-11-08 Frank Ch. Eigler + + * mf-runtime.c (options): Add new "wipe-heap", "wipe-stack" + options. + (__mf_unregister): Implement stack/heap object wiping. + (__mf_set_options): Renamed from __mf_process_opts. + (__mf_uncache_object): Change arg type, correct callers. + * mf-impl.h: Corresponding changes. + * mf-hooks.c (realloc): Save/restore heap-wiping flag. + * mf-runtime.h.in (__mf_set_options): Extend public API. + * test/pass26-frag.c: New test for stack wiping. + * Makefile.am (TESTS): Run it. + * Makefile.in: Regenerated. + +2002-11-07 Frank Ch. Eigler + + * mf-runtime.h.in (__mf_watch, __mf_unwatch): Extend public API. + * mf-runtime.c (__mf_object_t): Add watching_p field. + (__mf_watch_or_not): New function to implement + object watch flagging. + (__mf_watch, __mf_unwatch): New wrappers for above. + (__mf_check, __mf_describe_object): Handle objects with watching_p. + (__mf_count_violation): Enlarge array. + (__mf_uncache_object): Renamed from __mf_remove_old_object. Don't + unlink object. Clear cache properly. + (__mf_unregister): Unlink object explicitly before uncaching. + * test/fail21-frag.c, pass25-frag.c: New tests. + * Makefile.in, aclocal.m4: Regenerated. + +2002-11-05 Frank Ch. Eigler + + * test/fail20-frag.c: New test for NULL pointer dereferencing. + * Makefile.am (TESTS): Add it. + * test/pass-stratcliff.c: Add decls of stpcpy. + * configure.in: Test for . Generate mf-runtime.h in + build tree from config.h and new file mf-runtime.h.in. + * mf-runtime.h.in: Renamed from mf-runtime.h. Tweak uintptr_t decl. + * Makefile.in, configure, config.h.in: Regenerated. + * mf-hooks.c: Add #undef for wrapped glibc str*/mem* macros. + * mf-runtime.c (options, __mf_set_default_options): Support new + default "abbreviate" option. + (__mf_object.description_epoch): New field. + (__mf_describe_object): Conditionally abbreviate objects already + displayed in current epoch. Accept NULL input to increment epoch. + (__mf_fini, __mf_ini): Reset description epoch. + (__mf_register, __mf_unregister, __mf_adapt_cache, __mf_init): Ensure + that NULL pointer slot in lookup cache is invalidated. Register a + NOACCESS region around NULL. + * mf-impl.h: Corresponding changes. + +2002-10-16 Frank Ch. Eigler + + * test/fail19-frag.c, pass24-frag.c, pass-stratcliff.c: New tests. + * Makefile.am: Run them. Install mf-runtime.h. + * Makefile.in: Regenerated. + * mf-hooks.c: Add some markers for more missing functions. + * mf-runtime.c (__mf_adapt_cache): Experiment with a utilization-based + statistic to tune tune cache size (mask). + +2002-10-01 Frank Ch. Eigler + + * test/pass23-frag.c: New test for bit_field_ref expressions. + * Makefile.am, Makefile.in: Add new test. + * mf-hooks.c (mmap, munmap): Rewrite to track individual pages. + (MF_VALIDATE_EXTENT): Accept zero-size mem/str operations. + * mf-runtime.c (__mf_init): Register errno global. + (__mf_find_object): Removed function. + (__mf_check): Rewrite logic to support accesses across some + contiguous but distinctly registered objects. + (__mf_remove_old_object): Tolerate cache entries that span + contiguous objects. + +2002-09-30 Frank Ch. Eigler + + * test/pass21-frag.c, pass22-frag.c: New tests: alloca, bitfields. + * Makefile.am, Makefile.in: Run new tests. + * mf-hooks.c (alloca): Correct stack direction logic. + +2002-09-26 Frank Ch. Eigler + + * mf-impl.h (adapt_cache): New option. + * mf-runtime.c (__mf_set_default_options): Set its default value. + Tweak the tree_aging parameter down. + (__mf_check): Maintain separate counter for cache-adaptation. + (__mf_tree_analyze): New function to collect object tree stats. + (__mf_adapt_cache): New function to automate cache parameters. + +2002-09-24 Frank Ch. Eigler + + * mf-heuristics.c (__init_misc, __mf_heuristic_check): Add + hypothetical #if-0'd argv/envp region registration. + * mf-runtime.c (__mf_init): Add kludged form of above. + (*) Add "heur_argv_environ" flag, default on, to govern this. + * mf-impl.h: Corresponding changes. + +2002-09-20 Frank Ch. Eigler + + * test/fail18-frag.c: New test file for NOACCESS regions. + * Makefile.am (TESTS): Add new test. + * Makefile.in: Regenerated. + + * mf-heuristics.c (__mf_heuristics_check): Correct deja_vu logic. + * mf-impl.h (tree_aging): Add new mudflap_option, default 1000000. + (optimize_object_tree): Remove unused mudflap_option. + * mf-runtime.h (__MF_TYPE_NOACCESS): New region type. Add printing + support throughout. Use .._MAX_CEM for cemetary upper bound. + * mf-runtime.c (__mf_init): Register __mf_* globals as NOACCESS + regions. + (__mf_object): Add new liveness field for use by tree aging. + (__mf_check): Trigger tree aging when needed. + (__mf_age_tree): New function to decay liveness field. + (__mf_find_objects_rec): Use liveness field to rotate tree. + (__mf_insert_new_object): Only provide backtrace for HEAP objects. + (__mf_unregister): Ditto. + (__mf_register): Tweak duplicate-static message. + (__mf_violation: Tweak nearby-object counter printing. + +2002-09-16 Frank Ch. Eigler + + * test/pass20-frag.c: New test file. + * Makefile.am (TESTS): Reorganize. Add pass20 test. + * Makefile.in: Regenerated. + + * mf-impl.h (TRACE_IN, TRACE_OUT): Remove macros. Update callers. + * mf-hooks.c (BEGIN_PROTECT): Add hook tracing here. + * mf-heuristic.c (__mf_heuristic_check): Track seen /proc/self/map + entries to avoid repeat registration. + * mf-runtime.c (__mf_object_cemetary): Don't bother bury GUESS regions. + (__mf_register, __mf_unregister): Rewrite GUESS handling logic. + +2002-09-09 Frank Ch. Eigler + + * Makefile.am: Create test sources with #include, not cat>>. + * Makefile.in: Regenerated. + * test/buildtest.sh: Removed. + * test/driver.c (abort_handler, main): Be quiet. + +2002-09-06 Frank Ch. Eigler + + * test/pass18-frag.c, pass19-frag.c: New tests. + * Makefile.am (check): Run them. Rebuild test programs each time. + * Makefile.in: Regenerated. + +2002-09-06 Frank Ch. Eigler + + * mf-runtime.c (__mf_register): Correct SEGV-inducing error in + overlapping object search. + (__mf_violation): Likewise for nearby objects. + Improve nearby-object listing. + + cleanup: + * mf-runtime.c, mf-hooks.c: Remove "{{{"/"}}}" folding marks. + * mf-heuristics.c (__mf_heuristic_check): Tweak message. + +2002-09-03 Frank Ch. Eigler + + alloca support: + * Makefile.am (AM_CFLAGS): New definition of needed settings. + (HOOKOBJS): Add alloca-hook.o. + * mf-hooks.c (alloca): New function to implement alloca in libiberty + style. + * mf-runtime.c (__mf_report): Call alloca(0) to flush remaining blocks. + (__mf_backtrace): Reimplement without using alloca. + * Makefile.in: Regenerated. + + cleanup: + * mf-hooks.c: Use VERBOSE_TRACE throughout instead of fprintf(stderr). + Correct signedness bugs in length-tracking variables. + * mf-impl.h: Make options unsigned. + (CALL_WRAP): New macro to parallel CALL_REAL(). + (DECLARE): Remove erroneous ";" at end. + * mf-runtime.c, mf-hooks.c, mf-heuristics.c: Replace remaining %p + formatting specs with %08lx. Correct several compiler warnings. + +2002-08-28 Frank Ch. Eigler + + * mf-runtime.c (__mf_violation): Try harder to locate nearby objects. + +2002-08-27 Frank Ch. Eigler + + libmudflap hook breakup: + * Makefile.am (TESTS_ENVIRONMENT): Add ../../gcc to LD_LIBRARY_PATH + for libgcc_s. + (TESTS): Make dependent on libmudflap. + (HOOKOBJS): Break up mf-hooks.o into many little hook objects, + compiled from segments of mf-hooks.c. + * mf-hooks.c: Corresponding changes: wrap each function in + #ifdef/#endif. + * Makefile.in: Regenerated. + + Heuristics reorganization: + * mf-heuristics.c (__mf_register_ro_sections, __mf_init_heuristics): + Remove these functions. Update callers. + (__mf_heuristic_check): Incorporate all the various heuristics. + Encode cacheability/retry judgement into trinary return value. + Separate start-end logic into a separate fallback heuristic. Only + register relevant /proc/self/map segments. + * mf-impl.h: Corresponding changes. + * mf-runtime.c (__mf_check): Reorganize heuristics fallback logic. + (__mf_init): Don't call __mf_init_heuristics. + + Tracing cleanup: + * mf-heuristics.c, mf-runtime.c: Use new MUDFLAP_OPTION + "-verbose-trace" to emit all tracing messages other than those of + basic public api. Eliminate some duplicate/excessive messages. + * mf-runtime.h: Corresponding changes. + +2002-08-27 Graydon Hoare + + * mf-impl.h (WRAPPER): Change to create linker aliases for __wrap + and __real when compiled with -DPIC. + * mf-hooks.c (WRAPPER): Change all uses of WRAPPER macro slightly. + * Makefile.am (AUTOMAKE_OPTIONS): Fix LD_LIBRARY_PATH for tests. + * Makefile.in: Regenerate. + +2002-08-26 Graydon Hoare + + * mf-impl.h: New file, private implementation header. + * mf-runtime.h: Reorganize a bit. + (CLAMPSZ): Fix arithmetic. + (__MF_CACHE_MISS_P): Fix arithmetic. + * mf-runtime.c: Reorganize a bit. + (__mf_dynamic): New structure. + (resolve_single_dynamic): New function. + (__mf_resolve_dynamics): New function. + (__mf_init): Initialize dynamic wrappers. + * mf-hooks.c: Macro-ize __real calls. + Clamp various bits of arithmetic. + Add explicit __mf_check call contexts. + * Makefile.am: Add dependencies on mf-impl.h + * Makefile.in: Regenerate. + * configure.in: Comment out shared override. + * configure: Regenerate. + +2002-08-22 Graydon Hoare + + * mf-runtime.c (__mf_process_opts): Sanity-check free_queue_length. + (__mf_check): Re-inialize and check heuristics before violation. + (__mf_register): Permit updating pure-guess regions. + * mf-hooks.c (__wrap_free): Correct some free queue logic. + (__wrap_dlopen): New wrapper function. + (__wrap_mmap): New wrapper function. + (__wrap_munmap): New wrapper function. + * mf-heuristics.c (__mf_register_ro_sections): Register *all* regions + which are not stack addresses. + (is_stack_address): New function. + (__mf_init_heuristics): Save and restore state, always initialize with + "starting" state. + +2002-08-21 Frank Ch. Eigler + + * mf-hooks.c (MF_VALIDATE_EXTENT): Rewrite to correct off-by-one + error. Pass location string. + (wrap_strcpy, wrap_strncpy): Remove extra %s in trace strings. + * mf-runtime.c (options): Add lc-mask, lc-shift options. + (__mf_process_opts): Apply some sanity checking for lc-mask. + (__mf_check, __mf_violation): Take new location-string argument. + Update callers to pass NULL if necessary. + (__mf_backtrace): New smart backtracer function. Calls replace + several ad-hoc blocks elsewhere. + (__mf_describe_object): Remove bad reentrancy test. Improve + tracing message. + * mf-runtime.h: Corresponding changes. Public/private markup. + (__MF_CACHE_MISS_P): New macro. + +2002-08-20 Graydon Hoare + + * mf-runtime.h: New option: stack_bound (heuristic). + Move some macros out of implementation files. + * mf-runtime.c: New option string: -stack-bound. + Unify recursion protection with hooks. + Add more logging. + (__mf_check): Call __mf_heuristic_check. + (__mf_process_opts): Fix "no-" processing. + * mf-heuristics.c (__mf_heuristic_check): New function. + * mf-hooks.c: Much off-by-one fixing, recursion protection. + +2002-08-20 Frank Ch. Eigler + + Option parsing improvements, region splitting bug fixes: + * mf-heuristics.c (__mf_register_ro_sections): Add warned casts. + * mf-runtime.h (heur_proc_map): New libmudflap option. + * mf-runtime.c (__mf_set_default_options): Set it. + (__mf_usage): Print default values/status. + (__mf_process_opts): Support general "no-" option string prefix. + (__mf_init): Print __mf_usage on unknown-option error. + (__mf_register): Print trace message up front. + Correct region splitting logic for case where a subregion disappears. + Correct memory leak. + (__mf_violation): Make even basic message conditional on option. + + Build cleanup: + * Makefile.am (TESTS_ENVIRONMENT): Add -no-heur-proc-map. + (clean-local): New target. + (test/*x rules): Add -g CFLAGS. + (CFLAGS): Add -freorder-blocks. + (MFCONFIG_CFLAGS, INCLUDE): Remove unneeded settings. + * Makefile.in: Regenerated. + * Makefile, mf-config.h: Removed files. + +2002-08-16 Graydon Hoare + + * mf-runtime.c (__mf_insert_new_object): Factor out of + __mf_register. + (__mf_remove_old_object): Factor out of __mf_unregister. + (__mf_register): Handle guessed regions, splitting + guesses when new registrations arrive. + (__mf_unregister): Do not unregister guesses. + * mf-runtime.h: Move convenience macros around, + declare new option fields. Add __MF_TYPE_GUESS. + * mf-hooks.c (__wrap_*alloc): Use crumple zones. + (__wrap_free): Call __real_free for deferred frees. + * Makefile.am: Add more tests, fix dependency. + * Makefile.in: Regenerate. + * test/pass[13..17]-frag.c: New testcases. + * test/fail[13..17]-frag.c: New testcases. + +2002-08-15 Graydon Hoare + + * mf-heuristics.c: New file. + * mf-runtime.c (options): Add -trace-calls option. + (__mf_init): Call __mf_init_heuristics. + +2002-08-14 Graydon Hoare + + * Makefile.am (TESTS): Add testsuite support. + * Makefile.in: Regenerate. + * test/mf-driver.c: New file. + * test/buildtest.sh: New file. + * test/passNN-frag.c: New testcases. + * test/failNN-frag.c: New testcases. + +2002-08-14 Graydon Hoare + + * mf-hooks.c: Change __real_strlen() to __real_strlen()+1 when + verifying non-size-limited string extents. + +2002-08-14 Frank Ch. Eigler + + * mf-hooks.c: Make __wrap string* functions use __real_str[n]len + instead of plain str[n]len for internal checks. + * mf-runtime.c (__mf_violation): Print optional stack traceback. + +2002-08-14 Frank Ch. Eigler + + * mf-hooks.c: Remove #if-0 around hooks that are now ld-wrapped. + +2002-08-13 Graydon Hoare + + * mf-runtime.c: Rework configuration to operate on + environment variable options rather than #defines + (__mf_violation): Add simple fork-a-gdb violaiton mode. + (__mf_init): Set static __mf_active_p flag on startup, + to inhibit mudflap wrap-based checking during crt0.s. + * mf-runtime.h: Declare options structure. + * mf-hooks.c: New wrappings for mem*, b*, str* + libc functions (temporarily #if 0-ed out). + +2002-08-12 Frank Ch. Eigler + + * Makefile.am, configure.in: New files. + * Makefile.in, Makefile, configure, config.h.in: New generated files. + * stamp-h.in, aclocal.m4: Ditto. + +2002-08-08 Frank Ch. Eigler + + * Makefile: New file. + * mf-config.h: New file: runtime configuration. + * mf-hooks.c: New file: interposed libc functions. + * mf-runtime.c: New file: bulk of runtime. + * mf-runtime.h: New file: public functions. + diff --git a/libmudflap/Makefile.am b/libmudflap/Makefile.am new file mode 100644 index 00000000000..c5a07490f26 --- /dev/null +++ b/libmudflap/Makefile.am @@ -0,0 +1,388 @@ +## Makefile for the toplevel directory of the mudflap library. +## +## Copyright (C) 2002, 2003 +## Free Software Foundation, Inc. +## + +AUTOMAKE_OPTIONS = 1.3 foreign +MAINT_CHARSET = latin1 +SUBDIRS = testsuite + +AM_CFLAGS = -Wall + +if LIBMUDFLAPTH +libmudflapth = libmudflapth.la +else +libmudflapth = +endif + +lib_LTLIBRARIES = libmudflap.la $(libmudflapth) +include_HEADERS = mf-runtime.h + +libmudflap_la_SOURCES = \ + mf-runtime.c \ + mf-heuristics.c + +HOOK1OBJS = \ + malloc-hook.lo \ + free-hook.lo \ + calloc-hook.lo \ + realloc-hook.lo \ + mmap-hook.lo \ + munmap-hook.lo \ + alloca-hook.lo + +HOOK2OBJS = \ + memcpy-hook.lo \ + memmove-hook.lo \ + memset-hook.lo \ + memcmp-hook.lo \ + memchr-hook.lo \ + memrchr-hook.lo \ + strcpy-hook.lo \ + strncpy-hook.lo \ + strcat-hook.lo \ + strncat-hook.lo \ + strcmp-hook.lo \ + strcasecmp-hook.lo \ + strncmp-hook.lo \ + strncasecmp-hook.lo \ + strdup-hook.lo \ + strndup-hook.lo \ + strchr-hook.lo \ + strrchr-hook.lo \ + strstr-hook.lo \ + memmem-hook.lo \ + strlen-hook.lo \ + strnlen-hook.lo \ + bzero-hook.lo \ + bcopy-hook.lo \ + bcmp-hook.lo \ + index-hook.lo \ + rindex-hook.lo \ + asctime-hook.lo \ + ctime-hook.lo \ + gmtime-hook.lo \ + localtime-hook.lo \ + time-hook.lo \ + strerror-hook.lo \ + fopen-hook.lo \ + fclose-hook.lo \ + fread-hook.lo \ + fwrite-hook.lo \ + fgetc-hook.lo \ + fgets-hook.lo \ + getc-hook.lo \ + gets-hook.lo \ + ungetc-hook.lo \ + fputc-hook.lo \ + fputs-hook.lo \ + putc-hook.lo \ + puts-hook.lo \ + clearerr-hook.lo \ + feof-hook.lo \ + ferror-hook.lo \ + fileno-hook.lo \ + printf-hook.lo \ + fprintf-hook.lo \ + sprintf-hook.lo \ + snprintf-hook.lo \ + vprintf-hook.lo \ + vfprintf-hook.lo \ + vsprintf-hook.lo \ + vsnprintf-hook.lo \ + access-hook.lo \ + remove-hook.lo \ + fflush-hook.lo \ + fseek-hook.lo \ + ftell-hook.lo \ + rewind-hook.lo \ + fgetpos-hook.lo \ + fsetpos-hook.lo \ + stat-hook.lo \ + fstat-hook.lo \ + lstat-hook.lo \ + mkfifo-hook.lo \ + setvbuf-hook.lo \ + setbuf-hook.lo \ + opendir-hook.lo \ + closedir-hook.lo \ + readdir-hook.lo \ + recv-hook.lo \ + recvfrom-hook.lo \ + recvmsg-hook.lo \ + send-hook.lo \ + sendto-hook.lo \ + sendmsg-hook.lo \ + setsockopt-hook.lo \ + getsockopt-hook.lo \ + accept-hook.lo \ + bind-hook.lo \ + connect-hook.lo \ + gethostname-hook.lo \ + sethostname-hook.lo \ + gethostbyname-hook.lo \ + wait-hook.lo \ + waitpid-hook.lo \ + popen-hook.lo \ + pclose-hook.lo \ + execve-hook.lo \ + execv-hook.lo \ + execvp-hook.lo \ + system-hook.lo \ + dlopen-hook.lo \ + dlerror-hook.lo \ + dlsym-hook.lo \ + dlclose-hook.lo \ + fopen64-hook.lo \ + stat64-hook.lo \ + fseeko64-hook.lo \ + ftello64-hook.lo \ + semop-hook.lo \ + semctl-hook.lo \ + shmctl-hook.lo \ + shmat-hook.lo \ + shmdt-hook.lo +HOOK3OBJS = + +$(HOOK1OBJS): mf-hooks1.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks1.c -o $@ +$(HOOK2OBJS): mf-hooks2.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks2.c -o $@ +$(HOOK3OBJS): mf-hooks3.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks3.c -o $@ + +# Hook objects only for libmudflapth use +PTHHOOK1OBJS= \ + pth/malloc-hook.lo \ + pth/free-hook.lo \ + pth/calloc-hook.lo \ + pth/realloc-hook.lo \ + pth/mmap-hook.lo \ + pth/munmap-hook.lo \ + pth/alloca-hook.lo + +PTHHOOK2OBJS= \ + pth/memcpy-hook.lo \ + pth/memmove-hook.lo \ + pth/memset-hook.lo \ + pth/memcmp-hook.lo \ + pth/memchr-hook.lo \ + pth/memrchr-hook.lo \ + pth/strcpy-hook.lo \ + pth/strncpy-hook.lo \ + pth/strcat-hook.lo \ + pth/strncat-hook.lo \ + pth/strcmp-hook.lo \ + pth/strcasecmp-hook.lo \ + pth/strncmp-hook.lo \ + pth/strncasecmp-hook.lo \ + pth/strdup-hook.lo \ + pth/strndup-hook.lo \ + pth/strchr-hook.lo \ + pth/strrchr-hook.lo \ + pth/strstr-hook.lo \ + pth/memmem-hook.lo \ + pth/strlen-hook.lo \ + pth/strnlen-hook.lo \ + pth/bzero-hook.lo \ + pth/bcopy-hook.lo \ + pth/bcmp-hook.lo \ + pth/index-hook.lo \ + pth/rindex-hook.lo \ + pth/asctime-hook.lo \ + pth/ctime-hook.lo \ + pth/gmtime-hook.lo \ + pth/localtime-hook.lo \ + pth/time-hook.lo \ + pth/strerror-hook.lo \ + pth/fopen-hook.lo \ + pth/fclose-hook.lo \ + pth/fread-hook.lo \ + pth/fwrite-hook.lo \ + pth/fgetc-hook.lo \ + pth/fgets-hook.lo \ + pth/getc-hook.lo \ + pth/gets-hook.lo \ + pth/ungetc-hook.lo \ + pth/fputc-hook.lo \ + pth/fputs-hook.lo \ + pth/putc-hook.lo \ + pth/puts-hook.lo \ + pth/clearerr-hook.lo \ + pth/feof-hook.lo \ + pth/ferror-hook.lo \ + pth/fileno-hook.lo \ + pth/printf-hook.lo \ + pth/fprintf-hook.lo \ + pth/sprintf-hook.lo \ + pth/snprintf-hook.lo \ + pth/vprintf-hook.lo \ + pth/vfprintf-hook.lo \ + pth/vsprintf-hook.lo \ + pth/vsnprintf-hook.lo \ + pth/access-hook.lo \ + pth/remove-hook.lo \ + pth/fflush-hook.lo \ + pth/fseek-hook.lo \ + pth/ftell-hook.lo \ + pth/rewind-hook.lo \ + pth/fgetpos-hook.lo \ + pth/fsetpos-hook.lo \ + pth/stat-hook.lo \ + pth/fstat-hook.lo \ + pth/lstat-hook.lo \ + pth/mkfifo-hook.lo \ + pth/setvbuf-hook.lo \ + pth/setbuf-hook.lo \ + pth/opendir-hook.lo \ + pth/closedir-hook.lo \ + pth/readdir-hook.lo \ + pth/recv-hook.lo \ + pth/recvfrom-hook.lo \ + pth/recvmsg-hook.lo \ + pth/send-hook.lo \ + pth/sendto-hook.lo \ + pth/sendmsg-hook.lo \ + pth/setsockopt-hook.lo \ + pth/getsockopt-hook.lo \ + pth/accept-hook.lo \ + pth/bind-hook.lo \ + pth/connect-hook.lo \ + pth/gethostname-hook.lo \ + pth/sethostname-hook.lo \ + pth/gethostbyname-hook.lo \ + pth/wait-hook.lo \ + pth/waitpid-hook.lo \ + pth/popen-hook.lo \ + pth/pclose-hook.lo \ + pth/execve-hook.lo \ + pth/execv-hook.lo \ + pth/execvp-hook.lo \ + pth/system-hook.lo \ + pth/dlopen-hook.lo \ + pth/dlerror-hook.lo \ + pth/dlsym-hook.lo \ + pth/dlclose-hook.lo \ + pth/fopen64-hook.lo \ + pth/stat64-hook.lo \ + pth/fseeko64-hook.lo \ + pth/ftello64-hook.lo \ + pth/semop-hook.lo \ + pth/semctl-hook.lo \ + pth/shmctl-hook.lo \ + pth/shmat-hook.lo \ + pth/shmdt-hook.lo + +PTHHOOK3OBJS= \ + pth/pthreadstuff-hook.lo + + +clean-local: + rm -f pth/*.o pth/*.lo + +libmudflapth_la_SOURCES = +pth/mf-runtime.lo: mf-runtime.c mf-runtime.h mf-impl.h + $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-runtime.c -o $@ +pth/mf-heuristics.lo: mf-heuristics.c mf-runtime.h mf-impl.h + $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-heuristics.c -o $@ +$(PTHHOOK1OBJS): mf-hooks1.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks1.c -o $@ +$(PTHHOOK2OBJS): mf-hooks2.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks2.c -o $@ +$(PTHHOOK3OBJS): mf-hooks3.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks3.c -o $@ + +libmudflap_la_LIBADD = $(HOOK1OBJS) $(HOOK2OBJS) $(HOOK3OBJS) +libmudflap_la_DEPENDENCIES = $(libmudflap_la_LIBADD) + +libmudflapth_la_LIBADD = pth/mf-runtime.lo pth/mf-heuristics.lo \ + $(PTHHOOK1OBJS) $(PTHHOOK2OBJS) $(PTHHOOK3OBJS) +libmudflapth_la_DEPENDENCIES = $(libmudflapth_la_LIBADD) + + + +# XXX hack alert +# From libffi/Makefile.am + +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "JC1FLAGS=$(JC1FLAGS)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "prefix=$(prefix)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "CC=$(CC)" \ + "CXX=$(CXX)" \ + "LD=$(LD)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "NM=$(NM)" \ + "PICFLAG=$(PICFLAG)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" + +MAKEOVERRIDES= + +# Multilib support variables. +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = +MULTIDO = true +MULTICLEAN = true + +# Multilib support. +.PHONY: all-multi mostlyclean-multi clean-multi distclean-multi \ + maintainer-clean-multi + +all-recursive: all-multi +install-recursive: install-multi +mostlyclean-recursive: mostlyclean-multi +clean-recursive: clean-multi +distclean-recursive: distclean-multi +maintainer-clean-recursive: maintainer-clean-multi + +all-multi: + : $(MAKE) ; exec $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do +install-multi: + $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do +mostlyclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean +clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean +distclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean +maintainer-clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean + + +## ################################################################ + diff --git a/libmudflap/Makefile.in b/libmudflap/Makefile.in new file mode 100644 index 00000000000..c21b2dc335f --- /dev/null +++ b/libmudflap/Makefile.in @@ -0,0 +1,918 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AS = @AS@ +CC = @CC@ +CPP = @CPP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DLLTOOL = @DLLTOOL@ +EXEEXT = @EXEEXT@ +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MF_HAVE_STDINT_H = @MF_HAVE_STDINT_H@ +MF_HAVE_UINTPTR_T = @MF_HAVE_UINTPTR_T@ +NM = @NM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +enable_shared = @enable_shared@ +enable_static = @enable_static@ +libtool_VERSION = @libtool_VERSION@ + +AUTOMAKE_OPTIONS = 1.3 foreign +MAINT_CHARSET = latin1 +SUBDIRS = testsuite + +AM_CFLAGS = -Wall +@LIBMUDFLAPTH_TRUE@libmudflapth = @LIBMUDFLAPTH_TRUE@libmudflapth.la +@LIBMUDFLAPTH_FALSE@libmudflapth = + +lib_LTLIBRARIES = libmudflap.la $(libmudflapth) +include_HEADERS = mf-runtime.h + +libmudflap_la_SOURCES = \ + mf-runtime.c \ + mf-heuristics.c + + +HOOK1OBJS = \ + malloc-hook.lo \ + free-hook.lo \ + calloc-hook.lo \ + realloc-hook.lo \ + mmap-hook.lo \ + munmap-hook.lo \ + alloca-hook.lo + + +HOOK2OBJS = \ + memcpy-hook.lo \ + memmove-hook.lo \ + memset-hook.lo \ + memcmp-hook.lo \ + memchr-hook.lo \ + memrchr-hook.lo \ + strcpy-hook.lo \ + strncpy-hook.lo \ + strcat-hook.lo \ + strncat-hook.lo \ + strcmp-hook.lo \ + strcasecmp-hook.lo \ + strncmp-hook.lo \ + strncasecmp-hook.lo \ + strdup-hook.lo \ + strndup-hook.lo \ + strchr-hook.lo \ + strrchr-hook.lo \ + strstr-hook.lo \ + memmem-hook.lo \ + strlen-hook.lo \ + strnlen-hook.lo \ + bzero-hook.lo \ + bcopy-hook.lo \ + bcmp-hook.lo \ + index-hook.lo \ + rindex-hook.lo \ + asctime-hook.lo \ + ctime-hook.lo \ + gmtime-hook.lo \ + localtime-hook.lo \ + time-hook.lo \ + strerror-hook.lo \ + fopen-hook.lo \ + fclose-hook.lo \ + fread-hook.lo \ + fwrite-hook.lo \ + fgetc-hook.lo \ + fgets-hook.lo \ + getc-hook.lo \ + gets-hook.lo \ + ungetc-hook.lo \ + fputc-hook.lo \ + fputs-hook.lo \ + putc-hook.lo \ + puts-hook.lo \ + clearerr-hook.lo \ + feof-hook.lo \ + ferror-hook.lo \ + fileno-hook.lo \ + printf-hook.lo \ + fprintf-hook.lo \ + sprintf-hook.lo \ + snprintf-hook.lo \ + vprintf-hook.lo \ + vfprintf-hook.lo \ + vsprintf-hook.lo \ + vsnprintf-hook.lo \ + access-hook.lo \ + remove-hook.lo \ + fflush-hook.lo \ + fseek-hook.lo \ + ftell-hook.lo \ + rewind-hook.lo \ + fgetpos-hook.lo \ + fsetpos-hook.lo \ + stat-hook.lo \ + fstat-hook.lo \ + lstat-hook.lo \ + mkfifo-hook.lo \ + setvbuf-hook.lo \ + setbuf-hook.lo \ + opendir-hook.lo \ + closedir-hook.lo \ + readdir-hook.lo \ + recv-hook.lo \ + recvfrom-hook.lo \ + recvmsg-hook.lo \ + send-hook.lo \ + sendto-hook.lo \ + sendmsg-hook.lo \ + setsockopt-hook.lo \ + getsockopt-hook.lo \ + accept-hook.lo \ + bind-hook.lo \ + connect-hook.lo \ + gethostname-hook.lo \ + sethostname-hook.lo \ + gethostbyname-hook.lo \ + wait-hook.lo \ + waitpid-hook.lo \ + popen-hook.lo \ + pclose-hook.lo \ + execve-hook.lo \ + execv-hook.lo \ + execvp-hook.lo \ + system-hook.lo \ + dlopen-hook.lo \ + dlerror-hook.lo \ + dlsym-hook.lo \ + dlclose-hook.lo \ + fopen64-hook.lo \ + stat64-hook.lo \ + fseeko64-hook.lo \ + ftello64-hook.lo \ + semop-hook.lo \ + semctl-hook.lo \ + shmctl-hook.lo \ + shmat-hook.lo \ + shmdt-hook.lo + +HOOK3OBJS = + +# Hook objects only for libmudflapth use +PTHHOOK1OBJS = \ + pth/malloc-hook.lo \ + pth/free-hook.lo \ + pth/calloc-hook.lo \ + pth/realloc-hook.lo \ + pth/mmap-hook.lo \ + pth/munmap-hook.lo \ + pth/alloca-hook.lo + + +PTHHOOK2OBJS = \ + pth/memcpy-hook.lo \ + pth/memmove-hook.lo \ + pth/memset-hook.lo \ + pth/memcmp-hook.lo \ + pth/memchr-hook.lo \ + pth/memrchr-hook.lo \ + pth/strcpy-hook.lo \ + pth/strncpy-hook.lo \ + pth/strcat-hook.lo \ + pth/strncat-hook.lo \ + pth/strcmp-hook.lo \ + pth/strcasecmp-hook.lo \ + pth/strncmp-hook.lo \ + pth/strncasecmp-hook.lo \ + pth/strdup-hook.lo \ + pth/strndup-hook.lo \ + pth/strchr-hook.lo \ + pth/strrchr-hook.lo \ + pth/strstr-hook.lo \ + pth/memmem-hook.lo \ + pth/strlen-hook.lo \ + pth/strnlen-hook.lo \ + pth/bzero-hook.lo \ + pth/bcopy-hook.lo \ + pth/bcmp-hook.lo \ + pth/index-hook.lo \ + pth/rindex-hook.lo \ + pth/asctime-hook.lo \ + pth/ctime-hook.lo \ + pth/gmtime-hook.lo \ + pth/localtime-hook.lo \ + pth/time-hook.lo \ + pth/strerror-hook.lo \ + pth/fopen-hook.lo \ + pth/fclose-hook.lo \ + pth/fread-hook.lo \ + pth/fwrite-hook.lo \ + pth/fgetc-hook.lo \ + pth/fgets-hook.lo \ + pth/getc-hook.lo \ + pth/gets-hook.lo \ + pth/ungetc-hook.lo \ + pth/fputc-hook.lo \ + pth/fputs-hook.lo \ + pth/putc-hook.lo \ + pth/puts-hook.lo \ + pth/clearerr-hook.lo \ + pth/feof-hook.lo \ + pth/ferror-hook.lo \ + pth/fileno-hook.lo \ + pth/printf-hook.lo \ + pth/fprintf-hook.lo \ + pth/sprintf-hook.lo \ + pth/snprintf-hook.lo \ + pth/vprintf-hook.lo \ + pth/vfprintf-hook.lo \ + pth/vsprintf-hook.lo \ + pth/vsnprintf-hook.lo \ + pth/access-hook.lo \ + pth/remove-hook.lo \ + pth/fflush-hook.lo \ + pth/fseek-hook.lo \ + pth/ftell-hook.lo \ + pth/rewind-hook.lo \ + pth/fgetpos-hook.lo \ + pth/fsetpos-hook.lo \ + pth/stat-hook.lo \ + pth/fstat-hook.lo \ + pth/lstat-hook.lo \ + pth/mkfifo-hook.lo \ + pth/setvbuf-hook.lo \ + pth/setbuf-hook.lo \ + pth/opendir-hook.lo \ + pth/closedir-hook.lo \ + pth/readdir-hook.lo \ + pth/recv-hook.lo \ + pth/recvfrom-hook.lo \ + pth/recvmsg-hook.lo \ + pth/send-hook.lo \ + pth/sendto-hook.lo \ + pth/sendmsg-hook.lo \ + pth/setsockopt-hook.lo \ + pth/getsockopt-hook.lo \ + pth/accept-hook.lo \ + pth/bind-hook.lo \ + pth/connect-hook.lo \ + pth/gethostname-hook.lo \ + pth/sethostname-hook.lo \ + pth/gethostbyname-hook.lo \ + pth/wait-hook.lo \ + pth/waitpid-hook.lo \ + pth/popen-hook.lo \ + pth/pclose-hook.lo \ + pth/execve-hook.lo \ + pth/execv-hook.lo \ + pth/execvp-hook.lo \ + pth/system-hook.lo \ + pth/dlopen-hook.lo \ + pth/dlerror-hook.lo \ + pth/dlsym-hook.lo \ + pth/dlclose-hook.lo \ + pth/fopen64-hook.lo \ + pth/stat64-hook.lo \ + pth/fseeko64-hook.lo \ + pth/ftello64-hook.lo \ + pth/semop-hook.lo \ + pth/semctl-hook.lo \ + pth/shmctl-hook.lo \ + pth/shmat-hook.lo \ + pth/shmdt-hook.lo + + +PTHHOOK3OBJS = \ + pth/pthreadstuff-hook.lo + + +libmudflapth_la_SOURCES = + +libmudflap_la_LIBADD = $(HOOK1OBJS) $(HOOK2OBJS) $(HOOK3OBJS) +libmudflap_la_DEPENDENCIES = $(libmudflap_la_LIBADD) + +libmudflapth_la_LIBADD = pth/mf-runtime.lo pth/mf-heuristics.lo \ + $(PTHHOOK1OBJS) $(PTHHOOK2OBJS) $(PTHHOOK3OBJS) + +libmudflapth_la_DEPENDENCIES = $(libmudflapth_la_LIBADD) + +# XXX hack alert +# From libffi/Makefile.am + +# Work around what appears to be a GNU make bug handling MAKEFLAGS +# values defined in terms of make variables, as is the case for CC and +# friends when we are called from the top level Makefile. +AM_MAKEFLAGS = \ + "AR_FLAGS=$(AR_FLAGS)" \ + "CC_FOR_BUILD=$(CC_FOR_BUILD)" \ + "CFLAGS=$(CFLAGS)" \ + "CXXFLAGS=$(CXXFLAGS)" \ + "CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \ + "CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \ + "INSTALL=$(INSTALL)" \ + "INSTALL_DATA=$(INSTALL_DATA)" \ + "INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \ + "INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \ + "JC1FLAGS=$(JC1FLAGS)" \ + "LDFLAGS=$(LDFLAGS)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \ + "MAKE=$(MAKE)" \ + "MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \ + "PICFLAG=$(PICFLAG)" \ + "PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \ + "SHELL=$(SHELL)" \ + "exec_prefix=$(exec_prefix)" \ + "infodir=$(infodir)" \ + "libdir=$(libdir)" \ + "prefix=$(prefix)" \ + "AR=$(AR)" \ + "AS=$(AS)" \ + "CC=$(CC)" \ + "CXX=$(CXX)" \ + "LD=$(LD)" \ + "LIBCFLAGS=$(LIBCFLAGS)" \ + "NM=$(NM)" \ + "PICFLAG=$(PICFLAG)" \ + "RANLIB=$(RANLIB)" \ + "DESTDIR=$(DESTDIR)" + + +MAKEOVERRIDES = + +# Multilib support variables. +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = +MULTIDO = true +MULTICLEAN = true +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = mf-runtime.h +LTLIBRARIES = $(lib_LTLIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libmudflap_la_LDFLAGS = +libmudflap_la_OBJECTS = mf-runtime.lo mf-heuristics.lo +libmudflapth_la_LDFLAGS = +libmudflapth_la_OBJECTS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(include_HEADERS) + +DIST_COMMON = ./stamp-h.in ChangeLog Makefile.am Makefile.in \ +acinclude.m4 aclocal.m4 config.h.in configure configure.in \ +mf-runtime.h.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +DEP_FILES = .deps/mf-heuristics.P .deps/mf-runtime.P +SOURCES = $(libmudflap_la_SOURCES) $(libmudflapth_la_SOURCES) +OBJECTS = $(libmudflap_la_OBJECTS) $(libmudflapth_la_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .obj .s +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4 + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +config.h: stamp-h + @if test ! -f $@; then \ + rm -f stamp-h; \ + $(MAKE) stamp-h; \ + else :; fi +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h 2> /dev/null +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@$(srcdir)/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/stamp-h.in; \ + $(MAKE) $(srcdir)/stamp-h.in; \ + else :; fi +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: +mf-runtime.h: $(top_builddir)/config.status mf-runtime.h.in + cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +mostlyclean-libLTLIBRARIES: + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + +distclean-libLTLIBRARIES: + +maintainer-clean-libLTLIBRARIES: + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libdir) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +# FIXME: We should only use cygpath when building on Windows, +# and only if it is available. +.c.obj: + $(COMPILE) -c `cygpath -w $<` + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libmudflap.la: $(libmudflap_la_OBJECTS) $(libmudflap_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libmudflap_la_LDFLAGS) $(libmudflap_la_OBJECTS) $(libmudflap_la_LIBADD) $(LIBS) + +libmudflapth.la: $(libmudflapth_la_OBJECTS) $(libmudflapth_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libmudflapth_la_LDFLAGS) $(libmudflapth_la_OBJECTS) $(libmudflapth_la_LIBADD) $(LIBS) + +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(includedir) + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ + echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p"; \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + list='$(include_HEADERS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(includedir)/$$p; \ + done + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) dist + -rm -rf $(distdir) + @banner="$(distdir).tar.gz is ready for distribution"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +all-recursive-am: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +install-exec-am: install-libLTLIBRARIES +install-exec: install-exec-recursive + +install-data-am: install-includeHEADERS +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: uninstall-libLTLIBRARIES uninstall-includeHEADERS +uninstall: uninstall-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h +all-redirect: all-recursive-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-hdr mostlyclean-libLTLIBRARIES \ + mostlyclean-compile mostlyclean-libtool \ + mostlyclean-tags mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-hdr clean-libLTLIBRARIES clean-compile clean-libtool \ + clean-tags clean-depend clean-generic mostlyclean-am \ + clean-local + +clean: clean-recursive + +distclean-am: distclean-hdr distclean-libLTLIBRARIES distclean-compile \ + distclean-libtool distclean-tags distclean-depend \ + distclean-generic clean-am + -rm -f libtool + +distclean: distclean-recursive + -rm -f config.status + +maintainer-clean-am: maintainer-clean-hdr \ + maintainer-clean-libLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-depend \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \ +clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \ +uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \ +distclean-compile clean-compile maintainer-clean-compile \ +mostlyclean-libtool distclean-libtool clean-libtool \ +maintainer-clean-libtool uninstall-includeHEADERS \ +install-includeHEADERS install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir \ +mostlyclean-depend distclean-depend clean-depend \ +maintainer-clean-depend info-am info dvi-am dvi check check-am \ +installcheck-am installcheck all-recursive-am install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +$(HOOK1OBJS): mf-hooks1.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks1.c -o $@ +$(HOOK2OBJS): mf-hooks2.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks2.c -o $@ +$(HOOK3OBJS): mf-hooks3.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks3.c -o $@ + +clean-local: + rm -f pth/*.o pth/*.lo +pth/mf-runtime.lo: mf-runtime.c mf-runtime.h mf-impl.h + $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-runtime.c -o $@ +pth/mf-heuristics.lo: mf-heuristics.c mf-runtime.h mf-impl.h + $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-heuristics.c -o $@ +$(PTHHOOK1OBJS): mf-hooks1.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks1.c -o $@ +$(PTHHOOK2OBJS): mf-hooks2.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks2.c -o $@ +$(PTHHOOK3OBJS): mf-hooks3.c mf-runtime.h mf-impl.h + hook=`basename $@ -hook.lo`; \ + $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks3.c -o $@ + +# Multilib support. +.PHONY: all-multi mostlyclean-multi clean-multi distclean-multi \ + maintainer-clean-multi + +all-recursive: all-multi +install-recursive: install-multi +mostlyclean-recursive: mostlyclean-multi +clean-recursive: clean-multi +distclean-recursive: distclean-multi +maintainer-clean-recursive: maintainer-clean-multi + +all-multi: + : $(MAKE) ; exec $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do +install-multi: + $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do +mostlyclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean +clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean +distclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean +maintainer-clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libmudflap/acinclude.m4 b/libmudflap/acinclude.m4 new file mode 100644 index 00000000000..421197d6124 --- /dev/null +++ b/libmudflap/acinclude.m4 @@ -0,0 +1,928 @@ +## libtool.m4 - Configure libtool for the host system. -*-Shell-script-*- +## Copyright 1996, 1997, 1998, 1999, 2000, 2001 +## Free Software Foundation, Inc. +## Originally by Gordon Matzigkeit , 1996 +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## As a special exception to the GNU General Public License, if you +## distribute this file as part of a program that contains a +## configuration script generated by Autoconf, you may include it under +## the same distribution terms that you use for the rest of that program. + +# serial 46 AC_PROG_LIBTOOL +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ +])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ +])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ +])])])])])]) + +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# Save cache, so that ltconfig can load it +AC_CACHE_SAVE + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +AR="$AR" LTCC="$CC" CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) + +# Reload cache, that may have been modified by ltconfig +AC_CACHE_LOAD + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh $ac_aux_dir/ltcf-c.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +# Check for any special flags to pass to ltconfig. +libtool_flags="--cache-file=$cache_file" +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$GCC" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$lt_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], +[libtool_flags="$libtool_flags --enable-dlopen"]) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[libtool_flags="$libtool_flags --enable-win32-dll"]) +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + +AC_ARG_WITH(pic, + [ --with-pic try to use only PIC/non-PIC objects [default=use both]], + pic_mode="$withval", pic_mode=default) +test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic" +test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_SAVE + AC_LANG_C + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_RESTORE]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one + AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain, + [AC_TRY_LINK([], + [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*); + DllMain (0, 0, 0);], + [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])]) + + case $host/$CC in + *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*) + # old mingw systems require "-dll" to link a DLL, while more recent ones + # require "-mdll" + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -mdll" + AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch, + [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])]) + CFLAGS="$SAVE_CFLAGS" ;; + *-*-cygwin* | *-*-pw32*) + # cygwin systems need to pass --dll to the linker, and not link + # crt.o which will require a WinMain@16 definition. + lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;; + esac + ;; + ]) +esac +]) + +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) + +# AC_LIBTOOL_PICMODE - implement the --with-pic flag +# Usage: AC_LIBTOOL_PICMODE[(MODE)] +# Where MODE is either `yes' or `no'. If omitted, it defaults to +# `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default)]) + + +# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +]) + + +# AC_PATH_MAGIC - find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl +AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH) + else + MAGIC_CMD=: + fi +fi +]) + + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + re_direlt=['/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$lt_cv_prog_gnu_ld +]) + +# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +AC_DEFUN([AC_PROG_LD_RELOAD_FLAG], +[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag, +[lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" +]) + +# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +# Don't cache this sucker. +AC_DEFUN([AC_DEPLIBS_CHECK_METHOD], +[AC_MSG_CHECKING([how to recognise dependant libraries]) +lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [regex]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'] + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* |pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[012]) + lt_cv_file_magic_test_file='/System/Library/Frameworks/System.framework/System' + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd* ) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method=['file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + case $host_cpu in + hppa*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + ia64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + esac + ;; + +irix5* | irix6*) + case $host_os in + irix5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method=["file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"] + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + case $host_cpu in + alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | x86_64*) + lt_cv_deplibs_check_method=pass_all ;; + # NB 2003-06-03: According to Alexandre Oliva, x86_64 should not be + # in this list. However, it works around a libtool problem that + # wrongly excludes -ldl/-lpthread from the libmudflap(th) dependencies. + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'] ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$'] + else + [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$'] + fi + ;; + +newsos6) + [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +[sysv5uw[78]* | sysv4*uw2*)] + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + motorola) + lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'] + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + esac + ;; +esac +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +# NB: See above NB ... this is to make sure that the overriden +# local libtool variant doesn't pollute the upstream cache +unset lt_cv_file_magic_cmd +unset lt_cv_deplibs_check_method +AC_MSG_RESULT($deplibs_check_method) +]) + + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +AC_MSG_RESULT([$NM]) +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-convenience to the +# configure arguments. Note that LIBLTDL and INCLTDL are not +# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not +# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed +# with '${top_builddir}/' and INCLTDL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-install to the configure +# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is +# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed +# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed +# with '${top_srcdir}/' (note the single quotes!). If your package is +# not flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + INCLTDL= + fi +]) + +# If this macro is not defined by Autoconf, define it here. +ifdef([AC_PROVIDE_IFELSE], + [], + [define([AC_PROVIDE_IFELSE], + [ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + +# AC_LIBTOOL_CXX - enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], [AC_REQUIRE([_AC_LIBTOOL_CXX])]) + +AC_DEFUN([_AC_LIBTOOL_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +LIBTOOL_DEPS=$LIBTOOL_DEPS" $ac_aux_dir/ltcf-cxx.sh" +lt_save_CC="$CC" +lt_save_CFLAGS="$CFLAGS" +dnl Make sure LTCC is set to the C compiler, i.e. set LTCC before CC +dnl is set to the C++ compiler. +AR="$AR" LTCC="$CC" CC="$CXX" CXX="$CXX" CFLAGS="$CXXFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" \ +file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig -o libtool $libtool_flags \ +--build="$build" --add-tag=CXX $ac_aux_dir/ltcf-cxx.sh $host \ +|| AC_MSG_ERROR([libtool tag configuration failed]) +CC="$lt_save_CC" +CFLAGS="$lt_save_CFLAGS" + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +# AC_LIBTOOL_GCJ - enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ],[AC_REQUIRE([_AC_LIBTOOL_GCJ])]) + +AC_DEFUN([_AC_LIBTOOL_GCJ], +[AC_REQUIRE([AC_PROG_LIBTOOL]) +AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +LIBTOOL_DEPS=$LIBTOOL_DEPS" $ac_aux_dir/ltcf-gcj.sh" +lt_save_CC="$CC" +lt_save_CFLAGS="$CFLAGS" +dnl Make sure LTCC is set to the C compiler, i.e. set LTCC before CC +dnl is set to the C++ compiler. +AR="$AR" LTCC="$CC" CC="$GCJ" CFLAGS="$GCJFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" \ +file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig -o libtool $libtool_flags \ +--build="$build" --add-tag=GCJ $ac_aux_dir/ltcf-gcj.sh $host \ +|| AC_MSG_ERROR([libtool tag configuration failed]) +CC="$lt_save_CC" +CFLAGS="$lt_save_CFLAGS" + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +dnl old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +dnl This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL])dnl + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) diff --git a/libmudflap/aclocal.m4 b/libmudflap/aclocal.m4 new file mode 100644 index 00000000000..f33f60bba61 --- /dev/null +++ b/libmudflap/aclocal.m4 @@ -0,0 +1,1066 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + + +# serial 46 AC_PROG_LIBTOOL +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ +])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ +])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ +])])])])])]) + +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# Save cache, so that ltconfig can load it +AC_CACHE_SAVE + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +AR="$AR" LTCC="$CC" CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \ +|| AC_MSG_ERROR([libtool configure failed]) + +# Reload cache, that may have been modified by ltconfig +AC_CACHE_LOAD + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh $ac_aux_dir/ltcf-c.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +# Check for any special flags to pass to ltconfig. +libtool_flags="--cache-file=$cache_file" +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$GCC" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$lt_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], +[libtool_flags="$libtool_flags --enable-dlopen"]) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[libtool_flags="$libtool_flags --enable-win32-dll"]) +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + +AC_ARG_WITH(pic, + [ --with-pic try to use only PIC/non-PIC objects [default=use both]], + pic_mode="$withval", pic_mode=default) +test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic" +test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_SAVE + AC_LANG_C + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_RESTORE]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + + # recent cygwin and mingw systems supply a stub DllMain which the user + # can override, but on older systems we have to supply one + AC_CACHE_CHECK([if libtool should supply DllMain function], lt_cv_need_dllmain, + [AC_TRY_LINK([], + [extern int __attribute__((__stdcall__)) DllMain(void*, int, void*); + DllMain (0, 0, 0);], + [lt_cv_need_dllmain=no],[lt_cv_need_dllmain=yes])]) + + case $host/$CC in + *-*-cygwin*/gcc*-mno-cygwin*|*-*-mingw*) + # old mingw systems require "-dll" to link a DLL, while more recent ones + # require "-mdll" + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -mdll" + AC_CACHE_CHECK([how to link DLLs], lt_cv_cc_dll_switch, + [AC_TRY_LINK([], [], [lt_cv_cc_dll_switch=-mdll],[lt_cv_cc_dll_switch=-dll])]) + CFLAGS="$SAVE_CFLAGS" ;; + *-*-cygwin* | *-*-pw32*) + # cygwin systems need to pass --dll to the linker, and not link + # crt.o which will require a WinMain@16 definition. + lt_cv_cc_dll_switch="-Wl,--dll -nostartfiles" ;; + esac + ;; + ]) +esac +]) + +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_DISABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) + +# AC_LIBTOOL_PICMODE - implement the --with-pic flag +# Usage: AC_LIBTOOL_PICMODE[(MODE)] +# Where MODE is either `yes' or `no'. If omitted, it defaults to +# `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default)]) + + +# AC_PATH_TOOL_PREFIX - find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +]) + + +# AC_PATH_MAGIC - find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_REQUIRE([AC_CHECK_TOOL_PREFIX])dnl +AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin:$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin:$PATH) + else + MAGIC_CMD=: + fi +fi +]) + + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + re_direlt=['/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +AC_DEFUN([AC_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi]) +with_gnu_ld=$lt_cv_prog_gnu_ld +]) + +# AC_PROG_LD_RELOAD_FLAG - find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +AC_DEFUN([AC_PROG_LD_RELOAD_FLAG], +[AC_CACHE_CHECK([for $LD option to reload object files], lt_cv_ld_reload_flag, +[lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" +]) + +# AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +# Don't cache this sucker. +AC_DEFUN([AC_DEPLIBS_CHECK_METHOD], +[AC_MSG_CHECKING([how to recognise dependant libraries]) +lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [regex]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'] + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* |pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.[012]) + lt_cv_file_magic_test_file='/System/Library/Frameworks/System.framework/System' + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd* ) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method=['file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + case $host_cpu in + hppa*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + ia64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + esac + ;; + +irix5* | irix6*) + case $host_os in + irix5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method=["file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1"] + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + case $host_cpu in + alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | x86_64*) + lt_cv_deplibs_check_method=pass_all ;; + # NB 2003-06-03: According to Alexandre Oliva, x86_64 should not be + # in this list. However, it works around a libtool problem that + # wrongly excludes -ldl/-lpthread from the libmudflap(th) dependencies. + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'] ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$'] + else + [lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$'] + fi + ;; + +newsos6) + [lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'] + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +[sysv5uw[78]* | sysv4*uw2*)] + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + motorola) + lt_cv_deplibs_check_method=['file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'] + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + esac + ;; +esac +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +# NB: See above NB ... this is to make sure that the overriden +# local libtool variant doesn't pollute the upstream cache +unset lt_cv_file_magic_cmd +unset lt_cv_deplibs_check_method +AC_MSG_RESULT($deplibs_check_method) +]) + + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +AC_MSG_RESULT([$NM]) +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-convenience to the +# configure arguments. Note that LIBLTDL and INCLTDL are not +# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not +# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed +# with '${top_builddir}/' and INCLTDL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-install to the configure +# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is +# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed +# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed +# with '${top_srcdir}/' (note the single quotes!). If your package is +# not flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + INCLTDL= + fi +]) + +# If this macro is not defined by Autoconf, define it here. +ifdef([AC_PROVIDE_IFELSE], + [], + [define([AC_PROVIDE_IFELSE], + [ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + +# AC_LIBTOOL_CXX - enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], [AC_REQUIRE([_AC_LIBTOOL_CXX])]) + +AC_DEFUN([_AC_LIBTOOL_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([AC_PROG_CXXCPP]) +LIBTOOL_DEPS=$LIBTOOL_DEPS" $ac_aux_dir/ltcf-cxx.sh" +lt_save_CC="$CC" +lt_save_CFLAGS="$CFLAGS" +dnl Make sure LTCC is set to the C compiler, i.e. set LTCC before CC +dnl is set to the C++ compiler. +AR="$AR" LTCC="$CC" CC="$CXX" CXX="$CXX" CFLAGS="$CXXFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" \ +file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig -o libtool $libtool_flags \ +--build="$build" --add-tag=CXX $ac_aux_dir/ltcf-cxx.sh $host \ +|| AC_MSG_ERROR([libtool tag configuration failed]) +CC="$lt_save_CC" +CFLAGS="$lt_save_CFLAGS" + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +# AC_LIBTOOL_GCJ - enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ],[AC_REQUIRE([_AC_LIBTOOL_GCJ])]) + +AC_DEFUN([_AC_LIBTOOL_GCJ], +[AC_REQUIRE([AC_PROG_LIBTOOL]) +AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +LIBTOOL_DEPS=$LIBTOOL_DEPS" $ac_aux_dir/ltcf-gcj.sh" +lt_save_CC="$CC" +lt_save_CFLAGS="$CFLAGS" +dnl Make sure LTCC is set to the C compiler, i.e. set LTCC before CC +dnl is set to the C++ compiler. +AR="$AR" LTCC="$CC" CC="$GCJ" CFLAGS="$GCJFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" \ +file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig -o libtool $libtool_flags \ +--build="$build" --add-tag=GCJ $ac_aux_dir/ltcf-gcj.sh $host \ +|| AC_MSG_ERROR([libtool tag configuration failed]) +CC="$lt_save_CC" +CFLAGS="$lt_save_CFLAGS" + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +dnl old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +dnl This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL])dnl + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# serial 1 + +AC_DEFUN(AM_MAINTAINER_MODE, +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT($USE_MAINTAINER_MODE) + AM_CONDITIONAL(MAINTAINER_MODE, test $USE_MAINTAINER_MODE = yes) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +# Define a conditional. + +AC_DEFUN(AM_CONDITIONAL, +[AC_SUBST($1_TRUE) +AC_SUBST($1_FALSE) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + diff --git a/libmudflap/config.h.in b/libmudflap/config.h.in new file mode 100644 index 00000000000..ebb7360df60 --- /dev/null +++ b/libmudflap/config.h.in @@ -0,0 +1,62 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if you have the backtrace function. */ +#undef HAVE_BACKTRACE + +/* Define if you have the backtrace_symbols function. */ +#undef HAVE_BACKTRACE_SYMBOLS + +/* Define if you have the dlvsym function. */ +#undef HAVE_DLVSYM + +/* Define if you have the fopen64 function. */ +#undef HAVE_FOPEN64 + +/* Define if you have the fseeko64 function. */ +#undef HAVE_FSEEKO64 + +/* Define if you have the ftello64 function. */ +#undef HAVE_FTELLO64 + +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if you have the signal function. */ +#undef HAVE_SIGNAL + +/* Define if you have the stat64 function. */ +#undef HAVE_STAT64 + +/* Define if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define if you have the header file. */ +#undef HAVE_EXECINFO_H + +/* Define if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define if you have the dl library (-ldl). */ +#undef HAVE_LIBDL + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + +/* union semun defined in sys/ipc.h or sys/sem.h */ +#undef HAVE_UNION_SEMUN + +/* Define it socklen_t typedef is in sys/socket.h. */ +#undef HAVE_SOCKLEN_T + +/* define if you have */ +#undef HAVE_PTHREAD_H + +/* pthread_create symbol version */ +#undef PTHREAD_CREATE_VERSION + diff --git a/libmudflap/configure b/libmudflap/configure new file mode 100755 index 00000000000..71259c4ce75 --- /dev/null +++ b/libmudflap/configure @@ -0,0 +1,3218 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer" +ac_help="$ac_help + --enable-shared[=PKGS] build shared libraries [default=yes]" +ac_help="$ac_help + --enable-static[=PKGS] build static libraries [default=yes]" +ac_help="$ac_help + --enable-fast-install[=PKGS] optimize for fast installation [default=yes]" +ac_help="$ac_help + --with-gnu-ld assume the C compiler uses GNU ld [default=no]" +ac_help="$ac_help + --disable-libtool-lock avoid locking (might break parallel builds)" +ac_help="$ac_help + --with-pic try to use only PIC/non-PIC objects [default=use both]" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=mf-runtime.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + +ac_aux_dir= +for ac_dir in ${GNUSYSTEM_AUX_DIR} $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:587: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:608: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:626: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:660: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:713: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:770: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=libmudflap + +VERSION=1.0 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:816: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:829: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:842: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:855: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:868: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + + +# For libtool versioning info, format is CURRENT:REVISION:AGE +libtool_VERSION=1:0:0 + + +echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 +echo "configure:888: checking whether to enable maintainer-specific portions of Makefiles" >&5 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" + USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6 + + +if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + MAINT=$MAINTAINER_MODE_TRUE + + +echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 +echo "configure:911: checking for Cygwin environment" >&5 +if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cygwin=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cygwin=no +fi +rm -f conftest* +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cygwin" 1>&6 +CYGWIN= +test "$ac_cv_cygwin" = yes && CYGWIN=yes +echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 +echo "configure:944: checking for mingw32 environment" >&5 +if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_mingw32=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_mingw32=no +fi +rm -f conftest* +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_mingw32" 1>&6 +MINGW32= +test "$ac_cv_mingw32" = yes && MINGW32=yes + + +echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 +echo "configure:975: checking for executable suffix" >&5 +if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$CYGWIN" = yes || test "$MINGW32" = yes; then + ac_cv_exeext=.exe +else + rm -f conftest* + echo 'int main () { return 0; }' > conftest.$ac_ext + ac_cv_exeext= + if { (eval echo configure:985: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + for file in conftest.*; do + case $file in + *.c | *.o | *.obj) ;; + *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;; + esac + done + else + { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; } + fi + rm -f conftest* + test x"${ac_cv_exeext}" = x && ac_cv_exeext=no +fi +fi + +EXEEXT="" +test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext} +echo "$ac_t""${ac_cv_exeext}" 1>&6 +ac_exeext=$EXEEXT + + +target_alias=${target_alias-$target} + + + + + + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1023: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1053: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1104: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:1136: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 1147 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:1152: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:1178: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:1183: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:1211: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +if test "x$GCC" != "xyes"; then + { echo "configure: error: libmudflap must be built with GCC" 1>&2; exit 1; } +fi +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1246: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1267: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1284: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1301: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + + +# Some hosts don't have dlsym(RTLD_NEXT, "symbol") for use in +# symbol interposition. We disable shared libraries for these. +echo $ac_n "checking whether dlsym(RTLD_NEXT,...) is available""... $ac_c" 1>&6 +echo "configure:1329: checking whether dlsym(RTLD_NEXT,...) is available" >&5 +cat > conftest.$ac_ext < + +int main() { +void *foo = dlsym (RTLD_NEXT, "exit"); +; return 0; } +EOF +if { (eval echo configure:1341: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +enable_shared=no +fi +rm -f conftest* + +for ac_hdr in stdint.h execinfo.h signal.h dlfcn.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1357: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1367: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +for ac_func in backtrace backtrace_symbols gettimeofday signal +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1396: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1424: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +for ac_func in fopen64 fseeko64 ftello64 stat64 +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1452: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1480: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +cat > conftest.$ac_ext < +#include +#include +int main() { +union semun foo; +; return 0; } +EOF +if { (eval echo configure:1515: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + mf_have_semun=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + mf_have_semun=0 +fi +rm -f conftest* +if test $mf_have_semun = 1 +then + cat >> confdefs.h <<\EOF +#define HAVE_UNION_SEMUN 1 +EOF + +fi + + +echo $ac_n "checking for socklen_t in sys/socket.h""... $ac_c" 1>&6 +echo "configure:1535: checking for socklen_t in sys/socket.h" >&5 +cat > conftest.$ac_ext < +#include +int main() { +socklen_t x = 5; +; return 0; } +EOF +if { (eval echo configure:1546: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_SOCKLEN_T 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} +case $enableval in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_shared=yes +fi + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} +case $enableval in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_static=yes +fi + +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} +case $enableval in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac +else + enable_fast_install=yes +fi + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 +echo "configure:1643: checking for ld used by GCC" >&5 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 +echo "configure:1673: checking for GNU ld" >&5 +else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 +echo "configure:1676: checking for non-GNU ld" >&5 +fi +if eval "test \"`echo '$''{'lt_cv_path_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$lt_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } +echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 +echo "configure:1711: checking if the linker ($LD) is GNU ld" >&5 +if eval "test \"`echo '$''{'lt_cv_prog_gnu_ld'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + lt_cv_prog_gnu_ld=yes +else + lt_cv_prog_gnu_ld=no +fi +fi + +echo "$ac_t""$lt_cv_prog_gnu_ld" 1>&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + +echo $ac_n "checking for $LD option to reload object files""... $ac_c" 1>&6 +echo "configure:1728: checking for $LD option to reload object files" >&5 +if eval "test \"`echo '$''{'lt_cv_ld_reload_flag'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + lt_cv_ld_reload_flag='-r' +fi + +echo "$ac_t""$lt_cv_ld_reload_flag" 1>&6 +reload_flag=$lt_cv_ld_reload_flag +test -n "$reload_flag" && reload_flag=" $reload_flag" + +echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 +echo "configure:1740: checking for BSD-compatible nm" >&5 +if eval "test \"`echo '$''{'lt_cv_path_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/${ac_tool_prefix}nm + if test -f $tmp_nm || test -f $tmp_nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + if ($tmp_nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep '(/dev/null|Invalid file or object type)' >/dev/null; then + lt_cv_path_NM="$tmp_nm -B" + break + elif ($tmp_nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + lt_cv_path_NM="$tmp_nm -p" + break + else + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi + +NM="$lt_cv_path_NM" +echo "$ac_t""$NM" 1>&6 + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:1778: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking how to recognise dependant libraries""... $ac_c" 1>&6 +echo "configure:1799: checking how to recognise dependant libraries" >&5 +lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [regex]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi4*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin* | mingw* |pw32*) + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method='file_magic Mach-O dynamically linked shared library' + lt_cv_file_magic_cmd='/usr/bin/file -L' + case "$host_os" in + rhapsody* | darwin1.012) + lt_cv_file_magic_test_file='/System/Library/Frameworks/System.framework/System' + ;; + *) # Darwin 1.3 on + lt_cv_file_magic_test_file='/usr/lib/libSystem.dylib' + ;; + esac + ;; + +freebsd* ) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20*|hpux11*) + case $host_cpu in + hppa*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + esac + ;; + +irix5* | irix6*) + case $host_os in + irix5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method="file_magic ELF ${libmagic} MSB mips-[1234] dynamic lib MIPS - version 1" + ;; + esac + lt_cv_file_magic_test_file=`echo /lib${libsuff}/libc.so*` + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux-gnu*) + case $host_cpu in + alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | x86_64*) + lt_cv_deplibs_check_method=pass_all ;; + # NB 2003-06-03: According to Alexandre Oliva, x86_64 should not be + # in this list. However, it works around a libtool problem that + # wrongly excludes -ldl/-lpthread from the libmudflap(th) dependencies. + *) + # glibc up to 2.1.1 does not perform some relocations on ARM + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; + esac + lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so$' + fi + ;; + +newsos6) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +osf3* | osf4* | osf5*) + # this will be overridden with pass_all, but let us keep it just in case + lt_cv_deplibs_check_method='file_magic COFF format alpha shared library' + lt_cv_file_magic_test_file=/shlib/libc.so + lt_cv_deplibs_check_method=pass_all + ;; + +sco3.2v5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + lt_cv_file_magic_test_file=/lib/libc.so + ;; + +sysv5uw[78]* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + case $host_vendor in + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + esac + ;; +esac +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +# NB: See above NB ... this is to make sure that the overriden +# local libtool variant doesn't pollute the upstream cache +unset lt_cv_file_magic_cmd +unset lt_cv_deplibs_check_method +echo "$ac_t""$deplibs_check_method" 1>&6 + +echo $ac_n "checking for object suffix""... $ac_c" 1>&6 +echo "configure:1973: checking for object suffix" >&5 +if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftest* +echo 'int i = 1;' > conftest.$ac_ext +if { (eval echo configure:1979: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + for ac_file in conftest.*; do + case $ac_file in + *.c) ;; + *) ac_cv_objext=`echo $ac_file | sed -e s/conftest.//` ;; + esac + done +else + { echo "configure: error: installation or configuration problem; compiler does not work" 1>&2; exit 1; } +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_objext" 1>&6 +OBJEXT=$ac_cv_objext +ac_objext=$ac_cv_objext + +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo $ac_n "checking for ${ac_tool_prefix}file""... $ac_c" 1>&6 +echo "configure:2009: checking for ${ac_tool_prefix}file" >&5 +if eval "test \"`echo '$''{'lt_cv_path_MAGIC_CMD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$ac_t""$MAGIC_CMD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo $ac_n "checking for file""... $ac_c" 1>&6 +echo "configure:2071: checking for file" >&5 +if eval "test \"`echo '$''{'lt_cv_path_MAGIC_CMD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case $MAGIC_CMD in + /*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; + ?:/*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a dos path. + ;; + *) + ac_save_MAGIC_CMD="$MAGIC_CMD" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="/usr/bin:$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$ac_save_ifs" + MAGIC_CMD="$ac_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$ac_t""$MAGIC_CMD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2142: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_RANLIB"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2174: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + RANLIB=":" +fi +fi + +# Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2209: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +STRIP="$ac_cv_prog_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_STRIP"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2241: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_STRIP="strip" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_STRIP" && ac_cv_prog_STRIP=":" +fi +fi +STRIP="$ac_cv_prog_STRIP" +if test -n "$STRIP"; then + echo "$ac_t""$STRIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + STRIP=":" +fi +fi + + +# Check for any special flags to pass to ltconfig. +libtool_flags="--cache-file=$cache_file" +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$GCC" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$lt_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" +libtool_flags="$libtool_flags --enable-dlopen" + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + : +fi + +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi + +test x"$pic_mode" = xyes && libtool_flags="$libtool_flags --prefer-pic" +test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 2308 "configure"' > conftest.$ac_ext + if { (eval echo configure:2309: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo configure:2328: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + case "`/usr/bin/file conftest.o`" in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo configure:2344: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6 +echo "configure:2388: checking whether the C compiler needs -belf" >&5 +if eval "test \"`echo '$''{'lt_cv_cc_needs_belf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + lt_cv_cc_needs_belf=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + lt_cv_cc_needs_belf=no +fi +rm -f conftest* + ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +fi + +echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + + +esac + + +# Save cache, so that ltconfig can load it +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +AR="$AR" LTCC="$CC" CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +MAGIC_CMD="$MAGIC_CMD" LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" STRIP="$STRIP" \ +AS="$AS" DLLTOOL="$DLLTOOL" OBJDUMP="$OBJDUMP" \ +objext="$OBJEXT" exeext="$EXEEXT" reload_flag="$reload_flag" \ +deplibs_check_method="$deplibs_check_method" file_magic_cmd="$file_magic_cmd" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify --build="$build" $ac_aux_dir/ltmain.sh $host \ +|| { echo "configure: error: libtool configure failed" 1>&2; exit 1; } + +# Reload cache, that may have been modified by ltconfig +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh $ac_aux_dir/ltcf-c.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log + + + + + + + + + +ac_safe=`echo "stdint.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for stdint.h""... $ac_c" 1>&6 +echo "configure:2528: checking for stdint.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2538: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MF_HAVE_STDINT_H=1 +else + echo "$ac_t""no" 1>&6 +MF_HAVE_STDINT_H=0 +fi + + +if test $MF_HAVE_STDINT_H = 1 +then + MF_HAVE_UINTPTR_T=1 +else + cat > conftest.$ac_ext < +int main() { +uintptr_t k = 0; +; return 0; } +EOF +if { (eval echo configure:2573: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + MF_HAVE_UINTPTR_T=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + MF_HAVE_UINTPTR_T=0 +fi +rm -f conftest* +fi + + +if test ! -d pth +then + # libmudflapth objects are built in this subdirectory + mkdir pth +fi + +pthread_create_version='""' +ac_safe=`echo "pthread.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for pthread.h""... $ac_c" 1>&6 +echo "configure:2595: checking for pthread.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2605: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + +cat >> confdefs.h <&6 + +ac_have_pthread_h= + +fi + + + +if test "x$ac_have_pthread_h" != ""; then + LIBMUDFLAPTH_TRUE= + LIBMUDFLAPTH_FALSE='#' +else + LIBMUDFLAPTH_TRUE='#' + LIBMUDFLAPTH_FALSE= +fi + +echo $ac_n "checking for dlsym in -ldl""... $ac_c" 1>&6 +echo "configure:2646: checking for dlsym in -ldl" >&5 +ac_lib_var=`echo dl'_'dlsym | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo dl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +fi + + +if test "x$enable_shared" = "xyes" && test "x$ac_have_pthread_h" != ""; then + # NB: don't check for -lpthread here, because then it would be + # added to LIBS. For the thread-unaware libmudflap.la, we don't + # want it there. + + # glibc-related hacks. dlsym() may pick the wrong version of + # interposed functions like pthread_create on modern glibc. + # We need to find the proper symbol version string, and use + # the nonstandard dlvsym(). + for ac_func in dlvsym +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2705: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2733: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + # Extract the first word of "${ac_tool_prefix}nm", so it can be a program name with args. +set dummy ${ac_tool_prefix}nm; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:2760: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_NM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$NM"; then + ac_cv_prog_NM="$NM" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_NM="${ac_tool_prefix}nm" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_NM" && ac_cv_prog_NM="nm" +fi +fi +NM="$ac_cv_prog_NM" +if test -n "$NM"; then + echo "$ac_t""$NM" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + + + if test "x$ac_cv_have_dlvsym" != ""; then + # Try compiling a simple pthreads program. Find the shared libraries it + # ends up with. Then use "nm" on those libraries to extract the + # default symbol versioning suffix ("@@"), if any. But that's tricky. + # Rather, run nm on the resulting executable. Unfortunately, autoconf + # doesn't appear to have a macro that builds a test executable for + # subsequent analysis ... so we do it by hand here. + cat >> conftest.c << EOF +#include +int main () { void *p = (void *) & pthread_create; return (int) p; } +EOF + oldLIBS="$LIBS" + LIBS="$LIBS -lpthread" + pthread_create_version="\"\"" + echo $ac_n "checking pthread_create symbol version""... $ac_c" 1>&6 +echo "configure:2804: checking pthread_create symbol version" >&5 + if eval $ac_link 2>&5 && test -s conftest${ac_exeext}; then + version=`$NM conftest${ac_exeect} | grep 'pthread_create@@' | sed -e 's/^.*@@//'` + if test "x$version" != "x"; then + pthread_create_version="\"$version\"" + fi + fi + echo "$ac_t""$pthread_create_version" 1>&6 + LIBS="$oldLIBS" + fi +fi +cat >> confdefs.h < confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile testsuite/Makefile mf-runtime.h config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@libtool_VERSION@%$libtool_VERSION%g +s%@MAINTAINER_MODE_TRUE@%$MAINTAINER_MODE_TRUE%g +s%@MAINTAINER_MODE_FALSE@%$MAINTAINER_MODE_FALSE%g +s%@MAINT@%$MAINT%g +s%@EXEEXT@%$EXEEXT%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@LN_S@%$LN_S%g +s%@OBJEXT@%$OBJEXT%g +s%@RANLIB@%$RANLIB%g +s%@STRIP@%$STRIP%g +s%@LIBTOOL@%$LIBTOOL%g +s%@enable_shared@%$enable_shared%g +s%@enable_static@%$enable_static%g +s%@MF_HAVE_STDINT_H@%$MF_HAVE_STDINT_H%g +s%@MF_HAVE_UINTPTR_T@%$MF_HAVE_UINTPTR_T%g +s%@LIBMUDFLAPTH_TRUE@%$LIBMUDFLAPTH_TRUE%g +s%@LIBMUDFLAPTH_FALSE@%$LIBMUDFLAPTH_FALSE%g +s%@NM@%$NM%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/libmudflap/configure.in b/libmudflap/configure.in new file mode 100644 index 00000000000..afdde6c52a8 --- /dev/null +++ b/libmudflap/configure.in @@ -0,0 +1,137 @@ +# Process this file with autoconf to produce a configure script, like so: +# aclocal && autoconf && autoheader && automake + +AC_PREREQ(2.13) +AC_INIT(mf-runtime.c) +AC_CANONICAL_SYSTEM +AM_INIT_AUTOMAKE(libmudflap, 1.0) + +AC_SUBST(PACKAGE) +# For libtool versioning info, format is CURRENT:REVISION:AGE +libtool_VERSION=1:0:0 +AC_SUBST(libtool_VERSION) + +dnl AM_ENABLE_MULTILIB +AM_MAINTAINER_MODE +AC_EXEEXT + +target_alias=${target_alias-$target} +AC_SUBST(target_alias) + +AM_CONFIG_HEADER(config.h) + +AC_LANG_C +AC_PROG_CC +if test "x$GCC" != "xyes"; then + AC_MSG_ERROR([libmudflap must be built with GCC]) +fi +AC_PROG_CPP + +# Some hosts don't have dlsym(RTLD_NEXT, "symbol") for use in +# symbol interposition. We disable shared libraries for these. +AC_MSG_CHECKING([whether dlsym(RTLD_NEXT,...) is available]) +AC_TRY_COMPILE([ +#define _GNU_SOURCE +#include +], +[void *foo = dlsym (RTLD_NEXT, "exit");], +[AC_MSG_RESULT(yes)], +[AC_MSG_RESULT(no) +enable_shared=no]) + +AC_CHECK_HEADERS(stdint.h execinfo.h signal.h dlfcn.h) +AC_CHECK_FUNCS(backtrace backtrace_symbols gettimeofday signal) + +dnl Check for 64-bit stdio calls related to Large File Support +AC_CHECK_FUNCS(fopen64 fseeko64 ftello64 stat64) + +AC_TRY_COMPILE([#include +#include +#include ],[union semun foo;], [mf_have_semun=1], [mf_have_semun=0]) +if test $mf_have_semun = 1 +then + AC_DEFINE(HAVE_UNION_SEMUN, 1, [union semun defined in sys/ipc.h or sys/sem.h]) +fi + + +AC_MSG_CHECKING([for socklen_t in sys/socket.h]) +AC_TRY_COMPILE([#define _POSIX_PII_SOCKET +#include +#include ], [socklen_t x = 5;], + [AC_DEFINE(HAVE_SOCKLEN_T, 1, [Define it socklen_t typedef is in sys/socket.h.]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)]) + +AC_LIBTOOL_DLOPEN +AM_PROG_LIBTOOL +AC_SUBST(enable_shared) +AC_SUBST(enable_static) + +AC_CHECK_HEADER(stdint.h, [MF_HAVE_STDINT_H=1], [MF_HAVE_STDINT_H=0]) +AC_SUBST(MF_HAVE_STDINT_H) +if test $MF_HAVE_STDINT_H = 1 +then + MF_HAVE_UINTPTR_T=1 +else + AC_TRY_COMPILE([#include ], [uintptr_t k = 0;], + [MF_HAVE_UINTPTR_T=1], [MF_HAVE_UINTPTR_T=0]) +fi +AC_SUBST(MF_HAVE_UINTPTR_T) + +if test ! -d pth +then + # libmudflapth objects are built in this subdirectory + mkdir pth +fi + +pthread_create_version='""' +AC_CHECK_HEADER(pthread.h,[ +AC_DEFINE_UNQUOTED(HAVE_PTHREAD_H, 1, [define if you have ]) +ac_have_pthread_h=yes +],[ +ac_have_pthread_h= +]) +AM_CONDITIONAL(LIBMUDFLAPTH, [test "x$ac_have_pthread_h" != ""]) + +AC_CHECK_LIB(dl, dlsym) + +if test "x$enable_shared" = "xyes" && test "x$ac_have_pthread_h" != ""; then + # NB: don't check for -lpthread here, because then it would be + # added to LIBS. For the thread-unaware libmudflap.la, we don't + # want it there. + + # glibc-related hacks. dlsym() may pick the wrong version of + # interposed functions like pthread_create on modern glibc. + # We need to find the proper symbol version string, and use + # the nonstandard dlvsym(). + AC_CHECK_FUNCS(dlvsym) + AC_CHECK_TOOL(NM, nm) + if test "x$ac_cv_have_dlvsym" != ""; then + # Try compiling a simple pthreads program. Find the shared libraries it + # ends up with. Then use "nm" on those libraries to extract the + # default symbol versioning suffix ("@@"), if any. But that's tricky. + # Rather, run nm on the resulting executable. Unfortunately, autoconf + # doesn't appear to have a macro that builds a test executable for + # subsequent analysis ... so we do it by hand here. + cat >> conftest.c << EOF +#include +int main () { void *p = (void *) & pthread_create; return (int) p; } +EOF + oldLIBS="$LIBS" + LIBS="$LIBS -lpthread" + pthread_create_version="\"\"" + AC_MSG_CHECKING(pthread_create symbol version) + if eval $ac_link 2>&5 && test -s conftest${ac_exeext}; then + version=`$NM conftest${ac_exeect} | grep 'pthread_create@@' | sed -e 's/^.*@@//'` + if test "x$version" != "x"; then + pthread_create_version="\"$version\"" + fi + fi + AC_MSG_RESULT($pthread_create_version) + LIBS="$oldLIBS" + fi +fi +AC_DEFINE_UNQUOTED(PTHREAD_CREATE_VERSION, $pthread_create_version, [pthread_create symbol version]) + + +AC_OUTPUT([Makefile testsuite/Makefile mf-runtime.h]) diff --git a/libmudflap/mf-heuristics.c b/libmudflap/mf-heuristics.c new file mode 100644 index 00000000000..5231a08253a --- /dev/null +++ b/libmudflap/mf-heuristics.c @@ -0,0 +1,174 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" + +#include + +#include "mf-runtime.h" +#include "mf-impl.h" + +#ifdef _MUDFLAP +#error "Do not compile this file with -fmudflap!" +#endif + + +extern char _end; +extern char _start; + + +/* Run some quick validation of the given region. + Return -1 / 0 / 1 if the access known-invalid, possibly-valid, or known-valid. +*/ +int +__mf_heuristic_check (uintptr_t ptr, uintptr_t ptr_high) +{ + VERBOSE_TRACE ("mf: heuristic check\n"); + + /* XXX: Disable the stack bounding check for libmudflapth. We do + actually have enough information to track stack bounds (see + __mf_pthread_info in mf-hooks.c), so with a bit of future work, + this heuristic can be turned on. */ +#ifndef LIBMUDFLAPTH + + /* The first heuristic is to check stack bounds. This is a + transient condition and quick to check. */ + if (__mf_opts.heur_stack_bound) + { + uintptr_t stack_top_guess = (uintptr_t)__builtin_frame_address(0); +#if defined(__i386__) && defined (__linux__) + uintptr_t stack_segment_base = 0xC0000000; /* XXX: Bad assumption. */ +#else + /* Cause tests to fail. */ + uintptr_t stack_segment_base = 0; +#endif + + VERBOSE_TRACE ("mf: stack estimated as %p-%p\n", + (void *) stack_top_guess, (void *) stack_segment_base); + + if (ptr_high <= stack_segment_base && + ptr >= stack_top_guess && + ptr_high >= ptr) + { + return 1; + } + } +#endif + + + /* The second heuristic is to scan the range of memory regions + listed in /proc/self/maps, a special file provided by the Linux + kernel. Its results may be cached, and in fact, a GUESS object + may as well be recorded for interesting matching sections. */ + if (__mf_opts.heur_proc_map) + { + /* Keep a record of seen records from /proc/self/map. */ + enum { max_entries = 500 }; + struct proc_self_map_entry + { + uintptr_t low; + uintptr_t high; + }; + static struct proc_self_map_entry entry [max_entries]; + static unsigned entry_used [max_entries]; + + /* Look for a known proc_self_map entry that may cover this + region. If one exists, then this heuristic has already run, + and should not be run again. The check should be allowed to + fail. */ + unsigned i; + unsigned deja_vu = 0; + for (i=0; i= ptr_high)) + deja_vu = 1; + } + + if (! deja_vu) + { + /* Time to run the heuristic. Rescan /proc/self/maps; update the + entry[] array; XXX: remove expired entries, add new ones. + XXX: Consider entries that have grown (e.g., stack). */ + char buf[512]; + char flags[4]; + void *low, *high; + FILE *fp; + + fp = fopen ("/proc/self/maps", "r"); + if (fp) + { + while (fgets (buf, sizeof(buf), fp)) + { + if (sscanf (buf, "%p-%p %4c", &low, &high, flags) == 3) + { + if ((uintptr_t) low <= ptr && + (uintptr_t) high >= ptr_high) + { + for (i=0; i= (uintptr_t) & _start && ptr_high <= (uintptr_t) & _end) + return 1; /* uncacheable */ + + return 0; /* unknown */ +} diff --git a/libmudflap/mf-hooks1.c b/libmudflap/mf-hooks1.c new file mode 100644 index 00000000000..7199472ebe1 --- /dev/null +++ b/libmudflap/mf-hooks1.c @@ -0,0 +1,478 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" + +#ifndef HAVE_SOCKLEN_T +#define socklen_t int +#endif + + +/* These attempt to coax various unix flavours to declare all our + needed tidbits in the system headers. */ +#if !defined(__FreeBSD__) && !defined(__APPLE__) +#define _POSIX_SOURCE +#endif /* Some BSDs break if this is defined. */ +#define _GNU_SOURCE +#define _XOPEN_SOURCE +#define _BSD_TYPES +#define __EXTENSIONS__ +#define _ALL_SOURCE +#define _LARGE_FILE_API +#define _XOPEN_SOURCE_EXTENDED 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mf-runtime.h" +#include "mf-impl.h" + +#ifdef _MUDFLAP +#error "Do not compile this file with -fmudflap!" +#endif + + +/* Memory allocation related hook functions. Some of these are + intercepted via linker wrapping or symbol interposition. Others + use plain macros in mf-runtime.h. */ + + +#ifdef WRAP_malloc + +#if PIC +/* A special bootstrap variant. */ +void * +__mf_0fn_malloc (size_t c) +{ + /* fprintf (stderr, "0fn malloc c=%lu\n", c); */ + return NULL; +} +#endif + +#undef malloc +WRAPPER(void *, malloc, size_t c) +{ + size_t size_with_crumple_zones; + DECLARE(void *, malloc, size_t c); + void *result; + BEGIN_PROTECT (malloc, c); + + size_with_crumple_zones = + CLAMPADD(c,CLAMPADD(__mf_opts.crumple_zone, + __mf_opts.crumple_zone)); + result = (char *) CALL_REAL (malloc, size_with_crumple_zones); + + if (LIKELY(result)) + { + result += __mf_opts.crumple_zone; + __mf_register (result, c, __MF_TYPE_HEAP, "malloc region"); + /* XXX: register __MF_TYPE_NOACCESS for crumple zones. */ + } + + return result; +} +#endif + + +#ifdef WRAP_calloc + +#ifdef PIC +/* A special bootstrap variant. */ +void * +__mf_0fn_calloc (size_t c, size_t n) +{ + enum foo { BS = 4096, NB=10 }; + static char bufs[NB][BS]; + static unsigned bufs_used[NB]; + unsigned i; + + /* fprintf (stderr, "0fn calloc c=%lu n=%lu\n", c, n); */ + for (i=0; i 0)) + { + char *freeme = NULL; + LOCKTH (); + if (free_queue [free_ptr] != NULL) + { + freeme = free_queue [free_ptr]; + freeme -= __mf_opts.crumple_zone; + } + free_queue [free_ptr] = buf; + free_ptr = (free_ptr == (__mf_opts.free_queue_length-1) ? 0 : free_ptr + 1); + UNLOCKTH (); + if (freeme) + { + if (__mf_opts.trace_mf_calls) + { + VERBOSE_TRACE ("freeing deferred pointer %p (crumple %u)\n", + (void *) freeme, + __mf_opts.crumple_zone); + } + CALL_REAL (free, freeme); + } + } + else + { + /* back pointer up a bit to the beginning of crumple zone */ + char *base = (char *)buf; + base -= __mf_opts.crumple_zone; + if (__mf_opts.trace_mf_calls) + { + VERBOSE_TRACE ("freeing pointer %p = %p - %u\n", + (void *) base, + (void *) buf, + __mf_opts.crumple_zone); + } + CALL_REAL (free, base); + } +} +#endif + + +#ifdef WRAP_mmap + +#if PIC +/* A special bootstrap variant. */ +void * +__mf_0fn_mmap (void *start, size_t l, int prot, int f, int fd, off_t off) +{ + return (void *) -1; +} +#endif + + +#undef mmap +WRAPPER(void *, mmap, + void *start, size_t length, int prot, + int flags, int fd, off_t offset) +{ + DECLARE(void *, mmap, void *, size_t, int, + int, int, off_t); + void *result; + BEGIN_PROTECT (mmap, start, length, prot, flags, fd, offset); + + result = CALL_REAL (mmap, start, length, prot, + flags, fd, offset); + + /* + VERBOSE_TRACE ("mmap (%08lx, %08lx, ...) => %08lx\n", + (uintptr_t) start, (uintptr_t) length, + (uintptr_t) result); + */ + + if (result != (void *)-1) + { + /* Register each page as a heap object. Why not register it all + as a single segment? That's so that a later munmap() call + can unmap individual pages. XXX: would __MF_TYPE_GUESS make + this more automatic? */ + size_t ps = getpagesize (); + uintptr_t base = (uintptr_t) result; + uintptr_t offset; + + for (offset=0; offset %08lx\n", + (uintptr_t) start, (uintptr_t) length, + (uintptr_t) result); + */ + + if (result == 0) + { + /* Unregister each page as a heap object. */ + size_t ps = getpagesize (); + uintptr_t base = (uintptr_t) start & (~ (ps - 1)); /* page align */ + uintptr_t offset; + + for (offset=0; offsetstack DEEPER_THAN (uintptr_t) stack)) + { + struct alloca_tracking *next = alloca_history->next; + __mf_unregister (alloca_history->ptr, 0); + CALL_REAL (free, alloca_history->ptr); + CALL_REAL (free, alloca_history); + alloca_history = next; + } + + /* Allocate new block. */ + result = NULL; + if (LIKELY (c > 0)) /* alloca(0) causes no allocation. */ + { + track = (struct alloca_tracking *) CALL_REAL (malloc, + sizeof (struct alloca_tracking)); + if (LIKELY (track != NULL)) + { + result = CALL_REAL (malloc, c); + if (UNLIKELY (result == NULL)) + { + CALL_REAL (free, track); + /* Too bad. XXX: What about errno? */ + } + else + { + __mf_register (result, c, __MF_TYPE_HEAP, "alloca region"); + track->ptr = result; + track->stack = stack; + track->next = alloca_history; + alloca_history = track; + } + } + } + + return result; +} + + +#undef alloca +WRAPPER(void *, alloca, size_t c) +{ + return __mf_wrap_alloca_indirect (c); +} + +#endif + diff --git a/libmudflap/mf-hooks2.c b/libmudflap/mf-hooks2.c new file mode 100644 index 00000000000..b0867729979 --- /dev/null +++ b/libmudflap/mf-hooks2.c @@ -0,0 +1,1767 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" + +#ifndef HAVE_SOCKLEN_T +#define socklen_t int +#endif + +/* These attempt to coax various unix flavours to declare all our + needed tidbits in the system headers. */ +#if !defined(__FreeBSD__) && !defined(__APPLE__) +#define _POSIX_SOURCE +#endif /* Some BSDs break if this is defined. */ +#define _GNU_SOURCE +#define _XOPEN_SOURCE +#define _BSD_TYPES +#define __EXTENSIONS__ +#define _ALL_SOURCE +#define _LARGE_FILE_API +#define _XOPEN_SOURCE_EXTENDED 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mf-runtime.h" +#include "mf-impl.h" + +#ifdef _MUDFLAP +#error "Do not compile this file with -fmudflap!" +#endif + + +/* A bunch of independent stdlib/unistd hook functions, all + intercepted by mf-runtime.h macros. */ + +#ifdef __FreeBSD__ +#undef WRAP_memrchr +#undef WRAP_memmem +#include +static inline size_t (strnlen) (const char* str, size_t n) +{ + const char *s; + + for (s = str; n && *s; ++s, --n) + ; + return (s - str); +} +#endif + +/* str*,mem*,b* */ + +#ifdef WRAP_memcpy +WRAPPER2(void *, memcpy, void *dest, const void *src, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, n, __MF_CHECK_READ, "memcpy source"); + MF_VALIDATE_EXTENT(dest, n, __MF_CHECK_WRITE, "memcpy dest"); + return memcpy (dest, src, n); +} +#endif + + +#ifdef WRAP_memmove +WRAPPER2(void *, memmove, void *dest, const void *src, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, n, __MF_CHECK_READ, "memmove src"); + MF_VALIDATE_EXTENT(dest, n, __MF_CHECK_WRITE, "memmove dest"); + return memmove (dest, src, n); +} +#endif + +#ifdef WRAP_memset +WRAPPER2(void *, memset, void *s, int c, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, n, __MF_CHECK_WRITE, "memset dest"); + return memset (s, c, n); +} +#endif + +#ifdef WRAP_memcmp +WRAPPER2(int, memcmp, const void *s1, const void *s2, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s1, n, __MF_CHECK_READ, "memcmp 1st arg"); + MF_VALIDATE_EXTENT(s2, n, __MF_CHECK_READ, "memcmp 2nd arg"); + return memcmp (s1, s2, n); +} +#endif + +#ifdef WRAP_memchr +WRAPPER2(void *, memchr, const void *s, int c, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, n, __MF_CHECK_READ, "memchr region"); + return memchr (s, c, n); +} +#endif + +#ifdef WRAP_memrchr +WRAPPER2(void *, memrchr, const void *s, int c, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, n, __MF_CHECK_READ, "memrchr region"); + return memrchr (s, c, n); +} +#endif + +#ifdef WRAP_strcpy +WRAPPER2(char *, strcpy, char *dest, const char *src) +{ + /* nb: just because strlen(src) == n doesn't mean (src + n) or (src + n + + 1) are valid pointers. the allocated object might have size < n. + check anyways. */ + + size_t n = strlen (src); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, CLAMPADD(n, 1), __MF_CHECK_READ, "strcpy src"); + MF_VALIDATE_EXTENT(dest, CLAMPADD(n, 1), __MF_CHECK_WRITE, "strcpy dest"); + return strcpy (dest, src); +} +#endif + +#ifdef WRAP_strncpy +WRAPPER2(char *, strncpy, char *dest, const char *src, size_t n) +{ + size_t len = strnlen (src, n); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, len, __MF_CHECK_READ, "strncpy src"); + MF_VALIDATE_EXTENT(dest, len, __MF_CHECK_WRITE, "strncpy dest"); /* nb: strNcpy */ + return strncpy (dest, src, n); +} +#endif + +#ifdef WRAP_strcat +WRAPPER2(char *, strcat, char *dest, const char *src) +{ + size_t dest_sz; + size_t src_sz; + TRACE ("%s\n", __PRETTY_FUNCTION__); + dest_sz = strlen (dest); + src_sz = strlen (src); + MF_VALIDATE_EXTENT(src, CLAMPADD(src_sz, 1), __MF_CHECK_READ, "strcat src"); + MF_VALIDATE_EXTENT(dest, CLAMPADD(dest_sz, CLAMPADD(src_sz, 1)), + __MF_CHECK_WRITE, "strcat dest"); + return strcat (dest, src); +} +#endif + +#ifdef WRAP_strncat +WRAPPER2(char *, strncat, char *dest, const char *src, size_t n) +{ + + /* nb: validating the extents (s,n) might be a mistake for two reasons. + + (1) the string s might be shorter than n chars, and n is just a + poor choice by the programmer. this is not a "true" error in the + sense that the call to strncat would still be ok. + + (2) we could try to compensate for case (1) by calling strlen(s) and + using that as a bound for the extent to verify, but strlen might fall off + the end of a non-terminated string, leading to a false positive. + + so we will call strnlen(s,n) and use that as a bound. + + if strnlen returns a length beyond the end of the registered extent + associated with s, there is an error: the programmer's estimate for n is + too large _AND_ the string s is unterminated, in which case they'd be + about to touch memory they don't own while calling strncat. + + this same logic applies to further uses of strnlen later down in this + file. */ + + size_t src_sz; + size_t dest_sz; + TRACE ("%s\n", __PRETTY_FUNCTION__); + src_sz = strnlen (src, n); + dest_sz = strnlen (dest, n); + MF_VALIDATE_EXTENT(src, src_sz, __MF_CHECK_READ, "strncat src"); + MF_VALIDATE_EXTENT(dest, (CLAMPADD(dest_sz, CLAMPADD(src_sz, 1))), + __MF_CHECK_WRITE, "strncat dest"); + return strncat (dest, src, n); +} +#endif + +#ifdef WRAP_strcmp +WRAPPER2(int, strcmp, const char *s1, const char *s2) +{ + size_t s1_sz; + size_t s2_sz; + TRACE ("%s\n", __PRETTY_FUNCTION__); + s1_sz = strlen (s1); + s2_sz = strlen (s2); + MF_VALIDATE_EXTENT(s1, CLAMPADD(s1_sz, 1), __MF_CHECK_READ, "strcmp 1st arg"); + MF_VALIDATE_EXTENT(s2, CLAMPADD(s2_sz, 1), __MF_CHECK_WRITE, "strcmp 2nd arg"); + return strcmp (s1, s2); +} +#endif + +#ifdef WRAP_strcasecmp +WRAPPER2(int, strcasecmp, const char *s1, const char *s2) +{ + size_t s1_sz; + size_t s2_sz; + TRACE ("%s\n", __PRETTY_FUNCTION__); + s1_sz = strlen (s1); + s2_sz = strlen (s2); + MF_VALIDATE_EXTENT(s1, CLAMPADD(s1_sz, 1), __MF_CHECK_READ, "strcasecmp 1st arg"); + MF_VALIDATE_EXTENT(s2, CLAMPADD(s2_sz, 1), __MF_CHECK_READ, "strcasecmp 2nd arg"); + return strcasecmp (s1, s2); +} +#endif + +#ifdef WRAP_strncmp +WRAPPER2(int, strncmp, const char *s1, const char *s2, size_t n) +{ + size_t s1_sz; + size_t s2_sz; + TRACE ("%s\n", __PRETTY_FUNCTION__); + s1_sz = strnlen (s1, n); + s2_sz = strnlen (s2, n); + MF_VALIDATE_EXTENT(s1, s1_sz, __MF_CHECK_READ, "strncmp 1st arg"); + MF_VALIDATE_EXTENT(s2, s2_sz, __MF_CHECK_READ, "strncmp 2nd arg"); + return strncmp (s1, s2, n); +} +#endif + +#ifdef WRAP_strncasecmp +WRAPPER2(int, strncasecmp, const char *s1, const char *s2, size_t n) +{ + size_t s1_sz; + size_t s2_sz; + TRACE ("%s\n", __PRETTY_FUNCTION__); + s1_sz = strnlen (s1, n); + s2_sz = strnlen (s2, n); + MF_VALIDATE_EXTENT(s1, s1_sz, __MF_CHECK_READ, "strncasecmp 1st arg"); + MF_VALIDATE_EXTENT(s2, s2_sz, __MF_CHECK_READ, "strncasecmp 2nd arg"); + return strncasecmp (s1, s2, n); +} +#endif + +#ifdef WRAP_strdup +WRAPPER2(char *, strdup, const char *s) +{ + DECLARE(void *, malloc, size_t sz); + char *result; + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n,1), __MF_CHECK_READ, "strdup region"); + result = (char *)CALL_REAL(malloc, + CLAMPADD(CLAMPADD(n,1), + CLAMPADD(__mf_opts.crumple_zone, + __mf_opts.crumple_zone))); + + if (UNLIKELY(! result)) return result; + + result += __mf_opts.crumple_zone; + memcpy (result, s, n); + result[n] = '\0'; + + __mf_register (result, CLAMPADD(n,1), __MF_TYPE_HEAP_I, "strdup region"); + return result; +} +#endif + +#ifdef WRAP_strndup +WRAPPER2(char *, strndup, const char *s, size_t n) +{ + DECLARE(void *, malloc, size_t sz); + char *result; + size_t sz = strnlen (s, n); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, sz, __MF_CHECK_READ, "strndup region"); /* nb: strNdup */ + + /* note: strndup still adds a \0, even with the N limit! */ + result = (char *)CALL_REAL(malloc, + CLAMPADD(CLAMPADD(n,1), + CLAMPADD(__mf_opts.crumple_zone, + __mf_opts.crumple_zone))); + + if (UNLIKELY(! result)) return result; + + result += __mf_opts.crumple_zone; + memcpy (result, s, n); + result[n] = '\0'; + + __mf_register (result, CLAMPADD(n,1), __MF_TYPE_HEAP_I, "strndup region"); + return result; +} +#endif + +#ifdef WRAP_strchr +WRAPPER2(char *, strchr, const char *s, int c) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (s); + MF_VALIDATE_EXTENT(s, CLAMPADD(n,1), __MF_CHECK_READ, "strchr region"); + return strchr (s, c); +} +#endif + +#ifdef WRAP_strrchr +WRAPPER2(char *, strrchr, const char *s, int c) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (s); + MF_VALIDATE_EXTENT(s, CLAMPADD(n,1), __MF_CHECK_READ, "strrchr region"); + return strrchr (s, c); +} +#endif + +#ifdef WRAP_strstr +WRAPPER2(char *, strstr, const char *haystack, const char *needle) +{ + size_t haystack_sz; + size_t needle_sz; + TRACE ("%s\n", __PRETTY_FUNCTION__); + haystack_sz = strlen (haystack); + needle_sz = strlen (needle); + MF_VALIDATE_EXTENT(haystack, CLAMPADD(haystack_sz, 1), __MF_CHECK_READ, "strstr haystack"); + MF_VALIDATE_EXTENT(needle, CLAMPADD(needle_sz, 1), __MF_CHECK_READ, "strstr needle"); + return strstr (haystack, needle); +} +#endif + +#ifdef WRAP_memmem +WRAPPER2(void *, memmem, + const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(haystack, haystacklen, __MF_CHECK_READ, "memmem haystack"); + MF_VALIDATE_EXTENT(needle, needlelen, __MF_CHECK_READ, "memmem needle"); + return memmem (haystack, haystacklen, needle, needlelen); +} +#endif + +#ifdef WRAP_strlen +WRAPPER2(size_t, strlen, const char *s) +{ + size_t result = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(result, 1), __MF_CHECK_READ, "strlen region"); + return result; +} +#endif + +#ifdef WRAP_strnlen +WRAPPER2(size_t, strnlen, const char *s, size_t n) +{ + size_t result = strnlen (s, n); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, result, __MF_CHECK_READ, "strnlen region"); + return result; +} +#endif + +#ifdef WRAP_bzero +WRAPPER2(void, bzero, void *s, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, n, __MF_CHECK_WRITE, "bzero region"); + bzero (s, n); +} +#endif + +#ifdef WRAP_bcopy +#undef bcopy +WRAPPER2(void, bcopy, const void *src, void *dest, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, n, __MF_CHECK_READ, "bcopy src"); + MF_VALIDATE_EXTENT(dest, n, __MF_CHECK_WRITE, "bcopy dest"); + bcopy (src, dest, n); +} +#endif + +#ifdef WRAP_bcmp +#undef bcmp +WRAPPER2(int, bcmp, const void *s1, const void *s2, size_t n) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s1, n, __MF_CHECK_READ, "bcmp 1st arg"); + MF_VALIDATE_EXTENT(s2, n, __MF_CHECK_READ, "bcmp 2nd arg"); + return bcmp (s1, s2, n); +} +#endif + +#ifdef WRAP_index +WRAPPER2(char *, index, const char *s, int c) +{ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "index region"); + return index (s, c); +} +#endif + +#ifdef WRAP_rindex +WRAPPER2(char *, rindex, const char *s, int c) +{ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "rindex region"); + return rindex (s, c); +} +#endif + +/* XXX: stpcpy, memccpy */ + + +/* XXX: *printf,*scanf */ + + +/* XXX: setjmp, longjmp */ + +#ifdef WRAP_asctime +WRAPPER2(char *, asctime, struct tm *tm) +{ + static char *reg_result = NULL; + char *result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(tm, sizeof (struct tm), __MF_CHECK_READ, "asctime tm"); + result = asctime (tm); + if (reg_result == NULL) + { + __mf_register (result, strlen (result)+1, __MF_TYPE_STATIC, "asctime string"); + reg_result = result; + } + return result; +} +#endif + +#ifdef WRAP_ctime +WRAPPER2(char *, ctime, const time_t *timep) +{ + static char *reg_result = NULL; + char *result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(timep, sizeof (time_t), __MF_CHECK_READ, "ctime time"); + result = ctime (timep); + if (reg_result == NULL) + { + /* XXX: what if asctime and ctime return the same static ptr? */ + __mf_register (result, strlen (result)+1, __MF_TYPE_STATIC, "ctime string"); + reg_result = result; + } + return result; +} +#endif + + +#ifdef WRAP_localtime +WRAPPER2(struct tm*, localtime, const time_t *timep) +{ + static struct tm *reg_result = NULL; + struct tm *result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(timep, sizeof (time_t), __MF_CHECK_READ, "localtime time"); + result = localtime (timep); + if (reg_result == NULL) + { + __mf_register (result, sizeof (struct tm), __MF_TYPE_STATIC, "localtime tm"); + reg_result = result; + } + return result; +} +#endif + +#ifdef WRAP_gmtime +WRAPPER2(struct tm*, gmtime, const time_t *timep) +{ + static struct tm *reg_result = NULL; + struct tm *result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(timep, sizeof (time_t), __MF_CHECK_READ, "gmtime time"); + result = gmtime (timep); + if (reg_result == NULL) + { + __mf_register (result, sizeof (struct tm), __MF_TYPE_STATIC, "gmtime tm"); + reg_result = result; + } + return result; +} +#endif + + + +/* EL start */ + +/* The following indicate if the result of the corresponding function + * should be explicitly un/registered by the wrapper +*/ +#define MF_REGISTER_strerror __MF_TYPE_STATIC +#undef MF_REGISTER_fopen +#define MF_RESULT_SIZE_fopen (sizeof (FILE)) +#undef MF_REGISTER_opendir +#define MF_RESULT_SIZE_opendir 0 /* (sizeof (DIR)) */ +#undef MF_REGISTER_readdir +#define MF_REGISTER_gethostbyname __MF_TYPE_STATIC +#undef MF_REGISTER_gethostbyname_items +#undef MF_REGISTER_dlopen +#undef MF_REGISTER_dlerror +#undef MF_REGISTER_dlsym +#define MF_REGISTER_shmat __MF_TYPE_GUESS + + +#ifdef WRAP_time +#include +WRAPPER2(time_t, time, time_t *timep) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + if (NULL != timep) + MF_VALIDATE_EXTENT (timep, sizeof (*timep), __MF_CHECK_WRITE, + "time timep"); + return time (timep); +} +#endif + +#ifdef WRAP_strerror +WRAPPER2(char *, strerror, int errnum) +{ + char *p; + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + p = strerror (errnum); + if (NULL != p) { + n = strlen (p); + n = CLAMPADD(n, 1); +#ifdef MF_REGISTER_strerror + __mf_register (p, n, MF_REGISTER_strerror, "strerror result"); +#endif + MF_VALIDATE_EXTENT (p, n, __MF_CHECK_WRITE, "strerror result"); + } + return p; +} +#endif + +#ifdef WRAP_fopen +WRAPPER2(FILE *, fopen, const char *path, const char *mode) +{ + size_t n; + FILE *p; + TRACE ("%s\n", __PRETTY_FUNCTION__); + + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "fopen path"); + + n = strlen (mode); + MF_VALIDATE_EXTENT (mode, CLAMPADD(n, 1), __MF_CHECK_READ, "fopen mode"); + + p = fopen (path, mode); + if (NULL != p) { +#ifdef MF_REGISTER_fopen + __mf_register (p, sizeof (*p), MF_REGISTER_fopen, "fopen result"); +#endif + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_WRITE, "fopen result"); + } + + return p; +} +#endif + +#ifdef HAVE_FOPEN64 +#ifdef WRAP_fopen64 +WRAPPER2(FILE *, fopen64, const char *path, const char *mode) +{ + size_t n; + FILE *p; + TRACE ("%s\n", __PRETTY_FUNCTION__); + + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "fopen64 path"); + + n = strlen (mode); + MF_VALIDATE_EXTENT (mode, CLAMPADD(n, 1), __MF_CHECK_READ, "fopen64 mode"); + + p = fopen64 (path, mode); + if (NULL != p) { +#ifdef MF_REGISTER_fopen + __mf_register (p, sizeof (*p), MF_REGISTER_fopen, "fopen64 result"); +#endif + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_WRITE, "fopen64 result"); + } + + return p; +} +#endif +#endif + +#ifdef WRAP_fclose +WRAPPER2(int, fclose, FILE *stream) +{ + int resp; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fclose stream"); + resp = fclose (stream); +#ifdef MF_REGISTER_fopen + __mf_unregister (stream, sizeof (*stream)); +#endif + + return resp; +} +#endif + +#ifdef WRAP_fread +WRAPPER2(size_t, fread, void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fread stream"); + MF_VALIDATE_EXTENT (ptr, size * nmemb, __MF_CHECK_WRITE, "fread buffer"); + return fread (ptr, size, nmemb, stream); +} +#endif + +#ifdef WRAP_fwrite +WRAPPER2(size_t, fwrite, const void *ptr, size_t size, size_t nmemb, + FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fwrite stream"); + MF_VALIDATE_EXTENT (ptr, size * nmemb, __MF_CHECK_READ, "fwrite buffer"); + return fwrite (ptr, size, nmemb, stream); +} +#endif + +#ifdef WRAP_fgetc +WRAPPER2(int, fgetc, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fgetc stream"); + return fgetc (stream); +} +#endif + +#ifdef WRAP_fgets +WRAPPER2(char *, fgets, char *s, int size, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fgets stream"); + MF_VALIDATE_EXTENT (s, size, __MF_CHECK_WRITE, "fgets buffer"); + return fgets (s, size, stream); +} +#endif + +#ifdef WRAP_getc +WRAPPER2(int, getc, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "getc stream"); + return getc (stream); +} +#endif + +#ifdef WRAP_gets +WRAPPER2(char *, gets, char *s) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (s, 1, __MF_CHECK_WRITE, "gets buffer"); + /* Avoid link-time warning... */ + s = fgets (s, INT_MAX, stdin); + if (NULL != s) { /* better late than never */ + size_t n = strlen (s); + MF_VALIDATE_EXTENT (s, CLAMPADD(n, 1), __MF_CHECK_WRITE, "gets buffer"); + } + return s; +} +#endif + +#ifdef WRAP_ungetc +WRAPPER2(int, ungetc, int c, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "ungetc stream"); + return ungetc (c, stream); +} +#endif + +#ifdef WRAP_fputc +WRAPPER2(int, fputc, int c, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fputc stream"); + return fputc (c, stream); +} +#endif + +#ifdef WRAP_fputs +WRAPPER2(int, fputs, const char *s, FILE *stream) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (s); + MF_VALIDATE_EXTENT (s, CLAMPADD(n, 1), __MF_CHECK_READ, "fputs buffer"); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fputs stream"); + return fputs (s, stream); +} +#endif + +#ifdef WRAP_putc +WRAPPER2(int, putc, int c, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "putc stream"); + return putc (c, stream); +} +#endif + +#ifdef WRAP_puts +WRAPPER2(int, puts, const char *s) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (s); + MF_VALIDATE_EXTENT (s, CLAMPADD(n, 1), __MF_CHECK_READ, "puts buffer"); + return puts (s); +} +#endif + +#ifdef WRAP_clearerr +WRAPPER2(void, clearerr, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "clearerr stream"); + clearerr (stream); +} +#endif + +#ifdef WRAP_feof +WRAPPER2(int, feof, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "feof stream"); + return feof (stream); +} +#endif + +#ifdef WRAP_ferror +WRAPPER2(int, ferror, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "ferror stream"); + return ferror (stream); +} +#endif + +#ifdef WRAP_fileno +#include +WRAPPER2(int, fileno, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fileno stream"); + return fileno (stream); +} +#endif + +#ifdef WRAP_printf +#include +#include +WRAPPER2(int, printf, const char *format, ...) +{ + size_t n; + va_list ap; + int result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "printf format"); + va_start (ap, format); + result = vprintf (format, ap); + va_end (ap); + return result; +} +#endif + +#ifdef WRAP_fprintf +#include +#include +WRAPPER2(int, fprintf, FILE *stream, const char *format, ...) +{ + size_t n; + va_list ap; + int result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fprintf stream"); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "fprintf format"); + va_start (ap, format); + result = vfprintf (stream, format, ap); + va_end (ap); + return result; +} +#endif + +#ifdef WRAP_sprintf +#include +#include +WRAPPER2(int, sprintf, char *str, const char *format, ...) +{ + size_t n; + va_list ap; + int result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (str, 1, __MF_CHECK_WRITE, "sprintf str"); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "sprintf format"); + va_start (ap, format); + result = vsprintf (str, format, ap); + va_end (ap); + n = strlen (str); + MF_VALIDATE_EXTENT (str, CLAMPADD(n, 1), __MF_CHECK_WRITE, "sprintf str"); + return result; +} +#endif + +#ifdef WRAP_snprintf +#include +#include +WRAPPER2(int, snprintf, char *str, size_t size, const char *format, ...) +{ + size_t n; + va_list ap; + int result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (str, size, __MF_CHECK_WRITE, "snprintf str"); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "snprintf format"); + va_start (ap, format); + result = vsnprintf (str, size, format, ap); + va_end (ap); + return result; +} +#endif + +#ifdef WRAP_vprintf +#include +#include +WRAPPER2(int, vprintf, const char *format, va_list ap) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "vprintf format"); + return vprintf (format, ap); +} +#endif + +#ifdef WRAP_vfprintf +#include +#include +WRAPPER2(int, vfprintf, FILE *stream, const char *format, va_list ap) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "vfprintf stream"); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "vfprintf format"); + return vfprintf (stream, format, ap); +} +#endif + +#ifdef WRAP_vsprintf +#include +#include +WRAPPER2(int, vsprintf, char *str, const char *format, va_list ap) +{ + size_t n; + int result; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (str, 1, __MF_CHECK_WRITE, "vsprintf str"); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "vsprintf format"); + result = vsprintf (str, format, ap); + n = strlen (str); + MF_VALIDATE_EXTENT (str, CLAMPADD(n, 1), __MF_CHECK_WRITE, "vsprintf str"); + return result; +} +#endif + +#ifdef WRAP_vsnprintf +#include +#include +WRAPPER2(int, vsnprintf, char *str, size_t size, const char *format, + va_list ap) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (str, size, __MF_CHECK_WRITE, "vsnprintf str"); + n = strlen (format); + MF_VALIDATE_EXTENT (format, CLAMPADD(n, 1), __MF_CHECK_READ, + "vsnprintf format"); + return vsnprintf (str, size, format, ap); +} +#endif + +#ifdef WRAP_access +WRAPPER2(int , access, const char *path, int mode) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "access path"); + return access (path, mode); +} +#endif + +#ifdef WRAP_remove +WRAPPER2(int , remove, const char *path) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "remove path"); + return remove (path); +} +#endif + +#ifdef WRAP_fflush +WRAPPER2(int, fflush, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fflush stream"); + return fflush (stream); +} +#endif + +#ifdef WRAP_fseek +WRAPPER2(int, fseek, FILE *stream, long offset, int whence) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fseek stream"); + return fseek (stream, offset, whence); +} +#endif + +#ifdef HAVE_FSEEKO64 +#ifdef WRAP_fseeko64 +WRAPPER2(int, fseeko64, FILE *stream, off64_t offset, int whence) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fseeko64 stream"); + return fseeko64 (stream, offset, whence); +} +#endif +#endif + +#ifdef WRAP_ftell +WRAPPER2(long, ftell, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "ftell stream"); + return ftell (stream); +} +#endif + +#ifdef HAVE_FTELLO64 +#ifdef WRAP_ftello64 +WRAPPER2(off64_t, ftello64, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "ftello64 stream"); + return ftello64 (stream); +} +#endif +#endif + +#ifdef WRAP_rewind +WRAPPER2(void, rewind, FILE *stream) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "rewind stream"); + rewind (stream); +} +#endif + +#ifdef WRAP_fgetpos +WRAPPER2(int, fgetpos, FILE *stream, fpos_t *pos) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fgetpos stream"); + MF_VALIDATE_EXTENT (pos, sizeof (*pos), __MF_CHECK_WRITE, "fgetpos pos"); + return fgetpos (stream, pos); +} +#endif + +#ifdef WRAP_fsetpos +WRAPPER2(int, fsetpos, FILE *stream, fpos_t *pos) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "fsetpos stream"); + MF_VALIDATE_EXTENT (pos, sizeof (*pos), __MF_CHECK_READ, "fsetpos pos"); + return fsetpos (stream, pos); +} +#endif + +#ifdef WRAP_stat +#include +WRAPPER2(int , stat, const char *path, struct stat *buf) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "stat path"); + MF_VALIDATE_EXTENT (buf, sizeof (*buf), __MF_CHECK_READ, "stat buf"); + return stat (path, buf); +} +#endif + +#ifdef HAVE_STAT64 +#ifdef WRAP_stat64 +#include +WRAPPER2(int , stat64, const char *path, struct stat64 *buf) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "stat64 path"); + MF_VALIDATE_EXTENT (buf, sizeof (*buf), __MF_CHECK_READ, "stat64 buf"); + return stat64 (path, buf); +} +#endif +#endif + +#ifdef WRAP_fstat +#include +WRAPPER2(int , fstat, int filedes, struct stat *buf) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (buf, sizeof (*buf), __MF_CHECK_READ, "fstat buf"); + return fstat (filedes, buf); +} +#endif + +#ifdef WRAP_lstat +#include +WRAPPER2(int , lstat, const char *path, struct stat *buf) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "lstat path"); + MF_VALIDATE_EXTENT (buf, sizeof (*buf), __MF_CHECK_READ, "lstat buf"); + return lstat (path, buf); +} +#endif + +#ifdef WRAP_mkfifo +#include +WRAPPER2(int , mkfifo, const char *path, mode_t mode) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "mkfifo path"); + return mkfifo (path, mode); +} +#endif + +#ifdef WRAP_setvbuf +WRAPPER2(int, setvbuf, FILE *stream, char *buf, int mode , size_t size) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "setvbuf stream"); + if (NULL != buf) + MF_VALIDATE_EXTENT (buf, size, __MF_CHECK_READ, "setvbuf buf"); + return setvbuf (stream, buf, mode, size); +} +#endif + +#ifdef WRAP_setbuf +WRAPPER2(void, setbuf, FILE *stream, char *buf) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "setbuf stream"); + if (NULL != buf) + MF_VALIDATE_EXTENT (buf, BUFSIZ, __MF_CHECK_READ, "setbuf buf"); + setbuf (stream, buf); +} +#endif + +#ifdef WRAP_opendir +#include +WRAPPER2(DIR *, opendir, const char *path) +{ + DIR *p; + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "opendir path"); + + p = opendir (path); + if (NULL != p) { +#ifdef MF_REGISTER_opendir + __mf_register (p, MF_RESULT_SIZE_opendir, MF_REGISTER_opendir, + "opendir result"); +#endif + MF_VALIDATE_EXTENT (p, MF_RESULT_SIZE_opendir, __MF_CHECK_WRITE, + "opendir result"); + } + return p; +} +#endif + +#ifdef WRAP_closedir +#include +WRAPPER2(int, closedir, DIR *dir) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (dir, 0, __MF_CHECK_WRITE, "closedir dir"); +#ifdef MF_REGISTER_opendir + __mf_unregister (dir, MF_RESULT_SIZE_opendir); +#endif + return closedir (dir); +} +#endif + +#ifdef WRAP_readdir +#include +WRAPPER2(struct dirent *, readdir, DIR *dir) +{ + struct dirent *p; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (dir, 0, __MF_CHECK_READ, "readdir dir"); + p = readdir (dir); + if (NULL != p) { +#ifdef MF_REGISTER_readdir + __mf_register (p, sizeof (*p), MF_REGISTER_readdir, "readdir result"); +#endif + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_WRITE, "readdir result"); + } + return p; +} +#endif + +#ifdef WRAP_recv +#include +WRAPPER2(int, recv, int s, void *buf, size_t len, int flags) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (buf, len, __MF_CHECK_WRITE, "recv buf"); + return recv (s, buf, len, flags); +} +#endif + +#ifdef WRAP_recvfrom +#include +WRAPPER2(int, recvfrom, int s, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (buf, len, __MF_CHECK_WRITE, "recvfrom buf"); + MF_VALIDATE_EXTENT (from, (size_t)*fromlen, __MF_CHECK_WRITE, + "recvfrom from"); + return recvfrom (s, buf, len, flags, from, fromlen); +} +#endif + +#ifdef WRAP_recvmsg +#include +WRAPPER2(int, recvmsg, int s, struct msghdr *msg, int flags) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (msg, sizeof (*msg), __MF_CHECK_WRITE, "recvmsg msg"); + return recvmsg (s, msg, flags); +} +#endif + +#ifdef WRAP_send +#include +WRAPPER2(int, send, int s, const void *msg, size_t len, int flags) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (msg, len, __MF_CHECK_READ, "send msg"); + return send (s, msg, len, flags); +} +#endif + +#ifdef WRAP_sendto +#include +WRAPPER2(int, sendto, int s, const void *msg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (msg, len, __MF_CHECK_READ, "sendto msg"); + MF_VALIDATE_EXTENT (to, (size_t)tolen, __MF_CHECK_WRITE, "sendto to"); + return sendto (s, msg, len, flags, to, tolen); +} +#endif + +#ifdef WRAP_sendmsg +#include +WRAPPER2(int, sendmsg, int s, const void *msg, int flags) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (msg, sizeof (*msg), __MF_CHECK_READ, "sendmsg msg"); + return sendmsg (s, msg, flags); +} +#endif + +#ifdef WRAP_setsockopt +#include +WRAPPER2(int, setsockopt, int s, int level, int optname, const void *optval, + socklen_t optlen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (optval, (size_t)optlen, __MF_CHECK_READ, + "setsockopt optval"); + return setsockopt (s, level, optname, optval, optlen); +} +#endif + +#ifdef WRAP_getsockopt +#include +WRAPPER2(int, getsockopt, int s, int level, int optname, void *optval, + socklen_t *optlen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (optval, (size_t)*optlen, __MF_CHECK_WRITE, + "getsockopt optval"); + return getsockopt (s, level, optname, optval, optlen); +} +#endif + +#ifdef WRAP_accept +#include +WRAPPER2(int, accept, int s, struct sockaddr *addr, socklen_t *addrlen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (addr, (size_t)*addrlen, __MF_CHECK_WRITE, "accept addr"); + return accept (s, addr, addrlen); +} +#endif + +#ifdef WRAP_bind +#include +WRAPPER2(int, bind, int sockfd, struct sockaddr *addr, socklen_t addrlen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (addr, (size_t)addrlen, __MF_CHECK_WRITE, "bind addr"); + return bind (sockfd, addr, addrlen); +} +#endif + +#ifdef WRAP_connect +#include +WRAPPER2(int, connect, int sockfd, const struct sockaddr *addr, + socklen_t addrlen) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (addr, (size_t)addrlen, __MF_CHECK_READ, + "connect addr"); + return connect (sockfd, addr, addrlen); +} +#endif + +#ifdef WRAP_gethostname +WRAPPER2(int, gethostname, char *name, size_t len) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (name, len, __MF_CHECK_WRITE, "gethostname name"); + return gethostname (name, len); +} +#endif + +#ifdef WRAP_sethostname +WRAPPER2(int, sethostname, const char *name, size_t len) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (name, len, __MF_CHECK_READ, "sethostname name"); + return sethostname (name, len); +} +#endif + +#ifdef WRAP_gethostbyname +#include +WRAPPER2(struct hostent *, gethostbyname, const char *name) +{ + struct hostent *p; + char **ss; + char *s; + size_t n; + int nreg; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (name); + MF_VALIDATE_EXTENT (name, CLAMPADD(n, 1), __MF_CHECK_READ, + "gethostbyname name"); + p = gethostbyname (name); + if (NULL != p) { +#ifdef MF_REGISTER_gethostbyname + __mf_register (p, sizeof (*p), MF_REGISTER_gethostbyname, + "gethostbyname result"); +#endif + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_WRITE, + "gethostbyname result"); + if (NULL != (s = p->h_name)) { + n = strlen (s); + n = CLAMPADD(n, 1); +#ifdef MF_REGISTER_gethostbyname_items + __mf_register (s, n, MF_REGISTER_gethostbyname_items, + "gethostbyname result->h_name"); +#endif + MF_VALIDATE_EXTENT (s, n, __MF_CHECK_WRITE, + "gethostbyname result->h_name"); + } + + if (NULL != (ss = p->h_aliases)) { + for (nreg = 1;; ++nreg) { + s = *ss++; + if (NULL == s) + break; + n = strlen (s); + n = CLAMPADD(n, 1); +#ifdef MF_REGISTER_gethostbyname_items + __mf_register (s, n, MF_REGISTER_gethostbyname_items, + "gethostbyname result->h_aliases[]"); +#endif + MF_VALIDATE_EXTENT (s, n, __MF_CHECK_WRITE, + "gethostbyname result->h_aliases[]"); + } + nreg *= sizeof (*p->h_aliases); +#ifdef MF_REGISTER_gethostbyname_items + __mf_register (p->h_aliases, nreg, MF_REGISTER_gethostbyname_items, + "gethostbyname result->h_aliases"); +#endif + MF_VALIDATE_EXTENT (p->h_aliases, nreg, __MF_CHECK_WRITE, + "gethostbyname result->h_aliases"); + } + + if (NULL != (ss = p->h_addr_list)) { + for (nreg = 1;; ++nreg) { + s = *ss++; + if (NULL == s) + break; +#ifdef MF_REGISTER_gethostbyname_items + __mf_register (s, p->h_length, MF_REGISTER_gethostbyname_items, + "gethostbyname result->h_addr_list[]"); +#endif + MF_VALIDATE_EXTENT (s, p->h_length, __MF_CHECK_WRITE, + "gethostbyname result->h_addr_list[]"); + } + nreg *= sizeof (*p->h_addr_list); +#ifdef MF_REGISTER_gethostbyname_items + __mf_register (p->h_addr_list, nreg, MF_REGISTER_gethostbyname_items, + "gethostbyname result->h_addr_list"); +#endif + MF_VALIDATE_EXTENT (p->h_addr_list, nreg, __MF_CHECK_WRITE, + "gethostbyname result->h_addr_list"); + } + } + return p; +} +#endif + +#ifdef WRAP_wait +#include +WRAPPER2(pid_t, wait, int *status) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + if (NULL != status) + MF_VALIDATE_EXTENT (status, sizeof (*status), __MF_CHECK_WRITE, + "wait status"); + return wait (status); +} +#endif + +#ifdef WRAP_waitpid +#include +WRAPPER2(pid_t, waitpid, pid_t pid, int *status, int options) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + if (NULL != status) + MF_VALIDATE_EXTENT (status, sizeof (*status), __MF_CHECK_WRITE, + "waitpid status"); + return waitpid (pid, status, options); +} +#endif + +#ifdef WRAP_popen +WRAPPER2(FILE *, popen, const char *command, const char *mode) +{ + size_t n; + FILE *p; + TRACE ("%s\n", __PRETTY_FUNCTION__); + + n = strlen (command); + MF_VALIDATE_EXTENT (command, CLAMPADD(n, 1), __MF_CHECK_READ, "popen path"); + + n = strlen (mode); + MF_VALIDATE_EXTENT (mode, CLAMPADD(n, 1), __MF_CHECK_READ, "popen mode"); + + p = popen (command, mode); + if (NULL != p) { +#ifdef MF_REGISTER_fopen + __mf_register (p, sizeof (*p), MF_REGISTER_fopen, "popen result"); +#endif + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_WRITE, "popen result"); + } + return p; +} +#endif + +#ifdef WRAP_pclose +WRAPPER2(int, pclose, FILE *stream) +{ + int resp; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (stream, sizeof (*stream), __MF_CHECK_WRITE, + "pclose stream"); + resp = pclose (stream); +#ifdef MF_REGISTER_fopen + __mf_unregister (stream, sizeof (*stream)); +#endif + return resp; +} +#endif + +#ifdef WRAP_execve +WRAPPER2(int, execve, const char *path, char *const argv [], + char *const envp[]) +{ + size_t n; + char *const *p; + const char *s; + TRACE ("%s\n", __PRETTY_FUNCTION__); + + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "execve path"); + + for (p = argv;;) { + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_READ, "execve *argv"); + s = *p++; + if (NULL == s) + break; + n = strlen (s); + MF_VALIDATE_EXTENT (s, CLAMPADD(n, 1), __MF_CHECK_READ, "execve **argv"); + } + + for (p = envp;;) { + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_READ, "execve *envp"); + s = *p++; + if (NULL == s) + break; + n = strlen (s); + MF_VALIDATE_EXTENT (s, CLAMPADD(n, 1), __MF_CHECK_READ, "execve **envp"); + } + return execve (path, argv, envp); +} +#endif + +#ifdef WRAP_execv +WRAPPER2(int, execv, const char *path, char *const argv []) +{ + size_t n; + char *const *p; + const char *s; + TRACE ("%s\n", __PRETTY_FUNCTION__); + + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "execv path"); + + for (p = argv;;) { + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_READ, "execv *argv"); + s = *p++; + if (NULL == s) + break; + n = strlen (s); + MF_VALIDATE_EXTENT (s, CLAMPADD(n, 1), __MF_CHECK_READ, "execv **argv"); + } + return execv (path, argv); +} +#endif + +#ifdef WRAP_execvp +WRAPPER2(int, execvp, const char *path, char *const argv []) +{ + size_t n; + char *const *p; + const char *s; + TRACE ("%s\n", __PRETTY_FUNCTION__); + + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "execvp path"); + + for (p = argv;;) { + MF_VALIDATE_EXTENT (p, sizeof (*p), __MF_CHECK_READ, "execvp *argv"); + s = *p++; + if (NULL == s) + break; + n = strlen (s); + MF_VALIDATE_EXTENT (s, CLAMPADD(n, 1), __MF_CHECK_READ, "execvp **argv"); + } + return execvp (path, argv); +} +#endif + +#ifdef WRAP_system +WRAPPER2(int, system, const char *string) +{ + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (string); + MF_VALIDATE_EXTENT (string, CLAMPADD(n, 1), __MF_CHECK_READ, + "system string"); + return system (string); +} +#endif + +#ifdef WRAP_dlopen +WRAPPER2(void *, dlopen, const char *path, int flags) +{ + void *p; + size_t n; + TRACE ("%s\n", __PRETTY_FUNCTION__); + n = strlen (path); + MF_VALIDATE_EXTENT (path, CLAMPADD(n, 1), __MF_CHECK_READ, "dlopen path"); + p = dlopen (path, flags); + if (NULL != p) { +#ifdef MF_REGISTER_dlopen + __mf_register (p, 0, MF_REGISTER_dlopen, "dlopen result"); +#endif + MF_VALIDATE_EXTENT (p, 0, __MF_CHECK_WRITE, "dlopen result"); + } + return p; +} +#endif + +#ifdef WRAP_dlclose +WRAPPER2(int, dlclose, void *handle) +{ + int resp; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (handle, 0, __MF_CHECK_READ, "dlclose handle"); + resp = dlclose (handle); +#ifdef MF_REGISTER_dlopen + __mf_unregister (handle, 0); +#endif + return resp; +} +#endif + +#ifdef WRAP_dlerror +WRAPPER2(char *, dlerror) +{ + char *p; + TRACE ("%s\n", __PRETTY_FUNCTION__); + p = dlerror (); + if (NULL != p) { + size_t n; + n = strlen (p); + n = CLAMPADD(n, 1); +#ifdef MF_REGISTER_dlerror + __mf_register (p, n, MF_REGISTER_dlerror, "dlerror result"); +#endif + MF_VALIDATE_EXTENT (p, n, __MF_CHECK_WRITE, "dlerror result"); + } + return p; +} +#endif + +#ifdef WRAP_dlsym +WRAPPER2(void *, dlsym, void *handle, char *symbol) +{ + size_t n; + void *p; + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (handle, 0, __MF_CHECK_READ, "dlsym handle"); + n = strlen (symbol); + MF_VALIDATE_EXTENT (symbol, CLAMPADD(n, 1), __MF_CHECK_READ, "dlsym symbol"); + p = dlsym (handle, symbol); + if (NULL != p) { +#ifdef MF_REGISTER_dlsym + __mf_register (p, 0, MF_REGISTER_dlsym, "dlsym result"); +#endif + MF_VALIDATE_EXTENT (p, 0, __MF_CHECK_WRITE, "dlsym result"); + } + return p; +} +#endif + +#ifdef WRAP_semop +#include +#include +WRAPPER2(int, semop, int semid, struct sembuf *sops, unsigned nsops) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT (sops, sizeof (*sops) * nsops, __MF_CHECK_READ, + "semop sops"); + return semop (semid, sops, nsops); +} +#endif + +#ifdef WRAP_semctl +#include +#include +#ifndef HAVE_UNION_SEMUN +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ + unsigned short int *array; /* array for GETALL, SETALL */ + struct seminfo *__buf; /* buffer for IPC_INFO */ +}; +#endif +WRAPPER2(int, semctl, int semid, int semnum, int cmd, union semun arg) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + switch (cmd) { + case IPC_STAT: + MF_VALIDATE_EXTENT (arg.buf, sizeof (*arg.buf), __MF_CHECK_WRITE, + "semctl buf"); + break; + case IPC_SET: + MF_VALIDATE_EXTENT (arg.buf, sizeof (*arg.buf), __MF_CHECK_READ, + "semctl buf"); + break; + case GETALL: + MF_VALIDATE_EXTENT (arg.array, sizeof (*arg.array), __MF_CHECK_WRITE, + "semctl array"); + case SETALL: + MF_VALIDATE_EXTENT (arg.array, sizeof (*arg.array), __MF_CHECK_READ, + "semctl array"); + break; +#ifdef IPC_INFO + /* FreeBSD 5.1 headers include IPC_INFO but not the __buf field. */ +#if !defined(__FreeBSD__) + case IPC_INFO: + MF_VALIDATE_EXTENT (arg.__buf, sizeof (*arg.__buf), __MF_CHECK_WRITE, + "semctl __buf"); + break; +#endif +#endif + default: + break; + } + return semctl (semid, semnum, cmd, arg); +} +#endif + +#ifdef WRAP_shmctl +#include +#include +WRAPPER2(int, shmctl, int shmid, int cmd, struct shmid_ds *buf) +{ + TRACE ("%s\n", __PRETTY_FUNCTION__); + switch (cmd) { + case IPC_STAT: + MF_VALIDATE_EXTENT (buf, sizeof (*buf), __MF_CHECK_WRITE, + "shmctl buf"); + break; + case IPC_SET: + MF_VALIDATE_EXTENT (buf, sizeof (*buf), __MF_CHECK_READ, + "shmctl buf"); + break; + default: + break; + } + return shmctl (shmid, cmd, buf); +} +#endif + +#ifdef WRAP_shmat +#include +#include +WRAPPER2(void *, shmat, int shmid, const void *shmaddr, int shmflg) +{ + void *p; + TRACE ("%s\n", __PRETTY_FUNCTION__); + p = shmat (shmid, shmaddr, shmflg); +#ifdef MF_REGISTER_shmat + if (NULL != p) { + struct shmid_ds buf; + __mf_register (p, shmctl (shmid, IPC_STAT, &buf) ? 0 : buf.shm_segsz, + MF_REGISTER_shmat, "shmat result"); + } +#endif + return p; +} +#endif + +#ifdef WRAP_shmdt +#include +#include +WRAPPER2(int, shmdt, const void *shmaddr) +{ + int resp; + TRACE ("%s\n", __PRETTY_FUNCTION__); + resp = shmdt (shmaddr); +#ifdef MF_REGISTER_shmat + __mf_unregister ((void *)shmaddr, 0); +#endif + return resp; +} +#endif + diff --git a/libmudflap/mf-hooks3.c b/libmudflap/mf-hooks3.c new file mode 100644 index 00000000000..838f3810db5 --- /dev/null +++ b/libmudflap/mf-hooks3.c @@ -0,0 +1,573 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + + +#include "config.h" + +#ifndef HAVE_SOCKLEN_T +#define socklen_t int +#endif + +/* These attempt to coax various unix flavours to declare all our + needed tidbits in the system headers. */ +#if !defined(__FreeBSD__) && !defined(__APPLE__) +#define _POSIX_SOURCE +#endif /* Some BSDs break if this is defined. */ +#define _GNU_SOURCE +#define _XOPEN_SOURCE +#define _BSD_TYPES +#define __EXTENSIONS__ +#define _ALL_SOURCE +#define _LARGE_FILE_API +#define _XOPEN_SOURCE_EXTENDED 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mf-runtime.h" +#include "mf-impl.h" + +#ifdef _MUDFLAP +#error "Do not compile this file with -fmudflap!" +#endif + + +/* Multithreading support hooks. */ + + +#ifdef WRAP_pthreadstuff + + +#ifndef LIBMUDFLAPTH +#error "pthreadstuff is to be included only in libmudflapth" +#endif + + + +/* Describe a thread (dead or alive). */ +struct pthread_info +{ + short used_p; /* Is this slot in use? */ + short dead_p; /* Is this thread dead? */ + pthread_t self; /* The thread id. */ + + /* If libmudflapth allocated the stack, store its base/size. */ + void *stack; + size_t stack_size; + + int *thread_errno; + enum __mf_state_enum state; +}; + + +/* Describe the startup information for a new user thread. */ +struct pthread_start_info +{ + /* The user's thread entry point and argument. */ + void * (*user_fn)(void *); + void *user_arg; + + /* Set by user thread when this startup struct may be disposed of. */ + struct pthread_info *thread_info; +}; + + + + +/* To avoid dynamic memory allocation, use static array to store these + thread description structs. The second (_idx) array is used as a + simple caching hash table, mapping PTHREAD_HASH(thread) to its + index in __mf_pthread_info[]. */ + +#define LIBMUDFLAPTH_THREADS_MAX 1024 +static struct pthread_info __mf_pthread_info[LIBMUDFLAPTH_THREADS_MAX]; +static unsigned __mf_pthread_info_idx[LIBMUDFLAPTH_THREADS_MAX]; +#define PTHREAD_HASH(p) ((unsigned) (p) % LIBMUDFLAPTH_THREADS_MAX) + + +/* Find any old empty entry in __mf_pthread_info; mark it used and + return it. Return NULL if there are no more available slots. */ +struct pthread_info* +__mf_allocate_blank_threadinfo (unsigned* idx) +{ + static unsigned probe = LIBMUDFLAPTH_THREADS_MAX-1; + unsigned probe_at_start = probe; + static pthread_mutex_t mutex = +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; +#else + PTHREAD_MUTEX_INITIALIZER; +#endif + int rc; + + rc = pthread_mutex_lock (& mutex); + assert (rc == 0); + + /* Look for a blank spot starting one past the last one we found. */ + do + { + probe = (probe + 1) % LIBMUDFLAPTH_THREADS_MAX; + struct pthread_info* pi = & __mf_pthread_info [probe]; + if (! pi->used_p) + { + /* memset (pi, 0, sizeof (*pi)); */ + pi->used_p = 1; + if (idx != NULL) *idx = probe; + /* VERBOSE_TRACE ("allocated threadinfo slot %u\n", probe); */ + rc = pthread_mutex_unlock (& mutex); + assert (rc == 0); + return pi; + } + } + while (probe != probe_at_start); + + rc = pthread_mutex_unlock (& mutex); + assert (rc == 0); + return NULL; +} + + +/* Find and return the pthread_info struct for the current thread. + There might already be one in __mf_pthread_info for this thread, in + which case return it. There may not be one (if this is a main + thread, an auxiliary -lpthread manager, or an actual user thread + making an early call into libmudflap. In these cases, create a new + entry. If not it's not the main thread, put it into reentrant + initial state. +*/ +static struct pthread_info* +__mf_find_threadinfo () +{ + pthread_t it = pthread_self (); + unsigned *hash = & __mf_pthread_info_idx [PTHREAD_HASH (it)]; + struct pthread_info *result = NULL; + static pthread_t last; + static int main_thread_seen_p; + + /* Check out the lookup cache; failing that, do a linear search + around the table. */ + { + struct pthread_info* pi = & __mf_pthread_info [*hash]; + unsigned i; + + if (pi->used_p && pi->self == it) + result = pi; + else for (i = 0; i < LIBMUDFLAPTH_THREADS_MAX; i++) + { + struct pthread_info* pi2 = & __mf_pthread_info [i]; + if (pi2->used_p && pi2->self == it) + { + *hash = i; + result = pi2; + break; + } + } + } + + if (result == NULL) + { + /* Create a __mf_pthread_info record for the main thread. It's + different from the auto-recognized worker bees because for + example we can assume that it's a fully stack/errno-equipped + thread. */ + + /* This must be the main thread, until now unseen in libmudflap. */ + unsigned *hash = & __mf_pthread_info_idx [PTHREAD_HASH (it)]; + struct pthread_info* pi = __mf_allocate_blank_threadinfo (hash); + assert (pi != NULL); + assert (pi->used_p); + result = pi; + result->self = it; + + if (! main_thread_seen_p) + { + result->state = active; + /* NB: leave result->thread_errno unset, as main thread's errno + has already been registered in __mf_init. */ + /* NB: leave stack-related fields unset, to avoid + deallocation. */ + main_thread_seen_p = 1; + VERBOSE_TRACE ("identified self as main thread\n"); + } + else + { + result->state = reentrant; + /* NB: leave result->thread_errno unset, as worker thread's + errno is unlikely to be used, and user threads fill them + in during __mf_pthread_spawn(). */ + /* NB: leave stack-related fields unset, leaving pthread_create + to fill them in for user threads, leaving them empty for + other threads. */ + VERBOSE_TRACE ("identified self as new aux or user thread\n"); + } + } + + if (last != it) + { + VERBOSE_TRACE ("found threadinfo for %u, slot %u\n", + (unsigned) it, + (unsigned) *hash); + last = it; + } + + assert (result != NULL); + assert (result->self == it); + + return result; +} + + + +/* Return a pointer to the per-thread __mf_state variable. */ +enum __mf_state_enum * +__mf_state_perthread () +{ + assert (! __mf_starting_p); + return & (__mf_find_threadinfo()->state); +} + + +static void +__mf_pthread_cleanup (void *arg) +{ + struct pthread_info *pi = arg; + + /* XXX: This unregistration is not safe on platforms where distinct + threads share errno (or at least its virtual address). */ + if (pi->thread_errno != NULL) + __mf_unregister (pi->thread_errno, sizeof (int)); + + /* XXX: Only detached threads should designate themselves as dead + here. Non-detached threads are marked dead after their + personalized pthread_join() call. */ + pi->state = reentrant; + pi->dead_p = 1; + + VERBOSE_TRACE ("thread pi %p exiting\n", pi); +} + + +static void * +__mf_pthread_spawner (void *arg) +{ + struct pthread_info *pi = __mf_find_threadinfo (); + void *result = NULL; + + /* Turn off reentrancy indications. */ + assert (pi->state == reentrant); + pi->state = active; + + VERBOSE_TRACE ("new user thread\n"); + + if (__mf_opts.heur_std_data) + { + pi->thread_errno = & errno; + __mf_register (pi->thread_errno, sizeof (int), + __MF_TYPE_GUESS, "errno area (thread)"); + /* NB: we could use __MF_TYPE_STATIC above, but we guess that + the thread errno is coming out of some dynamically allocated + pool that we already know of as __MF_TYPE_HEAP. */ + } + + /* We considered using pthread_key_t objects instead of these + cleanup stacks, but they were less cooperative with the + interposed malloc hooks in libmudflap. */ + pthread_cleanup_push (& __mf_pthread_cleanup, pi); + + /* Call user thread */ + { + /* Extract given entry point and argument. */ + struct pthread_start_info *psi = arg; + void * (*user_fn)(void *) = psi->user_fn; + void *user_arg = psi->user_arg; + + /* Signal the main thread to resume. */ + psi->thread_info = pi; + + result = (*user_fn)(user_arg); + } + + pthread_cleanup_pop (1 /* execute */); + + /* NB: there is a slight race here. The pthread_info field will now + say this thread is dead, but it may still be running .. right + here. We try to check for this possibility using the + pthread_kill test below. */ + + return result; +} + + +#if PIC +/* A special bootstrap variant. */ +int +__mf_0fn_pthread_create (pthread_t *thr, const pthread_attr_t *attr, + void * (*start) (void *), void *arg) +{ + return -1; +} +#endif + + +#undef pthread_create +WRAPPER(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr, + void * (*start) (void *), void *arg) +{ + DECLARE(int, munmap, void *p, size_t l); + DECLARE(void *, mmap, void *p, size_t l, int prot, int flags, int fd, off_t of); + DECLARE(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr, + void * (*start) (void *), void *arg); + int result; + pthread_attr_t override_attr; + void *override_stack; + size_t override_stacksize; + unsigned i; + + TRACE ("pthread_create\n"); + + /* Garbage-collect dead threads' stacks. */ + LOCKTH (); + for (i = 0; i < LIBMUDFLAPTH_THREADS_MAX; i++) + { + struct pthread_info *pi = & __mf_pthread_info [i]; + if (! pi->used_p) + continue; + if (! pi->dead_p) + continue; + + /* VERBOSE_TRACE ("thread %u pi %p stack cleanup deferred (%u)\n", + (unsigned) pi->self, pi, pi->dead_p); */ + + /* Delay actual deallocation by a few cycles, try to discourage the + race mentioned at the end of __mf_pthread_spawner(). */ + if (pi->dead_p) + pi->dead_p ++; + if (pi->dead_p >= 10 /* XXX */) + { + if (pi->stack) + CALL_REAL (munmap, pi->stack, pi->stack_size); + + VERBOSE_TRACE ("slot %u freed, stack %p\n", i, pi->stack); + memset (pi, 0, sizeof (*pi)); + + /* One round of garbage collection is enough. */ + break; + } + } + UNLOCKTH (); + + /* Let's allocate a stack for this thread, if one is not already + supplied by the caller. We don't want to let e.g. the + linuxthreads manager thread do this allocation. */ + if (attr != NULL) + override_attr = *attr; + else + pthread_attr_init (& override_attr); + + /* Get supplied attributes, if any. */ + /* XXX: consider using POSIX2K attr_getstack() */ + if (pthread_attr_getstackaddr (& override_attr, & override_stack) != 0 || + pthread_attr_getstacksize (& override_attr, & override_stacksize) != 0) + { + override_stack = NULL; + override_stacksize = 0; + } + + /* Do we need to allocate the new thread's stack? */ + if (__mf_opts.thread_stack && override_stack == NULL) + { + uintptr_t alignment = 256; /* power of two */ + + /* Perturb the initial stack addresses slightly, to encourage + threads to have nonconflicting entries in the lookup cache + for their tracked stack objects. */ + static unsigned perturb = 0; + const unsigned perturb_delta = 32; + const unsigned perturb_count = 16; + perturb += perturb_delta; + if (perturb > perturb_delta*perturb_count) perturb = 0; + + /* Use glibc x86 defaults */ +/* Should have been defined in */ +#ifndef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 65536 +#endif + override_stacksize = max (PTHREAD_STACK_MIN, __mf_opts.thread_stack * 1024); + + +#if defined(MAP_ANONYMOUS) +#define MF_MAP_ANON MAP_ANONYMOUS +#elif defined(MAP_ANON) +#define MF_MAP_ANON MAP_ANON +#else +#error "Cannot mmap anonymous memory." +#endif + + override_stack = CALL_REAL (mmap, NULL, override_stacksize, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MF_MAP_ANON, + 0, 0); + if (override_stack == 0 || override_stack == MAP_FAILED) + { + errno = EAGAIN; + return -1; + } + + VERBOSE_TRACE ("thread stack alloc %p size %lu\n", + override_stack, (unsigned long) override_stacksize); + + /* The stackaddr pthreads attribute is a candidate stack pointer. + It must point near the top or the bottom of this buffer, depending + on whether stack grows downward or upward, and suitably aligned. + On the x86, it grows down, so we set stackaddr near the top. */ + override_stack = (void *) + (((uintptr_t) override_stack + override_stacksize - alignment - perturb) + & (~(uintptr_t)(alignment-1))); + + /* XXX: consider using POSIX2K attr_setstack() */ + if (pthread_attr_setstackaddr (& override_attr, override_stack) != 0 || + pthread_attr_setstacksize (& override_attr, + override_stacksize - alignment - perturb) != 0) + { + /* This should not happen. */ + CALL_REAL (munmap, override_stack, override_stacksize); + errno = EAGAIN; + return -1; + } + } + + /* Actually start the child thread. */ + { + struct pthread_start_info psi; + struct pthread_info *pi = NULL; + + /* Fill in startup-control fields. */ + psi.user_fn = start; + psi.user_arg = arg; + psi.thread_info = NULL; + + /* Actually create the thread. */ + __mf_state = reentrant; + result = CALL_REAL (pthread_create, thr, & override_attr, + & __mf_pthread_spawner, (void *) & psi); + __mf_state = active; + /* We also hook pthread_join/pthread_exit to get into reentrant + mode during thread shutdown/cleanup. */ + + /* Wait until child thread has progressed far enough into its + __mf_pthread_spawner() call. */ + while (1) /* XXX: timeout? */ + { + volatile struct pthread_start_info *psip = & psi; + pi = psip->thread_info; + if (pi != NULL) + break; + sched_yield (); + } + + /* Fill in remaining fields in pthread_info. */ + pi->stack = override_stack; + pi->stack_size = override_stacksize; + /* XXX: this might be too late for future heuristics that attempt + to use thread stack bounds. We may need to put the new thread + to sleep. */ + } + + + /* May need to clean up if we created a pthread_attr_t of our own. */ + if (attr == NULL) + pthread_attr_destroy (& override_attr); /* NB: this shouldn't deallocate stack */ + + return result; +} + + + +#if PIC +/* A special bootstrap variant. */ +int +__mf_0fn_pthread_join (pthread_t thr, void **rc) +{ + return -1; +} +#endif + + +#undef pthread_join +WRAPPER(int, pthread_join, pthread_t thr, void **rc) +{ + DECLARE(int, pthread_join, pthread_t thr, void **rc); + int result; + + TRACE ("pthread_join\n"); + __mf_state = reentrant; + result = CALL_REAL (pthread_join, thr, rc); + __mf_state = active; + + return result; +} + + +#if PIC +/* A special bootstrap variant. */ +void +__mf_0fn_pthread_exit (void *rc) +{ +} +#endif + + +#undef pthread_exit +WRAPPER(void, pthread_exit, void *rc) +{ + DECLARE(void, pthread_exit, void *rc); + + TRACE ("pthread_exit\n"); + /* __mf_state = reentrant; */ + CALL_REAL (pthread_exit, rc); + /* NOTREACHED */ +} + + + + + + + +#endif /* pthreadstuff */ diff --git a/libmudflap/mf-impl.h b/libmudflap/mf-impl.h new file mode 100644 index 00000000000..05120bfe4b6 --- /dev/null +++ b/libmudflap/mf-impl.h @@ -0,0 +1,389 @@ +/* Implementation header for mudflap runtime library. + Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef __MF_IMPL_H +#define __MF_IMPL_H + +#ifdef _MUDFLAP +#error "Do not compile this file with -fmudflap!" +#endif + +#if HAVE_PTHREAD_H +#include +#elif LIBMUDFLAPTH +#error "Cannot build libmudflapth without pthread.h." +#endif + + +/* Private definitions related to mf-runtime.h */ + +#define __MF_TYPE_MAX_CEM __MF_TYPE_STACK /* largest type# for the cemetary */ +#define __MF_TYPE_MAX __MF_TYPE_GUESS + + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* Address calculation macros. */ + +#define MINPTR ((uintptr_t) 0) +#define MAXPTR (~ (uintptr_t) 0) + +/* Clamp the addition/subtraction of uintptr_t's to [MINPTR,MAXPTR] */ +#define CLAMPSUB(ptr,offset) (((uintptr_t) ptr) >= (offset) ? ((uintptr_t) ptr)-((uintptr_t) offset) : MINPTR) +#define CLAMPADD(ptr,offset) (((uintptr_t) ptr) <= MAXPTR-(offset) ? ((uintptr_t) ptr)+((uintptr_t) offset) : MAXPTR) +#define CLAMPSZ(ptr,size) ((size) ? (((uintptr_t) ptr) <= MAXPTR-(size)+1 ? ((uintptr_t) ptr)+((uintptr_t) size) - 1 : MAXPTR) : ((uintptr_t) ptr)) + +#define __MF_CACHE_INDEX(ptr) ((((uintptr_t) (ptr)) >> __mf_lc_shift) & __mf_lc_mask) +#define __MF_CACHE_MISS_P(ptr,sz) ({ \ + struct __mf_cache *elem = & __mf_lookup_cache[__MF_CACHE_INDEX((ptr))]; \ + ((elem->low > (uintptr_t) (ptr)) || \ + (elem->high < (CLAMPADD((uintptr_t) (ptr), (uintptr_t) CLAMPSUB(sz,1) )))); }) +/* XXX: the above should use CLAMPSZ () */ + + + +/* Private functions. */ + +extern void __mf_violation (void *ptr, size_t sz, + uintptr_t pc, const char *location, + int type); +extern size_t __mf_backtrace (char ***, void *, unsigned); +extern int __mf_heuristic_check (uintptr_t, uintptr_t); + +/* ------------------------------------------------------------------------ */ +/* Type definitions. */ +/* ------------------------------------------------------------------------ */ + +/* The mf_state type codes describe recursion and initialization order. */ + +enum __mf_state_enum { active, reentrant }; + +/* The __mf_options structure records optional or tunable aspects of the + mudflap library's behavior. There is a single global instance of this + structure which is populated from user input (in an environment variable) + when the library initializes. */ + +struct __mf_options +{ + /* Emit a trace message for each call. */ + unsigned trace_mf_calls; + + /* Collect and emit statistics. */ + unsigned collect_stats; + + /* Set up a SIGUSR1 -> __mf_report handler. */ + unsigned sigusr1_report; + + /* Execute internal checking code. */ + unsigned internal_checking; + + /* Age object liveness periodically. */ + unsigned tree_aging; + + /* Adapt the lookup cache to working set. */ + unsigned adapt_cache; + + /* Print list of leaked heap objects on shutdown. */ + unsigned print_leaks; + + /* Detect reads of uninitialized objects. */ + unsigned check_initialization; + + /* Print verbose description of violations. */ + unsigned verbose_violations; + + /* Abbreviate duplicate object descriptions. */ + unsigned abbreviate; + + /* Emit internal tracing message. */ + unsigned verbose_trace; + + /* Support multiple threads. XXX: not yet implemented. */ + /* unsigned multi_threaded; */ + + /* Wipe stack/heap objects upon unwind. */ + unsigned wipe_stack; + unsigned wipe_heap; + + /* Maintain a queue of this many deferred free()s, + to trap use of freed memory. */ + unsigned free_queue_length; + + /* Maintain a history of this many past unregistered objects. */ + unsigned persistent_count; + + /* Pad allocated extents by this many bytes on either side. */ + unsigned crumple_zone; + + /* Maintain this many stack frames for contexts. */ + unsigned backtrace; + +#ifdef LIBMUDFLAPTH + /* Thread stack size. */ + unsigned thread_stack; +#endif + + /* Major operation mode */ + enum + { + mode_nop, /* mudflaps do nothing */ + mode_populate, /* mudflaps populate tree but do not check for violations */ + mode_check, /* mudflaps populate and check for violations (normal) */ + mode_violate /* mudflaps trigger a violation on every call (diagnostic) */ + } + mudflap_mode; + + + /* How to handle a violation. */ + + enum + { + viol_nop, /* Return control to application. */ + viol_segv, /* Signal self with segv. */ + viol_abort, /* Call abort (). */ + viol_gdb /* Fork a debugger on self */ + } + violation_mode; + + /* Violation heuristics selection. */ + unsigned heur_stack_bound; /* allow current stack region */ + unsigned heur_proc_map; /* allow & cache /proc/self/map regions. */ + unsigned heur_start_end; /* allow _start .. _end */ + unsigned heur_std_data; /* allow & cache stdlib data */ +}; + + +#ifdef PIC + +/* This is a table of dynamically resolved function pointers. */ + +struct __mf_dynamic_entry +{ + void *pointer; + char *name; + char *version; +}; + +/* The definition of the array (mf-runtime.c) must match the enums! */ +extern struct __mf_dynamic_entry __mf_dynamic[]; +enum __mf_dynamic_index +{ + dyn_calloc, dyn_free, dyn_malloc, dyn_mmap, + dyn_munmap, dyn_realloc, + dyn_INITRESOLVE, /* Marker for last init-time resolution. */ +#ifdef LIBMUDFLAPTH + dyn_pthread_create, + dyn_pthread_join, + dyn_pthread_exit +#endif +}; + +#endif /* PIC */ + +/* ------------------------------------------------------------------------ */ +/* Private global variables. */ +/* ------------------------------------------------------------------------ */ + +#ifdef LIBMUDFLAPTH +extern pthread_mutex_t __mf_biglock; +#define LOCKTH() do { extern unsigned long __mf_lock_contention; \ + int rc = pthread_mutex_trylock (& __mf_biglock); \ + if (rc) { __mf_lock_contention ++; \ + rc = pthread_mutex_lock (& __mf_biglock); } \ + assert (rc==0); } while (0) +#define UNLOCKTH() do { int rc = pthread_mutex_unlock (& __mf_biglock); \ + assert (rc==0); } while (0) +#else +#define LOCKTH() do {} while (0) +#define UNLOCKTH() do {} while (0) +#endif + +#ifdef LIBMUDFLAPTH +extern enum __mf_state_enum *__mf_state_perthread (); +#define __mf_state (* __mf_state_perthread ()) +#else +extern enum __mf_state_enum __mf_state; +#endif +extern int __mf_starting_p; + +extern struct __mf_options __mf_opts; + +/* ------------------------------------------------------------------------ */ +/* Utility macros. */ +/* ------------------------------------------------------------------------ */ + +#define UNLIKELY(e) (__builtin_expect (!!(e), 0)) +#define LIKELY(e) (__builtin_expect (!!(e), 1)) +#define STRINGIFY2(e) #e +#define STRINGIFY(e) STRINGIFY2(e) + +#ifdef LIBMUDFLAPTH +#define VERBOSE_TRACE(...) \ + do { if (UNLIKELY (__mf_opts.verbose_trace)) { \ + fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \ + fprintf (stderr, __VA_ARGS__); \ + } } while (0) +#define TRACE(...) \ + do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \ + fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \ + fprintf (stderr, __VA_ARGS__); \ + } } while (0) +#else +#define VERBOSE_TRACE(...) \ + do { if (UNLIKELY (__mf_opts.verbose_trace)) { \ + fprintf (stderr, "mf: "); \ + fprintf (stderr, __VA_ARGS__); \ + } } while (0) +#define TRACE(...) \ + do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \ + fprintf (stderr, "mf: "); \ + fprintf (stderr, __VA_ARGS__); \ + } } while (0) +#endif + + +#define __MF_PERSIST_MAX 256 +#define __MF_FREEQ_MAX 256 + +/* + Wrapping and redirection: + + Mudflap redirects a number of libc functions into itself, for "cheap" + verification (eg. strcpy, bzero, memcpy) and also to register / + unregister regions of memory as they are manipulated by the program + (eg. malloc/free, mmap/munmap). + + There are two methods of wrapping. + + (1) The static method involves a list of -wrap=foo flags being passed to + the linker, which then links references to "foo" to the symbol + "__wrap_foo", and links references to "__real_foo" to the symbol "foo". + When compiled without -DPIC, libmudflap.a contains such __wrap_foo + functions which delegate to __real_foo functions in libc to get their + work done. + + (2) The dynamic method involves providing a definition of symbol foo in + libmudflap.so and linking it earlier in the compiler command line, + before libc.so. The function "foo" in libmudflap must then call + dlsym(RTLD_NEXT, "foo") to acquire a pointer to the "real" libc foo, or + at least the "next" foo in the dynamic link resolution order. + + We switch between these two techniques by the presence of the -DPIC + #define passed in by libtool when building libmudflap. +*/ + + +#ifdef PIC + +extern void __mf_resolve_single_dynamic (struct __mf_dynamic_entry *); + +#define _GNU_SOURCE +#include + +#define WRAPPER(ret, fname, ...) \ +ret __wrap_ ## fname (__VA_ARGS__) \ + __attribute__ (( alias (#fname) )); \ +ret __real_ ## fname (__VA_ARGS__) \ + __attribute__ (( alias (#fname) )); \ +ret fname (__VA_ARGS__) +#define DECLARE(ty, fname, ...) \ + typedef ty (*__mf_fn_ ## fname) (__VA_ARGS__); \ + extern ty __mf_0fn_ ## fname (__VA_ARGS__); +#define CALL_REAL(fname, ...) \ + ({__mf_starting_p \ + ? __mf_0fn_ ## fname (__VA_ARGS__) \ + : (__mf_resolve_single_dynamic (& __mf_dynamic[dyn_ ## fname]), \ + (((__mf_fn_ ## fname)(__mf_dynamic[dyn_ ## fname].pointer)) (__VA_ARGS__)));}) +#define CALL_BACKUP(fname, ...) \ + __mf_0fn_ ## fname(__VA_ARGS__) + +#else /* not PIC --> static library */ + +#define WRAPPER(ret, fname, ...) \ +ret __wrap_ ## fname (__VA_ARGS__) +#define DECLARE(ty, fname, ...) \ + extern ty __real_ ## fname (__VA_ARGS__) +#define CALL_REAL(fname, ...) \ + __real_ ## fname (__VA_ARGS__) +#define CALL_BACKUP(fname, ...) \ + __real_ ## fname(__VA_ARGS__) + +#endif /* PIC */ + +/* WRAPPER2 is for functions intercepted via macros at compile time. */ +#define WRAPPER2(ret, fname, ...) \ +ret __mfwrap_ ## fname (__VA_ARGS__) + + +/* Utility macros for mf-hooks*.c */ + +#define MF_VALIDATE_EXTENT(value,size,acc,context) \ + do { \ + if (UNLIKELY (size > 0 && __MF_CACHE_MISS_P (value, size))) \ + __mf_check ((void *) (value), (size), acc, "(" context ")"); \ + } while (0) +#define BEGIN_PROTECT(fname, ...) \ + if (UNLIKELY (__mf_starting_p)) \ + { \ + return CALL_BACKUP(fname, __VA_ARGS__); \ + } \ + else if (UNLIKELY (__mf_state == reentrant)) \ + { \ + extern unsigned long __mf_reentrancy; \ + if (UNLIKELY (__mf_opts.verbose_trace)) { \ + write (2, "mf: reentrancy detected in `", 28); \ + write (2, __PRETTY_FUNCTION__, strlen(__PRETTY_FUNCTION__)); \ + write (2, "'\n", 2); } \ + __mf_reentrancy ++; \ + return CALL_REAL(fname, __VA_ARGS__); \ + } \ + else \ + { \ + TRACE ("%s\n", __PRETTY_FUNCTION__); \ + } + + +/* Unlocked variants of main entry points from mf-runtime.h. */ +extern void __mfu_check (void *ptr, size_t sz, int type, const char *location); +extern void __mfu_register (void *ptr, size_t sz, int type, const char *name); +extern void __mfu_unregister (void *ptr, size_t sz); +extern void __mfu_report (); +extern int __mfu_set_options (const char *opts); + + +#endif /* __MF_IMPL_H */ diff --git a/libmudflap/mf-runtime.c b/libmudflap/mf-runtime.c new file mode 100644 index 00000000000..88a3682081c --- /dev/null +++ b/libmudflap/mf-runtime.c @@ -0,0 +1,2431 @@ +/* Mudflap: narrow-pointer bounds-checking by tree rewriting. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Frank Ch. Eigler + and Graydon Hoare + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" + +/* These attempt to coax various unix flavours to declare all our + needed tidbits in the system headers. */ +#if !defined(__FreeBSD__) +#define _POSIX_SOURCE +#endif /* Some BSDs break if this is defined. */ +#define _GNU_SOURCE +#define _XOPEN_SOURCE +#define _BSD_TYPES +#define __EXTENSIONS__ +#define _ALL_SOURCE +#define _LARGE_FILE_API +#define _XOPEN_SOURCE_EXTENDED 1 + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_EXECINFO_H +#include +#endif +#ifdef HAVE_SIGNAL_H +#include +#endif +#include + +#include +#include +#include +#include +#include + +#include "mf-runtime.h" +#include "mf-impl.h" + + +/* ------------------------------------------------------------------------ */ +/* Utility macros */ + +#define CTOR __attribute__ ((constructor)) +#define DTOR __attribute__ ((destructor)) + + +/* Codes to describe the context in which a violation occurs. */ +#define __MF_VIOL_UNKNOWN 0 +#define __MF_VIOL_READ 1 +#define __MF_VIOL_WRITE 2 +#define __MF_VIOL_REGISTER 3 +#define __MF_VIOL_UNREGISTER 4 +#define __MF_VIOL_WATCH 5 + +/* Protect against recursive calls. */ +#define BEGIN_RECURSION_PROTECT() do { \ + if (UNLIKELY (__mf_state == reentrant)) { \ + write (2, "mf: erroneous reentrancy detected in `", 38); \ + write (2, __PRETTY_FUNCTION__, strlen(__PRETTY_FUNCTION__)); \ + write (2, "'\n", 2); \ + abort (); } \ + __mf_state = reentrant; \ + } while (0) + +#define END_RECURSION_PROTECT() do { \ + __mf_state = active; \ + } while (0) + + + +/* ------------------------------------------------------------------------ */ +/* Required globals. */ + +#define LOOKUP_CACHE_MASK_DFL 1023 +#define LOOKUP_CACHE_SIZE_MAX 4096 /* Allows max CACHE_MASK 0x0FFF */ +#define LOOKUP_CACHE_SHIFT_DFL 2 + +struct __mf_cache __mf_lookup_cache [LOOKUP_CACHE_SIZE_MAX]; +uintptr_t __mf_lc_mask = LOOKUP_CACHE_MASK_DFL; +unsigned char __mf_lc_shift = LOOKUP_CACHE_SHIFT_DFL; +#define LOOKUP_CACHE_SIZE (__mf_lc_mask + 1) + +struct __mf_options __mf_opts; + +int __mf_starting_p = 1; +#ifndef LIBMUDFLAPTH +enum __mf_state_enum __mf_state = active; +#else +/* See __mf_state_perthread() in mf-hooks.c. */ +#endif + + +#ifdef LIBMUDFLAPTH +pthread_mutex_t __mf_biglock = +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; +#else + PTHREAD_MUTEX_INITIALIZER; +#endif +#endif + +/* Use HAVE_PTHREAD_H here instead of LIBMUDFLAPTH, so that even + the libmudflap.la (no threading support) can diagnose whether + the application is linked with -lpthread. See __mf_usage() below. */ +#if HAVE_PTHREAD_H +#pragma weak pthread_join +const void *threads_active_p = (void *) pthread_join; +#endif + + +/* ------------------------------------------------------------------------ */ +/* stats-related globals. */ + +static unsigned long __mf_count_check; +static unsigned long __mf_lookup_cache_reusecount [LOOKUP_CACHE_SIZE_MAX]; +static unsigned long __mf_treerot_left, __mf_treerot_right; +static unsigned long __mf_count_register; +static unsigned long __mf_total_register_size [__MF_TYPE_MAX+1]; +static unsigned long __mf_count_unregister; +static unsigned long __mf_total_unregister_size; +static unsigned long __mf_count_violation [__MF_VIOL_WATCH+1]; +static unsigned long __mf_sigusr1_received; +static unsigned long __mf_sigusr1_handled; +/* not static */ unsigned long __mf_reentrancy; +#ifdef LIBMUDFLAPTH +/* not static */ unsigned long __mf_lock_contention; +#endif + + +/* ------------------------------------------------------------------------ */ +/* mode-check-related globals. */ + +typedef struct __mf_object +{ + uintptr_t low, high; /* __mf_register parameters */ + const char *name; + char type; /* __MF_TYPE_something */ + char watching_p; /* Trigger a VIOL_WATCH on access? */ + unsigned read_count; /* Number of times __mf_check/read was called on this object. */ + unsigned write_count; /* Likewise for __mf_check/write. */ + unsigned liveness; /* A measure of recent checking activity. */ + unsigned description_epoch; /* Last epoch __mf_describe_object printed this. */ + + uintptr_t alloc_pc; + struct timeval alloc_time; + char **alloc_backtrace; + size_t alloc_backtrace_size; +#ifdef LIBMUDFLAPTH + pthread_t alloc_thread; +#endif + + int deallocated_p; + uintptr_t dealloc_pc; + struct timeval dealloc_time; + char **dealloc_backtrace; + size_t dealloc_backtrace_size; +#ifdef LIBMUDFLAPTH + pthread_t dealloc_thread; +#endif +} __mf_object_t; + + +typedef struct __mf_object_tree +{ + __mf_object_t data; + struct __mf_object_tree *left; + struct __mf_object_tree *right; +} __mf_object_tree_t; + +/* Live objects: binary tree on __mf_object_t.low */ +static __mf_object_tree_t *__mf_object_root; + +/* Dead objects: circular arrays; _MIN_CEM .. _MAX_CEM only */ +static unsigned __mf_object_dead_head[__MF_TYPE_MAX_CEM+1]; /* next empty spot */ +static __mf_object_tree_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIST_MAX]; + + +/* ------------------------------------------------------------------------ */ +/* Forward function declarations */ + +static void __mf_init () CTOR; +static void __mf_sigusr1_respond (); +static unsigned __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high, + __mf_object_tree_t **objs, unsigned max_objs); +static unsigned __mf_find_dead_objects (uintptr_t ptr_low, uintptr_t ptr_high, + __mf_object_tree_t **objs, unsigned max_objs); +static void __mf_link_object (__mf_object_tree_t *obj); +static void __mf_age_tree (__mf_object_tree_t *obj); +static void __mf_adapt_cache (); +static void __mf_unlink_object (__mf_object_tree_t *obj); +static void __mf_describe_object (__mf_object_t *obj); +static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag); + + + +/* ------------------------------------------------------------------------ */ +/* Configuration engine */ + +static void +__mf_set_default_options () +{ + memset (& __mf_opts, 0, sizeof (__mf_opts)); + + __mf_opts.tree_aging = 13037; + __mf_opts.adapt_cache = 1000003; + __mf_opts.abbreviate = 1; + __mf_opts.verbose_violations = 1; + __mf_opts.free_queue_length = 4; + __mf_opts.persistent_count = 100; + __mf_opts.crumple_zone = 32; + __mf_opts.backtrace = 4; + __mf_opts.mudflap_mode = mode_check; + __mf_opts.violation_mode = viol_nop; + __mf_opts.heur_std_data = 1; +#ifdef LIBMUDFLAPTH + __mf_opts.thread_stack = 0; +#endif +} + +static struct option +{ + char *name; + char *description; + enum + { + set_option, + read_integer_option, + } type; + int value; + int *target; +} +options [] = + { + {"mode-nop", + "mudflaps do nothing", + set_option, (int)mode_nop, (int *)&__mf_opts.mudflap_mode}, + {"mode-populate", + "mudflaps populate object tree", + set_option, (int)mode_populate, (int *)&__mf_opts.mudflap_mode}, + {"mode-check", + "mudflaps check for memory violations", + set_option, (int)mode_check, (int *)&__mf_opts.mudflap_mode}, + {"mode-violate", + "mudflaps always cause violations (diagnostic)", + set_option, (int)mode_violate, (int *)&__mf_opts.mudflap_mode}, + + {"viol-nop", + "violations do not change program execution", + set_option, (int)viol_nop, (int *)&__mf_opts.violation_mode}, + {"viol-abort", + "violations cause a call to abort()", + set_option, (int)viol_abort, (int *)&__mf_opts.violation_mode}, + {"viol-segv", + "violations are promoted to SIGSEGV signals", + set_option, (int)viol_segv, (int *)&__mf_opts.violation_mode}, + {"viol-gdb", + "violations fork a gdb process attached to current program", + set_option, (int)viol_gdb, (int *)&__mf_opts.violation_mode}, + {"trace-calls", + "trace calls to mudflap runtime library", + set_option, 1, &__mf_opts.trace_mf_calls}, + {"verbose-trace", + "trace internal events within mudflap runtime library", + set_option, 1, &__mf_opts.verbose_trace}, + {"collect-stats", + "collect statistics on mudflap's operation", + set_option, 1, &__mf_opts.collect_stats}, +#if HAVE_SIGNAL + {"sigusr1-report", + "print report upon SIGUSR1", + set_option, 1, &__mf_opts.sigusr1_report}, +#endif + {"internal-checking", + "perform more expensive internal checking", + set_option, 1, &__mf_opts.internal_checking}, + {"age-tree", + "age the object tree after N accesses for working set", + read_integer_option, 1000000, &__mf_opts.tree_aging}, + {"print-leaks", + "print any memory leaks at program shutdown", + set_option, 1, &__mf_opts.print_leaks}, + {"check-initialization", + "detect uninitialized object reads", + set_option, 1, &__mf_opts.check_initialization}, + {"verbose-violations", + "print verbose messages when memory violations occur", + set_option, 1, &__mf_opts.verbose_violations}, + {"abbreviate", + "abbreviate repetitive listings", + set_option, 1, &__mf_opts.abbreviate}, + {"wipe-stack", + "wipe stack objects at unwind", + set_option, 1, &__mf_opts.wipe_stack}, + {"wipe-heap", + "wipe heap objects at free", + set_option, 1, &__mf_opts.wipe_heap}, + {"heur-proc-map", + "support /proc/self/map heuristics", + set_option, 1, &__mf_opts.heur_proc_map}, + {"heur-stack-bound", + "enable a simple upper stack bound heuristic", + set_option, 1, &__mf_opts.heur_stack_bound}, + {"heur-start-end", + "support _start.._end heuristics", + set_option, 1, &__mf_opts.heur_start_end}, + {"heur-stdlib", + "register standard library data (argv, errno, stdin, ...)", + set_option, 1, &__mf_opts.heur_std_data}, + {"free-queue-length", + "queue N deferred free() calls before performing them", + read_integer_option, 0, &__mf_opts.free_queue_length}, + {"persistent-count", + "keep a history of N unregistered regions", + read_integer_option, 0, &__mf_opts.persistent_count}, + {"crumple-zone", + "surround allocations with crumple zones of N bytes", + read_integer_option, 0, &__mf_opts.crumple_zone}, + /* XXX: not type-safe. + {"lc-mask", + "set lookup cache size mask to N (2**M - 1)", + read_integer_option, 0, (int *)(&__mf_lc_mask)}, + {"lc-shift", + "set lookup cache pointer shift", + read_integer_option, 0, (int *)(&__mf_lc_shift)}, + */ + {"lc-adapt", + "adapt mask/shift parameters after N cache misses", + read_integer_option, 1, &__mf_opts.adapt_cache}, + {"backtrace", + "keep an N-level stack trace of each call context", + read_integer_option, 0, &__mf_opts.backtrace}, +#ifdef LIBMUDFLAPTH + {"thread-stack", + "override thread stacks allocation: N kB", + read_integer_option, 0, &__mf_opts.thread_stack}, +#endif + {0, 0, set_option, 0, NULL} + }; + +static void +__mf_usage () +{ + struct option *opt; + + fprintf (stderr, + "This is a %s%sGCC \"mudflap\" memory-checked binary.\n" + "Mudflap is Copyright (C) 2002-2003 Free Software Foundation, Inc.\n" + "\n" + "The mudflap code can be controlled by an environment variable:\n" + "\n" + "$ export MUDFLAP_OPTIONS=''\n" + "$ \n" + "\n" + "where is a space-separated list of \n" + "any of the following options. Use `-no-OPTION' to disable options.\n" + "\n", +#if HAVE_PTHREAD_H + (threads_active_p ? "multi-threaded " : "single-threaded "), +#else + "", +#endif +#if LIBMUDFLAPTH + "thread-aware " +#else + "thread-unaware " +#endif + ); + /* XXX: The multi-threaded thread-unaware combination is bad. */ + + for (opt = options; opt->name; opt++) + { + int default_p = (opt->value == * opt->target); + + switch (opt->type) + { + char buf[128]; + case set_option: + fprintf (stderr, "-%-23.23s %s", opt->name, opt->description); + if (default_p) + fprintf (stderr, " [active]\n"); + else + fprintf (stderr, "\n"); + break; + case read_integer_option: + strncpy (buf, opt->name, 128); + strncpy (buf + strlen (opt->name), "=N", 2); + fprintf (stderr, "-%-23.23s %s", buf, opt->description); + fprintf (stderr, " [%d]\n", * opt->target); + break; + default: abort(); + } + } + + fprintf (stderr, "\n"); +} + + +int +__mf_set_options (const char *optstr) +{ + int rc; + LOCKTH (); + BEGIN_RECURSION_PROTECT (); + rc = __mfu_set_options (optstr); + /* XXX: It's not really that easy. A change to a bunch of parameters + can require updating auxiliary state or risk crashing: + free_queue_length, crumple_zone ... */ + END_RECURSION_PROTECT (); + UNLOCKTH (); + return rc; +} + + +int +__mfu_set_options (const char *optstr) +{ + struct option *opts = 0; + char *nxt = 0; + long tmp = 0; + int rc = 0; + const char *saved_optstr = optstr; + + /* XXX: bounds-check for optstr! */ + + while (*optstr) + { + switch (*optstr) { + case ' ': + case '\t': + case '\n': + optstr++; + break; + + case '-': + if (*optstr+1) + { + int negate = 0; + optstr++; + + if (*optstr == '?' || + strncmp (optstr, "help", 4) == 0) + { + /* Caller will print help and exit. */ + return -1; + } + + if (strncmp (optstr, "no-", 3) == 0) + { + negate = 1; + optstr = & optstr[3]; + } + + for (opts = options; opts->name; opts++) + { + if (strncmp (optstr, opts->name, strlen (opts->name)) == 0) + { + optstr += strlen (opts->name); + assert (opts->target); + switch (opts->type) + { + case set_option: + if (negate) + *(opts->target) = 0; + else + *(opts->target) = opts->value; + break; + case read_integer_option: + if (! negate && (*optstr == '=' && *(optstr+1))) + { + optstr++; + tmp = strtol (optstr, &nxt, 10); + if ((optstr != nxt) && (tmp != LONG_MAX)) + { + optstr = nxt; + *(opts->target) = (int)tmp; + } + } + else if (negate) + * opts->target = 0; + break; + } + } + } + } + break; + + default: + fprintf (stderr, + "warning: unrecognized string '%s' in mudflap options\n", + optstr); + optstr += strlen (optstr); + rc = -1; + break; + } + } + + /* Special post-processing: bound __mf_lc_mask and free_queue_length for security. */ + __mf_lc_mask &= (LOOKUP_CACHE_SIZE_MAX - 1); + __mf_opts.free_queue_length &= (__MF_FREEQ_MAX - 1); + + /* Clear the lookup cache, in case the parameters got changed. */ + /* XXX: race */ + memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache)); + /* void slot 0 */ + __mf_lookup_cache[0].low = MAXPTR; + + TRACE ("set options from `%s'\n", saved_optstr); + + /* Call this unconditionally, in case -sigusr1-report was toggled. */ + __mf_sigusr1_respond (); + + return rc; +} + + +#ifdef PIC + +void +__mf_resolve_single_dynamic (struct __mf_dynamic_entry *e) +{ + char *err; + + assert (e); + if (e->pointer) return; + +#if HAVE_DLVSYM + if (e->version != NULL && e->version[0] != '\0') /* non-null/empty */ + e->pointer = dlvsym (RTLD_NEXT, e->name, e->version); + else +#endif + e->pointer = dlsym (RTLD_NEXT, e->name); + + err = dlerror (); + + if (err) + { + fprintf (stderr, "mf: error in dlsym(\"%s\"): %s\n", + e->name, err); + abort (); + } + if (! e->pointer) + { + fprintf (stderr, "mf: dlsym(\"%s\") = NULL\n", e->name); + abort (); + } +} + + +static void +__mf_resolve_dynamics () +{ + int i; + for (i = 0; i < dyn_INITRESOLVE; i++) + __mf_resolve_single_dynamic (& __mf_dynamic[i]); +} + + +/* NB: order must match enums in mf-impl.h */ +struct __mf_dynamic_entry __mf_dynamic [] = +{ + {NULL, "calloc", NULL}, + {NULL, "free", NULL}, + {NULL, "malloc", NULL}, + {NULL, "mmap", NULL}, + {NULL, "munmap", NULL}, + {NULL, "realloc", NULL}, + {NULL, "DUMMY", NULL}, /* dyn_INITRESOLVE */ +#ifdef LIBMUDFLAPTH + {NULL, "pthread_create", PTHREAD_CREATE_VERSION}, + {NULL, "pthread_join", NULL}, + {NULL, "pthread_exit", NULL} +#endif +}; + +#endif /* PIC */ + + + +/* ------------------------------------------------------------------------ */ + + +void __mf_init () +{ + char *ov = 0; + + /* This initial bootstrap phase requires that __mf_starting_p = 1. */ +#ifdef PIC + __mf_resolve_dynamics (); +#endif + __mf_starting_p = 0; + + __mf_set_default_options (); + + ov = getenv ("MUDFLAP_OPTIONS"); + if (ov) + { + int rc = __mfu_set_options (ov); + if (rc < 0) + { + __mf_usage (); + exit (1); + } + } + + /* Initialize to a non-zero description epoch. */ + __mf_describe_object (NULL); + +#define REG_RESERVED(obj) \ + __mf_register (& obj, sizeof(obj), __MF_TYPE_NOACCESS, # obj) + + REG_RESERVED (__mf_lookup_cache); + REG_RESERVED (__mf_lc_mask); + REG_RESERVED (__mf_lc_shift); + /* XXX: others of our statics? */ + + /* Prevent access to *NULL. */ + __mf_register (MINPTR, 1, __MF_TYPE_NOACCESS, "NULL"); + __mf_lookup_cache[0].low = (uintptr_t) -1; +} + + + +int +__wrap_main (int argc, char* argv[]) +{ + extern char **environ; + extern int main (); + static int been_here = 0; + + if (__mf_opts.heur_std_data && ! been_here) + { + unsigned i; + + been_here = 1; + __mf_register (argv, sizeof(char *)*(argc+1), __MF_TYPE_STATIC, "argv[]"); + for (i=0; i0=okay */ + uintptr_t ptr_low = (uintptr_t) ptr; + uintptr_t ptr_high = CLAMPSZ (ptr, sz); + struct __mf_cache old_entry = *entry; + + if (UNLIKELY (__mf_opts.sigusr1_report)) + __mf_sigusr1_respond (); + + TRACE ("check ptr=%p b=%u size=%lu %s location=`%s'\n", + ptr, entry_idx, (unsigned long)sz, + (type == 0 ? "read" : "write"), location); + + switch (__mf_opts.mudflap_mode) + { + case mode_nop: + judgement = 1; + break; + + case mode_populate: + entry->low = ptr_low; + entry->high = ptr_high; + judgement = 1; + break; + + case mode_check: + { + unsigned heuristics = 0; + + /* Advance aging/adaptation counters. */ + if (__mf_object_root) + { + static unsigned aging_count; + static unsigned adapt_count; + aging_count ++; + adapt_count ++; + if (UNLIKELY (__mf_opts.tree_aging > 0 && + aging_count > __mf_opts.tree_aging)) + { + aging_count = 0; + __mf_age_tree (__mf_object_root); + } + if (UNLIKELY (__mf_opts.adapt_cache > 0 && + adapt_count > __mf_opts.adapt_cache)) + { + adapt_count = 0; + __mf_adapt_cache (); + } + } + + /* Looping only occurs if heuristics were triggered. */ + while (judgement == 0) + { + __mf_object_tree_t* ovr_obj[1]; + unsigned obj_count; + + obj_count = __mf_find_objects (ptr_low, ptr_high, ovr_obj, 1); + + if (LIKELY (obj_count == 1)) /* A single hit! */ + { + __mf_object_t *obj = & ovr_obj[0]->data; + assert (obj != NULL); + if (LIKELY (ptr_low >= obj->low && ptr_high <= obj->high)) + { + /* XXX: hope for no overflow! */ + if (type == __MF_CHECK_READ) + obj->read_count ++; + else + obj->write_count ++; + + obj->liveness ++; + + if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS)) + judgement = -1; + else if (UNLIKELY (obj->watching_p)) + judgement = -2; /* trigger VIOL_WATCH */ + else if (UNLIKELY (__mf_opts.check_initialization + /* reading */ + && type == __MF_CHECK_READ + /* not written */ + && obj->write_count == 0 + /* uninitialized (heap) */ + && obj->type == __MF_TYPE_HEAP)) + judgement = -1; + else + { + /* Valid access. */ + entry->low = obj->low; + entry->high = obj->high; + judgement = 1; + } + } + /* The object did not cover the entire accessed region. */ + } + else if (LIKELY (obj_count > 1)) + { + __mf_object_tree_t **all_ovr_objs; + unsigned n; + DECLARE (void *, malloc, size_t c); + DECLARE (void, free, void *p); + + all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_tree_t *) * + obj_count)); + if (all_ovr_objs == NULL) abort (); + n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count); + assert (n == obj_count); + + /* Confirm that accessed range is covered by first/last object. */ + if (LIKELY ((ptr_low >= all_ovr_objs[0]->data.low) && + (ptr_high <= all_ovr_objs[obj_count-1]->data.high))) + { + /* Presume valid access. */ + judgement = 1; + + /* Confirm that intermediate objects are + contiguous and share a single name. Thus they + are likely split up GUESS regions, or mmap + pages. The idea of the name check is to + prevent an oversize access to a + stack-registered object (followed by some GUESS + type) from being accepted as a hit. */ + for (n=0; ndata); + __mf_object_t *nextobj = & (all_ovr_objs[n+1]->data); + + if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS)) + judgement = -1; /* Force error. */ + + if (UNLIKELY (judgement == 1 && + (obj->high + 1 != nextobj->low))) + judgement = 0; /* Cancel presumption. */ + + if (UNLIKELY (judgement == 1 && + (obj->name != nextobj->name))) + judgement = 0; /* Cancel presumption. */ + /* NB: strcmp above is not necessary since the + same literal string pointer is normally + used when creating regions. */ + + /* XXX: hope for no overflow! */ + if (type == __MF_CHECK_READ) + obj->read_count ++; + else + obj->write_count ++; + obj->liveness ++; + } + + /* If the access is otherwise successful, check whether + any of the covered objects are being watched. */ + if (judgement > 0) + { + unsigned i; + for (i=0; idata.watching_p) + judgement = -2; /* trigger VIOL_WATCH */ + } + + /* Check for uninitialized reads. */ + if (judgement > 0 && + __mf_opts.check_initialization && + type == __MF_CHECK_READ) + { + unsigned i; + unsigned written_count = 0; + + for (i=0; idata; + + if (obj->write_count + || obj->type == __MF_TYPE_HEAP_I + || obj->type == __MF_TYPE_GUESS) + written_count ++; + } + + /* Check for ALL pieces having been written-to. + XXX: should this be ANY instead? */ + if (written_count != obj_count) + judgement = -1; + } + + /* Fill out the cache with the bounds of the first + object and the last object that covers this + cache line (== includes the same __MF_CACHE_INDEX). + This could let this cache line span *two* distinct + registered objects: a peculiar but reasonable + situation. The cache line may not include the + entire object though. */ + if (judgement > 0) + { + unsigned i; + entry->low = all_ovr_objs[0]->data.low; + for (i=0; idata.high; + if (__MF_CACHE_INDEX (high) == entry_idx) + entry->high = high; + } + } + } + + CALL_REAL (free, all_ovr_objs); + } + + if (judgement == 0) + { + if (heuristics++ < 2) /* XXX parametrize this number? */ + judgement = __mf_heuristic_check (ptr_low, ptr_high); + else + judgement = -1; + } + } + + } + break; + + case mode_violate: + judgement = -1; + break; + } + + if (__mf_opts.collect_stats) + { + __mf_count_check ++; + + if (LIKELY (old_entry.low != entry->low || old_entry.high != entry->high)) + /* && (old_entry.low != 0) && (old_entry.high != 0)) */ + __mf_lookup_cache_reusecount [entry_idx] ++; + } + + if (UNLIKELY (judgement < 0)) + __mf_violation (ptr, sz, + (uintptr_t) __builtin_return_address (0), location, + ((judgement == -1) ? + (type == __MF_CHECK_READ ? __MF_VIOL_READ : __MF_VIOL_WRITE) : + __MF_VIOL_WATCH)); +} + + +static __mf_object_tree_t * +__mf_insert_new_object (uintptr_t low, uintptr_t high, int type, + const char *name, uintptr_t pc) +{ + DECLARE (void *, calloc, size_t c, size_t n); + + __mf_object_tree_t *new_obj; + new_obj = CALL_REAL (calloc, 1, sizeof(__mf_object_tree_t)); + new_obj->data.low = low; + new_obj->data.high = high; + new_obj->data.type = type; + new_obj->data.name = name; + new_obj->data.alloc_pc = pc; +#if HAVE_GETTIMEOFDAY + gettimeofday (& new_obj->data.alloc_time, NULL); +#endif +#if LIBMUDFLAPTH + new_obj->data.alloc_thread = pthread_self (); +#endif + + if (__mf_opts.backtrace > 0 && (type == __MF_TYPE_HEAP || type == __MF_TYPE_HEAP_I)) + new_obj->data.alloc_backtrace_size = + __mf_backtrace (& new_obj->data.alloc_backtrace, + (void *) pc, 2); + + __mf_link_object (new_obj); + return new_obj; +} + + +static void +__mf_uncache_object (__mf_object_t *old_obj) +{ + /* Remove any low/high pointers for this object from the lookup cache. */ + + /* Can it possibly exist in the cache? */ + if (LIKELY (old_obj->read_count + old_obj->write_count)) + { + uintptr_t low = old_obj->low; + uintptr_t high = old_obj->high; + unsigned idx_low = __MF_CACHE_INDEX (low); + unsigned idx_high = __MF_CACHE_INDEX (high); + unsigned i; + for (i = idx_low; i <= idx_high; i++) + { + struct __mf_cache *entry = & __mf_lookup_cache [i]; + /* NB: the "||" in the following test permits this code to + tolerate the situation introduced by __mf_check over + contiguous objects, where a cache entry spans several + objects. */ + if (entry->low == low || entry->high == high) + { + entry->low = MAXPTR; + entry->high = MINPTR; + } + } + } +} + + +void +__mf_register (void *ptr, size_t sz, int type, const char *name) +{ + LOCKTH (); + BEGIN_RECURSION_PROTECT (); + __mfu_register (ptr, sz, type, name); + END_RECURSION_PROTECT (); + UNLOCKTH (); +} + + +void +__mfu_register (void *ptr, size_t sz, int type, const char *name) +{ + TRACE ("register ptr=%p size=%lu type=%x name='%s'\n", + ptr, (unsigned long) sz, type, name ? name : ""); + + if (__mf_opts.collect_stats) + { + __mf_count_register ++; + __mf_total_register_size [(type < 0) ? 0 : + (type > __MF_TYPE_MAX) ? 0 : + type] += sz; + } + + if (UNLIKELY (__mf_opts.sigusr1_report)) + __mf_sigusr1_respond (); + + switch (__mf_opts.mudflap_mode) + { + case mode_nop: + break; + + case mode_violate: + __mf_violation (ptr, sz, (uintptr_t) __builtin_return_address (0), NULL, + __MF_VIOL_REGISTER); + break; + + case mode_populate: + /* Clear the cache. */ + /* XXX: why the entire cache? */ + /* XXX: race */ + memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache)); + /* void slot 0 */ + __mf_lookup_cache[0].low = MAXPTR; + break; + + case mode_check: + { + __mf_object_tree_t *ovr_objs [1]; + unsigned num_overlapping_objs; + uintptr_t low = (uintptr_t) ptr; + uintptr_t high = CLAMPSZ (ptr, sz); + uintptr_t pc = (uintptr_t) __builtin_return_address (0); + + /* Treat unknown size indication as 1. */ + if (UNLIKELY (sz == 0)) sz = 1; + + num_overlapping_objs = __mf_find_objects (low, high, ovr_objs, 1); + + /* Handle overlaps. */ + if (UNLIKELY (num_overlapping_objs > 0)) + { + __mf_object_tree_t *ovr_obj = ovr_objs[0]; + + /* Quietly accept a single duplicate registration for + static objects, since these may come from distinct + compilation units. */ + if (type == __MF_TYPE_STATIC + && ovr_obj->data.type == __MF_TYPE_STATIC + && ovr_obj->data.low == low + && ovr_obj->data.high == high) + { + /* do nothing */ + VERBOSE_TRACE ("duplicate static reg %p-%p `%s'\n", + (void *) low, (void *) high, + (ovr_obj->data.name ? ovr_obj->data.name : "")); + break; + } + + /* Quietly accept a single duplicate registration for + guess objects too. */ + if (type == __MF_TYPE_GUESS && + ovr_obj->data.type == __MF_TYPE_GUESS && + ovr_obj->data.low == low && + ovr_obj->data.high == high) + { + /* do nothing */ + VERBOSE_TRACE ("duplicate guess reg %p-%p\n", + (void *) low, (void *) high); + break; + } + + /* Quietly accept new a guess registration that overlaps + at least one existing object. Trim it down to size. */ + else if (type == __MF_TYPE_GUESS) + { + /* We need to split this new GUESS region into some + smaller ones. Or we may not need to insert it at + all if it is covered by the overlapping region. */ + + /* First, identify all the overlapping objects. */ + __mf_object_tree_t **all_ovr_objs; + unsigned num_ovr_objs, n; + uintptr_t next_low; + DECLARE (void *, malloc, size_t c); + DECLARE (void, free, void *p); + + all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_tree_t *) * + num_overlapping_objs)); + if (all_ovr_objs == NULL) abort (); + num_ovr_objs = __mf_find_objects (low, high, all_ovr_objs, + num_overlapping_objs); + assert (num_ovr_objs == num_overlapping_objs); + + VERBOSE_TRACE ("splitting guess %p-%p, # overlaps: %u\n", + (void *) low, (void *) high, num_ovr_objs); + + /* Add GUESS regions between the holes: before each + overlapping region. */ + + next_low = low; + /* This makes use of the assumption that __mf_find_objects() returns + overlapping objects in an increasing sequence. */ + for (n=0; n < min (num_ovr_objs, num_overlapping_objs); n++) + { + if (all_ovr_objs[n]->data.low > next_low) /* Gap? */ + { + uintptr_t next_high = CLAMPSUB (all_ovr_objs[n]->data.low, 1); + __mfu_register ((void *) next_low, next_high-next_low+1, + __MF_TYPE_GUESS, name); + } + next_low = CLAMPADD (all_ovr_objs[n]->data.high, 1); + } + /* Add in any leftover room at the top. */ + if (next_low <= high) + __mfu_register ((void *) next_low, high-next_low+1, + __MF_TYPE_GUESS, name); + + /* XXX: future optimization: allow consecutive GUESS regions to + be glued together. */ + CALL_REAL (free, all_ovr_objs); + return; + } + + /* Quietly accept a non-GUESS region overlaying a GUESS + region. Handle it by removing the GUESS region + temporarily, then recursively adding this new object, + and then the GUESS back. The latter will be split up + by the recursive process above. */ + else if (ovr_obj->data.type == __MF_TYPE_GUESS) + { + uintptr_t old_low = ovr_obj->data.low; + uintptr_t old_high = ovr_obj->data.high; + const char* old_name = ovr_obj->data.name; + + /* Now to recursively remove the guess piece, and + reinsert them in the opposite order. Recursion + should bottom out if another non-GUESS overlapping + region is found for this new object (resulting in a + violation), or if no further overlap occurs. The + located GUESS region should end up being split up + in any case. */ + __mfu_unregister ((void *) old_low, old_high-old_low+1); + __mfu_register ((void *) low, sz, type, name); + __mfu_register ((void *) old_low, old_high-old_low+1, + __MF_TYPE_GUESS, old_name); + return; + } + + /* Alas, a genuine violation. */ + else + { + /* Two or more *real* mappings here. */ + __mf_violation ((void *) ptr, sz, + (uintptr_t) __builtin_return_address (0), NULL, + __MF_VIOL_REGISTER); + } + } + + /* No overlapping objects: AOK. */ + else + { + __mf_insert_new_object (low, high, type, name, pc); + } + + /* We could conceivably call __mf_check() here to prime the cache, + but then the read_count/write_count field is not reliable. */ + + break; + } + } /* end switch (__mf_opts.mudflap_mode) */ +} + + +void +__mf_unregister (void *ptr, size_t sz) +{ + LOCKTH (); + BEGIN_RECURSION_PROTECT (); + __mfu_unregister (ptr, sz); + END_RECURSION_PROTECT (); + UNLOCKTH (); +} + + +void +__mfu_unregister (void *ptr, size_t sz) +{ + DECLARE (void, free, void *ptr); + + if (UNLIKELY (__mf_opts.sigusr1_report)) + __mf_sigusr1_respond (); + + TRACE ("unregister ptr=%p size=%lu\n", ptr, (unsigned long) sz); + + switch (__mf_opts.mudflap_mode) + { + case mode_nop: + break; + + case mode_violate: + __mf_violation (ptr, sz, + (uintptr_t) __builtin_return_address (0), NULL, + __MF_VIOL_UNREGISTER); + break; + + case mode_populate: + /* Clear the cache. */ + /* XXX: race */ + memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache)); + /* void slot 0 */ + __mf_lookup_cache[0].low = MAXPTR; + break; + + case mode_check: + { + __mf_object_tree_t *old_obj = NULL; + __mf_object_tree_t *del_obj = NULL; /* Object to actually delete. */ + __mf_object_tree_t *objs[1] = {NULL}; + unsigned num_overlapping_objs; + + /* Treat unknown size indication as 1. */ + if (sz == 0) sz = 1; + + num_overlapping_objs = __mf_find_objects ((uintptr_t) ptr, + CLAMPSZ (ptr, sz), objs, 1); + + /* XXX: handle unregistration of big old GUESS region, that has since + been splintered. */ + old_obj = objs[0]; + + if (UNLIKELY (num_overlapping_objs != 1 || + (uintptr_t)ptr != old_obj->data.low)) /* XXX: what about sz? */ + { + __mf_violation (ptr, sz, + (uintptr_t) __builtin_return_address (0), NULL, + __MF_VIOL_UNREGISTER); + break; + } + + __mf_unlink_object (old_obj); + __mf_uncache_object (& old_obj->data); + + /* Wipe buffer contents if desired. */ + if ((__mf_opts.wipe_stack && old_obj->data.type == __MF_TYPE_STACK) + || (__mf_opts.wipe_heap && (old_obj->data.type == __MF_TYPE_HEAP + || old_obj->data.type == __MF_TYPE_HEAP_I))) + { + memset ((void *) old_obj->data.low, + 0, + (size_t) (old_obj->data.high - old_obj->data.low + 1)); + } + + /* Manage the object cemetary. */ + if (__mf_opts.persistent_count > 0 && + old_obj->data.type >= 0 && + old_obj->data.type <= __MF_TYPE_MAX_CEM) + { + old_obj->data.deallocated_p = 1; + old_obj->left = old_obj->right = NULL; + old_obj->data.dealloc_pc = (uintptr_t) __builtin_return_address (0); +#if HAVE_GETTIMEOFDAY + gettimeofday (& old_obj->data.dealloc_time, NULL); +#endif +#ifdef LIBMUDFLAPTH + old_obj->data.dealloc_thread = pthread_self (); +#endif + + if (__mf_opts.backtrace > 0 && old_obj->data.type == __MF_TYPE_HEAP) + old_obj->data.dealloc_backtrace_size = + __mf_backtrace (& old_obj->data.dealloc_backtrace, + NULL, 2); + + /* Encourage this object to be displayed again in current epoch. */ + old_obj->data.description_epoch --; + + /* Put this object into the cemetary. This may require this plot to + be recycled, and the previous resident to be designated del_obj. */ + { + unsigned row = old_obj->data.type; + unsigned plot = __mf_object_dead_head [row]; + + del_obj = __mf_object_cemetary [row][plot]; + __mf_object_cemetary [row][plot] = old_obj; + plot ++; + if (plot == __mf_opts.persistent_count) plot = 0; + __mf_object_dead_head [row] = plot; + } + } + else + del_obj = old_obj; + + if (__mf_opts.print_leaks) + { + if ((old_obj->data.read_count + old_obj->data.write_count) == 0 && + (old_obj->data.type == __MF_TYPE_HEAP + || old_obj->data.type == __MF_TYPE_HEAP_I)) + { + fprintf (stderr, + "*******\n" + "mudflap warning: unaccessed registered object:\n"); + __mf_describe_object (& old_obj->data); + } + } + + if (del_obj != NULL) /* May or may not equal old_obj. */ + { + if (__mf_opts.backtrace > 0) + { + CALL_REAL(free, del_obj->data.alloc_backtrace); + if (__mf_opts.persistent_count > 0) + { + CALL_REAL(free, del_obj->data.dealloc_backtrace); + } + } + CALL_REAL(free, del_obj); + } + + break; + } + } /* end switch (__mf_opts.mudflap_mode) */ + + + if (__mf_opts.collect_stats) + { + __mf_count_unregister ++; + __mf_total_unregister_size += sz; + } +} + +/* ------------------------------------------------------------------------ */ +/* __mf_validate_live_object_tree, _object_cemetary */ + +static void +__mf_validate_live_object_tree (__mf_object_tree_t *obj) +{ + assert (obj != NULL); + + if (__mf_opts.persistent_count > 0) + assert (! obj->data.deallocated_p); + + if (obj->left) + { + assert (obj->left->data.high < obj->data.low); + __mf_validate_live_object_tree (obj->left); + } + if (obj->right) + { + assert (obj->right->data.low > obj->data.high); + __mf_validate_live_object_tree (obj->right); + } +} + +static void +__mf_validate_object_cemetary () +{ + unsigned cls; + unsigned i; + + for (cls = 0; cls <= __MF_TYPE_MAX_CEM; cls++) + { + assert (__mf_object_dead_head [cls] >= 0 && + __mf_object_dead_head [cls] < __mf_opts.persistent_count); + for (i = 0; i < __mf_opts.persistent_count; i++) + { + __mf_object_tree_t *obj = __mf_object_cemetary [cls][i]; + if (obj != NULL) + { + assert (obj->data.deallocated_p); + assert (obj->left == NULL); + assert (obj->right == NULL); + } + } + } +} + +static void +__mf_validate_objects () +{ + if (__mf_object_root) + __mf_validate_live_object_tree (__mf_object_root); + + if (__mf_opts.persistent_count > 0) + __mf_validate_object_cemetary (); +} + + +static void +__mf_age_tree (__mf_object_tree_t *obj) +{ + assert (obj != NULL); + obj->data.liveness = obj->data.liveness >> 1; + + if (obj->left) + __mf_age_tree (obj->left); + if (obj->right) + __mf_age_tree (obj->right); +} + + + +struct tree_stats +{ + unsigned obj_count; + unsigned long total_size; + unsigned live_obj_count; + double total_weight; + double weighted_size; + unsigned long weighted_address_bits [sizeof (uintptr_t) * 8][2]; +}; + + +static void +__mf_tree_analyze (__mf_object_tree_t *obj, struct tree_stats* s) +{ + assert (obj != NULL); + + if (obj->left) + __mf_tree_analyze (obj->left, s); + + /* Exclude never-accessed objects. */ + if (obj->data.read_count + obj->data.write_count) + { + s->obj_count ++; + s->total_size += (obj->data.high - obj->data.low + 1); + + if (obj->data.liveness) + { + unsigned i; + uintptr_t addr; + + VERBOSE_TRACE ("analyze low=%p live=%u name=`%s'\n", + (void *) obj->data.low, obj->data.liveness, obj->data.name); + + s->live_obj_count ++; + s->total_weight += (double) obj->data.liveness; + s->weighted_size += + (double) (obj->data.high - obj->data.low + 1) * + (double) obj->data.liveness; + + addr = obj->data.low; + for (i=0; iweighted_address_bits[i][bit] += obj->data.liveness; + addr = addr >> 1; + } + } + } + + if (obj->right) + __mf_tree_analyze (obj->right, s); +} + + +static void +__mf_adapt_cache () +{ + struct tree_stats s; + uintptr_t new_mask = 0; + unsigned char new_shift; + float cache_utilization; + float max_value; + static float smoothed_new_shift = -1.0; + unsigned i; + + memset (&s, 0, sizeof (s)); + if (__mf_object_root) + __mf_tree_analyze (__mf_object_root, & s); + + /* Maybe we're dealing with funny aging/adaptation parameters, or an + empty tree. Just leave the cache alone in such cases, rather + than risk dying by division-by-zero. */ + if (! (s.obj_count > 0) && (s.live_obj_count > 0) && (s.total_weight > 0.0)) + return; + + /* Guess a good value for the shift parameter by finding an address bit that is a + good discriminant of lively objects. */ + max_value = 0.0; + for (i=0; i= max_value * shoulder_factor) + break; + } + if (smoothed_new_shift < 0) smoothed_new_shift = __mf_lc_shift; + /* Converge toward this slowly to reduce flapping. */ + smoothed_new_shift = 0.9*smoothed_new_shift + 0.1*i; + new_shift = (unsigned) (smoothed_new_shift + 0.5); + assert (new_shift < sizeof (uintptr_t)*8); + + /* Count number of used buckets. */ + cache_utilization = 0.0; + for (i = 0; i < (1 + __mf_lc_mask); i++) + if (__mf_lookup_cache[i].low != 0 || __mf_lookup_cache[i].high != 0) + cache_utilization += 1.0; + cache_utilization /= (1 + __mf_lc_mask); + + new_mask |= 0x3ff; /* XXX: force a large cache. */ + new_mask &= (LOOKUP_CACHE_SIZE_MAX - 1); + + VERBOSE_TRACE ("adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => " + "util=%u%% m=%p s=%u\n", + s.obj_count, s.live_obj_count, s.total_size, s.total_weight, s.weighted_size, + (unsigned)(cache_utilization*100.0), (void *) new_mask, new_shift); + + /* We should reinitialize cache if its parameters have changed. */ + if (new_mask != __mf_lc_mask || + new_shift != __mf_lc_shift) + { + __mf_lc_mask = new_mask; + __mf_lc_shift = new_shift; + /* XXX: race */ + memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache)); + /* void slot 0 */ + __mf_lookup_cache[0].low = MAXPTR; + } +} + + + + +/* __mf_find_object[s] */ + +/* Find overlapping live objecs between [low,high]. Return up to + max_objs of their pointers in objs[]. Return total count of + overlaps (may exceed max_objs). */ + +/* XXX: track traversal statistics, like average depth, balance. */ + +static unsigned +__mf_find_objects_rec (uintptr_t low, uintptr_t high, __mf_object_tree_t **nodep, + __mf_object_tree_t **objs, unsigned max_objs) +{ + unsigned count; + __mf_object_tree_t *node = *nodep; + + assert (low <= high); + assert (max_objs == 0 || objs != NULL); + + if (UNLIKELY (node == NULL)) return 0; + + /* Traverse down left subtree. */ + count = 0; + if (low < node->data.low) + count += __mf_find_objects_rec (low, min(high, node->data.low), + & node->left, objs, max_objs); + + /* Track the used slots of objs[]. */ + if (count < max_objs) + { + objs += count; + max_objs -= count; + } + else + { + max_objs = 0; + } + + /* Check for overlap with this node. */ + if (high >= node->data.low && low <= node->data.high) + { + count ++; + if (max_objs > 0) /* Any room left? */ + { + objs[0] = node; + objs ++; + max_objs --; + } + } + + /* Traverse down right subtree. */ + if (high > node->data.high) + count += __mf_find_objects_rec (max (low, node->data.high), high, + & node->right, objs, max_objs); + /* There is no need to manipulate objs/max_objs any further. */ + + + /* Rotate a child node up if its access count is higher. */ + if (UNLIKELY ((node->left && node->left->data.liveness > node->data.liveness) && + ((!node->right || (node->right && + node->left->data.liveness > + node->right->data.liveness))))) + { + __mf_object_tree_t *l = node->left; + __mf_object_tree_t *l_r = l->right; + + *nodep = l; + l->right = node; + node->left = l_r; + __mf_treerot_left ++; + } + else if (UNLIKELY ((node->right && node->right->data.liveness > node->data.liveness) && + ((!node->left || (node->left && + node->right->data.liveness > + node->left->data.liveness))))) + { + __mf_object_tree_t *r = node->right; + __mf_object_tree_t *r_l = r->left; + + *nodep = r; + r->left = node; + node->right = r_l; + __mf_treerot_right ++; + } + + return count; +} + + +unsigned +__mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high, + __mf_object_tree_t **objs, unsigned max_objs) +{ + if (UNLIKELY(__mf_opts.internal_checking)) + __mf_validate_objects (); + + return __mf_find_objects_rec (ptr_low, ptr_high, & __mf_object_root, objs, max_objs); +} + +/* __mf_link_object */ + +static void +__mf_link_object2 (__mf_object_tree_t *ptr, __mf_object_tree_t **link) +{ + __mf_object_tree_t *node = *link; + + assert (ptr != NULL); + if (UNLIKELY(node == NULL)) + { + *link = ptr; + return; + } + + if (ptr->data.high < node->data.low) + return __mf_link_object2 (ptr, & node->left); + else if (ptr->data.low > node->data.high) + return __mf_link_object2 (ptr, & node->right); + else + abort (); /* XXX: duplicate object */ +} + + +void +__mf_link_object (__mf_object_tree_t *ptr) +{ + if (UNLIKELY(__mf_opts.internal_checking)) + __mf_validate_objects (); + + return __mf_link_object2 (ptr, & __mf_object_root); +} + +/* __mf_unlink_object */ + +static void +__mf_unlink_object2 (__mf_object_tree_t *ptr, __mf_object_tree_t **link) +{ + __mf_object_tree_t *node = *link; + + assert (ptr != NULL); + if (UNLIKELY(node == ptr)) + { + static unsigned promote_left_p = 0; + promote_left_p = 1 - promote_left_p; + + /* Alternate promoting the left & right subtrees. */ + if (promote_left_p) + { + *link = ptr->left; + if (ptr->right != NULL) + __mf_link_object2 (ptr->right, link); + } + else + { + *link = ptr->right; + if (ptr->left != NULL) + __mf_link_object2 (ptr->left, link); + } + + return; + } + + if (ptr->data.high < node->data.low) + return __mf_unlink_object2 (ptr, & node->left); + else if (ptr->data.low > node->data.high) + return __mf_unlink_object2 (ptr, & node->right); + else + abort (); /* XXX: missing object; should fail more gracefully. */ +} + +static void +__mf_unlink_object (__mf_object_tree_t *node) +{ + __mf_unlink_object2 (node, & __mf_object_root); +} + +/* __mf_find_dead_objects */ + +/* Find overlapping dead objecs between [low,high]. Return up to + max_objs of their pointers in objs[]. Return total count of + overlaps (may exceed max_objs). */ + +static unsigned +__mf_find_dead_objects (uintptr_t low, uintptr_t high, + __mf_object_tree_t **objs, unsigned max_objs) +{ + if (__mf_opts.persistent_count > 0) + { + unsigned count = 0; + unsigned recollection = 0; + unsigned row = 0; + + assert (low <= high); + assert (max_objs == 0 || objs != NULL); + + /* Widen the search from the most recent plots in each row, looking + backward in time. */ + recollection = 0; + while (recollection < __mf_opts.persistent_count) + { + count = 0; + + for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++) + { + unsigned plot; + unsigned i; + + plot = __mf_object_dead_head [row]; + for (i = 0; i <= recollection; i ++) + { + __mf_object_tree_t *obj; + + /* Look backward through row: it's a circular buffer. */ + if (plot > 0) plot --; + else plot = __mf_opts.persistent_count - 1; + + obj = __mf_object_cemetary [row][plot]; + if (obj && obj->data.low <= high && obj->data.high >= low) + { + /* Found an overlapping dead object! */ + if (count < max_objs) + objs [count] = obj; + count ++; + } + } + } + + if (count) + break; + + /* Look farther back in time. */ + recollection = (recollection * 2) + 1; + } + + return count; + } else { + return 0; + } +} + +/* __mf_describe_object */ + +static void +__mf_describe_object (__mf_object_t *obj) +{ + static unsigned epoch = 0; + if (obj == NULL) + { + epoch ++; + return; + } + + if (__mf_opts.abbreviate && obj->description_epoch == epoch) + { + fprintf (stderr, + "mudflap object %p: name=`%s'\n", + (void *) obj, (obj->name ? obj->name : "")); + return; + } + else + obj->description_epoch = epoch; + + fprintf (stderr, + "mudflap object %p: name=`%s'\n" + "bounds=[%p,%p] size=%lu area=%s check=%ur/%uw liveness=%u%s\n" + "alloc time=%lu.%06lu pc=%p" +#ifdef LIBMUDFLAPTH + " thread=%u" +#endif + "\n", + (void *) obj, (obj->name ? obj->name : ""), + (void *) obj->low, (void *) obj->high, + (unsigned long) (obj->high - obj->low + 1), + (obj->type == __MF_TYPE_NOACCESS ? "no-access" : + obj->type == __MF_TYPE_HEAP ? "heap" : + obj->type == __MF_TYPE_HEAP_I ? "heap-init" : + obj->type == __MF_TYPE_STACK ? "stack" : + obj->type == __MF_TYPE_STATIC ? "static" : + obj->type == __MF_TYPE_GUESS ? "guess" : + "unknown"), + obj->read_count, obj->write_count, obj->liveness, + obj->watching_p ? " watching" : "", + obj->alloc_time.tv_sec, obj->alloc_time.tv_usec, + (void *) obj->alloc_pc +#ifdef LIBMUDFLAPTH + , (unsigned) obj->alloc_thread +#endif + ); + + if (__mf_opts.backtrace > 0) + { + unsigned i; + for (i=0; ialloc_backtrace_size; i++) + fprintf (stderr, " %s\n", obj->alloc_backtrace[i]); + } + + if (__mf_opts.persistent_count > 0) + { + if (obj->deallocated_p) + { + fprintf (stderr, "dealloc time=%lu.%06lu pc=%p" +#ifdef LIBMUDFLAPTH + " thread=%u" +#endif + "\n", + obj->dealloc_time.tv_sec, obj->dealloc_time.tv_usec, + (void *) obj->dealloc_pc +#ifdef LIBMUDFLAPTH + , (unsigned) obj->dealloc_thread +#endif + ); + + + if (__mf_opts.backtrace > 0) + { + unsigned i; + for (i=0; idealloc_backtrace_size; i++) + fprintf (stderr, " %s\n", obj->dealloc_backtrace[i]); + } + } + } +} + +static unsigned +__mf_report_leaks (__mf_object_tree_t *node) +{ + /* The counter is amongst recursive calls, so + that cumulative numbers are printed below. */ + static unsigned count = 0; + + if (node == NULL) /* Reset */ + { + count = 0; + return 0; + } + + /* Inorder traversal. */ + if (node->left) + __mf_report_leaks (node->left); + if (node->data.type == __MF_TYPE_HEAP + || node->data.type == __MF_TYPE_HEAP_I) + { + count ++; + fprintf (stderr, "Leaked object %u:\n", count); + __mf_describe_object (& node->data); + } + if (node->right) + __mf_report_leaks (node->right); + + return count; +} + +/* ------------------------------------------------------------------------ */ +/* __mf_report */ + +void +__mf_report () +{ + LOCKTH (); + BEGIN_RECURSION_PROTECT (); + __mfu_report (); + END_RECURSION_PROTECT (); + UNLOCKTH (); +} + +void +__mfu_report () +{ + if (__mf_opts.collect_stats) + { + fprintf (stderr, + "*******\n" + "mudflap stats:\n" + "calls to __mf_check: %lu rot: %lu/%lu\n" + " __mf_register: %lu [%luB, %luB, %luB, %luB, %luB]\n" + " __mf_unregister: %lu [%luB]\n" + " __mf_violation: [%lu, %lu, %lu, %lu, %lu]\n", + __mf_count_check, __mf_treerot_left, __mf_treerot_right, + __mf_count_register, + __mf_total_register_size[0], __mf_total_register_size[1], + __mf_total_register_size[2], __mf_total_register_size[3], + __mf_total_register_size[4], /* XXX */ + __mf_count_unregister, __mf_total_unregister_size, + __mf_count_violation[0], __mf_count_violation[1], + __mf_count_violation[2], __mf_count_violation[3], + __mf_count_violation[4]); + + fprintf (stderr, + "calls with reentrancy: %lu\n", __mf_reentrancy); +#ifdef LIBMUDFLAPTH + fprintf (stderr, + " lock contention: %lu\n", __mf_lock_contention); +#endif + + /* Lookup cache stats. */ + { + unsigned i; + unsigned max_reuse = 0; + unsigned num_used = 0; + unsigned num_unused = 0; + + for (i = 0; i < LOOKUP_CACHE_SIZE; i++) + { + if (__mf_lookup_cache_reusecount[i]) + num_used ++; + else + num_unused ++; + if (max_reuse < __mf_lookup_cache_reusecount[i]) + max_reuse = __mf_lookup_cache_reusecount[i]; + } + fprintf (stderr, "lookup cache slots used: %u unused: %u peak-reuse: %u\n", + num_used, num_unused, max_reuse); + } + + { + unsigned live_count; + live_count = __mf_find_objects (MINPTR, MAXPTR, NULL, 0); + fprintf (stderr, "number of live objects: %u\n", live_count); + } + + if (__mf_opts.persistent_count > 0) + { + unsigned dead_count = 0; + unsigned row, plot; + for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++) + for (plot = 0 ; plot < __mf_opts.persistent_count; plot ++) + if (__mf_object_cemetary [row][plot] != 0) + dead_count ++; + fprintf (stderr, " zombie objects: %u\n", dead_count); + } + } + if (__mf_opts.print_leaks && (__mf_opts.mudflap_mode == mode_check)) + { + unsigned l; + extern void * __mf_wrap_alloca_indirect (size_t c); + + /* Free up any remaining alloca()'d blocks. */ + __mf_wrap_alloca_indirect (0); + __mf_describe_object (NULL); /* Reset description epoch. */ + __mf_report_leaks (NULL); /* Reset cumulative count. */ + l = __mf_report_leaks (__mf_object_root); + fprintf (stderr, "number of leaked objects: %u\n", l); + } +} + +/* __mf_backtrace */ + +size_t +__mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels) +{ + void ** pc_array; + unsigned pc_array_size = __mf_opts.backtrace + guess_omit_levels; + unsigned remaining_size; + unsigned omitted_size = 0; + unsigned i; + DECLARE (void, free, void *ptr); + DECLARE (void *, calloc, size_t c, size_t n); + DECLARE (void *, malloc, size_t n); + + pc_array = CALL_REAL (calloc, pc_array_size, sizeof (void *) ); +#ifdef HAVE_BACKTRACE + pc_array_size = backtrace (pc_array, pc_array_size); +#else +#define FETCH(n) do { if (pc_array_size >= n) { \ + pc_array[n] = __builtin_return_address(n); \ + if (pc_array[n] == 0) pc_array_size = n; } } while (0) + + /* Unroll some calls __builtin_return_address because this function + only takes a literal integer parameter. */ + FETCH (0); +#if 0 + /* XXX: __builtin_return_address sometimes crashes (!) on >0 arguments, + rather than simply returning 0. :-( */ + FETCH (1); + FETCH (2); + FETCH (3); + FETCH (4); + FETCH (5); + FETCH (6); + FETCH (7); + FETCH (8); + if (pc_array_size > 8) pc_array_size = 9; +#else + if (pc_array_size > 0) pc_array_size = 1; +#endif + +#undef FETCH +#endif + + /* We want to trim the first few levels of the stack traceback, + since they contain libmudflap wrappers and junk. If pc_array[] + ends up containing a non-NULL guess_pc, then trim everything + before that. Otherwise, omit the first guess_omit_levels + entries. */ + + if (guess_pc != NULL) + for (i=0; i guess_omit_levels) + omitted_size = guess_omit_levels; + + remaining_size = pc_array_size - omitted_size; + +#ifdef HAVE_BACKTRACE_SYMBOLS + *symbols = backtrace_symbols (pc_array + omitted_size, remaining_size); +#else + { + /* Let's construct a buffer by hand. It will have + char*'s at the front, pointing at individual strings immediately + afterwards. */ + void *buffer; + char *chars; + char **pointers; + enum { perline = 30 }; + buffer = CALL_REAL (malloc, remaining_size * (perline + sizeof(char *))); + pointers = (char **) buffer; + chars = (char *)buffer + (remaining_size * sizeof (char *)); + for (i = 0; i < remaining_size; i++) + { + pointers[i] = chars; + sprintf (chars, "[0x%p]", pc_array [omitted_size + i]); + chars = chars + perline; + } + *symbols = pointers; + } +#endif + CALL_REAL (free, pc_array); + + return remaining_size; +} + +/* ------------------------------------------------------------------------ */ +/* __mf_violation */ + +void +__mf_violation (void *ptr, size_t sz, uintptr_t pc, + const char *location, int type) +{ + char buf [128]; + static unsigned violation_number; + DECLARE(void, free, void *ptr); + + TRACE ("violation pc=%p location=%s type=%d ptr=%p size=%lu\n", + (void *) pc, + (location != NULL ? location : ""), type, ptr, (unsigned long) sz); + + if (__mf_opts.collect_stats) + __mf_count_violation [(type < 0) ? 0 : + (type > __MF_VIOL_WATCH) ? 0 : + type] ++; + + /* Print out a basic warning message. */ + if (__mf_opts.verbose_violations) + { + unsigned dead_p; + unsigned num_helpful = 0; + struct timeval now; +#if HAVE_GETTIMEOFDAY + gettimeofday (& now, NULL); +#endif + + violation_number ++; + fprintf (stderr, + "*******\n" + "mudflap violation %u (%s): time=%lu.%06lu " + "ptr=%p size=%lu\npc=%p%s%s%s\n", + violation_number, + ((type == __MF_VIOL_READ) ? "check/read" : + (type == __MF_VIOL_WRITE) ? "check/write" : + (type == __MF_VIOL_REGISTER) ? "register" : + (type == __MF_VIOL_UNREGISTER) ? "unregister" : + (type == __MF_VIOL_WATCH) ? "watch" : "unknown"), + now.tv_sec, now.tv_usec, + (void *) ptr, (unsigned long)sz, (void *) pc, + (location != NULL ? " location=`" : ""), + (location != NULL ? location : ""), + (location != NULL ? "'" : "")); + + if (__mf_opts.backtrace > 0) + { + char ** symbols; + unsigned i, num; + + num = __mf_backtrace (& symbols, (void *) pc, 2); + /* Note: backtrace_symbols calls malloc(). But since we're in + __mf_violation and presumably __mf_check, it'll detect + recursion, and not put the new string into the database. */ + + for (i=0; idata; + uintptr_t low = (uintptr_t) ptr; + uintptr_t high = CLAMPSZ (ptr, sz); + unsigned before1 = (low < obj->low) ? obj->low - low : 0; + unsigned after1 = (low > obj->high) ? low - obj->high : 0; + unsigned into1 = (high >= obj->low && low <= obj->high) ? low - obj->low : 0; + unsigned before2 = (high < obj->low) ? obj->low - high : 0; + unsigned after2 = (high > obj->high) ? high - obj->high : 0; + unsigned into2 = (high >= obj->low && low <= obj->high) ? high - obj->low : 0; + + fprintf (stderr, "Nearby object %u: checked region begins %uB %s and ends %uB %s\n", + num_helpful + i + 1, + (before1 ? before1 : after1 ? after1 : into1), + (before1 ? "before" : after1 ? "after" : "into"), + (before2 ? before2 : after2 ? after2 : into2), + (before2 ? "before" : after2 ? "after" : "into")); + __mf_describe_object (obj); + } + num_helpful += num_objs; + } + + fprintf (stderr, "number of nearby objects: %u\n", num_helpful); + } + + /* How to finally handle this violation? */ + switch (__mf_opts.violation_mode) + { + case viol_nop: + break; + case viol_segv: + kill (getpid(), SIGSEGV); + break; + case viol_abort: + abort (); + break; + case viol_gdb: + snprintf (buf, 128, "gdb --pid=%d", getpid ()); + system (buf); + /* XXX: should probably fork() && sleep(GDB_WAIT_PARAMETER) + instead, and let the forked child execlp() gdb. That way, this + subject process can be resumed under the supervision of gdb. + This can't happen now, since system() only returns when gdb + dies. In that case, we need to beware of starting a second + concurrent gdb child upon the next violation. (But if the first + gdb dies, then starting a new one is appropriate.) */ + break; + } +} + +/* ------------------------------------------------------------------------ */ + + +unsigned __mf_watch (void *ptr, size_t sz) +{ + unsigned rc; + LOCKTH (); + BEGIN_RECURSION_PROTECT (); + rc = __mf_watch_or_not (ptr, sz, 1); + END_RECURSION_PROTECT (); + UNLOCKTH (); + return rc; +} + +unsigned __mf_unwatch (void *ptr, size_t sz) +{ + unsigned rc; + LOCKTH (); + rc = __mf_watch_or_not (ptr, sz, 0); + UNLOCKTH (); + return rc; +} + + +static unsigned +__mf_watch_or_not (void *ptr, size_t sz, char flag) +{ + uintptr_t ptr_high = CLAMPSZ (ptr, sz); + uintptr_t ptr_low = (uintptr_t) ptr; + unsigned count = 0; + + TRACE ("%s ptr=%p size=%lu\n", + (flag ? "watch" : "unwatch"), ptr, (unsigned long) sz); + + switch (__mf_opts.mudflap_mode) + { + case mode_nop: + case mode_populate: + case mode_violate: + count = 0; + break; + + case mode_check: + { + __mf_object_tree_t **all_ovr_objs; + unsigned obj_count; + unsigned n; + DECLARE (void *, malloc, size_t c); + DECLARE (void, free, void *p); + + obj_count = __mf_find_objects (ptr_low, ptr_high, NULL, 0); + VERBOSE_TRACE (" %u:", obj_count); + + all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_tree_t *) * + obj_count)); + if (all_ovr_objs == NULL) abort (); + n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count); + assert (n == obj_count); + + for (n = 0; n < obj_count; n ++) + { + __mf_object_t *obj = & (all_ovr_objs[n]->data); + + VERBOSE_TRACE (" [%p]", (void *) obj); + if (obj->watching_p != flag) + { + obj->watching_p = flag; + count ++; + + /* Remove object from cache, to ensure next access + goes through __mf_check(). */ + if (flag) + __mf_uncache_object (obj); + } + } + CALL_REAL (free, all_ovr_objs); + } + break; + } + + return count; +} + + +void +__mf_sigusr1_handler (int num) +{ + __mf_sigusr1_received ++; +} + +/* Install or remove SIGUSR1 handler as necessary. + Also, respond to a received pending SIGUSR1. */ +void +__mf_sigusr1_respond () +{ + static int handler_installed; + +#if HAVE_SIGNAL + /* Manage handler */ + if (__mf_opts.sigusr1_report && ! handler_installed) + { + signal (SIGUSR1, __mf_sigusr1_handler); + handler_installed = 1; + } + else if(! __mf_opts.sigusr1_report && handler_installed) + { + signal (SIGUSR1, SIG_DFL); + handler_installed = 0; + } +#endif + + /* Manage enqueued signals */ + if (__mf_sigusr1_received > __mf_sigusr1_handled) + { + __mf_sigusr1_handled ++; + assert (__mf_state == reentrant); + __mfu_report (); + handler_installed = 0; /* We may need to re-enable signal; this might be a SysV library. */ + } +} + + +/* XXX: provide an alternative __assert_fail function that cannot + fail due to libmudflap infinite recursion. */ +#ifndef NDEBUG + +static void +write_itoa (int fd, unsigned n) +{ + enum x { bufsize = sizeof(n)*4 }; + char buf [bufsize]; + unsigned i; + + for (i=0; i +#endif +#include +#if ! @MF_HAVE_UINTPTR_T@ +typedef unsigned long uintptr_t; +#define HAVE_UINTPTR_T 1 +/* Define this here, in case an autoconf application was run + without CFLAGS=-fmudflap but is being compiled with -fmudflap. */ +#endif + + +/* Global declarations used by instrumentation. */ + +struct __mf_cache { uintptr_t low; uintptr_t high; }; +extern struct __mf_cache __mf_lookup_cache []; +extern uintptr_t __mf_lc_mask; +extern unsigned char __mf_lc_shift; + +/* Multithreading support. */ +#ifdef _MUDFLAPTH +/* extern pthread_mutex_t __mf_biglock; */ +#define _REENTRANT +#define _THREAD_SAFE +#endif + +/* Codes to describe the type of access to check: __mf_check arg 3 */ + +#define __MF_CHECK_READ 0 +#define __MF_CHECK_WRITE 1 + + +/* Codes to describe a region of memory being registered: __mf_*register arg 3 */ + +#define __MF_TYPE_NOACCESS 0 +#define __MF_TYPE_HEAP 1 +#define __MF_TYPE_HEAP_I 2 +#define __MF_TYPE_STACK 3 +#define __MF_TYPE_STATIC 4 +#define __MF_TYPE_GUESS 5 + + +/* The public mudflap API */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void __mf_check (void *ptr, size_t sz, int type, const char *location) + __attribute((nothrow)); +extern void __mf_register (void *ptr, size_t sz, int type, const char *name) + __attribute((nothrow)); +extern void __mf_unregister (void *ptr, size_t sz) __attribute((nothrow)); +extern unsigned __mf_watch (void *ptr, size_t sz); +extern unsigned __mf_unwatch (void *ptr, size_t sz); +extern void __mf_report (); +extern int __mf_set_options (const char *opts); + + +/* Redirect some standard library functions to libmudflap. These are + done by simple #define rather than linker wrapping, since only + instrumented modules are meant to be affected. */ + +#ifdef _MUDFLAP +#pragma redefine_extname memcpy __mfwrap_memcpy +#pragma redefine_extname memmove __mfwrap_memmove +#pragma redefine_extname memset __mfwrap_memset +#pragma redefine_extname memcmp __mfwrap_memcmp +#pragma redefine_extname memchr __mfwrap_memchr +#pragma redefine_extname memrchr __mfwrap_memrchr +#pragma redefine_extname strcpy __mfwrap_strcpy +#pragma redefine_extname strncpy __mfwrap_strncpy +#pragma redefine_extname strcat __mfwrap_strcat +#pragma redefine_extname strncat __mfwrap_strncat +#pragma redefine_extname strcmp __mfwrap_strcmp +#pragma redefine_extname strcasecmp __mfwrap_strcasecmp +#pragma redefine_extname strncmp __mfwrap_strncmp +#pragma redefine_extname strncasecmp __mfwrap_strncasecmp +#pragma redefine_extname strdup __mfwrap_strdup +#pragma redefine_extname strndup __mfwrap_strndup +#pragma redefine_extname strchr __mfwrap_strchr +#pragma redefine_extname strrchr __mfwrap_strrchr +#pragma redefine_extname strstr __mfwrap_strstr +#pragma redefine_extname memmem __mfwrap_memmem +#pragma redefine_extname strlen __mfwrap_strlen +#pragma redefine_extname strnlen __mfwrap_strnlen +#pragma redefine_extname bzero __mfwrap_bzero +#pragma redefine_extname bcopy __mfwrap_bcopy +#pragma redefine_extname bcmp __mfwrap_bcmp +#pragma redefine_extname index __mfwrap_index +#pragma redefine_extname rindex __mfwrap_rindex +#pragma redefine_extname asctime __mfwrap_asctime +#pragma redefine_extname ctime __mfwrap_ctime +#pragma redefine_extname gmtime __mfwrap_gmtime +#pragma redefine_extname localtime __mfwrap_localtime +#pragma redefine_extname time __mfwrap_time +#pragma redefine_extname strerror __mfwrap_strerror +#pragma redefine_extname fopen __mfwrap_fopen +#pragma redefine_extname fclose __mfwrap_fclose +#pragma redefine_extname fread __mfwrap_fread +#pragma redefine_extname fwrite __mfwrap_fwrite +#pragma redefine_extname fgetc __mfwrap_fgetc +#pragma redefine_extname fgets __mfwrap_fgets +#pragma redefine_extname getc __mfwrap_getc +#pragma redefine_extname gets __mfwrap_gets +#pragma redefine_extname ungetc __mfwrap_ungetc +#pragma redefine_extname fputc __mfwrap_fputc +#pragma redefine_extname fputs __mfwrap_fputs +#pragma redefine_extname putc __mfwrap_putc +#pragma redefine_extname puts __mfwrap_puts +#pragma redefine_extname clearerr __mfwrap_clearerr +#pragma redefine_extname feof __mfwrap_feof +#pragma redefine_extname ferror __mfwrap_ferror +#pragma redefine_extname fileno __mfwrap_fileno +#pragma redefine_extname printf __mfwrap_printf +#pragma redefine_extname fprintf __mfwrap_fprintf +#pragma redefine_extname sprintf __mfwrap_sprintf +#pragma redefine_extname snprintf __mfwrap_snprintf +#pragma redefine_extname vprintf __mfwrap_vprintf +#pragma redefine_extname vfprintf __mfwrap_vfprintf +#pragma redefine_extname vsprintf __mfwrap_vsprintf +#pragma redefine_extname vsnprintf __mfwrap_vsnprintf +#pragma redefine_extname access __mfwrap_access +#pragma redefine_extname remove __mfwrap_remove +#pragma redefine_extname fflush __mfwrap_fflush +#pragma redefine_extname fseek __mfwrap_fseek +#pragma redefine_extname ftell __mfwrap_ftell +#pragma redefine_extname rewind __mfwrap_rewind +#pragma redefine_extname fgetpos __mfwrap_fgetpos +#pragma redefine_extname fsetpos __mfwrap_fsetpos +#pragma redefine_extname stat __mfwrap_stat +#pragma redefine_extname fstat __mfwrap_fstat +#pragma redefine_extname lstat __mfwrap_lstat +#pragma redefine_extname mkfifo __mfwrap_mkfifo +#pragma redefine_extname setvbuf __mfwrap_setvbuf +#pragma redefine_extname setbuf __mfwrap_setbuf +#pragma redefine_extname opendir __mfwrap_opendir +#pragma redefine_extname closedir __mfwrap_closedir +#pragma redefine_extname readdir __mfwrap_readdir +#pragma redefine_extname recv __mfwrap_recv +#pragma redefine_extname recvfrom __mfwrap_recvfrom +#pragma redefine_extname recvmsg __mfwrap_recvmsg +#pragma redefine_extname send __mfwrap_send +#pragma redefine_extname sendto __mfwrap_sendto +#pragma redefine_extname sendmsg __mfwrap_sendmsg +#pragma redefine_extname setsockopt __mfwrap_setsockopt +#pragma redefine_extname getsockopt __mfwrap_getsockopt +#pragma redefine_extname accept __mfwrap_accept +#pragma redefine_extname bind __mfwrap_bind +#pragma redefine_extname connect __mfwrap_connect +#pragma redefine_extname gethostname __mfwrap_gethostname +#pragma redefine_extname sethostname __mfwrap_sethostname +#pragma redefine_extname gethostbyname __mfwrap_gethostbyname +#pragma redefine_extname wait __mfwrap_wait +#pragma redefine_extname waitpid __mfwrap_waitpid +#pragma redefine_extname popen __mfwrap_popen +#pragma redefine_extname pclose __mfwrap_pclose +#pragma redefine_extname execve __mfwrap_execve +#pragma redefine_extname execv __mfwrap_execv +#pragma redefine_extname execvp __mfwrap_execvp +#pragma redefine_extname system __mfwrap_system +#pragma redefine_extname dlopen __mfwrap_dlopen +#pragma redefine_extname dlerror __mfwrap_dlerror +#pragma redefine_extname dlsym __mfwrap_dlsym +#pragma redefine_extname dlclose __mfwrap_dlclose +#pragma redefine_extname fopen64 __mfwrap_fopen64 +#pragma redefine_extname stat64 __mfwrap_stat64 +#pragma redefine_extname fseeko64 __mfwrap_fseeko64 +#pragma redefine_extname ftello64 __mfwrap_ftello64 +#pragma redefine_extname semop __mfwrap_semop +#pragma redefine_extname semctl __mfwrap_semctl +#pragma redefine_extname shmctl __mfwrap_shmctl +#pragma redefine_extname shmat __mfwrap_shmat +#pragma redefine_extname shmdt __mfwrap_shmdt + +/* Disable glibc macros. */ +#define __NO_STRING_INLINES + +#endif /* _MUDFLAP */ + + +#ifdef __cplusplus +} +#endif + +#endif /* MF_RUNTIME_H */ diff --git a/libmudflap/stamp-h.in b/libmudflap/stamp-h.in new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libmudflap/testsuite/Makefile.am b/libmudflap/testsuite/Makefile.am new file mode 100644 index 00000000000..11938e6cf65 --- /dev/null +++ b/libmudflap/testsuite/Makefile.am @@ -0,0 +1,18 @@ +## Process this with automake to create Makefile.in + +AUTOMAKE_OPTIONS = foreign dejagnu + +EXPECT = `if [ -f ../../expect/expect ] ; then \ + echo ../../expect/expect ; \ + else echo expect ; fi` + +RUNTEST = `if [ -f ${srcdir}/../../dejagnu/runtest ] ; then \ + echo ${srcdir}/../../dejagnu/runtest ; \ + else echo runtest ; fi` + +all-local: site.exp +if LIBMUDFLAPTH + echo 'set libmudflapth 1' >> site.exp +else + echo 'set libmudflapth 0' >> site.exp +endif diff --git a/libmudflap/testsuite/Makefile.in b/libmudflap/testsuite/Makefile.in new file mode 100644 index 00000000000..30e1763ccdd --- /dev/null +++ b/libmudflap/testsuite/Makefile.in @@ -0,0 +1,249 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AS = @AS@ +CC = @CC@ +CPP = @CPP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DLLTOOL = @DLLTOOL@ +EXEEXT = @EXEEXT@ +GCJ = @GCJ@ +GCJFLAGS = @GCJFLAGS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MF_HAVE_STDINT_H = @MF_HAVE_STDINT_H@ +MF_HAVE_UINTPTR_T = @MF_HAVE_UINTPTR_T@ +NM = @NM@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +enable_shared = @enable_shared@ +enable_static = @enable_static@ +libtool_VERSION = @libtool_VERSION@ + +AUTOMAKE_OPTIONS = foreign dejagnu + +EXPECT = `if [ -f ../../expect/expect ] ; then \ + echo ../../expect/expect ; \ + else echo expect ; fi` + + +RUNTEST = `if [ -f ${srcdir}/../../dejagnu/runtest ] ; then \ + echo ${srcdir}/../../dejagnu/runtest ; \ + else echo runtest ; fi` + +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = testsuite + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign testsuite/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +RUNTESTFLAGS = + +DEJATOOL = $(PACKAGE) + +RUNTESTDEFAULTFLAGS = --tool $(DEJATOOL) --srcdir $$srcdir + +check-DEJAGNU: site.exp + srcdir=`cd $(srcdir) && pwd`; export srcdir; \ + EXPECT=$(EXPECT); export EXPECT; \ + runtest=$(RUNTEST); \ + if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \ + $$runtest $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \ + else echo "WARNING: could not find \`runtest'" 1>&2; :;\ + fi +site.exp: Makefile + @echo 'Making a new site.exp file...' + @test ! -f site.bak || rm -f site.bak + @echo '## these variables are automatically generated by make ##' > $@-t + @echo '# Do not edit here. If you wish to override these values' >> $@-t + @echo '# edit the last section' >> $@-t + @echo 'set tool $(DEJATOOL)' >> $@-t + @echo 'set srcdir $(srcdir)' >> $@-t + @echo 'set objdir' `pwd` >> $@-t + @echo 'set host_alias $(host_alias)' >> $@-t + @echo 'set host_triplet $(host_triplet)' >> $@-t + @echo 'set target_alias $(target_alias)' >> $@-t + @echo 'set target_triplet $(target_triplet)' >> $@-t + @echo 'set build_alias $(build_alias)' >> $@-t + @echo 'set build_triplet $(build_triplet)' >> $@-t + @echo '## All variables above are generated by configure. Do Not Edit ##' >> $@-t + @test ! -f site.exp || sed '1,/^## All variables above are.*##/ d' site.exp >> $@-t + @test ! -f site.exp || mv site.exp site.bak + @mv $@-t site.exp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile all-local +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: tags distdir check-DEJAGNU info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-local all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +all-local: site.exp +@LIBMUDFLAPTH_TRUE@ echo 'set libmudflapth 1' >> site.exp +@LIBMUDFLAPTH_FALSE@ echo 'set libmudflapth 0' >> site.exp + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libmudflap/testsuite/config/default.exp b/libmudflap/testsuite/config/default.exp new file mode 100644 index 00000000000..b19491c547c --- /dev/null +++ b/libmudflap/testsuite/config/default.exp @@ -0,0 +1,2 @@ +load_lib standard.exp +load_lib libmudflap.exp diff --git a/libmudflap/testsuite/lib/libmudflap.exp b/libmudflap/testsuite/lib/libmudflap.exp new file mode 100644 index 00000000000..1d1e22ffb28 --- /dev/null +++ b/libmudflap/testsuite/lib/libmudflap.exp @@ -0,0 +1,237 @@ +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Define libmudflap callbacks for dg.exp. +# This file is a copy of libstdc++-v3's dejagnu driver, with minor changes. + + +load_lib mfdg.exp +load_lib libgloss.exp + +proc libmudflap-init { compiler } { + global srcdir + global outdir + global blddir + global cxx + global includes + global libs + global cxxflags + global objdir + global gluefile wrap_flags + global ld_library_path + global tool_root_dir + + verbose "libmudflap-init $compiler" + + set blddir [lookfor_file [get_multilibs] libmudflap] + + # By default, we assume we want to run program images. + global dg-do-what-default + set dg-do-what-default run + + # set LD_LIBRARY_PATH so that libgcc_s, libstdc++ binaries can be found. + # locate libgcc.a so we don't need to account for different values of + # SHLIB_EXT on different platforms + set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a] + if {$gccdir != ""} { + set gccdir [file dirname $gccdir] + } + + set ld_library_path "." + append ld_library_path ":${gccdir}" + append ld_library_path ":../../libstdc++-v3/src/.libs" + if {[is_remote host] == 0} { + foreach i "[exec ${gccdir}/xgcc --print-multi-lib]" { + set mldir "" + regexp -- "\[a-z0-9=/\.-\]*;" $i mldir + set mldir [string trimright $mldir "\;@"] + if { "$mldir" == "." } { + continue + } + if { [llength [glob -nocomplain ${gccdir}/${mldir}/libgcc_s*.so.*]] == 1 } { + append ld_library_path ":${gccdir}/${mldir}" + append ld_library_path ":../../libstdc++-v3/${mldir}/src/.libs" + } + } + } + append ld_library_path ":${blddir}/.libs" + set cxx $compiler + set libs "-L../.libs -L../../libstdc++-v3/src/.libs -L../../../gcc" + set cxxflags "-ggdb3 -DDEBUG_ASSERT" + set includes "-I${srcdir} -I.." + + verbose "ld_library_path=$ld_library_path" + setenv LD_LIBRARY_PATH $ld_library_path + setenv SHLIB_PATH $ld_library_path + setenv LD_LIBRARYN32_PATH $ld_library_path + setenv LD_LIBRARY64_PATH $ld_library_path + + if { [target_info needs_status_wrapper]!=""} { + file delete ${objdir}/testglue.o; + set gluefile ${objdir}/testglue.o; + set result [build_wrapper $gluefile]; + if { $result != "" } { + set gluefile [lindex $result 0]; + set wrap_flags [lindex $result 1]; + } else { + unset gluefile + } + } +} + +proc libmudflap-dg-test { prog do_what extra_tool_flags } { + # Set up the compiler flags, based on what we're going to do. + + switch $do_what { + "preprocess" { + set compile_type "preprocess" + set output_file "[file rootname [file tail $prog]].i" + } + "compile" { + set compile_type "assembly" + set output_file "[file rootname [file tail $prog]].s" + } + "assemble" { + set compile_type "object" + set output_file "[file rootname [file tail $prog]].o" + } + "link" { + set compile_type "executable" + set output_file "./[file rootname [file tail $prog]].exe" + } + "run" { + set compile_type "executable" + # FIXME: "./" is to cope with "." not being in $PATH. + # Should this be handled elsewhere? + # YES. + set output_file "./[file rootname [file tail $prog]].exe" + # This is the only place where we care if an executable was + # created or not. If it was, dg.exp will try to run it. + remote_file build delete $output_file; + } + default { + perror "$do_what: not a valid dg-do keyword" + return "" + } + } + set options "" + if { $extra_tool_flags != "" } { + lappend options "additional_flags=$extra_tool_flags" + } + + set comp_output [libmudflap_target_compile "$prog" "$output_file" "$compile_type" $options]; + set comp_output [prune_gcc_output $comp_output ]; + + return [list $comp_output $output_file] +} + + +proc libmudflap_target_compile { source dest type options } { + global gluefile + global wrap_flags + global cxx + global cxxflags + global includes + global libs + global blddir + + if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } { + lappend options "libs=${gluefile}" + lappend options "ldflags=${wrap_flags}" + } + + set cxx_final $cxx + set cxxlibglossflags [libgloss_link_flags] + set cxx_final [concat $cxx_final $cxxlibglossflags] + set cxx_final [concat $cxx_final $cxxflags] + set cxx_final [concat $cxx_final $includes] + set cxx_final [concat $cxx_final $libs] + + lappend options "compiler=$cxx_final" + + # Picks up the freshly-built testsuite library corresponding to the + # multilib under test. + lappend options "ldflags=-L${blddir}/testsuite" + + return [target_compile $source $dest $type $options] +} + + +# A bit sloppy... Returns a list of source files (full pathnames) to +# compile. We mimic the mkcheck script in that the first time this is run, +# all existing files are listed in "testsuite_files" in the output +# directory. Subsequent runs pull the list from that file, allowing users +# to trim the list down to problematic tests. +### This is supposed to be done via RUNTESTFLAGS, but that doesn't work. +proc libmudflap-list-sourcefiles { } { + global srcdir + global outdir + + set files_file "${outdir}/testsuite_files" + set sfiles "" + if { [file exists $files_file] } { + set f [open $files_file] + while { ! [eof $f] } { + set t [gets $f] + if { [string length "$t"] != 0 } { + lappend sfiles ${srcdir}/${t} + } + } + } else { + set f [open $files_file "w"] + set where_we_were [pwd] + cd $srcdir + foreach s [lsort [glob -nocomplain "*/*.cc" "*/*/*.cc" "{,*/}*/*/*/*.cc" ]] { + lappend sfiles ${srcdir}/${s} + puts $f $s + } + cd $where_we_were + } + close $f + + # Disable wchar_t tests if library not configured to support + # wchar_t testing. + set wchar_file "${outdir}/testsuite_wchar_t" + if { [file exists $wchar_file] } { + return $sfiles + } else { + # Remove wchar_t tests files from list. + set res {} + foreach w $sfiles { + if [regexp "wchar_t" $w] { + verbose "element out list is $w" + } else { + verbose "element in list is $w" + lappend res $w + } + } + return $res + } +} + + +proc prune_gcc_output { text } { + + regsub -all {(^|\n)[^\n]*ld: warning: libgcc_s[^\n]*not found[^\n]*try using[^\n]*} $text "" text + + regsub -all {(^|\n)[^\n]*In function.*pthread_create[^\n]*} $text "" text + + regsub -all {(^|\n)[^\n]*the use of .pthread.*is deprecated[^\n]*} $text "" text + + regsub -all {(^|\n)[^\n]*Dwarf Error:.*FORM value: 14[^\n]*} $text "" text + + return $text +} diff --git a/libmudflap/testsuite/lib/mfdg.exp b/libmudflap/testsuite/lib/mfdg.exp new file mode 100644 index 00000000000..25473d61269 --- /dev/null +++ b/libmudflap/testsuite/lib/mfdg.exp @@ -0,0 +1,377 @@ +# `mfdg' - overrides parts of general purpose testcase driver. +# Copyright (C) 1994 - 2001, 2003 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +# This is a modified excerpt of dejagnu/lib/dg.exp. + +load_lib dg.exp + + +# dg-test -- runs a new style DejaGnu test +# +# Syntax: dg-test [-keep-output] prog tool_flags default_extra_tool_flags +# +# PROG is the full path name of the file to pass to the tool (eg: compiler). +# TOOL_FLAGS is a set of options to always pass. +# DEFAULT_EXTRA_TOOL_FLAGS are additional options if the testcase has none. + +#proc dg-test { prog tool_flags default_extra_tool_flags } { +proc dg-test { args } { + global dg-do-what-default dg-interpreter-batch-mode dg-linenum-format + global errorCode errorInfo + global tool + global srcdir ;# eg: /calvin/dje/build/gcc/./testsuite/ + global host_triplet target_triplet + + set keep 0 + set i 0 + set dg-repetitions 1 ;# may be overridden by { dg-repetitions N } + global dg-timeout + set dg-timeout 0 ;# likewise by { dg-timeout N } + + if { [string index [lindex $args 0] 0] == "-" } { + for { set i 0 } { $i < [llength $args] } { incr i } { + if { [lindex $args $i] == "--" } { + incr i + break + } elseif { [lindex $args $i] == "-keep-output" } { + set keep 1 + } elseif { [string index [lindex $args $i] 0] == "-" } { + clone_output "ERROR: dg-test: illegal argument: [lindex $args $i]" + return + } else { + break + } + } + } + + if { $i + 3 != [llength $args] } { + clone_output "ERROR: dg-test: missing arguments in call" + return + } + set prog [lindex $args $i] + set tool_flags [lindex $args [expr $i + 1]] + set default_extra_tool_flags [lindex $args [expr $i + 2]] + + set text "\[- A-Za-z0-9\.\;\"\_\:\'\`\(\)\!\#\=\+\?\&\*]*" + + set name [dg-trim-dirname $srcdir $prog] + # If we couldn't rip $srcdir out of `prog' then just do the best we can. + # The point is to reduce the unnecessary noise in the logs. Don't strip + # out too much because different testcases with the same name can confuse + # `test-tool'. + if [string match "/*" $name] { + set name "[file tail [file dirname $prog]]/[file tail $prog]" + } + + if {$tool_flags != ""} { + append name " ($tool_flags)" + } + + # Process any embedded dg options in the testcase. + + # Use "" for the second element of dg-do-what so we can tell if it's been + # explicitly set to "S". + set dg-do-what [list ${dg-do-what-default} "" P] + set dg-excess-errors-flag 0 + set dg-messages "" + set dg-extra-tool-flags $default_extra_tool_flags + set dg-final-code "" + + # `dg-output-text' is a list of two elements: pass/fail and text. + # Leave second element off for now (indicates "don't perform test") + set dg-output-text "P" + + # Define our own "special function" `unknown' so we catch spelling errors. + # But first rename the existing one so we can restore it afterwards. + catch {rename dg-save-unknown ""} + rename unknown dg-save-unknown + proc unknown { args } { + return -code error "unknown dg option: $args" + } + + set tmp [dg-get-options $prog] + foreach op $tmp { + verbose "Processing option: $op" 3 + set status [catch "$op" errmsg] + if { $status != 0 } { + if { 0 && [info exists errorInfo] } { + # This also prints a backtrace which will just confuse + # testcase writers, so it's disabled. + perror "$name: $errorInfo\n" + } else { + perror "$name: $errmsg for \"$op\"\n" + } + # ??? The call to unresolved here is necessary to clear `errcnt'. + # What we really need is a proc like perror that doesn't set errcnt. + # It should also set exit_status to 1. + unresolved "$name: $errmsg for \"$op\"" + return + } + } + + # Restore normal error handling. + rename unknown "" + rename dg-save-unknown unknown + + # If we're not supposed to try this test on this target, we're done. + if { [lindex ${dg-do-what} 1] == "N" } { + unsupported "$name" + verbose "$name not supported on this target, skipping it" 3 + return + } + + # Run the tool and analyze the results. + # The result of ${tool}-dg-test is in a bit of flux. + # Currently it is the name of the output file (or "" if none). + # If we need more than this it will grow into a list of things. + # No intention is made (at this point) to preserve upward compatibility + # (though at some point we'll have to). + + set results [${tool}-dg-test $prog [lindex ${dg-do-what} 0] "$tool_flags ${dg-extra-tool-flags}"]; + + set comp_output [lindex $results 0]; + set output_file [lindex $results 1]; + + #send_user "\nold_dejagnu.exp: comp_output1 = :$comp_output:\n\n" + #send_user "\nold_dejagnu.exp: message = :$message:\n\n" + #send_user "\nold_dejagnu.exp: message length = [llength $message]\n\n" + + foreach i ${dg-messages} { + verbose "Scanning for message: $i" 4 + + # Remove all error messages for the line [lindex $i 0] + # in the source file. If we find any, success! + set line [lindex $i 0] + set pattern [lindex $i 2] + set comment [lindex $i 3] + #send_user "Before:\n$comp_output\n" + if [regsub -all "(^|\n)(\[^\n\]+$line\[^\n\]*($pattern)\[^\n\]*\n?)+" $comp_output "\n" comp_output] { + set comp_output [string trimleft $comp_output] + set ok pass + set uhoh fail + } else { + set ok fail + set uhoh pass + } + #send_user "After:\n$comp_output\n" + + # $line will either be a formatted line number or a number all by + # itself. Delete the formatting. + scan $line ${dg-linenum-format} line + switch [lindex $i 1] { + "ERROR" { + $ok "$name $comment (test for errors, line $line)" + } + "XERROR" { + x$ok "$name $comment (test for errors, line $line)" + } + "WARNING" { + $ok "$name $comment (test for warnings, line $line)" + } + "XWARNING" { + x$ok "$name $comment (test for warnings, line $line)" + } + "BOGUS" { + $uhoh "$name $comment (test for bogus messages, line $line)" + } + "XBOGUS" { + x$uhoh "$name $comment (test for bogus messages, line $line)" + } + "BUILD" { + $uhoh "$name $comment (test for build failure, line $line)" + } + "XBUILD" { + x$uhoh "$name $comment (test for build failure, line $line)" + } + "EXEC" { } + "XEXEC" { } + } + #send_user "\nold_dejagnu.exp: comp_output2= :$comp_output:\n\n" + } + #send_user "\nold_dejagnu.exp: comp_output3 = :$comp_output:\n\n" + + # Remove messages from the tool that we can ignore. + #send_user "comp_output: $comp_output\n" + set comp_output [prune_warnings $comp_output] + + if { [info proc ${tool}-dg-prune] != "" } { + set comp_output [${tool}-dg-prune $target_triplet $comp_output] + switch -glob $comp_output { + "::untested::*" { + regsub "::untested::" $comp_output "" message + untested "$name: $message" + return + } + "::unresolved::*" { + regsub "::unresolved::" $comp_output "" message + unresolved "$name: $message" + return + } + "::unsupported::*" { + regsub "::unsupported::" $comp_output "" message + unsupported "$name: $message" + return + } + } + } + + # See if someone forgot to delete the extra lines. + regsub -all "\n+" $comp_output "\n" comp_output + regsub "^\n+" $comp_output "" comp_output + #send_user "comp_output: $comp_output\n" + + # Don't do this if we're testing an interpreter. + # FIXME: why? + if { ${dg-interpreter-batch-mode} == 0 } { + # Catch excess errors (new bugs or incomplete testcases). + if ${dg-excess-errors-flag} { + setup_xfail "*-*-*" + } + if ![string match "" $comp_output] { + fail "$name (test for excess errors)" + send_log "Excess errors:\n$comp_output\n" + } else { + pass "$name (test for excess errors)" + } + } + + # Run the executable image if asked to do so. + # FIXME: This is the only place where we assume a standard meaning to + # the `keyword' argument of dg-do. This could be cleaned up. + if { [lindex ${dg-do-what} 0] == "run" } { + if ![file exists $output_file] { + warning "$name compilation failed to produce executable" + } else { + set testname $name + for {set rep 0} {$rep < ${dg-repetitions}} {incr rep} { + # include repetition number in test name + if {$rep > 0} { set name "$testname (rerun $rep)" } + + set status -1 + set result [${tool}_load $output_file] + set status [lindex $result 0]; + set output [lindex $result 1]; + #send_user "After exec, status: $status\n" + + if { "$status" == "pass" } { + verbose "Exec succeeded." 3 + } elseif { "$status" == "fail" } { + # It would be nice to get some info out of errorCode. + if [info exists errorCode] { + verbose "Exec failed, errorCode: $errorCode" 3 + } else { + verbose "Exec failed, errorCode not defined!" 3 + } + } + + if { [lindex ${dg-do-what} 2] == "F" } { + # Instead of modelling this as an xfail (via setup_xfail), + # treat an expected crash as a success. + if { $status == "pass" } then { set status fail } else { set status pass } + set testtype "crash" + } else { set testtype "execution" } + + $status "$name $testtype test" + + if { [llength ${dg-output-text}] > 1 } { + #send_user "${dg-output-text}\n" + if { [lindex ${dg-output-text} 0] == "F" } { + setup_xfail "*-*-*" + } + set texttmp [lindex ${dg-output-text} 1] + if { ![regexp $texttmp ${output}] } { + fail "$name output pattern test" + } else { + pass "$name output pattern test" + } + verbose -log "Output pattern $texttmp" + unset texttmp + } + } + } + } + + # Are there any further tests to perform? + # Note that if the program has special run-time requirements, running + # of the program can be delayed until here. Ditto for other situations. + # It would be a bit cumbersome though. + + if ![string match ${dg-final-code} ""] { + regsub -all "\\\\(\[{}\])" ${dg-final-code} "\\1" dg-final-code + # Note that the use of `args' here makes this a varargs proc. + proc dg-final-proc { args } ${dg-final-code} + verbose "Running dg-final tests." 3 + verbose "dg-final-proc:\n[info body dg-final-proc]" 4 + if [catch "dg-final-proc $prog" errmsg] { + perror "$name: error executing dg-final: $errmsg" + # ??? The call to unresolved here is necessary to clear `errcnt'. + # What we really need is a proc like perror that doesn't set errcnt. + # It should also set exit_status to 1. + unresolved "$name: error executing dg-final: $errmsg" + } + } + + # Do some final clean up. + # When testing an interpreter, we don't compile something and leave an + # output file. + if { ! ${keep} && ${dg-interpreter-batch-mode} == 0 } { + catch "exec rm -f $output_file" + } +} + + + +# +# Indicate that this test case is to be rerun several times. This +# is useful if it is nondeterministic. This applies to rerunning the +# test program only, not rebuilding it. +# The embedded format is "{ dg-repetitions N }", where N is the number +# of repetitions. It better be greater than zero. +# +proc dg-repetitions { line value } { + upvar dg-repetitions repetitions + set repetitions $value +} + + +# +# Indicate that this test case is to be run with a short timeout. +# The embedded format is "{ dg-timeout N }", where N is in seconds. +# +proc dg-timeout { line value } { + global dg-timeout + set dg-timeout $value +} + + +# dejagnu's config/unix.exp hard-codes 300 seconds as the timeout +# for any natively run executable. That's too long for tests run +# multiple times and that may possibly hang. So we override it here +# to provide some degree of control. +rename standard_wait hooked_standard_wait +proc standard_wait { dest timeout } { + global dg-timeout + if {[info exists dg-timeout]} { + if {${dg-timeout} > 0} { + verbose -log "Overriding timeout = ${dg-timeout}" + set timeout ${dg-timeout} + } + } + + hooked_standard_wait $dest $timeout +} diff --git a/libmudflap/testsuite/libmudflap.c++/c++frags.exp b/libmudflap/testsuite/libmudflap.c++/c++frags.exp new file mode 100644 index 00000000000..5d8be05245c --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c++/c++frags.exp @@ -0,0 +1,16 @@ + +libmudflap-init [find_g++] + +dg-init + +global srcdir + +foreach flags [list {} {-static} {-O2} {-O3}] { + foreach srcfile [lsort [glob -nocomplain ${srcdir}/libmudflap.c++/*.cxx]] { + set bsrc [file tail $srcfile] + setenv MUDFLAP_OPTIONS "-no-heur-proc-map -viol-segv" + dg-runtest $srcfile $flags "-fmudflap" + } +} + +dg-finish diff --git a/libmudflap/testsuite/libmudflap.c++/fail24-frag.cxx b/libmudflap/testsuite/libmudflap.c++/fail24-frag.cxx new file mode 100644 index 00000000000..e3467ddaf1a --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c++/fail24-frag.cxx @@ -0,0 +1,16 @@ +#include +#include +#include + +char zoo [10]; + +int main () +{ +int i = strlen ("twelve") + strlen ("zero") + strlen ("seventeen"); +zoo[i] = 'a'; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*zoo.*static.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c++/pass27-frag.cxx b/libmudflap/testsuite/libmudflap.c++/pass27-frag.cxx new file mode 100644 index 00000000000..aca2ea3a3b6 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c++/pass27-frag.cxx @@ -0,0 +1,12 @@ +class foo { + char z [10]; +public: + char *get_z () { return & this->z[0]; } +}; + +int main () +{ +foo x; +x.get_z()[9] = 'a'; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c++/pass28-frag.cxx b/libmudflap/testsuite/libmudflap.c++/pass28-frag.cxx new file mode 100644 index 00000000000..75e14ba1460 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c++/pass28-frag.cxx @@ -0,0 +1,20 @@ +class foo { + char z [10]; +public: + virtual char *get_z () { return & this->z[0]; } +}; + +class bar: public foo { + char q [20]; +public: + char *get_z () { return & this->q[0]; } +}; + +int main () { +foo *x = new bar (); + +x->get_z()[9] = 'a'; + +delete x; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c++/pass31-frag.cxx b/libmudflap/testsuite/libmudflap.c++/pass31-frag.cxx new file mode 100644 index 00000000000..6c4b9f9a7f8 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c++/pass31-frag.cxx @@ -0,0 +1,12 @@ +#include +#include +#include + +char zoo [10]; + +int main () +{ +int i = strlen ("eight") + strlen ("one"); +zoo[i] = 'a'; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c++/pass41-frag.cxx b/libmudflap/testsuite/libmudflap.c++/pass41-frag.cxx new file mode 100644 index 00000000000..d15b98f1cdd --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c++/pass41-frag.cxx @@ -0,0 +1,10 @@ +#include +#include + +int +main (int argc, char *argv[]) +{ + std::string myStr = "Hello, World!"; + std::cout << myStr << std::endl; + return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/cfrags.exp b/libmudflap/testsuite/libmudflap.c/cfrags.exp new file mode 100644 index 00000000000..bef2f91c312 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/cfrags.exp @@ -0,0 +1,15 @@ + +libmudflap-init [find_gcc] + +dg-init + +global srcdir +foreach flags [list {} {-static} {-O2} {-O3}] { + foreach srcfile [lsort [glob -nocomplain ${srcdir}/libmudflap.c/*.c]] { + set bsrc [file tail $srcfile] + setenv MUDFLAP_OPTIONS "-viol-segv" + dg-runtest $srcfile $flags "-fmudflap" + } +} + +dg-finish diff --git a/libmudflap/testsuite/libmudflap.c/fail1-frag.c b/libmudflap/testsuite/libmudflap.c/fail1-frag.c new file mode 100644 index 00000000000..1e48fff8771 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail1-frag.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main () +{ +volatile int foo [10]; +foo[10] = 0; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. foo.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail10-frag.c b/libmudflap/testsuite/libmudflap.c/fail10-frag.c new file mode 100644 index 00000000000..db135d5c451 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail10-frag.c @@ -0,0 +1,16 @@ +#include +#include +#include +int main () +{ +volatile int foo[10]; +int sz = sizeof (int); + +volatile char *bar = (char *)foo; +bar [sz * 10] = 0; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. foo.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail11-frag.c b/libmudflap/testsuite/libmudflap.c/fail11-frag.c new file mode 100644 index 00000000000..72038fdba30 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail11-frag.c @@ -0,0 +1,19 @@ +#include +#include +#include +int main () +{ +int i = 10; +char *x = (char *) malloc (i * sizeof (char)); + +while (i--) +{ + ++x; + *x = 0; +} +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail12-frag.c b/libmudflap/testsuite/libmudflap.c/fail12-frag.c new file mode 100644 index 00000000000..da8bfb7c046 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail12-frag.c @@ -0,0 +1,19 @@ +#include +#include +#include +int main () +{ +int i = 10; +int *x = (int *) malloc (i * sizeof (int)); + +while (i--) +{ + ++x; + *x = 0; +} +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail13-frag.c b/libmudflap/testsuite/libmudflap.c/fail13-frag.c new file mode 100644 index 00000000000..9fd3e255712 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail13-frag.c @@ -0,0 +1,26 @@ +#include +#include +#include +int main () +{ +struct a { + int x; + int y; + char z; +}; + +struct b { + int x; + int y; +}; + +struct b k; + +(*((volatile struct a *) &k)).z = 'q'; + +return 0; +} +/* { dg-output "mudflap violation 1..check/write.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. k.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail14-frag.c b/libmudflap/testsuite/libmudflap.c/fail14-frag.c new file mode 100644 index 00000000000..e66cc94c49b --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail14-frag.c @@ -0,0 +1,29 @@ +#include +#include +#include +int main () +{ +struct a { + int x; + int y; + char z; +}; + +struct b { + int x; + int y; +}; + +volatile struct b k; +volatile struct a *p; + +p = (struct a*) &k; + +p->z = 'q'; + +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. k.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail15-frag.c b/libmudflap/testsuite/libmudflap.c/fail15-frag.c new file mode 100644 index 00000000000..5d7ae744973 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail15-frag.c @@ -0,0 +1,27 @@ +#include +#include +#include +int main () +{ +struct base { + int basic; +}; + +struct derived { + struct base common; + char extra; +}; + +volatile struct base b; +volatile struct base *bp; + +bp = (struct base *)&b; + +bp->basic = 10; +((struct derived volatile *)bp)->extra = 'x'; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. b.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail16-frag.c b/libmudflap/testsuite/libmudflap.c/fail16-frag.c new file mode 100644 index 00000000000..317e2744731 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail16-frag.c @@ -0,0 +1,26 @@ +#include +#include +#include +int main () +{ +struct base { + int basic; +}; + +struct derived { + struct base common; + char extra; +}; + +struct base *bp; + +bp = (struct base *) malloc (sizeof (struct base));; + +bp->basic = 10; +((struct derived *)bp)->extra = 'x'; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail17-frag.c b/libmudflap/testsuite/libmudflap.c/fail17-frag.c new file mode 100644 index 00000000000..5af67f13858 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail17-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include +int main () +{ + +char * x; +int foo; +x = (char *) malloc (10); +strcpy (x, "123456789"); +foo = strlen (x+10); +x [foo] = 1; /* we just just use foo to force execution of strlen */ +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail18-frag.c b/libmudflap/testsuite/libmudflap.c/fail18-frag.c new file mode 100644 index 00000000000..dde150a8457 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail18-frag.c @@ -0,0 +1,16 @@ +#include +#include +#include +int main () +{ +/* One cannot redeclare __mf_lc_mask in proper C from instrumented + code, because of the way the instrumentation code emits its decls. */ +extern unsigned foo __asm__ ("__mf_lc_mask"); +unsigned *bar = &foo; +*bar = 4; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.__mf_lc_mask.*no-access.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail19-frag.c b/libmudflap/testsuite/libmudflap.c/fail19-frag.c new file mode 100644 index 00000000000..7e446b40503 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail19-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include +int main () +{ +struct foo { + int bar [10]; +}; + +struct foo *k = (struct foo *) malloc (2 * sizeof(int)); +k->bar[5] = 9; +free (k); +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail2-frag.c b/libmudflap/testsuite/libmudflap.c/fail2-frag.c new file mode 100644 index 00000000000..7672e60c602 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail2-frag.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main () +{ +volatile int foo [10][10]; +foo[10][0] = 0; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. foo.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail20-frag.c b/libmudflap/testsuite/libmudflap.c/fail20-frag.c new file mode 100644 index 00000000000..0dd8bb7f983 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail20-frag.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main () +{ +volatile char *p = (char *) 0; +*p = 5; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.NULL.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail21-frag.c b/libmudflap/testsuite/libmudflap.c/fail21-frag.c new file mode 100644 index 00000000000..4ab4a09f3b0 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail21-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include +int main () +{ + int *bar = (int *) malloc (sizeof (int)); +/* Make an access here to get &foo into the lookup cache. */ +*bar = 5; +__mf_watch (bar, sizeof(int)); +/* This access should trigger the watch violation. */ +*bar = 10; +/* NOTREACHED */ +return 0; +} +/* { dg-output "mudflap violation 1.*watch.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail22-frag.c b/libmudflap/testsuite/libmudflap.c/fail22-frag.c new file mode 100644 index 00000000000..7dd7103d359 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail22-frag.c @@ -0,0 +1,17 @@ +#include +#include +#include +int main () +{ +struct boo { int a; }; +int c; +struct boo *b = malloc (sizeof (struct boo)); +__mf_set_options ("-check-initialization"); +c = b->a; +(void) malloc (c); /* some dummy use of c */ +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.malloc region.*1r/0w.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail23-frag.c b/libmudflap/testsuite/libmudflap.c/fail23-frag.c new file mode 100644 index 00000000000..bb1b52ec7e0 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail23-frag.c @@ -0,0 +1,16 @@ +#include +#include +#include + +char zoo [10]; + +int main () +{ +int i = strlen ("012345") + strlen ("6789") + strlen ("01"); /* 11 */ +zoo[i] = 'a'; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*zoo.*static.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail25-frag.c b/libmudflap/testsuite/libmudflap.c/fail25-frag.c new file mode 100644 index 00000000000..acac5236b42 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail25-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +__mf_set_options ("-check-initialization"); +foo = (char *)malloc (10); +bar = (char *)malloc (10); +/* bar[2] = 'z'; */ /* don't touch memcpy source */ +memcpy(foo+1, bar+1, 9); +return 0; +} +/* { dg-output "mudflap violation 1.*check.read.*memcpy source.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*malloc region.*alloc time.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail26-frag.c b/libmudflap/testsuite/libmudflap.c/fail26-frag.c new file mode 100644 index 00000000000..88484d6adc4 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail26-frag.c @@ -0,0 +1,24 @@ +#include +#include +#include +int main () +{ +char *foo; + +__mf_set_options ("-check-initialization"); +foo = (char *)malloc (1); + +/* These two operations each expand to a read-modify-write. + * Even though the end result is that every bit of foo[0] is + * eventually written to deterministically, the first read + * triggers an uninit error. Ideally, it shouldn't, so this + * should be treated more like a regular XFAIL. */ +foo[0] &= 0xfe; +foo[0] |= 0x01; + +return foo[0]; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*malloc region.*1r/0w.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail27-frag.c b/libmudflap/testsuite/libmudflap.c/fail27-frag.c new file mode 100644 index 00000000000..7168dfc61b2 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail27-frag.c @@ -0,0 +1,24 @@ +#include +#include +#include + +char volatile * +__attribute__((noinline)) +foo (unsigned i) +{ + char volatile buffer[10]; + char volatile *k = i ? & buffer[i] : NULL; /* defeat addr-of-local-returned warning */ + return k; +} + +int main () +{ +char volatile *f = foo (5); +f[0] = 'b'; + +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*buffer.*alloc.*dealloc" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail28-frag.c b/libmudflap/testsuite/libmudflap.c/fail28-frag.c new file mode 100644 index 00000000000..7d61c57f34b --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail28-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int foo (int *u, int i) +{ + return u[i]; /* this dereference should be instrumented */ +} + +int main () +{ +int *k = malloc (6); +return foo (k, 8); +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*malloc region.*alloc" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail29-frag.c b/libmudflap/testsuite/libmudflap.c/fail29-frag.c new file mode 100644 index 00000000000..2024064dc73 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail29-frag.c @@ -0,0 +1,17 @@ +#include +#include + +int foo (int u[10]) +{ + return u[8]; /* this dereference should be instrumented */ +} + +int main () +{ +int *k = malloc (6); +return foo (k); +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*malloc region.*alloc" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail3-frag.c b/libmudflap/testsuite/libmudflap.c/fail3-frag.c new file mode 100644 index 00000000000..98c1dbae165 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail3-frag.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main () +{ +volatile int foo [10][10][10]; +foo[9][10][0] = 0; +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. foo.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail30-frag.c b/libmudflap/testsuite/libmudflap.c/fail30-frag.c new file mode 100644 index 00000000000..8bfea61cbb2 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail30-frag.c @@ -0,0 +1,18 @@ +#include +#include + +int foo (int u) +{ + return u*u; +} + +int main () +{ +int *k = malloc(5); +int j = foo (k[8]); /* this call argument should be instrumented */ +return j; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*malloc region.*alloc" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail31-frag.c b/libmudflap/testsuite/libmudflap.c/fail31-frag.c new file mode 100644 index 00000000000..b15056c970c --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail31-frag.c @@ -0,0 +1,22 @@ +#include +#include + +extern int h (int i, int j); + +int main () +{ + int z = h (4, 10); + return 0; +} + +int h (int i, int j) +{ + int k[i]; + k[j] = i; + return j; +} + +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*\(h\).*k" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail4-frag.c b/libmudflap/testsuite/libmudflap.c/fail4-frag.c new file mode 100644 index 00000000000..a3423e6c36b --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail4-frag.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main () +{ +char foo [10]; +strcpy(foo, "1234567890"); +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. foo.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail5-frag.c b/libmudflap/testsuite/libmudflap.c/fail5-frag.c new file mode 100644 index 00000000000..a08569fe773 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail5-frag.c @@ -0,0 +1,14 @@ +#include +#include +#include +int main () +{ +char foo [15]; +char bar [10]; +memcpy(foo, bar, 11); +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*.main. bar.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail6-frag.c b/libmudflap/testsuite/libmudflap.c/fail6-frag.c new file mode 100644 index 00000000000..1904a88711a --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail6-frag.c @@ -0,0 +1,17 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +foo = (char *)malloc (10); +bar = (char *)malloc (15); + +memcpy(foo, bar, 11); +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail7-frag.c b/libmudflap/testsuite/libmudflap.c/fail7-frag.c new file mode 100644 index 00000000000..580d045386d --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail7-frag.c @@ -0,0 +1,17 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +foo = (char *)malloc (12); +bar = (char *)malloc (10); + +memcpy(foo+1, bar+1, 10); +return 0; +} +/* { dg-output "mudflap violation 1.*" } */ +/* { dg-output "Nearby object 1.*" } */ +/* { dg-output "mudflap object.*malloc region.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail8-frag.c b/libmudflap/testsuite/libmudflap.c/fail8-frag.c new file mode 100644 index 00000000000..cc2fbdaac4c --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail8-frag.c @@ -0,0 +1,19 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +foo = (char *)malloc (10); +bar = (char *)malloc (10); + +free(bar); + +memcpy(foo, bar, 10); +return 0; +} +/* { dg-output "mudflap violation 1.*memcpy source.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*malloc region.*alloc time.*dealloc time.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/fail9-frag.c b/libmudflap/testsuite/libmudflap.c/fail9-frag.c new file mode 100644 index 00000000000..029fda5d4d0 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/fail9-frag.c @@ -0,0 +1,21 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +foo = (char *)malloc (10); +bar = (char *)malloc (10); + +free(foo); + +bar[4] = 'a'; /* touch source buffer */ +memcpy(foo, bar, 10); +return 0; +} + +/* { dg-output "mudflap violation 1.*memcpy dest.*" } */ +/* { dg-output "Nearby object.*" } */ +/* { dg-output "mudflap object.*malloc region.*alloc time.*dealloc time.*" } */ +/* { dg-do run { xfail *-*-* } } */ diff --git a/libmudflap/testsuite/libmudflap.c/hook-allocstuff.c b/libmudflap/testsuite/libmudflap.c/hook-allocstuff.c new file mode 100644 index 00000000000..dc25375488d --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/hook-allocstuff.c @@ -0,0 +1,16 @@ +#include +#include + +int main () +{ + char *foo = (char *) malloc (10); + strcpy (foo, "hello"); + foo = (char *) realloc (foo, 20); + printf ("%s", foo); + if (strcmp (foo, "hello")) + abort (); + free (foo); + printf (" world\n"); + return 0; +} +/* { dg-output "hello world" } */ diff --git a/libmudflap/testsuite/libmudflap.c/pass-stratcliff.c b/libmudflap/testsuite/libmudflap.c/pass-stratcliff.c new file mode 100644 index 00000000000..894f10ffa96 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass-stratcliff.c @@ -0,0 +1,319 @@ +/* Test for string function add boundaries of usable memory. + Copyright (C) 1996,1997,1999,2000,2001,2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#define _GNU_SOURCE 1 +#define __USE_GNU + +/* Make sure we don't test the optimized inline functions if we want to + test the real implementation. */ +#undef __USE_STRING_INLINES + +#include +#include +#include +#include +#include +#include + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +int +main (int argc, char *argv[]) +{ + int size = sysconf (_SC_PAGESIZE); + char *adr, *dest; + int result = 0; + + adr = (char *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + dest = (char *) mmap (NULL, 3 * size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (adr == MAP_FAILED || dest == MAP_FAILED) + { + if (errno == ENOSYS) + puts ("No test, mmap not available."); + else + { + printf ("mmap failed: %m"); + result = 1; + } + } + else + { + int inner, middle, outer; + + mprotect(adr, size, PROT_NONE); + mprotect(adr + 2 * size, size, PROT_NONE); + adr += size; + + mprotect(dest, size, PROT_NONE); + mprotect(dest + 2 * size, size, PROT_NONE); + dest += size; + + memset (adr, 'T', size); + + /* strlen test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (inner = MAX (outer, size - 64); inner < size; ++inner) + { + adr[inner] = '\0'; + + if (strlen (&adr[outer]) != (size_t) (inner - outer)) + { + printf ("strlen flunked for outer = %d, inner = %d\n", + outer, inner); + result = 1; + } + + adr[inner] = 'T'; + } + } + + /* strchr test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (middle = MAX (outer, size - 64); middle < size; ++middle) + { + for (inner = middle; inner < size; ++inner) + { + char *cp; + adr[middle] = 'V'; + adr[inner] = '\0'; + + cp = strchr (&adr[outer], 'V'); + + if ((inner == middle && cp != NULL) + || (inner != middle + && (cp - &adr[outer]) != middle - outer)) + { + printf ("strchr flunked for outer = %d, middle = %d, " + "inner = %d\n", outer, middle, inner); + result = 1; + } + + adr[inner] = 'T'; + adr[middle] = 'T'; + } + } + } + + /* Special test. */ + adr[size - 1] = '\0'; + if (strchr (&adr[size - 1], '\n') != NULL) + { + puts ("strchr flunked for test of empty string at end of page"); + result = 1; + } + + /* strrchr test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (middle = MAX (outer, size - 64); middle < size; ++middle) + { + for (inner = middle; inner < size; ++inner) + { + char *cp; + adr[middle] = 'V'; + adr[inner] = '\0'; + + cp = strrchr (&adr[outer], 'V'); + + if ((inner == middle && cp != NULL) + || (inner != middle + && (cp - &adr[outer]) != middle - outer)) + { + printf ("strrchr flunked for outer = %d, middle = %d, " + "inner = %d\n", outer, middle, inner); + result = 1; + } + + adr[inner] = 'T'; + adr[middle] = 'T'; + } + } + } + +#ifndef __FreeBSD__ + /* rawmemchr test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (middle = MAX (outer, size - 64); middle < size; ++middle) + { + char *cp; + adr[middle] = 'V'; + + cp = (char *) rawmemchr (&adr[outer], 'V'); + + if (cp - &adr[outer] != middle - outer) + { + printf ("rawmemchr flunked for outer = %d, middle = %d\n", + outer, middle); + result = 1; + } + + adr[middle] = 'T'; + } + } +#endif + + /* strcpy test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (inner = MAX (outer, size - 64); inner < size; ++inner) + { + adr[inner] = '\0'; + + if (strcpy (dest, &adr[outer]) != dest + || strlen (dest) != (size_t) (inner - outer)) + { + printf ("strcpy flunked for outer = %d, inner = %d\n", + outer, inner); + result = 1; + } + + adr[inner] = 'T'; + } + } + + /* strncpy tests */ + adr[size-1] = 'T'; + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + size_t len; + + for (len = 0; len < size - outer; ++len) + { + if (strncpy (dest, &adr[outer], len) != dest + || memcmp (dest, &adr[outer], len) != 0) + { + printf ("outer strncpy flunked for outer = %d, len = %Zd\n", + outer, len); + result = 1; + } + } + } + adr[size-1] = '\0'; + + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (inner = MAX (outer, size - 64); inner < size; ++inner) + { + size_t len; + + adr[inner] = '\0'; + + for (len = 0; len < size - outer + 64; ++len) + { + if (strncpy (dest, &adr[outer], len) != dest + || memcmp (dest, &adr[outer], + MIN (inner - outer, len)) != 0 + || (inner - outer < len + && strlen (dest) != (inner - outer))) + { + printf ("strncpy flunked for outer = %d, inner = %d, len = %Zd\n", + outer, inner, len); + result = 1; + } + if (strncpy (dest + 1, &adr[outer], len) != dest + 1 + || memcmp (dest + 1, &adr[outer], + MIN (inner - outer, len)) != 0 + || (inner - outer < len + && strlen (dest + 1) != (inner - outer))) + { + printf ("strncpy+1 flunked for outer = %d, inner = %d, len = %Zd\n", + outer, inner, len); + result = 1; + } + } + + adr[inner] = 'T'; + } + } + +#ifndef __FreeBSD__ + /* stpcpy test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (inner = MAX (outer, size - 64); inner < size; ++inner) + { + adr[inner] = '\0'; + + if ((stpcpy (dest, &adr[outer]) - dest) != inner - outer) + { + printf ("stpcpy flunked for outer = %d, inner = %d\n", + outer, inner); + result = 1; + } + + adr[inner] = 'T'; + } + } + + /* stpncpy test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + { + for (middle = MAX (outer, size - 64); middle < size; ++middle) + { + adr[middle] = '\0'; + + for (inner = 0; inner < size - outer; ++ inner) + { + if ((stpncpy (dest, &adr[outer], inner) - dest) + != MIN (inner, middle - outer)) + { + printf ("stpncpy flunked for outer = %d, middle = %d, " + "inner = %d\n", outer, middle, inner); + result = 1; + } + } + + adr[middle] = 'T'; + } + } +#endif + + /* memcpy test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + for (inner = 0; inner < size - outer; ++inner) + if (memcpy (dest, &adr[outer], inner) != dest) + { + printf ("memcpy flunked for outer = %d, inner = %d\n", + outer, inner); + result = 1; + } + +#ifndef __FreeBSD__ + /* mempcpy test */ + for (outer = size - 1; outer >= MAX (0, size - 128); --outer) + for (inner = 0; inner < size - outer; ++inner) + if (mempcpy (dest, &adr[outer], inner) != dest + inner) + { + printf ("mempcpy flunked for outer = %d, inner = %d\n", + outer, inner); + result = 1; + } +#endif + } + + return result; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass1-frag.c b/libmudflap/testsuite/libmudflap.c/pass1-frag.c new file mode 100644 index 00000000000..40f629b56da --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass1-frag.c @@ -0,0 +1,9 @@ +#include +#include +#include +int main () +{ +int foo [10]; +foo[9] = 0; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass10-frag.c b/libmudflap/testsuite/libmudflap.c/pass10-frag.c new file mode 100644 index 00000000000..f05650da515 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass10-frag.c @@ -0,0 +1,12 @@ +#include +#include +#include +int main () +{ +int foo[10]; +int sz = sizeof (int); + +char *bar = (char *)foo; +bar [sz * 9] = 0; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass11-frag.c b/libmudflap/testsuite/libmudflap.c/pass11-frag.c new file mode 100644 index 00000000000..ab7ee38c4f8 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass11-frag.c @@ -0,0 +1,15 @@ +#include +#include +#include +int main () +{ +int i = 10; +char *x = (char *) malloc (i * sizeof (char)); + +while (--i) +{ + ++x; + *x = 0; +} +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass12-frag.c b/libmudflap/testsuite/libmudflap.c/pass12-frag.c new file mode 100644 index 00000000000..53630d9971d --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass12-frag.c @@ -0,0 +1,15 @@ +#include +#include +#include +int main () +{ +int i = 10; +int *x = (int *) malloc (i * sizeof (int)); + +while (--i) +{ + ++x; + *x = 0; +} +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass13-frag.c b/libmudflap/testsuite/libmudflap.c/pass13-frag.c new file mode 100644 index 00000000000..c2b820d0f43 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass13-frag.c @@ -0,0 +1,17 @@ +#include +#include +#include +int main () +{ +struct a { + int x; + int y; + char z; +}; + +struct a k; + +k.z = 'q'; + +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass14-frag.c b/libmudflap/testsuite/libmudflap.c/pass14-frag.c new file mode 100644 index 00000000000..26456432979 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass14-frag.c @@ -0,0 +1,20 @@ +#include +#include +#include +int main () +{ +struct a { + int x; + int y; + char z; +}; + +struct a k; +struct a *p; + +p = &k; + +p->z = 'q'; + +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass15-frag.c b/libmudflap/testsuite/libmudflap.c/pass15-frag.c new file mode 100644 index 00000000000..5e1fee8eb9c --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass15-frag.c @@ -0,0 +1,23 @@ +#include +#include +#include +int main () +{ +struct base { + int basic; +}; + +struct derived { + struct base common; + char extra; +}; + +struct derived d; +struct base *bp; + +bp = (struct base *)&d; + +bp->basic = 10; +((struct derived *)bp)->extra = 'x'; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass16-frag.c b/libmudflap/testsuite/libmudflap.c/pass16-frag.c new file mode 100644 index 00000000000..99ede3f2138 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass16-frag.c @@ -0,0 +1,22 @@ +#include +#include +#include +int main () +{ +struct base { + int basic; +}; + +struct derived { + struct base common; + char extra; +}; + +struct base *bp; + +bp = (struct base *) malloc (sizeof (struct derived)); + +bp->basic = 10; +((struct derived *)bp)->extra = 'x'; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass17-frag.c b/libmudflap/testsuite/libmudflap.c/pass17-frag.c new file mode 100644 index 00000000000..b840dc98746 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass17-frag.c @@ -0,0 +1,9 @@ +#include +#include +#include +int main () +{ + +strlen("123456789"); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass18-frag.c b/libmudflap/testsuite/libmudflap.c/pass18-frag.c new file mode 100644 index 00000000000..c5d5af0fe12 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass18-frag.c @@ -0,0 +1,27 @@ +#include +#include +#include +int main () +{ +int t; +char foo[3] = { 'b', 'c', 'd' }; +int bar[3] = {1, 2, 0}; +t = 1; + +/* These tests check expression evaluation rules, such as + ensuring that side-effect expression (++) get executed the + right number of times; that array lookup checks nest correctly. */ +foo[t++] = 'a'; +if (foo[0] != 'b' || foo[1] != 'a' || foo[2] != 'd' || t != 2) abort (); +if (bar[0] != 1 || bar[1] != 2 || bar[2] != 0) abort(); + +foo[bar[t--]] = 'e'; +if (foo[0] != 'e' || foo[1] != 'a' || foo[2] != 'd' || t != 1) abort (); +if (bar[0] != 1 || bar[1] != 2 || bar[2] != 0) abort(); + +foo[bar[++t]--] = 'g'; +if (foo[0] != 'g' || foo[1] != 'a' || foo[2] != 'd' || t != 2) abort (); +if (bar[0] != 1 || bar[1] != 2 || bar[2] != -1) abort(); + +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass19-frag.c b/libmudflap/testsuite/libmudflap.c/pass19-frag.c new file mode 100644 index 00000000000..0b00845d412 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass19-frag.c @@ -0,0 +1,11 @@ +#include +#include +#include +int main () +{ +struct foo {int base; char variable[1]; }; /* a common idiom for variable-size structs */ + +struct foo * b = (struct foo *) malloc (sizeof (int)); /* enough for base */ +b->base = 4; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass2-frag.c b/libmudflap/testsuite/libmudflap.c/pass2-frag.c new file mode 100644 index 00000000000..7e71e0cd7b5 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass2-frag.c @@ -0,0 +1,9 @@ +#include +#include +#include +int main () +{ +int foo [10][10]; +foo[9][0] = 0; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass20-frag.c b/libmudflap/testsuite/libmudflap.c/pass20-frag.c new file mode 100644 index 00000000000..98431168548 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass20-frag.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main () +{ +struct bar {int stuff; int array[10]; }; + +struct bar *foo = (struct bar *) malloc (sizeof (struct bar)); +foo->array[5] = 4; +free (foo); + +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass21-frag.c b/libmudflap/testsuite/libmudflap.c/pass21-frag.c new file mode 100644 index 00000000000..231055a236f --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass21-frag.c @@ -0,0 +1,15 @@ +#include +#include +#include +#ifndef __FreeBSD__ +#include +#endif +int main () +{ +char *boo, *foo; +boo = (char *) alloca (100); +boo[99] = 'a'; +foo = (char *) __builtin_alloca (200); +foo[44] = 'b'; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass22-frag.c b/libmudflap/testsuite/libmudflap.c/pass22-frag.c new file mode 100644 index 00000000000..b092ea0b277 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass22-frag.c @@ -0,0 +1,23 @@ +#include +#include +#include +int main () +{ +struct foo { + unsigned base:8; + unsigned flag1:1; + unsigned flag2:3; + unsigned flag3:4; + char nothing[0]; +}; + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) + +struct foo* f = (struct foo *) malloc (offsetof (struct foo, nothing)); +f->base = 1; +f->flag1 = 1; +free (f); + + +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass23-frag.c b/libmudflap/testsuite/libmudflap.c/pass23-frag.c new file mode 100644 index 00000000000..f27c223614b --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass23-frag.c @@ -0,0 +1,29 @@ +#include +#include +#include +int main () +{ +struct foo { + int part1: 8; + int nothing : 1; + int part2 : 5; + int lots_more_nothing : 3; + int some_padding; /* for 64-bit hosts */ + float some_more_nothing; + double yet_more_nothing; +}; + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER) + +struct foo* q = (struct foo *) malloc (offsetof (struct foo, some_more_nothing)); +q->nothing = 1; /* touch q */ +/* The RHS of the following expression is meant to trigger a + fold-const.c mapping the expression to a BIT_FIELD_REF. It glues + together the accesses to the two non-neighbouring bitfields into a + single bigger boolean test. */ +q->lots_more_nothing = (q->part1 == 13 && q->part2 == 7); +free (q); + + +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass24-frag.c b/libmudflap/testsuite/libmudflap.c/pass24-frag.c new file mode 100644 index 00000000000..00385822130 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass24-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include +int main () +{ +struct foo { + int zoo; + int bar [10]; + float baz; +}; + +#define offsetof(S,F) ((size_t) & (((S *) 0)->F)) + +struct foo *k = (struct foo *) malloc (offsetof (struct foo, bar[4])); +k->bar[1] = 9; +free (k); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass25-frag.c b/libmudflap/testsuite/libmudflap.c/pass25-frag.c new file mode 100644 index 00000000000..c5a75e3338e --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass25-frag.c @@ -0,0 +1,15 @@ +#include +#include +#include +int main () +{ +int *foo = malloc (10 * sizeof(int)); +int *bar = & foo[3]; +/* Watching occurs at the object granularity, which is in this case + the entire array. */ +__mf_watch (& foo[1], sizeof(foo[1])); +__mf_unwatch (& foo[6], sizeof(foo[6])); +*bar = 10; +free (foo); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass26-frag.c b/libmudflap/testsuite/libmudflap.c/pass26-frag.c new file mode 100644 index 00000000000..5a72f5b790c --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass26-frag.c @@ -0,0 +1,52 @@ +#include +#include +#include +int main () +{ +volatile int *p; + +__mf_set_options ("-wipe-stack -no-check-initialization"); + +{ + volatile int array [10]; + p = & array[0]; + + array[0] = 2; + array[9] = 5; + + /* Array[] should be wiped clean at this point. */ +} + +__mf_set_options ("-no-wipe-stack"); + +{ + volatile int array2[10]; + + /* hope that this is allocated on top of old array[] */ + if (p != & array2[0]) + exit (0); /* Test is not applicable. */ + + array2[5] = 6; + + /* Old values shouldn't still be around; the new one should. */ + if (p[0] == 2 || p[9] == 5 || p[5] != 6) + abort() ; + + /* array2[] should not be wiped at this point! */ +} + +{ + volatile int array3[10]; + + /* hope that this is allocated on top of old array[] and array2[]*/ + if (p != & array3[0]) + exit (0); /* Test is not applicable. */ + + array3[1] = 2; + + /* Check that old assignment is still around. */ + if (p[5] != 6 || p[1] != 2) + abort() ; +} +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass29-frag.c b/libmudflap/testsuite/libmudflap.c/pass29-frag.c new file mode 100644 index 00000000000..97bed6eb373 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass29-frag.c @@ -0,0 +1,15 @@ +#include +#include +#include +int main () +{ +struct boo { int a; }; +int c; +struct boo *b = malloc (sizeof (struct boo)); +__mf_set_options ("-check-initialization"); +b->a = 0; +/* That __mf_set_options call could be here instead. */ +c = b->a; +(void) malloc (c); /* some dummy use of c */ +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass3-frag.c b/libmudflap/testsuite/libmudflap.c/pass3-frag.c new file mode 100644 index 00000000000..4e950a2c5d8 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass3-frag.c @@ -0,0 +1,9 @@ +#include +#include +#include +int main () +{ +int foo [10][10][10]; +foo[9][9][0] = 0; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass30-frag.c b/libmudflap/testsuite/libmudflap.c/pass30-frag.c new file mode 100644 index 00000000000..6c4b9f9a7f8 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass30-frag.c @@ -0,0 +1,12 @@ +#include +#include +#include + +char zoo [10]; + +int main () +{ +int i = strlen ("eight") + strlen ("one"); +zoo[i] = 'a'; +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass32-frag.c b/libmudflap/testsuite/libmudflap.c/pass32-frag.c new file mode 100644 index 00000000000..83f121d4fa2 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass32-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include + +struct foo { char z[10]; }; + +char * get_z (struct foo *this) +{ + return & this->z[0] /* the `this' pointer is not dereferenced! */; +} + +int main () +{ +struct foo k; +char *n = get_z (& k); +srand ((int)(uintptr_t) n); /* use the pointer value */ +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass33-frag.c b/libmudflap/testsuite/libmudflap.c/pass33-frag.c new file mode 100644 index 00000000000..95d762cc1aa --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass33-frag.c @@ -0,0 +1,17 @@ +#include +#include +#include + +void test (int *k) +{ + if (*k > 5) { *k --; } +} + +int main () +{ +int z; +/* z is initialized, but not via a pointer, so not instrumented */ +z = rand (); +test (& z); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass34-frag.c b/libmudflap/testsuite/libmudflap.c/pass34-frag.c new file mode 100644 index 00000000000..2dfd0ca2113 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass34-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include + +void test (int *k) +{ + if (*k > 5) { *k --; } +} + +int z; + +int main () +{ +/* z is initialized, but not via a pointer, so not instrumented */ +z = rand (); +test (& z); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass35-frag.c b/libmudflap/testsuite/libmudflap.c/pass35-frag.c new file mode 100644 index 00000000000..4744ecdbe99 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass35-frag.c @@ -0,0 +1,14 @@ +#include +#include +#include + +extern char end []; /* Any old symbol we're sure will be defined. */ +/* { dg-warning "cannot track lifetime of `end'" "cannot track lifetime" { target *-*-* } 0 } */ + +int main () +{ +/* dummy register */ +__mf_register ((void *) end, 1, __MF_TYPE_GUESS, "end"); +char z = end[0]; +return z & 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass36-frag.c b/libmudflap/testsuite/libmudflap.c/pass36-frag.c new file mode 100644 index 00000000000..68d1a7f8080 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass36-frag.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +int main () +{ +char *k; +__mf_set_options ("-sigusr1-report -print-leaks"); +k = (char *) malloc (100); +raise (SIGUSR1); +free (k); +return 0; +} +/* { dg-output "Leaked object.*name=.malloc region.*objects: 1" } */ diff --git a/libmudflap/testsuite/libmudflap.c/pass38-frag.c b/libmudflap/testsuite/libmudflap.c/pass38-frag.c new file mode 100644 index 00000000000..a250234da8a --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass38-frag.c @@ -0,0 +1,9 @@ +/* Test an odd construct for compilability. */ +static void *fwd; +void *bwd = &fwd; +static void *fwd = &bwd; + +int main () +{ + return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass4-frag.c b/libmudflap/testsuite/libmudflap.c/pass4-frag.c new file mode 100644 index 00000000000..0a40d1c425a --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass4-frag.c @@ -0,0 +1,9 @@ +#include +#include +#include +int main () +{ +char foo[10]; +strcpy (foo, "123456789"); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass42-frag.c b/libmudflap/testsuite/libmudflap.c/pass42-frag.c new file mode 100644 index 00000000000..1045c47c37a --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass42-frag.c @@ -0,0 +1,17 @@ +#include + +void +foo () +{ + putc ('h', stdout); + putc ('i', stdout); + putc ('\n', stdout); +} + +int +main (int argc, char *argv[]) +{ + foo (); + return 0; +} +/* { dg-output "hi" } */ diff --git a/libmudflap/testsuite/libmudflap.c/pass43-frag.c b/libmudflap/testsuite/libmudflap.c/pass43-frag.c new file mode 100644 index 00000000000..4fec3306eb1 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass43-frag.c @@ -0,0 +1,11 @@ +void +foo () +{ +} + +int +main (int argc, char *argv[]) +{ + foo (); + return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass44-frag.c b/libmudflap/testsuite/libmudflap.c/pass44-frag.c new file mode 100644 index 00000000000..338d6da63bf --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass44-frag.c @@ -0,0 +1,14 @@ +#include + +void +foo () +{ + return; /* accept value-less return statement */ +} + +int +main (int argc, char *argv[]) +{ + foo (); + return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass45-frag.c b/libmudflap/testsuite/libmudflap.c/pass45-frag.c new file mode 100644 index 00000000000..c6bfeb5048c --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass45-frag.c @@ -0,0 +1,31 @@ +#include +#include +#include + +extern void h (const char *p, const char *f); +int +main (void) +{ + h (0, "foo"); + return 0; +} + +void +h (const char *p, const char *f) +{ + size_t pl = p == NULL ? 0 : strlen (p); + size_t fl = strlen (f) + 1; + char a[pl + 1 + fl]; + char *cp = a; + char b[pl + 5 + fl * 2]; + char *cccp = b; + if (p != NULL) + { + cp = memcpy (cp, p, pl); + *cp++ = ':'; + } + memcpy (cp, f, fl); + strcpy (b, a); + puts (a); +} +/* { dg-output "foo" } */ diff --git a/libmudflap/testsuite/libmudflap.c/pass46-frag.c b/libmudflap/testsuite/libmudflap.c/pass46-frag.c new file mode 100644 index 00000000000..a1f24be1dc0 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass46-frag.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int foo (int *u, int i) +{ + return u[i]; /* this dereference should not be instrumented */ +} + +int main () +{ + int *k = malloc (6); + int l = foo (k, 8); + int boo [8]; + int m = boo [l % 2 + 12]; /* should not be instrumented */ + return m & strlen (""); /* a fancy way of saying "0" */ +} +/* { dg-options "-fmudflap -fmudflapir -Wall" } */ diff --git a/libmudflap/testsuite/libmudflap.c/pass5-frag.c b/libmudflap/testsuite/libmudflap.c/pass5-frag.c new file mode 100644 index 00000000000..6d3408a4e52 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass5-frag.c @@ -0,0 +1,11 @@ +#include +#include +#include +int main () +{ +char foo [10]; +char bar [10]; +bar[4] = 'k'; /* touch memcpy source */ +memcpy(foo, bar, 10); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass6-frag.c b/libmudflap/testsuite/libmudflap.c/pass6-frag.c new file mode 100644 index 00000000000..9b07fe2de22 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass6-frag.c @@ -0,0 +1,14 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; + +foo = (char *)malloc (10); +bar = (char *)malloc (10); +bar[2] = 'z'; /* touch memcpy source */ +memcpy(foo, bar, 10); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass7-frag.c b/libmudflap/testsuite/libmudflap.c/pass7-frag.c new file mode 100644 index 00000000000..36197339e88 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass7-frag.c @@ -0,0 +1,13 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +foo = (char *)malloc (10); +bar = (char *)malloc (10); +bar[2] = 'z'; /* touch memcpy source */ +memcpy(foo+1, bar+1, 9); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass8-frag.c b/libmudflap/testsuite/libmudflap.c/pass8-frag.c new file mode 100644 index 00000000000..6be4e93f000 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass8-frag.c @@ -0,0 +1,16 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +foo = (char *)malloc (10); +bar = (char *)malloc (10); + +free(bar); +bar = (char *)malloc (10); +bar[6] = 'k'; /* touch memcpy source */ +memcpy(foo, bar, 10); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.c/pass9-frag.c b/libmudflap/testsuite/libmudflap.c/pass9-frag.c new file mode 100644 index 00000000000..9186e062ff8 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.c/pass9-frag.c @@ -0,0 +1,16 @@ +#include +#include +#include +int main () +{ +char *foo; +char *bar; +foo = (char *)malloc (10); +bar = (char *)malloc (10); + +free(foo); +foo = (char *)malloc (10); +bar[3] = 'w'; /* touch memcpy source */ +memcpy(foo, bar, 10); +return 0; +} diff --git a/libmudflap/testsuite/libmudflap.cth/cthfrags.exp b/libmudflap/testsuite/libmudflap.cth/cthfrags.exp new file mode 100644 index 00000000000..508d8eced10 --- /dev/null +++ b/libmudflap/testsuite/libmudflap.cth/cthfrags.exp @@ -0,0 +1,23 @@ + +libmudflap-init [find_gcc] + +dg-init + +global srcdir +foreach flags [list {} {-static -DSTATIC} {-O2} {-O3}] { + foreach srcfile [lsort [glob -nocomplain ${srcdir}/libmudflap.cth/*.c]] { + set bsrc [file tail $srcfile] + setenv MUDFLAP_OPTIONS "-viol-segv" + if {$libmudflapth} then { + # --noinhibit-exec works around a ld problem that causes + # "Dwarf Error: Invalid or unhandled FORM value: 14" + # to fail builds unnecessarily. + dg-runtest $srcfile $flags "-fmudflapth -Wl,--noinhibit-exec" + } else { + if {$flags != ""} {set f " ($flags)"} {set f ""} + untested "libmudflap.cth/$bsrc$f" + } + } +} + +dg-finish diff --git a/libmudflap/testsuite/libmudflap.cth/pass37-frag.c b/libmudflap/testsuite/libmudflap.cth/pass37-frag.c new file mode 100644 index 00000000000..bfa2c7c02ab --- /dev/null +++ b/libmudflap/testsuite/libmudflap.cth/pass37-frag.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +static void * +func (void *p) +{ + int *counter = (int *) p; + unsigned i; + + for (i=0; i<100; i++) + { + (*counter) ++; + { + int array[17]; + unsigned x = i % (sizeof(array)/sizeof(array[0])); + /* VRP could prove that x is within [0,16], but until then, the + following access will ensure that array[] is registered to + libmudflap. */ + array[x] = i; + } + sched_yield (); /* sleep (1); */ + } + + return (NULL); +} + + +int main () +{ + int rc; + unsigned i; + enum foo { NT=10 }; + pthread_t threads[NT]; + int counts[NT]; + + + for (i=0; i +#include +#include +#include +#include + +static void * +func (void *p) +{ + int *counter = (int *) p; + unsigned i; + enum { numarrays = 100, numels = 17 }; + char *arrays [numarrays]; + + for (i=0; i +#include +#include + +static void * +func (void *p) +{ + return (NULL); +} + +static void +test (void) +{ + int rc; + pthread_attr_t my_pthread_attr; + pthread_t h; + long i; + + rc = pthread_attr_init (&my_pthread_attr); + + for (i = 1; i <= 10000; ++i) { + if (i%100 == 0) fprintf (stderr, "%i ", i); + if (i%1000 == 0) fprintf (stderr, "\n"); +#ifndef STATIC + /* Some glibc versions don't like static multithreaded programs doing this. */ + if (i==5000) __mf_set_options ("-thread-stack=192"); +#endif + rc = pthread_create (&h, &my_pthread_attr, + func, NULL); + if (rc) + break; + + rc = pthread_join (h, NULL); + if (rc) + break; + } + + rc = pthread_attr_destroy (&my_pthread_attr); +} + +int main () +{ + test (); + + return (0); +} + +/* { dg-timeout 20 } */ +/* { dg-output "100 200 300 400 500 600 700 800 900 1000 \n" } */ +/* { dg-output "1100 1200 1300 1400 1500 1600 1700 1800 1900 2000 \n" } */ +/* { dg-output "2100 2200 2300 2400 2500 2600 2700 2800 2900 3000 \n" } */ +/* { dg-output "3100 3200 3300 3400 3500 3600 3700 3800 3900 4000 \n" } */ +/* { dg-output "4100 4200 4300 4400 4500 4600 4700 4800 4900 5000 \n" } */ +/* { dg-output "5100 5200 5300 5400 5500 5600 5700 5800 5900 6000 \n" } */ +/* { dg-output "6100 6200 6300 6400 6500 6600 6700 6800 6900 7000 \n" } */ +/* { dg-output "7100 7200 7300 7400 7500 7600 7700 7800 7900 8000 \n" } */ +/* { dg-output "8100 8200 8300 8400 8500 8600 8700 8800 8900 9000 \n" } */ +/* { dg-output "9100 9200 9300 9400 9500 9600 9700 9800 9900 10000 \n" } */ + diff --git a/libobjc/configure b/libobjc/configure index 4c4ebb6361c..36f7c94fd18 100755 --- a/libobjc/configure +++ b/libobjc/configure @@ -951,7 +951,7 @@ esac else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi - cd "$ac_popdir" + cd $ac_popdir done fi @@ -2183,7 +2183,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -2241,7 +2242,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -2357,7 +2359,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -2411,7 +2414,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -2456,7 +2460,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -2500,7 +2505,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -3147,7 +3153,7 @@ darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; -freebsd* ) +freebsd* | kfreebsd*-gnu) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then case $host_cpu in i*86 ) @@ -3215,7 +3221,7 @@ linux-gnu*) lt_cv_file_magic_test_file=`echo /lib/libc.so* /lib/libc-*.so` ;; -netbsd*) +netbsd* | knetbsd*-gnu) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/\.]+\.so\.[0-9]+\.[0-9]+$' else @@ -3607,7 +3613,7 @@ test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 3610 "configure"' > conftest.$ac_ext + echo '#line 3616 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -3754,7 +3760,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -4216,7 +4223,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -4386,7 +4394,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -4449,7 +4458,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -4606,7 +4616,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -4773,7 +4784,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? @@ -5792,6 +5804,11 @@ esac *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ @@ -5830,12 +5847,6 @@ echo "$as_me: error: cannot find input file: $f" >&2;} fi;; esac done` || { (exit 1); exit 1; } - - if test x"$ac_file" != x-; then - { echo "$as_me:$LINENO: creating $ac_file" >&5 -echo "$as_me: creating $ac_file" >&6;} - rm -f "$ac_file" - fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub diff --git a/maintainer-scripts/ChangeLog b/maintainer-scripts/ChangeLog index 94988ab3bfd..13b504c79d8 100644 --- a/maintainer-scripts/ChangeLog +++ b/maintainer-scripts/ChangeLog @@ -1,3 +1,9 @@ +2003-07-26 Paul Brook + + * gcc_release: Add gcc-fortran. + * snapshot-README: Ditto. + * snapshot-index.html: Ditto. + 2004-05-02 Gerald Pfeifer * crontab: Move GCC 3.4 snapshots from Wednesday afternoon to diff --git a/maintainer-scripts/gcc_release b/maintainer-scripts/gcc_release index 313a37f8211..ed0751d2315 100755 --- a/maintainer-scripts/gcc_release +++ b/maintainer-scripts/gcc_release @@ -295,13 +295,14 @@ build_tarfiles() { build_tarfile gcc-ada-${RELEASE} ${ADA_DIRS} build_tarfile gcc-g++-${RELEASE} ${CPLUSPLUS_DIRS} build_tarfile gcc-g77-${RELEASE} ${FORTRAN_DIRS} + build_tarfile gcc-fortran-${RELEASE} ${FORTRAN95_DIRS} build_tarfile gcc-java-${RELEASE} ${JAVA_DIRS} build_tarfile gcc-objc-${RELEASE} ${OBJECTIVEC_DIRS} build_tarfile gcc-testsuite-${RELEASE} ${TESTSUITE_DIRS} # The core is everything else. EXCLUDES="" - for x in ${ADA_DIRS} ${CPLUSPLUS_DIRS} ${FORTRAN_DIRS} \ + for x in ${ADA_DIRS} ${CPLUSPLUS_DIRS} ${FORTRAN_DIRS} ${FORTRAN95_DIRS}\ ${JAVA_DIRS} ${OBJECTIVEC_DIRS} ${TESTSUITE_DIRS}; do EXCLUDES="${EXCLUDES} --exclude $x" done @@ -324,7 +325,7 @@ build_diffs() { old_vers=${old_file%.tar.bz2} old_vers=${old_vers#gcc-} inform "Building diffs against version $old_vers" - for f in gcc gcc-ada gcc-g++ gcc-g77 gcc-java gcc-objc gcc-testsuite gcc-core; do + for f in gcc gcc-ada gcc-g++ gcc-g77 gcc-fortran gcc-java gcc-objc gcc-testsuite gcc-core; do old_tar=${old_dir}/${f}-${old_vers}.tar.bz2 new_tar=${WORKING_DIRECTORY}/${f}-${RELEASE}.tar.bz2 if [ ! -e $old_tar ]; then @@ -489,6 +490,7 @@ SOURCE_DIRECTORY="" ADA_DIRS="gcc/ada libada" CPLUSPLUS_DIRS="gcc/cp libstdc++-v3" FORTRAN_DIRS="gcc/f libf2c" +FORTRAN95_DIRS="gcc/fortran libgfortran" JAVA_DIRS="gcc/java libjava libffi fastjar zlib boehm-gc" OBJECTIVEC_DIRS="gcc/objc libobjc" TESTSUITE_DIRS="gcc/testsuite" @@ -638,6 +640,7 @@ SOURCE_DIRECTORY="${WORKING_DIRECTORY}/gcc-${RELEASE}" ADA_DIRS=`adjust_dirs ${ADA_DIRS}` CPLUSPLUS_DIRS=`adjust_dirs ${CPLUSPLUS_DIRS}` FORTRAN_DIRS=`adjust_dirs ${FORTRAN_DIRS}` +FORTRAN95_DIRS=`adjust_dirs ${FORTRAN95_DIRS}` JAVA_DIRS=`adjust_dirs ${JAVA_DIRS}` OBJECTIVEC_DIRS=`adjust_dirs ${OBJECTIVEC_DIRS}` TESTSUITE_DIRS=`adjust_dirs ${TESTSUITE_DIRS}` diff --git a/maintainer-scripts/snapshot-README b/maintainer-scripts/snapshot-README index b32cdd706b8..77b49ac7ea7 100644 --- a/maintainer-scripts/snapshot-README +++ b/maintainer-scripts/snapshot-README @@ -20,6 +20,8 @@ You'll find: gcc-g77-@RELEASE@.tar.bz2 The F77 front end and runtime. + gcc-fortran-@RELEASE@.tar.gz The Fortran front end and runtime. + gcc-objc-@RELEASE@.tar.bz2 The Objective-C front end and runtime. gcc-java-@RELEASE@.tar.bz2 The Java front end and runtime. diff --git a/maintainer-scripts/snapshot-index.html b/maintainer-scripts/snapshot-index.html index 67a786b50eb..de3859b7ac5 100644 --- a/maintainer-scripts/snapshot-index.html +++ b/maintainer-scripts/snapshot-index.html @@ -34,6 +34,10 @@ with the following options: @EXPORT@

gcc-g77
@TEXT_DATE@ snapshot, includes just the F77 front end and runtime. +

+ gcc-fortran @TEXT_DATE@ snapshot, includes just the Fortran front + end and runtime. +

gcc-java @TEXT_DATE@ snapshot, includes just the Java front end and runtime. -- 2.30.2